Home | History | Annotate | Download | only in llvm-symbolizer
      1 //===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This utility works much like "addr2line". It is able of transforming
     11 // tuples (module name, module offset) to code locations (function name,
     12 // file, line number, column number). It is targeted for compiler-rt tools
     13 // (especially AddressSanitizer and ThreadSanitizer) that can use it
     14 // to symbolize stack traces in their error reports.
     15 //
     16 //===----------------------------------------------------------------------===//
     17 
     18 #include "llvm/ADT/OwningPtr.h"
     19 #include "llvm/ADT/StringRef.h"
     20 #include "llvm/DebugInfo/DIContext.h"
     21 #include "llvm/Object/ObjectFile.h"
     22 #include "llvm/Support/CommandLine.h"
     23 #include "llvm/Support/Debug.h"
     24 #include "llvm/Support/ManagedStatic.h"
     25 #include "llvm/Support/MemoryBuffer.h"
     26 #include "llvm/Support/PrettyStackTrace.h"
     27 #include "llvm/Support/Signals.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 
     30 #include <cstdio>
     31 #include <cstring>
     32 #include <map>
     33 #include <string>
     34 
     35 using namespace llvm;
     36 using namespace object;
     37 using std::string;
     38 
     39 static cl::opt<bool>
     40 UseSymbolTable("use-symbol-table", cl::init(true),
     41                cl::desc("Prefer names in symbol table to names "
     42                         "in debug info"));
     43 
     44 static cl::opt<bool>
     45 PrintFunctions("functions", cl::init(true),
     46                cl::desc("Print function names as well as line "
     47                         "information for a given address"));
     48 
     49 static cl::opt<bool>
     50 PrintInlining("inlining", cl::init(true),
     51               cl::desc("Print all inlined frames for a given address"));
     52 
     53 static cl::opt<bool>
     54 Demangle("demangle", cl::init(true),
     55          cl::desc("Demangle function names"));
     56 
     57 static StringRef ToolInvocationPath;
     58 
     59 static bool error(error_code ec) {
     60   if (!ec) return false;
     61   errs() << ToolInvocationPath << ": error reading file: "
     62          << ec.message() << ".\n";
     63   return true;
     64 }
     65 
     66 static uint32_t getDILineInfoSpecifierFlags() {
     67   uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo |
     68                    llvm::DILineInfoSpecifier::AbsoluteFilePath;
     69   if (PrintFunctions)
     70     Flags |= llvm::DILineInfoSpecifier::FunctionName;
     71   return Flags;
     72 }
     73 
     74 static void patchFunctionNameInDILineInfo(const string &NewFunctionName,
     75                                           DILineInfo &LineInfo) {
     76   string FileName = LineInfo.getFileName();
     77   LineInfo = DILineInfo(StringRef(FileName), StringRef(NewFunctionName),
     78                         LineInfo.getLine(), LineInfo.getColumn());
     79 }
     80 
     81 namespace {
     82 class ModuleInfo {
     83   OwningPtr<ObjectFile> Module;
     84   OwningPtr<DIContext> DebugInfoContext;
     85  public:
     86   ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
     87       : Module(Obj), DebugInfoContext(DICtx) {}
     88   DILineInfo symbolizeCode(uint64_t ModuleOffset) const {
     89     DILineInfo LineInfo;
     90     if (DebugInfoContext) {
     91       LineInfo = DebugInfoContext->getLineInfoForAddress(
     92           ModuleOffset, getDILineInfoSpecifierFlags());
     93     }
     94     // Override function name from symbol table if necessary.
     95     if (PrintFunctions && UseSymbolTable) {
     96       string Function;
     97       if (getFunctionNameFromSymbolTable(ModuleOffset, Function)) {
     98         patchFunctionNameInDILineInfo(Function, LineInfo);
     99       }
    100     }
    101     return LineInfo;
    102   }
    103   DIInliningInfo symbolizeInlinedCode(uint64_t ModuleOffset) const {
    104     DIInliningInfo InlinedContext;
    105     if (DebugInfoContext) {
    106       InlinedContext = DebugInfoContext->getInliningInfoForAddress(
    107           ModuleOffset, getDILineInfoSpecifierFlags());
    108     }
    109     // Make sure there is at least one frame in context.
    110     if (InlinedContext.getNumberOfFrames() == 0) {
    111       InlinedContext.addFrame(DILineInfo());
    112     }
    113     // Override the function name in lower frame with name from symbol table.
    114     if (PrintFunctions && UseSymbolTable) {
    115       DIInliningInfo PatchedInlinedContext;
    116       for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames();
    117            i != n; i++) {
    118         DILineInfo LineInfo = InlinedContext.getFrame(i);
    119         if (i == n - 1) {
    120           string Function;
    121           if (getFunctionNameFromSymbolTable(ModuleOffset, Function)) {
    122             patchFunctionNameInDILineInfo(Function, LineInfo);
    123           }
    124         }
    125         PatchedInlinedContext.addFrame(LineInfo);
    126       }
    127       InlinedContext = PatchedInlinedContext;
    128     }
    129     return InlinedContext;
    130   }
    131  private:
    132   bool getFunctionNameFromSymbolTable(size_t Address,
    133                                       string &FunctionName) const {
    134     assert(Module);
    135     error_code ec;
    136     for (symbol_iterator si = Module->begin_symbols(),
    137                          se = Module->end_symbols();
    138                          si != se; si.increment(ec)) {
    139       if (error(ec)) return false;
    140       uint64_t SymbolAddress;
    141       uint64_t SymbolSize;
    142       if (error(si->getAddress(SymbolAddress))) continue;
    143       if (error(si->getSize(SymbolSize))) continue;
    144       // FIXME: If a function has alias, there are two entries in symbol table
    145       // with same address size. Make sure we choose the correct one.
    146       if (SymbolAddress <= Address && Address < SymbolAddress + SymbolSize) {
    147         StringRef Name;
    148         if (error(si->getName(Name))) continue;
    149         FunctionName = Name.str();
    150         return true;
    151       }
    152     }
    153     return false;
    154   }
    155 };
    156 
    157 typedef std::map<string, ModuleInfo*> ModuleMapTy;
    158 typedef ModuleMapTy::iterator ModuleMapIter;
    159 typedef ModuleMapTy::const_iterator ModuleMapConstIter;
    160 }  // namespace
    161 
    162 static ModuleMapTy Modules;
    163 
    164 static bool isFullNameOfDwarfSection(const StringRef &FullName,
    165                                      const StringRef &ShortName) {
    166   static const char kDwarfPrefix[] = "__DWARF,";
    167   StringRef Name = FullName;
    168   // Skip "__DWARF," prefix.
    169   if (Name.startswith(kDwarfPrefix))
    170     Name = Name.substr(strlen(kDwarfPrefix));
    171   // Skip . and _ prefixes.
    172   Name = Name.substr(Name.find_first_not_of("._"));
    173   return (Name == ShortName);
    174 }
    175 
    176 // Returns true if the object endianness is known.
    177 static bool getObjectEndianness(const ObjectFile *Obj,
    178                                 bool &IsLittleEndian) {
    179   // FIXME: Implement this when libLLVMObject allows to do it easily.
    180   IsLittleEndian = true;
    181   return true;
    182 }
    183 
    184 static ModuleInfo *getOrCreateModuleInfo(const string &ModuleName) {
    185   ModuleMapIter I = Modules.find(ModuleName);
    186   if (I != Modules.end())
    187     return I->second;
    188 
    189   OwningPtr<MemoryBuffer> Buff;
    190   MemoryBuffer::getFile(ModuleName, Buff);
    191   ObjectFile *Obj = ObjectFile::createObjectFile(Buff.take());
    192   if (Obj == 0) {
    193     // Module name doesn't point to a valid object file.
    194     Modules.insert(make_pair(ModuleName, (ModuleInfo*)0));
    195     return 0;
    196   }
    197 
    198   DIContext *Context = 0;
    199   bool IsLittleEndian;
    200   if (getObjectEndianness(Obj, IsLittleEndian)) {
    201     StringRef DebugInfoSection;
    202     StringRef DebugAbbrevSection;
    203     StringRef DebugLineSection;
    204     StringRef DebugArangesSection;
    205     StringRef DebugStringSection;
    206     StringRef DebugRangesSection;
    207     error_code ec;
    208     for (section_iterator i = Obj->begin_sections(),
    209                           e = Obj->end_sections();
    210                           i != e; i.increment(ec)) {
    211       if (error(ec)) break;
    212       StringRef Name;
    213       if (error(i->getName(Name))) continue;
    214       StringRef Data;
    215       if (error(i->getContents(Data))) continue;
    216       if (isFullNameOfDwarfSection(Name, "debug_info"))
    217         DebugInfoSection = Data;
    218       else if (isFullNameOfDwarfSection(Name, "debug_abbrev"))
    219         DebugAbbrevSection = Data;
    220       else if (isFullNameOfDwarfSection(Name, "debug_line"))
    221         DebugLineSection = Data;
    222       // Don't use debug_aranges for now, as address ranges contained
    223       // there may not cover all instructions in the module
    224       // else if (isFullNameOfDwarfSection(Name, "debug_aranges"))
    225       //   DebugArangesSection = Data;
    226       else if (isFullNameOfDwarfSection(Name, "debug_str"))
    227         DebugStringSection = Data;
    228       else if (isFullNameOfDwarfSection(Name, "debug_ranges"))
    229         DebugRangesSection = Data;
    230     }
    231 
    232     Context = DIContext::getDWARFContext(
    233         IsLittleEndian, DebugInfoSection, DebugAbbrevSection,
    234         DebugArangesSection, DebugLineSection, DebugStringSection,
    235         DebugRangesSection);
    236     assert(Context);
    237   }
    238 
    239   ModuleInfo *Info = new ModuleInfo(Obj, Context);
    240   Modules.insert(make_pair(ModuleName, Info));
    241   return Info;
    242 }
    243 
    244 // Assume that __cxa_demangle is provided by libcxxabi.
    245 extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
    246                                 size_t *length, int *status);
    247 
    248 static void printDILineInfo(DILineInfo LineInfo) {
    249   // By default, DILineInfo contains "<invalid>" for function/filename it
    250   // cannot fetch. We replace it to "??" to make our output closer to addr2line.
    251   static const string kDILineInfoBadString = "<invalid>";
    252   static const string kSymbolizerBadString = "??";
    253   if (PrintFunctions) {
    254     string FunctionName = LineInfo.getFunctionName();
    255     if (FunctionName == kDILineInfoBadString)
    256       FunctionName = kSymbolizerBadString;
    257     if (Demangle) {
    258       int status = 0;
    259       char *DemangledName = __cxa_demangle(
    260           FunctionName.c_str(), 0, 0, &status);
    261       if (status == 0) {
    262         FunctionName = DemangledName;
    263         free(DemangledName);
    264       }
    265     }
    266     outs() << FunctionName << "\n";
    267   }
    268   string Filename = LineInfo.getFileName();
    269   if (Filename == kDILineInfoBadString)
    270     Filename = kSymbolizerBadString;
    271   outs() << Filename <<
    272          ":" << LineInfo.getLine() <<
    273          ":" << LineInfo.getColumn() <<
    274          "\n";
    275 }
    276 
    277 static void symbolize(string ModuleName, string ModuleOffsetStr) {
    278   ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
    279   uint64_t Offset = 0;
    280   if (Info == 0 ||
    281       StringRef(ModuleOffsetStr).getAsInteger(0, Offset)) {
    282     printDILineInfo(DILineInfo());
    283   } else if (PrintInlining) {
    284     DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(Offset);
    285     uint32_t FramesNum = InlinedContext.getNumberOfFrames();
    286     assert(FramesNum > 0);
    287     for (uint32_t i = 0; i < FramesNum; i++) {
    288       DILineInfo LineInfo = InlinedContext.getFrame(i);
    289       printDILineInfo(LineInfo);
    290     }
    291   } else {
    292     DILineInfo LineInfo = Info->symbolizeCode(Offset);
    293     printDILineInfo(LineInfo);
    294   }
    295 
    296   outs() << "\n";  // Print extra empty line to mark the end of output.
    297   outs().flush();
    298 }
    299 
    300 static bool parseModuleNameAndOffset(string &ModuleName,
    301                                      string &ModuleOffsetStr) {
    302   static const int kMaxInputStringLength = 1024;
    303   static const char kDelimiters[] = " \n";
    304   char InputString[kMaxInputStringLength];
    305   if (!fgets(InputString, sizeof(InputString), stdin))
    306     return false;
    307   ModuleName = "";
    308   ModuleOffsetStr = "";
    309   // FIXME: Handle case when filename is given in quotes.
    310   if (char *FilePath = strtok(InputString, kDelimiters)) {
    311     ModuleName = FilePath;
    312     if (char *OffsetStr = strtok((char*)0, kDelimiters))
    313       ModuleOffsetStr = OffsetStr;
    314   }
    315   return true;
    316 }
    317 
    318 int main(int argc, char **argv) {
    319   // Print stack trace if we signal out.
    320   sys::PrintStackTraceOnErrorSignal();
    321   PrettyStackTraceProgram X(argc, argv);
    322   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
    323 
    324   cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
    325   ToolInvocationPath = argv[0];
    326 
    327   string ModuleName;
    328   string ModuleOffsetStr;
    329   while (parseModuleNameAndOffset(ModuleName, ModuleOffsetStr)) {
    330     symbolize(ModuleName, ModuleOffsetStr);
    331   }
    332   return 0;
    333 }
    334