Home | History | Annotate | Download | only in llvm-symbolizer
      1 //===-- LLVMSymbolize.cpp -------------------------------------------------===//
      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 // Implementation for LLVM symbolization library.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "LLVMSymbolize.h"
     15 #include "llvm/Object/MachO.h"
     16 #include "llvm/Support/Casting.h"
     17 #include "llvm/Support/Path.h"
     18 
     19 #include <sstream>
     20 
     21 namespace llvm {
     22 namespace symbolize {
     23 
     24 static bool error(error_code ec) {
     25   if (!ec)
     26     return false;
     27   errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
     28   return true;
     29 }
     30 
     31 static uint32_t
     32 getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) {
     33   uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo |
     34                    llvm::DILineInfoSpecifier::AbsoluteFilePath;
     35   if (Opts.PrintFunctions)
     36     Flags |= llvm::DILineInfoSpecifier::FunctionName;
     37   return Flags;
     38 }
     39 
     40 static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName,
     41                                           DILineInfo &LineInfo) {
     42   std::string FileName = LineInfo.getFileName();
     43   LineInfo = DILineInfo(StringRef(FileName), StringRef(NewFunctionName),
     44                         LineInfo.getLine(), LineInfo.getColumn());
     45 }
     46 
     47 ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
     48     : Module(Obj), DebugInfoContext(DICtx) {
     49   error_code ec;
     50   for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols();
     51        si != se; si.increment(ec)) {
     52     if (error(ec))
     53       return;
     54     SymbolRef::Type SymbolType;
     55     if (error(si->getType(SymbolType)))
     56       continue;
     57     if (SymbolType != SymbolRef::ST_Function &&
     58         SymbolType != SymbolRef::ST_Data)
     59       continue;
     60     uint64_t SymbolAddress;
     61     if (error(si->getAddress(SymbolAddress)) ||
     62         SymbolAddress == UnknownAddressOrSize)
     63       continue;
     64     uint64_t SymbolSize;
     65     if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize)
     66       continue;
     67     StringRef SymbolName;
     68     if (error(si->getName(SymbolName)))
     69       continue;
     70     // FIXME: If a function has alias, there are two entries in symbol table
     71     // with same address size. Make sure we choose the correct one.
     72     SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
     73     SymbolDesc SD = { SymbolAddress, SymbolAddress + SymbolSize };
     74     M.insert(std::make_pair(SD, SymbolName));
     75   }
     76 }
     77 
     78 bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
     79                                         std::string &Name, uint64_t &Addr,
     80                                         uint64_t &Size) const {
     81   const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
     82   SymbolDesc SD = { Address, Address + 1 };
     83   SymbolMapTy::const_iterator it = M.find(SD);
     84   if (it == M.end())
     85     return false;
     86   if (Address < it->first.Addr || Address >= it->first.AddrEnd)
     87     return false;
     88   Name = it->second.str();
     89   Addr = it->first.Addr;
     90   Size = it->first.AddrEnd - it->first.Addr;
     91   return true;
     92 }
     93 
     94 DILineInfo ModuleInfo::symbolizeCode(
     95     uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
     96   DILineInfo LineInfo;
     97   if (DebugInfoContext) {
     98     LineInfo = DebugInfoContext->getLineInfoForAddress(
     99         ModuleOffset, getDILineInfoSpecifierFlags(Opts));
    100   }
    101   // Override function name from symbol table if necessary.
    102   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
    103     std::string FunctionName;
    104     uint64_t Start, Size;
    105     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
    106                                FunctionName, Start, Size)) {
    107       patchFunctionNameInDILineInfo(FunctionName, LineInfo);
    108     }
    109   }
    110   return LineInfo;
    111 }
    112 
    113 DIInliningInfo ModuleInfo::symbolizeInlinedCode(
    114     uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
    115   DIInliningInfo InlinedContext;
    116   if (DebugInfoContext) {
    117     InlinedContext = DebugInfoContext->getInliningInfoForAddress(
    118         ModuleOffset, getDILineInfoSpecifierFlags(Opts));
    119   }
    120   // Make sure there is at least one frame in context.
    121   if (InlinedContext.getNumberOfFrames() == 0) {
    122     InlinedContext.addFrame(DILineInfo());
    123   }
    124   // Override the function name in lower frame with name from symbol table.
    125   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
    126     DIInliningInfo PatchedInlinedContext;
    127     for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
    128       DILineInfo LineInfo = InlinedContext.getFrame(i);
    129       if (i == n - 1) {
    130         std::string FunctionName;
    131         uint64_t Start, Size;
    132         if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
    133                                    FunctionName, Start, Size)) {
    134           patchFunctionNameInDILineInfo(FunctionName, LineInfo);
    135         }
    136       }
    137       PatchedInlinedContext.addFrame(LineInfo);
    138     }
    139     InlinedContext = PatchedInlinedContext;
    140   }
    141   return InlinedContext;
    142 }
    143 
    144 bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name,
    145                                uint64_t &Start, uint64_t &Size) const {
    146   return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start,
    147                                 Size);
    148 }
    149 
    150 const char LLVMSymbolizer::kBadString[] = "??";
    151 
    152 std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
    153                                           uint64_t ModuleOffset) {
    154   ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
    155   if (Info == 0)
    156     return printDILineInfo(DILineInfo());
    157   if (Opts.PrintInlining) {
    158     DIInliningInfo InlinedContext =
    159         Info->symbolizeInlinedCode(ModuleOffset, Opts);
    160     uint32_t FramesNum = InlinedContext.getNumberOfFrames();
    161     assert(FramesNum > 0);
    162     std::string Result;
    163     for (uint32_t i = 0; i < FramesNum; i++) {
    164       DILineInfo LineInfo = InlinedContext.getFrame(i);
    165       Result += printDILineInfo(LineInfo);
    166     }
    167     return Result;
    168   }
    169   DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts);
    170   return printDILineInfo(LineInfo);
    171 }
    172 
    173 std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
    174                                           uint64_t ModuleOffset) {
    175   std::string Name = kBadString;
    176   uint64_t Start = 0;
    177   uint64_t Size = 0;
    178   if (Opts.UseSymbolTable) {
    179     if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) {
    180       if (Info->symbolizeData(ModuleOffset, Name, Start, Size))
    181         DemangleName(Name);
    182     }
    183   }
    184   std::stringstream ss;
    185   ss << Name << "\n" << Start << " " << Size << "\n";
    186   return ss.str();
    187 }
    188 
    189 // Returns true if the object endianness is known.
    190 static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
    191   // FIXME: Implement this when libLLVMObject allows to do it easily.
    192   IsLittleEndian = true;
    193   return true;
    194 }
    195 
    196 static ObjectFile *getObjectFile(const std::string &Path) {
    197   OwningPtr<MemoryBuffer> Buff;
    198   if (error_code ec = MemoryBuffer::getFile(Path, Buff))
    199     error(ec);
    200   return ObjectFile::createObjectFile(Buff.take());
    201 }
    202 
    203 static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
    204   StringRef Basename = sys::path::filename(Path);
    205   const std::string &DSymDirectory = Path + ".dSYM";
    206   SmallString<16> ResourceName = StringRef(DSymDirectory);
    207   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
    208   sys::path::append(ResourceName, Basename);
    209   return ResourceName.str();
    210 }
    211 
    212 ModuleInfo *
    213 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
    214   ModuleMapTy::iterator I = Modules.find(ModuleName);
    215   if (I != Modules.end())
    216     return I->second;
    217 
    218   ObjectFile *Obj = getObjectFile(ModuleName);
    219   if (Obj == 0) {
    220     // Module name doesn't point to a valid object file.
    221     Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
    222     return 0;
    223   }
    224 
    225   DIContext *Context = 0;
    226   bool IsLittleEndian;
    227   if (getObjectEndianness(Obj, IsLittleEndian)) {
    228     // On Darwin we may find DWARF in separate object file in
    229     // resource directory.
    230     ObjectFile *DbgObj = Obj;
    231     if (isa<MachOObjectFile>(Obj)) {
    232       const std::string &ResourceName =
    233           getDarwinDWARFResourceForModule(ModuleName);
    234       ObjectFile *ResourceObj = getObjectFile(ResourceName);
    235       if (ResourceObj != 0)
    236         DbgObj = ResourceObj;
    237     }
    238     Context = DIContext::getDWARFContext(DbgObj);
    239     assert(Context);
    240   }
    241 
    242   ModuleInfo *Info = new ModuleInfo(Obj, Context);
    243   Modules.insert(make_pair(ModuleName, Info));
    244   return Info;
    245 }
    246 
    247 std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
    248   // By default, DILineInfo contains "<invalid>" for function/filename it
    249   // cannot fetch. We replace it to "??" to make our output closer to addr2line.
    250   static const std::string kDILineInfoBadString = "<invalid>";
    251   std::stringstream Result;
    252   if (Opts.PrintFunctions) {
    253     std::string FunctionName = LineInfo.getFunctionName();
    254     if (FunctionName == kDILineInfoBadString)
    255       FunctionName = kBadString;
    256     DemangleName(FunctionName);
    257     Result << FunctionName << "\n";
    258   }
    259   std::string Filename = LineInfo.getFileName();
    260   if (Filename == kDILineInfoBadString)
    261     Filename = kBadString;
    262   Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn()
    263          << "\n";
    264   return Result.str();
    265 }
    266 
    267 #if !defined(_MSC_VER)
    268 // Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
    269 extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
    270                                 size_t *length, int *status);
    271 #endif
    272 
    273 void LLVMSymbolizer::DemangleName(std::string &Name) const {
    274 #if !defined(_MSC_VER)
    275   if (!Opts.Demangle)
    276     return;
    277   int status = 0;
    278   char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status);
    279   if (status != 0)
    280     return;
    281   Name = DemangledName;
    282   free(DemangledName);
    283 #endif
    284 }
    285 
    286 } // namespace symbolize
    287 } // namespace llvm
    288