[llvm] Revert "[dsymutil] Remove support for obfuscated bitcode" (PR #85826)

Andres Villegas via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 19 10:16:12 PDT 2024


https://github.com/avillega created https://github.com/llvm/llvm-project/pull/85826

Reverts llvm/llvm-project#85713 Since it is breaking Linux x64 builds.

>From 48ebe1b0a23d5d692db931afa214ac964cf06bfd Mon Sep 17 00:00:00 2001
From: Andres Villegas <villegas.pelaez.andres at gmail.com>
Date: Tue, 19 Mar 2024 10:15:43 -0700
Subject: [PATCH] Revert "[dsymutil] Remove support for obfuscated bitcode
 (#85713)"

This reverts commit 43a2ec483fe08064b53a6293682e9bab97df61a0.
---
 llvm/docs/CommandGuide/dsymutil.rst           |   4 +
 .../llvm/CodeGen/NonRelocatableStringpool.h   |   6 +-
 .../llvm/DWARFLinker/Classic/DWARFStreamer.h  |   8 +-
 .../llvm/DWARFLinker/DWARFLinkerBase.h        |   1 +
 .../llvm/DWARFLinker/Parallel/DWARFLinker.h   |   3 +-
 llvm/lib/CodeGen/NonRelocatableStringpool.cpp |   5 +
 llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp  |   4 +-
 .../lib/DWARFLinker/Classic/DWARFStreamer.cpp |  12 +-
 llvm/lib/DWARFLinker/Parallel/DWARFLinker.cpp |   6 +-
 .../Parallel/DWARFLinkerGlobalData.h          |  15 ++
 .../DWARFLinker/Parallel/DWARFLinkerImpl.cpp  |   4 +-
 .../DWARFLinker/Parallel/DWARFLinkerImpl.h    |   3 +-
 .../lib/DWARFLinker/Parallel/OutputSections.h |   2 +-
 .../StringEntryToDwarfStringPoolEntryMap.h    |   2 +-
 llvm/test/tools/dsymutil/ARM/obfuscated.test  | 200 ++++++++++++++++++
 .../tools/dsymutil/Inputs/obfuscated.2.arm64  | Bin 0 -> 10339 bytes
 .../tools/dsymutil/Inputs/obfuscated.2.map    |  22 ++
 .../tools/dsymutil/Inputs/obfuscated.arm64    | Bin 0 -> 10434 bytes
 .../test/tools/dsymutil/Inputs/obfuscated.map |  17 ++
 llvm/test/tools/dsymutil/cmdline.test         |   1 +
 llvm/tools/dsymutil/CMakeLists.txt            |   1 +
 llvm/tools/dsymutil/DwarfLinkerForBinary.cpp  |  14 +-
 llvm/tools/dsymutil/LinkUtils.h               |   5 +
 llvm/tools/dsymutil/MachOUtils.cpp            |   7 +-
 llvm/tools/dsymutil/MachOUtils.h              |   4 +-
 llvm/tools/dsymutil/Options.td                |   6 +
 llvm/tools/dsymutil/SymbolMap.cpp             | 157 ++++++++++++++
 llvm/tools/dsymutil/SymbolMap.h               |  53 +++++
 llvm/tools/dsymutil/dsymutil.cpp              |  15 +-
 llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp |   6 +-
 30 files changed, 555 insertions(+), 28 deletions(-)
 create mode 100644 llvm/test/tools/dsymutil/ARM/obfuscated.test
 create mode 100644 llvm/test/tools/dsymutil/Inputs/obfuscated.2.arm64
 create mode 100644 llvm/test/tools/dsymutil/Inputs/obfuscated.2.map
 create mode 100644 llvm/test/tools/dsymutil/Inputs/obfuscated.arm64
 create mode 100644 llvm/test/tools/dsymutil/Inputs/obfuscated.map
 create mode 100644 llvm/tools/dsymutil/SymbolMap.cpp
 create mode 100644 llvm/tools/dsymutil/SymbolMap.h

diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst
index e3f2f33224b015..af9d7f16b36196 100644
--- a/llvm/docs/CommandGuide/dsymutil.rst
+++ b/llvm/docs/CommandGuide/dsymutil.rst
@@ -140,6 +140,10 @@ OPTIONS
  (in bytes) to the linked dSYM. The table is sorted by the output size listing
  the object files with the largest contribution first.
 
+.. option:: --symbol-map <bcsymbolmap>
+
+ Update the existing dSYMs inplace using symbol map specified.
+
 .. option:: -s, --symtab
 
  Dumps the symbol table found in *executable* or object file(s) and exits.
diff --git a/llvm/include/llvm/CodeGen/NonRelocatableStringpool.h b/llvm/include/llvm/CodeGen/NonRelocatableStringpool.h
index 4b8eed7bdb1b53..3dc0731f5a04ee 100644
--- a/llvm/include/llvm/CodeGen/NonRelocatableStringpool.h
+++ b/llvm/include/llvm/CodeGen/NonRelocatableStringpool.h
@@ -27,7 +27,10 @@ class NonRelocatableStringpool {
   /// order.
   using MapTy = StringMap<DwarfStringPoolEntry, BumpPtrAllocator>;
 
-  NonRelocatableStringpool(bool PutEmptyString = false) {
+  NonRelocatableStringpool(
+      std::function<StringRef(StringRef Input)> Translator = nullptr,
+      bool PutEmptyString = false)
+      : Translator(Translator) {
     if (PutEmptyString)
       getEntry("");
   }
@@ -56,6 +59,7 @@ class NonRelocatableStringpool {
   MapTy Strings;
   uint64_t CurrentEndOffset = 0;
   unsigned NumEntries = 0;
+  std::function<StringRef(StringRef Input)> Translator;
 };
 
 /// Helper for making strong types.
diff --git a/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h
index e7a1a3cd838c22..bebdfd5e60257e 100644
--- a/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h
+++ b/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h
@@ -45,13 +45,16 @@ class DwarfStreamer : public DwarfEmitter {
 public:
   DwarfStreamer(DWARFLinkerBase::OutputFileType OutFileType,
                 raw_pwrite_stream &OutFile,
+                DWARFLinkerBase::TranslatorFuncTy Translator,
                 DWARFLinkerBase::MessageHandlerTy Warning)
-      : OutFile(OutFile), OutFileType(OutFileType), WarningHandler(Warning) {}
+      : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator),
+        WarningHandler(Warning) {}
   virtual ~DwarfStreamer() = default;
 
   static Expected<std::unique_ptr<DwarfStreamer>> createStreamer(
       const Triple &TheTriple, DWARFLinkerBase::OutputFileType FileType,
-      raw_pwrite_stream &OutFile, DWARFLinkerBase::MessageHandlerTy Warning);
+      raw_pwrite_stream &OutFile, DWARFLinkerBase::TranslatorFuncTy Translator,
+      DWARFLinkerBase::MessageHandlerTy Warning);
 
   Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName);
 
@@ -292,6 +295,7 @@ class DwarfStreamer : public DwarfEmitter {
   /// The output file we stream the linked Dwarf to.
   raw_pwrite_stream &OutFile;
   DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
+  std::function<StringRef(StringRef Input)> Translator;
 
   uint64_t RangesSectionSize = 0;
   uint64_t RngListsSectionSize = 0;
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
index 70b25cf02df7f8..5c811b668f0a31 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
@@ -82,6 +82,7 @@ class DWARFLinkerBase {
       std::function<void(const DWARFFile &File, llvm::StringRef Output)>;
   using ObjectPrefixMapTy = std::map<std::string, std::string>;
   using CompileUnitHandlerTy = function_ref<void(const DWARFUnit &Unit)>;
+  using TranslatorFuncTy = std::function<StringRef(StringRef)>;
   using SwiftInterfacesMapTy = std::map<std::string, std::string>;
   /// Type of output file.
   enum class OutputFileType : uint8_t {
diff --git a/llvm/include/llvm/DWARFLinker/Parallel/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/Parallel/DWARFLinker.h
index 8acc046d072493..5312712a4a5b81 100644
--- a/llvm/include/llvm/DWARFLinker/Parallel/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/Parallel/DWARFLinker.h
@@ -123,7 +123,8 @@ class DWARFLinker : public DWARFLinkerBase {
 
   /// Creates dwarf linker instance.
   static std::unique_ptr<DWARFLinker>
-  createLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler);
+  createLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
+               TranslatorFuncTy StringsTranslator = nullptr);
 
   /// Set output DWARF handler. Result of linking DWARF is set of sections
   /// containing final debug info. DWARFLinkerBase::link() pass generated
diff --git a/llvm/lib/CodeGen/NonRelocatableStringpool.cpp b/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
index 26857c6a40889d..e8391afb8e3f8d 100644
--- a/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
+++ b/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
@@ -12,6 +12,8 @@
 namespace llvm {
 
 DwarfStringPoolEntryRef NonRelocatableStringpool::getEntry(StringRef S) {
+  if (Translator)
+    S = Translator(S);
   auto I = Strings.insert({S, DwarfStringPoolEntry()});
   auto &Entry = I.first->second;
   if (I.second || !Entry.isIndexed()) {
@@ -26,6 +28,9 @@ DwarfStringPoolEntryRef NonRelocatableStringpool::getEntry(StringRef S) {
 StringRef NonRelocatableStringpool::internString(StringRef S) {
   DwarfStringPoolEntry Entry{nullptr, 0, DwarfStringPoolEntry::NotIndexed};
 
+  if (Translator)
+    S = Translator(S);
+
   auto InsertResult = Strings.insert({S, Entry});
   return InsertResult.first->getKey();
 }
diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
index 60f664ece7eef9..9b581a6c9ab774 100644
--- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
@@ -2701,8 +2701,8 @@ Error DWARFLinker::link() {
   // This Dwarf string pool which is used for emission. It must be used
   // serially as the order of calling getStringOffset matters for
   // reproducibility.
-  OffsetsStringPool DebugStrPool(true);
-  OffsetsStringPool DebugLineStrPool(false);
+  OffsetsStringPool DebugStrPool(StringsTranslator, true);
+  OffsetsStringPool DebugLineStrPool(StringsTranslator, false);
   DebugDieValuePool StringOffsetPool;
 
   // ODR Contexts for the optimize.
diff --git a/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp
index 8b31b5ead29ad0..6d522370e440d1 100644
--- a/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp
+++ b/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp
@@ -32,9 +32,10 @@ using namespace dwarf_linker::classic;
 
 Expected<std::unique_ptr<DwarfStreamer>> DwarfStreamer::createStreamer(
     const Triple &TheTriple, DWARFLinkerBase::OutputFileType FileType,
-    raw_pwrite_stream &OutFile, DWARFLinkerBase::MessageHandlerTy Warning) {
+    raw_pwrite_stream &OutFile, DWARFLinkerBase::TranslatorFuncTy Translator,
+    DWARFLinkerBase::MessageHandlerTy Warning) {
   std::unique_ptr<DwarfStreamer> Streamer =
-      std::make_unique<DwarfStreamer>(FileType, OutFile, Warning);
+      std::make_unique<DwarfStreamer>(FileType, OutFile, Translator, Warning);
   if (Error Err = Streamer->init(TheTriple, "__DWARF"))
     return std::move(Err);
 
@@ -976,10 +977,11 @@ void DwarfStreamer::emitLineTableString(const DWARFDebugLine::Prologue &P,
 
   switch (String.getForm()) {
   case dwarf::DW_FORM_string: {
-    StringRef Str = *StringVal;
-    Asm->OutStreamer->emitBytes(Str.data());
+    StringRef TranslatedString =
+        (Translator) ? Translator(*StringVal) : *StringVal;
+    Asm->OutStreamer->emitBytes(TranslatedString.data());
     Asm->emitInt8(0);
-    LineSectionSize += Str.size() + 1;
+    LineSectionSize += TranslatedString.size() + 1;
   } break;
   case dwarf::DW_FORM_strp:
   case dwarf::DW_FORM_line_strp: {
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinker.cpp
index 31c7e867767a0f..ad8d28a643174a 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinker.cpp
@@ -15,6 +15,8 @@ using namespace dwarf_linker::parallel;
 
 std::unique_ptr<DWARFLinker>
 DWARFLinker::createLinker(MessageHandlerTy ErrorHandler,
-                          MessageHandlerTy WarningHandler) {
-  return std::make_unique<DWARFLinkerImpl>(ErrorHandler, WarningHandler);
+                          MessageHandlerTy WarningHandler,
+                          TranslatorFuncTy StringsTranslator) {
+  return std::make_unique<DWARFLinkerImpl>(ErrorHandler, WarningHandler,
+                                           StringsTranslator);
 }
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
index 7ca81eb34f005e..38c261a8106fcd 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
@@ -21,6 +21,7 @@ class DWARFDie;
 namespace dwarf_linker {
 namespace parallel {
 
+using TranslatorFuncTy = std::function<StringRef(StringRef)>;
 using MessageHandlerTy = std::function<void(
     const Twine &Warning, StringRef Context, const DWARFDie *DIE)>;
 
@@ -94,6 +95,19 @@ class LinkingGlobalData {
   /// Returns global string pool.
   StringPool &getStringPool() { return Strings; }
 
+  /// Set translation function.
+  void setTranslator(TranslatorFuncTy Translator) {
+    this->Translator = Translator;
+  }
+
+  /// Translate specified string.
+  StringRef translateString(StringRef String) {
+    if (Translator)
+      return Translator(String);
+
+    return String;
+  }
+
   /// Returns linking options.
   const DWARFLinkerOptions &getOptions() const { return Options; }
 
@@ -147,6 +161,7 @@ class LinkingGlobalData {
 protected:
   llvm::parallel::PerThreadBumpPtrAllocator Allocator;
   StringPool Strings;
+  TranslatorFuncTy Translator;
   DWARFLinkerOptions Options;
   MessageHandlerTy WarningHandler;
   MessageHandlerTy ErrorHandler;
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
index e68bf0c227a0a0..49b08997eb9c1c 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
@@ -20,9 +20,11 @@ using namespace dwarf_linker;
 using namespace dwarf_linker::parallel;
 
 DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
-                                 MessageHandlerTy WarningHandler)
+                                 MessageHandlerTy WarningHandler,
+                                 TranslatorFuncTy StringsTranslator)
     : UniqueUnitID(0), DebugStrStrings(GlobalData),
       DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
+  GlobalData.setTranslator(StringsTranslator);
   GlobalData.setErrorHandler(ErrorHandler);
   GlobalData.setWarningHandler(WarningHandler);
 }
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
index 597bb1b4da59a8..7c17c5b79c7c18 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
@@ -26,7 +26,8 @@ namespace parallel {
 class DWARFLinkerImpl : public DWARFLinker {
 public:
   DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
-                  MessageHandlerTy WarningHandler);
+                  MessageHandlerTy WarningHandler,
+                  TranslatorFuncTy StringsTranslator);
 
   /// Add object file to be linked. Pre-load compile unit die. Call
   /// \p OnCUDieLoaded for each compile unit die. If specified \p File
diff --git a/llvm/lib/DWARFLinker/Parallel/OutputSections.h b/llvm/lib/DWARFLinker/Parallel/OutputSections.h
index 0e1f2dae54bcc2..a21e4b2b75a503 100644
--- a/llvm/lib/DWARFLinker/Parallel/OutputSections.h
+++ b/llvm/lib/DWARFLinker/Parallel/OutputSections.h
@@ -253,7 +253,7 @@ struct SectionDescriptor : SectionDescriptorBase {
 
   /// Emit specified inplace string value into the current section contents.
   void emitInplaceString(StringRef String) {
-    OS << String;
+    OS << GlobalData.translateString(String);
     emitIntVal(0, 1);
   }
 
diff --git a/llvm/lib/DWARFLinker/Parallel/StringEntryToDwarfStringPoolEntryMap.h b/llvm/lib/DWARFLinker/Parallel/StringEntryToDwarfStringPoolEntryMap.h
index f67536ef7a1a84..858f224777dba7 100644
--- a/llvm/lib/DWARFLinker/Parallel/StringEntryToDwarfStringPoolEntryMap.h
+++ b/llvm/lib/DWARFLinker/Parallel/StringEntryToDwarfStringPoolEntryMap.h
@@ -33,7 +33,7 @@ class StringEntryToDwarfStringPoolEntryMap {
       DwarfStringPoolEntryWithExtString *DataPtr =
           GlobalData.getAllocator()
               .Allocate<DwarfStringPoolEntryWithExtString>();
-      DataPtr->String = String->getKey();
+      DataPtr->String = GlobalData.translateString(String->getKey());
       DataPtr->Index = DwarfStringPoolEntry::NotIndexed;
       DataPtr->Offset = 0;
       DataPtr->Symbol = nullptr;
diff --git a/llvm/test/tools/dsymutil/ARM/obfuscated.test b/llvm/test/tools/dsymutil/ARM/obfuscated.test
new file mode 100644
index 00000000000000..3443b8e634692b
--- /dev/null
+++ b/llvm/test/tools/dsymutil/ARM/obfuscated.test
@@ -0,0 +1,200 @@
+REQUIRES: system-darwin
+
+RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck %s
+
+RUN: dsymutil --accelerator=Pub --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=PUB %s
+
+RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=NOHIDDEN %s
+
+RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.2.map %p/../Inputs/obfuscated.2.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=NOHIDDEN %s
+
+// Run with plist and make sure dsymutil finds it.
+RUN: mkdir -p %t.dSYM/Contents/Resources/DWARF/
+RUN: mkdir -p %t.mapdir
+RUN: cp %p/../Inputs/obfuscated.arm64 %t.dSYM/Contents/Resources/DWARF/
+RUN: cp %p/../Inputs/E828A486-8433-3A5E-B6DB-A6294D28133D.plist %t.dSYM/Contents/Resources/
+RUN: cp %p/../Inputs/obfuscated.map %t.mapdir/506AA50A-6B26-3B37-86D2-DC6EBD57B720.bcsymbolmap
+RUN: dsymutil --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=OBFUSCATING %s
+
+// Run without plist and make sure dsymutil doesn't crash.
+RUN: rm %t.dSYM/Contents/Resources/E828A486-8433-3A5E-B6DB-A6294D28133D.plist
+RUN: dsymutil --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=NOTOBFUSCATING %s
+
+// ----------------------------------------
+// Repeat the same steps for --linker parallel.
+RUN: dsymutil --linker parallel --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck %s
+
+RUN: dsymutil --linker parallel --accelerator=Pub --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=PUB %s
+
+RUN: dsymutil --linker parallel --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=NOHIDDEN %s
+
+RUN: dsymutil --linker parallel --symbol-map %p/../Inputs/obfuscated.2.map %p/../Inputs/obfuscated.2.arm64 -f -o - \
+RUN:     | llvm-dwarfdump -v - \
+RUN:     | FileCheck --check-prefix=NOHIDDEN %s
+
+// Run with plist and make sure dsymutil finds it.
+RUN: mkdir -p %t.dSYM/Contents/Resources/DWARF/
+RUN: mkdir -p %t.mapdir
+RUN: cp %p/../Inputs/obfuscated.arm64 %t.dSYM/Contents/Resources/DWARF/
+RUN: cp %p/../Inputs/E828A486-8433-3A5E-B6DB-A6294D28133D.plist %t.dSYM/Contents/Resources/
+RUN: cp %p/../Inputs/obfuscated.map %t.mapdir/506AA50A-6B26-3B37-86D2-DC6EBD57B720.bcsymbolmap
+RUN: dsymutil --linker parallel --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=OBFUSCATING %s
+
+// Run without plist and make sure dsymutil doesn't crash.
+RUN: rm %t.dSYM/Contents/Resources/E828A486-8433-3A5E-B6DB-A6294D28133D.plist
+RUN: dsymutil --linker parallel --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=NOTOBFUSCATING %s
+
+OBFUSCATING-NOT: not unobfuscating
+
+NOTOBFUSCATING: not unobfuscating
+
+NOHIDDEN-NOT: __hidden#
+
+CHECK: .debug_info contents:
+
+CHECK: DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "main.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "main")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "one.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "one")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "two.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "two")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "three.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "three")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "four.c")
+CHECK:    DW_AT_stmt_list [DW_FORM_data4]  (0x0000011e)
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "four")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "five.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "five")
+
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]    ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
+CHECK:    DW_AT_name [DW_FORM_strp]        ( {{.*}} "six.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]    ( {{.*}} "/Users/steven/dev/alpena/tests/src")
+CHECK:    DW_TAG_subprogram [2]
+CHECK:      DW_AT_name [DW_FORM_strp]      ( {{.*}} "six")
+
+CHECK: .debug_line contents:
+CHECK: file_names[  1]:
+CHECK:            name: "main.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "one.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "two.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "three.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "four.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "five.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+CHECK: file_names[  1]:
+CHECK:            name: "six.c"
+CHECK:       dir_index: 0
+CHECK:        mod_time: 0x00000000
+CHECK:          length: 0x00000000
+
+PUB: .debug_pubnames contents:
+PUB: length = 0x00000017, format = DWARF32, version = 0x0002, unit_offset = 0x00000000, unit_size = 0x00000044
+PUB: 0x0000002e "main"
+PUB: length = 0x00000016, format = DWARF32, version = 0x0002, unit_offset = 0x00000044, unit_size = 0x00000044
+PUB: 0x0000002e "one"
+PUB: length = 0x00000016, format = DWARF32, version = 0x0002, unit_offset = 0x00000088, unit_size = 0x00000044
+PUB: 0x0000002e "two"
+PUB: length = 0x00000018, format = DWARF32, version = 0x0002, unit_offset = 0x000000cc, unit_size = 0x00000044
+PUB: 0x0000002e "three"
+PUB: length = 0x00000017, format = DWARF32, version = 0x0002, unit_offset = 0x00000110, unit_size = 0x00000044
+PUB: 0x0000002e "four"
+PUB: length = 0x00000017, format = DWARF32, version = 0x0002, unit_offset = 0x00000154, unit_size = 0x00000044
+PUB: 0x0000002e "five"
+PUB: length = 0x00000016, format = DWARF32, version = 0x0002, unit_offset = 0x00000198, unit_size = 0x00000044
+PUB: 0x0000002e "six"
+
+CHECK: .apple_names contents:
+
+CHECK: String: 0x00000091 "five"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x00000182
+CHECK-NEXT: ]
+CHECK: String: 0x0000009c "six"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x000001c6
+CHECK-NEXT: ]
+CHECK: String: 0x00000078 "three"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x000000fa
+CHECK-NEXT: ]
+CHECK: String: 0x0000006c "two"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x000000b6
+CHECK-NEXT: ]
+CHECK: String: 0x00000057 "main"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x0000002e
+CHECK-NEXT: ]
+CHECK: String: 0x00000085 "four"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x0000013e
+CHECK-NEXT: ]
+CHECK: String: 0x00000062 "one"
+CHECK-NEXT: Data 0 [
+CHECK-NEXT:   Atom[0]: 0x00000072
+CHECK-NEXT: ]
diff --git a/llvm/test/tools/dsymutil/Inputs/obfuscated.2.arm64 b/llvm/test/tools/dsymutil/Inputs/obfuscated.2.arm64
new file mode 100644
index 0000000000000000000000000000000000000000..b40e023eb4916cca1fe38388ce12b030c1a51eda
GIT binary patch
literal 10339
zcmeHNO>A355Pr|jbJ8?*5>i!-f<mAz6jY#YY4{1ESZN at 6<tGY(0s^i4^GIAdwy_;Z
zq^hw{4hSwtRDxcRkjjA*qUxdT1rCS{pk6q at k)K1Qs1nFGkODJrXV%aAY$v(Gjx>Hd
zv$NmM&dzSK``(SeZf*8imTdv`0(S%7jG-iH1Rnc=cYk|r at Y9)zKR<l-yUomzmu^K!
zZw**h50q>0Ov7^+cp6xU+2qqxuTIT94}wO1XPQnI5$7i`6k>kr<@x4XzkRJ)$C3jD
zX4DB$^;W7}8^-(Nyd3<6hKYq^Q`BYER2d3FRI1DAic;zRt*=Quh^eCBczXzs>m{C8
z^ztRI3 at voL4+!s|LbJB;FH@<ObA<)6*YU0pURMAwSZo?QR0y$Lcsp0fid^B1qAxek
z$5q0^IcL%_SdUMf*PFmXoJ!6oQA1RtBz%$;&Ce)^$c!z-LNPF{ZSf#26=8cOO!45n
z2$4^T%IZ?Om=~pLIfOS*llGYFOhG(cH$l0v4xX8L?)22DnR#mUwKh(2 at K>rvpMriN
z&LRLqyv`)&o+2xJ*wT&%I3}wy<RJTlYZ^(2te0M15cyoelX7dkI(I&XR_%%LQsq=(
z!K;M)tJ~7QS;DK|*&YjP7_YRPE~J*ciay at SsKl!i%;bUX;ZfR#{2T9*c)yW<<G}^i
z0-F6xrPF2at?+yd$0Xie)OPsp79ar?<H2I}wfcA`2=9ApGqELJs#MB*!Vey_(eb*w
zrGLK at UiUpzX!8&vfLBUobi571<FIXP6R)~jf@}%<*WV-kJ4*iaA8z9qsoB3``fLVO
zx_>7LkNrEj1zzXgOs$E4iGYcKiGYcKiGYc~e<uQXo*K2~Ap-vu-sj7f#pmMNNq&va
zdH0f>C3&3WJjs(JS4o~F`5eiwgWL}t&6AA(xh*XUZ^g?jS3Nifr?PMk7E7sI0cylz
zE}QiV2abw>kO&ILg2M5j at DK<^dDwwI4Veg-2$%?%2$%?%2$%?%2$%?%2$%?%2$%@`
zpCf=TPa+n+wX*HM<9py2UflVwAZ<8u)A9RZAw#q)!q)=PUfUVytvmZ;?>PHhXUug*
zUFSa6IqW*eT_ at o>kGsxet`m)&u1EF)=o5Z7_|C3FHwifA`?M><*8 at XNw09`dvuy;p
z4j=@+u-GXATpJJqUvcadVO$~brN~YZ9#IH<jj}_8V~t4i#Y+R>2#gP}edLE5jjNul
zuM7W3`zdA5a}#_O9&9D;-&6KH6P at jED0_~3XZyX7rqY6=+}ZvWWzR9~Z2yU}=Loj5
z9|g~4JTXQO0;`2XsUR(|He~Uroa#G#42)UGA_4bZNYVtu6gGj2uZ9UmCTwydXoA5A
zo6s_s9pU)HCgg4sdZQHbw~Ib&kMDr|zQg8Sf-^;J8>~2l)?ttYXcvI-qX(O9IepZg
zzzW<`T7bBq{T$c_VO!3rh^{!(8U)wE27_>8PPB-wc(XOgc~IXEVe~!W#?>`{ceNtA
z;{DbjAA`EcAl&#IgXoIST7z5$^_L97jn^4OSA2ya_Mm+z4x2`NAT|>JWvy?}z6}5(
z4_H`;#?eHj`3bytZTziJW!T458J2=7<3_IpNGVlL_}96Fgo)p%!RuV^BjI24vRM;y
z(3M26{{&>W0>J%I2?_9E`i0~)4A1}k4L_af!|?&3&bIJlA(`+|cy<9h!2bYYP50av
z2VY#dc>OFqM^-Oh{|L%Mz&``yCrazU7l1DTUjhCG_(xz|1c;A21`=iw%9|(vVSb~G
z7)UrRDF1*zK$tLCoFo}j8H?9|kuVofewXTbj3kD}h~v?1 at Y6pe95cot3L|%{-B618
L<Jax=xFP1h4!zc3

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/dsymutil/Inputs/obfuscated.2.map b/llvm/test/tools/dsymutil/Inputs/obfuscated.2.map
new file mode 100644
index 00000000000000..6efca5960311d6
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/obfuscated.2.map
@@ -0,0 +1,22 @@
+BCSymbolMap Version: 2.0
+_two
+_three
+_four
+_five
+_six
+LLVM version 3.9.0 (ssh://git@stash.sd.apple.com/devtools/clang.git c74ae34bd917b77f9c848bd599dfde2813fb509f)
+main
+main.c
+/Volumes/Data/dev/BitcodeBuildTests/unit
+one
+one.c
+two
+two.c
+three
+three.c
+four
+four.c
+five
+five.c
+six
+six.c
diff --git a/llvm/test/tools/dsymutil/Inputs/obfuscated.arm64 b/llvm/test/tools/dsymutil/Inputs/obfuscated.arm64
new file mode 100644
index 0000000000000000000000000000000000000000..8395798be17ff1aaea4397cd38c2b0f26f465cb0
GIT binary patch
literal 10434
zcmeHNO>7%Q6y9BDoiv0rZ4nA8Y649lMW~7i2~a^5LqhWdC4@*Igc#ZJCUNE1R_s7p
zA&5+bdV>Q8Bv4Ng;({twRaJ4K2sjmS;edc6sv;z~lv6>J at 9n&|S&uhq(j)AXo at d^h
zZ@!&*GduP^@Ao%;|EJBeYzxu~ZH8_n$<lHVMJIHlZ~eWsfn%><`uWo%&-Wd8%3;6N
zVOcGxucADK@*e0IRH>=-iP2X_r(b|!h<`D|XPU(GBY;ZHjJ`5c-|F{Yt at nxLq9RH@
zrK;XaRazVQF2AiOe{~aL(cA)QvQ~pSDoRzV%h^icGRL>}j^;y50}0Q!h54ji^Qi@|
zQ1+J4!{qyb`Fa92>lWjityGut#d*e?d>5IoDa049*3BIaN-Y=P%olSiUz{uXcKv!>
zW<FYT5tBpwRMNU`K$RLv&!ox2vdWuqSRD0b0w$?&D>YvVE$fzi*p`7%e-YZ^;dN1}
zkWrP>i`h~^m8(k)d>yMAPkUV?%t!Z4*xtMko*O?oIXW^fd-zLZo;<+cn3Tp89vAT}
zfEe+5IX(R>qo}YoPA1r`o4(=!%6RCWCQ&NqWtZnwCYxRI-q at P2OT#UzTPo3Iz_*ks
z&U=-H at pbX|rg$=4JLKbS*1%V?^?ZL}zS4cs;}WlouaGZ#<TK+pnb3THGvDN4=^0%L
zUwJuO%q)5plkbG9`TpSUCwilK#4CKbS$&tuH<;9XDIVY81JX0PR4P+07d+(;4iJ-X
zu37W_%H8K4jOG!q at KsNjvAT_X6D^vrpF2$SNzdp~`26veGqdLS&M=>xb7ywQSIVB6
zr7N0z=M27cx8RE&b?l8J5Jw=6KpcTM0&xW52>kaVK+jWq at f&l7pX2tj{Tkc%vYli5
z2-^j=huE&N{S4c0u|4J6`XPmW%I3ITp1bLnn_9@{a$fOpzX}<tu<=OP7zi7WhK)fo
z78jJa;>|8sJv>!sa(Jp%i<x{8*Nr8PKpcTM0&xW52*eSHBM?U*jzAoNI0A75;t2d-
zBVg~dd)p7ViS~}<!S;RjemtW)M=h!(+7Xk7q53aZ{lB6-wtuokyfl6Utr{<B1#LBU
z()hChUeXTR<F5vINlR>x at 4&1yLedu7<7WcAq&2q3e-z*)?XeYp7$fI+;tx&BYO|ik
zC&@{uL|3Bbn2z at eISj4m_!yotlsKfXMA9)Gp8*uXaS`4NP~woj5?#l1TmdM8<2!i&
zgc67Jm54j0<0pV3IIh7vgwPO&^p#a`Ovm+Tj+=0=Fo*P&m2pf*8?D1I)PZ83 at Va!u
z{RMMK-!)EZIi{nRI0{h5x*wmm{a5>)`1GmJWFsxbIj$!Z+97*_wN13zZb$2Nw=+56
z-d%IMYwn?%`%um8tGNR;H&t_=thvW(Zgb7upPY0P$%$mk=gwVVKMoqlqW`V8xn2r+
zG+*`v8v%EF>!j1PV+JJOm_fF|ZW)lVV+Pp-yJbL{j~QeO?3Q6LV2};4TZW;4L6(1$
z;Sffr_Ya+YN1?%rKd!rJ1hqCGkoP3fh_g`$UPO(c)31Sp7fB=NylX)4B4`Aia196!
zvPRIE)_{;829tXX+1uNY&FJ8M2*^_Xw?U;s1PJvenV&!oXO_91@{`G8gnRgjWp1bg
z`AKGO2!m3HM{vO~D22TeGypXAQhE&W^xv+dH*?ycB;>QLq;(S_Hf^IOD80o-Zz;X|
z;`yFy&@6O(`h3qfDAUk&Xcg^i&<~;OP&&lFhW-Gh^Og8-KuPF~BKuqVfLwu6^%5Bn
z`feecHZKXCi)7d6147>$RMqdRSQeeVWFO~tnIoJ2TZ3r!=R$K#U`DQW2Woo0CO#@A
HJHh-5T*?4#

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/dsymutil/Inputs/obfuscated.map b/llvm/test/tools/dsymutil/Inputs/obfuscated.map
new file mode 100644
index 00000000000000..30fed8bf9b5a57
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/obfuscated.map
@@ -0,0 +1,17 @@
+one
+two
+three
+four
+five
+six
+.str
+Apple LLVM version 7.0.0 (clang-700.2.38.2)
+main
+main.c
+/Users/steven/dev/alpena/tests/src
+one.c
+two.c
+three.c
+four.c
+five.c
+six.c
diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test
index 814252b6e23067..36cf3f542695ca 100644
--- a/llvm/test/tools/dsymutil/cmdline.test
+++ b/llvm/test/tools/dsymutil/cmdline.test
@@ -28,6 +28,7 @@ CHECK: -remarks-output-format <format>
 CHECK: -remarks-prepend-path <path>
 CHECK: -reproducer <mode>
 CHECK: -statistics
+CHECK: -symbol-map
 CHECK: -symtab
 CHECK: {{-S}}
 CHECK: -toolchain
diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt
index efe28bda68ebf1..53f882e90b4e92 100644
--- a/llvm/tools/dsymutil/CMakeLists.txt
+++ b/llvm/tools/dsymutil/CMakeLists.txt
@@ -32,6 +32,7 @@ add_llvm_tool(dsymutil
   MachOUtils.cpp
   Reproducer.cpp
   RelocationMap.cpp
+  SymbolMap.cpp
 
   DEPENDS
   intrinsics_gen
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 677dfc44c54a40..5ae5ecd556adb7 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -634,19 +634,25 @@ bool DwarfLinkerForBinary::linkImpl(
 
   DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
 
+  std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
+    assert(Options.Translator);
+    return Options.Translator(Input);
+  };
+
   std::unique_ptr<Linker> GeneralLinker = Linker::createLinker(
       [&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
         reportError(Error, Context, DIE);
       },
       [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
         reportWarning(Warning, Context, DIE);
-      });
+      },
+      Options.Translator ? TranslationLambda : nullptr);
 
   std::unique_ptr<classic::DwarfStreamer> Streamer;
   if (!Options.NoOutput) {
     if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
             classic::DwarfStreamer::createStreamer(
-                Map.getTriple(), ObjectType, OutFile,
+                Map.getTriple(), ObjectType, OutFile, Options.Translator,
                 [&](const Twine &Warning, StringRef Context,
                     const DWARFDie *DIE) {
                   reportWarning(Warning, Context, DIE);
@@ -860,8 +866,8 @@ bool DwarfLinkerForBinary::linkImpl(
   if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
       ObjectType == Linker::OutputFileType::Object)
     return MachOUtils::generateDsymCompanion(
-        Options.VFS, Map, *Streamer->getAsmPrinter().OutStreamer, OutFile,
-        RelocationsToApply);
+        Options.VFS, Map, Options.Translator,
+        *Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply);
 
   Streamer->finish();
   return true;
diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h
index 6aa0b847eebd67..fd9d985097d6e2 100644
--- a/llvm/tools/dsymutil/LinkUtils.h
+++ b/llvm/tools/dsymutil/LinkUtils.h
@@ -9,6 +9,8 @@
 #ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
 #define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
 
+#include "SymbolMap.h"
+
 #include "llvm/ADT/Twine.h"
 #include "llvm/Remarks/RemarkFormat.h"
 #include "llvm/Support/VirtualFileSystem.h"
@@ -85,6 +87,9 @@ struct LinkOptions {
   /// The Resources directory in the .dSYM bundle.
   std::optional<std::string> ResourceDir;
 
+  /// Symbol map translator.
+  SymbolMapTranslator Translator;
+
   /// Virtual File System.
   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       vfs::getRealFileSystem();
diff --git a/llvm/tools/dsymutil/MachOUtils.cpp b/llvm/tools/dsymutil/MachOUtils.cpp
index 8e144d640ed01f..3efc1aff823744 100644
--- a/llvm/tools/dsymutil/MachOUtils.cpp
+++ b/llvm/tools/dsymutil/MachOUtils.cpp
@@ -373,7 +373,7 @@ static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {
 // \a OutFile and it must be using a MachObjectWriter object to do so.
 bool generateDsymCompanion(
     llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const DebugMap &DM,
-    MCStreamer &MS, raw_fd_ostream &OutFile,
+    SymbolMapTranslator &Translator, MCStreamer &MS, raw_fd_ostream &OutFile,
     const std::vector<MachOUtils::DwarfRelocationApplicationInfo>
         &RelocationsToApply) {
   auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);
@@ -509,9 +509,12 @@ bool generateDsymCompanion(
   }
 
   SmallString<0> NewSymtab;
+  std::function<StringRef(StringRef)> TranslationLambda =
+      Translator ? [&](StringRef Input) { return Translator(Input); }
+                 : static_cast<std::function<StringRef(StringRef)>>(nullptr);
   // Legacy dsymutil puts an empty string at the start of the line table.
   // thus we set NonRelocatableStringpool(,PutEmptyString=true)
-  NonRelocatableStringpool NewStrings(true);
+  NonRelocatableStringpool NewStrings(TranslationLambda, true);
   unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
   unsigned NumSyms = 0;
   uint64_t NewStringsSize = 0;
diff --git a/llvm/tools/dsymutil/MachOUtils.h b/llvm/tools/dsymutil/MachOUtils.h
index 0229647b00f85c..059d9fdd788a66 100644
--- a/llvm/tools/dsymutil/MachOUtils.h
+++ b/llvm/tools/dsymutil/MachOUtils.h
@@ -8,6 +8,8 @@
 #ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
 #define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
 
+#include "SymbolMap.h"
+
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/VirtualFileSystem.h"
@@ -57,7 +59,7 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
                              StringRef SDKPath, bool Fat64 = false);
 bool generateDsymCompanion(
     llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const DebugMap &DM,
-    MCStreamer &MS, raw_fd_ostream &OutFile,
+    SymbolMapTranslator &Translator, MCStreamer &MS, raw_fd_ostream &OutFile,
     const std::vector<MachOUtils::DwarfRelocationApplicationInfo>
         &RelocationsToApply);
 
diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td
index d8cec0cb2c410d..a4e4c6c4cdb9c0 100644
--- a/llvm/tools/dsymutil/Options.td
+++ b/llvm/tools/dsymutil/Options.td
@@ -128,6 +128,12 @@ def object_prefix_map: Separate<["--", "-"], "object-prefix-map">,
     Group<grp_general>;
 def: Joined<["--", "-"], "object-prefix-map=">, Alias<object_prefix_map>;
 
+def symbolmap: Separate<["--", "-"], "symbol-map">,
+  MetaVarName<"<bcsymbolmap>">,
+  HelpText<"Updates the existing dSYMs inplace using symbol map specified.">,
+  Group<grp_general>;
+def: Joined<["--", "-"], "symbol-map=">, Alias<symbolmap>;
+
 def arch: Separate<["--", "-"], "arch">,
   MetaVarName<"<arch>">,
   HelpText<"Link DWARF debug information only for specified CPU architecture"
diff --git a/llvm/tools/dsymutil/SymbolMap.cpp b/llvm/tools/dsymutil/SymbolMap.cpp
new file mode 100644
index 00000000000000..c55362e5f77563
--- /dev/null
+++ b/llvm/tools/dsymutil/SymbolMap.cpp
@@ -0,0 +1,157 @@
+//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolMap.h"
+#include "DebugMap.h"
+#include "MachOUtils.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#include <uuid/uuid.h>
+#endif
+
+namespace llvm {
+namespace dsymutil {
+
+StringRef SymbolMapTranslator::operator()(StringRef Input) {
+  if (!Input.starts_with("__hidden#") && !Input.starts_with("___hidden#"))
+    return Input;
+
+  StringRef Line = Input.drop_front(sizeof("__hidden#") - 1);
+  bool MightNeedUnderscore = Line.consume_front("#");
+
+  std::size_t LineNumber = std::numeric_limits<std::size_t>::max();
+  Line.split('_').first.getAsInteger(10, LineNumber);
+  if (LineNumber >= UnobfuscatedStrings.size()) {
+    WithColor::warning() << "reference to a unexisting unobfuscated string "
+                         << Input << ": symbol map mismatch?\n"
+                         << Line << '\n';
+    return Input;
+  }
+
+  const std::string &Translation = UnobfuscatedStrings[LineNumber];
+  if (!MightNeedUnderscore || !MangleNames)
+    return Translation;
+
+  // Objective-C symbols for the MachO symbol table start with a \1. Please see
+  // `MangleContext::mangleObjCMethodName` in clang.
+  if (Translation[0] == 1)
+    return StringRef(Translation).drop_front();
+
+  // We need permanent storage for the string we are about to create. Just
+  // append it to the vector containing translations. This should only happen
+  // during MachO symbol table translation, thus there should be no risk on
+  // exponential growth.
+  UnobfuscatedStrings.emplace_back("_" + Translation);
+  return UnobfuscatedStrings.back();
+}
+
+SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile,
+                                          const DebugMap &Map) const {
+  if (SymbolMap.empty())
+    return {};
+
+  std::string SymbolMapPath = SymbolMap;
+
+#if __APPLE__
+  // Look through the UUID Map.
+  if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) {
+    uuid_string_t UUIDString;
+    uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString);
+
+    SmallString<256> PlistPath(
+        sys::path::parent_path(sys::path::parent_path(InputFile)));
+    sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist");
+
+    CFStringRef plistFile = CFStringCreateWithCString(
+        kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8);
+    CFURLRef fileURL = CFURLCreateWithFileSystemPath(
+        kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false);
+    CFReadStreamRef resourceData =
+        CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
+    if (resourceData) {
+      CFReadStreamOpen(resourceData);
+      CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream(
+          kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable,
+          nullptr, nullptr);
+
+      if (plist) {
+        if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) {
+          CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue(
+              plist, CFSTR("DBGOriginalUUID"));
+
+          StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8));
+          SmallString<256> BCSymbolMapPath(SymbolMapPath);
+          sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap");
+          SymbolMapPath = std::string(BCSymbolMapPath);
+        }
+        CFRelease(plist);
+      }
+      CFReadStreamClose(resourceData);
+      CFRelease(resourceData);
+    }
+    CFRelease(fileURL);
+    CFRelease(plistFile);
+  }
+#endif
+
+  if (sys::fs::is_directory(SymbolMapPath)) {
+    SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" +
+                      MachOUtils::getArchName(Map.getTriple().getArchName()) +
+                      ".bcsymbolmap")
+                         .str();
+  }
+
+  auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath);
+  if (auto EC = ErrOrMemBuffer.getError()) {
+    WithColor::warning() << SymbolMapPath << ": " << EC.message()
+                         << ": not unobfuscating.\n";
+    return {};
+  }
+
+  std::vector<std::string> UnobfuscatedStrings;
+  auto &MemBuf = **ErrOrMemBuffer;
+  StringRef Data(MemBuf.getBufferStart(),
+                 MemBuf.getBufferEnd() - MemBuf.getBufferStart());
+  StringRef LHS;
+  std::tie(LHS, Data) = Data.split('\n');
+  bool MangleNames = false;
+
+  // Check version string first.
+  if (!LHS.starts_with("BCSymbolMap Version:")) {
+    // Version string not present, warns but try to parse it.
+    WithColor::warning() << SymbolMapPath
+                         << " is missing version string: assuming 1.0.\n";
+    UnobfuscatedStrings.emplace_back(LHS);
+  } else if (LHS.equals("BCSymbolMap Version: 1.0")) {
+    MangleNames = true;
+  } else if (LHS.equals("BCSymbolMap Version: 2.0")) {
+    MangleNames = false;
+  } else {
+    StringRef VersionNum;
+    std::tie(LHS, VersionNum) = LHS.split(':');
+    WithColor::warning() << SymbolMapPath
+                         << " has unsupported symbol map version" << VersionNum
+                         << ": not unobfuscating.\n";
+    return {};
+  }
+
+  while (!Data.empty()) {
+    std::tie(LHS, Data) = Data.split('\n');
+    UnobfuscatedStrings.emplace_back(LHS);
+  }
+
+  return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames);
+}
+
+} // namespace dsymutil
+} // namespace llvm
diff --git a/llvm/tools/dsymutil/SymbolMap.h b/llvm/tools/dsymutil/SymbolMap.h
new file mode 100644
index 00000000000000..977de31a5a17ac
--- /dev/null
+++ b/llvm/tools/dsymutil/SymbolMap.h
@@ -0,0 +1,53 @@
+//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
+#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace dsymutil {
+class DebugMap;
+
+/// Callable class to unobfuscate strings based on a BCSymbolMap.
+class SymbolMapTranslator {
+public:
+  SymbolMapTranslator() : MangleNames(false) {}
+
+  SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings,
+                      bool MangleNames)
+      : UnobfuscatedStrings(std::move(UnobfuscatedStrings)),
+        MangleNames(MangleNames) {}
+
+  StringRef operator()(StringRef Input);
+
+  operator bool() const { return !UnobfuscatedStrings.empty(); }
+
+private:
+  std::vector<std::string> UnobfuscatedStrings;
+  bool MangleNames;
+};
+
+/// Class to initialize SymbolMapTranslators from a BCSymbolMap.
+class SymbolMapLoader {
+public:
+  SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {}
+
+  SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const;
+
+private:
+  const std::string SymbolMap;
+};
+} // namespace dsymutil
+} // namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index bc968b6387b653..25e281c415e75a 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -108,6 +108,7 @@ struct DsymutilOptions {
   bool Flat = false;
   bool InputIsYAMLDebugMap = false;
   bool ForceKeepFunctionForStatic = false;
+  std::string SymbolMap;
   std::string OutputFile;
   std::string Toolchain;
   std::string ReproducerPath;
@@ -340,6 +341,12 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
     return DWARFLinkerType.takeError();
   }
 
+  if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
+    Options.SymbolMap = SymbolMap->getValue();
+
+  if (Args.hasArg(OPT_symbolmap))
+    Options.LinkOpts.Update = true;
+
   if (Expected<std::vector<std::string>> InputFiles =
           getInputs(Args, Options.LinkOpts.Update)) {
     Options.InputFiles = std::move(*InputFiles);
@@ -553,7 +560,8 @@ getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) {
     return OutputLocation(Options.OutputFile);
 
   // When updating, do in place replacement.
-  if (Options.OutputFile.empty() && Options.LinkOpts.Update)
+  if (Options.OutputFile.empty() &&
+      (Options.LinkOpts.Update || !Options.SymbolMap.empty()))
     return OutputLocation(std::string(InputFile));
 
   // When dumping the debug map, just return an empty output location. This
@@ -660,6 +668,8 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
       return EXIT_FAILURE;
     }
 
+  SymbolMapLoader SymMapLoader(Options.SymbolMap);
+
   for (auto &InputFile : Options.InputFiles) {
     // Dump the symbol table for each input file and requested arch
     if (Options.DumpStab) {
@@ -750,6 +760,9 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
         if (Options.DumpDebugMap)
           continue;
 
+        if (!Options.SymbolMap.empty())
+          Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map);
+
         if (Map->begin() == Map->end()) {
           std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
           WithColor::warning()
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index 285dcf75ecd9d3..bd17f3c4a6595e 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -338,9 +338,9 @@ Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
   Triple TargetTriple = File.makeTriple();
   std::unique_ptr<classic::DwarfStreamer> Streamer;
   if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
-          classic::DwarfStreamer::createStreamer(TargetTriple,
-                                                 Linker::OutputFileType::Object,
-                                                 OutStream, ReportWarn))
+          classic::DwarfStreamer::createStreamer(
+              TargetTriple, Linker::OutputFileType::Object, OutStream, nullptr,
+              ReportWarn))
     Streamer = std::move(*StreamerOrErr);
   else
     return StreamerOrErr.takeError();



More information about the llvm-commits mailing list