blob: 52ae49c0f178da72d744495d6f5b31fbf90f9154 [file] [log] [blame]
Alexey Samsonovea83baf2013-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 Vyukovef8fb722013-02-14 13:06:18 +000024static bool error(error_code ec) {
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000025 if (!ec)
26 return false;
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000027 errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
28 return true;
29}
30
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000031static uint32_t
32getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) {
Alexey Samsonovea83baf2013-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 Vyukovef8fb722013-02-14 13:06:18 +000047ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000048 : Module(Obj), DebugInfoContext(DICtx) {
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000049 error_code ec;
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000050 for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols();
51 si != se; si.increment(ec)) {
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000052 if (error(ec))
53 return;
54 SymbolRef::Type SymbolType;
55 if (error(si->getType(SymbolType)))
56 continue;
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000057 if (SymbolType != SymbolRef::ST_Function &&
58 SymbolType != SymbolRef::ST_Data)
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000059 continue;
60 uint64_t SymbolAddress;
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000061 if (error(si->getAddress(SymbolAddress)) ||
62 SymbolAddress == UnknownAddressOrSize)
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000063 continue;
64 uint64_t SymbolSize;
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000065 if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize)
Dmitry Vyukovef8fb722013-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 Samsonovd5d7bb52013-02-15 08:54:47 +000072 SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
73 SymbolDesc SD = { SymbolAddress, SymbolAddress + SymbolSize };
Dmitry Vyukovef8fb722013-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 Samsonovd5d7bb52013-02-15 08:54:47 +000081 const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
82 SymbolDesc SD = { Address, Address + 1 };
Dmitry Vyukovef8fb722013-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 Samsonovd5d7bb52013-02-15 08:54:47 +000094DILineInfo ModuleInfo::symbolizeCode(
95 uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
Alexey Samsonovea83baf2013-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 Samsonovd5d7bb52013-02-15 08:54:47 +0000105 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
106 FunctionName, Start, Size)) {
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000107 patchFunctionNameInDILineInfo(FunctionName, LineInfo);
108 }
109 }
110 return LineInfo;
111}
112
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000113DIInliningInfo ModuleInfo::symbolizeInlinedCode(
114 uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
Alexey Samsonovea83baf2013-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 Samsonovd5d7bb52013-02-15 08:54:47 +0000127 for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
Alexey Samsonovea83baf2013-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 Samsonovd5d7bb52013-02-15 08:54:47 +0000132 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
133 FunctionName, Start, Size)) {
Alexey Samsonovea83baf2013-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 Samsonovd5d7bb52013-02-15 08:54:47 +0000146 return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start,
147 Size);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000148}
149
Alexey Samsonovd6cef102013-02-04 15:55:26 +0000150const char LLVMSymbolizer::kBadString[] = "??";
Alexey Samsonovea83baf2013-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 Samsonovd5d7bb52013-02-15 08:54:47 +0000158 DIInliningInfo InlinedContext =
159 Info->symbolizeInlinedCode(ModuleOffset, Opts);
Alexey Samsonovea83baf2013-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
Dmitry Vyukove8504e22013-03-19 10:24:42 +0000189void LLVMSymbolizer::flush() {
190 Modules.clear();
191}
192
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000193// Returns true if the object endianness is known.
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000194static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000195 // FIXME: Implement this when libLLVMObject allows to do it easily.
196 IsLittleEndian = true;
197 return true;
198}
199
200static ObjectFile *getObjectFile(const std::string &Path) {
201 OwningPtr<MemoryBuffer> Buff;
Alexey Samsonov741c688f2013-02-05 07:01:34 +0000202 if (error_code ec = MemoryBuffer::getFile(Path, Buff))
203 error(ec);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000204 return ObjectFile::createObjectFile(Buff.take());
205}
206
207static std::string getDarwinDWARFResourceForModule(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
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000216ModuleInfo *
217LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000218 ModuleMapTy::iterator I = Modules.find(ModuleName);
219 if (I != Modules.end())
220 return I->second;
221
222 ObjectFile *Obj = getObjectFile(ModuleName);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000223 if (Obj == 0) {
224 // Module name doesn't point to a valid object file.
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000225 Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000226 return 0;
227 }
228
229 DIContext *Context = 0;
230 bool IsLittleEndian;
231 if (getObjectEndianness(Obj, IsLittleEndian)) {
232 // On Darwin we may find DWARF in separate object file in
233 // resource directory.
Dmitry Vyukovef8fb722013-02-14 13:06:18 +0000234 ObjectFile *DbgObj = Obj;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000235 if (isa<MachOObjectFile>(Obj)) {
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000236 const std::string &ResourceName =
237 getDarwinDWARFResourceForModule(ModuleName);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000238 ObjectFile *ResourceObj = getObjectFile(ResourceName);
239 if (ResourceObj != 0)
240 DbgObj = ResourceObj;
241 }
242 Context = DIContext::getDWARFContext(DbgObj);
243 assert(Context);
244 }
245
246 ModuleInfo *Info = new ModuleInfo(Obj, Context);
247 Modules.insert(make_pair(ModuleName, Info));
248 return Info;
249}
250
251std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
252 // By default, DILineInfo contains "<invalid>" for function/filename it
253 // cannot fetch. We replace it to "??" to make our output closer to addr2line.
254 static const std::string kDILineInfoBadString = "<invalid>";
255 std::stringstream Result;
256 if (Opts.PrintFunctions) {
257 std::string FunctionName = LineInfo.getFunctionName();
258 if (FunctionName == kDILineInfoBadString)
259 FunctionName = kBadString;
260 DemangleName(FunctionName);
261 Result << FunctionName << "\n";
262 }
263 std::string Filename = LineInfo.getFileName();
264 if (Filename == kDILineInfoBadString)
265 Filename = kBadString;
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000266 Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn()
267 << "\n";
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000268 return Result.str();
269}
270
271#if !defined(_MSC_VER)
272// Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
273extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
274 size_t *length, int *status);
275#endif
276
277void LLVMSymbolizer::DemangleName(std::string &Name) const {
278#if !defined(_MSC_VER)
279 if (!Opts.Demangle)
280 return;
281 int status = 0;
282 char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status);
283 if (status != 0)
284 return;
285 Name = DemangledName;
286 free(DemangledName);
287#endif
288}
289
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000290} // namespace symbolize
291} // namespace llvm