1249259Sdim//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10249259Sdim// This utility works much like "addr2line". It is able of transforming 11249259Sdim// tuples (module name, module offset) to code locations (function name, 12249259Sdim// file, line number, column number). It is targeted for compiler-rt tools 13249259Sdim// (especially AddressSanitizer and ThreadSanitizer) that can use it 14249259Sdim// to symbolize stack traces in their error reports. 15249259Sdim// 16249259Sdim//===----------------------------------------------------------------------===// 17249259Sdim 18249259Sdim#include "LLVMSymbolize.h" 19249259Sdim#include "llvm/ADT/StringRef.h" 20249259Sdim#include "llvm/Support/CommandLine.h" 21249259Sdim#include "llvm/Support/Debug.h" 22249259Sdim#include "llvm/Support/ManagedStatic.h" 23249259Sdim#include "llvm/Support/PrettyStackTrace.h" 24249259Sdim#include "llvm/Support/Signals.h" 25249259Sdim#include "llvm/Support/raw_ostream.h" 26249259Sdim#include <cstdio> 27249259Sdim#include <cstring> 28249259Sdim#include <string> 29249259Sdim 30249259Sdimusing namespace llvm; 31249259Sdimusing namespace symbolize; 32249259Sdim 33249259Sdimstatic cl::opt<bool> 34249259SdimClUseSymbolTable("use-symbol-table", cl::init(true), 35249259Sdim cl::desc("Prefer names in symbol table to names " 36249259Sdim "in debug info")); 37249259Sdim 38249259Sdimstatic cl::opt<bool> 39249259SdimClPrintFunctions("functions", cl::init(true), 40249259Sdim cl::desc("Print function names as well as line " 41249259Sdim "information for a given address")); 42249259Sdim 43249259Sdimstatic cl::opt<bool> 44249259SdimClPrintInlining("inlining", cl::init(true), 45249259Sdim cl::desc("Print all inlined frames for a given address")); 46249259Sdim 47249259Sdimstatic cl::opt<bool> 48249259SdimClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); 49249259Sdim 50263508Sdimstatic cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), 51263508Sdim cl::desc("Default architecture " 52263508Sdim "(for multi-arch objects)")); 53263508Sdim 54249259Sdimstatic bool parseCommand(bool &IsData, std::string &ModuleName, 55249259Sdim uint64_t &ModuleOffset) { 56249259Sdim const char *kDataCmd = "DATA "; 57249259Sdim const char *kCodeCmd = "CODE "; 58249259Sdim const int kMaxInputStringLength = 1024; 59249259Sdim const char kDelimiters[] = " \n"; 60249259Sdim char InputString[kMaxInputStringLength]; 61249259Sdim if (!fgets(InputString, sizeof(InputString), stdin)) 62249259Sdim return false; 63249259Sdim IsData = false; 64249259Sdim ModuleName = ""; 65249259Sdim std::string ModuleOffsetStr = ""; 66249259Sdim char *pos = InputString; 67249259Sdim if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { 68249259Sdim IsData = true; 69249259Sdim pos += strlen(kDataCmd); 70249259Sdim } else if (strncmp(pos, kCodeCmd, strlen(kCodeCmd)) == 0) { 71249259Sdim IsData = false; 72249259Sdim pos += strlen(kCodeCmd); 73249259Sdim } else { 74249259Sdim // If no cmd, assume it's CODE. 75249259Sdim IsData = false; 76249259Sdim } 77249259Sdim // Skip delimiters and parse input filename. 78249259Sdim pos += strspn(pos, kDelimiters); 79249259Sdim if (*pos == '"' || *pos == '\'') { 80249259Sdim char quote = *pos; 81249259Sdim pos++; 82249259Sdim char *end = strchr(pos, quote); 83249259Sdim if (end == 0) 84249259Sdim return false; 85249259Sdim ModuleName = std::string(pos, end - pos); 86249259Sdim pos = end + 1; 87249259Sdim } else { 88249259Sdim int name_length = strcspn(pos, kDelimiters); 89249259Sdim ModuleName = std::string(pos, name_length); 90249259Sdim pos += name_length; 91249259Sdim } 92249259Sdim // Skip delimiters and parse module offset. 93249259Sdim pos += strspn(pos, kDelimiters); 94249259Sdim int offset_length = strcspn(pos, kDelimiters); 95249259Sdim ModuleOffsetStr = std::string(pos, offset_length); 96249259Sdim if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset)) 97249259Sdim return false; 98249259Sdim return true; 99249259Sdim} 100249259Sdim 101249259Sdimint main(int argc, char **argv) { 102249259Sdim // Print stack trace if we signal out. 103249259Sdim sys::PrintStackTraceOnErrorSignal(); 104249259Sdim PrettyStackTraceProgram X(argc, argv); 105249259Sdim llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 106249259Sdim 107249259Sdim cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); 108249259Sdim LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, 109263508Sdim ClPrintInlining, ClDemangle, ClDefaultArch); 110249259Sdim LLVMSymbolizer Symbolizer(Opts); 111249259Sdim 112249259Sdim bool IsData = false; 113249259Sdim std::string ModuleName; 114249259Sdim uint64_t ModuleOffset; 115249259Sdim while (parseCommand(IsData, ModuleName, ModuleOffset)) { 116249259Sdim std::string Result = 117249259Sdim IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset) 118249259Sdim : Symbolizer.symbolizeCode(ModuleName, ModuleOffset); 119249259Sdim outs() << Result << "\n"; 120249259Sdim outs().flush(); 121249259Sdim } 122249259Sdim return 0; 123249259Sdim} 124