diff options
Diffstat (limited to 'tools/llvm-symbolizer')
-rw-r--r-- | tools/llvm-symbolizer/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/llvm-symbolizer/LLVMSymbolize.cpp | 131 | ||||
-rw-r--r-- | tools/llvm-symbolizer/LLVMSymbolize.h | 5 | ||||
-rw-r--r-- | tools/llvm-symbolizer/llvm-symbolizer.cpp | 41 |
4 files changed, 95 insertions, 83 deletions
diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt index 5967b89..9e76248 100644 --- a/tools/llvm-symbolizer/CMakeLists.txt +++ b/tools/llvm-symbolizer/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS DebugInfo Object + Support ) add_llvm_tool(llvm-symbolizer diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 320ab3f..13f2f8f 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -14,6 +14,7 @@ #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" @@ -21,7 +22,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" - #include <sstream> #include <stdlib.h> @@ -53,43 +53,51 @@ static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName, 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, std::string &Name, uint64_t &Addr, uint64_t &Size) const { @@ -196,7 +204,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; @@ -221,7 +229,7 @@ static std::string getDarwinDWARFResourceForPath(const std::string &Path) { } static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - OwningPtr<MemoryBuffer> MB; + std::unique_ptr<MemoryBuffer> MB; if (MemoryBuffer::getFileOrSTDIN(Path, MB)) return false; return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); @@ -269,15 +277,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)) { @@ -302,22 +308,21 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { return I->second; Binary *Bin = 0; Binary *DbgBin = 0; - OwningPtr<Binary> ParsedBinary; - OwningPtr<Binary> ParsedDbgBinary; - if (!error(createBinary(Path, ParsedBinary))) { + 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(); + Bin = ParsedBinary.release(); ParsedBinariesAndObjects.push_back(Bin); 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(); + BinaryOrErr = createBinary(ResourcePath); + error_code EC = BinaryOrErr.getError(); + if (EC != errc::no_such_file_or_directory && !error(EC)) { + DbgBin = BinaryOrErr.get(); ParsedBinariesAndObjects.push_back(DbgBin); } } @@ -327,10 +332,12 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { 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(DbgBin); + } } } } @@ -351,9 +358,9 @@ LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName std::make_pair(UB, ArchName)); if (I != ObjectFileForArch.end()) return I->second; - OwningPtr<ObjectFile> ParsedObj; + std::unique_ptr<ObjectFile> ParsedObj; if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { - Res = ParsedObj.take(); + Res = ParsedObj.release(); ParsedBinariesAndObjects.push_back(Res); } ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; @@ -424,6 +431,10 @@ 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); if (status != 0) @@ -436,11 +447,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 diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index eb2666a..288be80 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -13,7 +13,6 @@ #ifndef LLVM_SYMBOLIZE_H #define LLVM_SYMBOLIZE_H -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/MachOUniversal.h" @@ -71,7 +70,6 @@ private: ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName); std::string printDILineInfo(DILineInfo LineInfo) const; - static std::string DemangleGlobalName(const std::string &Name); // Owns all the parsed binaries and object files. SmallVector<Binary*, 4> ParsedBinariesAndObjects; @@ -103,8 +101,9 @@ private: bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size) const; + void addSymbol(const SymbolRef &Symbol); ObjectFile *Module; - OwningPtr<DIContext> DebugInfoContext; + std::unique_ptr<DIContext> DebugInfoContext; struct SymbolDesc { uint64_t Addr; diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index c32e949..83f5c5e 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -51,6 +51,11 @@ static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), cl::desc("Default architecture " "(for multi-arch objects)")); +static cl::opt<std::string> +ClBinaryName("obj", cl::init(""), + cl::desc("Path to object file to be symbolized (if not provided, " + "object file should be specified for each input line)")); + static bool parseCommand(bool &IsData, std::string &ModuleName, uint64_t &ModuleOffset) { const char *kDataCmd = "DATA "; @@ -62,7 +67,6 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, return false; IsData = false; ModuleName = ""; - std::string ModuleOffsetStr = ""; char *pos = InputString; if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { IsData = true; @@ -74,26 +78,29 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, // If no cmd, assume it's CODE. IsData = false; } - // Skip delimiters and parse input filename. - pos += strspn(pos, kDelimiters); - if (*pos == '"' || *pos == '\'') { - char quote = *pos; - pos++; - char *end = strchr(pos, quote); - if (end == 0) - return false; - ModuleName = std::string(pos, end - pos); - pos = end + 1; + // Skip delimiters and parse input filename (if needed). + if (ClBinaryName == "") { + pos += strspn(pos, kDelimiters); + if (*pos == '"' || *pos == '\'') { + char quote = *pos; + pos++; + char *end = strchr(pos, quote); + if (end == 0) + return false; + ModuleName = std::string(pos, end - pos); + pos = end + 1; + } else { + int name_length = strcspn(pos, kDelimiters); + ModuleName = std::string(pos, name_length); + pos += name_length; + } } else { - int name_length = strcspn(pos, kDelimiters); - ModuleName = std::string(pos, name_length); - pos += name_length; + ModuleName = ClBinaryName; } // Skip delimiters and parse module offset. pos += strspn(pos, kDelimiters); int offset_length = strcspn(pos, kDelimiters); - ModuleOffsetStr = std::string(pos, offset_length); - if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset)) + if (StringRef(pos, offset_length).getAsInteger(0, ModuleOffset)) return false; return true; } @@ -104,7 +111,7 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); + cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n"); LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, ClPrintInlining, ClDemangle, ClDefaultArch); LLVMSymbolizer Symbolizer(Opts); |