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