[llvm-symbolizer] Make --relative-address work with DWARF contexts
authorReid Kleckner <rnk@google.com>
Fri, 9 Oct 2015 00:15:01 +0000 (00:15 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 9 Oct 2015 00:15:01 +0000 (00:15 +0000)
Summary:
Previously the relative address flag only affected PDB debug info.  Now
both DIContext implementations always expect to be passed virtual
addresses. llvm-symbolizer is now responsible for adding ImageBase to
module offsets when --relative-offset is passed.

Reviewers: zturner

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D12883

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

include/llvm/DebugInfo/PDB/PDBContext.h
include/llvm/Object/COFF.h
lib/DebugInfo/PDB/PDBContext.cpp
lib/Object/COFFObjectFile.cpp
test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp [new file with mode: 0644]
test/tools/llvm-symbolizer/Inputs/coff-dwarf.exe [new file with mode: 0644]
test/tools/llvm-symbolizer/Inputs/coff-dwarf.input [new file with mode: 0644]
test/tools/llvm-symbolizer/coff-dwarf.test [new file with mode: 0644]
test/tools/llvm-symbolizer/pdb/pdb.test
tools/llvm-symbolizer/LLVMSymbolize.cpp
tools/llvm-symbolizer/LLVMSymbolize.h

index 2bb9746..9404a59 100644 (file)
@@ -32,8 +32,7 @@ class PDBContext : public DIContext {
 
 public:
   PDBContext(const object::COFFObjectFile &Object,
-             std::unique_ptr<IPDBSession> PDBSession,
-             bool RelativeAddress);
+             std::unique_ptr<IPDBSession> PDBSession);
 
   static bool classof(const DIContext *DICtx) {
     return DICtx->getKind() == CK_PDB;
index ce9042f..ba846dd 100644 (file)
@@ -773,6 +773,7 @@ public:
   std::error_code getSectionContents(const coff_section *Sec,
                                      ArrayRef<uint8_t> &Res) const;
 
+  ErrorOr<uint64_t> getImageBase() const;
   std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const;
   std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
   std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
index 83f27c7..ca2ae66 100644 (file)
@@ -21,24 +21,11 @@ using namespace llvm;
 using namespace llvm::object;
 
 PDBContext::PDBContext(const COFFObjectFile &Object,
-                       std::unique_ptr<IPDBSession> PDBSession,
-                       bool RelativeAddress)
+                       std::unique_ptr<IPDBSession> PDBSession)
     : DIContext(CK_PDB), Session(std::move(PDBSession)) {
-  if (!RelativeAddress) {
-    uint64_t ImageBase = 0;
-    if (Object.is64()) {
-      const pe32plus_header *Header = nullptr;
-      Object.getPE32PlusHeader(Header);
-      if (Header)
-        ImageBase = Header->ImageBase;
-    } else {
-      const pe32_header *Header = nullptr;
-      Object.getPE32Header(Header);
-      if (Header)
-        ImageBase = static_cast<uint64_t>(Header->ImageBase);
-    }
-    Session->setLoadAddress(ImageBase);
-  }
+  ErrorOr<uint64_t> ImageBase = Object.getImageBase();
+  if (ImageBase)
+    Session->setLoadAddress(ImageBase.get());
 }
 
 void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
index d3f604a..efb3ea0 100644 (file)
@@ -174,10 +174,7 @@ ErrorOr<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
 
   // The section VirtualAddress does not include ImageBase, and we want to
   // return virtual addresses.
-  if (PE32Header)
-    Result += PE32Header->ImageBase;
-  else if (PE32PlusHeader)
-    Result += PE32PlusHeader->ImageBase;
+  Result += getImageBase().get();
 
   return Result;
 }
@@ -274,10 +271,7 @@ uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
 
   // The section VirtualAddress does not include ImageBase, and we want to
   // return virtual addresses.
-  if (PE32Header)
-    Result += PE32Header->ImageBase;
-  else if (PE32PlusHeader)
-    Result += PE32PlusHeader->ImageBase;
+  Result += getImageBase().get();
   return Result;
 }
 
@@ -424,10 +418,17 @@ std::error_code COFFObjectFile::initSymbolTablePtr() {
   return std::error_code();
 }
 
+ErrorOr<uint64_t> COFFObjectFile::getImageBase() const {
+  if (PE32Header)
+    return uint64_t(PE32Header->ImageBase);
+  else if (PE32PlusHeader)
+    return uint64_t(PE32PlusHeader->ImageBase);
+  return object_error::parse_failed;
+}
+
 // Returns the file offset for the given VA.
 std::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
-  uint64_t ImageBase = PE32Header ? (uint64_t)PE32Header->ImageBase
-                                  : (uint64_t)PE32PlusHeader->ImageBase;
+  uint64_t ImageBase = getImageBase().get();
   uint64_t Rva = Addr - ImageBase;
   assert(Rva <= UINT32_MAX);
   return getRvaPtr((uint32_t)Rva, Res);
diff --git a/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp
new file mode 100644 (file)
index 0000000..9741439
--- /dev/null
@@ -0,0 +1,19 @@
+// To generate the corresponding EXE, run:
+// clang-cl -O2 -gdwarf -c coff-dwarf.cpp && lld-link -debug coff-dwarf.obj
+
+extern "C" int puts(const char *str);
+
+void __declspec(noinline) foo() {
+  puts("foo1");
+  puts("foo2");
+}
+
+// LLVM should inline this into main.
+static void bar() {
+  foo();
+}
+
+int main() {
+  bar();
+  return 0;
+}
diff --git a/test/tools/llvm-symbolizer/Inputs/coff-dwarf.exe b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.exe
new file mode 100644 (file)
index 0000000..018053b
Binary files /dev/null and b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.exe differ
diff --git a/test/tools/llvm-symbolizer/Inputs/coff-dwarf.input b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.input
new file mode 100644 (file)
index 0000000..6f6cd2e
--- /dev/null
@@ -0,0 +1,2 @@
+0x5009
+0x5038
diff --git a/test/tools/llvm-symbolizer/coff-dwarf.test b/test/tools/llvm-symbolizer/coff-dwarf.test
new file mode 100644 (file)
index 0000000..5daf6b0
--- /dev/null
@@ -0,0 +1,9 @@
+RUN: llvm-symbolizer --inlining --relative-address -obj="%p/Inputs/coff-dwarf.exe" \
+RUN:       < %p/Inputs/coff-dwarf.input | FileCheck %s
+
+CHECK: foo(void)
+CHECK: coff-dwarf.cpp:7
+CHECK: bar(void)
+CHECK: coff-dwarf.cpp:13
+CHECK: main
+CHECK: coff-dwarf.cpp:17
index 958a5a7..228779e 100644 (file)
@@ -1,8 +1,18 @@
 RUN: llvm-symbolizer -obj="%p/Inputs/test.exe" < "%p/Inputs/test.exe.input" | \
 RUN:    FileCheck %s --check-prefix=CHECK
+RUN: llvm-symbolizer -obj="%p/Inputs/test.exe" < "%p/Inputs/test.exe.input" | \
+RUN:    FileCheck %s --check-prefix=CHECK
 RUN: llvm-symbolizer -obj="%p/Inputs/test.exe" -demangle=false < \
 RUN:    "%p/Inputs/test.exe.input" | FileCheck %s --check-prefix=CHECK-NO-DEMANGLE
 
+Subtract ImageBase from all the offsets and run the test again with
+--relative-address.
+
+RUN: python -c 'import sys;print "\n".join([hex(int(x, 16) - 0x400000) for x in sys.stdin])' \
+RUN:   < %p/Inputs/test.exe.input \
+RUN:   | llvm-symbolizer -obj="%p/Inputs/test.exe" -demangle=false --relative-address \
+RUN:    | FileCheck %s --check-prefix=CHECK-NO-DEMANGLE
+
 CHECK: foo(void)
 CHECK-NEXT: test.cpp:10
 CHECK: main
index 497207e..cbfbdda 100644 (file)
@@ -126,6 +126,13 @@ bool ModuleInfo::isWin32Module() const {
   return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
 }
 
+uint64_t ModuleInfo::getModulePreferredBase() const {
+  if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
+    if (auto Base = CoffObject->getImageBase())
+      return Base.get();
+  return 0;
+}
+
 bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
                                         std::string &Name, uint64_t &Addr,
                                         uint64_t &Size) const {
@@ -210,6 +217,12 @@ std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
   ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
   if (!Info)
     return printDILineInfo(DILineInfo(), Info);
+
+  // If the user is giving us relative addresses, add the preferred base of the
+  // object to the offset before we do the query. It's what DIContext expects.
+  if (Opts.RelativeAddresses)
+    ModuleOffset += Info->getModulePreferredBase();
+
   if (Opts.PrintInlining) {
     DIInliningInfo InlinedContext =
         Info->symbolizeInlinedCode(ModuleOffset, Opts);
@@ -233,6 +246,10 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
   uint64_t Size = 0;
   if (Opts.UseSymbolTable) {
     if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) {
+      // If the user is giving us relative addresses, add the preferred base of the
+      // object to the offset before we do the query. It's what DIContext expects.
+      if (Opts.RelativeAddresses)
+        ModuleOffset += Info->getModulePreferredBase();
       if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle)
         Name = DemangleName(Name, Info);
     }
@@ -474,8 +491,7 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
     PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
                                          Objects.first->getFileName(), Session);
     if (Error == PDB_ErrorCode::Success) {
-      Context = new PDBContext(*CoffObject, std::move(Session),
-                               Opts.RelativeAddresses);
+      Context = new PDBContext(*CoffObject, std::move(Session));
     }
   }
   if (!Context)
index b52c760..00a3860 100644 (file)
@@ -117,6 +117,10 @@ public:
   // Return true if this is a 32-bit x86 PE COFF module.
   bool isWin32Module() const;
 
+  // Returns the preferred base of the module, i.e. where the loader would place
+  // it in memory assuming there were no conflicts.
+  uint64_t getModulePreferredBase() const;
+
 private:
   bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
                               std::string &Name, uint64_t &Addr,