Index: include/llvm/Object/MachO.h =================================================================== --- include/llvm/Object/MachO.h +++ include/llvm/Object/MachO.h @@ -191,6 +191,24 @@ MachO::load_command C; // The command itself. }; + class LoadCommandInfoHolder { + public: + ErrorOr get() const { return LCI; } + bool operator==(const LoadCommandInfoHolder &) const; + void moveNext(); + + private: + friend class MachOObjectFile; + LoadCommandInfoHolder(const MachOObjectFile &OwningObject, uint32_t Index); + + const MachOObjectFile &OwningObject; + uint32_t Index; + uint32_t TotalCount; + ErrorOr LCI; + }; + + typedef content_iterator load_command_iterator; + MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, std::error_code &EC); @@ -273,10 +291,14 @@ dice_iterator begin_dices() const; dice_iterator end_dices() const; - + + load_command_iterator begin_load_commands() const; + load_command_iterator end_load_commands() const; + iterator_range load_commands() const; + /// For use iterating over all exported symbols. iterator_range exports() const; - + /// For use examining a trie not in a MachOObjectFile. static iterator_range exports(ArrayRef Trie); Index: lib/Object/MachOObjectFile.cpp =================================================================== --- lib/Object/MachOObjectFile.cpp +++ lib/Object/MachOObjectFile.cpp @@ -251,15 +251,15 @@ DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr), DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr), HasPageZeroSegment(false) { - uint32_t LoadCommandCount = this->getHeader().ncmds; - if (LoadCommandCount == 0) - return; - MachO::LoadCommandType SegmentLoadType = is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; - - MachOObjectFile::LoadCommandInfo Load = getFirstLoadCommandInfo(); - for (unsigned I = 0; ; ++I) { + for (const auto &L : load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) { + EC = LoadOrErr.getError(); + return; + } + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SYMTAB) { // Multiple symbol tables if (SymtabLoadCmd) { @@ -324,11 +324,6 @@ Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { Libraries.push_back(Load.Ptr); } - - if (I == LoadCommandCount - 1) - break; - else - Load = getNextLoadCommandInfo(Load); } } @@ -2104,6 +2099,45 @@ MachOBindEntry::Kind::Weak); } +MachOObjectFile::LoadCommandInfoHolder::LoadCommandInfoHolder( + const MachOObjectFile &OwningObject, uint32_t Index) + : OwningObject(OwningObject), Index(Index), + TotalCount(OwningObject.getHeader().ncmds), + LCI(object_error::parse_failed) { + if (Index == 0 && TotalCount > 0) + LCI = OwningObject.getFirstLoadCommandInfo(); +} + +bool MachOObjectFile::LoadCommandInfoHolder:: +operator==(const LoadCommandInfoHolder &Other) const { + assert(&OwningObject == &Other.OwningObject); + return Index == Other.Index; +} + +void MachOObjectFile::LoadCommandInfoHolder::moveNext() { + assert(Index < TotalCount); + if (++Index < TotalCount) + LCI = OwningObject.getNextLoadCommandInfo(LCI.get()); + else + LCI = object_error::parse_failed; +} + +MachOObjectFile::load_command_iterator +MachOObjectFile::begin_load_commands() const { + return LoadCommandInfoHolder(*this, 0); +} + +MachOObjectFile::load_command_iterator +MachOObjectFile::end_load_commands() const { + return LoadCommandInfoHolder(*this, getHeader().ncmds); +} + +iterator_range +MachOObjectFile::load_commands() const { + return iterator_range(begin_load_commands(), + end_load_commands()); +} + StringRef MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef Raw = getSectionRawFinalSegmentName(Sec); Index: tools/llvm-objdump/MachODump.cpp =================================================================== --- tools/llvm-objdump/MachODump.cpp +++ tools/llvm-objdump/MachODump.cpp @@ -281,8 +281,7 @@ return Size; } -static void getSectionsAndSymbols(const MachO::mach_header Header, - MachOObjectFile *MachOObj, +static void getSectionsAndSymbols(MachOObjectFile *MachOObj, std::vector &Sections, std::vector &Symbols, SmallVectorImpl &FoundFns, @@ -300,10 +299,12 @@ Sections.push_back(Section); } - MachOObjectFile::LoadCommandInfo Command = - MachOObj->getFirstLoadCommandInfo(); bool BaseSegmentAddressSet = false; - for (unsigned i = 0;; ++i) { + for (const auto &L : MachOObj->load_commands()) { + auto CmdOrErr = L.get(); + if (!CmdOrErr) + break; + auto Command = CmdOrErr.get(); if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { // We found a function starts segment, parse the addresses for later // consumption. @@ -319,11 +320,6 @@ BaseSegmentAddress = SLC.vmaddr; } } - - if (i == Header.ncmds - 1) - break; - else - Command = MachOObj->getNextLoadCommandInfo(Command); } } @@ -386,9 +382,11 @@ } static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) { - uint32_t LoadCommandCount = O->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo(); - for (unsigned I = 0;; ++I) { + for (const auto &L : O->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load); for (unsigned J = 0; J < Seg.nsects; ++J) { @@ -446,10 +444,6 @@ } } } - if (I == LoadCommandCount - 1) - break; - else - Load = O->getNextLoadCommandInfo(Load); } } @@ -553,9 +547,12 @@ } static void PrintDylibs(MachOObjectFile *O, bool JustId) { - uint32_t LoadCommandCount = O->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo(); - for (unsigned I = 0;; ++I) { + unsigned Index = 0; + for (const auto &L : O->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) || (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB || Load.C.cmd == MachO::LC_LOAD_DYLIB || @@ -595,13 +592,9 @@ outs() << "LC_LOAD_UPWARD_DYLIB "; else outs() << "LC_??? "; - outs() << "command " << I << "\n"; + outs() << "command " << Index++ << "\n"; } } - if (I == LoadCommandCount - 1) - break; - else - Load = O->getNextLoadCommandInfo(Load); } } @@ -2132,9 +2125,11 @@ // it returns a pointer to that string. Else it returns nullptr. static const char *GuessCstringPointer(uint64_t ReferenceValue, struct DisassembleInfo *info) { - uint32_t LoadCommandCount = info->O->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo(); - for (unsigned I = 0;; ++I) { + for (const auto &L : info->O->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load); for (unsigned J = 0; J < Seg.nsects; ++J) { @@ -2178,10 +2173,6 @@ } } } - if (I == LoadCommandCount - 1) - break; - else - Load = info->O->getNextLoadCommandInfo(Load); } return nullptr; } @@ -2192,11 +2183,13 @@ // symbol name being referenced by the stub or pointer. static const char *GuessIndirectSymbol(uint64_t ReferenceValue, struct DisassembleInfo *info) { - uint32_t LoadCommandCount = info->O->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo(); MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand(); MachO::symtab_command Symtab = info->O->getSymtabLoadCommand(); - for (unsigned I = 0;; ++I) { + for (const auto &L : info->O->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load); for (unsigned J = 0; J < Seg.nsects; ++J) { @@ -2266,10 +2259,6 @@ } } } - if (I == LoadCommandCount - 1) - break; - else - Load = info->O->getNextLoadCommandInfo(Load); } return nullptr; } @@ -2356,9 +2345,11 @@ selref = false; msgref = false; cfstring = false; - uint32_t LoadCommandCount = info->O->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo(); - for (unsigned I = 0;; ++I) { + for (const auto &L : info->O->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load); for (unsigned J = 0; J < Seg.nsects; ++J) { @@ -2403,10 +2394,6 @@ } } // TODO: Look for LC_SEGMENT for 32-bit Mach-O files. - if (I == LoadCommandCount - 1) - break; - else - Load = info->O->getNextLoadCommandInfo(Load); } return 0; } @@ -6075,7 +6062,7 @@ SmallVector FoundFns; uint64_t BaseSegmentAddress; - getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns, + getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns, BaseSegmentAddress); // Sort the symbols by address, just in case they didn't come in that way. @@ -8367,15 +8354,16 @@ outs() << "\n"; } -static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds, - uint32_t filetype, uint32_t cputype, - bool verbose) { - if (ncmds == 0) - return; +static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype, + uint32_t cputype, bool verbose) { StringRef Buf = Obj->getData(); - MachOObjectFile::LoadCommandInfo Command = Obj->getFirstLoadCommandInfo(); - for (unsigned i = 0;; ++i) { - outs() << "Load command " << i << "\n"; + unsigned Index = 0; + for (const auto &L : Obj->load_commands()) { + auto CmdOrErr = L.get(); + if (!CmdOrErr) + break; + outs() << "Load command " << Index++ << "\n"; + MachOObjectFile::LoadCommandInfo Command = CmdOrErr.get(); if (Command.C.cmd == MachO::LC_SEGMENT) { MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command); const char *sg_segname = SLC.segname; @@ -8494,14 +8482,10 @@ // TODO: get and print the raw bytes of the load command. } // TODO: print all the other kinds of load commands. - if (i == ncmds - 1) - break; - else - Command = Obj->getNextLoadCommandInfo(Command); } } -static void getAndPrintMachHeader(const MachOObjectFile *Obj, uint32_t &ncmds, +static void getAndPrintMachHeader(const MachOObjectFile *Obj, uint32_t &filetype, uint32_t &cputype, bool verbose) { if (Obj->is64Bit()) { @@ -8509,7 +8493,6 @@ H_64 = Obj->getHeader64(); PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype, H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose); - ncmds = H_64.ncmds; filetype = H_64.filetype; cputype = H_64.cputype; } else { @@ -8517,7 +8500,6 @@ H = Obj->getHeader(); PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds, H.sizeofcmds, H.flags, verbose); - ncmds = H.ncmds; filetype = H.filetype; cputype = H.cputype; } @@ -8525,11 +8507,10 @@ void llvm::printMachOFileHeader(const object::ObjectFile *Obj) { const MachOObjectFile *file = dyn_cast(Obj); - uint32_t ncmds = 0; uint32_t filetype = 0; uint32_t cputype = 0; - getAndPrintMachHeader(file, ncmds, filetype, cputype, !NonVerbose); - PrintLoadCommands(file, ncmds, filetype, cputype, !NonVerbose); + getAndPrintMachHeader(file, filetype, cputype, !NonVerbose); + PrintLoadCommands(file, filetype, cputype, !NonVerbose); } //===----------------------------------------------------------------------===// Index: tools/llvm-size/llvm-size.cpp =================================================================== --- tools/llvm-size/llvm-size.cpp +++ tools/llvm-size/llvm-size.cpp @@ -122,12 +122,14 @@ fmt << "0x"; fmt << "%" << radix_fmt; - uint32_t LoadCommandCount = MachO->getHeader().ncmds; uint32_t Filetype = MachO->getHeader().filetype; - MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo(); uint64_t total = 0; - for (unsigned I = 0;; ++I) { + for (const auto &L : MachO->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); outs() << "Segment " << Seg.segname << ": " @@ -181,10 +183,6 @@ if (Seg.nsects != 0) outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; } - if (I == LoadCommandCount - 1) - break; - else - Load = MachO->getNextLoadCommandInfo(Load); } outs() << "total " << format(fmt.str().c_str(), total) << "\n"; } @@ -194,14 +192,15 @@ /// This is when used when @c OutputFormat is berkeley with a Mach-O file and /// produces the same output as darwin's size(1) default output. static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) { - uint32_t LoadCommandCount = MachO->getHeader().ncmds; - MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo(); - uint64_t total_text = 0; uint64_t total_data = 0; uint64_t total_objc = 0; uint64_t total_others = 0; - for (unsigned I = 0;; ++I) { + for (const auto &L : MachO->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) + break; + MachOObjectFile::LoadCommandInfo Load = LoadOrErr.get(); if (Load.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); if (MachO->getHeader().filetype == MachO::MH_OBJECT) { @@ -255,10 +254,6 @@ total_others += Seg.vmsize; } } - if (I == LoadCommandCount - 1) - break; - else - Load = MachO->getNextLoadCommandInfo(Load); } uint64_t total = total_text + total_data + total_objc + total_others; Index: tools/macho-dump/macho-dump.cpp =================================================================== --- tools/macho-dump/macho-dump.cpp +++ tools/macho-dump/macho-dump.cpp @@ -423,16 +423,16 @@ // Print the load commands. int Res = 0; - MachOObjectFile::LoadCommandInfo Command = - InputObject->getFirstLoadCommandInfo(); + unsigned Index = 0; outs() << "('load_commands', [\n"; - for (unsigned i = 0; ; ++i) { - if (DumpLoadCommand(*InputObject, i, Command)) + for (const auto &L : InputObject->load_commands()) { + auto LoadOrErr = L.get(); + if (!LoadOrErr) { + Error(LoadOrErr.getError().message()); break; - - if (i == Header->ncmds - 1) + } + if (DumpLoadCommand(*InputObject, Index++, LoadOrErr.get())) break; - Command = InputObject->getNextLoadCommandInfo(Command); } outs() << "])\n";