diff options
Diffstat (limited to 'tools/llvm-symbolizer/LLVMSymbolize.cpp')
-rw-r--r-- | tools/llvm-symbolizer/LLVMSymbolize.cpp | 215 |
1 files changed, 106 insertions, 109 deletions
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 320ab3fcbcfe..c1d39efc1b81 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -14,80 +14,80 @@ #include "LLVMSymbolize.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" - #include <sstream> #include <stdlib.h> namespace llvm { namespace symbolize { -static bool error(error_code ec) { +static bool error(std::error_code ec) { if (!ec) return false; errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; return true; } -static uint32_t -getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) { - uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo | - llvm::DILineInfoSpecifier::AbsoluteFilePath; - if (Opts.PrintFunctions) - Flags |= llvm::DILineInfoSpecifier::FunctionName; - return Flags; -} - -static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName, - DILineInfo &LineInfo) { - std::string FileName = LineInfo.getFileName(); - LineInfo = DILineInfo(StringRef(FileName), StringRef(NewFunctionName), - LineInfo.getLine(), LineInfo.getColumn()); +static DILineInfoSpecifier +getDILineInfoSpecifier(const LLVMSymbolizer::Options &Opts) { + return DILineInfoSpecifier( + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, + Opts.PrintFunctions); } ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) : Module(Obj), DebugInfoContext(DICtx) { - error_code ec; - for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols(); - si != se; si.increment(ec)) { - if (error(ec)) - return; - SymbolRef::Type SymbolType; - if (error(si->getType(SymbolType))) - continue; - if (SymbolType != SymbolRef::ST_Function && - SymbolType != SymbolRef::ST_Data) - continue; - uint64_t SymbolAddress; - if (error(si->getAddress(SymbolAddress)) || - SymbolAddress == UnknownAddressOrSize) - continue; - 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. - if (isa<MachOObjectFile>(Obj)) - SymbolSize = 0; - else if (error(si->getSize(SymbolSize)) || - SymbolSize == UnknownAddressOrSize) - continue; - StringRef SymbolName; - if (error(si->getName(SymbolName))) - continue; - // Mach-O symbol table names have leading underscore, skip it. - if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') - SymbolName = SymbolName.drop_front(); - // FIXME: If a function has alias, there are two entries in symbol table - // with same address size. Make sure we choose the correct one. - SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { SymbolAddress, SymbolSize }; - M.insert(std::make_pair(SD, SymbolName)); + for (const SymbolRef &Symbol : Module->symbols()) { + addSymbol(Symbol); } + bool NoSymbolTable = (Module->symbol_begin() == Module->symbol_end()); + if (NoSymbolTable && Module->isELF()) { + // Fallback to dynamic symbol table, if regular symbol table is stripped. + std::pair<symbol_iterator, symbol_iterator> IDyn = + getELFDynamicSymbolIterators(Module); + for (symbol_iterator si = IDyn.first, se = IDyn.second; si != se; ++si) { + addSymbol(*si); + } + } +} + +void ModuleInfo::addSymbol(const SymbolRef &Symbol) { + SymbolRef::Type SymbolType; + if (error(Symbol.getType(SymbolType))) + return; + if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) + return; + uint64_t SymbolAddress; + if (error(Symbol.getAddress(SymbolAddress)) || + SymbolAddress == UnknownAddressOrSize) + return; + 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. + if (isa<MachOObjectFile>(Module)) + SymbolSize = 0; + else if (error(Symbol.getSize(SymbolSize)) || + SymbolSize == UnknownAddressOrSize) + return; + StringRef SymbolName; + if (error(Symbol.getName(SymbolName))) + return; + // Mach-O symbol table names have leading underscore, skip it. + if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') + SymbolName = SymbolName.drop_front(); + // FIXME: If a function has alias, there are two entries in symbol table + // with same address size. Make sure we choose the correct one. + SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; + SymbolDesc SD = { SymbolAddress, SymbolSize }; + M.insert(std::make_pair(SD, SymbolName)); } bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, @@ -114,15 +114,15 @@ DILineInfo ModuleInfo::symbolizeCode( DILineInfo LineInfo; if (DebugInfoContext) { LineInfo = DebugInfoContext->getLineInfoForAddress( - ModuleOffset, getDILineInfoSpecifierFlags(Opts)); + ModuleOffset, getDILineInfoSpecifier(Opts)); } // Override function name from symbol table if necessary. - if (Opts.PrintFunctions && Opts.UseSymbolTable) { + if (Opts.PrintFunctions != FunctionNameKind::None && Opts.UseSymbolTable) { std::string FunctionName; uint64_t Start, Size; if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, FunctionName, Start, Size)) { - patchFunctionNameInDILineInfo(FunctionName, LineInfo); + LineInfo.FunctionName = FunctionName; } } return LineInfo; @@ -133,14 +133,14 @@ DIInliningInfo ModuleInfo::symbolizeInlinedCode( DIInliningInfo InlinedContext; if (DebugInfoContext) { InlinedContext = DebugInfoContext->getInliningInfoForAddress( - ModuleOffset, getDILineInfoSpecifierFlags(Opts)); + ModuleOffset, getDILineInfoSpecifier(Opts)); } // Make sure there is at least one frame in context. if (InlinedContext.getNumberOfFrames() == 0) { InlinedContext.addFrame(DILineInfo()); } // Override the function name in lower frame with name from symbol table. - if (Opts.PrintFunctions && Opts.UseSymbolTable) { + if (Opts.PrintFunctions != FunctionNameKind::None && Opts.UseSymbolTable) { DIInliningInfo PatchedInlinedContext; for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { DILineInfo LineInfo = InlinedContext.getFrame(i); @@ -149,7 +149,7 @@ DIInliningInfo ModuleInfo::symbolizeInlinedCode( uint64_t Start, Size; if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, FunctionName, Start, Size)) { - patchFunctionNameInDILineInfo(FunctionName, LineInfo); + LineInfo.FunctionName = FunctionName; } } PatchedInlinedContext.addFrame(LineInfo); @@ -170,7 +170,7 @@ const char LLVMSymbolizer::kBadString[] = "??"; std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset) { ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); - if (Info == 0) + if (!Info) return printDILineInfo(DILineInfo()); if (Opts.PrintInlining) { DIInliningInfo InlinedContext = @@ -196,7 +196,7 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, if (Opts.UseSymbolTable) { if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) - Name = DemangleGlobalName(Name); + Name = DemangleName(Name); } } std::stringstream ss; @@ -206,7 +206,6 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, void LLVMSymbolizer::flush() { DeleteContainerSeconds(Modules); - DeleteContainerPointers(ParsedBinariesAndObjects); BinaryForPath.clear(); ObjectFileForArch.clear(); } @@ -221,10 +220,11 @@ static std::string getDarwinDWARFResourceForPath(const std::string &Path) { } static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - OwningPtr<MemoryBuffer> MB; - if (MemoryBuffer::getFileOrSTDIN(Path, MB)) + ErrorOr<std::unique_ptr<MemoryBuffer>> MB = + MemoryBuffer::getFileOrSTDIN(Path); + if (!MB) return false; - return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); + return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer()); } static bool findDebugBinary(const std::string &OrigPath, @@ -232,7 +232,7 @@ static bool findDebugBinary(const std::string &OrigPath, std::string &Result) { std::string OrigRealPath = OrigPath; #if defined(HAVE_REALPATH) - if (char *RP = realpath(OrigPath.c_str(), NULL)) { + if (char *RP = realpath(OrigPath.c_str(), nullptr)) { OrigRealPath = RP; free(RP); } @@ -269,15 +269,13 @@ static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName, const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin); if (!Obj) return false; - error_code EC; - for (section_iterator I = Obj->begin_sections(), E = Obj->end_sections(); - I != E; I.increment(EC)) { + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - I->getName(Name); + Section.getName(Name); Name = Name.substr(Name.find_first_not_of("._")); if (Name == "gnu_debuglink") { StringRef Data; - I->getContents(Data); + Section.getContents(Data); DataExtractor DE(Data, Obj->isLittleEndian(), 0); uint32_t Offset = 0; if (const char *DebugNameStr = DE.getCStr(&Offset)) { @@ -300,41 +298,42 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { BinaryMapTy::iterator I = BinaryForPath.find(Path); if (I != BinaryForPath.end()) return I->second; - Binary *Bin = 0; - Binary *DbgBin = 0; - OwningPtr<Binary> ParsedBinary; - OwningPtr<Binary> ParsedDbgBinary; - if (!error(createBinary(Path, ParsedBinary))) { + Binary *Bin = nullptr; + Binary *DbgBin = nullptr; + ErrorOr<Binary *> BinaryOrErr = createBinary(Path); + if (!error(BinaryOrErr.getError())) { + std::unique_ptr<Binary> ParsedBinary(BinaryOrErr.get()); // Check if it's a universal binary. - Bin = ParsedBinary.take(); - ParsedBinariesAndObjects.push_back(Bin); + Bin = ParsedBinary.get(); + ParsedBinariesAndObjects.push_back(std::move(ParsedBinary)); if (Bin->isMachO() || Bin->isMachOUniversalBinary()) { // On Darwin we may find DWARF in separate object file in // resource directory. const std::string &ResourcePath = getDarwinDWARFResourceForPath(Path); - bool ResourceFileExists = false; - if (!sys::fs::exists(ResourcePath, ResourceFileExists) && - ResourceFileExists && - !error(createBinary(ResourcePath, ParsedDbgBinary))) { - DbgBin = ParsedDbgBinary.take(); - ParsedBinariesAndObjects.push_back(DbgBin); + BinaryOrErr = createBinary(ResourcePath); + std::error_code EC = BinaryOrErr.getError(); + if (EC != errc::no_such_file_or_directory && !error(EC)) { + DbgBin = BinaryOrErr.get(); + ParsedBinariesAndObjects.push_back(std::unique_ptr<Binary>(DbgBin)); } } // Try to locate the debug binary using .gnu_debuglink section. - if (DbgBin == 0) { + if (!DbgBin) { std::string DebuglinkName; uint32_t CRCHash; std::string DebugBinaryPath; if (getGNUDebuglinkContents(Bin, DebuglinkName, CRCHash) && - findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath) && - !error(createBinary(DebugBinaryPath, ParsedDbgBinary))) { - DbgBin = ParsedDbgBinary.take(); - ParsedBinariesAndObjects.push_back(DbgBin); + findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) { + BinaryOrErr = createBinary(DebugBinaryPath); + if (!error(BinaryOrErr.getError())) { + DbgBin = BinaryOrErr.get(); + ParsedBinariesAndObjects.push_back(std::unique_ptr<Binary>(DbgBin)); + } } } } - if (DbgBin == 0) + if (!DbgBin) DbgBin = Bin; BinaryPair Res = std::make_pair(Bin, DbgBin); BinaryForPath[Path] = Res; @@ -343,18 +342,19 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { ObjectFile * LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) { - if (Bin == 0) - return 0; - ObjectFile *Res = 0; + if (!Bin) + return nullptr; + ObjectFile *Res = nullptr; if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find( std::make_pair(UB, ArchName)); if (I != ObjectFileForArch.end()) return I->second; - OwningPtr<ObjectFile> ParsedObj; - if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { - Res = ParsedObj.take(); - ParsedBinariesAndObjects.push_back(Res); + ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj = + UB->getObjectForArch(Triple(ArchName).getArch()); + if (ParsedObj) { + Res = ParsedObj.get().get(); + ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get())); } ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; } else if (Bin->isObject()) { @@ -383,10 +383,10 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName); ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName); - if (Obj == 0) { + if (!Obj) { // Failed to find valid object file. - Modules.insert(make_pair(ModuleName, (ModuleInfo *)0)); - return 0; + Modules.insert(make_pair(ModuleName, (ModuleInfo *)nullptr)); + return nullptr; } DIContext *Context = DIContext::getDWARFContext(DbgObj); assert(Context); @@ -400,19 +400,18 @@ std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const { // cannot fetch. We replace it to "??" to make our output closer to addr2line. static const std::string kDILineInfoBadString = "<invalid>"; std::stringstream Result; - if (Opts.PrintFunctions) { - std::string FunctionName = LineInfo.getFunctionName(); + if (Opts.PrintFunctions != FunctionNameKind::None) { + std::string FunctionName = LineInfo.FunctionName; if (FunctionName == kDILineInfoBadString) FunctionName = kBadString; else if (Opts.Demangle) FunctionName = DemangleName(FunctionName); Result << FunctionName << "\n"; } - std::string Filename = LineInfo.getFileName(); + std::string Filename = LineInfo.FileName; if (Filename == kDILineInfoBadString) Filename = kBadString; - Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn() - << "\n"; + Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n"; return Result.str(); } @@ -424,8 +423,12 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #if !defined(_MSC_VER) + // We can spoil names of symbols with C linkage, so use an heuristic + // approach to check if the name should be demangled. + if (Name.substr(0, 2) != "_Z") + return Name; int status = 0; - char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status); + char *DemangledName = __cxa_demangle(Name.c_str(), nullptr, nullptr, &status); if (status != 0) return Name; std::string Result = DemangledName; @@ -436,11 +439,5 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #endif } -std::string LLVMSymbolizer::DemangleGlobalName(const std::string &Name) { - // We can spoil names of globals with C linkage, so use an heuristic - // approach to check if the name should be demangled. - return (Name.substr(0, 2) == "_Z") ? DemangleName(Name) : Name; -} - } // namespace symbolize } // namespace llvm |