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