mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-30 00:24:00 +00:00
[Object][XCOFF] Add support for 64-bit file header and section header dumping.
Adds a readobj dumper for 32-bit and 64-bit section header tables, and extend support for the file-header dumping to include 64-bit object files. Also refactors the binary file parsing to be done in a helper function in an attempt to cleanup error handeling. Differential Revision: https://reviews.llvm.org/D63843 llvm-svn: 365524
This commit is contained in:
parent
7ca6dd8656
commit
aa1c5e5087
@ -46,6 +46,7 @@ struct file_magic {
|
||||
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
|
||||
};
|
||||
|
@ -51,7 +51,9 @@ protected:
|
||||
// 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 @@ public:
|
||||
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; }
|
||||
|
||||
|
@ -359,7 +359,7 @@ public:
|
||||
createCOFFObjectFile(MemoryBufferRef Object);
|
||||
|
||||
static Expected<std::unique_ptr<ObjectFile>>
|
||||
createXCOFFObjectFile(MemoryBufferRef Object);
|
||||
createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType);
|
||||
|
||||
static Expected<std::unique_ptr<ObjectFile>>
|
||||
createELFObjectFile(MemoryBufferRef Object);
|
||||
|
@ -34,7 +34,7 @@
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
||||
struct XCOFFFileHeader {
|
||||
struct XCOFFFileHeader32 {
|
||||
support::ubig16_t Magic;
|
||||
support::ubig16_t NumberOfSections;
|
||||
|
||||
@ -48,7 +48,21 @@ struct XCOFFFileHeader {
|
||||
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 @@ struct XCOFFSectionHeader {
|
||||
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 @@ struct XCOFFStringTable {
|
||||
|
||||
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<DataRefImpl> 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<std::unique_ptr<XCOFFObjectFile>> create(unsigned Type,
|
||||
MemoryBufferRef MBR);
|
||||
|
||||
// Helper for parsing the StringTable. Returns an 'Error' if parsing failed
|
||||
// and an XCOFFStringTable if parsing succeeded.
|
||||
static Expected<XCOFFStringTable> parseStringTable(const XCOFFObjectFile *Obj,
|
||||
uint64_t Offset);
|
||||
|
||||
// Make a friend so it can call the private 'create' function.
|
||||
friend Expected<std::unique_ptr<ObjectFile>>
|
||||
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 @@ public:
|
||||
Expected<uint64_t> 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 @@ public:
|
||||
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<XCOFFSectionHeader32> sections32() const;
|
||||
ArrayRef<XCOFFSectionHeader64> sections64() const;
|
||||
}; // XCOFFObjectFile
|
||||
|
||||
} // namespace object
|
||||
|
@ -66,6 +66,8 @@ file_magic llvm::identify_magic(StringRef Magic) {
|
||||
// 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
|
||||
|
@ -70,6 +70,7 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
|
||||
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:
|
||||
|
@ -150,7 +150,9 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) {
|
||||
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);
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
|
||||
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:
|
||||
|
@ -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 <typename T>
|
||||
static std::error_code getObject(const T *&Obj, MemoryBufferRef M,
|
||||
const void *Ptr,
|
||||
const uint64_t Size = sizeof(T)) {
|
||||
static Expected<const T *> 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<const T *>(Addr);
|
||||
return std::error_code();
|
||||
return errorCodeToError(EC);
|
||||
return reinterpret_cast<const T *>(Addr);
|
||||
}
|
||||
|
||||
static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
|
||||
return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
|
||||
Offset);
|
||||
}
|
||||
|
||||
template <typename T> static const T *viewAs(uintptr_t in) {
|
||||
@ -60,43 +48,69 @@ static StringRef generateStringRef(const char *Name, uint64_t Size) {
|
||||
: StringRef(Name, Size);
|
||||
}
|
||||
|
||||
const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const {
|
||||
auto Sec = viewAs<XCOFFSectionHeader>(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<XCOFFSectionHeader32>(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<XCOFFSectionHeader64>(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<XCOFFSymbolEntry>(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<const XCOFFFileHeader32 *>(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<const XCOFFFileHeader64 *>(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<const XCOFFSectionHeader32 *>(SectionHeaderTable);
|
||||
}
|
||||
|
||||
const XCOFFSectionHeader64 *
|
||||
XCOFFObjectFile::sectionHeaderTable64() const {
|
||||
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
|
||||
return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
|
||||
}
|
||||
|
||||
void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
|
||||
const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
|
||||
|
||||
SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
|
||||
Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
|
||||
}
|
||||
@ -158,14 +172,11 @@ XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
|
||||
if (isReservedSectionNumber(SectNum))
|
||||
return section_end();
|
||||
|
||||
const XCOFFSectionHeader *Sec;
|
||||
if (std::error_code EC = getSectionByNum(SectNum, Sec))
|
||||
return errorCodeToError(EC);
|
||||
Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
|
||||
if (!ExpSec)
|
||||
return ExpSec.takeError();
|
||||
|
||||
DataRefImpl SecDRI;
|
||||
SecDRI.p = reinterpret_cast<uintptr_t>(Sec);
|
||||
|
||||
return section_iterator(SectionRef(SecDRI, this));
|
||||
return section_iterator(SectionRef(ExpSec.get(), this));
|
||||
}
|
||||
|
||||
void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
|
||||
@ -174,25 +185,26 @@ void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
|
||||
}
|
||||
|
||||
Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
|
||||
const char *Name = toSection(Sec)->Name;
|
||||
auto NulCharPtr =
|
||||
static_cast<const char *>(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<ArrayRef<uint8_t>>
|
||||
@ -213,16 +225,16 @@ bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
|
||||
}
|
||||
|
||||
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 @@ uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
|
||||
}
|
||||
|
||||
basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
|
||||
assert(!is64Bit() && "64-bit support not implemented yet.");
|
||||
DataRefImpl SymDRI;
|
||||
SymDRI.p = reinterpret_cast<uintptr_t>(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<uintptr_t>(
|
||||
SymbolTblPtr + getLogicalNumberOfSymbolTableEntries());
|
||||
SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32());
|
||||
return basic_symbol_iterator(SymbolRef(SymDRI, this));
|
||||
}
|
||||
|
||||
section_iterator XCOFFObjectFile::section_begin() const {
|
||||
DataRefImpl DRI;
|
||||
DRI.p = reinterpret_cast<uintptr_t>(SectionHdrTablePtr);
|
||||
DRI.p = getSectionHeaderTableAddress();
|
||||
return section_iterator(SectionRef(DRI, this));
|
||||
}
|
||||
|
||||
section_iterator XCOFFObjectFile::section_end() const {
|
||||
DataRefImpl DRI;
|
||||
DRI.p =
|
||||
reinterpret_cast<uintptr_t>(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 @@ Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::error_code
|
||||
XCOFFObjectFile::getSectionByNum(int16_t Num,
|
||||
const XCOFFSectionHeader *&Result) const {
|
||||
if (Num > 0 && static_cast<uint16_t>(Num) <= getNumberOfSections()) {
|
||||
Result = SectionHdrTablePtr + (Num - 1);
|
||||
return std::error_code();
|
||||
}
|
||||
size_t XCOFFObjectFile::getFileHeaderSize() const {
|
||||
return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
|
||||
}
|
||||
|
||||
return object_error::invalid_section_index;
|
||||
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<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
|
||||
if (Num <= 0 || Num > getNumberOfSections())
|
||||
return errorCodeToError(object_error::invalid_section_index);
|
||||
|
||||
DataRefImpl DRI;
|
||||
DRI.p = getWithOffset(getSectionHeaderTableAddress(),
|
||||
getSectionHeaderSize() * (Num - 1));
|
||||
return DRI;
|
||||
}
|
||||
|
||||
Expected<StringRef>
|
||||
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 @@ XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
|
||||
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<DataRefImpl> SecRef = getSectionByNum(SectionNum);
|
||||
if (SecRef)
|
||||
return generateStringRef(getSectionNameInternal(SecRef.get()),
|
||||
XCOFF::SectionNameSize);
|
||||
return SecRef.takeError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,99 +396,180 @@ bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
|
||||
}
|
||||
|
||||
uint16_t XCOFFObjectFile::getNumberOfSections() const {
|
||||
return FileHdrPtr->NumberOfSections;
|
||||
return is64Bit() ? fileHeader64()->NumberOfSections
|
||||
: fileHeader32()->NumberOfSections;
|
||||
}
|
||||
|
||||
int32_t XCOFFObjectFile::getTimeStamp() const { return FileHdrPtr->TimeStamp; }
|
||||
|
||||
uint32_t XCOFFObjectFile::getSymbolTableOffset() const {
|
||||
return FileHdrPtr->SymbolTableOffset;
|
||||
}
|
||||
|
||||
int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries() const {
|
||||
return FileHdrPtr->NumberOfSymTableEntries;
|
||||
}
|
||||
|
||||
uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries() const {
|
||||
return (FileHdrPtr->NumberOfSymTableEntries >= 0
|
||||
? FileHdrPtr->NumberOfSymTableEntries
|
||||
: 0);
|
||||
int32_t XCOFFObjectFile::getTimeStamp() const {
|
||||
return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
|
||||
}
|
||||
|
||||
uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
|
||||
return FileHdrPtr->AuxHeaderSize;
|
||||
return is64Bit() ? fileHeader64()->AuxHeaderSize
|
||||
: fileHeader32()->AuxHeaderSize;
|
||||
}
|
||||
|
||||
XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
|
||||
: ObjectFile(Binary::ID_XCOFF32, Object) {
|
||||
uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
|
||||
return fileHeader32()->SymbolTableOffset;
|
||||
}
|
||||
|
||||
// Current location within the file.
|
||||
uint64_t CurPtr = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr)))
|
||||
return;
|
||||
uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
|
||||
return (fileHeader32()->NumberOfSymTableEntries >= 0
|
||||
? fileHeader32()->NumberOfSymTableEntries
|
||||
: 0);
|
||||
}
|
||||
|
||||
CurPtr += getFileHeaderSize();
|
||||
uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
|
||||
return fileHeader64()->SymbolTableOffset;
|
||||
}
|
||||
|
||||
uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
|
||||
return fileHeader64()->NumberOfSymTableEntries;
|
||||
}
|
||||
|
||||
uint16_t XCOFFObjectFile::getFlags() const {
|
||||
return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
|
||||
}
|
||||
|
||||
const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
|
||||
return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
|
||||
}
|
||||
|
||||
uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
|
||||
return reinterpret_cast<uintptr_t>(SectionHeaderTable);
|
||||
}
|
||||
|
||||
int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
|
||||
return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
|
||||
}
|
||||
|
||||
XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
|
||||
: ObjectFile(Type, Object) {
|
||||
assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
|
||||
}
|
||||
|
||||
ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
|
||||
assert(is64Bit() && "64-bit interface called for non 64-bit file.");
|
||||
const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
|
||||
return ArrayRef<XCOFFSectionHeader64>(TablePtr,
|
||||
TablePtr + getNumberOfSections());
|
||||
}
|
||||
|
||||
ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
|
||||
assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
|
||||
const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
|
||||
return ArrayRef<XCOFFSectionHeader32>(TablePtr,
|
||||
TablePtr + getNumberOfSections());
|
||||
}
|
||||
|
||||
Expected<XCOFFStringTable>
|
||||
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<uintptr_t>(Obj->base() + Offset), 4))
|
||||
return XCOFFStringTable{0, nullptr};
|
||||
|
||||
// Read the size out of the buffer.
|
||||
uint32_t Size = support::endian::read32be(Obj->base() + Offset);
|
||||
|
||||
// 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};
|
||||
|
||||
auto StringTableOrErr =
|
||||
getObject<char>(Obj->Data, Obj->base() + Offset, Size);
|
||||
if (Error E = StringTableOrErr.takeError())
|
||||
return std::move(E);
|
||||
|
||||
const char *StringTablePtr = StringTableOrErr.get();
|
||||
if (StringTablePtr[Size - 1] != '\0')
|
||||
return errorCodeToError(object_error::string_table_non_null_end);
|
||||
|
||||
return XCOFFStringTable{Size, StringTablePtr};
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<XCOFFObjectFile>>
|
||||
XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
|
||||
// Can't use make_unique because of the private constructor.
|
||||
std::unique_ptr<XCOFFObjectFile> 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<void>(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.
|
||||
CurPtr += FileHdrPtr->AuxHeaderSize;
|
||||
CurOffset += Obj->getOptionalHeaderSize();
|
||||
|
||||
if (getNumberOfSections() != 0) {
|
||||
if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr,
|
||||
getNumberOfSections() * getSectionHeaderSize())))
|
||||
return;
|
||||
// Parse the section header table if it is present.
|
||||
if (Obj->getNumberOfSections()) {
|
||||
auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset,
|
||||
Obj->getNumberOfSections() *
|
||||
Obj->getSectionHeaderSize());
|
||||
if (Error E = SecHeadersOrErr.takeError())
|
||||
return std::move(E);
|
||||
Obj->SectionHeaderTable = SecHeadersOrErr.get();
|
||||
}
|
||||
|
||||
if (getLogicalNumberOfSymbolTableEntries() == 0)
|
||||
return;
|
||||
// 64-bit object supports only file header and section headers for now.
|
||||
if (Obj->is64Bit())
|
||||
return std::move(Obj);
|
||||
|
||||
// Get pointer to the symbol table.
|
||||
CurPtr = FileHdrPtr->SymbolTableOffset;
|
||||
// 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)) *
|
||||
getLogicalNumberOfSymbolTableEntries();
|
||||
Obj->getLogicalNumberOfSymbolTableEntries32();
|
||||
auto SymTableOrErr =
|
||||
getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize);
|
||||
if (Error E = SymTableOrErr.takeError())
|
||||
return std::move(E);
|
||||
Obj->SymbolTblPtr = SymTableOrErr.get();
|
||||
CurOffset += SymbolTableSize;
|
||||
|
||||
if ((EC = getObject(SymbolTblPtr, Data, base() + CurPtr, SymbolTableSize)))
|
||||
return;
|
||||
// Parse String table.
|
||||
Expected<XCOFFStringTable> StringTableOrErr =
|
||||
parseStringTable(Obj.get(), CurOffset);
|
||||
if (Error E = StringTableOrErr.takeError())
|
||||
return std::move(E);
|
||||
Obj->StringTable = StringTableOrErr.get();
|
||||
|
||||
// Move pointer to the string table.
|
||||
CurPtr += SymbolTableSize;
|
||||
|
||||
if (CurPtr + 4 > Data.getBufferSize())
|
||||
return;
|
||||
|
||||
StringTable.Size = support::endian::read32be(base() + CurPtr);
|
||||
|
||||
if (StringTable.Size <= 4)
|
||||
return;
|
||||
|
||||
// Check for whether the String table has the size indicated by length
|
||||
// field
|
||||
if (!checkSize(Data, EC, CurPtr, StringTable.Size))
|
||||
return;
|
||||
|
||||
StringTable.Data = reinterpret_cast<const char *>(base() + CurPtr);
|
||||
if (StringTable.Data[StringTable.Size - 1] != '\0') {
|
||||
EC = object_error::string_table_non_null_end;
|
||||
return;
|
||||
}
|
||||
return std::move(Obj);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<ObjectFile>>
|
||||
ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) {
|
||||
StringRef Data = Object.getBuffer();
|
||||
file_magic Type = identify_magic(Data);
|
||||
std::error_code EC;
|
||||
std::unique_ptr<ObjectFile> Ret;
|
||||
ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
|
||||
unsigned FileType) {
|
||||
return XCOFFObjectFile::create(FileType, MemBufRef);
|
||||
}
|
||||
|
||||
if (Type == file_magic::xcoff_object_32) {
|
||||
Ret.reset(new XCOFFObjectFile(Object, EC));
|
||||
} else {
|
||||
llvm_unreachable("Encountered an unexpected binary file type!");
|
||||
}
|
||||
StringRef XCOFFSectionHeader32::getName() const {
|
||||
return generateStringRef(Name, XCOFF::SectionNameSize);
|
||||
}
|
||||
|
||||
if (EC)
|
||||
return errorCodeToError(EC);
|
||||
return std::move(Ret);
|
||||
StringRef XCOFFSectionHeader64::getName() const {
|
||||
return generateStringRef(Name, XCOFF::SectionNameSize);
|
||||
}
|
||||
|
||||
} // namespace object
|
||||
|
BIN
test/tools/llvm-readobj/Inputs/xcoff-basic-64.o
Normal file
BIN
test/tools/llvm-readobj/Inputs/xcoff-basic-64.o
Normal file
Binary file not shown.
@ -1,5 +1,8 @@
|
||||
# RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic.o | \
|
||||
# RUN: FileCheck --check-prefix=FILEHEADER %s
|
||||
#
|
||||
# RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic-64.o | \
|
||||
# RUN: FileCheck --check-prefix=FILEHEADER64 %s
|
||||
|
||||
# RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic-neg-time.o | \
|
||||
# RUN: FileCheck --check-prefix=NEGTIME %s
|
||||
@ -21,6 +24,20 @@
|
||||
# FILEHEADER-NEXT: Flags: 0x0
|
||||
# FILEHEADER-NEXT: }
|
||||
|
||||
# FILEHEADER64: File: {{.*}}xcoff-basic-64.o
|
||||
# FILEHEADER64-NEXT: Format: aix5coff64-rs6000
|
||||
# FILEHEADER64-NEXT: Arch: powerpc64
|
||||
# FILEHEADER64-NEXT: AddressSize: 64bit
|
||||
# FILEHEADER64-NEXT: FileHeader {
|
||||
# FILEHEADER64-NEXT: Magic: 0x1F7
|
||||
# FILEHEADER64-NEXT: NumberOfSections: 5
|
||||
# FILEHEADER64-NEXT: TimeStamp: 2019-03-18T20:03:47Z (0x5C8FF9A3)
|
||||
# FILEHEADER64-NEXT: SymbolTableOffset: 0x54C
|
||||
# FILEHEADER64-NEXT: SymbolTableEntries: 58
|
||||
# FILEHEADER64-NEXT: OptionalHeaderSize: 0x0
|
||||
# FILEHEADER64-NEXT: Flags: 0x0
|
||||
# FILEHEADER64-NEXT: }
|
||||
|
||||
# NEGTIME: File: {{.*}}xcoff-basic-neg-time.o
|
||||
# NEGTIME-NEXT: Format: aixcoff-rs6000
|
||||
# NEGTIME-NEXT: Arch: powerpc
|
||||
|
164
test/tools/llvm-readobj/xcoff-sections.test
Normal file
164
test/tools/llvm-readobj/xcoff-sections.test
Normal file
@ -0,0 +1,164 @@
|
||||
# RUN: llvm-readobj --section-headers %p/Inputs/xcoff-basic.o | \
|
||||
# RUN: FileCheck --check-prefix=SEC32 %s
|
||||
|
||||
# RUN: llvm-readobj --section-headers %p/Inputs/xcoff-basic-64.o | \
|
||||
# RUN: FileCheck --check-prefix=SEC64 %s
|
||||
|
||||
# SEC32: File: {{.*}}xcoff-basic.o
|
||||
# SEC32-NEXT: Format: aixcoff-rs6000
|
||||
# SEC32-NEXT: Arch: powerpc
|
||||
# SEC32-NEXT: AddressSize: 32bit
|
||||
# SEC32-NEXT: Sections [
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 1
|
||||
# SEC32-NEXT: Name: .text
|
||||
# SEC32-NEXT: PhysicalAddress: 0x0
|
||||
# SEC32-NEXT: VirtualAddress: 0x0
|
||||
# SEC32-NEXT: Size: 0x100
|
||||
# SEC32-NEXT: RawDataOffset: 0x200
|
||||
# SEC32-NEXT: RelocationPointer: 0x3D8
|
||||
# SEC32-NEXT: LineNumberPointer: 0x4E6
|
||||
# SEC32-NEXT: NumberOfRelocations: 8
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 12
|
||||
# SEC32-NEXT: Type: STYP_TEXT (0x20)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 2
|
||||
# SEC32-NEXT: Name: .data
|
||||
# SEC32-NEXT: PhysicalAddress: 0x100
|
||||
# SEC32-NEXT: VirtualAddress: 0x100
|
||||
# SEC32-NEXT: Size: 0x68
|
||||
# SEC32-NEXT: RawDataOffset: 0x300
|
||||
# SEC32-NEXT: RelocationPointer: 0x428
|
||||
# SEC32-NEXT: LineNumberPointer: 0x0
|
||||
# SEC32-NEXT: NumberOfRelocations: 19
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC32-NEXT: Type: STYP_DATA (0x40)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 3
|
||||
# SEC32-NEXT: Name: .bss
|
||||
# SEC32-NEXT: PhysicalAddress: 0x168
|
||||
# SEC32-NEXT: VirtualAddress: 0x168
|
||||
# SEC32-NEXT: Size: 0x4
|
||||
# SEC32-NEXT: RawDataOffset: 0x0
|
||||
# SEC32-NEXT: RelocationPointer: 0x0
|
||||
# SEC32-NEXT: LineNumberPointer: 0x0
|
||||
# SEC32-NEXT: NumberOfRelocations: 0
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC32-NEXT: Type: STYP_BSS (0x80)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 4
|
||||
# SEC32-NEXT: Name: .tdata
|
||||
# SEC32-NEXT: PhysicalAddress: 0x0
|
||||
# SEC32-NEXT: VirtualAddress: 0x0
|
||||
# SEC32-NEXT: Size: 0x4
|
||||
# SEC32-NEXT: RawDataOffset: 0x368
|
||||
# SEC32-NEXT: RelocationPointer: 0x47A
|
||||
# SEC32-NEXT: LineNumberPointer: 0x0
|
||||
# SEC32-NEXT: NumberOfRelocations: 0
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC32-NEXT: Type: STYP_TDATA (0x400)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 5
|
||||
# SEC32-NEXT: Name: .tbss
|
||||
# SEC32-NEXT: PhysicalAddress: 0x4
|
||||
# SEC32-NEXT: VirtualAddress: 0x4
|
||||
# SEC32-NEXT: Size: 0x8
|
||||
# SEC32-NEXT: RawDataOffset: 0x0
|
||||
# SEC32-NEXT: RelocationPointer: 0x0
|
||||
# SEC32-NEXT: LineNumberPointer: 0x0
|
||||
# SEC32-NEXT: NumberOfRelocations: 0
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC32-NEXT: Type: STYP_TBSS (0x800)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: Section {
|
||||
# SEC32-NEXT: Index: 6
|
||||
# SEC32-NEXT: Name: .debug
|
||||
# SEC32-NEXT: PhysicalAddress: 0x0
|
||||
# SEC32-NEXT: VirtualAddress: 0x0
|
||||
# SEC32-NEXT: Size: 0x6C
|
||||
# SEC32-NEXT: RawDataOffset: 0x36C
|
||||
# SEC32-NEXT: RelocationPointer: 0x0
|
||||
# SEC32-NEXT: LineNumberPointer: 0x0
|
||||
# SEC32-NEXT: NumberOfRelocations: 0
|
||||
# SEC32-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC32-NEXT: Type: STYP_DEBUG (0x2000)
|
||||
# SEC32-NEXT: }
|
||||
# SEC32-NEXT: ]
|
||||
|
||||
|
||||
# SEC64: File: {{.*}}xcoff-basic-64.o
|
||||
# SEC64-NEXT: Format: aix5coff64-rs6000
|
||||
# SEC64-NEXT: Arch: powerpc64
|
||||
# SEC64-NEXT: AddressSize: 64bit
|
||||
# SEC64-NEXT: Sections [
|
||||
# SEC64-NEXT: Section {
|
||||
# SEC64-NEXT: Index: 1
|
||||
# SEC64-NEXT: Name: .text
|
||||
# SEC64-NEXT: PhysicalAddress: 0x0
|
||||
# SEC64-NEXT: VirtualAddress: 0x0
|
||||
# SEC64-NEXT: Size: 0x100
|
||||
# SEC64-NEXT: RawDataOffset: 0x200
|
||||
# SEC64-NEXT: RelocationPointer: 0x3C4
|
||||
# SEC64-NEXT: LineNumberPointer: 0x0
|
||||
# SEC64-NEXT: NumberOfRelocations: 9
|
||||
# SEC64-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC64-NEXT: Type: STYP_TEXT (0x20)
|
||||
# SEC64-NEXT: }
|
||||
# SEC64-NEXT: Section {
|
||||
# SEC64-NEXT: Index: 2
|
||||
# SEC64-NEXT: Name: .data
|
||||
# SEC64-NEXT: PhysicalAddress: 0x100
|
||||
# SEC64-NEXT: VirtualAddress: 0x100
|
||||
# SEC64-NEXT: Size: 0xC0
|
||||
# SEC64-NEXT: RawDataOffset: 0x300
|
||||
# SEC64-NEXT: RelocationPointer: 0x442
|
||||
# SEC64-NEXT: LineNumberPointer: 0x0
|
||||
# SEC64-NEXT: NumberOfRelocations: 19
|
||||
# SEC64-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC64-NEXT: Type: STYP_DATA (0x40)
|
||||
# SEC64-NEXT: }
|
||||
# SEC64-NEXT: Section {
|
||||
# SEC64-NEXT: Index: 3
|
||||
# SEC64-NEXT: Name: .bss
|
||||
# SEC64-NEXT: PhysicalAddress: 0x1C0
|
||||
# SEC64-NEXT: VirtualAddress: 0x1C0
|
||||
# SEC64-NEXT: Size: 0x8
|
||||
# SEC64-NEXT: RawDataOffset: 0x0
|
||||
# SEC64-NEXT: RelocationPointer: 0x0
|
||||
# SEC64-NEXT: LineNumberPointer: 0x0
|
||||
# SEC64-NEXT: NumberOfRelocations: 0
|
||||
# SEC64-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC64-NEXT: Type: STYP_BSS (0x80)
|
||||
# SEC64-NEXT: }
|
||||
# SEC64-NEXT: Section {
|
||||
# SEC64-NEXT: Index: 4
|
||||
# SEC64-NEXT: Name: .tdata
|
||||
# SEC64-NEXT: PhysicalAddress: 0x0
|
||||
# SEC64-NEXT: VirtualAddress: 0x0
|
||||
# SEC64-NEXT: Size: 0x4
|
||||
# SEC64-NEXT: RawDataOffset: 0x3C0
|
||||
# SEC64-NEXT: RelocationPointer: 0x54C
|
||||
# SEC64-NEXT: LineNumberPointer: 0x0
|
||||
# SEC64-NEXT: NumberOfRelocations: 0
|
||||
# SEC64-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC64-NEXT: Type: STYP_TDATA (0x400)
|
||||
# SEC64-NEXT: }
|
||||
# SEC64-NEXT: Section {
|
||||
# SEC64-NEXT: Index: 5
|
||||
# SEC64-NEXT: Name: .tbss
|
||||
# SEC64-NEXT: PhysicalAddress: 0x4
|
||||
# SEC64-NEXT: VirtualAddress: 0x4
|
||||
# SEC64-NEXT: Size: 0x8
|
||||
# SEC64-NEXT: RawDataOffset: 0x0
|
||||
# SEC64-NEXT: RelocationPointer: 0x0
|
||||
# SEC64-NEXT: LineNumberPointer: 0x0
|
||||
# SEC64-NEXT: NumberOfRelocations: 0
|
||||
# SEC64-NEXT: NumberOfLineNumbers: 0
|
||||
# SEC64-NEXT: Type: STYP_TBSS (0x800)
|
||||
# SEC64-NEXT: }
|
||||
# SEC64-NEXT: ]
|
||||
|
@ -36,7 +36,12 @@ public:
|
||||
void printNeededLibraries() override;
|
||||
|
||||
private:
|
||||
template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
|
||||
|
||||
const XCOFFObjectFile &Obj;
|
||||
|
||||
// Least significant 3 bits are reserved.
|
||||
static constexpr unsigned SectionFlagsReservedMask = 0x7;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
@ -65,12 +70,20 @@ void XCOFFDumper::printFileHeaders() {
|
||||
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::printFileHeaders() {
|
||||
}
|
||||
|
||||
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,59 @@ void XCOFFDumper::printNeededLibraries() {
|
||||
llvm_unreachable("Unimplemented functionality for XCOFFDumper");
|
||||
}
|
||||
|
||||
static const EnumEntry<XCOFF::SectionTypeFlags> 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 <typename T>
|
||||
void XCOFFDumper::printSectionHeaders(ArrayRef<T> 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 == _OVERFLOW_MARKER
|
||||
// in 32-bit object files.
|
||||
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,
|
||||
|
@ -29,22 +29,25 @@ public:
|
||||
} // 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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user