diff options
-rw-r--r-- | llvm/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp | 2 | ||||
-rw-r--r-- | llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp | 20 | ||||
-rw-r--r-- | llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.exe | bin | 0 -> 8192 bytes | |||
-rw-r--r-- | llvm/test/tools/llvm-symbolizer/coff-exports.test | 17 | ||||
-rw-r--r-- | llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp | 44 | ||||
-rw-r--r-- | llvm/tools/llvm-symbolizer/LLVMSymbolize.h | 1 |
6 files changed, 83 insertions, 1 deletions
diff --git a/llvm/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp b/llvm/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp index 9741439cdcf..3a832a9fcff 100644 --- a/llvm/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp +++ b/llvm/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp @@ -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/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp b/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp new file mode 100644 index 00000000000..23b44b32902 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.cpp @@ -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/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.exe b/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.exe Binary files differnew file mode 100644 index 00000000000..939205e3f82 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/Inputs/coff-exports.exe diff --git a/llvm/test/tools/llvm-symbolizer/coff-exports.test b/llvm/test/tools/llvm-symbolizer/coff-exports.test new file mode 100644 index 00000000000..7283acda2fc --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/coff-exports.test @@ -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 diff --git a/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp b/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp index 996520b8430..ae164b07b96 100644 --- a/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -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, diff --git a/llvm/tools/llvm-symbolizer/LLVMSymbolize.h b/llvm/tools/llvm-symbolizer/LLVMSymbolize.h index 00a3860eacb..17df56e695a 100644 --- a/llvm/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/llvm/tools/llvm-symbolizer/LLVMSymbolize.h @@ -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; |