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 // 243 // The function also tries to find a hole in the address map to fit the __DWARF 244 // segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the 245 // highest segment address. 246 // 247 // When the __LINKEDIT segment is transferred, its offset and size are set resp. 248 // to \a LinkeditOffset and \a LinkeditSize. 249 // 250 // When the eh_frame section is transferred, its offset and size are set resp. 251 // to \a EHFrameOffset and \a EHFrameSize. 252 template <typename SegmentTy> 253 static void transferSegmentAndSections( 254 const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, 255 const object::MachOObjectFile &Obj, MachObjectWriter &Writer, 256 uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset, 257 uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf, 258 uint64_t &EndAddress) { 259 if (StringRef("__DWARF") == Segment.segname) 260 return; 261 262 if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) { 263 Segment.fileoff = EHFrameOffset; 264 Segment.filesize = EHFrameSize; 265 } else if (StringRef("__LINKEDIT") == Segment.segname) { 266 Segment.fileoff = LinkeditOffset; 267 Segment.filesize = LinkeditSize; 268 // Resize vmsize by rounding to the page size. 269 Segment.vmsize = alignTo(LinkeditSize, 0x1000); 270 } else { 271 Segment.fileoff = Segment.filesize = 0; 272 } 273 274 // Check if the end address of the last segment and our current 275 // start address leave a sufficient gap to store the __DWARF 276 // segment. 277 uint64_t PrevEndAddress = EndAddress; 278 EndAddress = alignTo(EndAddress, 0x1000); 279 if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress && 280 Segment.vmaddr - EndAddress >= DwarfSegmentSize) 281 GapForDwarf = EndAddress; 282 283 // The segments are not necessarily sorted by their vmaddr. 284 EndAddress = 285 std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize); 286 unsigned nsects = Segment.nsects; 287 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) 288 MachO::swapStruct(Segment); 289 Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment)); 290 for (unsigned i = 0; i < nsects; ++i) { 291 auto Sect = getSection(Obj, Segment, LCI, i); 292 if (StringRef("__eh_frame") == Sect.sectname) { 293 Sect.offset = EHFrameOffset; 294 Sect.reloff = Sect.nreloc = 0; 295 } else { 296 Sect.offset = Sect.reloff = Sect.nreloc = 0; 297 } 298 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) 299 MachO::swapStruct(Sect); 300 Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect)); 301 } 302 } 303 304 // Write the __DWARF segment load command to the output file. 305 static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset, 306 uint64_t FileSize, unsigned NumSections, 307 MCAsmLayout &Layout, MachObjectWriter &Writer) { 308 Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr, 309 alignTo(FileSize, 0x1000), FileOffset, 310 FileSize, /* MaxProt */ 7, 311 /* InitProt =*/3); 312 313 for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { 314 MCSection *Sec = Layout.getSectionOrder()[i]; 315 if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec)) 316 continue; 317 318 unsigned Align = Sec->getAlignment(); 319 if (Align > 1) { 320 VMAddr = alignTo(VMAddr, Align); 321 FileOffset = alignTo(FileOffset, Align); 322 } 323 Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0); 324 325 FileOffset += Layout.getSectionAddressSize(Sec); 326 VMAddr += Layout.getSectionAddressSize(Sec); 327 } 328 } 329 330 static bool isExecutable(const object::MachOObjectFile &Obj) { 331 if (Obj.is64Bit()) 332 return Obj.getHeader64().filetype != MachO::MH_OBJECT; 333 else 334 return Obj.getHeader().filetype != MachO::MH_OBJECT; 335 } 336 337 static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) { 338 bool HasLinkEditSegment = false; 339 iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) { 340 if (StringRef("__LINKEDIT") == Segment.segname) 341 HasLinkEditSegment = true; 342 }); 343 return HasLinkEditSegment; 344 } 345 346 static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) { 347 if (Is64Bit) 348 return sizeof(MachO::segment_command_64) + 349 NumSections * sizeof(MachO::section_64); 350 351 return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); 352 } 353 354 // Stream a dSYM companion binary file corresponding to the binary referenced 355 // by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to 356 // \a OutFile and it must be using a MachObjectWriter object to do so. 357 bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 358 const DebugMap &DM, SymbolMapTranslator &Translator, 359 MCStreamer &MS, raw_fd_ostream &OutFile) { 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 // Get LC_UUID and LC_BUILD_VERSION. 398 MachO::uuid_command UUIDCmd; 399 SmallVector<MachO::build_version_command, 2> BuildVersionCmd; 400 memset(&UUIDCmd, 0, sizeof(UUIDCmd)); 401 for (auto &LCI : InputBinary.load_commands()) { 402 switch (LCI.C.cmd) { 403 case MachO::LC_UUID: 404 if (UUIDCmd.cmd) 405 return error("Binary contains more than one UUID"); 406 UUIDCmd = InputBinary.getUuidCommand(LCI); 407 ++NumLoadCommands; 408 LoadCommandSize += sizeof(UUIDCmd); 409 break; 410 case MachO::LC_BUILD_VERSION: { 411 MachO::build_version_command Cmd; 412 memset(&Cmd, 0, sizeof(Cmd)); 413 Cmd = InputBinary.getBuildVersionLoadCommand(LCI); 414 ++NumLoadCommands; 415 LoadCommandSize += sizeof(Cmd); 416 // LLDB doesn't care about the build tools for now. 417 Cmd.ntools = 0; 418 BuildVersionCmd.push_back(Cmd); 419 break; 420 } 421 default: 422 break; 423 } 424 } 425 426 // If we have a valid symtab to copy, do it. 427 bool ShouldEmitSymtab = 428 isExecutable(InputBinary) && hasLinkEditSegment(InputBinary); 429 if (ShouldEmitSymtab) { 430 LoadCommandSize += sizeof(MachO::symtab_command); 431 ++NumLoadCommands; 432 } 433 434 // If we have a valid eh_frame to copy, do it. 435 uint64_t EHFrameSize = 0; 436 StringRef EHFrameData; 437 for (const object::SectionRef &Section : InputBinary.sections()) { 438 Expected<StringRef> NameOrErr = Section.getName(); 439 if (!NameOrErr) { 440 consumeError(NameOrErr.takeError()); 441 continue; 442 } 443 StringRef SectionName = *NameOrErr; 444 SectionName = SectionName.substr(SectionName.find_first_not_of("._")); 445 if (SectionName == "eh_frame") { 446 if (Expected<StringRef> ContentsOrErr = Section.getContents()) { 447 EHFrameData = *ContentsOrErr; 448 EHFrameSize = Section.getSize(); 449 } else { 450 consumeError(ContentsOrErr.takeError()); 451 } 452 } 453 } 454 455 unsigned HeaderSize = 456 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 457 // We will copy every segment that isn't __DWARF. 458 iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) { 459 if (StringRef("__DWARF") == Segment.segname) 460 return; 461 462 ++NumLoadCommands; 463 LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects); 464 }); 465 466 // We will add our own brand new __DWARF segment if we have debug 467 // info. 468 unsigned NumDwarfSections = 0; 469 uint64_t DwarfSegmentSize = 0; 470 471 for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { 472 MCSection *Sec = Layout.getSectionOrder()[i]; 473 if (Sec->begin() == Sec->end()) 474 continue; 475 476 if (uint64_t Size = Layout.getSectionFileSize(Sec)) { 477 DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment()); 478 DwarfSegmentSize += Size; 479 ++NumDwarfSections; 480 } 481 } 482 483 if (NumDwarfSections) { 484 ++NumLoadCommands; 485 LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections); 486 } 487 488 SmallString<0> NewSymtab; 489 std::function<StringRef(StringRef)> TranslationLambda = 490 Translator ? [&](StringRef Input) { return Translator(Input); } 491 : static_cast<std::function<StringRef(StringRef)>>(nullptr); 492 // Legacy dsymutil puts an empty string at the start of the line table. 493 // thus we set NonRelocatableStringpool(,PutEmptyString=true) 494 NonRelocatableStringpool NewStrings(TranslationLambda, true); 495 unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); 496 unsigned NumSyms = 0; 497 uint64_t NewStringsSize = 0; 498 if (ShouldEmitSymtab) { 499 NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2); 500 NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings); 501 NewStringsSize = NewStrings.getSize() + 1; 502 } 503 504 uint64_t SymtabStart = LoadCommandSize; 505 SymtabStart += HeaderSize; 506 SymtabStart = alignTo(SymtabStart, 0x1000); 507 508 // We gathered all the information we need, start emitting the output file. 509 Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); 510 511 // Write the load commands. 512 assert(OutFile.tell() == HeaderSize); 513 if (UUIDCmd.cmd != 0) { 514 Writer.W.write<uint32_t>(UUIDCmd.cmd); 515 Writer.W.write<uint32_t>(sizeof(UUIDCmd)); 516 OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16); 517 assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd)); 518 } 519 for (auto Cmd : BuildVersionCmd) { 520 Writer.W.write<uint32_t>(Cmd.cmd); 521 Writer.W.write<uint32_t>(sizeof(Cmd)); 522 Writer.W.write<uint32_t>(Cmd.platform); 523 Writer.W.write<uint32_t>(Cmd.minos); 524 Writer.W.write<uint32_t>(Cmd.sdk); 525 Writer.W.write<uint32_t>(Cmd.ntools); 526 } 527 528 assert(SymtabCmd.cmd && "No symbol table."); 529 uint64_t StringStart = SymtabStart + NumSyms * NListSize; 530 if (ShouldEmitSymtab) 531 Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, 532 NewStringsSize); 533 534 uint64_t EHFrameStart = StringStart + NewStringsSize; 535 EHFrameStart = alignTo(EHFrameStart, 0x1000); 536 537 uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize; 538 DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); 539 540 // Write the load commands for the segments and sections we 'import' from 541 // the original binary. 542 uint64_t EndAddress = 0; 543 uint64_t GapForDwarf = UINT64_MAX; 544 for (auto &LCI : InputBinary.load_commands()) { 545 if (LCI.C.cmd == MachO::LC_SEGMENT) 546 transferSegmentAndSections( 547 LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer, 548 SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, 549 EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); 550 else if (LCI.C.cmd == MachO::LC_SEGMENT_64) 551 transferSegmentAndSections( 552 LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer, 553 SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, 554 EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); 555 } 556 557 uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); 558 uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX; 559 if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax || 560 DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) { 561 // There is no room for the __DWARF segment at the end of the 562 // address space. Look through segments to find a gap. 563 DwarfVMAddr = GapForDwarf; 564 if (DwarfVMAddr == UINT64_MAX) 565 warn("not enough VM space for the __DWARF segment.", 566 "output file streaming"); 567 } 568 569 // Write the load command for the __DWARF segment. 570 createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize, 571 NumDwarfSections, Layout, Writer); 572 573 assert(OutFile.tell() == LoadCommandSize + HeaderSize); 574 OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize)); 575 assert(OutFile.tell() == SymtabStart); 576 577 // Transfer symbols. 578 if (ShouldEmitSymtab) { 579 OutFile << NewSymtab.str(); 580 assert(OutFile.tell() == StringStart); 581 582 // Transfer string table. 583 // FIXME: The NonRelocatableStringpool starts with an empty string, but 584 // dsymutil-classic starts the reconstructed string table with 2 of these. 585 // Reproduce that behavior for now (there is corresponding code in 586 // transferSymbol). 587 OutFile << '\0'; 588 std::vector<DwarfStringPoolEntryRef> Strings = 589 NewStrings.getEntriesForEmission(); 590 for (auto EntryRef : Strings) { 591 OutFile.write(EntryRef.getString().data(), 592 EntryRef.getString().size() + 1); 593 } 594 } 595 assert(OutFile.tell() == StringStart + NewStringsSize); 596 597 // Pad till the EH frame start. 598 OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize)); 599 assert(OutFile.tell() == EHFrameStart); 600 601 // Transfer eh_frame. 602 if (EHFrameSize > 0) 603 OutFile << EHFrameData; 604 assert(OutFile.tell() == EHFrameStart + EHFrameSize); 605 606 // Pad till the Dwarf segment start. 607 OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize)); 608 assert(OutFile.tell() == DwarfSegmentStart); 609 610 // Emit the Dwarf sections contents. 611 for (const MCSection &Sec : MCAsm) { 612 if (Sec.begin() == Sec.end()) 613 continue; 614 615 uint64_t Pos = OutFile.tell(); 616 OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos); 617 MCAsm.writeSectionData(OutFile, &Sec, Layout); 618 } 619 620 return true; 621 } 622 } // namespace MachOUtils 623 } // namespace dsymutil 624 } // namespace llvm 625