Support multiple remappings for dSYMs

When compiling Swift, we automatically enable dSYMs for an improved
debugging experience.

Previously for dSYMs, we had only one of the following mappings:

- ./ -> workspace_root (only for non-Swift with DebugPathNormalization)
- bazel_exec_root -> workspace_root (otherwise)

We should instead always do the later and optionally do the former
if the DebugPathNormalization is enabled. This allows Objective-C
compilation to be normalized even if Swift compilation isn't.

Note that for non-dSYMs, we only use one of the two path remappings
as only one of them should apply (depending of what flags were used
to compile the Cxx sources). It appears that trying to use both
remappings may not work as lldb does not intelligently handle
multiple remappings of the form:
BuildRootA => SourceRoot, BuildRootB => SourceRoot inside .lldbinit's
target.source-map although dSYM remappings do support them.
PiperOrigin-RevId: 206626005
diff --git a/src/TulsiGenerator/BazelSettingsProvider.swift b/src/TulsiGenerator/BazelSettingsProvider.swift
index 5d1dd5d..82e7cd4 100644
--- a/src/TulsiGenerator/BazelSettingsProvider.swift
+++ b/src/TulsiGenerator/BazelSettingsProvider.swift
@@ -43,6 +43,8 @@
   /// For this reason, -fdebug-prefix-map is provided as a default for non-distributed purposes.
   case DirectDebugPrefixMap(String, String)
 
+  /// TODO(b/111928007): Remove this and/or BazelSettingFeature once DebugPathNormalization is
+  /// supported by all builds.
   public var stringValue: String {
     switch self {
       case .DebugPathNormalization:
@@ -63,7 +65,9 @@
   public var supportsSwift: Bool {
     switch self {
       case .DebugPathNormalization:
-        return false
+        /// Technically this doesn't support swiftc, but we now support this feature for
+        /// Cxx compilation alongside swift compilation.
+        return true
       case .DirectDebugPrefixMap:
         return true
     }
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index 925b24e..9eae1c8 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -1446,7 +1446,7 @@
 
     return (0, uuids_found)
 
-  def _CreateUUIDPlist(self, dsym_bundle_path, uuid, arch, source_map):
+  def _CreateUUIDPlist(self, dsym_bundle_path, uuid, arch, source_maps):
     """Creates a UUID.plist in a dSYM bundle to redirect sources.
 
     Args:
@@ -1454,10 +1454,10 @@
       uuid: string representing the UUID of the binary slice with paths to
             remap in the dSYM bundle.
       arch: the architecture of the binary slice.
-      source_map: a single tuple representing all absolute paths to source
-                   files compiled by Bazel as strings ($0) associated with the
-                   paths to Xcode-visible sources used for the purposes of
-                   Tulsi debugging as strings ($1).
+      source_maps:  list of tuples representing all absolute paths to source
+                    files compiled by Bazel as strings ($0) associated with the
+                    paths to Xcode-visible sources used for the purposes of
+                    Tulsi debugging as strings ($1).
 
     Returns:
       Bool: True if no error was found, or False, representing a failure to
@@ -1480,9 +1480,9 @@
                   '<dict>\n'
                   '<key>DBGSourcePathRemapping</key>\n'
                   '<dict>\n')
-
-        # Add the mapping as a DBGSourcePathRemapping to the UUID plist here.
-        out.write('<key>%s</key>\n<string>%s</string>\n' % source_map)
+        for source_map in source_maps:
+          # Add the mapping as a DBGSourcePathRemapping to the UUID plist here.
+          out.write('<key>%s</key>\n<string>%s</string>\n' % source_map)
 
         # Make sure that we also set DBGVersion to 2.
         out.write('</dict>\n'
@@ -1519,17 +1519,14 @@
     """Adds Plists to a given dSYM bundle to redirect DWARF data."""
 
     # Retrieve the paths that we are expected to remap.
+
+    # Always include a direct path from the execroot to Xcode-visible sources.
+    source_maps = [self._ExtractTargetSourceMap()]
+
+    # Remap relative paths from the workspace root.
     if self.normalized_prefix_map:
       # Take the normalized path and map that to Xcode-visible sources.
-      source_map = ('./', self._NormalizePath(self.workspace_root))
-    else:
-      # Use a direct path from the execroot to Xcode-visible sources.
-      source_map = self._ExtractTargetSourceMap()
-
-    if not source_map:
-      _PrintXcodeWarning('Extracted 0 source paths. File-based breakpoints '
-                         'may not work. Please report as a bug.')
-      return 410
+      source_maps.append(('./', self._NormalizePath(self.workspace_root)))
 
     # Find the binaries within the dSYM bundle. UUIDs will match that of the
     # binary it was based on.
@@ -1553,7 +1550,7 @@
         plist_created = self._CreateUUIDPlist(dsym_bundle_path,
                                               uuid,
                                               arch,
-                                              source_map)
+                                              source_maps)
         if not plist_created:
           return 405
 
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/PlatformDependent.BUILD b/src/TulsiGeneratorIntegrationTests/Resources/PlatformDependent.BUILD
index 69f1443..73831ba 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/PlatformDependent.BUILD
+++ b/src/TulsiGeneratorIntegrationTests/Resources/PlatformDependent.BUILD
@@ -180,7 +180,7 @@
 ios_ui_test(
     name = "XCUITest",
     minimum_os_version = "8.0",
-    runner = "//tools/objc/sim_devices:default_runner",
+    runner = "@build_bazel_rules_apple//apple/testing/default_runner:ios_default_runner",
     test_host = ":SkylarkApplication",
     deps = [
         ":XCUITestCode",