diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 38ea814ed1c8..d7965a33e7c1 100644 --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -250,6 +250,7 @@ private: friend class ExportDirectoryEntryRef; const coff_file_header *COFFHeader; const pe32_header *PE32Header; + const pe32plus_header *PE32PlusHeader; const data_directory *DataDirectory; const coff_section *SectionTable; const coff_symbol *SymbolTable; @@ -347,6 +348,7 @@ public: error_code getHeader(const coff_file_header *&Res) const; error_code getCOFFHeader(const coff_file_header *&Res) const; error_code getPE32Header(const pe32_header *&Res) const; + error_code getPE32PlusHeader(const pe32plus_header *&Res) const; error_code getDataDirectory(uint32_t index, const data_directory *&Res) const; error_code getSection(int32_t index, const coff_section *&Res) const; error_code getSymbol(uint32_t index, const coff_symbol *&Res) const; diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index c28f88484fb1..1558d9d15fd6 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -466,8 +466,8 @@ error_code COFFObjectFile::initExportTablePtr() { COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &EC, bool BufferOwned) : ObjectFile(Binary::ID_COFF, Object, BufferOwned), COFFHeader(0), - PE32Header(0), DataDirectory(0), SectionTable(0), SymbolTable(0), - StringTable(0), StringTableSize(0), ImportDirectory(0), + PE32Header(0), PE32PlusHeader(0), DataDirectory(0), SectionTable(0), + SymbolTable(0), StringTable(0), StringTableSize(0), ImportDirectory(0), NumberOfImportDirectory(0), ExportDirectory(0) { // Check that we at least have enough room for a header. if (!checkSize(Data, EC, sizeof(coff_file_header))) return; @@ -499,19 +499,27 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &EC, CurPtr += sizeof(coff_file_header); if (HasPEHeader) { - if ((EC = getObject(PE32Header, Data, base() + CurPtr))) + const pe32_header *Header; + if ((EC = getObject(Header, Data, base() + CurPtr))) + return; + + const uint8_t *DataDirAddr; + uint64_t DataDirSize; + if (Header->Magic == 0x10b) { + PE32Header = Header; + DataDirAddr = base() + CurPtr + sizeof(pe32_header); + DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; + } else if (Header->Magic == 0x20b) { + PE32PlusHeader = reinterpret_cast(Header); + DataDirAddr = base() + CurPtr + sizeof(pe32plus_header); + DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize; + } else { + // It's neither PE32 nor PE32+. + EC = object_error::parse_failed; return; - if (PE32Header->Magic != 0x10b) { - // We only support PE32. If this is PE32 (not PE32+), the magic byte - // should be 0x10b. If this is not PE32, continue as if there's no PE - // header in this file. - PE32Header = 0; - } else if (PE32Header->NumberOfRvaAndSize > 0) { - const uint8_t *Addr = base() + CurPtr + sizeof(pe32_header); - uint64_t size = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; - if ((EC = getObject(DataDirectory, Data, Addr, size))) - return; } + if ((EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))) + return; CurPtr += COFFHeader->SizeOfOptionalHeader; } @@ -655,10 +663,21 @@ error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { return object_error::success; } +error_code +COFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const { + Res = PE32PlusHeader; + return object_error::success; +} + error_code COFFObjectFile::getDataDirectory(uint32_t Index, const data_directory *&Res) const { // Error if if there's no data directory or the index is out of range. - if (!DataDirectory || Index > PE32Header->NumberOfRvaAndSize) + if (!DataDirectory) + return object_error::parse_failed; + assert(PE32Header || PE32PlusHeader); + uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize + : PE32PlusHeader->NumberOfRvaAndSize; + if (Index > NumEnt) return object_error::parse_failed; Res = &DataDirectory[Index]; return object_error::success; diff --git a/llvm/test/tools/llvm-readobj/Inputs/nop.exe.coff-x86-64 b/llvm/test/tools/llvm-readobj/Inputs/nop.exe.coff-x86-64 new file mode 100644 index 000000000000..62b3b46c369c Binary files /dev/null and b/llvm/test/tools/llvm-readobj/Inputs/nop.exe.coff-x86-64 differ diff --git a/llvm/test/tools/llvm-readobj/peplus.test b/llvm/test/tools/llvm-readobj/peplus.test new file mode 100644 index 000000000000..13c3f160055b --- /dev/null +++ b/llvm/test/tools/llvm-readobj/peplus.test @@ -0,0 +1,82 @@ +RUN: llvm-readobj -file-headers %p/Inputs/nop.exe.coff-x86-64 | FileCheck %s + +CHECK: Format: COFF-x86-64 +CHECK: Arch: x86_64 +CHECK: AddressSize: 64bit +CHECK: ImageFileHeader { +CHECK: Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) +CHECK: SectionCount: 1 +CHECK: TimeDateStamp: 2014-01-26 03:43:56 (0x52E4847C) +CHECK: PointerToSymbolTable: 0x0 +CHECK: SymbolCount: 0 +CHECK: OptionalHeaderSize: 240 +CHECK: Characteristics [ (0x22) +CHECK: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) +CHECK: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20) +CHECK: ] +CHECK: } +CHECK: ImageOptionalHeader { +CHECK: MajorLinkerVersion: 11 +CHECK: MinorLinkerVersion: 0 +CHECK: SizeOfCode: 512 +CHECK: SizeOfInitializedData: 0 +CHECK: SizeOfUninitializedData: 0 +CHECK: AddressOfEntryPoint: 0x1000 +CHECK: BaseOfCode: 0x1000 +CHECK: ImageBase: 0x140000000 +CHECK: SectionAlignment: 4096 +CHECK: FileAlignment: 512 +CHECK: MajorOperatingSystemVersion: 6 +CHECK: MinorOperatingSystemVersion: 0 +CHECK: MajorImageVersion: 0 +CHECK: MinorImageVersion: 0 +CHECK: MajorSubsystemVersion: 6 +CHECK: MinorSubsystemVersion: 0 +CHECK: SizeOfImage: 8192 +CHECK: SizeOfHeaders: 512 +CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) +CHECK: Subsystem [ (0x8160) +CHECK: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) +CHECK: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) +CHECK: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) +CHECK: ] +CHECK: SizeOfStackReserve: 1048576 +CHECK: SizeOfStackCommit: 4096 +CHECK: SizeOfHeapReserve: 1048576 +CHECK: SizeOfHeapCommit: 4096 +CHECK: NumberOfRvaAndSize: 16 +CHECK: DataDirectory { +CHECK: ExportTableRVA: 0x0 +CHECK: ExportTableSize: 0x0 +CHECK: ImportTableRVA: 0x0 +CHECK: ImportTableSize: 0x0 +CHECK: ResourceTableRVA: 0x0 +CHECK: ResourceTableSize: 0x0 +CHECK: ExceptionTableRVA: 0x0 +CHECK: ExceptionTableSize: 0x0 +CHECK: CertificateTableRVA: 0x0 +CHECK: CertificateTableSize: 0x0 +CHECK: BaseRelocationTableRVA: 0x0 +CHECK: BaseRelocationTableSize: 0x0 +CHECK: DebugRVA: 0x0 +CHECK: DebugSize: 0x0 +CHECK: ArchitectureRVA: 0x0 +CHECK: ArchitectureSize: 0x0 +CHECK: GlobalPtrRVA: 0x0 +CHECK: GlobalPtrSize: 0x0 +CHECK: TLSTableRVA: 0x0 +CHECK: TLSTableSize: 0x0 +CHECK: LoadConfigTableRVA: 0x0 +CHECK: LoadConfigTableSize: 0x0 +CHECK: BoundImportRVA: 0x0 +CHECK: BoundImportSize: 0x0 +CHECK: IATRVA: 0x0 +CHECK: IATSize: 0x0 +CHECK: DelayImportDescriptorRVA: 0x0 +CHECK: DelayImportDescriptorSize: 0x0 +CHECK: CLRRuntimeHeaderRVA: 0x0 +CHECK: CLRRuntimeHeaderSize: 0x0 +CHECK: ReservedRVA: 0x0 +CHECK: ReservedSize: 0x0 +CHECK: } +CHECK: } diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 1a6384afa000..493396f2e281 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -56,13 +56,14 @@ public: private: void printSymbol(symbol_iterator SymI); - void printRelocation(section_iterator SecI, relocation_iterator RelI); - void printDataDirectory(uint32_t Index, const std::string &FieldName); - void printX64UnwindInfo(); + template void printPEHeader(const PEHeader *Hdr); + void printBaseOfDataField(const pe32_header *Hdr); + void printBaseOfDataField(const pe32plus_header *Hdr); + void printRuntimeFunction( const RuntimeFunction& RTF, uint64_t OffsetInSection, @@ -599,56 +600,70 @@ void COFFDumper::printFileHeaders() { const pe32_header *PEHeader = 0; if (error(Obj->getPE32Header(PEHeader))) return; + if (PEHeader) + printPEHeader(PEHeader); - if (PEHeader) { - DictScope D(W, "ImageOptionalHeader"); - W.printNumber("MajorLinkerVersion", PEHeader->MajorLinkerVersion); - W.printNumber("MinorLinkerVersion", PEHeader->MinorLinkerVersion); - W.printNumber("SizeOfCode", PEHeader->SizeOfCode); - W.printNumber("SizeOfInitializedData", PEHeader->SizeOfInitializedData); - W.printNumber("SizeOfUninitializedData", PEHeader->SizeOfUninitializedData); - W.printHex ("AddressOfEntryPoint", PEHeader->AddressOfEntryPoint); - W.printHex ("BaseOfCode", PEHeader->BaseOfCode); - W.printHex ("BaseOfData", PEHeader->BaseOfData); - W.printHex ("ImageBase", PEHeader->ImageBase); - W.printNumber("SectionAlignment", PEHeader->SectionAlignment); - W.printNumber("FileAlignment", PEHeader->FileAlignment); - W.printNumber("MajorOperatingSystemVersion", - PEHeader->MajorOperatingSystemVersion); - W.printNumber("MinorOperatingSystemVersion", - PEHeader->MinorOperatingSystemVersion); - W.printNumber("MajorImageVersion", PEHeader->MajorImageVersion); - W.printNumber("MinorImageVersion", PEHeader->MinorImageVersion); - W.printNumber("MajorSubsystemVersion", PEHeader->MajorSubsystemVersion); - W.printNumber("MinorSubsystemVersion", PEHeader->MinorSubsystemVersion); - W.printNumber("SizeOfImage", PEHeader->SizeOfImage); - W.printNumber("SizeOfHeaders", PEHeader->SizeOfHeaders); - W.printEnum ("Subsystem", PEHeader->Subsystem, - makeArrayRef(PEWindowsSubsystem)); - W.printFlags ("Subsystem", PEHeader->DLLCharacteristics, - makeArrayRef(PEDLLCharacteristics)); - W.printNumber("SizeOfStackReserve", PEHeader->SizeOfStackReserve); - W.printNumber("SizeOfStackCommit", PEHeader->SizeOfStackCommit); - W.printNumber("SizeOfHeapReserve", PEHeader->SizeOfHeapReserve); - W.printNumber("SizeOfHeapCommit", PEHeader->SizeOfHeapCommit); - W.printNumber("NumberOfRvaAndSize", PEHeader->NumberOfRvaAndSize); + const pe32plus_header *PEPlusHeader = 0; + if (error(Obj->getPE32PlusHeader(PEPlusHeader))) + return; + if (PEPlusHeader) + printPEHeader(PEPlusHeader); +} - if (PEHeader->NumberOfRvaAndSize > 0) { - DictScope D(W, "DataDirectory"); - static const char * const directory[] = { - "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable", - "CertificateTable", "BaseRelocationTable", "Debug", "Architecture", - "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT", - "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" - }; +template +void COFFDumper::printPEHeader(const PEHeader *Hdr) { + DictScope D(W, "ImageOptionalHeader"); + W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion); + W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion); + W.printNumber("SizeOfCode", Hdr->SizeOfCode); + W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData); + W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData); + W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint); + W.printHex ("BaseOfCode", Hdr->BaseOfCode); + printBaseOfDataField(Hdr); + W.printHex ("ImageBase", Hdr->ImageBase); + W.printNumber("SectionAlignment", Hdr->SectionAlignment); + W.printNumber("FileAlignment", Hdr->FileAlignment); + W.printNumber("MajorOperatingSystemVersion", + Hdr->MajorOperatingSystemVersion); + W.printNumber("MinorOperatingSystemVersion", + Hdr->MinorOperatingSystemVersion); + W.printNumber("MajorImageVersion", Hdr->MajorImageVersion); + W.printNumber("MinorImageVersion", Hdr->MinorImageVersion); + W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion); + W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion); + W.printNumber("SizeOfImage", Hdr->SizeOfImage); + W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders); + W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem)); + W.printFlags ("Subsystem", Hdr->DLLCharacteristics, + makeArrayRef(PEDLLCharacteristics)); + W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve); + W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit); + W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve); + W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit); + W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize); - for (uint32_t i = 0; i < PEHeader->NumberOfRvaAndSize; ++i) { - printDataDirectory(i, directory[i]); - } + if (Hdr->NumberOfRvaAndSize > 0) { + DictScope D(W, "DataDirectory"); + static const char * const directory[] = { + "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable", + "CertificateTable", "BaseRelocationTable", "Debug", "Architecture", + "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT", + "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" + }; + + for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) { + printDataDirectory(i, directory[i]); } } } +void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { + W.printHex("BaseOfData", Hdr->BaseOfData); +} + +void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} + void COFFDumper::printCodeViewLineTables(section_iterator SecI) { StringRef Data; if (error(SecI->getContents(Data))) return;