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 "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 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 StringRef Name = StringRef(Strings.begin() + NList.n_strx); 167 if (InDebugNote) { 168 InDebugNote = 169 (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0'); 170 return false; 171 } else if (NList.n_type == MachO::N_SO) { 172 InDebugNote = true; 173 return false; 174 } 175 176 // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty 177 // strings at the start of the generated string table (There is 178 // corresponding code in the string table emission). 179 NList.n_strx = NewStrings.getStringOffset(Name) + 1; 180 if (IsLittleEndian != sys::IsLittleEndianHost) 181 MachO::swapStruct(NList); 182 183 NewSymtab.append(reinterpret_cast<char *>(&NList), 184 reinterpret_cast<char *>(&NList + 1)); 185 return true; 186 } 187 188 // Wrapper around transferSymbol to transfer all of \a Obj symbols 189 // to \a NewSymtab. This function does not write in the output file. 190 // \returns the number of symbols in \a NewSymtab. 191 static unsigned transferSymbols(const object::MachOObjectFile &Obj, 192 SmallVectorImpl<char> &NewSymtab, 193 NonRelocatableStringpool &NewStrings) { 194 unsigned Syms = 0; 195 StringRef Strings = Obj.getStringTableData(); 196 bool IsLittleEndian = Obj.isLittleEndian(); 197 bool InDebugNote = false; 198 199 if (Obj.is64Bit()) { 200 for (const object::SymbolRef &Symbol : Obj.symbols()) { 201 object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); 202 if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian, 203 Strings, NewSymtab, NewStrings, InDebugNote)) 204 ++Syms; 205 } 206 } else { 207 for (const object::SymbolRef &Symbol : Obj.symbols()) { 208 object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); 209 if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings, 210 NewSymtab, NewStrings, InDebugNote)) 211 ++Syms; 212 } 213 } 214 return Syms; 215 } 216 217 static MachO::section 218 getSection(const object::MachOObjectFile &Obj, 219 const MachO::segment_command &Seg, 220 const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { 221 return Obj.getSection(LCI, Idx); 222 } 223 224 static MachO::section_64 225 getSection(const object::MachOObjectFile &Obj, 226 const MachO::segment_command_64 &Seg, 227 const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { 228 return Obj.getSection64(LCI, Idx); 229 } 230 231 // Transfer \a Segment from \a Obj to the output file. This calls into \a Writer 232 // to write these load commands directly in the output file at the current 233 // position. 234 // The function also tries to find a hole in the address map to fit the __DWARF 235 // segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the 236 // highest segment address. 237 // When the __LINKEDIT segment is transferred, its offset and size are set resp. 238 // to \a LinkeditOffset and \a LinkeditSize. 239 template <typename SegmentTy> 240 static void transferSegmentAndSections( 241 const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, 242 const object::MachOObjectFile &Obj, MachObjectWriter &Writer, 243 uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t DwarfSegmentSize, 244 uint64_t &GapForDwarf, uint64_t &EndAddress) { 245 if (StringRef("__DWARF") == Segment.segname) 246 return; 247 248 Segment.fileoff = Segment.filesize = 0; 249 250 if (StringRef("__LINKEDIT") == Segment.segname) { 251 Segment.fileoff = LinkeditOffset; 252 Segment.filesize = LinkeditSize; 253 // Resize vmsize by rounding to the page size. 254 Segment.vmsize = alignTo(LinkeditSize, 0x1000); 255 } 256 257 // Check if the end address of the last segment and our current 258 // start address leave a sufficient gap to store the __DWARF 259 // segment. 260 uint64_t PrevEndAddress = EndAddress; 261 EndAddress = alignTo(EndAddress, 0x1000); 262 if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress && 263 Segment.vmaddr - EndAddress >= DwarfSegmentSize) 264 GapForDwarf = EndAddress; 265 266 // The segments are not necessarily sorted by their vmaddr. 267 EndAddress = 268 std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize); 269 unsigned nsects = Segment.nsects; 270 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) 271 MachO::swapStruct(Segment); 272 Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment)); 273 for (unsigned i = 0; i < nsects; ++i) { 274 auto Sect = getSection(Obj, Segment, LCI, i); 275 Sect.offset = Sect.reloff = Sect.nreloc = 0; 276 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) 277 MachO::swapStruct(Sect); 278 Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect)); 279 } 280 } 281 282 // Write the __DWARF segment load command to the output file. 283 static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset, 284 uint64_t FileSize, unsigned NumSections, 285 MCAsmLayout &Layout, MachObjectWriter &Writer) { 286 Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr, 287 alignTo(FileSize, 0x1000), FileOffset, 288 FileSize, /* MaxProt */ 7, 289 /* InitProt =*/3); 290 291 for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { 292 MCSection *Sec = Layout.getSectionOrder()[i]; 293 if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec)) 294 continue; 295 296 unsigned Align = Sec->getAlignment(); 297 if (Align > 1) { 298 VMAddr = alignTo(VMAddr, Align); 299 FileOffset = alignTo(FileOffset, Align); 300 } 301 Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0); 302 303 FileOffset += Layout.getSectionAddressSize(Sec); 304 VMAddr += Layout.getSectionAddressSize(Sec); 305 } 306 } 307 308 static bool isExecutable(const object::MachOObjectFile &Obj) { 309 if (Obj.is64Bit()) 310 return Obj.getHeader64().filetype != MachO::MH_OBJECT; 311 else 312 return Obj.getHeader().filetype != MachO::MH_OBJECT; 313 } 314 315 static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) { 316 bool HasLinkEditSegment = false; 317 iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) { 318 if (StringRef("__LINKEDIT") == Segment.segname) 319 HasLinkEditSegment = true; 320 }); 321 return HasLinkEditSegment; 322 } 323 324 static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) { 325 if (Is64Bit) 326 return sizeof(MachO::segment_command_64) + 327 NumSections * sizeof(MachO::section_64); 328 329 return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); 330 } 331 332 // Stream a dSYM companion binary file corresponding to the binary referenced 333 // by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to 334 // \a OutFile and it must be using a MachObjectWriter object to do so. 335 bool generateDsymCompanion(const DebugMap &DM, SymbolMapTranslator &Translator, 336 MCStreamer &MS, raw_fd_ostream &OutFile) { 337 auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS); 338 MCAssembler &MCAsm = ObjectStreamer.getAssembler(); 339 auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter()); 340 341 // Layout but don't emit. 342 ObjectStreamer.flushPendingLabels(); 343 MCAsmLayout Layout(MCAsm); 344 MCAsm.layout(Layout); 345 346 BinaryHolder InputBinaryHolder(false); 347 348 auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath()); 349 if (!ObjectEntry) { 350 auto Err = ObjectEntry.takeError(); 351 return error(Twine("opening ") + DM.getBinaryPath() + ": " + 352 toString(std::move(Err)), 353 "output file streaming"); 354 } 355 356 auto Object = 357 ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple()); 358 if (!Object) { 359 auto Err = Object.takeError(); 360 return error(Twine("opening ") + DM.getBinaryPath() + ": " + 361 toString(std::move(Err)), 362 "output file streaming"); 363 } 364 365 auto &InputBinary = *Object; 366 367 bool Is64Bit = Writer.is64Bit(); 368 MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand(); 369 370 // Compute the number of load commands we will need. 371 unsigned LoadCommandSize = 0; 372 unsigned NumLoadCommands = 0; 373 374 // Get LC_UUID and LC_BUILD_VERSION. 375 MachO::uuid_command UUIDCmd; 376 SmallVector<MachO::build_version_command, 2> BuildVersionCmd; 377 memset(&UUIDCmd, 0, sizeof(UUIDCmd)); 378 for (auto &LCI : InputBinary.load_commands()) { 379 switch (LCI.C.cmd) { 380 case MachO::LC_UUID: 381 if (UUIDCmd.cmd) 382 return error("Binary contains more than one UUID"); 383 UUIDCmd = InputBinary.getUuidCommand(LCI); 384 ++NumLoadCommands; 385 LoadCommandSize += sizeof(UUIDCmd); 386 break; 387 case MachO::LC_BUILD_VERSION: { 388 MachO::build_version_command Cmd; 389 memset(&Cmd, 0, sizeof(Cmd)); 390 Cmd = InputBinary.getBuildVersionLoadCommand(LCI); 391 ++NumLoadCommands; 392 LoadCommandSize += sizeof(Cmd); 393 // LLDB doesn't care about the build tools for now. 394 Cmd.ntools = 0; 395 BuildVersionCmd.push_back(Cmd); 396 break; 397 } 398 default: 399 break; 400 } 401 } 402 403 // If we have a valid symtab to copy, do it. 404 bool ShouldEmitSymtab = 405 isExecutable(InputBinary) && hasLinkEditSegment(InputBinary); 406 if (ShouldEmitSymtab) { 407 LoadCommandSize += sizeof(MachO::symtab_command); 408 ++NumLoadCommands; 409 } 410 411 unsigned HeaderSize = 412 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 413 // We will copy every segment that isn't __DWARF. 414 iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) { 415 if (StringRef("__DWARF") == Segment.segname) 416 return; 417 418 ++NumLoadCommands; 419 LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects); 420 }); 421 422 // We will add our own brand new __DWARF segment if we have debug 423 // info. 424 unsigned NumDwarfSections = 0; 425 uint64_t DwarfSegmentSize = 0; 426 427 for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { 428 MCSection *Sec = Layout.getSectionOrder()[i]; 429 if (Sec->begin() == Sec->end()) 430 continue; 431 432 if (uint64_t Size = Layout.getSectionFileSize(Sec)) { 433 DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment()); 434 DwarfSegmentSize += Size; 435 ++NumDwarfSections; 436 } 437 } 438 439 if (NumDwarfSections) { 440 ++NumLoadCommands; 441 LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections); 442 } 443 444 SmallString<0> NewSymtab; 445 NonRelocatableStringpool NewStrings(Translator); 446 unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); 447 unsigned NumSyms = 0; 448 uint64_t NewStringsSize = 0; 449 if (ShouldEmitSymtab) { 450 NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2); 451 NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings); 452 NewStringsSize = NewStrings.getSize() + 1; 453 } 454 455 uint64_t SymtabStart = LoadCommandSize; 456 SymtabStart += HeaderSize; 457 SymtabStart = alignTo(SymtabStart, 0x1000); 458 459 // We gathered all the information we need, start emitting the output file. 460 Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); 461 462 // Write the load commands. 463 assert(OutFile.tell() == HeaderSize); 464 if (UUIDCmd.cmd != 0) { 465 Writer.W.write<uint32_t>(UUIDCmd.cmd); 466 Writer.W.write<uint32_t>(sizeof(UUIDCmd)); 467 OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16); 468 assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd)); 469 } 470 for (auto Cmd : BuildVersionCmd) { 471 Writer.W.write<uint32_t>(Cmd.cmd); 472 Writer.W.write<uint32_t>(sizeof(Cmd)); 473 Writer.W.write<uint32_t>(Cmd.platform); 474 Writer.W.write<uint32_t>(Cmd.minos); 475 Writer.W.write<uint32_t>(Cmd.sdk); 476 Writer.W.write<uint32_t>(Cmd.ntools); 477 } 478 479 assert(SymtabCmd.cmd && "No symbol table."); 480 uint64_t StringStart = SymtabStart + NumSyms * NListSize; 481 if (ShouldEmitSymtab) 482 Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, 483 NewStringsSize); 484 485 uint64_t DwarfSegmentStart = StringStart + NewStringsSize; 486 DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); 487 488 // Write the load commands for the segments and sections we 'import' from 489 // the original binary. 490 uint64_t EndAddress = 0; 491 uint64_t GapForDwarf = UINT64_MAX; 492 for (auto &LCI : InputBinary.load_commands()) { 493 if (LCI.C.cmd == MachO::LC_SEGMENT) 494 transferSegmentAndSections(LCI, InputBinary.getSegmentLoadCommand(LCI), 495 InputBinary, Writer, SymtabStart, 496 StringStart + NewStringsSize - SymtabStart, 497 DwarfSegmentSize, GapForDwarf, EndAddress); 498 else if (LCI.C.cmd == MachO::LC_SEGMENT_64) 499 transferSegmentAndSections(LCI, InputBinary.getSegment64LoadCommand(LCI), 500 InputBinary, Writer, SymtabStart, 501 StringStart + NewStringsSize - SymtabStart, 502 DwarfSegmentSize, GapForDwarf, EndAddress); 503 } 504 505 uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); 506 uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX; 507 if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax || 508 DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) { 509 // There is no room for the __DWARF segment at the end of the 510 // address space. Look through segments to find a gap. 511 DwarfVMAddr = GapForDwarf; 512 if (DwarfVMAddr == UINT64_MAX) 513 warn("not enough VM space for the __DWARF segment.", 514 "output file streaming"); 515 } 516 517 // Write the load command for the __DWARF segment. 518 createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize, 519 NumDwarfSections, Layout, Writer); 520 521 assert(OutFile.tell() == LoadCommandSize + HeaderSize); 522 OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize)); 523 assert(OutFile.tell() == SymtabStart); 524 525 // Transfer symbols. 526 if (ShouldEmitSymtab) { 527 OutFile << NewSymtab.str(); 528 assert(OutFile.tell() == StringStart); 529 530 // Transfer string table. 531 // FIXME: The NonRelocatableStringpool starts with an empty string, but 532 // dsymutil-classic starts the reconstructed string table with 2 of these. 533 // Reproduce that behavior for now (there is corresponding code in 534 // transferSymbol). 535 OutFile << '\0'; 536 std::vector<DwarfStringPoolEntryRef> Strings = 537 NewStrings.getEntriesForEmission(); 538 for (auto EntryRef : Strings) { 539 OutFile.write(EntryRef.getString().data(), 540 EntryRef.getString().size() + 1); 541 } 542 } 543 544 assert(OutFile.tell() == StringStart + NewStringsSize); 545 546 // Pad till the Dwarf segment start. 547 OutFile.write_zeros(DwarfSegmentStart - (StringStart + NewStringsSize)); 548 assert(OutFile.tell() == DwarfSegmentStart); 549 550 // Emit the Dwarf sections contents. 551 for (const MCSection &Sec : MCAsm) { 552 if (Sec.begin() == Sec.end()) 553 continue; 554 555 uint64_t Pos = OutFile.tell(); 556 OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos); 557 MCAsm.writeSectionData(OutFile, &Sec, Layout); 558 } 559 560 return true; 561 } 562 } // namespace MachOUtils 563 } // namespace dsymutil 564 } // namespace llvm 565