MachODebugMapParser.cpp 22 KB

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