From: Reid Kleckner Date: Fri, 9 Oct 2015 00:15:01 +0000 (+0000) Subject: [llvm-symbolizer] Make --relative-address work with DWARF contexts X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=27a9e1dbcf5d0fdf2457c10fecd089a8c02cdec5;p=oota-llvm.git [llvm-symbolizer] Make --relative-address work with DWARF contexts 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 --- diff --git a/include/llvm/DebugInfo/PDB/PDBContext.h b/include/llvm/DebugInfo/PDB/PDBContext.h index 2bb97463f90..9404a592244 100644 --- a/include/llvm/DebugInfo/PDB/PDBContext.h +++ b/include/llvm/DebugInfo/PDB/PDBContext.h @@ -32,8 +32,7 @@ class PDBContext : public DIContext { public: PDBContext(const object::COFFObjectFile &Object, - std::unique_ptr PDBSession, - bool RelativeAddress); + std::unique_ptr PDBSession); static bool classof(const DIContext *DICtx) { return DICtx->getKind() == CK_PDB; diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index ce9042fd3ab..ba846dd7d8b 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -773,6 +773,7 @@ public: std::error_code getSectionContents(const coff_section *Sec, ArrayRef &Res) const; + ErrorOr 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, diff --git a/lib/DebugInfo/PDB/PDBContext.cpp b/lib/DebugInfo/PDB/PDBContext.cpp index 83f27c7fa3d..ca2ae6665ce 100644 --- a/lib/DebugInfo/PDB/PDBContext.cpp +++ b/lib/DebugInfo/PDB/PDBContext.cpp @@ -21,24 +21,11 @@ using namespace llvm; using namespace llvm::object; PDBContext::PDBContext(const COFFObjectFile &Object, - std::unique_ptr PDBSession, - bool RelativeAddress) + std::unique_ptr 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(Header->ImageBase); - } - Session->setLoadAddress(ImageBase); - } + ErrorOr ImageBase = Object.getImageBase(); + if (ImageBase) + Session->setLoadAddress(ImageBase.get()); } void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {} diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index d3f604a8d35..efb3ea04083 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -174,10 +174,7 @@ ErrorOr 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 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 index 00000000000..9741439cdcf --- /dev/null +++ b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.cpp @@ -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 index 00000000000..018053b979b 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 index 00000000000..6f6cd2eedb5 --- /dev/null +++ b/test/tools/llvm-symbolizer/Inputs/coff-dwarf.input @@ -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 index 00000000000..5daf6b04a33 --- /dev/null +++ b/test/tools/llvm-symbolizer/coff-dwarf.test @@ -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 diff --git a/test/tools/llvm-symbolizer/pdb/pdb.test b/test/tools/llvm-symbolizer/pdb/pdb.test index 958a5a7e1a8..228779e56a8 100644 --- a/test/tools/llvm-symbolizer/pdb/pdb.test +++ b/test/tools/llvm-symbolizer/pdb/pdb.test @@ -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 diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 497207ed4ca..cbfbdda08c9 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -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(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) diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index b52c76036e1..00a3860eacb 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -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,