dsymutil.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. //===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===//
  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. // This program is a utility that aims to be a dropin replacement for Darwin's
  10. // dsymutil.
  11. //===----------------------------------------------------------------------===//
  12. #include "dsymutil.h"
  13. #include "BinaryHolder.h"
  14. #include "CFBundle.h"
  15. #include "DebugMap.h"
  16. #include "LinkUtils.h"
  17. #include "MachOUtils.h"
  18. #include "Reproducer.h"
  19. #include "llvm/ADT/STLExtras.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/ADT/StringExtras.h"
  23. #include "llvm/ADT/StringRef.h"
  24. #include "llvm/ADT/Triple.h"
  25. #include "llvm/DebugInfo/DIContext.h"
  26. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  27. #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
  28. #include "llvm/Object/Binary.h"
  29. #include "llvm/Object/MachO.h"
  30. #include "llvm/Option/Arg.h"
  31. #include "llvm/Option/ArgList.h"
  32. #include "llvm/Option/Option.h"
  33. #include "llvm/Support/CommandLine.h"
  34. #include "llvm/Support/FileCollector.h"
  35. #include "llvm/Support/FileSystem.h"
  36. #include "llvm/Support/InitLLVM.h"
  37. #include "llvm/Support/ManagedStatic.h"
  38. #include "llvm/Support/Path.h"
  39. #include "llvm/Support/TargetSelect.h"
  40. #include "llvm/Support/ThreadPool.h"
  41. #include "llvm/Support/WithColor.h"
  42. #include "llvm/Support/raw_ostream.h"
  43. #include "llvm/Support/thread.h"
  44. #include <algorithm>
  45. #include <cstdint>
  46. #include <cstdlib>
  47. #include <string>
  48. #include <system_error>
  49. using namespace llvm;
  50. using namespace llvm::dsymutil;
  51. using namespace object;
  52. namespace {
  53. enum ID {
  54. OPT_INVALID = 0, // This is not an option ID.
  55. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  56. HELPTEXT, METAVAR, VALUES) \
  57. OPT_##ID,
  58. #include "Options.inc"
  59. #undef OPTION
  60. };
  61. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
  62. #include "Options.inc"
  63. #undef PREFIX
  64. const opt::OptTable::Info InfoTable[] = {
  65. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  66. HELPTEXT, METAVAR, VALUES) \
  67. { \
  68. PREFIX, NAME, HELPTEXT, \
  69. METAVAR, OPT_##ID, opt::Option::KIND##Class, \
  70. PARAM, FLAGS, OPT_##GROUP, \
  71. OPT_##ALIAS, ALIASARGS, VALUES},
  72. #include "Options.inc"
  73. #undef OPTION
  74. };
  75. class DsymutilOptTable : public opt::OptTable {
  76. public:
  77. DsymutilOptTable() : OptTable(InfoTable) {}
  78. };
  79. } // namespace
  80. struct DsymutilOptions {
  81. bool DumpDebugMap = false;
  82. bool DumpStab = false;
  83. bool Flat = false;
  84. bool InputIsYAMLDebugMap = false;
  85. bool PaperTrailWarnings = false;
  86. bool Verify = false;
  87. bool ForceKeepFunctionForStatic = false;
  88. std::string SymbolMap;
  89. std::string OutputFile;
  90. std::string Toolchain;
  91. std::string ReproducerPath;
  92. std::vector<std::string> Archs;
  93. std::vector<std::string> InputFiles;
  94. unsigned NumThreads;
  95. ReproducerMode ReproMode = ReproducerMode::Off;
  96. dsymutil::LinkOptions LinkOpts;
  97. };
  98. /// Return a list of input files. This function has logic for dealing with the
  99. /// special case where we might have dSYM bundles as input. The function
  100. /// returns an error when the directory structure doesn't match that of a dSYM
  101. /// bundle.
  102. static Expected<std::vector<std::string>> getInputs(opt::InputArgList &Args,
  103. bool DsymAsInput) {
  104. std::vector<std::string> InputFiles;
  105. for (auto *File : Args.filtered(OPT_INPUT))
  106. InputFiles.push_back(File->getValue());
  107. if (!DsymAsInput)
  108. return InputFiles;
  109. // If we are updating, we might get dSYM bundles as input.
  110. std::vector<std::string> Inputs;
  111. for (const auto &Input : InputFiles) {
  112. if (!sys::fs::is_directory(Input)) {
  113. Inputs.push_back(Input);
  114. continue;
  115. }
  116. // Make sure that we're dealing with a dSYM bundle.
  117. SmallString<256> BundlePath(Input);
  118. sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
  119. if (!sys::fs::is_directory(BundlePath))
  120. return make_error<StringError>(
  121. Input + " is a directory, but doesn't look like a dSYM bundle.",
  122. inconvertibleErrorCode());
  123. // Create a directory iterator to iterate over all the entries in the
  124. // bundle.
  125. std::error_code EC;
  126. sys::fs::directory_iterator DirIt(BundlePath, EC);
  127. sys::fs::directory_iterator DirEnd;
  128. if (EC)
  129. return errorCodeToError(EC);
  130. // Add each entry to the list of inputs.
  131. while (DirIt != DirEnd) {
  132. Inputs.push_back(DirIt->path());
  133. DirIt.increment(EC);
  134. if (EC)
  135. return errorCodeToError(EC);
  136. }
  137. }
  138. return Inputs;
  139. }
  140. // Verify that the given combination of options makes sense.
  141. static Error verifyOptions(const DsymutilOptions &Options) {
  142. if (Options.InputFiles.empty()) {
  143. return make_error<StringError>("no input files specified",
  144. errc::invalid_argument);
  145. }
  146. if (Options.LinkOpts.Update && llvm::is_contained(Options.InputFiles, "-")) {
  147. // FIXME: We cannot use stdin for an update because stdin will be
  148. // consumed by the BinaryHolder during the debugmap parsing, and
  149. // then we will want to consume it again in DwarfLinker. If we
  150. // used a unique BinaryHolder object that could cache multiple
  151. // binaries this restriction would go away.
  152. return make_error<StringError>(
  153. "standard input cannot be used as input for a dSYM update.",
  154. errc::invalid_argument);
  155. }
  156. if (!Options.Flat && Options.OutputFile == "-")
  157. return make_error<StringError>(
  158. "cannot emit to standard output without --flat.",
  159. errc::invalid_argument);
  160. if (Options.InputFiles.size() > 1 && Options.Flat &&
  161. !Options.OutputFile.empty())
  162. return make_error<StringError>(
  163. "cannot use -o with multiple inputs in flat mode.",
  164. errc::invalid_argument);
  165. if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap)
  166. return make_error<StringError>(
  167. "paper trail warnings are not supported for YAML input.",
  168. errc::invalid_argument);
  169. if (!Options.ReproducerPath.empty() &&
  170. Options.ReproMode != ReproducerMode::Use)
  171. return make_error<StringError>(
  172. "cannot combine --gen-reproducer and --use-reproducer.",
  173. errc::invalid_argument);
  174. return Error::success();
  175. }
  176. static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) {
  177. if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) {
  178. StringRef S = Accelerator->getValue();
  179. if (S == "Apple")
  180. return AccelTableKind::Apple;
  181. if (S == "Dwarf")
  182. return AccelTableKind::Dwarf;
  183. if (S == "Pub")
  184. return AccelTableKind::Pub;
  185. if (S == "Default")
  186. return AccelTableKind::Default;
  187. return make_error<StringError>(
  188. "invalid accelerator type specified: '" + S +
  189. "'. Support values are 'Apple', 'Dwarf', 'Pub' and 'Default'.",
  190. inconvertibleErrorCode());
  191. }
  192. return AccelTableKind::Default;
  193. }
  194. /// Parses the command line options into the LinkOptions struct and performs
  195. /// some sanity checking. Returns an error in case the latter fails.
  196. static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
  197. DsymutilOptions Options;
  198. Options.DumpDebugMap = Args.hasArg(OPT_dump_debug_map);
  199. Options.DumpStab = Args.hasArg(OPT_symtab);
  200. Options.Flat = Args.hasArg(OPT_flat);
  201. Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input);
  202. Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail);
  203. Options.Verify = Args.hasArg(OPT_verify);
  204. Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr);
  205. Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output);
  206. Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
  207. Options.LinkOpts.Update = Args.hasArg(OPT_update);
  208. Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
  209. Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
  210. Options.LinkOpts.KeepFunctionForStatic =
  211. Args.hasArg(OPT_keep_func_for_static);
  212. if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) {
  213. Options.ReproMode = ReproducerMode::Use;
  214. Options.ReproducerPath = ReproducerPath->getValue();
  215. }
  216. if (Args.hasArg(OPT_gen_reproducer))
  217. Options.ReproMode = ReproducerMode::Generate;
  218. if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) {
  219. Options.LinkOpts.TheAccelTableKind = *AccelKind;
  220. } else {
  221. return AccelKind.takeError();
  222. }
  223. if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
  224. Options.SymbolMap = SymbolMap->getValue();
  225. if (Args.hasArg(OPT_symbolmap))
  226. Options.LinkOpts.Update = true;
  227. if (Expected<std::vector<std::string>> InputFiles =
  228. getInputs(Args, Options.LinkOpts.Update)) {
  229. Options.InputFiles = std::move(*InputFiles);
  230. } else {
  231. return InputFiles.takeError();
  232. }
  233. for (auto *Arch : Args.filtered(OPT_arch))
  234. Options.Archs.push_back(Arch->getValue());
  235. if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path))
  236. Options.LinkOpts.PrependPath = OsoPrependPath->getValue();
  237. for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) {
  238. auto Split = StringRef(Arg).split('=');
  239. Options.LinkOpts.ObjectPrefixMap.insert(
  240. {std::string(Split.first), std::string(Split.second)});
  241. }
  242. if (opt::Arg *OutputFile = Args.getLastArg(OPT_output))
  243. Options.OutputFile = OutputFile->getValue();
  244. if (opt::Arg *Toolchain = Args.getLastArg(OPT_toolchain))
  245. Options.Toolchain = Toolchain->getValue();
  246. if (Args.hasArg(OPT_assembly))
  247. Options.LinkOpts.FileType = OutputFileType::Assembly;
  248. if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
  249. Options.LinkOpts.Threads = atoi(NumThreads->getValue());
  250. else
  251. Options.LinkOpts.Threads = 0; // Use all available hardware threads
  252. if (Options.DumpDebugMap || Options.LinkOpts.Verbose)
  253. Options.LinkOpts.Threads = 1;
  254. if (getenv("RC_DEBUG_OPTIONS"))
  255. Options.PaperTrailWarnings = true;
  256. if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path))
  257. Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue();
  258. if (opt::Arg *RemarksOutputFormat =
  259. Args.getLastArg(OPT_remarks_output_format)) {
  260. if (Expected<remarks::Format> FormatOrErr =
  261. remarks::parseFormat(RemarksOutputFormat->getValue()))
  262. Options.LinkOpts.RemarksFormat = *FormatOrErr;
  263. else
  264. return FormatOrErr.takeError();
  265. }
  266. if (Error E = verifyOptions(Options))
  267. return std::move(E);
  268. return Options;
  269. }
  270. static Error createPlistFile(StringRef Bin, StringRef BundleRoot,
  271. StringRef Toolchain) {
  272. // Create plist file to write to.
  273. SmallString<128> InfoPlist(BundleRoot);
  274. sys::path::append(InfoPlist, "Contents/Info.plist");
  275. std::error_code EC;
  276. raw_fd_ostream PL(InfoPlist, EC, sys::fs::OF_TextWithCRLF);
  277. if (EC)
  278. return make_error<StringError>(
  279. "cannot create Plist: " + toString(errorCodeToError(EC)), EC);
  280. CFBundleInfo BI = getBundleInfo(Bin);
  281. if (BI.IDStr.empty()) {
  282. StringRef BundleID = *sys::path::rbegin(BundleRoot);
  283. if (sys::path::extension(BundleRoot) == ".dSYM")
  284. BI.IDStr = std::string(sys::path::stem(BundleID));
  285. else
  286. BI.IDStr = std::string(BundleID);
  287. }
  288. // Print out information to the plist file.
  289. PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n"
  290. << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
  291. << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
  292. << "<plist version=\"1.0\">\n"
  293. << "\t<dict>\n"
  294. << "\t\t<key>CFBundleDevelopmentRegion</key>\n"
  295. << "\t\t<string>English</string>\n"
  296. << "\t\t<key>CFBundleIdentifier</key>\n"
  297. << "\t\t<string>com.apple.xcode.dsym.";
  298. printHTMLEscaped(BI.IDStr, PL);
  299. PL << "</string>\n"
  300. << "\t\t<key>CFBundleInfoDictionaryVersion</key>\n"
  301. << "\t\t<string>6.0</string>\n"
  302. << "\t\t<key>CFBundlePackageType</key>\n"
  303. << "\t\t<string>dSYM</string>\n"
  304. << "\t\t<key>CFBundleSignature</key>\n"
  305. << "\t\t<string>\?\?\?\?</string>\n";
  306. if (!BI.OmitShortVersion()) {
  307. PL << "\t\t<key>CFBundleShortVersionString</key>\n";
  308. PL << "\t\t<string>";
  309. printHTMLEscaped(BI.ShortVersionStr, PL);
  310. PL << "</string>\n";
  311. }
  312. PL << "\t\t<key>CFBundleVersion</key>\n";
  313. PL << "\t\t<string>";
  314. printHTMLEscaped(BI.VersionStr, PL);
  315. PL << "</string>\n";
  316. if (!Toolchain.empty()) {
  317. PL << "\t\t<key>Toolchain</key>\n";
  318. PL << "\t\t<string>";
  319. printHTMLEscaped(Toolchain, PL);
  320. PL << "</string>\n";
  321. }
  322. PL << "\t</dict>\n"
  323. << "</plist>\n";
  324. PL.close();
  325. return Error::success();
  326. }
  327. static Error createBundleDir(StringRef BundleBase) {
  328. SmallString<128> Bundle(BundleBase);
  329. sys::path::append(Bundle, "Contents", "Resources", "DWARF");
  330. if (std::error_code EC =
  331. create_directories(Bundle.str(), true, sys::fs::perms::all_all))
  332. return make_error<StringError>(
  333. "cannot create bundle: " + toString(errorCodeToError(EC)), EC);
  334. return Error::success();
  335. }
  336. static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
  337. if (OutputFile == "-") {
  338. WithColor::warning() << "verification skipped for " << Arch
  339. << "because writing to stdout.\n";
  340. return true;
  341. }
  342. Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile);
  343. if (!BinOrErr) {
  344. WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError());
  345. return false;
  346. }
  347. Binary &Binary = *BinOrErr.get().getBinary();
  348. if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) {
  349. raw_ostream &os = Verbose ? errs() : nulls();
  350. os << "Verifying DWARF for architecture: " << Arch << "\n";
  351. std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
  352. DIDumpOptions DumpOpts;
  353. bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
  354. if (!success)
  355. WithColor::error() << "verification failed for " << Arch << '\n';
  356. return success;
  357. }
  358. return false;
  359. }
  360. namespace {
  361. struct OutputLocation {
  362. OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {})
  363. : DWARFFile(DWARFFile), ResourceDir(ResourceDir) {}
  364. /// This method is a workaround for older compilers.
  365. Optional<std::string> getResourceDir() const { return ResourceDir; }
  366. std::string DWARFFile;
  367. Optional<std::string> ResourceDir;
  368. };
  369. } // namespace
  370. static Expected<OutputLocation>
  371. getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) {
  372. if (Options.OutputFile == "-")
  373. return OutputLocation(Options.OutputFile);
  374. // When updating, do in place replacement.
  375. if (Options.OutputFile.empty() &&
  376. (Options.LinkOpts.Update || !Options.SymbolMap.empty()))
  377. return OutputLocation(std::string(InputFile));
  378. // When dumping the debug map, just return an empty output location. This
  379. // allows us to compute the output location once.
  380. if (Options.DumpDebugMap)
  381. return OutputLocation("");
  382. // If a flat dSYM has been requested, things are pretty simple.
  383. if (Options.Flat) {
  384. if (Options.OutputFile.empty()) {
  385. if (InputFile == "-")
  386. return OutputLocation{"a.out.dwarf", {}};
  387. return OutputLocation((InputFile + ".dwarf").str());
  388. }
  389. return OutputLocation(Options.OutputFile);
  390. }
  391. // We need to create/update a dSYM bundle.
  392. // A bundle hierarchy looks like this:
  393. // <bundle name>.dSYM/
  394. // Contents/
  395. // Info.plist
  396. // Resources/
  397. // DWARF/
  398. // <DWARF file(s)>
  399. std::string DwarfFile =
  400. std::string(InputFile == "-" ? StringRef("a.out") : InputFile);
  401. SmallString<128> Path(Options.OutputFile);
  402. if (Path.empty())
  403. Path = DwarfFile + ".dSYM";
  404. if (!Options.LinkOpts.NoOutput) {
  405. if (auto E = createBundleDir(Path))
  406. return std::move(E);
  407. if (auto E = createPlistFile(DwarfFile, Path, Options.Toolchain))
  408. return std::move(E);
  409. }
  410. sys::path::append(Path, "Contents", "Resources");
  411. std::string ResourceDir = std::string(Path.str());
  412. sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile));
  413. return OutputLocation(std::string(Path.str()), ResourceDir);
  414. }
  415. int main(int argc, char **argv) {
  416. InitLLVM X(argc, argv);
  417. // Parse arguments.
  418. DsymutilOptTable T;
  419. unsigned MAI;
  420. unsigned MAC;
  421. ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1);
  422. opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
  423. void *P = (void *)(intptr_t)getOutputFileName;
  424. std::string SDKPath = sys::fs::getMainExecutable(argv[0], P);
  425. SDKPath = std::string(sys::path::parent_path(SDKPath));
  426. for (auto *Arg : Args.filtered(OPT_UNKNOWN)) {
  427. WithColor::warning() << "ignoring unknown option: " << Arg->getSpelling()
  428. << '\n';
  429. }
  430. if (Args.hasArg(OPT_help)) {
  431. T.printHelp(
  432. outs(), (std::string(argv[0]) + " [options] <input files>").c_str(),
  433. "manipulate archived DWARF debug symbol files.\n\n"
  434. "dsymutil links the DWARF debug information found in the object files\n"
  435. "for the executable <input file> by using debug symbols information\n"
  436. "contained in its symbol table.\n",
  437. false);
  438. return EXIT_SUCCESS;
  439. }
  440. if (Args.hasArg(OPT_version)) {
  441. cl::PrintVersionMessage();
  442. return EXIT_SUCCESS;
  443. }
  444. auto OptionsOrErr = getOptions(Args);
  445. if (!OptionsOrErr) {
  446. WithColor::error() << toString(OptionsOrErr.takeError());
  447. return EXIT_FAILURE;
  448. }
  449. auto &Options = *OptionsOrErr;
  450. InitializeAllTargetInfos();
  451. InitializeAllTargetMCs();
  452. InitializeAllTargets();
  453. InitializeAllAsmPrinters();
  454. auto Repro =
  455. Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath);
  456. if (!Repro) {
  457. WithColor::error() << toString(Repro.takeError());
  458. return EXIT_FAILURE;
  459. }
  460. Options.LinkOpts.VFS = (*Repro)->getVFS();
  461. for (const auto &Arch : Options.Archs)
  462. if (Arch != "*" && Arch != "all" &&
  463. !object::MachOObjectFile::isValidArch(Arch)) {
  464. WithColor::error() << "unsupported cpu architecture: '" << Arch << "'\n";
  465. return EXIT_FAILURE;
  466. }
  467. SymbolMapLoader SymMapLoader(Options.SymbolMap);
  468. for (auto &InputFile : Options.InputFiles) {
  469. // Dump the symbol table for each input file and requested arch
  470. if (Options.DumpStab) {
  471. if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs,
  472. Options.LinkOpts.PrependPath))
  473. return EXIT_FAILURE;
  474. continue;
  475. }
  476. auto DebugMapPtrsOrErr =
  477. parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs,
  478. Options.LinkOpts.PrependPath, Options.PaperTrailWarnings,
  479. Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
  480. if (auto EC = DebugMapPtrsOrErr.getError()) {
  481. WithColor::error() << "cannot parse the debug map for '" << InputFile
  482. << "': " << EC.message() << '\n';
  483. return EXIT_FAILURE;
  484. }
  485. // Remember the number of debug maps that are being processed to decide how
  486. // to name the remark files.
  487. Options.LinkOpts.NumDebugMaps = DebugMapPtrsOrErr->size();
  488. if (Options.LinkOpts.Update) {
  489. // The debug map should be empty. Add one object file corresponding to
  490. // the input file.
  491. for (auto &Map : *DebugMapPtrsOrErr)
  492. Map->addDebugMapObject(InputFile,
  493. sys::TimePoint<std::chrono::seconds>());
  494. }
  495. // Ensure that the debug map is not empty (anymore).
  496. if (DebugMapPtrsOrErr->empty()) {
  497. WithColor::error() << "no architecture to link\n";
  498. return EXIT_FAILURE;
  499. }
  500. // Shared a single binary holder for all the link steps.
  501. BinaryHolder BinHolder(Options.LinkOpts.VFS);
  502. // Compute the output location and update the resource directory.
  503. Expected<OutputLocation> OutputLocationOrErr =
  504. getOutputFileName(InputFile, Options);
  505. if (!OutputLocationOrErr) {
  506. WithColor::error() << toString(OutputLocationOrErr.takeError());
  507. return EXIT_FAILURE;
  508. }
  509. Options.LinkOpts.ResourceDir = OutputLocationOrErr->getResourceDir();
  510. // Statistics only require different architectures to be processed
  511. // sequentially, the link itself can still happen in parallel. Change the
  512. // thread pool strategy here instead of modifying LinkOpts.Threads.
  513. ThreadPoolStrategy S = hardware_concurrency(
  514. Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads);
  515. if (Options.LinkOpts.Threads == 0) {
  516. // If NumThreads is not specified, create one thread for each input, up to
  517. // the number of hardware threads.
  518. S.ThreadsRequested = DebugMapPtrsOrErr->size();
  519. S.Limit = true;
  520. }
  521. ThreadPool Threads(S);
  522. // If there is more than one link to execute, we need to generate
  523. // temporary files.
  524. const bool NeedsTempFiles =
  525. !Options.DumpDebugMap && (Options.OutputFile != "-") &&
  526. (DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update);
  527. const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput;
  528. SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
  529. std::atomic_char AllOK(1);
  530. for (auto &Map : *DebugMapPtrsOrErr) {
  531. if (Options.LinkOpts.Verbose || Options.DumpDebugMap)
  532. Map->print(outs());
  533. if (Options.DumpDebugMap)
  534. continue;
  535. if (!Options.SymbolMap.empty())
  536. Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map);
  537. if (Map->begin() == Map->end())
  538. WithColor::warning()
  539. << "no debug symbols in executable (-arch "
  540. << MachOUtils::getArchName(Map->getTriple().getArchName()) << ")\n";
  541. // Using a std::shared_ptr rather than std::unique_ptr because move-only
  542. // types don't work with std::bind in the ThreadPool implementation.
  543. std::shared_ptr<raw_fd_ostream> OS;
  544. std::string OutputFile = OutputLocationOrErr->DWARFFile;
  545. if (NeedsTempFiles) {
  546. TempFiles.emplace_back(Map->getTriple().getArchName().str());
  547. auto E = TempFiles.back().createTempFile();
  548. if (E) {
  549. WithColor::error() << toString(std::move(E));
  550. return EXIT_FAILURE;
  551. }
  552. auto &TempFile = *(TempFiles.back().File);
  553. OS = std::make_shared<raw_fd_ostream>(TempFile.FD,
  554. /*shouldClose*/ false);
  555. OutputFile = TempFile.TmpName;
  556. } else {
  557. std::error_code EC;
  558. OS = std::make_shared<raw_fd_ostream>(
  559. Options.LinkOpts.NoOutput ? "-" : OutputFile, EC, sys::fs::OF_None);
  560. if (EC) {
  561. WithColor::error() << OutputFile << ": " << EC.message();
  562. return EXIT_FAILURE;
  563. }
  564. }
  565. auto LinkLambda = [&, OutputFile](std::shared_ptr<raw_fd_ostream> Stream,
  566. LinkOptions Options) {
  567. AllOK.fetch_and(
  568. linkDwarf(*Stream, BinHolder, *Map, std::move(Options)));
  569. Stream->flush();
  570. if (Verify)
  571. AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(),
  572. Options.Verbose));
  573. };
  574. // FIXME: The DwarfLinker can have some very deep recursion that can max
  575. // out the (significantly smaller) stack when using threads. We don't
  576. // want this limitation when we only have a single thread.
  577. if (S.ThreadsRequested == 1)
  578. LinkLambda(OS, Options.LinkOpts);
  579. else
  580. Threads.async(LinkLambda, OS, Options.LinkOpts);
  581. }
  582. Threads.wait();
  583. if (!AllOK)
  584. return EXIT_FAILURE;
  585. if (NeedsTempFiles) {
  586. if (!MachOUtils::generateUniversalBinary(TempFiles,
  587. OutputLocationOrErr->DWARFFile,
  588. Options.LinkOpts, SDKPath))
  589. return EXIT_FAILURE;
  590. }
  591. // The Mach-O object file format is limited to 4GB. Make sure that we print
  592. // an error when we emit an invalid Mach-O companion file. Leave the
  593. // invalid object file around on disk for inspection.
  594. ErrorOr<vfs::Status> stat =
  595. Options.LinkOpts.VFS->status(OutputLocationOrErr->DWARFFile);
  596. if (stat) {
  597. if (stat->getSize() > std::numeric_limits<uint32_t>::max()) {
  598. WithColor::error() << "the linked debug info exceeds the 4GB Mach-O "
  599. "object file format.";
  600. return EXIT_FAILURE;
  601. }
  602. }
  603. }
  604. return EXIT_SUCCESS;
  605. }