Symbolize.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  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. #include "llvm/DebugInfo/Symbolize/Symbolize.h"
  13. #include "llvm/ADT/STLExtras.h"
  14. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  15. #include "llvm/DebugInfo/PDB/PDB.h"
  16. #include "llvm/DebugInfo/PDB/PDBContext.h"
  17. #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
  18. #include "llvm/Demangle/Demangle.h"
  19. #include "llvm/Object/BuildID.h"
  20. #include "llvm/Object/COFF.h"
  21. #include "llvm/Object/ELFObjectFile.h"
  22. #include "llvm/Object/MachO.h"
  23. #include "llvm/Object/MachOUniversal.h"
  24. #include "llvm/Support/CRC.h"
  25. #include "llvm/Support/Casting.h"
  26. #include "llvm/Support/DataExtractor.h"
  27. #include "llvm/Support/Errc.h"
  28. #include "llvm/Support/FileSystem.h"
  29. #include "llvm/Support/MemoryBuffer.h"
  30. #include "llvm/Support/Path.h"
  31. #include <algorithm>
  32. #include <cassert>
  33. #include <cstring>
  34. namespace llvm {
  35. namespace codeview {
  36. union DebugInfo;
  37. }
  38. namespace symbolize {
  39. LLVMSymbolizer::LLVMSymbolizer() = default;
  40. LLVMSymbolizer::LLVMSymbolizer(const Options &Opts)
  41. : Opts(Opts),
  42. BIDFetcher(std::make_unique<BuildIDFetcher>(Opts.DebugFileDirectory)) {}
  43. LLVMSymbolizer::~LLVMSymbolizer() = default;
  44. template <typename T>
  45. Expected<DILineInfo>
  46. LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
  47. object::SectionedAddress ModuleOffset) {
  48. auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
  49. if (!InfoOrErr)
  50. return InfoOrErr.takeError();
  51. SymbolizableModule *Info = *InfoOrErr;
  52. // A null module means an error has already been reported. Return an empty
  53. // result.
  54. if (!Info)
  55. return DILineInfo();
  56. // If the user is giving us relative addresses, add the preferred base of the
  57. // object to the offset before we do the query. It's what DIContext expects.
  58. if (Opts.RelativeAddresses)
  59. ModuleOffset.Address += Info->getModulePreferredBase();
  60. DILineInfo LineInfo = Info->symbolizeCode(
  61. ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
  62. Opts.UseSymbolTable);
  63. if (Opts.Demangle)
  64. LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
  65. return LineInfo;
  66. }
  67. Expected<DILineInfo>
  68. LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
  69. object::SectionedAddress ModuleOffset) {
  70. return symbolizeCodeCommon(Obj, ModuleOffset);
  71. }
  72. Expected<DILineInfo>
  73. LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
  74. object::SectionedAddress ModuleOffset) {
  75. return symbolizeCodeCommon(ModuleName, ModuleOffset);
  76. }
  77. Expected<DILineInfo>
  78. LLVMSymbolizer::symbolizeCode(ArrayRef<uint8_t> BuildID,
  79. object::SectionedAddress ModuleOffset) {
  80. return symbolizeCodeCommon(BuildID, ModuleOffset);
  81. }
  82. template <typename T>
  83. Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
  84. const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
  85. auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
  86. if (!InfoOrErr)
  87. return InfoOrErr.takeError();
  88. SymbolizableModule *Info = *InfoOrErr;
  89. // A null module means an error has already been reported. Return an empty
  90. // result.
  91. if (!Info)
  92. return DIInliningInfo();
  93. // If the user is giving us relative addresses, add the preferred base of the
  94. // object to the offset before we do the query. It's what DIContext expects.
  95. if (Opts.RelativeAddresses)
  96. ModuleOffset.Address += Info->getModulePreferredBase();
  97. DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
  98. ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
  99. Opts.UseSymbolTable);
  100. if (Opts.Demangle) {
  101. for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
  102. auto *Frame = InlinedContext.getMutableFrame(i);
  103. Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
  104. }
  105. }
  106. return InlinedContext;
  107. }
  108. Expected<DIInliningInfo>
  109. LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
  110. object::SectionedAddress ModuleOffset) {
  111. return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
  112. }
  113. Expected<DIInliningInfo>
  114. LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
  115. object::SectionedAddress ModuleOffset) {
  116. return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
  117. }
  118. Expected<DIInliningInfo>
  119. LLVMSymbolizer::symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,
  120. object::SectionedAddress ModuleOffset) {
  121. return symbolizeInlinedCodeCommon(BuildID, ModuleOffset);
  122. }
  123. template <typename T>
  124. Expected<DIGlobal>
  125. LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
  126. object::SectionedAddress ModuleOffset) {
  127. auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
  128. if (!InfoOrErr)
  129. return InfoOrErr.takeError();
  130. SymbolizableModule *Info = *InfoOrErr;
  131. // A null module means an error has already been reported. Return an empty
  132. // result.
  133. if (!Info)
  134. return DIGlobal();
  135. // If the user is giving us relative addresses, add the preferred base of
  136. // the object to the offset before we do the query. It's what DIContext
  137. // expects.
  138. if (Opts.RelativeAddresses)
  139. ModuleOffset.Address += Info->getModulePreferredBase();
  140. DIGlobal Global = Info->symbolizeData(ModuleOffset);
  141. if (Opts.Demangle)
  142. Global.Name = DemangleName(Global.Name, Info);
  143. return Global;
  144. }
  145. Expected<DIGlobal>
  146. LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
  147. object::SectionedAddress ModuleOffset) {
  148. return symbolizeDataCommon(Obj, ModuleOffset);
  149. }
  150. Expected<DIGlobal>
  151. LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
  152. object::SectionedAddress ModuleOffset) {
  153. return symbolizeDataCommon(ModuleName, ModuleOffset);
  154. }
  155. Expected<DIGlobal>
  156. LLVMSymbolizer::symbolizeData(ArrayRef<uint8_t> BuildID,
  157. object::SectionedAddress ModuleOffset) {
  158. return symbolizeDataCommon(BuildID, ModuleOffset);
  159. }
  160. template <typename T>
  161. Expected<std::vector<DILocal>>
  162. LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
  163. object::SectionedAddress ModuleOffset) {
  164. auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
  165. if (!InfoOrErr)
  166. return InfoOrErr.takeError();
  167. SymbolizableModule *Info = *InfoOrErr;
  168. // A null module means an error has already been reported. Return an empty
  169. // result.
  170. if (!Info)
  171. return std::vector<DILocal>();
  172. // If the user is giving us relative addresses, add the preferred base of
  173. // the object to the offset before we do the query. It's what DIContext
  174. // expects.
  175. if (Opts.RelativeAddresses)
  176. ModuleOffset.Address += Info->getModulePreferredBase();
  177. return Info->symbolizeFrame(ModuleOffset);
  178. }
  179. Expected<std::vector<DILocal>>
  180. LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
  181. object::SectionedAddress ModuleOffset) {
  182. return symbolizeFrameCommon(Obj, ModuleOffset);
  183. }
  184. Expected<std::vector<DILocal>>
  185. LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
  186. object::SectionedAddress ModuleOffset) {
  187. return symbolizeFrameCommon(ModuleName, ModuleOffset);
  188. }
  189. Expected<std::vector<DILocal>>
  190. LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
  191. object::SectionedAddress ModuleOffset) {
  192. return symbolizeFrameCommon(BuildID, ModuleOffset);
  193. }
  194. void LLVMSymbolizer::flush() {
  195. ObjectForUBPathAndArch.clear();
  196. LRUBinaries.clear();
  197. CacheSize = 0;
  198. BinaryForPath.clear();
  199. ObjectPairForPathArch.clear();
  200. Modules.clear();
  201. BuildIDPaths.clear();
  202. }
  203. namespace {
  204. // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
  205. // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
  206. // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
  207. // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
  208. std::string getDarwinDWARFResourceForPath(const std::string &Path,
  209. const std::string &Basename) {
  210. SmallString<16> ResourceName = StringRef(Path);
  211. if (sys::path::extension(Path) != ".dSYM") {
  212. ResourceName += ".dSYM";
  213. }
  214. sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
  215. sys::path::append(ResourceName, Basename);
  216. return std::string(ResourceName.str());
  217. }
  218. bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
  219. ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
  220. MemoryBuffer::getFileOrSTDIN(Path);
  221. if (!MB)
  222. return false;
  223. return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
  224. }
  225. bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
  226. uint32_t &CRCHash) {
  227. if (!Obj)
  228. return false;
  229. for (const SectionRef &Section : Obj->sections()) {
  230. StringRef Name;
  231. consumeError(Section.getName().moveInto(Name));
  232. Name = Name.substr(Name.find_first_not_of("._"));
  233. if (Name == "gnu_debuglink") {
  234. Expected<StringRef> ContentsOrErr = Section.getContents();
  235. if (!ContentsOrErr) {
  236. consumeError(ContentsOrErr.takeError());
  237. return false;
  238. }
  239. DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
  240. uint64_t Offset = 0;
  241. if (const char *DebugNameStr = DE.getCStr(&Offset)) {
  242. // 4-byte align the offset.
  243. Offset = (Offset + 3) & ~0x3;
  244. if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
  245. DebugName = DebugNameStr;
  246. CRCHash = DE.getU32(&Offset);
  247. return true;
  248. }
  249. }
  250. break;
  251. }
  252. }
  253. return false;
  254. }
  255. bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
  256. const MachOObjectFile *Obj) {
  257. ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
  258. ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
  259. if (dbg_uuid.empty() || bin_uuid.empty())
  260. return false;
  261. return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
  262. }
  263. } // end anonymous namespace
  264. ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
  265. const MachOObjectFile *MachExeObj,
  266. const std::string &ArchName) {
  267. // On Darwin we may find DWARF in separate object file in
  268. // resource directory.
  269. std::vector<std::string> DsymPaths;
  270. StringRef Filename = sys::path::filename(ExePath);
  271. DsymPaths.push_back(
  272. getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
  273. for (const auto &Path : Opts.DsymHints) {
  274. DsymPaths.push_back(
  275. getDarwinDWARFResourceForPath(Path, std::string(Filename)));
  276. }
  277. for (const auto &Path : DsymPaths) {
  278. auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
  279. if (!DbgObjOrErr) {
  280. // Ignore errors, the file might not exist.
  281. consumeError(DbgObjOrErr.takeError());
  282. continue;
  283. }
  284. ObjectFile *DbgObj = DbgObjOrErr.get();
  285. if (!DbgObj)
  286. continue;
  287. const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
  288. if (!MachDbgObj)
  289. continue;
  290. if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
  291. return DbgObj;
  292. }
  293. return nullptr;
  294. }
  295. ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
  296. const ObjectFile *Obj,
  297. const std::string &ArchName) {
  298. std::string DebuglinkName;
  299. uint32_t CRCHash;
  300. std::string DebugBinaryPath;
  301. if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
  302. return nullptr;
  303. if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
  304. return nullptr;
  305. auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
  306. if (!DbgObjOrErr) {
  307. // Ignore errors, the file might not exist.
  308. consumeError(DbgObjOrErr.takeError());
  309. return nullptr;
  310. }
  311. return DbgObjOrErr.get();
  312. }
  313. ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
  314. const ELFObjectFileBase *Obj,
  315. const std::string &ArchName) {
  316. auto BuildID = getBuildID(Obj);
  317. if (!BuildID)
  318. return nullptr;
  319. if (BuildID->size() < 2)
  320. return nullptr;
  321. std::string DebugBinaryPath;
  322. if (!getOrFindDebugBinary(*BuildID, DebugBinaryPath))
  323. return nullptr;
  324. auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
  325. if (!DbgObjOrErr) {
  326. consumeError(DbgObjOrErr.takeError());
  327. return nullptr;
  328. }
  329. return DbgObjOrErr.get();
  330. }
  331. bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
  332. const std::string &DebuglinkName,
  333. uint32_t CRCHash, std::string &Result) {
  334. SmallString<16> OrigDir(OrigPath);
  335. llvm::sys::path::remove_filename(OrigDir);
  336. SmallString<16> DebugPath = OrigDir;
  337. // Try relative/path/to/original_binary/debuglink_name
  338. llvm::sys::path::append(DebugPath, DebuglinkName);
  339. if (checkFileCRC(DebugPath, CRCHash)) {
  340. Result = std::string(DebugPath.str());
  341. return true;
  342. }
  343. // Try relative/path/to/original_binary/.debug/debuglink_name
  344. DebugPath = OrigDir;
  345. llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
  346. if (checkFileCRC(DebugPath, CRCHash)) {
  347. Result = std::string(DebugPath.str());
  348. return true;
  349. }
  350. // Make the path absolute so that lookups will go to
  351. // "/usr/lib/debug/full/path/to/debug", not
  352. // "/usr/lib/debug/to/debug"
  353. llvm::sys::fs::make_absolute(OrigDir);
  354. if (!Opts.FallbackDebugPath.empty()) {
  355. // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
  356. DebugPath = Opts.FallbackDebugPath;
  357. } else {
  358. #if defined(__NetBSD__)
  359. // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
  360. DebugPath = "/usr/libdata/debug";
  361. #else
  362. // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
  363. DebugPath = "/usr/lib/debug";
  364. #endif
  365. }
  366. llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
  367. DebuglinkName);
  368. if (checkFileCRC(DebugPath, CRCHash)) {
  369. Result = std::string(DebugPath.str());
  370. return true;
  371. }
  372. return false;
  373. }
  374. static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) {
  375. return StringRef(reinterpret_cast<const char *>(BuildID.data()),
  376. BuildID.size());
  377. }
  378. bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
  379. std::string &Result) {
  380. StringRef BuildIDStr = getBuildIDStr(BuildID);
  381. auto I = BuildIDPaths.find(BuildIDStr);
  382. if (I != BuildIDPaths.end()) {
  383. Result = I->second;
  384. return true;
  385. }
  386. if (!BIDFetcher)
  387. return false;
  388. if (std::optional<std::string> Path = BIDFetcher->fetch(BuildID)) {
  389. Result = *Path;
  390. auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
  391. assert(InsertResult.second);
  392. (void)InsertResult;
  393. return true;
  394. }
  395. return false;
  396. }
  397. Expected<LLVMSymbolizer::ObjectPair>
  398. LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
  399. const std::string &ArchName) {
  400. auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
  401. if (I != ObjectPairForPathArch.end()) {
  402. recordAccess(BinaryForPath.find(Path)->second);
  403. return I->second;
  404. }
  405. auto ObjOrErr = getOrCreateObject(Path, ArchName);
  406. if (!ObjOrErr) {
  407. ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
  408. ObjectPair(nullptr, nullptr));
  409. return ObjOrErr.takeError();
  410. }
  411. ObjectFile *Obj = ObjOrErr.get();
  412. assert(Obj != nullptr);
  413. ObjectFile *DbgObj = nullptr;
  414. if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
  415. DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
  416. else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
  417. DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
  418. if (!DbgObj)
  419. DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
  420. if (!DbgObj)
  421. DbgObj = Obj;
  422. ObjectPair Res = std::make_pair(Obj, DbgObj);
  423. std::string DbgObjPath = DbgObj->getFileName().str();
  424. auto Pair =
  425. ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
  426. BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
  427. ObjectPairForPathArch.erase(I);
  428. });
  429. return Res;
  430. }
  431. Expected<ObjectFile *>
  432. LLVMSymbolizer::getOrCreateObject(const std::string &Path,
  433. const std::string &ArchName) {
  434. Binary *Bin;
  435. auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
  436. if (!Pair.second) {
  437. Bin = Pair.first->second->getBinary();
  438. recordAccess(Pair.first->second);
  439. } else {
  440. Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
  441. if (!BinOrErr)
  442. return BinOrErr.takeError();
  443. CachedBinary &CachedBin = Pair.first->second;
  444. CachedBin = std::move(BinOrErr.get());
  445. CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
  446. LRUBinaries.push_back(CachedBin);
  447. CacheSize += CachedBin.size();
  448. Bin = CachedBin->getBinary();
  449. }
  450. if (!Bin)
  451. return static_cast<ObjectFile *>(nullptr);
  452. if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
  453. auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
  454. if (I != ObjectForUBPathAndArch.end())
  455. return I->second.get();
  456. Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
  457. UB->getMachOObjectForArch(ArchName);
  458. if (!ObjOrErr) {
  459. ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
  460. std::unique_ptr<ObjectFile>());
  461. return ObjOrErr.takeError();
  462. }
  463. ObjectFile *Res = ObjOrErr->get();
  464. auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
  465. std::move(ObjOrErr.get()));
  466. BinaryForPath.find(Path)->second.pushEvictor(
  467. [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
  468. return Res;
  469. }
  470. if (Bin->isObject()) {
  471. return cast<ObjectFile>(Bin);
  472. }
  473. return errorCodeToError(object_error::arch_not_found);
  474. }
  475. Expected<SymbolizableModule *>
  476. LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
  477. std::unique_ptr<DIContext> Context,
  478. StringRef ModuleName) {
  479. auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
  480. Opts.UntagAddresses);
  481. std::unique_ptr<SymbolizableModule> SymMod;
  482. if (InfoOrErr)
  483. SymMod = std::move(*InfoOrErr);
  484. auto InsertResult = Modules.insert(
  485. std::make_pair(std::string(ModuleName), std::move(SymMod)));
  486. assert(InsertResult.second);
  487. if (!InfoOrErr)
  488. return InfoOrErr.takeError();
  489. return InsertResult.first->second.get();
  490. }
  491. Expected<SymbolizableModule *>
  492. LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
  493. std::string BinaryName = ModuleName;
  494. std::string ArchName = Opts.DefaultArch;
  495. size_t ColonPos = ModuleName.find_last_of(':');
  496. // Verify that substring after colon form a valid arch name.
  497. if (ColonPos != std::string::npos) {
  498. std::string ArchStr = ModuleName.substr(ColonPos + 1);
  499. if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
  500. BinaryName = ModuleName.substr(0, ColonPos);
  501. ArchName = ArchStr;
  502. }
  503. }
  504. auto I = Modules.find(ModuleName);
  505. if (I != Modules.end()) {
  506. recordAccess(BinaryForPath.find(BinaryName)->second);
  507. return I->second.get();
  508. }
  509. auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
  510. if (!ObjectsOrErr) {
  511. // Failed to find valid object file.
  512. Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
  513. return ObjectsOrErr.takeError();
  514. }
  515. ObjectPair Objects = ObjectsOrErr.get();
  516. std::unique_ptr<DIContext> Context;
  517. // If this is a COFF object containing PDB info, use a PDBContext to
  518. // symbolize. Otherwise, use DWARF.
  519. if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
  520. const codeview::DebugInfo *DebugInfo;
  521. StringRef PDBFileName;
  522. auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
  523. if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
  524. using namespace pdb;
  525. std::unique_ptr<IPDBSession> Session;
  526. PDB_ReaderType ReaderType =
  527. Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
  528. if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
  529. Session)) {
  530. Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
  531. // Return along the PDB filename to provide more context
  532. return createFileError(PDBFileName, std::move(Err));
  533. }
  534. Context.reset(new PDBContext(*CoffObject, std::move(Session)));
  535. }
  536. }
  537. if (!Context)
  538. Context = DWARFContext::create(
  539. *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
  540. nullptr, Opts.DWPName);
  541. auto ModuleOrErr =
  542. createModuleInfo(Objects.first, std::move(Context), ModuleName);
  543. if (ModuleOrErr) {
  544. auto I = Modules.find(ModuleName);
  545. BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() {
  546. Modules.erase(I);
  547. });
  548. }
  549. return ModuleOrErr;
  550. }
  551. Expected<SymbolizableModule *>
  552. LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
  553. StringRef ObjName = Obj.getFileName();
  554. auto I = Modules.find(ObjName);
  555. if (I != Modules.end())
  556. return I->second.get();
  557. std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
  558. // FIXME: handle COFF object with PDB info to use PDBContext
  559. return createModuleInfo(&Obj, std::move(Context), ObjName);
  560. }
  561. Expected<SymbolizableModule *>
  562. LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) {
  563. std::string Path;
  564. if (!getOrFindDebugBinary(BuildID, Path)) {
  565. return createStringError(errc::no_such_file_or_directory,
  566. Twine("could not find build ID '") +
  567. toHex(BuildID) + "'");
  568. }
  569. return getOrCreateModuleInfo(Path);
  570. }
  571. namespace {
  572. // Undo these various manglings for Win32 extern "C" functions:
  573. // cdecl - _foo
  574. // stdcall - _foo@12
  575. // fastcall - @foo@12
  576. // vectorcall - foo@@12
  577. // These are all different linkage names for 'foo'.
  578. StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
  579. char Front = SymbolName.empty() ? '\0' : SymbolName[0];
  580. // Remove any '@[0-9]+' suffix.
  581. bool HasAtNumSuffix = false;
  582. if (Front != '?') {
  583. size_t AtPos = SymbolName.rfind('@');
  584. if (AtPos != StringRef::npos &&
  585. all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) {
  586. SymbolName = SymbolName.substr(0, AtPos);
  587. HasAtNumSuffix = true;
  588. }
  589. }
  590. // Remove any ending '@' for vectorcall.
  591. bool IsVectorCall = false;
  592. if (HasAtNumSuffix && SymbolName.endswith("@")) {
  593. SymbolName = SymbolName.drop_back();
  594. IsVectorCall = true;
  595. }
  596. // If not vectorcall, remove any '_' or '@' prefix.
  597. if (!IsVectorCall && (Front == '_' || Front == '@'))
  598. SymbolName = SymbolName.drop_front();
  599. return SymbolName;
  600. }
  601. } // end anonymous namespace
  602. std::string
  603. LLVMSymbolizer::DemangleName(const std::string &Name,
  604. const SymbolizableModule *DbiModuleDescriptor) {
  605. std::string Result;
  606. if (nonMicrosoftDemangle(Name.c_str(), Result))
  607. return Result;
  608. if (!Name.empty() && Name.front() == '?') {
  609. // Only do MSVC C++ demangling on symbols starting with '?'.
  610. int status = 0;
  611. char *DemangledName = microsoftDemangle(
  612. Name.c_str(), nullptr, nullptr, nullptr, &status,
  613. MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
  614. MSDF_NoMemberType | MSDF_NoReturnType));
  615. if (status != 0)
  616. return Name;
  617. Result = DemangledName;
  618. free(DemangledName);
  619. return Result;
  620. }
  621. if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) {
  622. std::string DemangledCName(demanglePE32ExternCFunc(Name));
  623. // On i386 Windows, the C name mangling for different calling conventions
  624. // may also be applied on top of the Itanium or Rust name mangling.
  625. if (nonMicrosoftDemangle(DemangledCName.c_str(), Result))
  626. return Result;
  627. return DemangledCName;
  628. }
  629. return Name;
  630. }
  631. void LLVMSymbolizer::recordAccess(CachedBinary &Bin) {
  632. if (Bin->getBinary())
  633. LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator());
  634. }
  635. void LLVMSymbolizer::pruneCache() {
  636. // Evict the LRU binary until the max cache size is reached or there's <= 1
  637. // item in the cache. The MRU binary is always kept to avoid thrashing if it's
  638. // larger than the cache size.
  639. while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() &&
  640. std::next(LRUBinaries.begin()) != LRUBinaries.end()) {
  641. CachedBinary &Bin = LRUBinaries.front();
  642. CacheSize -= Bin.size();
  643. LRUBinaries.pop_front();
  644. Bin.evict();
  645. }
  646. }
  647. void CachedBinary::pushEvictor(std::function<void()> NewEvictor) {
  648. if (Evictor) {
  649. this->Evictor = [OldEvictor = std::move(this->Evictor),
  650. NewEvictor = std::move(NewEvictor)]() {
  651. NewEvictor();
  652. OldEvictor();
  653. };
  654. } else {
  655. this->Evictor = std::move(NewEvictor);
  656. }
  657. }
  658. } // namespace symbolize
  659. } // namespace llvm