1f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===// 2f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// 3f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// The LLVM Compiler Infrastructure 4f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// 5f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// This file is distributed under the University of Illinois Open Source 6f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// License. See LICENSE.TXT for details. 7f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// 8f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko//===----------------------------------------------------------------------===// 9f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// 10f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// This utility works much like "addr2line". It is able of transforming 11f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// tuples (module name, module offset) to code locations (function name, 12f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// file, line number, column number). It is targeted for compiler-rt tools 13f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// (especially AddressSanitizer and ThreadSanitizer) that can use it 14f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// to symbolize stack traces in their error reports. 15f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko// 16f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko//===----------------------------------------------------------------------===// 17f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 18c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov#include "LLVMSymbolize.h" 19f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/ADT/StringRef.h" 20f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/CommandLine.h" 21f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/Debug.h" 22f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/ManagedStatic.h" 23f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/PrettyStackTrace.h" 24f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/Signals.h" 25f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include "llvm/Support/raw_ostream.h" 26f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include <cstdio> 27f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include <cstring> 28f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko#include <string> 29f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 30f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenkousing namespace llvm; 31c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonovusing namespace symbolize; 32f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 33f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenkostatic cl::opt<bool> 34c4c7ea3184335259da63d973acbed2043e8a6523Alexey SamsonovClUseSymbolTable("use-symbol-table", cl::init(true), 35c4439c3508aa705add9dc46106270f0b3763b882Alexey Samsonov cl::desc("Prefer names in symbol table to names " 36c4439c3508aa705add9dc46106270f0b3763b882Alexey Samsonov "in debug info")); 37f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 38dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesstatic cl::opt<FunctionNameKind> ClPrintFunctions( 39dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines "functions", cl::init(FunctionNameKind::LinkageName), 40dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines cl::desc("Print function name for a given address:"), 41dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"), 42dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines clEnumValN(FunctionNameKind::ShortName, "short", 43dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines "print short function name"), 44dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines clEnumValN(FunctionNameKind::LinkageName, "linkage", 45dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines "print function linkage name"), 46dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines clEnumValEnd)); 47f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 48f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenkostatic cl::opt<bool> 49c4c7ea3184335259da63d973acbed2043e8a6523Alexey SamsonovClPrintInlining("inlining", cl::init(true), 50c4439c3508aa705add9dc46106270f0b3763b882Alexey Samsonov cl::desc("Print all inlined frames for a given address")); 51f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 52f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenkostatic cl::opt<bool> 53c4439c3508aa705add9dc46106270f0b3763b882Alexey SamsonovClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); 54f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 558175bc3d3bc8567a90b9dd50d68c1423baffd63bAlexey Samsonovstatic cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), 568175bc3d3bc8567a90b9dd50d68c1423baffd63bAlexey Samsonov cl::desc("Default architecture " 578175bc3d3bc8567a90b9dd50d68c1423baffd63bAlexey Samsonov "(for multi-arch objects)")); 588175bc3d3bc8567a90b9dd50d68c1423baffd63bAlexey Samsonov 5936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic cl::opt<std::string> 6036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen HinesClBinaryName("obj", cl::init(""), 6136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines cl::desc("Path to object file to be symbolized (if not provided, " 6236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines "object file should be specified for each input line)")); 6336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines 64c4439c3508aa705add9dc46106270f0b3763b882Alexey Samsonovstatic bool parseCommand(bool &IsData, std::string &ModuleName, 65c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov uint64_t &ModuleOffset) { 66fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov const char *kDataCmd = "DATA "; 67fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov const char *kCodeCmd = "CODE "; 68fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov const int kMaxInputStringLength = 1024; 69fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov const char kDelimiters[] = " \n"; 70f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko char InputString[kMaxInputStringLength]; 71f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko if (!fgets(InputString, sizeof(InputString), stdin)) 72f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko return false; 73fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov IsData = false; 74f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko ModuleName = ""; 75fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov char *pos = InputString; 76fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { 77fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov IsData = true; 78fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov pos += strlen(kDataCmd); 79fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov } else if (strncmp(pos, kCodeCmd, strlen(kCodeCmd)) == 0) { 80fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov IsData = false; 81fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov pos += strlen(kCodeCmd); 82fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov } else { 83fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov // If no cmd, assume it's CODE. 84fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov IsData = false; 85fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov } 8636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // Skip delimiters and parse input filename (if needed). 8736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if (ClBinaryName == "") { 8836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines pos += strspn(pos, kDelimiters); 8936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if (*pos == '"' || *pos == '\'') { 9036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines char quote = *pos; 9136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines pos++; 9236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines char *end = strchr(pos, quote); 93dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines if (!end) 9436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return false; 9536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines ModuleName = std::string(pos, end - pos); 9636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines pos = end + 1; 9736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } else { 9836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines int name_length = strcspn(pos, kDelimiters); 9936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines ModuleName = std::string(pos, name_length); 10036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines pos += name_length; 10136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 102ef148afba873b1e24af1b3c22148f967b9b8a232Alexey Samsonov } else { 10336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines ModuleName = ClBinaryName; 104f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko } 105ef148afba873b1e24af1b3c22148f967b9b8a232Alexey Samsonov // Skip delimiters and parse module offset. 106ef148afba873b1e24af1b3c22148f967b9b8a232Alexey Samsonov pos += strspn(pos, kDelimiters); 107ef148afba873b1e24af1b3c22148f967b9b8a232Alexey Samsonov int offset_length = strcspn(pos, kDelimiters); 10836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if (StringRef(pos, offset_length).getAsInteger(0, ModuleOffset)) 109c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov return false; 110f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko return true; 111f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko} 112f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 113f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenkoint main(int argc, char **argv) { 114f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko // Print stack trace if we signal out. 115f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko sys::PrintStackTraceOnErrorSignal(); 116f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko PrettyStackTraceProgram X(argc, argv); 117c4439c3508aa705add9dc46106270f0b3763b882Alexey Samsonov llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 118f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 11936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n"); 120c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, 1218175bc3d3bc8567a90b9dd50d68c1423baffd63bAlexey Samsonov ClPrintInlining, ClDemangle, ClDefaultArch); 122c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov LLVMSymbolizer Symbolizer(Opts); 123f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko 124fc183ceae302f7dcfd23a6f0e6c801d74f560ca8Dmitry Vyukov bool IsData = false; 125f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko std::string ModuleName; 126c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov uint64_t ModuleOffset; 127c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov while (parseCommand(IsData, ModuleName, ModuleOffset)) { 128c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov std::string Result = 129c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset) 130c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov : Symbolizer.symbolizeCode(ModuleName, ModuleOffset); 131c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov outs() << Result << "\n"; 132c4c7ea3184335259da63d973acbed2043e8a6523Alexey Samsonov outs().flush(); 133f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko } 134f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko return 0; 135f41954b7328dd53c883810f31cf13d4455199c1dAlexander Potapenko} 136