From 222fcc59cbd2445e496f67de33e9717220bfc142 Mon Sep 17 00:00:00 2001 From: Jay Foad Date: Fri, 7 Nov 2014 09:08:39 +0000 Subject: [PATCH] llvm-symbolizer: teach it about PowerPC64 ELF function descriptors Summary: Teach llvm-symbolizer about PowerPC64 ELF function descriptors. Symbols in the .opd section point to function descriptors, the first word of which is a pointer to the real function. For the purposes of symbolizing we pretend that the symbol points directly to the function. This is enough to get decent function names in stack traces for unoptimized binaries, which fixes the sanitizer print-stack-trace test on PowerPC64 Linux. Reviewers: kcc, willschm, samsonov Reviewed By: samsonov Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6110 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221514 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/DataExtractor.h | 11 +++++++ test/tools/llvm-symbolizer/Inputs/ppc64 | Bin 0 -> 1624 bytes test/tools/llvm-symbolizer/ppc64.test | 11 +++++++ tools/llvm-symbolizer/LLVMSymbolize.cpp | 37 ++++++++++++++++++++++-- tools/llvm-symbolizer/LLVMSymbolize.h | 7 ++++- 5 files changed, 62 insertions(+), 4 deletions(-) create mode 100755 test/tools/llvm-symbolizer/Inputs/ppc64 create mode 100644 test/tools/llvm-symbolizer/ppc64.test diff --git a/include/llvm/Support/DataExtractor.h b/include/llvm/Support/DataExtractor.h index e8a19cd773b..48235d4145b 100644 --- a/include/llvm/Support/DataExtractor.h +++ b/include/llvm/Support/DataExtractor.h @@ -348,6 +348,17 @@ public: bool isValidOffsetForDataOfSize(uint32_t offset, uint32_t length) const { return offset + length >= offset && isValidOffset(offset + length - 1); } + + /// Test the availability of enough bytes of data for a pointer from + /// \a offset. The size of a pointer is \a getAddressSize(). + /// + /// @return + /// \b true if \a offset is a valid offset and there are enough + /// bytes for a pointer available at that offset, \b false + /// otherwise. + bool isValidOffsetForAddress(uint32_t offset) const { + return isValidOffsetForDataOfSize(offset, AddressSize); + } }; } // namespace llvm diff --git a/test/tools/llvm-symbolizer/Inputs/ppc64 b/test/tools/llvm-symbolizer/Inputs/ppc64 new file mode 100755 index 0000000000000000000000000000000000000000..2356e4347468d535c433834aef7b2bd35c39218e GIT binary patch literal 1624 zcmb_c&x_Mg5T2xUx5Y~o1wn-@h_0Yvce|`TX~A7xv@CiMJSb_Jrrp9eDebGQQn33! zc<>;2TRiB^i~os&hl&V-CvOE0b>_V{X&MRi;6UCt^S$|%yvcjHQ@vxF2E<~*S=1$A z8K$NAibC_X#0r!l4;3iF658Z@LhY-SgBa1}tJ=}1%F#;kD8`sp%a})`c8Nz(sN(Wy z(}QBzxPS$QjSwTMm&it8%s0f3hiL11a&M7^UV&h6VHZ&$sDhVt_SSnH~*qojklhoqnmI!_Z&;SYCnAPu%;3 zKEp!pc)|D&i^g*w_U4Xg#)KPXdg7Lw;SMy;81`Q?7PjL*9pLhx=8v_rxS#N z>i#D=k9n4LE|ZYwgy#k+o)7KDb0tj&S2b~ZZumPQ&2#yR12q;B_GTiU>(BoO31_X+ ztg+lgh3n^tpFqy7^2pL(yje+BLg+`jO70$jJ=?`ypoMc@VvPk0Dn1L|H6{sN?jk8}V4 literal 0 HcmV?d00001 diff --git a/test/tools/llvm-symbolizer/ppc64.test b/test/tools/llvm-symbolizer/ppc64.test new file mode 100644 index 00000000000..b2b5ccf455e --- /dev/null +++ b/test/tools/llvm-symbolizer/ppc64.test @@ -0,0 +1,11 @@ +// ppc64 was compiled from this source on a big-endian 64-bit PowerPC box +// with just "clang -nostdlib": +int foo() { return 0; } +int bar() { return foo(); } +int _start() { return bar(); } + +RUN: ( echo 0x1000014c ; echo 0x1000018c ; echo 0x100001cc ) | llvm-symbolizer -obj=%p/Inputs/ppc64 | FileCheck %s + +CHECK: foo +CHECK: bar +CHECK: _start diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 760d83bf38a..36061d7e684 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -45,8 +45,26 @@ getDILineInfoSpecifier(const LLVMSymbolizer::Options &Opts) { ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) : Module(Obj), DebugInfoContext(DICtx) { + std::unique_ptr OpdExtractor; + uint64_t OpdAddress = 0; + // Find the .opd (function descriptor) section if any, for big-endian + // PowerPC64 ELF. + if (Module->getArch() == Triple::ppc64) { + for (section_iterator Section : Module->sections()) { + StringRef Name; + if (!error(Section->getName(Name)) && Name == ".opd") { + StringRef Data; + if (!error(Section->getContents(Data))) { + OpdExtractor.reset(new DataExtractor(Data, Module->isLittleEndian(), + Module->getBytesInAddress())); + OpdAddress = Section->getAddress(); + } + break; + } + } + } for (const SymbolRef &Symbol : Module->symbols()) { - addSymbol(Symbol); + addSymbol(Symbol, OpdExtractor.get(), OpdAddress); } bool NoSymbolTable = (Module->symbol_begin() == Module->symbol_end()); if (NoSymbolTable && Module->isELF()) { @@ -54,12 +72,13 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) std::pair IDyn = getELFDynamicSymbolIterators(Module); for (symbol_iterator si = IDyn.first, se = IDyn.second; si != se; ++si) { - addSymbol(*si); + addSymbol(*si, OpdExtractor.get(), OpdAddress); } } } -void ModuleInfo::addSymbol(const SymbolRef &Symbol) { +void ModuleInfo::addSymbol(const SymbolRef &Symbol, DataExtractor *OpdExtractor, + uint64_t OpdAddress) { SymbolRef::Type SymbolType; if (error(Symbol.getType(SymbolType))) return; @@ -69,6 +88,18 @@ void ModuleInfo::addSymbol(const SymbolRef &Symbol) { if (error(Symbol.getAddress(SymbolAddress)) || SymbolAddress == UnknownAddressOrSize) return; + if (OpdExtractor) { + // For big-endian PowerPC64 ELF, symbols in the .opd section refer to + // function descriptors. The first word of the descriptor is a pointer to + // the function's code. + // For the purposes of symbolization, pretend the symbol's address is that + // of the function's code, not the descriptor. + uint64_t OpdOffset = SymbolAddress - OpdAddress; + uint32_t OpdOffset32 = OpdOffset; + if (OpdOffset == OpdOffset32 && + OpdExtractor->isValidOffsetForAddress(OpdOffset32)) + SymbolAddress = OpdExtractor->getAddress(&OpdOffset32); + } uint64_t SymbolSize; // Getting symbol size is linear for Mach-O files, so assume that symbol // occupies the memory range up to the following symbol. diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index db3f56237b4..ff848fceb24 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/MemoryBuffer.h" #include #include @@ -115,7 +116,11 @@ private: bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size) const; - void addSymbol(const SymbolRef &Symbol); + // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd + // (function descriptor) section and OpdExtractor refers to its contents. + void addSymbol(const SymbolRef &Symbol, + DataExtractor *OpdExtractor = nullptr, + uint64_t OpdAddress = 0); ObjectFile *Module; std::unique_ptr DebugInfoContext; -- 2.34.1