LLVM  16.0.0git
Symbolize.cpp
Go to the documentation of this file.
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 
14 
15 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/DebugInfo/PDB/PDB.h"
21 #include "llvm/Demangle/Demangle.h"
22 #include "llvm/Object/COFF.h"
24 #include "llvm/Object/MachO.h"
26 #include "llvm/Support/CRC.h"
27 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Errc.h"
32 #include "llvm/Support/Path.h"
33 #include <algorithm>
34 #include <cassert>
35 #include <cstring>
36 
37 namespace llvm {
38 namespace codeview {
39 union DebugInfo;
40 }
41 namespace object {
42 template <class ELFT> class ELFFile;
43 }
44 namespace symbolize {
45 
47 
48 LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) : Opts(Opts) {}
49 
51 
52 template <typename T>
54 LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
55  object::SectionedAddress ModuleOffset) {
56 
57  auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
58  if (!InfoOrErr)
59  return InfoOrErr.takeError();
60 
61  SymbolizableModule *Info = *InfoOrErr;
62 
63  // A null module means an error has already been reported. Return an empty
64  // result.
65  if (!Info)
66  return DILineInfo();
67 
68  // If the user is giving us relative addresses, add the preferred base of the
69  // object to the offset before we do the query. It's what DIContext expects.
70  if (Opts.RelativeAddresses)
71  ModuleOffset.Address += Info->getModulePreferredBase();
72 
73  DILineInfo LineInfo = Info->symbolizeCode(
74  ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
75  Opts.UseSymbolTable);
76  if (Opts.Demangle)
77  LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
78  return LineInfo;
79 }
80 
83  object::SectionedAddress ModuleOffset) {
84  return symbolizeCodeCommon(Obj, ModuleOffset);
85 }
86 
89  object::SectionedAddress ModuleOffset) {
90  return symbolizeCodeCommon(ModuleName, ModuleOffset);
91 }
92 
95  object::SectionedAddress ModuleOffset) {
96  return symbolizeCodeCommon(BuildID, ModuleOffset);
97 }
98 
99 template <typename T>
100 Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
101  const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
102  auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
103  if (!InfoOrErr)
104  return InfoOrErr.takeError();
105 
106  SymbolizableModule *Info = *InfoOrErr;
107 
108  // A null module means an error has already been reported. Return an empty
109  // result.
110  if (!Info)
111  return DIInliningInfo();
112 
113  // If the user is giving us relative addresses, add the preferred base of the
114  // object to the offset before we do the query. It's what DIContext expects.
115  if (Opts.RelativeAddresses)
116  ModuleOffset.Address += Info->getModulePreferredBase();
117 
118  DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
119  ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
120  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<DIInliningInfo>
132  object::SectionedAddress ModuleOffset) {
133  return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
134 }
135 
138  object::SectionedAddress ModuleOffset) {
139  return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
140 }
141 
144  object::SectionedAddress ModuleOffset) {
145  return symbolizeInlinedCodeCommon(BuildID, ModuleOffset);
146 }
147 
148 template <typename T>
150 LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
151  object::SectionedAddress ModuleOffset) {
152 
153  auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
154  if (!InfoOrErr)
155  return InfoOrErr.takeError();
156 
157  SymbolizableModule *Info = *InfoOrErr;
158  // A null module means an error has already been reported. Return an empty
159  // result.
160  if (!Info)
161  return DIGlobal();
162 
163  // If the user is giving us relative addresses, add the preferred base of
164  // the object to the offset before we do the query. It's what DIContext
165  // expects.
166  if (Opts.RelativeAddresses)
167  ModuleOffset.Address += Info->getModulePreferredBase();
168 
169  DIGlobal Global = Info->symbolizeData(ModuleOffset);
170  if (Opts.Demangle)
171  Global.Name = DemangleName(Global.Name, Info);
172  return Global;
173 }
174 
177  object::SectionedAddress ModuleOffset) {
178  return symbolizeDataCommon(Obj, ModuleOffset);
179 }
180 
183  object::SectionedAddress ModuleOffset) {
184  return symbolizeDataCommon(ModuleName, ModuleOffset);
185 }
186 
189  object::SectionedAddress ModuleOffset) {
190  return symbolizeDataCommon(BuildID, ModuleOffset);
191 }
192 
193 template <typename T>
195 LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
196  object::SectionedAddress ModuleOffset) {
197  auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
198  if (!InfoOrErr)
199  return InfoOrErr.takeError();
200 
201  SymbolizableModule *Info = *InfoOrErr;
202  // A null module means an error has already been reported. Return an empty
203  // result.
204  if (!Info)
205  return std::vector<DILocal>();
206 
207  // If the user is giving us relative addresses, add the preferred base of
208  // the object to the offset before we do the query. It's what DIContext
209  // expects.
210  if (Opts.RelativeAddresses)
211  ModuleOffset.Address += Info->getModulePreferredBase();
212 
213  return Info->symbolizeFrame(ModuleOffset);
214 }
215 
218  object::SectionedAddress ModuleOffset) {
219  return symbolizeFrameCommon(Obj, ModuleOffset);
220 }
221 
224  object::SectionedAddress ModuleOffset) {
225  return symbolizeFrameCommon(ModuleName, ModuleOffset);
226 }
227 
230  object::SectionedAddress ModuleOffset) {
231  return symbolizeFrameCommon(BuildID, ModuleOffset);
232 }
233 
235  ObjectForUBPathAndArch.clear();
236  LRUBinaries.clear();
237  CacheSize = 0;
238  BinaryForPath.clear();
239  ObjectPairForPathArch.clear();
240  Modules.clear();
241  BuildIDPaths.clear();
242 }
243 
244 namespace {
245 
246 // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
247 // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
248 // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
249 // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
250 std::string getDarwinDWARFResourceForPath(const std::string &Path,
251  const std::string &Basename) {
252  SmallString<16> ResourceName = StringRef(Path);
253  if (sys::path::extension(Path) != ".dSYM") {
254  ResourceName += ".dSYM";
255  }
256  sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
257  sys::path::append(ResourceName, Basename);
258  return std::string(ResourceName.str());
259 }
260 
261 bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
262  ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
264  if (!MB)
265  return false;
266  return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
267 }
268 
269 bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
270  uint32_t &CRCHash) {
271  if (!Obj)
272  return false;
273  for (const SectionRef &Section : Obj->sections()) {
274  StringRef Name;
275  consumeError(Section.getName().moveInto(Name));
276 
277  Name = Name.substr(Name.find_first_not_of("._"));
278  if (Name == "gnu_debuglink") {
279  Expected<StringRef> ContentsOrErr = Section.getContents();
280  if (!ContentsOrErr) {
281  consumeError(ContentsOrErr.takeError());
282  return false;
283  }
284  DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
285  uint64_t Offset = 0;
286  if (const char *DebugNameStr = DE.getCStr(&Offset)) {
287  // 4-byte align the offset.
288  Offset = (Offset + 3) & ~0x3;
289  if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
290  DebugName = DebugNameStr;
291  CRCHash = DE.getU32(&Offset);
292  return true;
293  }
294  }
295  break;
296  }
297  }
298  return false;
299 }
300 
301 bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
302  const MachOObjectFile *Obj) {
303  ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
304  ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
305  if (dbg_uuid.empty() || bin_uuid.empty())
306  return false;
307  return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
308 }
309 
310 template <typename ELFT>
311 Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) {
312  auto PhdrsOrErr = Obj.program_headers();
313  if (!PhdrsOrErr) {
314  consumeError(PhdrsOrErr.takeError());
315  return {};
316  }
317  for (const auto &P : *PhdrsOrErr) {
318  if (P.p_type != ELF::PT_NOTE)
319  continue;
320  Error Err = Error::success();
321  for (auto N : Obj.notes(P, Err))
322  if (N.getType() == ELF::NT_GNU_BUILD_ID &&
323  N.getName() == ELF::ELF_NOTE_GNU)
324  return N.getDesc();
325  consumeError(std::move(Err));
326  }
327  return {};
328 }
329 
330 } // end anonymous namespace
331 
334  if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
335  BuildID = getBuildID(O->getELFFile());
336  else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
337  BuildID = getBuildID(O->getELFFile());
338  else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
339  BuildID = getBuildID(O->getELFFile());
340  else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
341  BuildID = getBuildID(O->getELFFile());
342  else
343  llvm_unreachable("unsupported file format");
344  return BuildID;
345 }
346 
347 ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
348  const MachOObjectFile *MachExeObj,
349  const std::string &ArchName) {
350  // On Darwin we may find DWARF in separate object file in
351  // resource directory.
352  std::vector<std::string> DsymPaths;
353  StringRef Filename = sys::path::filename(ExePath);
354  DsymPaths.push_back(
355  getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
356  for (const auto &Path : Opts.DsymHints) {
357  DsymPaths.push_back(
358  getDarwinDWARFResourceForPath(Path, std::string(Filename)));
359  }
360  for (const auto &Path : DsymPaths) {
361  auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
362  if (!DbgObjOrErr) {
363  // Ignore errors, the file might not exist.
364  consumeError(DbgObjOrErr.takeError());
365  continue;
366  }
367  ObjectFile *DbgObj = DbgObjOrErr.get();
368  if (!DbgObj)
369  continue;
370  const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
371  if (!MachDbgObj)
372  continue;
373  if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
374  return DbgObj;
375  }
376  return nullptr;
377 }
378 
379 ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
380  const ObjectFile *Obj,
381  const std::string &ArchName) {
382  std::string DebuglinkName;
383  uint32_t CRCHash;
384  std::string DebugBinaryPath;
385  if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
386  return nullptr;
387  if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
388  return nullptr;
389  auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
390  if (!DbgObjOrErr) {
391  // Ignore errors, the file might not exist.
392  consumeError(DbgObjOrErr.takeError());
393  return nullptr;
394  }
395  return DbgObjOrErr.get();
396 }
397 
398 ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
399  const ELFObjectFileBase *Obj,
400  const std::string &ArchName) {
401  auto BuildID = getBuildID(Obj);
402  if (!BuildID)
403  return nullptr;
404  if (BuildID->size() < 2)
405  return nullptr;
406  std::string DebugBinaryPath;
407  if (!getOrFindDebugBinary(*BuildID, DebugBinaryPath))
408  return nullptr;
409  auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
410  if (!DbgObjOrErr) {
411  consumeError(DbgObjOrErr.takeError());
412  return nullptr;
413  }
414  return DbgObjOrErr.get();
415 }
416 
417 bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
418  const std::string &DebuglinkName,
419  uint32_t CRCHash, std::string &Result) {
420  SmallString<16> OrigDir(OrigPath);
422  SmallString<16> DebugPath = OrigDir;
423  // Try relative/path/to/original_binary/debuglink_name
424  llvm::sys::path::append(DebugPath, DebuglinkName);
425  if (checkFileCRC(DebugPath, CRCHash)) {
426  Result = std::string(DebugPath.str());
427  return true;
428  }
429  // Try relative/path/to/original_binary/.debug/debuglink_name
430  DebugPath = OrigDir;
431  llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
432  if (checkFileCRC(DebugPath, CRCHash)) {
433  Result = std::string(DebugPath.str());
434  return true;
435  }
436  // Make the path absolute so that lookups will go to
437  // "/usr/lib/debug/full/path/to/debug", not
438  // "/usr/lib/debug/to/debug"
440  if (!Opts.FallbackDebugPath.empty()) {
441  // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
442  DebugPath = Opts.FallbackDebugPath;
443  } else {
444 #if defined(__NetBSD__)
445  // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
446  DebugPath = "/usr/libdata/debug";
447 #else
448  // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
449  DebugPath = "/usr/lib/debug";
450 #endif
451  }
453  DebuglinkName);
454  if (checkFileCRC(DebugPath, CRCHash)) {
455  Result = std::string(DebugPath.str());
456  return true;
457  }
458  return false;
459 }
460 
462  return StringRef(reinterpret_cast<const char *>(BuildID.data()),
463  BuildID.size());
464 }
465 
466 bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
467  std::string &Result) {
468  StringRef BuildIDStr = getBuildIDStr(BuildID);
469  auto I = BuildIDPaths.find(BuildIDStr);
470  if (I != BuildIDPaths.end()) {
471  Result = I->second;
472  return true;
473  }
474  auto recordPath = [&](StringRef Path) {
475  Result = Path.str();
476  auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
477  assert(InsertResult.second);
478  (void)InsertResult;
479  };
480 
481  Optional<std::string> Path;
482  Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID);
483  if (Path) {
484  recordPath(*Path);
485  return true;
486  }
487 
488  // Try caller-provided debug info fetchers.
489  for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) {
490  Path = Fetcher->fetchBuildID(BuildID);
491  if (Path) {
492  recordPath(*Path);
493  return true;
494  }
495  }
496 
497  return false;
498 }
499 
500 Expected<LLVMSymbolizer::ObjectPair>
501 LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
502  const std::string &ArchName) {
503  auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
504  if (I != ObjectPairForPathArch.end()) {
505  recordAccess(BinaryForPath.find(Path)->second);
506  return I->second;
507  }
508 
509  auto ObjOrErr = getOrCreateObject(Path, ArchName);
510  if (!ObjOrErr) {
511  ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
512  ObjectPair(nullptr, nullptr));
513  return ObjOrErr.takeError();
514  }
515 
516  ObjectFile *Obj = ObjOrErr.get();
517  assert(Obj != nullptr);
518  ObjectFile *DbgObj = nullptr;
519 
520  if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
521  DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
522  else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
523  DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
524  if (!DbgObj)
525  DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
526  if (!DbgObj)
527  DbgObj = Obj;
528  ObjectPair Res = std::make_pair(Obj, DbgObj);
529  std::string DbgObjPath = DbgObj->getFileName().str();
530  auto Pair =
531  ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
532  BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
533  ObjectPairForPathArch.erase(I);
534  });
535  return Res;
536 }
537 
538 Expected<ObjectFile *>
539 LLVMSymbolizer::getOrCreateObject(const std::string &Path,
540  const std::string &ArchName) {
541  Binary *Bin;
542  auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
543  if (!Pair.second) {
544  Bin = Pair.first->second->getBinary();
545  recordAccess(Pair.first->second);
546  } else {
547  Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
548  if (!BinOrErr)
549  return BinOrErr.takeError();
550 
551  CachedBinary &CachedBin = Pair.first->second;
552  CachedBin = std::move(BinOrErr.get());
553  CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
554  LRUBinaries.push_back(CachedBin);
555  CacheSize += CachedBin.size();
556  Bin = CachedBin->getBinary();
557  }
558 
559  if (!Bin)
560  return static_cast<ObjectFile *>(nullptr);
561 
562  if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
563  auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
564  if (I != ObjectForUBPathAndArch.end())
565  return I->second.get();
566 
567  Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
568  UB->getMachOObjectForArch(ArchName);
569  if (!ObjOrErr) {
570  ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
571  std::unique_ptr<ObjectFile>());
572  return ObjOrErr.takeError();
573  }
574  ObjectFile *Res = ObjOrErr->get();
575  auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
576  std::move(ObjOrErr.get()));
577  BinaryForPath.find(Path)->second.pushEvictor(
578  [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
579  return Res;
580  }
581  if (Bin->isObject()) {
582  return cast<ObjectFile>(Bin);
583  }
584  return errorCodeToError(object_error::arch_not_found);
585 }
586 
587 Expected<SymbolizableModule *>
588 LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
589  std::unique_ptr<DIContext> Context,
590  StringRef ModuleName) {
591  auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
592  Opts.UntagAddresses);
593  std::unique_ptr<SymbolizableModule> SymMod;
594  if (InfoOrErr)
595  SymMod = std::move(*InfoOrErr);
596  auto InsertResult = Modules.insert(
597  std::make_pair(std::string(ModuleName), std::move(SymMod)));
598  assert(InsertResult.second);
599  if (!InfoOrErr)
600  return InfoOrErr.takeError();
601  return InsertResult.first->second.get();
602 }
603 
604 Expected<SymbolizableModule *>
605 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
606  std::string BinaryName = ModuleName;
607  std::string ArchName = Opts.DefaultArch;
608  size_t ColonPos = ModuleName.find_last_of(':');
609  // Verify that substring after colon form a valid arch name.
610  if (ColonPos != std::string::npos) {
611  std::string ArchStr = ModuleName.substr(ColonPos + 1);
612  if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
613  BinaryName = ModuleName.substr(0, ColonPos);
614  ArchName = ArchStr;
615  }
616  }
617 
618  auto I = Modules.find(ModuleName);
619  if (I != Modules.end()) {
620  recordAccess(BinaryForPath.find(BinaryName)->second);
621  return I->second.get();
622  }
623 
624  auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
625  if (!ObjectsOrErr) {
626  // Failed to find valid object file.
627  Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
628  return ObjectsOrErr.takeError();
629  }
630  ObjectPair Objects = ObjectsOrErr.get();
631 
632  std::unique_ptr<DIContext> Context;
633  // If this is a COFF object containing PDB info, use a PDBContext to
634  // symbolize. Otherwise, use DWARF.
635  if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
636  const codeview::DebugInfo *DebugInfo;
637  StringRef PDBFileName;
638  auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
639  if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
640  using namespace pdb;
641  std::unique_ptr<IPDBSession> Session;
642 
643  PDB_ReaderType ReaderType =
644  Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
645  if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
646  Session)) {
647  Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
648  // Return along the PDB filename to provide more context
649  return createFileError(PDBFileName, std::move(Err));
650  }
651  Context.reset(new PDBContext(*CoffObject, std::move(Session)));
652  }
653  }
654  if (!Context)
657  nullptr, Opts.DWPName);
658  auto ModuleOrErr =
659  createModuleInfo(Objects.first, std::move(Context), ModuleName);
660  if (ModuleOrErr) {
661  auto I = Modules.find(ModuleName);
662  BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() {
663  Modules.erase(I);
664  });
665  }
666  return ModuleOrErr;
667 }
668 
669 Expected<SymbolizableModule *>
670 LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
671  StringRef ObjName = Obj.getFileName();
672  auto I = Modules.find(ObjName);
673  if (I != Modules.end())
674  return I->second.get();
675 
676  std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
677  // FIXME: handle COFF object with PDB info to use PDBContext
678  return createModuleInfo(&Obj, std::move(Context), ObjName);
679 }
680 
681 Expected<SymbolizableModule *>
682 LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) {
683  std::string Path;
684  if (!getOrFindDebugBinary(BuildID, Path)) {
686  Twine("could not find build ID '") +
687  toHex(BuildID) + "'");
688  }
689  return getOrCreateModuleInfo(Path);
690 }
691 
692 namespace {
693 
694 // Undo these various manglings for Win32 extern "C" functions:
695 // cdecl - _foo
696 // stdcall - _foo@12
697 // fastcall - @foo@12
698 // vectorcall - foo@@12
699 // These are all different linkage names for 'foo'.
700 StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
701  // Remove any '_' or '@' prefix.
702  char Front = SymbolName.empty() ? '\0' : SymbolName[0];
703  if (Front == '_' || Front == '@')
704  SymbolName = SymbolName.drop_front();
705 
706  // Remove any '@[0-9]+' suffix.
707  if (Front != '?') {
708  size_t AtPos = SymbolName.rfind('@');
709  if (AtPos != StringRef::npos &&
710  all_of(drop_begin(SymbolName, AtPos + 1), isDigit))
711  SymbolName = SymbolName.substr(0, AtPos);
712  }
713 
714  // Remove any ending '@' for vectorcall.
715  if (SymbolName.endswith("@"))
716  SymbolName = SymbolName.drop_back();
717 
718  return SymbolName;
719 }
720 
721 } // end anonymous namespace
722 
723 std::string
725  const SymbolizableModule *DbiModuleDescriptor) {
726  std::string Result;
727  if (nonMicrosoftDemangle(Name.c_str(), Result))
728  return Result;
729 
730  if (!Name.empty() && Name.front() == '?') {
731  // Only do MSVC C++ demangling on symbols starting with '?'.
732  int status = 0;
733  char *DemangledName = microsoftDemangle(
734  Name.c_str(), nullptr, nullptr, nullptr, &status,
737  if (status != 0)
738  return Name;
739  Result = DemangledName;
740  free(DemangledName);
741  return Result;
742  }
743 
744  if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
745  return std::string(demanglePE32ExternCFunc(Name));
746  return Name;
747 }
748 
749 void LLVMSymbolizer::recordAccess(CachedBinary &Bin) {
750  if (Bin->getBinary())
751  LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator());
752 }
753 
755  // Evict the LRU binary until the max cache size is reached or there's <= 1
756  // item in the cache. The MRU binary is always kept to avoid thrashing if it's
757  // larger than the cache size.
758  while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() &&
759  std::next(LRUBinaries.begin()) != LRUBinaries.end()) {
760  CachedBinary &Bin = LRUBinaries.front();
761  CacheSize -= Bin.size();
762  LRUBinaries.pop_front();
763  Bin.evict();
764  }
765 }
766 
767 void CachedBinary::pushEvictor(std::function<void()> NewEvictor) {
768  if (Evictor) {
769  this->Evictor = [OldEvictor = std::move(this->Evictor),
770  NewEvictor = std::move(NewEvictor)]() {
771  NewEvictor();
772  OldEvictor();
773  };
774  } else {
775  this->Evictor = std::move(NewEvictor);
776  }
777 }
778 
779 } // namespace symbolize
780 } // namespace llvm
i
i
Definition: README.txt:29
MemoryBuffer.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::drop_begin
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:281
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
llvm::DWARFContext::create
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler)
Definition: DWARFContext.cpp:1999
llvm::sys::path::extension
StringRef extension(StringRef path, Style style=Style::native)
Get extension.
Definition: Path.cpp:590
FileSystem.h
llvm::Triple::UnknownArch
@ UnknownArch
Definition: Triple.h:47
llvm::symbolize::LLVMSymbolizer::Options::UntagAddresses
bool UntagAddresses
Definition: Symbolize.h:58
llvm::MSDF_NoAccessSpecifier
@ MSDF_NoAccessSpecifier
Definition: Demangle.h:37
llvm::DIInliningInfo
A format-neutral container for inlined code description.
Definition: DIContext.h:87
llvm::DILineInfoSpecifier
Controls which fields of DILineInfo container should be filled with data.
Definition: DIContext.h:139
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
llvm::BuildID
SmallVector< uint8_t, 10 > BuildID
Definition: Debuginfod.h:41
llvm::StringRef::npos
static constexpr size_t npos
Definition: StringRef.h:52
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1183
Path.h
llvm::symbolize::CachedBinary::pushEvictor
void pushEvictor(std::function< void()> Evictor)
Definition: Symbolize.cpp:767
llvm::object::SectionedAddress::Address
uint64_t Address
Definition: ObjectFile.h:147
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::crc32
uint32_t crc32(ArrayRef< uint8_t > Data)
Definition: CRC.cpp:101
DWARFContext.h
memcmp
Merge contiguous icmps into a memcmp
Definition: MergeICmps.cpp:899
llvm::symbolize::LLVMSymbolizer::Options::DebugFileDirectory
std::vector< std::string > DebugFileDirectory
Definition: Symbolize.h:64
llvm::ELF::NT_GNU_BUILD_ID
@ NT_GNU_BUILD_ID
Definition: ELF.h:1598
Errc.h
llvm::StringMap::end
iterator end()
Definition: StringMap.h:204
llvm::symbolize::SymbolizableObjectFile::create
static Expected< std::unique_ptr< SymbolizableObjectFile > > create(const object::ObjectFile *Obj, std::unique_ptr< DIContext > DICtx, bool UntagAddresses)
Definition: SymbolizableObjectFile.cpp:31
llvm::Optional
Definition: APInt.h:33
llvm::errc::no_such_file_or_directory
@ no_such_file_or_directory
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::symbolize::LLVMSymbolizer::flush
void flush()
Definition: Symbolize.cpp:234
STLExtras.h
llvm::StringMap::find
iterator find(StringRef Key)
Definition: StringMap.h:217
llvm::msgpack::Type::Binary
@ Binary
llvm::symbolize::LLVMSymbolizer::pruneCache
void pruneCache()
Definition: Symbolize.cpp:754
llvm::symbolize::CachedBinary
Definition: Symbolize.h:220
llvm::consumeError
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1043
llvm::DWARFContext::ProcessDebugRelocations::Process
@ Process
llvm::symbolize::LLVMSymbolizer::Options::DsymHints
std::vector< std::string > DsymHints
Definition: Symbolize.h:61
MachO.h
llvm::SubDirectoryType::Bin
@ Bin
llvm::DILineInfo::FunctionName
std::string FunctionName
Definition: DIContext.h:37
llvm::symbolize::LLVMSymbolizer::symbolizeCode
Expected< DILineInfo > symbolizeCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:82
llvm::sys::path::append
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:456
SymbolizableObjectFile.h
Context
LLVMContext & Context
Definition: NVVMIntrRange.cpp:66
llvm::ELF::PT_NOTE
@ PT_NOTE
Definition: ELF.h:1362
llvm::object::ELFObjectFileBase
Definition: ELFObjectFile.h:51
llvm::ARMBuildAttrs::Section
@ Section
Legacy Tags.
Definition: ARMBuildAttributes.h:82
llvm::pdb::loadDataForEXE
Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, std::unique_ptr< IPDBSession > &Session)
Definition: PDB.cpp:35
PDB.h
x3
In x86 we generate this spiffy xmm0 xmm0 ret in x86 we generate this which could be xmm1 movss xmm1 xmm0 ret In sse4 we could use insertps to make both better Here s another testcase that could use x3
Definition: README-SSE.txt:547
llvm::all_of
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1618
llvm::symbolize::LLVMSymbolizer::Options::UseSymbolTable
bool UseSymbolTable
Definition: Symbolize.h:55
llvm::symbolize::LLVMSymbolizer::symbolizeFrame
Expected< std::vector< DILocal > > symbolizeFrame(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:217
llvm::dyn_cast
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition: Casting.h:597
llvm::symbolize::LLVMSymbolizer::Options::DefaultArch
std::string DefaultArch
Definition: Symbolize.h:60
llvm::createFileError
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition: Error.h:1320
llvm::StringMap::insert
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition: StringMap.h:275
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
llvm::symbolize::getBuildIDStr
static StringRef getBuildIDStr(ArrayRef< uint8_t > BuildID)
Definition: Symbolize.cpp:461
MachOUniversal.h
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
CRC.h
llvm::StringMap::clear
void clear()
Definition: StringMap.h:348
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
llvm::symbolize::LLVMSymbolizer::Options::PrintFunctions
FunctionNameKind PrintFunctions
Definition: Symbolize.h:53
llvm::symbolize::LLVMSymbolizer::Options::RelativeAddresses
bool RelativeAddresses
Definition: Symbolize.h:57
llvm::pdb::PDB_ReaderType
PDB_ReaderType
Specifies which PDB reader implementation is to be used.
Definition: PDBTypes.h:80
llvm::pdb::PDB_ColorItem::Path
@ Path
llvm::MSDF_NoCallingConvention
@ MSDF_NoCallingConvention
Definition: Demangle.h:38
llvm::SmallString< 16 >
llvm::symbolize::LLVMSymbolizer::Options::Demangle
bool Demangle
Definition: Symbolize.h:56
llvm::symbolize::LLVMSymbolizer::LLVMSymbolizer
LLVMSymbolizer()
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:240
object
bar al al movzbl eax ret Missed when stored in a memory object
Definition: README.txt:1411
llvm::symbolize::getBuildID
Optional< ArrayRef< uint8_t > > getBuildID(const ELFObjectFileBase *Obj)
Definition: Symbolize.cpp:332
llvm::AMDGPU::Hwreg::Offset
Offset
Definition: SIDefines.h:416
uint64_t
llvm::symbolize::SymbolizableModule
Definition: SymbolizableModule.h:23
llvm::MSDF_NoReturnType
@ MSDF_NoReturnType
Definition: Demangle.h:39
llvm::symbolize::toHex
static std::string toHex(uint64_t V)
Definition: DIPrinter.cpp:278
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
DIFetcher.h
llvm::MemoryBuffer::getFileOrSTDIN
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
Definition: MemoryBuffer.cpp:146
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::DILineInfo
A format-neutral container for source line information.
Definition: DIContext.h:31
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ModuleName
Definition: ItaniumDemangle.h:998
llvm::codeview::CompileSym2Flags::EC
@ EC
llvm::symbolize::LLVMSymbolizer::symbolizeData
Expected< DIGlobal > symbolizeData(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:176
function
print Print MemDeps of function
Definition: MemDepPrinter.cpp:82
llvm::codeview::CodeViewContainer::ObjectFile
@ ObjectFile
llvm::sys::fs::make_absolute
void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
Definition: Path.cpp:906
isDigit
static bool isDigit(const char C)
Definition: RustDemangle.cpp:176
Demangle.h
llvm::ArrayRef< uint8_t >
Symbolize.h
PDBContext.h
llvm::symbolize::LLVMSymbolizer::symbolizeInlinedCode
Expected< DIInliningInfo > symbolizeInlinedCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:131
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm::object::ObjectFile
This class is the base class for all object file types.
Definition: ObjectFile.h:228
llvm::MSDemangleFlags
MSDemangleFlags
Definition: Demangle.h:34
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
uint32_t
llvm::symbolize::LLVMSymbolizer::Options::FallbackDebugPath
std::string FallbackDebugPath
Definition: Symbolize.h:62
ELFObjectFile.h
llvm::sampleprof::InlinedContext
@ InlinedContext
Definition: SampleProf.h:434
llvm::AMDGPU::HSAMD::Kernel::Key::SymbolName
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
Definition: AMDGPUMetadata.h:386
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1239
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::DIGlobal
Container for description of a global variable.
Definition: DIContext.h:113
llvm::symbolize::LLVMSymbolizer::Options::PathStyle
FileLineInfoKind PathStyle
Definition: Symbolize.h:54
llvm::ELF::ELF_NOTE_GNU
constexpr const char * ELF_NOTE_GNU
Definition: ELF.h:1761
Casting.h
DataExtractor.h
llvm::symbolize::LLVMSymbolizer::DemangleName
static std::string DemangleName(const std::string &Name, const SymbolizableModule *DbiModuleDescriptor)
Definition: Symbolize.cpp:724
llvm::SmallString::str
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:260
llvm::symbolize::LLVMSymbolizer::~LLVMSymbolizer
~LLVMSymbolizer()
llvm::microsoftDemangle
char * microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf, size_t *n_buf, int *status, MSDemangleFlags Flags=MSDF_None)
Demangles the Microsoft symbol pointed at by mangled_name and returns it.
Definition: MicrosoftDemangle.cpp:2338
llvm::symbolize::SymbolizableModule::isWin32Module
virtual bool isWin32Module() const =0
llvm::sys::path::filename
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:577
COFF.h
llvm::symbolize::LLVMSymbolizer::Options::DWPName
std::string DWPName
Definition: Symbolize.h:63
llvm::sys::fs::status
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
N
#define N
llvm::object::SectionedAddress
Definition: ObjectFile.h:144
llvm::nonMicrosoftDemangle
bool nonMicrosoftDemangle(const char *MangledName, std::string &Result)
Definition: Demangle.cpp:49
llvm::object::createBinary
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
Definition: Binary.cpp:45
llvm::sys::path::remove_filename
void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
Definition: Path.cpp:474
llvm::symbolize::LLVMSymbolizer::Options
Definition: Symbolize.h:52
llvm::sys::path::relative_path
StringRef relative_path(StringRef path, Style style=Style::native)
Get relative path.
Definition: Path.cpp:413
llvm::symbolize::LLVMSymbolizer::Options::MaxCacheSize
size_t MaxCacheSize
Definition: Symbolize.h:65
n
The same transformation can work with an even modulo with the addition of a and shrink the compare RHS by the same amount Unless the target supports that transformation probably isn t worthwhile The transformation can also easily be made to work with non zero equality for n
Definition: README.txt:685
llvm::object::ELFObjectFile
Definition: ELFObjectFile.h:240
llvm::MSDF_NoMemberType
@ MSDF_NoMemberType
Definition: Demangle.h:40