diff --git a/llvm/include/llvm/BinaryFormat/Magic.h b/llvm/include/llvm/BinaryFormat/Magic.h --- a/llvm/include/llvm/BinaryFormat/Magic.h +++ b/llvm/include/llvm/BinaryFormat/Magic.h @@ -46,6 +46,7 @@ pecoff_executable, ///< PECOFF executable file windows_resource, ///< Windows compiled resource file (.res) xcoff_object_32, ///< 32-bit XCOFF object file + xcoff_object_64, ///< 64-bit XCOFF object file wasm_object, ///< WebAssembly Object file pdb, ///< Windows PDB debug info file }; diff --git a/llvm/include/llvm/Object/Binary.h b/llvm/include/llvm/Object/Binary.h --- a/llvm/include/llvm/Object/Binary.h +++ b/llvm/include/llvm/Object/Binary.h @@ -51,7 +51,9 @@ // Object and children. ID_StartObjects, ID_COFF, + ID_XCOFF32, // AIX XCOFF 32-bit + ID_XCOFF64, // AIX XCOFF 64-bit ID_ELF32L, // ELF 32-bit, little endian ID_ELF32B, // ELF 32-bit, big endian @@ -121,7 +123,7 @@ return TypeID == ID_COFF; } - bool isXCOFF() const { return TypeID == ID_XCOFF32; } + bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; } bool isWasm() const { return TypeID == ID_Wasm; } 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 @@ -359,7 +359,7 @@ createCOFFObjectFile(MemoryBufferRef Object); static Expected> - createXCOFFObjectFile(MemoryBufferRef Object); + createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); static Expected> createELFObjectFile(MemoryBufferRef Object); diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -34,7 +34,7 @@ namespace llvm { namespace object { -struct XCOFFFileHeader { +struct XCOFFFileHeader32 { support::ubig16_t Magic; support::ubig16_t NumberOfSections; @@ -48,7 +48,21 @@ support::ubig16_t Flags; }; -struct XCOFFSectionHeader { +struct XCOFFFileHeader64 { + support::ubig16_t Magic; + support::ubig16_t NumberOfSections; + + // Unix time value, value of 0 indicates no timestamp. + // Negative values are reserved. + support::big32_t TimeStamp; + + support::ubig64_t SymbolTableOffset; // File offset to symbol table. + support::ubig16_t AuxHeaderSize; + support::ubig16_t Flags; + support::ubig32_t NumberOfSymTableEntries; +}; + +struct XCOFFSectionHeader32 { char Name[XCOFF::SectionNameSize]; support::ubig32_t PhysicalAddress; support::ubig32_t VirtualAddress; @@ -59,6 +73,24 @@ support::ubig16_t NumberOfRelocations; support::ubig16_t NumberOfLineNumbers; support::big32_t Flags; + + StringRef getName() const; +}; + +struct XCOFFSectionHeader64 { + char Name[XCOFF::SectionNameSize]; + support::ubig64_t PhysicalAddress; + support::ubig64_t VirtualAddress; + support::ubig64_t SectionSize; + support::big64_t FileOffsetToRawData; + support::big64_t FileOffsetToRelocationInfo; + support::big64_t FileOffsetToLineNumberInfo; + support::ubig32_t NumberOfRelocations; + support::ubig32_t NumberOfLineNumbers; + support::big32_t Flags; + char Padding[4]; + + StringRef getName() const; }; struct XCOFFSymbolEntry { @@ -97,20 +129,54 @@ class XCOFFObjectFile : public ObjectFile { private: - const XCOFFFileHeader *FileHdrPtr = nullptr; - const XCOFFSectionHeader *SectionHdrTablePtr = nullptr; + const void *FileHeader = nullptr; + const void *SectionHeaderTable = nullptr; + const XCOFFSymbolEntry *SymbolTblPtr = nullptr; XCOFFStringTable StringTable = {0, nullptr}; + const XCOFFFileHeader32 *fileHeader32() const; + const XCOFFFileHeader64 *fileHeader64() const; + + const XCOFFSectionHeader32 *sectionHeaderTable32() const; + const XCOFFSectionHeader64 *sectionHeaderTable64() const; + size_t getFileHeaderSize() const; size_t getSectionHeaderSize() const; - const XCOFFSectionHeader *toSection(DataRefImpl Ref) const; + const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; + const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + uintptr_t getSectionHeaderTableAddress() const; + + // This returns a pointer to the start of the storage for the name field of + // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily + // null-terminated. + const char *getSectionNameInternal(DataRefImpl Sec) const; + + int32_t getSectionFlags(DataRefImpl Sec) const; + static bool isReservedSectionNumber(int16_t SectionNumber); - std::error_code getSectionByNum(int16_t Num, - const XCOFFSectionHeader *&Result) const; + Expected getSectionByNum(int16_t Num) const; + + // Constructor and "create" factory function. The constructor is only a thin + // wrapper around the base constructor. The "create" function fills out the + // XCOFF-specific information and performs the error checking along the way. + XCOFFObjectFile(unsigned Type, MemoryBufferRef Object); + static Expected> create(unsigned Type, + MemoryBufferRef MBR); + + // Helper for parsing the StringTable. Returns an 'Error' if parsing failed + // and an XCOFFStringTable if parsing succeeded. + static Expected parseStringTable(const XCOFFObjectFile *Obj, + uint64_t Offset); + + // Make a friend so it can call the private 'create' function. + friend Expected> + ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); public: + // Interface inherited from base classes. void moveSymbolNext(DataRefImpl &Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; basic_symbol_iterator symbol_begin() const override; @@ -156,10 +222,11 @@ Expected getStartAddress() const override; bool isRelocatableObject() const override; - XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC); + // Below here is the non-inherited interface. + bool is64Bit() const; - const XCOFFFileHeader *getFileHeader() const { return FileHdrPtr; } const XCOFFSymbolEntry *getPointerToSymbolTable() const { + assert(!is64Bit() && "Symbol table handling not supported yet."); return SymbolTblPtr; } @@ -167,19 +234,32 @@ getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const; const XCOFFSymbolEntry *toSymbolEntry(DataRefImpl Ref) const; + + // File header related interfaces. uint16_t getMagic() const; uint16_t getNumberOfSections() const; int32_t getTimeStamp() const; - uint32_t getSymbolTableOffset() const; - // Returns the value as encoded in the object file. - // Negative values are reserved for future use. - int32_t getRawNumberOfSymbolTableEntries() const; + // Symbol table offset and entry count are handled differently between + // XCOFF32 and XCOFF64. + uint32_t getSymbolTableOffset32() const; + uint64_t getSymbolTableOffset64() const; + + // Note that this value is signed and might return a negative value. Negative + // values are reserved for future use. + int32_t getRawNumberOfSymbolTableEntries32() const; + + // The sanitized value appropriate to use as an index into the symbol table. + uint32_t getLogicalNumberOfSymbolTableEntries32() const; + + uint32_t getNumberOfSymbolTableEntries64() const; - // Returns a sanitized value, useable as an index into the symbol table. - uint32_t getLogicalNumberOfSymbolTableEntries() const; uint16_t getOptionalHeaderSize() const; - uint16_t getFlags() const { return FileHdrPtr->Flags; }; + uint16_t getFlags() const; + + // Section header table related interfaces. + ArrayRef sections32() const; + ArrayRef sections64() const; }; // XCOFFObjectFile } // namespace object diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -66,6 +66,8 @@ // XCOFF format if (startswith(Magic, "\x01\xDF")) return file_magic::xcoff_object_32; + if (startswith(Magic, "\x01\xF7")) + return file_magic::xcoff_object_64; break; case 0xDE: // 0x0B17C0DE = BC wraper diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp --- a/llvm/lib/Object/Binary.cpp +++ b/llvm/lib/Object/Binary.cpp @@ -70,6 +70,7 @@ case file_magic::pecoff_executable: case file_magic::bitcode: case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case file_magic::macho_universal_binary: diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -150,7 +150,9 @@ case file_magic::pecoff_executable: return createCOFFObjectFile(Object); case file_magic::xcoff_object_32: - return createXCOFFObjectFile(Object); + return createXCOFFObjectFile(Object, Binary::ID_XCOFF32); + case file_magic::xcoff_object_64: + return createXCOFFObjectFile(Object, Binary::ID_XCOFF64); case file_magic::wasm_object: return createWasmObjectFile(Object); } diff --git a/llvm/lib/Object/SymbolicFile.cpp b/llvm/lib/Object/SymbolicFile.cpp --- a/llvm/lib/Object/SymbolicFile.cpp +++ b/llvm/lib/Object/SymbolicFile.cpp @@ -70,6 +70,7 @@ case file_magic::macho_kext_bundle: case file_magic::pecoff_executable: case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createObjectFile(Object, Type); case file_magic::coff_import_library: diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -22,32 +22,20 @@ namespace llvm { namespace object { -enum { XCOFF32FileHeaderSize = 20 }; -static_assert(sizeof(XCOFFFileHeader) == XCOFF32FileHeaderSize, - "Wrong size for XCOFF file header."); - -// Sets EC and returns false if there is less than 'Size' bytes left in the -// buffer at 'Offset'. -static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Offset, - uint64_t Size) { - if (M.getBufferSize() < Offset + Size) { - EC = object_error::unexpected_eof; - return false; - } - return true; -} - -// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. -// Returns unexpected_eof on error. +// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer +// 'M'. Returns a pointer to the underlying object on success. template -static std::error_code getObject(const T *&Obj, MemoryBufferRef M, - const void *Ptr, - const uint64_t Size = sizeof(T)) { +static Expected getObject(MemoryBufferRef M, const void *Ptr, + const uint64_t Size = sizeof(T)) { uintptr_t Addr = uintptr_t(Ptr); if (std::error_code EC = Binary::checkOffset(M, Addr, Size)) - return EC; - Obj = reinterpret_cast(Addr); - return std::error_code(); + return errorCodeToError(EC); + return reinterpret_cast(Addr); +} + +static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { + return reinterpret_cast(reinterpret_cast(Base) + + Offset); } template static const T *viewAs(uintptr_t in) { @@ -60,43 +48,69 @@ : StringRef(Name, Size); } -const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const { - auto Sec = viewAs(Ref.p); -#ifndef NDEBUG - if (Sec < SectionHdrTablePtr || - Sec >= (SectionHdrTablePtr + getNumberOfSections())) +void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, + uintptr_t TableAddress) const { + if (Addr < TableAddress) + report_fatal_error("Section header outside of section header table."); + + uintptr_t Offset = Addr - TableAddress; + if (Offset >= getSectionHeaderSize() * getNumberOfSections()) report_fatal_error("Section header outside of section header table."); - uintptr_t Offset = uintptr_t(Sec) - uintptr_t(SectionHdrTablePtr); if (Offset % getSectionHeaderSize() != 0) report_fatal_error( "Section header pointer does not point to a valid section header."); +} + +const XCOFFSectionHeader32 * +XCOFFObjectFile::toSection32(DataRefImpl Ref) const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); #endif - return Sec; + return viewAs(Ref.p); +} + +const XCOFFSectionHeader64 * +XCOFFObjectFile::toSection64(DataRefImpl Ref) const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); +#endif + return viewAs(Ref.p); } const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); auto SymEntPtr = viewAs(Ref.p); return SymEntPtr; } -// The next 2 functions are not exactly necessary yet, but they are useful to -// abstract over the size difference between XCOFF32 and XCOFF64 structure -// definitions. -size_t XCOFFObjectFile::getFileHeaderSize() const { - return sizeof(XCOFFFileHeader); +const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast(FileHeader); } -size_t XCOFFObjectFile::getSectionHeaderSize() const { - return sizeof(XCOFFSectionHeader); +const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast(FileHeader); } -uint16_t XCOFFObjectFile::getMagic() const { return FileHdrPtr->Magic; } +const XCOFFSectionHeader32 * +XCOFFObjectFile::sectionHeaderTable32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast(SectionHeaderTable); +} + +const XCOFFSectionHeader64 * +XCOFFObjectFile::sectionHeaderTable64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast(SectionHeaderTable); +} void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); - SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; Symb.p = reinterpret_cast(SymEntPtr); } @@ -158,14 +172,11 @@ if (isReservedSectionNumber(SectNum)) return section_end(); - const XCOFFSectionHeader *Sec; - if (std::error_code EC = getSectionByNum(SectNum, Sec)) - return errorCodeToError(EC); - - DataRefImpl SecDRI; - SecDRI.p = reinterpret_cast(Sec); + Expected ExpSec = getSectionByNum(SectNum); + if (!ExpSec) + return ExpSec.takeError(); - return section_iterator(SectionRef(SecDRI, this)); + return section_iterator(SectionRef(ExpSec.get(), this)); } void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { @@ -174,25 +185,26 @@ } Expected XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { - const char *Name = toSection(Sec)->Name; - auto NulCharPtr = - static_cast(memchr(Name, '\0', XCOFF::SectionNameSize)); - return NulCharPtr ? StringRef(Name, NulCharPtr - Name) - : StringRef(Name, XCOFF::SectionNameSize); + return generateStringRef(getSectionNameInternal(Sec), XCOFF::SectionNameSize); } uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { - return toSection(Sec)->VirtualAddress; + return is64Bit() ? toSection64(Sec)->VirtualAddress + : toSection32(Sec)->VirtualAddress; } uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { // Section numbers in XCOFF are numbered beginning at 1. A section number of // zero is used to indicate that a symbol is being imported or is undefined. - return toSection(Sec) - SectionHdrTablePtr + 1; + if (is64Bit()) + return toSection64(Sec) - sectionHeaderTable64() + 1; + else + return toSection32(Sec) - sectionHeaderTable32() + 1; } uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { - return toSection(Sec)->SectionSize; + return is64Bit() ? toSection64(Sec)->SectionSize + : toSection32(Sec)->SectionSize; } Expected> @@ -213,16 +225,16 @@ } bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { - return toSection(Sec)->Flags & XCOFF::STYP_TEXT; + return getSectionFlags(Sec) & XCOFF::STYP_TEXT; } bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { - unsigned Flags = toSection(Sec)->Flags; + uint32_t Flags = getSectionFlags(Sec); return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); } bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { - unsigned Flags = toSection(Sec)->Flags; + uint32_t Flags = getSectionFlags(Sec); return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); } @@ -277,45 +289,41 @@ } basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { + assert(!is64Bit() && "64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast(SymbolTblPtr); return basic_symbol_iterator(SymbolRef(SymDRI, this)); } basic_symbol_iterator XCOFFObjectFile::symbol_end() const { + assert(!is64Bit() && "64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast( - SymbolTblPtr + getLogicalNumberOfSymbolTableEntries()); + SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); return basic_symbol_iterator(SymbolRef(SymDRI, this)); } section_iterator XCOFFObjectFile::section_begin() const { DataRefImpl DRI; - DRI.p = reinterpret_cast(SectionHdrTablePtr); + DRI.p = getSectionHeaderTableAddress(); return section_iterator(SectionRef(DRI, this)); } section_iterator XCOFFObjectFile::section_end() const { DataRefImpl DRI; - DRI.p = - reinterpret_cast(SectionHdrTablePtr + getNumberOfSections()); + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getNumberOfSections() * getSectionHeaderSize()); return section_iterator(SectionRef(DRI, this)); } -uint8_t XCOFFObjectFile::getBytesInAddress() const { - // Only support 32-bit object files for now ... - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return 4; -} +uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } StringRef XCOFFObjectFile::getFileFormatName() const { - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return "aixcoff-rs6000"; + return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; } Triple::ArchType XCOFFObjectFile::getArch() const { - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return Triple::ppc; + return is64Bit() ? Triple::ppc64 : Triple::ppc; } SubtargetFeatures XCOFFObjectFile::getFeatures() const { @@ -335,19 +343,36 @@ return 0; } -std::error_code -XCOFFObjectFile::getSectionByNum(int16_t Num, - const XCOFFSectionHeader *&Result) const { - if (Num > 0 && static_cast(Num) <= getNumberOfSections()) { - Result = SectionHdrTablePtr + (Num - 1); - return std::error_code(); - } +size_t XCOFFObjectFile::getFileHeaderSize() const { + return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); +} + +size_t XCOFFObjectFile::getSectionHeaderSize() const { + return is64Bit() ? sizeof(XCOFFSectionHeader64) : + sizeof(XCOFFSectionHeader32); +} + +bool XCOFFObjectFile::is64Bit() const { + return Binary::ID_XCOFF64 == getType(); +} + +uint16_t XCOFFObjectFile::getMagic() const { + return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; +} + +Expected XCOFFObjectFile::getSectionByNum(int16_t Num) const { + if (Num <= 0 || Num > getNumberOfSections()) + return errorCodeToError(object_error::invalid_section_index); - return object_error::invalid_section_index; + DataRefImpl DRI; + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getSectionHeaderSize() * (Num - 1)); + return DRI; } Expected XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); int16_t SectionNum = SymEntPtr->SectionNumber; switch (SectionNum) { @@ -357,14 +382,12 @@ return "N_ABS"; case XCOFF::N_UNDEF: return "N_UNDEF"; - default: { - const XCOFFSectionHeader *SectHeaderPtr; - std::error_code EC; - if ((EC = getSectionByNum(SectionNum, SectHeaderPtr))) - return errorCodeToError(EC); - else - return generateStringRef(SectHeaderPtr->Name, XCOFF::SectionNameSize); - } + default: + Expected SecRef = getSectionByNum(SectionNum); + if (SecRef) + return generateStringRef(getSectionNameInternal(SecRef.get()), + XCOFF::SectionNameSize); + return SecRef.takeError(); } } @@ -373,99 +396,180 @@ } uint16_t XCOFFObjectFile::getNumberOfSections() const { - return FileHdrPtr->NumberOfSections; + return is64Bit() ? fileHeader64()->NumberOfSections + : fileHeader32()->NumberOfSections; } -int32_t XCOFFObjectFile::getTimeStamp() const { return FileHdrPtr->TimeStamp; } +int32_t XCOFFObjectFile::getTimeStamp() const { + return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; +} + +uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { + return is64Bit() ? fileHeader64()->AuxHeaderSize + : fileHeader32()->AuxHeaderSize; +} -uint32_t XCOFFObjectFile::getSymbolTableOffset() const { - return FileHdrPtr->SymbolTableOffset; +uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { + return fileHeader32()->SymbolTableOffset; } -int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries() const { - return FileHdrPtr->NumberOfSymTableEntries; +int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { + // As far as symbol table size is concerned, if this field is negative it is + // to be treated as a 0. However since this field is also used for printing we + // don't want to truncate any negative values. + return fileHeader32()->NumberOfSymTableEntries; } -uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries() const { - return (FileHdrPtr->NumberOfSymTableEntries >= 0 - ? FileHdrPtr->NumberOfSymTableEntries +uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { + return (fileHeader32()->NumberOfSymTableEntries >= 0 + ? fileHeader32()->NumberOfSymTableEntries : 0); } -uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { - return FileHdrPtr->AuxHeaderSize; +uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { + return fileHeader64()->SymbolTableOffset; } -XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) - : ObjectFile(Binary::ID_XCOFF32, Object) { +uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { + return fileHeader64()->NumberOfSymTableEntries; +} - // Current location within the file. - uint64_t CurPtr = 0; +uint16_t XCOFFObjectFile::getFlags() const { + return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; +} - if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr))) - return; +const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; +} - CurPtr += getFileHeaderSize(); - // TODO FIXME we don't have support for an optional header yet, so just skip - // past it. - CurPtr += FileHdrPtr->AuxHeaderSize; +uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { + return reinterpret_cast(SectionHeaderTable); +} - if (getNumberOfSections() != 0) { - if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr, - getNumberOfSections() * getSectionHeaderSize()))) - return; - } +int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; +} - if (getLogicalNumberOfSymbolTableEntries() == 0) - return; +XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) + : ObjectFile(Type, Object) { + assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); +} - // Get pointer to the symbol table. - CurPtr = FileHdrPtr->SymbolTableOffset; - uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * - getLogicalNumberOfSymbolTableEntries(); +ArrayRef XCOFFObjectFile::sections64() const { + assert(is64Bit() && "64-bit interface called for non 64-bit file."); + const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); + return ArrayRef(TablePtr, + TablePtr + getNumberOfSections()); +} - if ((EC = getObject(SymbolTblPtr, Data, base() + CurPtr, SymbolTableSize))) - return; +ArrayRef XCOFFObjectFile::sections32() const { + assert(!is64Bit() && "32-bit interface called for non 32-bit file."); + const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); + return ArrayRef(TablePtr, + TablePtr + getNumberOfSections()); +} - // Move pointer to the string table. - CurPtr += SymbolTableSize; +Expected +XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { + // If there is a string table, then the buffer must contain at least 4 bytes + // for the string table's size. Not having a string table is not an error. + if (auto EC = Binary::checkOffset( + Obj->Data, reinterpret_cast(Obj->base()) + Offset, 4)) + return XCOFFStringTable{0, nullptr}; - if (CurPtr + 4 > Data.getBufferSize()) - return; + // Read the size out of the buffer. + uint32_t Size = support::endian::read32be(Obj->base() + Offset); - StringTable.Size = support::endian::read32be(base() + CurPtr); + // If the size is less then 4, then the string table is just a size and no + // string data. + if (Size <= 4) + return XCOFFStringTable{4, nullptr}; - if (StringTable.Size <= 4) - return; + auto StringTableOrErr = + getObject(Obj->Data, Obj->base() + Offset, Size); + if (Error E = StringTableOrErr.takeError()) + return std::move(E); - // Check for whether the String table has the size indicated by length - // field - if (!checkSize(Data, EC, CurPtr, StringTable.Size)) - return; + const char *StringTablePtr = StringTableOrErr.get(); + if (StringTablePtr[Size - 1] != '\0') + return errorCodeToError(object_error::string_table_non_null_end); - StringTable.Data = reinterpret_cast(base() + CurPtr); - if (StringTable.Data[StringTable.Size - 1] != '\0') { - EC = object_error::string_table_non_null_end; - return; + return XCOFFStringTable{Size, StringTablePtr}; +} + +Expected> +XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { + // Can't use make_unique because of the private constructor. + std::unique_ptr Obj; + Obj.reset(new XCOFFObjectFile(Type, MBR)); + + uint64_t CurOffset = 0; + const auto *Base = Obj->base(); + MemoryBufferRef Data = Obj->Data; + + // Parse file header. + auto FileHeaderOrErr = + getObject(Data, Base + CurOffset, Obj->getFileHeaderSize()); + if (Error E = FileHeaderOrErr.takeError()) + return std::move(E); + Obj->FileHeader = FileHeaderOrErr.get(); + + CurOffset += Obj->getFileHeaderSize(); + // TODO FIXME we don't have support for an optional header yet, so just skip + // past it. + CurOffset += Obj->getOptionalHeaderSize(); + + // Parse the section header table if it is present. + if (Obj->getNumberOfSections()) { + auto SecHeadersOrErr = getObject(Data, Base + CurOffset, + Obj->getNumberOfSections() * + Obj->getSectionHeaderSize()); + if (Error E = SecHeadersOrErr.takeError()) + return std::move(E); + Obj->SectionHeaderTable = SecHeadersOrErr.get(); } + + // 64-bit object supports only file header and section headers for now. + if (Obj->is64Bit()) + return std::move(Obj); + + // If there is no symbol table we are done parsing the memory buffer. + if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0) + return std::move(Obj); + + // Parse symbol table. + CurOffset = Obj->fileHeader32()->SymbolTableOffset; + uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * + Obj->getLogicalNumberOfSymbolTableEntries32(); + auto SymTableOrErr = + getObject(Data, Base + CurOffset, SymbolTableSize); + if (Error E = SymTableOrErr.takeError()) + return std::move(E); + Obj->SymbolTblPtr = SymTableOrErr.get(); + CurOffset += SymbolTableSize; + + // Parse String table. + Expected StringTableOrErr = + parseStringTable(Obj.get(), CurOffset); + if (Error E = StringTableOrErr.takeError()) + return std::move(E); + Obj->StringTable = StringTableOrErr.get(); + + return std::move(Obj); } Expected> -ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) { - StringRef Data = Object.getBuffer(); - file_magic Type = identify_magic(Data); - std::error_code EC; - std::unique_ptr Ret; - - if (Type == file_magic::xcoff_object_32) { - Ret.reset(new XCOFFObjectFile(Object, EC)); - } else { - llvm_unreachable("Encountered an unexpected binary file type!"); - } +ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, + unsigned FileType) { + return XCOFFObjectFile::create(FileType, MemBufRef); +} - if (EC) - return errorCodeToError(EC); - return std::move(Ret); +StringRef XCOFFSectionHeader32::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); +} + +StringRef XCOFFSectionHeader64::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); } } // namespace object diff --git a/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-64.o b/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-64.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ void printSectionHeaders(ArrayRef Sections); + const XCOFFObjectFile &Obj; + + // Least significant 3 bits are reserved. + static constexpr unsigned SectionFlagsReservedMask = 0x7; }; } // anonymous namespace @@ -65,12 +70,20 @@ TimeStamp); } - W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset()); - int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries(); - if (SymTabEntries >= 0) - W.printNumber("SymbolTableEntries", SymTabEntries); - else - W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); + // The number of symbol table entries is an unsigned value in 64-bit objects + // and a signed value (with negative values being 'reserved') in 32-bit + // objects. + if (Obj.is64Bit()) { + W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64()); + W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64()); + } else { + W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32()); + int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); + if (SymTabEntries >= 0) + W.printNumber("SymbolTableEntries", SymTabEntries); + else + W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); + } W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); W.printHex("Flags", Obj.getFlags()); @@ -80,7 +93,10 @@ } void XCOFFDumper::printSectionHeaders() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + if (Obj.is64Bit()) + printSectionHeaders(Obj.sections64()); + else + printSectionHeaders(Obj.sections32()); } void XCOFFDumper::printRelocations() { @@ -107,6 +123,58 @@ llvm_unreachable("Unimplemented functionality for XCOFFDumper"); } +static const EnumEntry SectionTypeFlagsNames[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT), + ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT), + ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS), + ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK), + ECase(STYP_OVRFLO) +#undef ECase +}; + +template +void XCOFFDumper::printSectionHeaders(ArrayRef Sections) { + ListScope Group(W, "Sections"); + + uint16_t Index = 1; + for (const T &Sec : Sections) { + DictScope SecDS(W, "Section"); + + W.printNumber("Index", Index++); + W.printString("Name", Sec.getName()); + + W.printHex("PhysicalAddress", Sec.PhysicalAddress); + W.printHex("VirtualAddress", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + + // TODO Need to add overflow handling (when NumberOfX == STYP_OVRFLO). + W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); + W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); + + // The most significant 16-bits represent the DWARF section subtype. For + // now we just dump the section type flags. + uint16_t Flags = Sec.Flags & 0xffffu; + if (Flags & SectionFlagsReservedMask) + W.printHex("Flags", "Reserved", Flags); + else + W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames)); + } + + if (opts::SectionRelocations) + report_fatal_error("Dumping section relocations is unimplemented"); + + if (opts::SectionSymbols) + report_fatal_error("Dumping symbols is unimplemented"); + + if (opts::SectionData) + report_fatal_error("Dumping section data is unimplemented"); +} + namespace llvm { std::error_code createXCOFFDumper(const object::ObjectFile *Obj, ScopedPrinter &Writer, diff --git a/llvm/tools/obj2yaml/xcoff2yaml.cpp b/llvm/tools/obj2yaml/xcoff2yaml.cpp --- a/llvm/tools/obj2yaml/xcoff2yaml.cpp +++ b/llvm/tools/obj2yaml/xcoff2yaml.cpp @@ -29,22 +29,25 @@ } // namespace std::error_code XCOFFDumper::dump() { - std::error_code EC; dumpHeader(); - EC = dumpSymbols(); - return EC; + return dumpSymbols(); } void XCOFFDumper::dumpHeader() { - const XCOFFFileHeader *FileHdrPtr = Obj.getFileHeader(); - - YAMLObj.Header.Magic = FileHdrPtr->Magic; - YAMLObj.Header.NumberOfSections = FileHdrPtr->NumberOfSections; - YAMLObj.Header.TimeStamp = FileHdrPtr->TimeStamp; - YAMLObj.Header.SymbolTableOffset = FileHdrPtr->SymbolTableOffset; - YAMLObj.Header.NumberOfSymTableEntries = FileHdrPtr->NumberOfSymTableEntries; - YAMLObj.Header.AuxHeaderSize = FileHdrPtr->AuxHeaderSize; - YAMLObj.Header.Flags = FileHdrPtr->Flags; + + YAMLObj.Header.Magic = Obj.getMagic(); + YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections(); + YAMLObj.Header.TimeStamp = Obj.getTimeStamp(); + + // TODO FIXME only dump 32 bit header for now. + if (Obj.is64Bit()) + report_fatal_error("64-bit XCOFF files not supported yet."); + YAMLObj.Header.SymbolTableOffset = Obj.getSymbolTableOffset32(); + + YAMLObj.Header.NumberOfSymTableEntries = + Obj.getRawNumberOfSymbolTableEntries32(); + YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize(); + YAMLObj.Header.Flags = Obj.getFlags(); } std::error_code XCOFFDumper::dumpSymbols() {