llvm-symbolizer: skip leading underscore in Mach-O symbol table entries
[oota-llvm.git] / tools / llvm-symbolizer / LLVMSymbolize.cpp
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/ADT/STLExtras.h"
16 #include "llvm/Object/MachO.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20
21 #include <sstream>
22
23 namespace llvm {
24 namespace symbolize {
25
26 static bool error(error_code ec) {
27   if (!ec)
28     return false;
29   errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
30   return true;
31 }
32
33 static uint32_t
34 getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) {
35   uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo |
36                    llvm::DILineInfoSpecifier::AbsoluteFilePath;
37   if (Opts.PrintFunctions)
38     Flags |= llvm::DILineInfoSpecifier::FunctionName;
39   return Flags;
40 }
41
42 static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName,
43                                           DILineInfo &LineInfo) {
44   std::string FileName = LineInfo.getFileName();
45   LineInfo = DILineInfo(StringRef(FileName), StringRef(NewFunctionName),
46                         LineInfo.getLine(), LineInfo.getColumn());
47 }
48
49 ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
50     : Module(Obj), DebugInfoContext(DICtx) {
51   error_code ec;
52   for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols();
53        si != se; si.increment(ec)) {
54     if (error(ec))
55       return;
56     SymbolRef::Type SymbolType;
57     if (error(si->getType(SymbolType)))
58       continue;
59     if (SymbolType != SymbolRef::ST_Function &&
60         SymbolType != SymbolRef::ST_Data)
61       continue;
62     uint64_t SymbolAddress;
63     if (error(si->getAddress(SymbolAddress)) ||
64         SymbolAddress == UnknownAddressOrSize)
65       continue;
66     uint64_t SymbolSize;
67     // Getting symbol size is linear for Mach-O files, so assume that symbol
68     // occupies the memory range up to the following symbol.
69     if (isa<MachOObjectFile>(Obj))
70       SymbolSize = 0;
71     else if (error(si->getSize(SymbolSize)) ||
72              SymbolSize == UnknownAddressOrSize)
73       continue;
74     StringRef SymbolName;
75     if (error(si->getName(SymbolName)))
76       continue;
77     // Mach-O symbol table names have leading underscore, skip it.
78     if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_')
79       SymbolName = SymbolName.drop_front();
80     // FIXME: If a function has alias, there are two entries in symbol table
81     // with same address size. Make sure we choose the correct one.
82     SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
83     SymbolDesc SD = { SymbolAddress, SymbolSize };
84     M.insert(std::make_pair(SD, SymbolName));
85   }
86 }
87
88 bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
89                                         std::string &Name, uint64_t &Addr,
90                                         uint64_t &Size) const {
91   const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
92   if (M.empty())
93     return false;
94   SymbolDesc SD = { Address, Address };
95   SymbolMapTy::const_iterator it = M.upper_bound(SD);
96   if (it == M.begin())
97     return false;
98   --it;
99   if (it->first.Size != 0 && it->first.Addr + it->first.Size <= Address)
100     return false;
101   Name = it->second.str();
102   Addr = it->first.Addr;
103   Size = it->first.Size;
104   return true;
105 }
106
107 DILineInfo ModuleInfo::symbolizeCode(
108     uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
109   DILineInfo LineInfo;
110   if (DebugInfoContext) {
111     LineInfo = DebugInfoContext->getLineInfoForAddress(
112         ModuleOffset, getDILineInfoSpecifierFlags(Opts));
113   }
114   // Override function name from symbol table if necessary.
115   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
116     std::string FunctionName;
117     uint64_t Start, Size;
118     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
119                                FunctionName, Start, Size)) {
120       patchFunctionNameInDILineInfo(FunctionName, LineInfo);
121     }
122   }
123   return LineInfo;
124 }
125
126 DIInliningInfo ModuleInfo::symbolizeInlinedCode(
127     uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
128   DIInliningInfo InlinedContext;
129   if (DebugInfoContext) {
130     InlinedContext = DebugInfoContext->getInliningInfoForAddress(
131         ModuleOffset, getDILineInfoSpecifierFlags(Opts));
132   }
133   // Make sure there is at least one frame in context.
134   if (InlinedContext.getNumberOfFrames() == 0) {
135     InlinedContext.addFrame(DILineInfo());
136   }
137   // Override the function name in lower frame with name from symbol table.
138   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
139     DIInliningInfo PatchedInlinedContext;
140     for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
141       DILineInfo LineInfo = InlinedContext.getFrame(i);
142       if (i == n - 1) {
143         std::string FunctionName;
144         uint64_t Start, Size;
145         if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
146                                    FunctionName, Start, Size)) {
147           patchFunctionNameInDILineInfo(FunctionName, LineInfo);
148         }
149       }
150       PatchedInlinedContext.addFrame(LineInfo);
151     }
152     InlinedContext = PatchedInlinedContext;
153   }
154   return InlinedContext;
155 }
156
157 bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name,
158                                uint64_t &Start, uint64_t &Size) const {
159   return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start,
160                                 Size);
161 }
162
163 const char LLVMSymbolizer::kBadString[] = "??";
164
165 std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
166                                           uint64_t ModuleOffset) {
167   ModuleInfo *Info = getOrCreateModuleInfo(ModuleName);
168   if (Info == 0)
169     return printDILineInfo(DILineInfo());
170   if (Opts.PrintInlining) {
171     DIInliningInfo InlinedContext =
172         Info->symbolizeInlinedCode(ModuleOffset, Opts);
173     uint32_t FramesNum = InlinedContext.getNumberOfFrames();
174     assert(FramesNum > 0);
175     std::string Result;
176     for (uint32_t i = 0; i < FramesNum; i++) {
177       DILineInfo LineInfo = InlinedContext.getFrame(i);
178       Result += printDILineInfo(LineInfo);
179     }
180     return Result;
181   }
182   DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts);
183   return printDILineInfo(LineInfo);
184 }
185
186 std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
187                                           uint64_t ModuleOffset) {
188   std::string Name = kBadString;
189   uint64_t Start = 0;
190   uint64_t Size = 0;
191   if (Opts.UseSymbolTable) {
192     if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) {
193       if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle)
194         Name = DemangleName(Name);
195     }
196   }
197   std::stringstream ss;
198   ss << Name << "\n" << Start << " " << Size << "\n";
199   return ss.str();
200 }
201
202 void LLVMSymbolizer::flush() {
203   DeleteContainerSeconds(Modules);
204   DeleteContainerPointers(ParsedBinariesAndObjects);
205 }
206
207 static std::string getDarwinDWARFResourceForPath(const std::string &Path) {
208   StringRef Basename = sys::path::filename(Path);
209   const std::string &DSymDirectory = Path + ".dSYM";
210   SmallString<16> ResourceName = StringRef(DSymDirectory);
211   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
212   sys::path::append(ResourceName, Basename);
213   return ResourceName.str();
214 }
215
216 LLVMSymbolizer::BinaryPair
217 LLVMSymbolizer::getOrCreateBinary(const std::string &Path) {
218   BinaryMapTy::iterator I = BinaryForPath.find(Path);
219   if (I != BinaryForPath.end())
220     return I->second;
221   Binary *Bin = 0;
222   Binary *DbgBin = 0;
223   OwningPtr<Binary> ParsedBinary;
224   OwningPtr<Binary> ParsedDbgBinary;
225   if (!error(createBinary(Path, ParsedBinary))) {
226     // Check if it's a universal binary.
227     Bin = ParsedBinary.take();
228     ParsedBinariesAndObjects.push_back(Bin);
229     if (Bin->isMachO() || Bin->isMachOUniversalBinary()) {
230       // On Darwin we may find DWARF in separate object file in
231       // resource directory.
232       const std::string &ResourcePath =
233           getDarwinDWARFResourceForPath(Path);
234       bool ResourceFileExists = false;
235       if (!sys::fs::exists(ResourcePath, ResourceFileExists) &&
236           ResourceFileExists &&
237           !error(createBinary(ResourcePath, ParsedDbgBinary))) {
238         DbgBin = ParsedDbgBinary.take();
239         ParsedBinariesAndObjects.push_back(DbgBin);
240       }
241     }
242   }
243   if (DbgBin == 0)
244     DbgBin = Bin;
245   BinaryPair Res = std::make_pair(Bin, DbgBin);
246   BinaryForPath[Path] = Res;
247   return Res;
248 }
249
250 ObjectFile *
251 LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) {
252   if (Bin == 0)
253     return 0;
254   ObjectFile *Res = 0;
255   if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
256     ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find(
257         std::make_pair(UB, ArchName));
258     if (I != ObjectFileForArch.end())
259       return I->second;
260     OwningPtr<ObjectFile> ParsedObj;
261     if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) {
262       Res = ParsedObj.take();
263       ParsedBinariesAndObjects.push_back(Res);
264     }
265     ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
266   } else if (Bin->isObject()) {
267     Res = cast<ObjectFile>(Bin);
268   }
269   return Res;
270 }
271
272 ModuleInfo *
273 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
274   ModuleMapTy::iterator I = Modules.find(ModuleName);
275   if (I != Modules.end())
276     return I->second;
277   std::string BinaryName = ModuleName;
278   std::string ArchName = Opts.DefaultArch;
279   size_t ColonPos = ModuleName.find(':');
280   if (ColonPos != std::string::npos) {
281     BinaryName = ModuleName.substr(0, ColonPos);
282     ArchName = ModuleName.substr(ColonPos + 1);
283   }
284   BinaryPair Binaries = getOrCreateBinary(BinaryName);
285   ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName);
286   ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName);
287
288   if (Obj == 0) {
289     // Failed to find valid object file.
290     Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
291     return 0;
292   }
293   DIContext *Context = DIContext::getDWARFContext(DbgObj);
294   assert(Context);
295   ModuleInfo *Info = new ModuleInfo(Obj, Context);
296   Modules.insert(make_pair(ModuleName, Info));
297   return Info;
298 }
299
300 std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
301   // By default, DILineInfo contains "<invalid>" for function/filename it
302   // cannot fetch. We replace it to "??" to make our output closer to addr2line.
303   static const std::string kDILineInfoBadString = "<invalid>";
304   std::stringstream Result;
305   if (Opts.PrintFunctions) {
306     std::string FunctionName = LineInfo.getFunctionName();
307     if (FunctionName == kDILineInfoBadString)
308       FunctionName = kBadString;
309     else if (Opts.Demangle)
310       FunctionName = DemangleName(FunctionName);
311     Result << FunctionName << "\n";
312   }
313   std::string Filename = LineInfo.getFileName();
314   if (Filename == kDILineInfoBadString)
315     Filename = kBadString;
316   Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn()
317          << "\n";
318   return Result.str();
319 }
320
321 #if !defined(_MSC_VER)
322 // Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
323 extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
324                                 size_t *length, int *status);
325 #endif
326
327 std::string LLVMSymbolizer::DemangleName(const std::string &Name) {
328 #if !defined(_MSC_VER)
329   int status = 0;
330   char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status);
331   if (status != 0)
332     return Name;
333   std::string Result = DemangledName;
334   free(DemangledName);
335   return Result;
336 #else
337   return Name;
338 #endif
339 }
340
341 } // namespace symbolize
342 } // namespace llvm