diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -898,12 +898,17 @@ uint32_t count; }; +union lc_str { + uint32_t offset; +}; + struct fileset_entry_command { uint32_t cmd; uint32_t cmdsize; uint64_t vmaddr; uint64_t fileoff; - uint32_t entry_id; + union lc_str entry_id; + uint32_t reserved; }; // The symseg_command is obsolete and no longer supported. @@ -1434,7 +1439,8 @@ sys::swapByteOrder(C.cmdsize); sys::swapByteOrder(C.vmaddr); sys::swapByteOrder(C.fileoff); - sys::swapByteOrder(C.entry_id); + sys::swapByteOrder(C.entry_id.offset); + sys::swapByteOrder(C.reserved); } inline void swapStruct(version_min_command &C) { diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -414,7 +414,8 @@ static Expected> create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, - uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); + uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0, + size_t MachOFilesetEntryOffset = 0); static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch); @@ -697,6 +698,8 @@ getRoutinesCommand64(const LoadCommandInfo &L) const; MachO::thread_command getThreadCommand(const LoadCommandInfo &L) const; + MachO::fileset_entry_command + getFilesetEntryLoadCommand(const LoadCommandInfo &L) const; MachO::any_relocation_info getRelocation(DataRefImpl Rel) const; MachO::data_in_code_entry getDice(DataRefImpl Rel) const; @@ -760,6 +763,8 @@ bool hasPageZeroSegment() const { return HasPageZeroSegment; } + size_t getMachOFilesetEntryOffset() const { return MachOFilesetEntryOffset; } + static bool classof(const Binary *v) { return v->isMachO(); } @@ -839,7 +844,8 @@ private: MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, Error &Err, uint32_t UniversalCputype = 0, - uint32_t UniversalIndex = 0); + uint32_t UniversalIndex = 0, + size_t MachOFilesetEntryOffset = 0); uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; @@ -867,6 +873,7 @@ const char *DyldExportsTrieLoadCmd = nullptr; const char *UuidLoadCmd = nullptr; bool HasPageZeroSegment = false; + size_t MachOFilesetEntryOffset = 0; }; /// DiceRef diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -389,9 +389,9 @@ createELFObjectFile(MemoryBufferRef Object, bool InitContent = true); static Expected> - createMachOObjectFile(MemoryBufferRef Object, - uint32_t UniversalCputype = 0, - uint32_t UniversalIndex = 0); + createMachOObjectFile(MemoryBufferRef Object, uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0, + size_t MachOFilesetEntryOffset = 0); static Expected> createGOFFObjectFile(MemoryBufferRef Object); diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -108,9 +108,11 @@ return reinterpret_cast(SectionAddr); } -static const char *getPtr(const MachOObjectFile &O, size_t Offset) { - assert(Offset <= O.getData().size()); - return O.getData().data() + Offset; +static const char *getPtr(const MachOObjectFile &O, size_t Offset, + size_t MachOFilesetEntryOffset = 0) { + assert(Offset <= O.getData().size() && + MachOFilesetEntryOffset <= O.getData().size()); + return O.getData().data() + Offset + MachOFilesetEntryOffset; } static MachO::nlist_base @@ -208,7 +210,8 @@ if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds) return malformedError("load command 0 extends past the end all load " "commands in the file"); - return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize), 0); + return getLoadCommandInfo( + Obj, getPtr(Obj, HeaderSize, Obj.getMachOFilesetEntryOffset()), 0); } static Expected @@ -217,7 +220,8 @@ unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) > - Obj.getData().data() + HeaderSize + Obj.getHeader().sizeofcmds) + Obj.getData().data() + Obj.getMachOFilesetEntryOffset() + HeaderSize + + Obj.getHeader().sizeofcmds) return malformedError("load command " + Twine(LoadCommandIndex + 1) + " extends past the end all load commands in the file"); return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1); @@ -231,7 +235,8 @@ "file"); return; } - if (auto HeaderOrErr = getStructOrErr(Obj, getPtr(Obj, 0))) + if (auto HeaderOrErr = getStructOrErr( + Obj, getPtr(Obj, 0, Obj.getMachOFilesetEntryOffset()))) Header = *HeaderOrErr; else Err = HeaderOrErr.takeError(); @@ -1247,12 +1252,12 @@ Expected> MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, uint32_t UniversalCputype, - uint32_t UniversalIndex) { + uint32_t UniversalIndex, + size_t MachOFilesetEntryOffset) { Error Err = Error::success(); - std::unique_ptr Obj( - new MachOObjectFile(std::move(Object), IsLittleEndian, - Is64Bits, Err, UniversalCputype, - UniversalIndex)); + std::unique_ptr Obj(new MachOObjectFile( + std::move(Object), IsLittleEndian, Is64Bits, Err, UniversalCputype, + UniversalIndex, MachOFilesetEntryOffset)); if (Err) return std::move(Err); return std::move(Obj); @@ -1261,8 +1266,10 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64bits, Error &Err, uint32_t UniversalCputype, - uint32_t UniversalIndex) - : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object) { + uint32_t UniversalIndex, + size_t MachOFilesetEntryOffset) + : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), + MachOFilesetEntryOffset(MachOFilesetEntryOffset) { ErrorAsOutParameter ErrAsOutParam(&Err); uint64_t SizeOfHeaders; uint32_t cputype; @@ -4761,6 +4768,11 @@ return getStruct(*this, L.Ptr); } +MachO::fileset_entry_command +MachOObjectFile::getFilesetEntryLoadCommand(const LoadCommandInfo &L) const { + return getStruct(*this, L.Ptr); +} + MachO::any_relocation_info MachOObjectFile::getRelocation(DataRefImpl Rel) const { uint32_t Offset; @@ -5300,23 +5312,29 @@ return getHeader().filetype == MachO::MH_OBJECT; } -Expected> -ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer, - uint32_t UniversalCputype, - uint32_t UniversalIndex) { +/// Create a MachOObjectFile instance from a given buffer. +/// +/// \param Buffer Memory buffer containing the MachO binary data. +/// \param UniversalCputype CPU type when the MachO part of a universal binary. +/// \param UniversalIndex Index of the MachO within a universal binary. +/// \param MachOFilesetEntryOffset Offset of the MachO entry in a fileset MachO. +/// \returns A std::unique_ptr to a MachOObjectFile instance on success. +Expected> ObjectFile::createMachOObjectFile( + MemoryBufferRef Buffer, uint32_t UniversalCputype, uint32_t UniversalIndex, + size_t MachOFilesetEntryOffset) { StringRef Magic = Buffer.getBuffer().slice(0, 4); if (Magic == "\xFE\xED\xFA\xCE") - return MachOObjectFile::create(Buffer, false, false, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, false, false, UniversalCputype, + UniversalIndex, MachOFilesetEntryOffset); if (Magic == "\xCE\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, false, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, true, false, UniversalCputype, + UniversalIndex, MachOFilesetEntryOffset); if (Magic == "\xFE\xED\xFA\xCF") - return MachOObjectFile::create(Buffer, false, true, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, false, true, UniversalCputype, + UniversalIndex, MachOFilesetEntryOffset); if (Magic == "\xCF\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, true, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, true, true, UniversalCputype, + UniversalIndex, MachOFilesetEntryOffset); return make_error("Unrecognized MachO magic number", object_error::invalid_file_type); } diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -627,7 +627,8 @@ IO &IO, MachO::fileset_entry_command &LoadCommand) { IO.mapRequired("vmaddr", LoadCommand.vmaddr); IO.mapRequired("fileoff", LoadCommand.fileoff); - IO.mapRequired("id", LoadCommand.entry_id); + IO.mapRequired("id", LoadCommand.entry_id.offset); + IO.mapOptional("reserved", LoadCommand.reserved); } } // end namespace yaml diff --git a/llvm/test/tools/llvm-nm/AArch64/Inputs/fileset.macho-aarch64 b/llvm/test/tools/llvm-nm/AArch64/Inputs/fileset.macho-aarch64 new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ &SymbolList, bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {}, StringRef ArchitectureName = {}, StringRef ObjectName = {}, bool PrintArchiveName = true) { - if (!shouldDump(Obj)) - return; - - if (ExportSymbols && Obj.isXCOFF()) { - XCOFFObjectFile *XCOFFObj = cast(&Obj); - getXCOFFExports(XCOFFObj, SymbolList, ArchiveName); - return; - } if (PrintObjectLabel && !ExportSymbols) printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName, ObjectName.empty() ? Obj.getFileName() : ObjectName); + if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols) return; - CurrentFilename = Obj.getFileName(); // If there is an error in hasSymbols(), the error should be encountered in // function getSymbolNamesFromObject first. @@ -1923,6 +1917,68 @@ ArchitectureName); } +static void dumpSymbolsNameFromMachOFilesetEntry( + MachOObjectFile *Obj, std::vector &SymbolList, + bool PrintSymbolObject, bool PrintObjectLabel) { + auto Buf = Obj->getMemoryBufferRef(); + const auto *End = Obj->load_commands().end(); + for (const auto *It = Obj->load_commands().begin(); It != End; ++It) { + const auto &Command = *It; + if (Command.C.cmd != MachO::LC_FILESET_ENTRY) + continue; + + MachO::fileset_entry_command Entry = + Obj->getFilesetEntryLoadCommand(Command); + auto MaybeMachO = + MachOObjectFile::createMachOObjectFile(Buf, 0, 0, Entry.fileoff); + + if (Error Err = MaybeMachO.takeError()) + report_fatal_error(std::move(Err)); + + const char *EntryName = Command.Ptr + Entry.entry_id.offset; + if (EntryName) + outs() << "Symbols for " << EntryName << ": \n"; + + std::unique_ptr EntryMachO = std::move(MaybeMachO.get()); + printSymbolNamesFromObject(*EntryMachO, SymbolList, PrintSymbolObject, + PrintObjectLabel); + + if (std::next(It) != End) + outs() << "\n"; + } +} + +static void dumpSymbolNamesFromObject( + SymbolicFile &Obj, std::vector &SymbolList, + bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {}, + StringRef ArchitectureName = {}, StringRef ObjectName = {}, + bool PrintArchiveName = true) { + if (!shouldDump(Obj)) + return; + + if (ExportSymbols && Obj.isXCOFF()) { + XCOFFObjectFile *XCOFFObj = cast(&Obj); + getXCOFFExports(XCOFFObj, SymbolList, ArchiveName); + return; + } + + CurrentFilename = Obj.getFileName(); + + // Are we handling a MachO of type MH_FILESET? + if (Obj.isMachO() && Obj.is64Bit() && + cast(&Obj)->getHeader64().filetype == + MachO::MH_FILESET) { + dumpSymbolsNameFromMachOFilesetEntry(cast(&Obj), + SymbolList, PrintSymbolObject, + PrintObjectLabel); + return; + } + + printSymbolNamesFromObject(Obj, SymbolList, PrintSymbolObject, + PrintObjectLabel, ArchiveName, ArchitectureName, + ObjectName, PrintArchiveName); +} + // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file // and if it is and there is a list of architecture flags is specified then // check to make sure this Mach-O file is one of those architectures or all