Line data Source code
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 "llvm/DebugInfo/Symbolize/Symbolize.h"
15 :
16 : #include "SymbolizableObjectFile.h"
17 :
18 : #include "llvm/ADT/STLExtras.h"
19 : #include "llvm/BinaryFormat/COFF.h"
20 : #include "llvm/Config/config.h"
21 : #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22 : #include "llvm/DebugInfo/PDB/PDB.h"
23 : #include "llvm/DebugInfo/PDB/PDBContext.h"
24 : #include "llvm/Demangle/Demangle.h"
25 : #include "llvm/Object/COFF.h"
26 : #include "llvm/Object/MachO.h"
27 : #include "llvm/Object/MachOUniversal.h"
28 : #include "llvm/Support/Casting.h"
29 : #include "llvm/Support/Compression.h"
30 : #include "llvm/Support/DataExtractor.h"
31 : #include "llvm/Support/Errc.h"
32 : #include "llvm/Support/FileSystem.h"
33 : #include "llvm/Support/MemoryBuffer.h"
34 : #include "llvm/Support/Path.h"
35 : #include <algorithm>
36 : #include <cassert>
37 : #include <cstdlib>
38 : #include <cstring>
39 :
40 : #if defined(_MSC_VER)
41 : #include <Windows.h>
42 :
43 : // This must be included after windows.h.
44 : #include <DbgHelp.h>
45 : #pragma comment(lib, "dbghelp.lib")
46 :
47 : // Windows.h conflicts with our COFF header definitions.
48 : #ifdef IMAGE_FILE_MACHINE_I386
49 : #undef IMAGE_FILE_MACHINE_I386
50 : #endif
51 : #endif
52 :
53 : namespace llvm {
54 : namespace symbolize {
55 :
56 : Expected<DILineInfo>
57 772 : LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
58 : uint64_t ModuleOffset, StringRef DWPName) {
59 : SymbolizableModule *Info;
60 772 : if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName, DWPName))
61 741 : Info = InfoOrErr.get();
62 : else
63 : return InfoOrErr.takeError();
64 :
65 : // A null module means an error has already been reported. Return an empty
66 : // result.
67 741 : if (!Info)
68 138 : return DILineInfo();
69 :
70 : // If the user is giving us relative addresses, add the preferred base of the
71 : // object to the offset before we do the query. It's what DIContext expects.
72 672 : if (Opts.RelativeAddresses)
73 0 : ModuleOffset += Info->getModulePreferredBase();
74 :
75 : DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions,
76 1344 : Opts.UseSymbolTable);
77 672 : if (Opts.Demangle)
78 514 : LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
79 : return LineInfo;
80 : }
81 :
82 : Expected<DIInliningInfo>
83 670 : LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
84 : uint64_t ModuleOffset, StringRef DWPName) {
85 : SymbolizableModule *Info;
86 670 : if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName, DWPName))
87 667 : Info = InfoOrErr.get();
88 : else
89 : return InfoOrErr.takeError();
90 :
91 : // A null module means an error has already been reported. Return an empty
92 : // result.
93 667 : if (!Info)
94 0 : return DIInliningInfo();
95 :
96 : // If the user is giving us relative addresses, add the preferred base of the
97 : // object to the offset before we do the query. It's what DIContext expects.
98 667 : if (Opts.RelativeAddresses)
99 0 : ModuleOffset += Info->getModulePreferredBase();
100 :
101 : DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
102 667 : ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable);
103 667 : if (Opts.Demangle) {
104 1126 : for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
105 569 : auto *Frame = InlinedContext.getMutableFrame(i);
106 1138 : Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
107 : }
108 : }
109 : return InlinedContext;
110 : }
111 :
112 0 : Expected<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
113 : uint64_t ModuleOffset) {
114 : SymbolizableModule *Info;
115 0 : if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
116 0 : Info = InfoOrErr.get();
117 : else
118 : return InfoOrErr.takeError();
119 :
120 : // A null module means an error has already been reported. Return an empty
121 : // result.
122 0 : if (!Info)
123 0 : return DIGlobal();
124 :
125 : // If the user is giving us relative addresses, add the preferred base of
126 : // the object to the offset before we do the query. It's what DIContext
127 : // expects.
128 0 : if (Opts.RelativeAddresses)
129 0 : ModuleOffset += Info->getModulePreferredBase();
130 :
131 0 : DIGlobal Global = Info->symbolizeData(ModuleOffset);
132 0 : if (Opts.Demangle)
133 0 : Global.Name = DemangleName(Global.Name, Info);
134 : return Global;
135 : }
136 :
137 1727 : void LLVMSymbolizer::flush() {
138 : ObjectForUBPathAndArch.clear();
139 : BinaryForPath.clear();
140 : ObjectPairForPathArch.clear();
141 : Modules.clear();
142 1727 : }
143 :
144 : namespace {
145 :
146 : // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
147 : // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
148 : // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
149 : // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
150 21 : std::string getDarwinDWARFResourceForPath(
151 : const std::string &Path, const std::string &Basename) {
152 : SmallString<16> ResourceName = StringRef(Path);
153 42 : if (sys::path::extension(Path) != ".dSYM") {
154 : ResourceName += ".dSYM";
155 : }
156 21 : sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
157 21 : sys::path::append(ResourceName, Basename);
158 21 : return ResourceName.str();
159 : }
160 :
161 95 : bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
162 : ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
163 95 : MemoryBuffer::getFileOrSTDIN(Path);
164 95 : if (!MB)
165 : return false;
166 4 : return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer());
167 : }
168 :
169 34 : bool findDebugBinary(const std::string &OrigPath,
170 : const std::string &DebuglinkName, uint32_t CRCHash,
171 : std::string &Result) {
172 : std::string OrigRealPath = OrigPath;
173 : #if defined(HAVE_REALPATH)
174 34 : if (char *RP = realpath(OrigPath.c_str(), nullptr)) {
175 : OrigRealPath = RP;
176 34 : free(RP);
177 : }
178 : #endif
179 : SmallString<16> OrigDir(OrigRealPath);
180 34 : llvm::sys::path::remove_filename(OrigDir);
181 : SmallString<16> DebugPath = OrigDir;
182 : // Try /path/to/original_binary/debuglink_name
183 34 : llvm::sys::path::append(DebugPath, DebuglinkName);
184 34 : if (checkFileCRC(DebugPath, CRCHash)) {
185 3 : Result = DebugPath.str();
186 3 : return true;
187 : }
188 : // Try /path/to/original_binary/.debug/debuglink_name
189 : DebugPath = OrigDir;
190 31 : llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
191 31 : if (checkFileCRC(DebugPath, CRCHash)) {
192 1 : Result = DebugPath.str();
193 1 : return true;
194 : }
195 : #if defined(__NetBSD__)
196 : // Try /usr/libdata/debug/path/to/original_binary/debuglink_name
197 : DebugPath = "/usr/libdata/debug";
198 : #else
199 : // Try /usr/lib/debug/path/to/original_binary/debuglink_name
200 : DebugPath = "/usr/lib/debug";
201 : #endif
202 30 : llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
203 : DebuglinkName);
204 30 : if (checkFileCRC(DebugPath, CRCHash)) {
205 0 : Result = DebugPath.str();
206 0 : return true;
207 : }
208 : return false;
209 : }
210 :
211 196 : bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
212 : uint32_t &CRCHash) {
213 196 : if (!Obj)
214 : return false;
215 6777 : for (const SectionRef &Section : Obj->sections()) {
216 6615 : StringRef Name;
217 6615 : Section.getName(Name);
218 13230 : Name = Name.substr(Name.find_first_not_of("._"));
219 : if (Name == "gnu_debuglink") {
220 34 : StringRef Data;
221 34 : Section.getContents(Data);
222 34 : DataExtractor DE(Data, Obj->isLittleEndian(), 0);
223 34 : uint32_t Offset = 0;
224 34 : if (const char *DebugNameStr = DE.getCStr(&Offset)) {
225 : // 4-byte align the offset.
226 34 : Offset = (Offset + 3) & ~0x3;
227 : if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
228 : DebugName = DebugNameStr;
229 34 : CRCHash = DE.getU32(&Offset);
230 34 : return true;
231 : }
232 : }
233 0 : break;
234 : }
235 : }
236 162 : return false;
237 : }
238 :
239 3 : bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
240 : const MachOObjectFile *Obj) {
241 3 : ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
242 3 : ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
243 3 : if (dbg_uuid.empty() || bin_uuid.empty())
244 : return false;
245 3 : return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
246 : }
247 :
248 : } // end anonymous namespace
249 :
250 19 : ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
251 : const MachOObjectFile *MachExeObj, const std::string &ArchName) {
252 : // On Darwin we may find DWARF in separate object file in
253 : // resource directory.
254 19 : std::vector<std::string> DsymPaths;
255 19 : StringRef Filename = sys::path::filename(ExePath);
256 44 : DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename));
257 21 : for (const auto &Path : Opts.DsymHints) {
258 5 : DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
259 : }
260 36 : for (const auto &Path : DsymPaths) {
261 20 : auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
262 20 : if (!DbgObjOrErr) {
263 : // Ignore errors, the file might not exist.
264 14 : consumeError(DbgObjOrErr.takeError());
265 14 : continue;
266 : }
267 6 : ObjectFile *DbgObj = DbgObjOrErr.get();
268 6 : if (!DbgObj)
269 : continue;
270 : const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
271 : if (!MachDbgObj)
272 : continue;
273 3 : if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
274 : return DbgObj;
275 : }
276 : return nullptr;
277 : }
278 :
279 196 : ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
280 : const ObjectFile *Obj,
281 : const std::string &ArchName) {
282 : std::string DebuglinkName;
283 : uint32_t CRCHash;
284 : std::string DebugBinaryPath;
285 196 : if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
286 : return nullptr;
287 34 : if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
288 : return nullptr;
289 4 : auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
290 4 : if (!DbgObjOrErr) {
291 : // Ignore errors, the file might not exist.
292 0 : consumeError(DbgObjOrErr.takeError());
293 0 : return nullptr;
294 : }
295 4 : return DbgObjOrErr.get();
296 : }
297 :
298 : Expected<LLVMSymbolizer::ObjectPair>
299 236 : LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
300 : const std::string &ArchName) {
301 236 : const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
302 236 : if (I != ObjectPairForPathArch.end()) {
303 : return I->second;
304 : }
305 :
306 233 : auto ObjOrErr = getOrCreateObject(Path, ArchName);
307 233 : if (!ObjOrErr) {
308 34 : ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
309 : ObjectPair(nullptr, nullptr)));
310 : return ObjOrErr.takeError();
311 : }
312 :
313 199 : ObjectFile *Obj = ObjOrErr.get();
314 : assert(Obj != nullptr);
315 : ObjectFile *DbgObj = nullptr;
316 :
317 : if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
318 19 : DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
319 199 : if (!DbgObj)
320 196 : DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
321 199 : if (!DbgObj)
322 : DbgObj = Obj;
323 : ObjectPair Res = std::make_pair(Obj, DbgObj);
324 : ObjectPairForPathArch.insert(
325 199 : std::make_pair(std::make_pair(Path, ArchName), Res));
326 : return Res;
327 : }
328 :
329 : Expected<ObjectFile *>
330 257 : LLVMSymbolizer::getOrCreateObject(const std::string &Path,
331 : const std::string &ArchName) {
332 : const auto &I = BinaryForPath.find(Path);
333 : Binary *Bin = nullptr;
334 257 : if (I == BinaryForPath.end()) {
335 248 : Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
336 248 : if (!BinOrErr) {
337 47 : BinaryForPath.insert(std::make_pair(Path, OwningBinary<Binary>()));
338 : return BinOrErr.takeError();
339 : }
340 : Bin = BinOrErr->getBinary();
341 201 : BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
342 : } else {
343 : Bin = I->second.getBinary();
344 : }
345 :
346 210 : if (!Bin)
347 : return static_cast<ObjectFile *>(nullptr);
348 :
349 : if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
350 12 : const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
351 12 : if (I != ObjectForUBPathAndArch.end()) {
352 : return I->second.get();
353 : }
354 : Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
355 36 : UB->getObjectForArch(ArchName);
356 12 : if (!ObjOrErr) {
357 1 : ObjectForUBPathAndArch.insert(std::make_pair(
358 1 : std::make_pair(Path, ArchName), std::unique_ptr<ObjectFile>()));
359 : return ObjOrErr.takeError();
360 : }
361 : ObjectFile *Res = ObjOrErr->get();
362 11 : ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
363 : std::move(ObjOrErr.get())));
364 : return Res;
365 : }
366 390 : if (Bin->isObject()) {
367 : return cast<ObjectFile>(Bin);
368 : }
369 0 : return errorCodeToError(object_error::arch_not_found);
370 : }
371 :
372 : Expected<SymbolizableModule *>
373 1442 : LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName,
374 : StringRef DWPName) {
375 : const auto &I = Modules.find(ModuleName);
376 1442 : if (I != Modules.end()) {
377 : return I->second.get();
378 : }
379 : std::string BinaryName = ModuleName;
380 : std::string ArchName = Opts.DefaultArch;
381 : size_t ColonPos = ModuleName.find_last_of(':');
382 : // Verify that substring after colon form a valid arch name.
383 236 : if (ColonPos != std::string::npos) {
384 6 : std::string ArchStr = ModuleName.substr(ColonPos + 1);
385 6 : if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
386 12 : BinaryName = ModuleName.substr(0, ColonPos);
387 : ArchName = ArchStr;
388 : }
389 : }
390 236 : auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
391 236 : if (!ObjectsOrErr) {
392 : // Failed to find valid object file.
393 : Modules.insert(
394 34 : std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
395 : return ObjectsOrErr.takeError();
396 : }
397 202 : ObjectPair Objects = ObjectsOrErr.get();
398 :
399 : std::unique_ptr<DIContext> Context;
400 : // If this is a COFF object containing PDB info, use a PDBContext to
401 : // symbolize. Otherwise, use DWARF.
402 : if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
403 : const codeview::DebugInfo *DebugInfo;
404 0 : StringRef PDBFileName;
405 0 : auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
406 0 : if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
407 : using namespace pdb;
408 0 : std::unique_ptr<IPDBSession> Session;
409 0 : if (auto Err = loadDataForEXE(PDB_ReaderType::DIA,
410 0 : Objects.first->getFileName(), Session)) {
411 : Modules.insert(
412 0 : std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
413 : // Return along the PDB filename to provide more context
414 0 : return createFileError(PDBFileName, std::move(Err));
415 : }
416 0 : Context.reset(new PDBContext(*CoffObject, std::move(Session)));
417 : }
418 : }
419 202 : if (!Context)
420 202 : Context = DWARFContext::create(*Objects.second, nullptr,
421 : DWARFContext::defaultErrorHandler, DWPName);
422 : assert(Context);
423 : auto InfoOrErr =
424 404 : SymbolizableObjectFile::create(Objects.first, std::move(Context));
425 : std::unique_ptr<SymbolizableModule> SymMod;
426 202 : if (InfoOrErr)
427 : SymMod = std::move(InfoOrErr.get());
428 : auto InsertResult =
429 202 : Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
430 : assert(InsertResult.second);
431 202 : if (auto EC = InfoOrErr.getError())
432 0 : return errorCodeToError(EC);
433 : return InsertResult.first->second.get();
434 : }
435 :
436 : namespace {
437 :
438 : // Undo these various manglings for Win32 extern "C" functions:
439 : // cdecl - _foo
440 : // stdcall - _foo@12
441 : // fastcall - @foo@12
442 : // vectorcall - foo@@12
443 : // These are all different linkage names for 'foo'.
444 0 : StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
445 : // Remove any '_' or '@' prefix.
446 0 : char Front = SymbolName.empty() ? '\0' : SymbolName[0];
447 0 : if (Front == '_' || Front == '@')
448 0 : SymbolName = SymbolName.drop_front();
449 :
450 : // Remove any '@[0-9]+' suffix.
451 0 : if (Front != '?') {
452 0 : size_t AtPos = SymbolName.rfind('@');
453 0 : if (AtPos != StringRef::npos &&
454 0 : std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(),
455 0 : [](char C) { return C >= '0' && C <= '9'; })) {
456 0 : SymbolName = SymbolName.substr(0, AtPos);
457 : }
458 : }
459 :
460 : // Remove any ending '@' for vectorcall.
461 : if (SymbolName.endswith("@"))
462 0 : SymbolName = SymbolName.drop_back();
463 :
464 0 : return SymbolName;
465 : }
466 :
467 : } // end anonymous namespace
468 :
469 : std::string
470 826 : LLVMSymbolizer::DemangleName(const std::string &Name,
471 : const SymbolizableModule *DbiModuleDescriptor) {
472 : // We can spoil names of symbols with C linkage, so use an heuristic
473 : // approach to check if the name should be demangled.
474 1652 : if (Name.substr(0, 2) == "_Z") {
475 398 : int status = 0;
476 398 : char *DemangledName = itaniumDemangle(Name.c_str(), nullptr, nullptr, &status);
477 398 : if (status != 0)
478 : return Name;
479 398 : std::string Result = DemangledName;
480 398 : free(DemangledName);
481 : return Result;
482 : }
483 :
484 : #if defined(_MSC_VER)
485 : if (!Name.empty() && Name.front() == '?') {
486 : // Only do MSVC C++ demangling on symbols starting with '?'.
487 : char DemangledName[1024] = {0};
488 : DWORD result = ::UnDecorateSymbolName(
489 : Name.c_str(), DemangledName, 1023,
490 : UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
491 : UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc
492 : UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
493 : UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
494 : UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords
495 : UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types
496 : return (result == 0) ? Name : std::string(DemangledName);
497 : }
498 : #endif
499 428 : if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
500 0 : return std::string(demanglePE32ExternCFunc(Name));
501 : return Name;
502 : }
503 :
504 : } // namespace symbolize
505 : } // namespace llvm
|