Index: test/tools/llvm-symbolizer/ppc64.test =================================================================== --- /dev/null +++ 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 Index: tools/llvm-symbolizer/LLVMSymbolize.h =================================================================== --- tools/llvm-symbolizer/LLVMSymbolize.h +++ 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,10 @@ 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, + uint64_t OpdAddress); ObjectFile *Module; std::unique_ptr DebugInfoContext; Index: tools/llvm-symbolizer/LLVMSymbolize.cpp =================================================================== --- tools/llvm-symbolizer/LLVMSymbolize.cpp +++ tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -45,8 +45,24 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) : Module(Obj), DebugInfoContext(DICtx) { + DataExtractor OpdExtractor("", false, 0); + 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 = DataExtractor(Data, false, 8); + OpdAddress = Section->getAddress(); + break; + } + } + } for (const SymbolRef &Symbol : Module->symbols()) { - addSymbol(Symbol); + addSymbol(Symbol, OpdExtractor, OpdAddress); } bool NoSymbolTable = (Module->symbol_begin() == Module->symbol_end()); if (NoSymbolTable && Module->isELF()) { @@ -54,12 +70,13 @@ std::pair IDyn = getELFDynamicSymbolIterators(Module); for (symbol_iterator si = IDyn.first, se = IDyn.second; si != se; ++si) { - addSymbol(*si); + addSymbol(*si, OpdExtractor, 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 +86,17 @@ if (error(Symbol.getAddress(SymbolAddress)) || SymbolAddress == UnknownAddressOrSize) return; + uint64_t OpdOffset = SymbolAddress - OpdAddress; + if (OpdOffset == (uint32_t)OpdOffset && + OpdExtractor.isValidOffsetForDataOfSize(OpdOffset, 8)) { + // 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. + uint32_t Offset = OpdOffset; + SymbolAddress = OpdExtractor.getAddress(&Offset); + } 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.