Add support for an additional dictionary in the per-arch plists
that may be embedded in the Contents/Resources subdir of a dSYM
bundle.  These allow for the specification of a build-time path
to debug-time path remapping for source files.  Files may be built
in /BuildDirectory/sources/project-100 but when the debugger is
run, they're actually found via ~sources/project-100 - this plist
allows for that remapping through the DBGBuildSourcePath and
DBGSourcePath keys.

This patch adds support for a new DBGSourcePathRemapping
dictionary in the plist where the keys are the build-time paths
and the values are the debug-time paths that they should be
remapped to.  There are instances were we have multiple possible
build-time paths that need to be included, so the dictionary was
required.

<rdar://problem/26725174> 

llvm-svn: 276729
diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp
index f6a18fe..3eba327 100644
--- a/lldb/source/Host/macosx/Symbols.cpp
+++ b/lldb/source/Host/macosx/Symbols.cpp
@@ -310,6 +310,7 @@
     {
         std::string str;
         CFStringRef cf_str;
+        CFDictionaryRef cf_dict;
         
         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
@@ -362,8 +363,69 @@
         
         if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
         {
+            if (DBGSourcePath[0] == '~')
+            {
+                FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
+                DBGSourcePath = resolved_source_path.GetPath();
+            }
             module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
         }
+
+        cf_dict = (CFDictionaryRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePathRemapping"));
+        if (cf_dict && CFGetTypeID (cf_dict) == CFDictionaryGetTypeID ())
+        {
+            // If we see DBGVersion with any kind of value, this is a new style DBGSourcePathRemapping dictionary
+            bool new_style_source_remapping_dictionary = false;
+            std::string original_DBGSourcePath_value = DBGSourcePath;
+            const void *version_value;
+            version_value = CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGVersion"));
+            if (version_value)
+                new_style_source_remapping_dictionary = true;
+
+            CFIndex kv_pair_count = CFDictionaryGetCount ((CFDictionaryRef) uuid_dict);
+            if (kv_pair_count > 0)
+            {
+                CFStringRef *keys = (CFStringRef *) malloc (kv_pair_count * sizeof (CFStringRef));
+                CFStringRef *values = (CFStringRef *) malloc (kv_pair_count * sizeof (CFStringRef));
+                if (keys != nullptr && values != nullptr)
+                {
+                    CFDictionaryGetKeysAndValues ((CFDictionaryRef) uuid_dict, (const void**)keys, (const void**)values);
+                }
+                for (CFIndex i = 0; i < kv_pair_count; i++)
+                {
+                    DBGBuildSourcePath.clear();
+                    DBGSourcePath.clear();
+                    if (keys[i] && CFGetTypeID (keys[i]) == CFStringGetTypeID ())
+                    {
+                        CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
+                    }
+                    if (values[i] && CFGetTypeID (values[i]) == CFStringGetTypeID ())
+                    {
+                        CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
+                    }
+                    if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
+                    {
+                        // In the "old style" DBGSourcePathRemapping dictionary, the DBGSourcePath values
+                        // (the "values" half of key-value path pairs) were wrong.  Ignore them and use the
+                        // universal DBGSourcePath string from earlier.
+                        if (new_style_source_remapping_dictionary == true && !original_DBGSourcePath_value.empty())
+                        {
+                            DBGSourcePath = original_DBGSourcePath_value;
+                        }
+                        if (DBGSourcePath[0] == '~')
+                        {
+                            FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
+                            DBGSourcePath = resolved_source_path.GetPath();
+                        }
+                        module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
+                    }
+                }
+                if (keys)
+                    free (keys);
+                if (values)
+                    free (values);
+            }
+        }
     }
     return success;
 }