blob: 86ea34bff6f17d573e6213f65a9039f5bae9b263 [file] [log] [blame]
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +00001//===-- 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
21namespace llvm {
22namespace symbolize {
23
Dmitry Vyukovb1819192013-02-14 13:06:18 +000024static bool error(error_code ec) {
Alexey Samsonovc4439c32013-02-15 08:54:47 +000025 if (!ec)
26 return false;
Dmitry Vyukovb1819192013-02-14 13:06:18 +000027 errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
28 return true;
29}
30
Alexey Samsonovc4439c32013-02-15 08:54:47 +000031static uint32_t
32getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +000033 uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo |
34 llvm::DILineInfoSpecifier::AbsoluteFilePath;
35 if (Opts.PrintFunctions)
36 Flags |= llvm::DILineInfoSpecifier::FunctionName;
37 return Flags;
38}
39
40static 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
Dmitry Vyukovb1819192013-02-14 13:06:18 +000047ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
Alexey Samsonovc4439c32013-02-15 08:54:47 +000048 : Module(Obj), DebugInfoContext(DICtx) {
Dmitry Vyukovb1819192013-02-14 13:06:18 +000049 error_code ec;
Alexey Samsonovc4439c32013-02-15 08:54:47 +000050 for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols();
51 si != se; si.increment(ec)) {
Dmitry Vyukovb1819192013-02-14 13:06:18 +000052 if (error(ec))
53 return;
54 SymbolRef::Type SymbolType;
55 if (error(si->getType(SymbolType)))
56 continue;
Alexey Samsonovc4439c32013-02-15 08:54:47 +000057 if (SymbolType != SymbolRef::ST_Function &&
58 SymbolType != SymbolRef::ST_Data)
Dmitry Vyukovb1819192013-02-14 13:06:18 +000059 continue;
60 uint64_t SymbolAddress;
Alexey Samsonovc4439c32013-02-15 08:54:47 +000061 if (error(si->getAddress(SymbolAddress)) ||
62 SymbolAddress == UnknownAddressOrSize)
Dmitry Vyukovb1819192013-02-14 13:06:18 +000063 continue;
64 uint64_t SymbolSize;
Alexey Samsonovc4439c32013-02-15 08:54:47 +000065 if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize)
Dmitry Vyukovb1819192013-02-14 13:06:18 +000066 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.
Alexey Samsonovc4439c32013-02-15 08:54:47 +000072 SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
73 SymbolDesc SD = { SymbolAddress, SymbolAddress + SymbolSize };
Dmitry Vyukovb1819192013-02-14 13:06:18 +000074 M.insert(std::make_pair(SD, SymbolName));
75 }
76}
77
78bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
79 std::string &Name, uint64_t &Addr,
80 uint64_t &Size) const {
Alexey Samsonovc4439c32013-02-15 08:54:47 +000081 const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
82 SymbolDesc SD = { Address, Address + 1 };
Dmitry Vyukovb1819192013-02-14 13:06:18 +000083 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
Alexey Samsonovc4439c32013-02-15 08:54:47 +000094DILineInfo ModuleInfo::symbolizeCode(
95 uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +000096 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;
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000105 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
106 FunctionName, Start, Size)) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000107 patchFunctionNameInDILineInfo(FunctionName, LineInfo);
108 }
109 }
110 return LineInfo;
111}
112
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000113DIInliningInfo ModuleInfo::symbolizeInlinedCode(
114 uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000115 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;
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000127 for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000128 DILineInfo LineInfo = InlinedContext.getFrame(i);
129 if (i == n - 1) {
130 std::string FunctionName;
131 uint64_t Start, Size;
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000132 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
133 FunctionName, Start, Size)) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000134 patchFunctionNameInDILineInfo(FunctionName, LineInfo);
135 }
136 }
137 PatchedInlinedContext.addFrame(LineInfo);
138 }
139 InlinedContext = PatchedInlinedContext;
140 }
141 return InlinedContext;
142}
143
144bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name,
145 uint64_t &Start, uint64_t &Size) const {
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000146 return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start,
147 Size);
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000148}
149
Alexey Samsonov638c63c2013-02-04 15:55:26 +0000150const char LLVMSymbolizer::kBadString[] = "??";
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000151
152std::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) {
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000158 DIInliningInfo InlinedContext =
159 Info->symbolizeInlinedCode(ModuleOffset, Opts);
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000160 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
173std::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.
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000190static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000191 // FIXME: Implement this when libLLVMObject allows to do it easily.
192 IsLittleEndian = true;
193 return true;
194}
195
196static ObjectFile *getObjectFile(const std::string &Path) {
197 OwningPtr<MemoryBuffer> Buff;
Alexey Samsonov933b8512013-02-05 07:01:34 +0000198 if (error_code ec = MemoryBuffer::getFile(Path, Buff))
199 error(ec);
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000200 return ObjectFile::createObjectFile(Buff.take());
201}
202
203static 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
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000212ModuleInfo *
213LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000214 ModuleMapTy::iterator I = Modules.find(ModuleName);
215 if (I != Modules.end())
216 return I->second;
217
218 ObjectFile *Obj = getObjectFile(ModuleName);
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000219 if (Obj == 0) {
220 // Module name doesn't point to a valid object file.
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000221 Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000222 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.
Dmitry Vyukovb1819192013-02-14 13:06:18 +0000230 ObjectFile *DbgObj = Obj;
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000231 if (isa<MachOObjectFile>(Obj)) {
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000232 const std::string &ResourceName =
233 getDarwinDWARFResourceForModule(ModuleName);
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000234 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
247std::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;
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000262 Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn()
263 << "\n";
Alexey Samsonovc4c7ea32013-01-22 14:21:19 +0000264 return Result.str();
265}
266
267#if !defined(_MSC_VER)
268// Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
269extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
270 size_t *length, int *status);
271#endif
272
273void 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
Alexey Samsonovc4439c32013-02-15 08:54:47 +0000286} // namespace symbolize
287} // namespace llvm