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