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