MachOUtils.cpp 23 KB

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