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