MachOUtils.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. //===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===//
  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 "MachOUtils.h"
  9. #include "BinaryHolder.h"
  10. #include "DebugMap.h"
  11. #include "LinkUtils.h"
  12. #include "llvm/CodeGen/NonRelocatableStringpool.h"
  13. #include "llvm/MC/MCAsmLayout.h"
  14. #include "llvm/MC/MCMachObjectWriter.h"
  15. #include "llvm/MC/MCObjectStreamer.h"
  16. #include "llvm/MC/MCSectionMachO.h"
  17. #include "llvm/MC/MCStreamer.h"
  18. #include "llvm/Object/MachO.h"
  19. #include "llvm/Support/FileUtilities.h"
  20. #include "llvm/Support/Program.h"
  21. #include "llvm/Support/WithColor.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. namespace llvm {
  24. namespace dsymutil {
  25. namespace MachOUtils {
  26. llvm::Error ArchAndFile::createTempFile() {
  27. llvm::SmallString<128> TmpModel;
  28. llvm::sys::path::system_temp_directory(true, TmpModel);
  29. llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
  30. Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel);
  31. if (!T)
  32. return T.takeError();
  33. File = std::make_unique<sys::fs::TempFile>(std::move(*T));
  34. return Error::success();
  35. }
  36. llvm::StringRef ArchAndFile::path() const { return File->TmpName; }
  37. ArchAndFile::~ArchAndFile() {
  38. if (File)
  39. if (auto E = File->discard())
  40. llvm::consumeError(std::move(E));
  41. }
  42. std::string getArchName(StringRef Arch) {
  43. if (Arch.startswith("thumb"))
  44. return (llvm::Twine("arm") + Arch.drop_front(5)).str();
  45. return std::string(Arch);
  46. }
  47. static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
  48. auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath));
  49. if (!Path)
  50. Path = sys::findProgramByName("lipo");
  51. if (!Path) {
  52. WithColor::error() << "lipo: " << Path.getError().message() << "\n";
  53. return false;
  54. }
  55. std::string ErrMsg;
  56. int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg);
  57. if (result) {
  58. WithColor::error() << "lipo: " << ErrMsg << "\n";
  59. return false;
  60. }
  61. return true;
  62. }
  63. bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
  64. StringRef OutputFileName,
  65. const LinkOptions &Options, StringRef SDKPath) {
  66. // No need to merge one file into a universal fat binary.
  67. if (ArchFiles.size() == 1) {
  68. if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
  69. WithColor::error() << "while keeping " << ArchFiles.front().path()
  70. << " as " << OutputFileName << ": "
  71. << toString(std::move(E)) << "\n";
  72. return false;
  73. }
  74. return true;
  75. }
  76. SmallVector<StringRef, 8> Args;
  77. Args.push_back("lipo");
  78. Args.push_back("-create");
  79. for (auto &Thin : ArchFiles)
  80. Args.push_back(Thin.path());
  81. // Align segments to match dsymutil-classic alignment
  82. for (auto &Thin : ArchFiles) {
  83. Thin.Arch = getArchName(Thin.Arch);
  84. Args.push_back("-segalign");
  85. Args.push_back(Thin.Arch);
  86. Args.push_back("20");
  87. }
  88. Args.push_back("-output");
  89. Args.push_back(OutputFileName.data());
  90. if (Options.Verbose) {
  91. outs() << "Running lipo\n";
  92. for (auto Arg : Args)
  93. outs() << ' ' << Arg;
  94. outs() << "\n";
  95. }
  96. return Options.NoOutput ? true : runLipo(SDKPath, Args);
  97. }
  98. // Return a MachO::segment_command_64 that holds the same values as the passed
  99. // MachO::segment_command. We do that to avoid having to duplicate the logic
  100. // for 32bits and 64bits segments.
  101. struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) {
  102. MachO::segment_command_64 Seg64;
  103. Seg64.cmd = Seg.cmd;
  104. Seg64.cmdsize = Seg.cmdsize;
  105. memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname));
  106. Seg64.vmaddr = Seg.vmaddr;
  107. Seg64.vmsize = Seg.vmsize;
  108. Seg64.fileoff = Seg.fileoff;
  109. Seg64.filesize = Seg.filesize;
  110. Seg64.maxprot = Seg.maxprot;
  111. Seg64.initprot = Seg.initprot;
  112. Seg64.nsects = Seg.nsects;
  113. Seg64.flags = Seg.flags;
  114. return Seg64;
  115. }
  116. // Iterate on all \a Obj segments, and apply \a Handler to them.
  117. template <typename FunctionTy>
  118. static void iterateOnSegments(const object::MachOObjectFile &Obj,
  119. FunctionTy Handler) {
  120. for (const auto &LCI : Obj.load_commands()) {
  121. MachO::segment_command_64 Segment;
  122. if (LCI.C.cmd == MachO::LC_SEGMENT)
  123. Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI));
  124. else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
  125. Segment = Obj.getSegment64LoadCommand(LCI);
  126. else
  127. continue;
  128. Handler(Segment);
  129. }
  130. }
  131. // Transfer the symbols described by \a NList to \a NewSymtab which is just the
  132. // raw contents of the symbol table for the dSYM companion file. \returns
  133. // whether the symbol was transferred or not.
  134. template <typename NListTy>
  135. static bool transferSymbol(NListTy NList, bool IsLittleEndian,
  136. StringRef Strings, SmallVectorImpl<char> &NewSymtab,
  137. NonRelocatableStringpool &NewStrings,
  138. bool &InDebugNote) {
  139. // Do not transfer undefined symbols, we want real addresses.
  140. if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF)
  141. return false;
  142. // Do not transfer N_AST symbols as their content is copied into a section of
  143. // the Mach-O companion file.
  144. if (NList.n_type == MachO::N_AST)
  145. return false;
  146. StringRef Name = StringRef(Strings.begin() + NList.n_strx);
  147. // An N_SO with a filename opens a debugging scope and another one without a
  148. // name closes it. Don't transfer anything in the debugging scope.
  149. if (InDebugNote) {
  150. InDebugNote =
  151. (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0');
  152. return false;
  153. } else if (NList.n_type == MachO::N_SO) {
  154. InDebugNote = true;
  155. return false;
  156. }
  157. // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty
  158. // strings at the start of the generated string table (There is
  159. // corresponding code in the string table emission).
  160. NList.n_strx = NewStrings.getStringOffset(Name) + 1;
  161. if (IsLittleEndian != sys::IsLittleEndianHost)
  162. MachO::swapStruct(NList);
  163. NewSymtab.append(reinterpret_cast<char *>(&NList),
  164. reinterpret_cast<char *>(&NList + 1));
  165. return true;
  166. }
  167. // Wrapper around transferSymbol to transfer all of \a Obj symbols
  168. // to \a NewSymtab. This function does not write in the output file.
  169. // \returns the number of symbols in \a NewSymtab.
  170. static unsigned transferSymbols(const object::MachOObjectFile &Obj,
  171. SmallVectorImpl<char> &NewSymtab,
  172. NonRelocatableStringpool &NewStrings) {
  173. unsigned Syms = 0;
  174. StringRef Strings = Obj.getStringTableData();
  175. bool IsLittleEndian = Obj.isLittleEndian();
  176. bool InDebugNote = false;
  177. if (Obj.is64Bit()) {
  178. for (const object::SymbolRef &Symbol : Obj.symbols()) {
  179. object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
  180. if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian,
  181. Strings, NewSymtab, NewStrings, InDebugNote))
  182. ++Syms;
  183. }
  184. } else {
  185. for (const object::SymbolRef &Symbol : Obj.symbols()) {
  186. object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
  187. if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings,
  188. NewSymtab, NewStrings, InDebugNote))
  189. ++Syms;
  190. }
  191. }
  192. return Syms;
  193. }
  194. static MachO::section
  195. getSection(const object::MachOObjectFile &Obj,
  196. const MachO::segment_command &Seg,
  197. const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
  198. return Obj.getSection(LCI, Idx);
  199. }
  200. static MachO::section_64
  201. getSection(const object::MachOObjectFile &Obj,
  202. const MachO::segment_command_64 &Seg,
  203. const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
  204. return Obj.getSection64(LCI, Idx);
  205. }
  206. // Transfer \a Segment from \a Obj to the output file. This calls into \a Writer
  207. // to write these load commands directly in the output file at the current
  208. // position.
  209. //
  210. // The function also tries to find a hole in the address map to fit the __DWARF
  211. // segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the
  212. // highest segment address.
  213. //
  214. // When the __LINKEDIT segment is transferred, its offset and size are set resp.
  215. // to \a LinkeditOffset and \a LinkeditSize.
  216. //
  217. // When the eh_frame section is transferred, its offset and size are set resp.
  218. // to \a EHFrameOffset and \a EHFrameSize.
  219. template <typename SegmentTy>
  220. static void transferSegmentAndSections(
  221. const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,
  222. const object::MachOObjectFile &Obj, MachObjectWriter &Writer,
  223. uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset,
  224. uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf,
  225. uint64_t &EndAddress) {
  226. if (StringRef("__DWARF") == Segment.segname)
  227. return;
  228. if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) {
  229. Segment.fileoff = EHFrameOffset;
  230. Segment.filesize = EHFrameSize;
  231. } else if (StringRef("__LINKEDIT") == Segment.segname) {
  232. Segment.fileoff = LinkeditOffset;
  233. Segment.filesize = LinkeditSize;
  234. // Resize vmsize by rounding to the page size.
  235. Segment.vmsize = alignTo(LinkeditSize, 0x1000);
  236. } else {
  237. Segment.fileoff = Segment.filesize = 0;
  238. }
  239. // Check if the end address of the last segment and our current
  240. // start address leave a sufficient gap to store the __DWARF
  241. // segment.
  242. uint64_t PrevEndAddress = EndAddress;
  243. EndAddress = alignTo(EndAddress, 0x1000);
  244. if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress &&
  245. Segment.vmaddr - EndAddress >= DwarfSegmentSize)
  246. GapForDwarf = EndAddress;
  247. // The segments are not necessarily sorted by their vmaddr.
  248. EndAddress =
  249. std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize);
  250. unsigned nsects = Segment.nsects;
  251. if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
  252. MachO::swapStruct(Segment);
  253. Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment));
  254. for (unsigned i = 0; i < nsects; ++i) {
  255. auto Sect = getSection(Obj, Segment, LCI, i);
  256. if (StringRef("__eh_frame") == Sect.sectname) {
  257. Sect.offset = EHFrameOffset;
  258. Sect.reloff = Sect.nreloc = 0;
  259. } else {
  260. Sect.offset = Sect.reloff = Sect.nreloc = 0;
  261. }
  262. if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
  263. MachO::swapStruct(Sect);
  264. Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect));
  265. }
  266. }
  267. // Write the __DWARF segment load command to the output file.
  268. static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
  269. uint64_t FileSize, unsigned NumSections,
  270. MCAsmLayout &Layout, MachObjectWriter &Writer) {
  271. Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr,
  272. alignTo(FileSize, 0x1000), FileOffset,
  273. FileSize, /* MaxProt */ 7,
  274. /* InitProt =*/3);
  275. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
  276. MCSection *Sec = Layout.getSectionOrder()[i];
  277. if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec))
  278. continue;
  279. unsigned Align = Sec->getAlignment();
  280. if (Align > 1) {
  281. VMAddr = alignTo(VMAddr, Align);
  282. FileOffset = alignTo(FileOffset, Align);
  283. }
  284. Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0);
  285. FileOffset += Layout.getSectionAddressSize(Sec);
  286. VMAddr += Layout.getSectionAddressSize(Sec);
  287. }
  288. }
  289. static bool isExecutable(const object::MachOObjectFile &Obj) {
  290. if (Obj.is64Bit())
  291. return Obj.getHeader64().filetype != MachO::MH_OBJECT;
  292. else
  293. return Obj.getHeader().filetype != MachO::MH_OBJECT;
  294. }
  295. static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) {
  296. bool HasLinkEditSegment = false;
  297. iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) {
  298. if (StringRef("__LINKEDIT") == Segment.segname)
  299. HasLinkEditSegment = true;
  300. });
  301. return HasLinkEditSegment;
  302. }
  303. static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {
  304. if (Is64Bit)
  305. return sizeof(MachO::segment_command_64) +
  306. NumSections * sizeof(MachO::section_64);
  307. return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);
  308. }
  309. // Stream a dSYM companion binary file corresponding to the binary referenced
  310. // by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to
  311. // \a OutFile and it must be using a MachObjectWriter object to do so.
  312. bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
  313. const DebugMap &DM, SymbolMapTranslator &Translator,
  314. MCStreamer &MS, raw_fd_ostream &OutFile) {
  315. auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);
  316. MCAssembler &MCAsm = ObjectStreamer.getAssembler();
  317. auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter());
  318. // Layout but don't emit.
  319. ObjectStreamer.flushPendingLabels();
  320. MCAsmLayout Layout(MCAsm);
  321. MCAsm.layout(Layout);
  322. BinaryHolder InputBinaryHolder(VFS, false);
  323. auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath());
  324. if (!ObjectEntry) {
  325. auto Err = ObjectEntry.takeError();
  326. return error(Twine("opening ") + DM.getBinaryPath() + ": " +
  327. toString(std::move(Err)),
  328. "output file streaming");
  329. }
  330. auto Object =
  331. ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple());
  332. if (!Object) {
  333. auto Err = Object.takeError();
  334. return error(Twine("opening ") + DM.getBinaryPath() + ": " +
  335. toString(std::move(Err)),
  336. "output file streaming");
  337. }
  338. auto &InputBinary = *Object;
  339. bool Is64Bit = Writer.is64Bit();
  340. MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand();
  341. // Compute the number of load commands we will need.
  342. unsigned LoadCommandSize = 0;
  343. unsigned NumLoadCommands = 0;
  344. // Get LC_UUID and LC_BUILD_VERSION.
  345. MachO::uuid_command UUIDCmd;
  346. SmallVector<MachO::build_version_command, 2> BuildVersionCmd;
  347. memset(&UUIDCmd, 0, sizeof(UUIDCmd));
  348. for (auto &LCI : InputBinary.load_commands()) {
  349. switch (LCI.C.cmd) {
  350. case MachO::LC_UUID:
  351. if (UUIDCmd.cmd)
  352. return error("Binary contains more than one UUID");
  353. UUIDCmd = InputBinary.getUuidCommand(LCI);
  354. ++NumLoadCommands;
  355. LoadCommandSize += sizeof(UUIDCmd);
  356. break;
  357. case MachO::LC_BUILD_VERSION: {
  358. MachO::build_version_command Cmd;
  359. memset(&Cmd, 0, sizeof(Cmd));
  360. Cmd = InputBinary.getBuildVersionLoadCommand(LCI);
  361. ++NumLoadCommands;
  362. LoadCommandSize += sizeof(Cmd);
  363. // LLDB doesn't care about the build tools for now.
  364. Cmd.ntools = 0;
  365. BuildVersionCmd.push_back(Cmd);
  366. break;
  367. }
  368. default:
  369. break;
  370. }
  371. }
  372. // If we have a valid symtab to copy, do it.
  373. bool ShouldEmitSymtab =
  374. isExecutable(InputBinary) && hasLinkEditSegment(InputBinary);
  375. if (ShouldEmitSymtab) {
  376. LoadCommandSize += sizeof(MachO::symtab_command);
  377. ++NumLoadCommands;
  378. }
  379. // If we have a valid eh_frame to copy, do it.
  380. uint64_t EHFrameSize = 0;
  381. StringRef EHFrameData;
  382. for (const object::SectionRef &Section : InputBinary.sections()) {
  383. Expected<StringRef> NameOrErr = Section.getName();
  384. if (!NameOrErr) {
  385. consumeError(NameOrErr.takeError());
  386. continue;
  387. }
  388. StringRef SectionName = *NameOrErr;
  389. SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
  390. if (SectionName == "eh_frame") {
  391. if (Expected<StringRef> ContentsOrErr = Section.getContents()) {
  392. EHFrameData = *ContentsOrErr;
  393. EHFrameSize = Section.getSize();
  394. } else {
  395. consumeError(ContentsOrErr.takeError());
  396. }
  397. }
  398. }
  399. unsigned HeaderSize =
  400. Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
  401. // We will copy every segment that isn't __DWARF.
  402. iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) {
  403. if (StringRef("__DWARF") == Segment.segname)
  404. return;
  405. ++NumLoadCommands;
  406. LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects);
  407. });
  408. // We will add our own brand new __DWARF segment if we have debug
  409. // info.
  410. unsigned NumDwarfSections = 0;
  411. uint64_t DwarfSegmentSize = 0;
  412. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
  413. MCSection *Sec = Layout.getSectionOrder()[i];
  414. if (Sec->begin() == Sec->end())
  415. continue;
  416. if (uint64_t Size = Layout.getSectionFileSize(Sec)) {
  417. DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment());
  418. DwarfSegmentSize += Size;
  419. ++NumDwarfSections;
  420. }
  421. }
  422. if (NumDwarfSections) {
  423. ++NumLoadCommands;
  424. LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections);
  425. }
  426. SmallString<0> NewSymtab;
  427. std::function<StringRef(StringRef)> TranslationLambda =
  428. Translator ? [&](StringRef Input) { return Translator(Input); }
  429. : static_cast<std::function<StringRef(StringRef)>>(nullptr);
  430. // Legacy dsymutil puts an empty string at the start of the line table.
  431. // thus we set NonRelocatableStringpool(,PutEmptyString=true)
  432. NonRelocatableStringpool NewStrings(TranslationLambda, true);
  433. unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
  434. unsigned NumSyms = 0;
  435. uint64_t NewStringsSize = 0;
  436. if (ShouldEmitSymtab) {
  437. NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2);
  438. NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings);
  439. NewStringsSize = NewStrings.getSize() + 1;
  440. }
  441. uint64_t SymtabStart = LoadCommandSize;
  442. SymtabStart += HeaderSize;
  443. SymtabStart = alignTo(SymtabStart, 0x1000);
  444. // We gathered all the information we need, start emitting the output file.
  445. Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false);
  446. // Write the load commands.
  447. assert(OutFile.tell() == HeaderSize);
  448. if (UUIDCmd.cmd != 0) {
  449. Writer.W.write<uint32_t>(UUIDCmd.cmd);
  450. Writer.W.write<uint32_t>(sizeof(UUIDCmd));
  451. OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16);
  452. assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd));
  453. }
  454. for (auto Cmd : BuildVersionCmd) {
  455. Writer.W.write<uint32_t>(Cmd.cmd);
  456. Writer.W.write<uint32_t>(sizeof(Cmd));
  457. Writer.W.write<uint32_t>(Cmd.platform);
  458. Writer.W.write<uint32_t>(Cmd.minos);
  459. Writer.W.write<uint32_t>(Cmd.sdk);
  460. Writer.W.write<uint32_t>(Cmd.ntools);
  461. }
  462. assert(SymtabCmd.cmd && "No symbol table.");
  463. uint64_t StringStart = SymtabStart + NumSyms * NListSize;
  464. if (ShouldEmitSymtab)
  465. Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart,
  466. NewStringsSize);
  467. uint64_t EHFrameStart = StringStart + NewStringsSize;
  468. EHFrameStart = alignTo(EHFrameStart, 0x1000);
  469. uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize;
  470. DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);
  471. // Write the load commands for the segments and sections we 'import' from
  472. // the original binary.
  473. uint64_t EndAddress = 0;
  474. uint64_t GapForDwarf = UINT64_MAX;
  475. for (auto &LCI : InputBinary.load_commands()) {
  476. if (LCI.C.cmd == MachO::LC_SEGMENT)
  477. transferSegmentAndSections(
  478. LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer,
  479. SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
  480. EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
  481. else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
  482. transferSegmentAndSections(
  483. LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer,
  484. SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
  485. EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
  486. }
  487. uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);
  488. uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX;
  489. if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax ||
  490. DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) {
  491. // There is no room for the __DWARF segment at the end of the
  492. // address space. Look through segments to find a gap.
  493. DwarfVMAddr = GapForDwarf;
  494. if (DwarfVMAddr == UINT64_MAX)
  495. warn("not enough VM space for the __DWARF segment.",
  496. "output file streaming");
  497. }
  498. // Write the load command for the __DWARF segment.
  499. createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,
  500. NumDwarfSections, Layout, Writer);
  501. assert(OutFile.tell() == LoadCommandSize + HeaderSize);
  502. OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize));
  503. assert(OutFile.tell() == SymtabStart);
  504. // Transfer symbols.
  505. if (ShouldEmitSymtab) {
  506. OutFile << NewSymtab.str();
  507. assert(OutFile.tell() == StringStart);
  508. // Transfer string table.
  509. // FIXME: The NonRelocatableStringpool starts with an empty string, but
  510. // dsymutil-classic starts the reconstructed string table with 2 of these.
  511. // Reproduce that behavior for now (there is corresponding code in
  512. // transferSymbol).
  513. OutFile << '\0';
  514. std::vector<DwarfStringPoolEntryRef> Strings =
  515. NewStrings.getEntriesForEmission();
  516. for (auto EntryRef : Strings) {
  517. OutFile.write(EntryRef.getString().data(),
  518. EntryRef.getString().size() + 1);
  519. }
  520. }
  521. assert(OutFile.tell() == StringStart + NewStringsSize);
  522. // Pad till the EH frame start.
  523. OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize));
  524. assert(OutFile.tell() == EHFrameStart);
  525. // Transfer eh_frame.
  526. if (EHFrameSize > 0)
  527. OutFile << EHFrameData;
  528. assert(OutFile.tell() == EHFrameStart + EHFrameSize);
  529. // Pad till the Dwarf segment start.
  530. OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize));
  531. assert(OutFile.tell() == DwarfSegmentStart);
  532. // Emit the Dwarf sections contents.
  533. for (const MCSection &Sec : MCAsm) {
  534. if (Sec.begin() == Sec.end())
  535. continue;
  536. uint64_t Pos = OutFile.tell();
  537. OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos);
  538. MCAsm.writeSectionData(OutFile, &Sec, Layout);
  539. }
  540. return true;
  541. }
  542. } // namespace MachOUtils
  543. } // namespace dsymutil
  544. } // namespace llvm