[dsymutil] Have the YAML deserialization rewrite the object address of symbols.
authorFrederic Riss <friss@apple.com>
Fri, 5 Jun 2015 21:12:07 +0000 (21:12 +0000)
committerFrederic Riss <friss@apple.com>
Fri, 5 Jun 2015 21:12:07 +0000 (21:12 +0000)
The main use of the YAML debug map format is for testing inside LLVM. If we have IR
files in the tests used to generate object files, then we obviously don't know the
addresses of the symbols inside the object files beforehand.

This change lets the YAML import lookup the addresses in the object files and rewrite
them. This will allow to have test that really don't need any binary input.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239189 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/dsymutil/yaml-object-address-rewrite.test [new file with mode: 0644]
tools/dsymutil/DebugMap.cpp

diff --git a/test/tools/dsymutil/yaml-object-address-rewrite.test b/test/tools/dsymutil/yaml-object-address-rewrite.test
new file mode 100644 (file)
index 0000000..dcb39be
--- /dev/null
@@ -0,0 +1,44 @@
+# RUN: llvm-dsymutil -v -dump-debug-map -oso-prepend-path=%p -y %s | FileCheck %s
+#
+# The YAML debug map bellow is the one from basic-archive.macho.x86_64 with
+# the object addresses set to zero. Check that the YAML import is able to
+# rewrite these addresses to the right values.
+#
+# CHECK: ---
+# CHECK-NEXT: triple:{{.*}}'x86_64-unknown-unknown-macho'
+# CHECK-NEXT: objects:
+# CHECK-NEXT: filename:{{.*}}/Inputs/basic1.macho.x86_64.o
+# CHECK-NEXT: symbols:
+# CHECK-NEXT: sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000EA0, size: 0x00000024
+# CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic2.macho.x86_64.o)'
+# CHECK-NEXT: symbols:
+# CHECK-DAG:   sym: _foo, objAddr: 0x0000000000000020, binAddr: 0x0000000100000ED0, size: 0x00000050
+# CHECK-DAG:   sym: _private_int, objAddr: 0x0000000000000560, binAddr: 0x0000000100001004, size: 0x00000000
+# CHECK-DAG:   sym: _inc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000F20, size: 0x00000017
+# CHECK-DAG:   sym: _baz, objAddr: 0x0000000000000310, binAddr: 0x0000000100001000, size: 0x00000000
+# CHECK-NOT: { sym:
+# CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic3.macho.x86_64.o)'
+# CHECK-NEXT: symbols:
+# CHECK-DAG:   sym: _val, objAddr: 0x0000000000000004, binAddr: 0x0000000100001008, size: 0x00000000
+# CHECK-DAG:   sym: _bar, objAddr: 0x0000000000000020, binAddr: 0x0000000100000F40, size: 0x00000050
+# CHECK-DAG:   sym: _inc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000F90, size: 0x00000019
+# CHECK-NOT: { sym:
+# CHECK-NEXT: ...
+---
+triple:          'x86_64-unknown-unknown-macho'
+objects:
+  - filename: /Inputs/basic1.macho.x86_64.o
+    symbols:
+      - { sym: _main, objAddr: 0x0, binAddr: 0x0000000100000EA0, size: 0x00000024 }
+  - filename: /Inputs/./libbasic.a(basic2.macho.x86_64.o)
+    symbols:
+      - { sym: _foo, objAddr: 0x0, binAddr: 0x0000000100000ED0, size: 0x00000050 }
+      - { sym: _private_int, objAddr: 0x0, binAddr: 0x0000000100001004, size: 0x00000000 }
+      - { sym: _inc, objAddr: 0x0, binAddr: 0x0000000100000F20, size: 0x00000017 }
+      - { sym: _baz, objAddr: 0x0, binAddr: 0x0000000100001000, size: 0x00000000 }
+  - filename: /Inputs/./libbasic.a(basic3.macho.x86_64.o)
+    symbols:
+      - { sym: _val, objAddr: 0x0, binAddr: 0x0000000100001008, size: 0x00000000 }
+      - { sym: _bar, objAddr: 0x0, binAddr: 0x0000000100000F40, size: 0x00000050 }
+      - { sym: _inc, objAddr: 0x0, binAddr: 0x0000000100000F90, size: 0x00000019 }
+...
index 5ffb123f1b995bbeb5730f640e8b2c6db94e6d95..6a8e49ca86ffcc4cd590e8a9c2fe4c178d46be80 100644 (file)
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "DebugMap.h"
+#include "BinaryHolder.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/DataTypes.h"
@@ -87,6 +88,13 @@ void DebugMap::print(raw_ostream &OS) const {
 void DebugMap::dump() const { print(errs()); }
 #endif
 
+namespace {
+struct YAMLContext {
+  StringRef PrependPath;
+  Triple Triple;
+};
+}
+
 ErrorOr<std::unique_ptr<DebugMap>>
 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
                             bool Verbose) {
@@ -94,8 +102,12 @@ DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
   if (auto Err = ErrOrFile.getError())
     return Err;
 
+  YAMLContext Ctxt;
+
+  Ctxt.PrependPath = PrependPath;
+
   std::unique_ptr<DebugMap> Res;
-  yaml::Input yin((*ErrOrFile)->getBuffer(), &PrependPath);
+  yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
   yin >> Res;
 
   if (auto EC = yin.error())
@@ -163,6 +175,8 @@ void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
                                                 dsymutil::DebugMap &DM) {
   io.mapRequired("triple", DM.BinaryTriple);
   io.mapOptional("objects", DM.Objects);
+  if (void *Ctxt = io.getContext())
+    reinterpret_cast<YAMLContext *>(Ctxt)->Triple = DM.BinaryTriple;
 }
 
 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
@@ -171,6 +185,8 @@ void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
     DM.reset(new DebugMap());
   io.mapRequired("triple", DM->BinaryTriple);
   io.mapOptional("objects", DM->Objects);
+  if (void *Ctxt = io.getContext())
+    reinterpret_cast<YAMLContext *>(Ctxt)->Triple = DM->BinaryTriple;
 }
 
 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
@@ -183,15 +199,39 @@ MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
 
 dsymutil::DebugMapObject
 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
-  void *Ctxt = IO.getContext();
-  StringRef PrependPath = *reinterpret_cast<StringRef *>(Ctxt);
-  SmallString<80> Path(PrependPath);
+  BinaryHolder BinHolder(/* Verbose =*/false);
+  const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
+  SmallString<80> Path(Ctxt.PrependPath);
+  StringMap<uint64_t> SymbolAddresses;
+
   sys::path::append(Path, Filename);
+  auto ErrOrObjectFile = BinHolder.GetObjectFile(Path);
+  if (auto EC = ErrOrObjectFile.getError()) {
+    llvm::errs() << "warning: Unable to open " << Path << " " << EC.message()
+                 << '\n';
+  } else {
+    // Rewrite the object file symbol addresses in the debug map. The
+    // YAML input is mainly used to test llvm-dsymutil without
+    // requiring binaries checked-in. If we generate the object files
+    // during the test, we can't hardcode the symbols addresses, so
+    // look them up here and rewrite them.
+    for (const auto &Sym : ErrOrObjectFile->symbols()) {
+      StringRef Name;
+      uint64_t Address;
+      if (Sym.getName(Name) || Sym.getAddress(Address))
+        continue;
+      SymbolAddresses[Name] = Address;
+    }
+  }
+
   dsymutil::DebugMapObject Res(Path);
   for (auto &Entry : Entries) {
     auto &Mapping = Entry.second;
-    Res.addSymbol(Entry.first, Mapping.ObjectAddress, Mapping.BinaryAddress,
-                  Mapping.Size);
+    uint64_t ObjAddress = Mapping.ObjectAddress;
+    auto AddressIt = SymbolAddresses.find(Entry.first);
+    if (AddressIt != SymbolAddresses.end())
+      ObjAddress = AddressIt->getValue();
+    Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
   }
   return Res;
 }