MachODebugMapParser.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. //===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
  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. #include "BinaryHolder.h"
  9. #include "DebugMap.h"
  10. #include "MachOUtils.h"
  11. #include "llvm/ADT/SmallSet.h"
  12. #include "llvm/Object/MachO.h"
  13. #include "llvm/Support/Path.h"
  14. #include "llvm/Support/WithColor.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. #include <optional>
  17. #include <vector>
  18. namespace {
  19. using namespace llvm;
  20. using namespace llvm::dsymutil;
  21. using namespace llvm::object;
  22. class MachODebugMapParser {
  23. public:
  24. MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
  25. StringRef BinaryPath, ArrayRef<std::string> Archs,
  26. StringRef PathPrefix = "",
  27. bool PaperTrailWarnings = false, bool Verbose = false)
  28. : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
  29. PathPrefix(std::string(PathPrefix)),
  30. PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
  31. CurrentDebugMapObject(nullptr) {}
  32. /// Parses and returns the DebugMaps of the input binary. The binary contains
  33. /// multiple maps in case it is a universal binary.
  34. /// \returns an error in case the provided BinaryPath doesn't exist
  35. /// or isn't of a supported type.
  36. ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();
  37. /// Walk the symbol table and dump it.
  38. bool dumpStab();
  39. private:
  40. std::string BinaryPath;
  41. SmallVector<StringRef, 1> Archs;
  42. std::string PathPrefix;
  43. bool PaperTrailWarnings;
  44. /// Owns the MemoryBuffer for the main binary.
  45. BinaryHolder BinHolder;
  46. /// Map of the binary symbol addresses.
  47. StringMap<uint64_t> MainBinarySymbolAddresses;
  48. StringRef MainBinaryStrings;
  49. /// The constructed DebugMap.
  50. std::unique_ptr<DebugMap> Result;
  51. /// List of common symbols that need to be added to the debug map.
  52. std::vector<std::string> CommonSymbols;
  53. /// Map of the currently processed object file symbol addresses.
  54. StringMap<std::optional<uint64_t>> CurrentObjectAddresses;
  55. /// Lazily computed map of symbols aliased to the processed object file.
  56. StringMap<std::optional<uint64_t>> CurrentObjectAliasMap;
  57. /// If CurrentObjectAliasMap has been computed for a given address.
  58. SmallSet<uint64_t, 4> SeenAliasValues;
  59. /// Element of the debug map corresponding to the current object file.
  60. DebugMapObject *CurrentDebugMapObject;
  61. /// Holds function info while function scope processing.
  62. const char *CurrentFunctionName;
  63. uint64_t CurrentFunctionAddress;
  64. std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
  65. StringRef BinaryPath);
  66. void
  67. switchToNewDebugMapObject(StringRef Filename,
  68. sys::TimePoint<std::chrono::seconds> Timestamp);
  69. void resetParserState();
  70. uint64_t getMainBinarySymbolAddress(StringRef Name);
  71. std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
  72. void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
  73. void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
  74. void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
  75. uint8_t SectionIndex, uint16_t Flags,
  76. uint64_t Value);
  77. template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
  78. handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
  79. STE.n_value);
  80. }
  81. void addCommonSymbols();
  82. /// Dump the symbol table output header.
  83. void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);
  84. /// Dump the contents of nlist entries.
  85. void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex,
  86. uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
  87. uint64_t Value);
  88. template <typename STEType>
  89. void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) {
  90. dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
  91. STE.n_value);
  92. }
  93. void dumpOneBinaryStab(const MachOObjectFile &MainBinary,
  94. StringRef BinaryPath);
  95. void Warning(const Twine &Msg, StringRef File = StringRef()) {
  96. WithColor::warning() << "("
  97. << MachOUtils::getArchName(
  98. Result->getTriple().getArchName())
  99. << ") " << File << " " << Msg << "\n";
  100. if (PaperTrailWarnings) {
  101. if (!File.empty())
  102. Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
  103. if (Result->end() != Result->begin()) {
  104. auto it = Result->end();
  105. (*--it)->addWarning(Msg.str());
  106. }
  107. }
  108. }
  109. };
  110. } // anonymous namespace
  111. /// Reset the parser state corresponding to the current object
  112. /// file. This is to be called after an object file is finished
  113. /// processing.
  114. void MachODebugMapParser::resetParserState() {
  115. CommonSymbols.clear();
  116. CurrentObjectAddresses.clear();
  117. CurrentObjectAliasMap.clear();
  118. SeenAliasValues.clear();
  119. CurrentDebugMapObject = nullptr;
  120. }
  121. /// Commons symbols won't show up in the symbol map but might need to be
  122. /// relocated. We can add them to the symbol table ourselves by combining the
  123. /// information in the object file (the symbol name) and the main binary (the
  124. /// address).
  125. void MachODebugMapParser::addCommonSymbols() {
  126. for (auto &CommonSymbol : CommonSymbols) {
  127. uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol);
  128. if (CommonAddr == 0) {
  129. // The main binary doesn't have an address for the given symbol.
  130. continue;
  131. }
  132. if (!CurrentDebugMapObject->addSymbol(CommonSymbol,
  133. std::nullopt /*ObjectAddress*/,
  134. CommonAddr, 0 /*size*/)) {
  135. // The symbol is already present.
  136. continue;
  137. }
  138. }
  139. }
  140. /// Create a new DebugMapObject. This function resets the state of the
  141. /// parser that was referring to the last object file and sets
  142. /// everything up to add symbols to the new one.
  143. void MachODebugMapParser::switchToNewDebugMapObject(
  144. StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
  145. addCommonSymbols();
  146. resetParserState();
  147. SmallString<80> Path(PathPrefix);
  148. sys::path::append(Path, Filename);
  149. auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
  150. if (!ObjectEntry) {
  151. auto Err = ObjectEntry.takeError();
  152. Warning("unable to open object file: " + toString(std::move(Err)),
  153. Path.str());
  154. return;
  155. }
  156. auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple());
  157. if (!Object) {
  158. auto Err = Object.takeError();
  159. Warning("unable to open object file: " + toString(std::move(Err)),
  160. Path.str());
  161. return;
  162. }
  163. CurrentDebugMapObject =
  164. &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO);
  165. loadCurrentObjectFileSymbols(*Object);
  166. }
  167. static std::string getArchName(const object::MachOObjectFile &Obj) {
  168. Triple T = Obj.getArchTriple();
  169. return std::string(T.getArchName());
  170. }
  171. std::unique_ptr<DebugMap>
  172. MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
  173. StringRef BinaryPath) {
  174. loadMainBinarySymbols(MainBinary);
  175. ArrayRef<uint8_t> UUID = MainBinary.getUuid();
  176. Result =
  177. std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID);
  178. MainBinaryStrings = MainBinary.getStringTableData();
  179. for (const SymbolRef &Symbol : MainBinary.symbols()) {
  180. const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
  181. if (MainBinary.is64Bit())
  182. handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
  183. else
  184. handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
  185. }
  186. resetParserState();
  187. return std::move(Result);
  188. }
  189. // Table that maps Darwin's Mach-O stab constants to strings to allow printing.
  190. // llvm-nm has very similar code, the strings used here are however slightly
  191. // different and part of the interface of dsymutil (some project's build-systems
  192. // parse the ouptut of dsymutil -s), thus they shouldn't be changed.
  193. struct DarwinStabName {
  194. uint8_t NType;
  195. const char *Name;
  196. };
  197. const struct DarwinStabName DarwinStabNames[] = {
  198. {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"},
  199. {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"},
  200. {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"},
  201. {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"},
  202. {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"},
  203. {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"},
  204. {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"},
  205. {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"},
  206. {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"},
  207. {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
  208. {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"},
  209. {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"},
  210. {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"},
  211. {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"},
  212. {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"},
  213. {MachO::N_LENG, "N_LENG"}, {0, nullptr}};
  214. static const char *getDarwinStabString(uint8_t NType) {
  215. for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
  216. if (DarwinStabNames[i].NType == NType)
  217. return DarwinStabNames[i].Name;
  218. }
  219. return nullptr;
  220. }
  221. void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) {
  222. OS << "-----------------------------------"
  223. "-----------------------------------\n";
  224. OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n";
  225. OS << "-----------------------------------"
  226. "-----------------------------------\n";
  227. OS << "Index n_strx n_type n_sect n_desc n_value\n";
  228. OS << "======== -------- ------------------ ------ ------ ----------------\n";
  229. }
  230. void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index,
  231. uint32_t StringIndex, uint8_t Type,
  232. uint8_t SectionIndex, uint16_t Flags,
  233. uint64_t Value) {
  234. // Index
  235. OS << '[' << format_decimal(Index, 6)
  236. << "] "
  237. // n_strx
  238. << format_hex_no_prefix(StringIndex, 8)
  239. << ' '
  240. // n_type...
  241. << format_hex_no_prefix(Type, 2) << " (";
  242. if (Type & MachO::N_STAB)
  243. OS << left_justify(getDarwinStabString(Type), 13);
  244. else {
  245. if (Type & MachO::N_PEXT)
  246. OS << "PEXT ";
  247. else
  248. OS << " ";
  249. switch (Type & MachO::N_TYPE) {
  250. case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT
  251. OS << "UNDF";
  252. break;
  253. case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT
  254. OS << "ABS ";
  255. break;
  256. case MachO::N_SECT: // 0xe defined in section number n_sect
  257. OS << "SECT";
  258. break;
  259. case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib)
  260. OS << "PBUD";
  261. break;
  262. case MachO::N_INDR: // 0xa indirect
  263. OS << "INDR";
  264. break;
  265. default:
  266. OS << format_hex_no_prefix(Type, 2) << " ";
  267. break;
  268. }
  269. if (Type & MachO::N_EXT)
  270. OS << " EXT";
  271. else
  272. OS << " ";
  273. }
  274. OS << ") "
  275. // n_sect
  276. << format_hex_no_prefix(SectionIndex, 2)
  277. << " "
  278. // n_desc
  279. << format_hex_no_prefix(Flags, 4)
  280. << " "
  281. // n_value
  282. << format_hex_no_prefix(Value, 16);
  283. const char *Name = &MainBinaryStrings.data()[StringIndex];
  284. if (Name && Name[0])
  285. OS << " '" << Name << "'";
  286. OS << "\n";
  287. }
  288. void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary,
  289. StringRef BinaryPath) {
  290. loadMainBinarySymbols(MainBinary);
  291. MainBinaryStrings = MainBinary.getStringTableData();
  292. raw_ostream &OS(llvm::outs());
  293. dumpSymTabHeader(OS, getArchName(MainBinary));
  294. uint64_t Idx = 0;
  295. for (const SymbolRef &Symbol : MainBinary.symbols()) {
  296. const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
  297. if (MainBinary.is64Bit())
  298. dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI));
  299. else
  300. dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI));
  301. Idx++;
  302. }
  303. OS << "\n\n";
  304. resetParserState();
  305. }
  306. static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) {
  307. if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*"))
  308. return true;
  309. if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm"))
  310. return true;
  311. SmallString<16> ArchName = Arch;
  312. if (Arch.startswith("thumb"))
  313. ArchName = ("arm" + Arch.substr(5)).str();
  314. return is_contained(Archs, ArchName);
  315. }
  316. bool MachODebugMapParser::dumpStab() {
  317. auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
  318. if (!ObjectEntry) {
  319. auto Err = ObjectEntry.takeError();
  320. WithColor::error() << "cannot load '" << BinaryPath
  321. << "': " << toString(std::move(Err)) << '\n';
  322. return false;
  323. }
  324. auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
  325. if (!Objects) {
  326. auto Err = Objects.takeError();
  327. WithColor::error() << "cannot get '" << BinaryPath
  328. << "' as MachO file: " << toString(std::move(Err))
  329. << "\n";
  330. return false;
  331. }
  332. for (const auto *Object : *Objects)
  333. if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
  334. dumpOneBinaryStab(*Object, BinaryPath);
  335. return true;
  336. }
  337. /// This main parsing routine tries to open the main binary and if
  338. /// successful iterates over the STAB entries. The real parsing is
  339. /// done in handleStabSymbolTableEntry.
  340. ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() {
  341. auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
  342. if (!ObjectEntry) {
  343. return errorToErrorCode(ObjectEntry.takeError());
  344. }
  345. auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
  346. if (!Objects) {
  347. return errorToErrorCode(Objects.takeError());
  348. }
  349. std::vector<std::unique_ptr<DebugMap>> Results;
  350. for (const auto *Object : *Objects)
  351. if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
  352. Results.push_back(parseOneBinary(*Object, BinaryPath));
  353. return std::move(Results);
  354. }
  355. /// Interpret the STAB entries to fill the DebugMap.
  356. void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
  357. uint8_t Type,
  358. uint8_t SectionIndex,
  359. uint16_t Flags,
  360. uint64_t Value) {
  361. if (!(Type & MachO::N_STAB))
  362. return;
  363. const char *Name = &MainBinaryStrings.data()[StringIndex];
  364. // An N_OSO entry represents the start of a new object file description.
  365. if (Type == MachO::N_OSO)
  366. return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
  367. if (Type == MachO::N_AST) {
  368. SmallString<80> Path(PathPrefix);
  369. sys::path::append(Path, Name);
  370. Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type);
  371. return;
  372. }
  373. // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be
  374. // null. Do not update anything until we find the next valid N_OSO entry.
  375. if (!CurrentDebugMapObject)
  376. return;
  377. uint32_t Size = 0;
  378. switch (Type) {
  379. case MachO::N_GSYM:
  380. // This is a global variable. We need to query the main binary
  381. // symbol table to find its address as it might not be in the
  382. // debug map (for common symbols).
  383. Value = getMainBinarySymbolAddress(Name);
  384. break;
  385. case MachO::N_FUN:
  386. // Functions are scopes in STABS. They have an end marker that
  387. // contains the function size.
  388. if (Name[0] == '\0') {
  389. Size = Value;
  390. Value = CurrentFunctionAddress;
  391. Name = CurrentFunctionName;
  392. break;
  393. } else {
  394. CurrentFunctionName = Name;
  395. CurrentFunctionAddress = Value;
  396. return;
  397. }
  398. case MachO::N_STSYM:
  399. break;
  400. default:
  401. return;
  402. }
  403. auto ObjectSymIt = CurrentObjectAddresses.find(Name);
  404. // If the name of a (non-static) symbol is not in the current object, we
  405. // check all its aliases from the main binary.
  406. if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) {
  407. if (SeenAliasValues.count(Value) == 0) {
  408. auto Aliases = getMainBinarySymbolNames(Value);
  409. for (const auto &Alias : Aliases) {
  410. auto It = CurrentObjectAddresses.find(Alias);
  411. if (It != CurrentObjectAddresses.end()) {
  412. auto AliasValue = It->getValue();
  413. for (const auto &Alias : Aliases)
  414. CurrentObjectAliasMap[Alias] = AliasValue;
  415. break;
  416. }
  417. }
  418. SeenAliasValues.insert(Value);
  419. }
  420. auto AliasIt = CurrentObjectAliasMap.find(Name);
  421. if (AliasIt != CurrentObjectAliasMap.end())
  422. ObjectSymIt = AliasIt;
  423. }
  424. // ThinLTO adds a unique suffix to exported private symbols.
  425. if (ObjectSymIt == CurrentObjectAddresses.end()) {
  426. for (auto Iter = CurrentObjectAddresses.begin();
  427. Iter != CurrentObjectAddresses.end(); ++Iter) {
  428. llvm::StringRef SymbolName = Iter->getKey();
  429. auto Pos = SymbolName.rfind(".llvm.");
  430. if (Pos != llvm::StringRef::npos && SymbolName.substr(0, Pos) == Name) {
  431. ObjectSymIt = Iter;
  432. break;
  433. }
  434. }
  435. }
  436. if (ObjectSymIt == CurrentObjectAddresses.end()) {
  437. Warning("could not find object file symbol for symbol " + Twine(Name));
  438. return;
  439. }
  440. if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value,
  441. Size)) {
  442. Warning(Twine("failed to insert symbol '") + Name + "' in the debug map.");
  443. return;
  444. }
  445. }
  446. /// Load the current object file symbols into CurrentObjectAddresses.
  447. void MachODebugMapParser::loadCurrentObjectFileSymbols(
  448. const object::MachOObjectFile &Obj) {
  449. CurrentObjectAddresses.clear();
  450. for (auto Sym : Obj.symbols()) {
  451. uint64_t Addr = cantFail(Sym.getValue());
  452. Expected<StringRef> Name = Sym.getName();
  453. if (!Name) {
  454. auto Err = Name.takeError();
  455. Warning("failed to get symbol name: " + toString(std::move(Err)),
  456. Obj.getFileName());
  457. continue;
  458. }
  459. // The value of some categories of symbols isn't meaningful. For
  460. // example common symbols store their size in the value field, not
  461. // their address. Absolute symbols have a fixed address that can
  462. // conflict with standard symbols. These symbols (especially the
  463. // common ones), might still be referenced by relocations. These
  464. // relocations will use the symbol itself, and won't need an
  465. // object file address. The object file address field is optional
  466. // in the DebugMap, leave it unassigned for these symbols.
  467. uint32_t Flags = cantFail(Sym.getFlags());
  468. if (Flags & SymbolRef::SF_Absolute) {
  469. CurrentObjectAddresses[*Name] = std::nullopt;
  470. } else if (Flags & SymbolRef::SF_Common) {
  471. CurrentObjectAddresses[*Name] = std::nullopt;
  472. CommonSymbols.push_back(std::string(*Name));
  473. } else {
  474. CurrentObjectAddresses[*Name] = Addr;
  475. }
  476. }
  477. }
  478. /// Lookup a symbol address in the main binary symbol table. The
  479. /// parser only needs to query common symbols, thus not every symbol's
  480. /// address is available through this function.
  481. uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
  482. auto Sym = MainBinarySymbolAddresses.find(Name);
  483. if (Sym == MainBinarySymbolAddresses.end())
  484. return 0;
  485. return Sym->second;
  486. }
  487. /// Get all symbol names in the main binary for the given value.
  488. std::vector<StringRef>
  489. MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) {
  490. std::vector<StringRef> Names;
  491. for (const auto &Entry : MainBinarySymbolAddresses) {
  492. if (Entry.second == Value)
  493. Names.push_back(Entry.first());
  494. }
  495. return Names;
  496. }
  497. /// Load the interesting main binary symbols' addresses into
  498. /// MainBinarySymbolAddresses.
  499. void MachODebugMapParser::loadMainBinarySymbols(
  500. const MachOObjectFile &MainBinary) {
  501. section_iterator Section = MainBinary.section_end();
  502. MainBinarySymbolAddresses.clear();
  503. for (const auto &Sym : MainBinary.symbols()) {
  504. Expected<SymbolRef::Type> TypeOrErr = Sym.getType();
  505. if (!TypeOrErr) {
  506. auto Err = TypeOrErr.takeError();
  507. Warning("failed to get symbol type: " + toString(std::move(Err)),
  508. MainBinary.getFileName());
  509. continue;
  510. }
  511. SymbolRef::Type Type = *TypeOrErr;
  512. // Skip undefined and STAB entries.
  513. if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown))
  514. continue;
  515. // In theory, the only symbols of interest are the global variables. These
  516. // are the only ones that need to be queried because the address of common
  517. // data won't be described in the debug map. All other addresses should be
  518. // fetched for the debug map. In reality, by playing with 'ld -r' and
  519. // export lists, you can get symbols described as N_GSYM in the debug map,
  520. // but associated with a local symbol. Gather all the symbols, but prefer
  521. // the global ones.
  522. uint8_t SymType =
  523. MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type;
  524. bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT);
  525. Expected<section_iterator> SectionOrErr = Sym.getSection();
  526. if (!SectionOrErr) {
  527. auto Err = TypeOrErr.takeError();
  528. Warning("failed to get symbol section: " + toString(std::move(Err)),
  529. MainBinary.getFileName());
  530. continue;
  531. }
  532. Section = *SectionOrErr;
  533. if ((Section == MainBinary.section_end() || Section->isText()) && !Extern)
  534. continue;
  535. uint64_t Addr = cantFail(Sym.getValue());
  536. Expected<StringRef> NameOrErr = Sym.getName();
  537. if (!NameOrErr) {
  538. auto Err = NameOrErr.takeError();
  539. Warning("failed to get symbol name: " + toString(std::move(Err)),
  540. MainBinary.getFileName());
  541. continue;
  542. }
  543. StringRef Name = *NameOrErr;
  544. if (Name.size() == 0 || Name[0] == '\0')
  545. continue;
  546. // Override only if the new key is global.
  547. if (Extern)
  548. MainBinarySymbolAddresses[Name] = Addr;
  549. else
  550. MainBinarySymbolAddresses.try_emplace(Name, Addr);
  551. }
  552. }
  553. namespace llvm {
  554. namespace dsymutil {
  555. llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
  556. parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
  557. StringRef InputFile, ArrayRef<std::string> Archs,
  558. StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
  559. bool InputIsYAML) {
  560. if (InputIsYAML)
  561. return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
  562. MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath,
  563. PaperTrailWarnings, Verbose);
  564. return Parser.parse();
  565. }
  566. bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
  567. StringRef InputFile, ArrayRef<std::string> Archs,
  568. StringRef PrependPath) {
  569. MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false);
  570. return Parser.dumpStab();
  571. }
  572. } // namespace dsymutil
  573. } // namespace llvm