X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-symbolizer%2Fllvm-symbolizer.cpp;h=950349377bf79c21ca85579188212b8442cc670c;hp=f3335a3fc36c62ef24eb30c4ad6ef3e29ca78a18;hb=d9750d38e1af417c1afaed440fcba6bc068a529c;hpb=d1726a4580f3dc42e2debbfea41acb9e815c06be diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index f3335a3fc36..950349377bf 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -15,309 +15,188 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" +#include "llvm/DebugInfo/Symbolize/DIPrinter.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" +#include "llvm/Support/COM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" - #include #include -#include #include using namespace llvm; -using namespace object; +using namespace symbolize; static cl::opt -UseSymbolTable("use-symbol-table", cl::init(true), - cl::desc("Prefer names in symbol table to names " - "in debug info")); +ClUseSymbolTable("use-symbol-table", cl::init(true), + cl::desc("Prefer names in symbol table to names " + "in debug info")); + +static cl::opt ClPrintFunctions( + "functions", cl::init(FunctionNameKind::LinkageName), + cl::desc("Print function name for a given address:"), + cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"), + clEnumValN(FunctionNameKind::ShortName, "short", + "print short function name"), + clEnumValN(FunctionNameKind::LinkageName, "linkage", + "print function linkage name"), + clEnumValEnd)); static cl::opt -PrintFunctions("functions", cl::init(true), - cl::desc("Print function names as well as line " - "information for a given address")); + ClUseRelativeAddress("relative-address", cl::init(false), + cl::desc("Interpret addresses as relative addresses"), + cl::ReallyHidden); static cl::opt -PrintInlining("inlining", cl::init(true), - cl::desc("Print all inlined frames for a given address")); + ClPrintInlining("inlining", cl::init(true), + cl::desc("Print all inlined frames for a given address")); static cl::opt -Demangle("demangle", cl::init(true), - cl::desc("Demangle function names")); - -static StringRef ToolInvocationPath; +ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); -static bool error(error_code ec) { - if (!ec) return false; - errs() << ToolInvocationPath << ": error reading file: " - << ec.message() << ".\n"; - return true; -} +static cl::opt ClDefaultArch("default-arch", cl::init(""), + cl::desc("Default architecture " + "(for multi-arch objects)")); -static uint32_t getDILineInfoSpecifierFlags() { - uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo | - llvm::DILineInfoSpecifier::AbsoluteFilePath; - if (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 cl::opt +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)")); -namespace { -class ModuleInfo { - OwningPtr Module; - OwningPtr DebugInfoContext; - public: - ModuleInfo(ObjectFile *Obj, DIContext *DICtx) - : Module(Obj), DebugInfoContext(DICtx) {} +static cl::list +ClDsymHint("dsym-hint", cl::ZeroOrMore, + cl::desc("Path to .dSYM bundles to search for debug info for the " + "object files")); +static cl::opt + ClPrintAddress("print-address", cl::init(false), + cl::desc("Show address before line information")); - DILineInfo symbolizeCode(uint64_t ModuleOffset) const { - DILineInfo LineInfo; - if (DebugInfoContext) { - LineInfo = DebugInfoContext->getLineInfoForAddress( - ModuleOffset, getDILineInfoSpecifierFlags()); - } - // Override function name from symbol table if necessary. - if (PrintFunctions && UseSymbolTable) { - std::string Function; - if (getFunctionNameFromSymbolTable(ModuleOffset, Function)) { - patchFunctionNameInDILineInfo(Function, LineInfo); - } - } - return LineInfo; - } +static cl::opt + ClPrettyPrint("pretty-print", cl::init(false), + cl::desc("Make the output more human friendly")); - DIInliningInfo symbolizeInlinedCode(uint64_t ModuleOffset) const { - DIInliningInfo InlinedContext; - if (DebugInfoContext) { - InlinedContext = DebugInfoContext->getInliningInfoForAddress( - ModuleOffset, getDILineInfoSpecifierFlags()); - } - // 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 (PrintFunctions && UseSymbolTable) { - DIInliningInfo PatchedInlinedContext; - for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); - i != n; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - if (i == n - 1) { - std::string Function; - if (getFunctionNameFromSymbolTable(ModuleOffset, Function)) { - patchFunctionNameInDILineInfo(Function, LineInfo); - } - } - PatchedInlinedContext.addFrame(LineInfo); - } - InlinedContext = PatchedInlinedContext; - } - return InlinedContext; - } +static cl::opt ClPrintSourceContextLines( + "print-source-context-lines", cl::init(0), + cl::desc("Print N number of source file context")); - private: - bool getFunctionNameFromSymbolTable(uint64_t Address, - std::string &FunctionName) const { - assert(Module); - error_code ec; - for (symbol_iterator si = Module->begin_symbols(), - se = Module->end_symbols(); - si != se; si.increment(ec)) { - if (error(ec)) return false; - uint64_t SymbolAddress; - uint64_t SymbolSize; - SymbolRef::Type SymbolType; - if (error(si->getAddress(SymbolAddress)) || - SymbolAddress == UnknownAddressOrSize) continue; - if (error(si->getSize(SymbolSize)) || - SymbolSize == UnknownAddressOrSize) continue; - if (error(si->getType(SymbolType))) continue; - // FIXME: If a function has alias, there are two entries in symbol table - // with same address size. Make sure we choose the correct one. - if (SymbolAddress <= Address && Address < SymbolAddress + SymbolSize && - SymbolType == SymbolRef::ST_Function) { - StringRef Name; - if (error(si->getName(Name))) continue; - FunctionName = Name.str(); - return true; - } - } +static bool error(std::error_code ec) { + if (!ec) return false; - } -}; - -typedef std::map ModuleMapTy; -typedef ModuleMapTy::iterator ModuleMapIter; -} // namespace - -static ModuleMapTy Modules; - -// Returns true if the object endianness is known. -static bool getObjectEndianness(const ObjectFile *Obj, - bool &IsLittleEndian) { - // FIXME: Implement this when libLLVMObject allows to do it easily. - IsLittleEndian = true; + errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; return true; } -static ObjectFile *getObjectFile(const std::string &Path) { - OwningPtr Buff; - MemoryBuffer::getFile(Path, Buff); - return ObjectFile::createObjectFile(Buff.take()); -} - -static std::string getDarwinDWARFResourceForModule(const std::string &Path) { - StringRef Basename = sys::path::filename(Path); - const std::string &DSymDirectory = Path + ".dSYM"; - SmallString<16> ResourceName = StringRef(DSymDirectory); - sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); - sys::path::append(ResourceName, Basename); - return ResourceName.str(); -} - -static ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName) { - ModuleMapIter I = Modules.find(ModuleName); - if (I != Modules.end()) - return I->second; - - ObjectFile *Obj = getObjectFile(ModuleName); - ObjectFile *DbgObj = Obj; - if (Obj == 0) { - // Module name doesn't point to a valid object file. - Modules.insert(make_pair(ModuleName, (ModuleInfo*)0)); - return 0; +static bool parseCommand(StringRef InputString, bool &IsData, + std::string &ModuleName, uint64_t &ModuleOffset) { + const char *kDataCmd = "DATA "; + const char *kCodeCmd = "CODE "; + const char kDelimiters[] = " \n\r"; + IsData = false; + ModuleName = ""; + const char *pos = InputString.data(); + if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { + IsData = true; + pos += strlen(kDataCmd); + } else if (strncmp(pos, kCodeCmd, strlen(kCodeCmd)) == 0) { + IsData = false; + pos += strlen(kCodeCmd); + } else { + // If no cmd, assume it's CODE. + IsData = false; } - - DIContext *Context = 0; - bool IsLittleEndian; - if (getObjectEndianness(Obj, IsLittleEndian)) { - // On Darwin we may find DWARF in separate object file in - // resource directory. - if (isa(Obj)) { - const std::string &ResourceName = getDarwinDWARFResourceForModule( - ModuleName); - ObjectFile *ResourceObj = getObjectFile(ResourceName); - if (ResourceObj != 0) - DbgObj = ResourceObj; + // Skip delimiters and parse input filename (if needed). + if (ClBinaryName == "") { + pos += strspn(pos, kDelimiters); + if (*pos == '"' || *pos == '\'') { + char quote = *pos; + pos++; + const char *end = strchr(pos, quote); + if (!end) + 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; } - Context = DIContext::getDWARFContext(DbgObj); - assert(Context); + } else { + ModuleName = ClBinaryName; } - - ModuleInfo *Info = new ModuleInfo(Obj, Context); - Modules.insert(make_pair(ModuleName, Info)); - return Info; + // Skip delimiters and parse module offset. + pos += strspn(pos, kDelimiters); + int offset_length = strcspn(pos, kDelimiters); + return !StringRef(pos, offset_length).getAsInteger(0, ModuleOffset); } -#if !defined(_MSC_VER) -// Assume that __cxa_demangle is provided by libcxxabi (except for Windows). -extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, - size_t *length, int *status); -#endif +int main(int argc, char **argv) { + // Print stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); -static void printDILineInfo(DILineInfo LineInfo) { - // By default, DILineInfo contains "" for function/filename it - // cannot fetch. We replace it to "??" to make our output closer to addr2line. - static const std::string kDILineInfoBadString = ""; - static const std::string kSymbolizerBadString = "??"; - if (PrintFunctions) { - std::string FunctionName = LineInfo.getFunctionName(); - if (FunctionName == kDILineInfoBadString) - FunctionName = kSymbolizerBadString; -#if !defined(_MSC_VER) - if (Demangle) { - int status = 0; - char *DemangledName = __cxa_demangle( - FunctionName.c_str(), 0, 0, &status); - if (status == 0) { - FunctionName = DemangledName; - free(DemangledName); - } - } -#endif - outs() << FunctionName << "\n"; - } - std::string Filename = LineInfo.getFileName(); - if (Filename == kDILineInfoBadString) - Filename = kSymbolizerBadString; - outs() << Filename << - ":" << LineInfo.getLine() << - ":" << LineInfo.getColumn() << - "\n"; -} + cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n"); + LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, ClDemangle, + ClUseRelativeAddress, ClDefaultArch); -static void symbolize(std::string ModuleName, std::string ModuleOffsetStr) { - ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); - uint64_t Offset = 0; - if (Info == 0 || - StringRef(ModuleOffsetStr).getAsInteger(0, Offset)) { - printDILineInfo(DILineInfo()); - } else if (PrintInlining) { - DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(Offset); - uint32_t FramesNum = InlinedContext.getNumberOfFrames(); - assert(FramesNum > 0); - for (uint32_t i = 0; i < FramesNum; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - printDILineInfo(LineInfo); + for (const auto &hint : ClDsymHint) { + if (sys::path::extension(hint) == ".dSYM") { + Opts.DsymHints.push_back(hint); + } else { + errs() << "Warning: invalid dSYM hint: \"" << hint << + "\" (must have the '.dSYM' extension).\n"; } - } else { - DILineInfo LineInfo = Info->symbolizeCode(Offset); - printDILineInfo(LineInfo); } + LLVMSymbolizer Symbolizer(Opts); - outs() << "\n"; // Print extra empty line to mark the end of output. - outs().flush(); -} + DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None, + ClPrettyPrint, ClPrintSourceContextLines); -static bool parseModuleNameAndOffset(std::string &ModuleName, - std::string &ModuleOffsetStr) { - static const int kMaxInputStringLength = 1024; - static const char kDelimiters[] = " \n"; + const int kMaxInputStringLength = 1024; char InputString[kMaxInputStringLength]; - if (!fgets(InputString, sizeof(InputString), stdin)) - return false; - ModuleName = ""; - ModuleOffsetStr = ""; - // FIXME: Handle case when filename is given in quotes. - if (char *FilePath = strtok(InputString, kDelimiters)) { - ModuleName = FilePath; - if (char *OffsetStr = strtok((char*)0, kDelimiters)) - ModuleOffsetStr = OffsetStr; - } - return true; -} -int main(int argc, char **argv) { - // Print stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); - ToolInvocationPath = argv[0]; + while (true) { + if (!fgets(InputString, sizeof(InputString), stdin)) + break; + + bool IsData = false; + std::string ModuleName; + uint64_t ModuleOffset = 0; + if (!parseCommand(StringRef(InputString), IsData, ModuleName, + ModuleOffset)) { + outs() << InputString; + continue; + } - std::string ModuleName; - std::string ModuleOffsetStr; - while (parseModuleNameAndOffset(ModuleName, ModuleOffsetStr)) { - symbolize(ModuleName, ModuleOffsetStr); + if (ClPrintAddress) { + outs() << "0x"; + outs().write_hex(ModuleOffset); + StringRef Delimiter = (ClPrettyPrint == true) ? ": " : "\n"; + outs() << Delimiter; + } + if (IsData) { + auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get()); + } else if (ClPrintInlining) { + auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DIInliningInfo() + : ResOrErr.get()); + } else { + auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get()); + } + outs() << "\n"; + outs().flush(); } + return 0; }