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