[llvm-symbolizer] Use the export table if no symbols are present
authorReid Kleckner <rnk@google.com>
Fri, 16 Oct 2015 23:43:22 +0000 (23:43 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 16 Oct 2015 23:43:22 +0000 (23:43 +0000)
This lets us make guesses about symbols in third party DLLs without
debug info, like MSVCR120.dll or kernel32.dll. dbghelp does the same
thing.

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

test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp
test/tools/llvm-symbolizer/Inputs/coff-exports.cpp [new file with mode: 0644]
test/tools/llvm-symbolizer/Inputs/coff-exports.exe [new file with mode: 0644]
test/tools/llvm-symbolizer/coff-exports.test [new file with mode: 0644]
tools/llvm-symbolizer/LLVMSymbolize.cpp
tools/llvm-symbolizer/LLVMSymbolize.h

index 9741439..3a832a9 100644 (file)
@@ -1,5 +1,5 @@
 // To generate the corresponding EXE, run:
-// clang-cl -O2 -gdwarf -c coff-dwarf.cpp && lld-link -debug coff-dwarf.obj
+// clang-cl -MD -O2 -gdwarf -c coff-dwarf.cpp && lld-link -debug coff-dwarf.obj
 
 extern "C" int puts(const char *str);
 
diff --git a/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp b/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp
new file mode 100644 (file)
index 0000000..23b44b3
--- /dev/null
@@ -0,0 +1,20 @@
+// To generate the corresponding EXE, run:
+// clang-cl -MD -c coff-exports.cpp && lld-link /MANIFEST:NO coff-exports.obj
+
+#define EXPORT __declspec(dllexport)
+
+extern "C" int puts(const char *str);
+
+EXPORT void __declspec(noinline) foo() {
+  puts("foo1");
+  puts("foo2");
+}
+
+void bar() {
+  foo();
+}
+
+EXPORT int main() {
+  bar();
+  return 0;
+}
diff --git a/test/tools/llvm-symbolizer/Inputs/coff-exports.exe b/test/tools/llvm-symbolizer/Inputs/coff-exports.exe
new file mode 100644 (file)
index 0000000..939205e
Binary files /dev/null and b/test/tools/llvm-symbolizer/Inputs/coff-exports.exe differ
diff --git a/test/tools/llvm-symbolizer/coff-exports.test b/test/tools/llvm-symbolizer/coff-exports.test
new file mode 100644 (file)
index 0000000..7283acd
--- /dev/null
@@ -0,0 +1,17 @@
+RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
+RUN:    | llvm-symbolizer --inlining --relative-address -obj="%p/Inputs/coff-exports.exe" \
+RUN:    | FileCheck %s
+
+ADDR: 0x500A
+ADDR: 0x5038
+ADDR: 0x504B
+
+We get the expected stack trace, except 'foo' appears for the 'bar' frame
+because 'bar' isn't in the export table.
+
+CHECK: foo(void)
+CHECK: ??:0:0
+CHECK: foo(void)
+CHECK: ??:0:0
+CHECK: main
+CHECK: ??:0:0
index 996520b..ae164b0 100644 (file)
@@ -83,6 +83,50 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
       computeSymbolSizes(*Module);
   for (auto &P : Symbols)
     addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress);
+
+  // If this is a COFF object and we didn't find any symbols, try the export
+  // table.
+  if (Symbols.empty()) {
+    if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
+      addCoffExportSymbols(CoffObj);
+  }
+}
+
+void ModuleInfo::addCoffExportSymbols(const COFFObjectFile *CoffObj) {
+  // Get all export names and offsets.
+  struct OffsetNamePair {
+    uint32_t Offset;
+    StringRef Name;
+  };
+  std::vector<OffsetNamePair> ExportSyms;
+  for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
+    StringRef Name;
+    uint32_t Offset;
+    if (error(Ref.getSymbolName(Name)) || error(Ref.getExportRVA(Offset)))
+      return;
+    ExportSyms.push_back(OffsetNamePair{Offset, Name});
+  }
+  if (ExportSyms.empty())
+    return;
+
+  // Sort by ascending offset.
+  array_pod_sort(ExportSyms.begin(), ExportSyms.end(),
+                 [](const OffsetNamePair *L, const OffsetNamePair *R) -> int {
+                   return L->Offset - R->Offset;
+                 });
+
+  // Approximate the symbol sizes by assuming they run to the next symbol.
+  // FIXME: This assumes all exports are functions.
+  uint64_t ImageBase = CoffObj->getImageBase();
+  for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
+    OffsetNamePair &Export = *I;
+    // FIXME: The last export has a one byte size now.
+    uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
+    uint64_t SymbolStart = ImageBase + Export.Offset;
+    uint64_t SymbolSize = NextOffset - Export.Offset;
+    SymbolDesc SD = {SymbolStart, SymbolSize};
+    Functions.insert(std::make_pair(SD, Export.Name));
+  }
 }
 
 void ModuleInfo::addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize,
index 00a3860..17df56e 100644 (file)
@@ -130,6 +130,7 @@ private:
   void addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize,
                  DataExtractor *OpdExtractor = nullptr,
                  uint64_t OpdAddress = 0);
+  void addCoffExportSymbols(const COFFObjectFile *CoffObj);
   ObjectFile *Module;
   std::unique_ptr<DIContext> DebugInfoContext;