forked from OSchip/llvm-project
[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 llvm-svn: 249784
This commit is contained in:
parent
d837cd044f
commit
e94fef7b3d
|
@ -32,8 +32,7 @@ class PDBContext : public DIContext {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PDBContext(const object::COFFObjectFile &Object,
|
PDBContext(const object::COFFObjectFile &Object,
|
||||||
std::unique_ptr<IPDBSession> PDBSession,
|
std::unique_ptr<IPDBSession> PDBSession);
|
||||||
bool RelativeAddress);
|
|
||||||
|
|
||||||
static bool classof(const DIContext *DICtx) {
|
static bool classof(const DIContext *DICtx) {
|
||||||
return DICtx->getKind() == CK_PDB;
|
return DICtx->getKind() == CK_PDB;
|
||||||
|
|
|
@ -773,6 +773,7 @@ public:
|
||||||
std::error_code getSectionContents(const coff_section *Sec,
|
std::error_code getSectionContents(const coff_section *Sec,
|
||||||
ArrayRef<uint8_t> &Res) const;
|
ArrayRef<uint8_t> &Res) const;
|
||||||
|
|
||||||
|
ErrorOr<uint64_t> getImageBase() const;
|
||||||
std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) 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 getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
|
||||||
std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
|
std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
|
||||||
|
|
|
@ -21,24 +21,11 @@ using namespace llvm;
|
||||||
using namespace llvm::object;
|
using namespace llvm::object;
|
||||||
|
|
||||||
PDBContext::PDBContext(const COFFObjectFile &Object,
|
PDBContext::PDBContext(const COFFObjectFile &Object,
|
||||||
std::unique_ptr<IPDBSession> PDBSession,
|
std::unique_ptr<IPDBSession> PDBSession)
|
||||||
bool RelativeAddress)
|
|
||||||
: DIContext(CK_PDB), Session(std::move(PDBSession)) {
|
: DIContext(CK_PDB), Session(std::move(PDBSession)) {
|
||||||
if (!RelativeAddress) {
|
ErrorOr<uint64_t> ImageBase = Object.getImageBase();
|
||||||
uint64_t ImageBase = 0;
|
if (ImageBase)
|
||||||
if (Object.is64()) {
|
Session->setLoadAddress(ImageBase.get());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
|
void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
|
||||||
|
|
|
@ -174,10 +174,7 @@ ErrorOr<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
|
||||||
|
|
||||||
// The section VirtualAddress does not include ImageBase, and we want to
|
// The section VirtualAddress does not include ImageBase, and we want to
|
||||||
// return virtual addresses.
|
// return virtual addresses.
|
||||||
if (PE32Header)
|
Result += getImageBase().get();
|
||||||
Result += PE32Header->ImageBase;
|
|
||||||
else if (PE32PlusHeader)
|
|
||||||
Result += PE32PlusHeader->ImageBase;
|
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -274,10 +271,7 @@ uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
|
||||||
|
|
||||||
// The section VirtualAddress does not include ImageBase, and we want to
|
// The section VirtualAddress does not include ImageBase, and we want to
|
||||||
// return virtual addresses.
|
// return virtual addresses.
|
||||||
if (PE32Header)
|
Result += getImageBase().get();
|
||||||
Result += PE32Header->ImageBase;
|
|
||||||
else if (PE32PlusHeader)
|
|
||||||
Result += PE32PlusHeader->ImageBase;
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,10 +418,17 @@ std::error_code COFFObjectFile::initSymbolTablePtr() {
|
||||||
return std::error_code();
|
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.
|
// Returns the file offset for the given VA.
|
||||||
std::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
|
std::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
|
||||||
uint64_t ImageBase = PE32Header ? (uint64_t)PE32Header->ImageBase
|
uint64_t ImageBase = getImageBase().get();
|
||||||
: (uint64_t)PE32PlusHeader->ImageBase;
|
|
||||||
uint64_t Rva = Addr - ImageBase;
|
uint64_t Rva = Addr - ImageBase;
|
||||||
assert(Rva <= UINT32_MAX);
|
assert(Rva <= UINT32_MAX);
|
||||||
return getRvaPtr((uint32_t)Rva, Res);
|
return getRvaPtr((uint32_t)Rva, Res);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
0x5009
|
||||||
|
0x5038
|
|
@ -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
|
|
@ -1,8 +1,18 @@
|
||||||
RUN: llvm-symbolizer -obj="%p/Inputs/test.exe" < "%p/Inputs/test.exe.input" | \
|
RUN: llvm-symbolizer -obj="%p/Inputs/test.exe" < "%p/Inputs/test.exe.input" | \
|
||||||
RUN: FileCheck %s --check-prefix=CHECK
|
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: llvm-symbolizer -obj="%p/Inputs/test.exe" -demangle=false < \
|
||||||
RUN: "%p/Inputs/test.exe.input" | FileCheck %s --check-prefix=CHECK-NO-DEMANGLE
|
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: foo(void)
|
||||||
CHECK-NEXT: test.cpp:10
|
CHECK-NEXT: test.cpp:10
|
||||||
CHECK: main
|
CHECK: main
|
||||||
|
|
|
@ -126,6 +126,13 @@ bool ModuleInfo::isWin32Module() const {
|
||||||
return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
|
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,
|
bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
|
||||||
std::string &Name, uint64_t &Addr,
|
std::string &Name, uint64_t &Addr,
|
||||||
uint64_t &Size) const {
|
uint64_t &Size) const {
|
||||||
|
@ -210,6 +217,12 @@ std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
|
||||||
ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
|
ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
|
||||||
if (!Info)
|
if (!Info)
|
||||||
return printDILineInfo(DILineInfo(), 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) {
|
if (Opts.PrintInlining) {
|
||||||
DIInliningInfo InlinedContext =
|
DIInliningInfo InlinedContext =
|
||||||
Info->symbolizeInlinedCode(ModuleOffset, Opts);
|
Info->symbolizeInlinedCode(ModuleOffset, Opts);
|
||||||
|
@ -233,6 +246,10 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
|
||||||
uint64_t Size = 0;
|
uint64_t Size = 0;
|
||||||
if (Opts.UseSymbolTable) {
|
if (Opts.UseSymbolTable) {
|
||||||
if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) {
|
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)
|
if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle)
|
||||||
Name = DemangleName(Name, Info);
|
Name = DemangleName(Name, Info);
|
||||||
}
|
}
|
||||||
|
@ -474,8 +491,7 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
||||||
PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
|
PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
|
||||||
Objects.first->getFileName(), Session);
|
Objects.first->getFileName(), Session);
|
||||||
if (Error == PDB_ErrorCode::Success) {
|
if (Error == PDB_ErrorCode::Success) {
|
||||||
Context = new PDBContext(*CoffObject, std::move(Session),
|
Context = new PDBContext(*CoffObject, std::move(Session));
|
||||||
Opts.RelativeAddresses);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Context)
|
if (!Context)
|
||||||
|
|
|
@ -117,6 +117,10 @@ public:
|
||||||
// Return true if this is a 32-bit x86 PE COFF module.
|
// Return true if this is a 32-bit x86 PE COFF module.
|
||||||
bool isWin32Module() const;
|
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:
|
private:
|
||||||
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
|
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
|
||||||
std::string &Name, uint64_t &Addr,
|
std::string &Name, uint64_t &Addr,
|
||||||
|
|
Loading…
Reference in New Issue