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