diff --git a/llvm/test/tools/llvm-objdump/COFF/private-headers.test b/llvm/test/tools/llvm-objdump/COFF/private-headers-old.test rename from llvm/test/tools/llvm-objdump/COFF/private-headers.test rename to llvm/test/tools/llvm-objdump/COFF/private-headers-old.test diff --git a/llvm/test/tools/llvm-objdump/COFF/private-headers.yaml b/llvm/test/tools/llvm-objdump/COFF/private-headers.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/COFF/private-headers.yaml @@ -0,0 +1,183 @@ +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: llvm-objdump -p %t | FileCheck %s --check-prefix=PE32PLUS --strict-whitespace --match-full-lines + +# PE32PLUS:{{.*}}file format coff-arm64 +# PE32PLUS-NEXT:Characteristics 0x22 +# PE32PLUS-NEXT: executable +# PE32PLUS-NEXT: large address aware +#PE32PLUS-EMPTY: +# PE32PLUS-NEXT:Time/Date {{.*}} 19{{69|70}} +# PE32PLUS-NEXT:Magic 020b (PE32+) +# PE32PLUS-NEXT:MajorLinkerVersion 0 +# PE32PLUS-NEXT:MinorLinkerVersion 0 +# PE32PLUS-NEXT:SizeOfCode 0000000000000200 +# PE32PLUS-NEXT:SizeOfInitializedData 0000000000000400 +# PE32PLUS-NEXT:SizeOfUninitializedData 0000000000000000 +# PE32PLUS-NEXT:AddressOfEntryPoint 0000000000001000 +# PE32PLUS-NEXT:BaseOfCode 0000000000001000 +# PE32PLUS-NEXT:ImageBase 0000000140000000 +# PE32PLUS-NEXT:SectionAlignment 00001000 +# PE32PLUS-NEXT:FileAlignment 00000200 +# PE32PLUS-NEXT:MajorOSystemVersion 6 +# PE32PLUS-NEXT:MinorOSystemVersion 1 +# PE32PLUS-NEXT:MajorImageVersion 7 +# PE32PLUS-NEXT:MinorImageVersion 2 +# PE32PLUS-NEXT:MajorSubsystemVersion 8 +# PE32PLUS-NEXT:MinorSubsystemVersion 3 +# PE32PLUS-NEXT:Win32Version 00000000 +# PE32PLUS-NEXT:SizeOfImage 00004000 +# PE32PLUS-NEXT:SizeOfHeaders 00000200 +# PE32PLUS-NEXT:CheckSum 00000000 +# PE32PLUS-NEXT:Subsystem 00000003 (Windows CUI) +# PE32PLUS-NEXT:DllCharacteristics 00008160 +# PE32PLUS-NEXT: HIGH_ENTROPY_VA +# PE32PLUS-NEXT: DYNAMIC_BASE +# PE32PLUS-NEXT: NX_COMPAT +# PE32PLUS-NEXT: TERMINAL_SERVER_AWARE +# PE32PLUS-NEXT:SizeOfStackReserve 0000000000100000 +# PE32PLUS-NEXT:SizeOfStackCommit 0000000000001000 +# PE32PLUS-NEXT:SizeOfHeapReserve 0000000000100000 +# PE32PLUS-NEXT:SizeOfHeapCommit 0000000000001000 +# PE32PLUS-NEXT:LoaderFlags 00000000 +# PE32PLUS-NEXT:NumberOfRvaAndSizes 00000010 +#PE32PLUS-EMPTY: +# PE32PLUS-NEXT:The Data Directory +# PE32PLUS-NEXT:Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)] +# PE32PLUS-NEXT:Entry 1 0000000000000000 00000000 Import Directory [parts of .idata] +# PE32PLUS-NEXT:Entry 2 0000000000000000 00000000 Resource Directory [.rsrc] +# PE32PLUS-NEXT:Entry 3 0000000000003000 00000008 Exception Directory [.pdata] +# PE32PLUS-NEXT:Entry 4 0000000000000000 00000000 Security Directory +# PE32PLUS-NEXT:Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc] +# PE32PLUS-NEXT:Entry 6 0000000000000000 00000000 Debug Directory +# PE32PLUS-NEXT:Entry 7 0000000000000000 00000000 Description Directory +# PE32PLUS-NEXT:Entry 8 0000000000000000 00000000 Special Directory +# PE32PLUS-NEXT:Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls] +# PE32PLUS-NEXT:Entry a 0000000000000000 00000000 Load Configuration Directory +# PE32PLUS-NEXT:Entry b 0000000000000000 00000000 Bound Import Directory +# PE32PLUS-NEXT:Entry c 0000000000000000 00000000 Import Address Table Directory +# PE32PLUS-NEXT:Entry d 0000000000000000 00000000 Delay Import Directory +# PE32PLUS-NEXT:Entry e 0000000000000000 00000000 CLR Runtime Header +# PE32PLUS-NEXT:Entry f 0000000000000000 00000000 Reserved + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4096 + ImageBase: 0x140000000 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 1 + MajorImageVersion: 7 + MinorImageVersion: 2 + MajorSubsystemVersion: 8 + MinorSubsystemVersion: 3 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExceptionTable: + RelativeVirtualAddress: 12288 + Size: 8 +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 4 + SectionData: C0035FD6 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 12 + SectionData: 0100400800000000E4E3E3E3 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 8 + SectionData: '0010000000200000' +symbols: [] +... + +## Test 32-bit object with full Characteristics and DllCharacteristics. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-objdump -p %t2 | FileCheck %s --check-prefix=PE32 --match-full-lines +# PE32:{{.*}}file format coff-i386 +# PE32:Characteristics 0xffbf +# PE32-NEXT: relocations stripped +# PE32-NEXT: executable +# PE32-NEXT: line numbers stripped +# PE32-NEXT: symbols stripped +# PE32-NEXT: large address aware +# PE32-NEXT: little endian +# PE32-NEXT: 32 bit words +# PE32-NEXT: debugging information removed +# PE32-NEXT: copy to swap file if on removable media +# PE32-NEXT: copy to swap file if on network media +# PE32-NEXT: system file +# PE32-NEXT: DLL +# PE32-NEXT: run only on uniprocessor machine +# PE32-NEXT: big endian +#PE32-EMPTY: +# PE32:Time/Date {{.*}} +# PE32-NEXT:Magic 010b (PE32) +# PE32-NEXT:MajorLinkerVersion 0 +# PE32-NEXT:MinorLinkerVersion 0 +# PE32-NEXT:SizeOfCode 00000004 +# PE32-NEXT:SizeOfInitializedData 00000000 +# PE32-NEXT:SizeOfUninitializedData 00000000 +# PE32-NEXT:AddressOfEntryPoint 00000000 +# PE32-NEXT:BaseOfCode 00001000 +# PE32-NEXT:BaseOfData 00000000 +# PE32-NEXT:ImageBase 00000000 +# PE32-NEXT:SectionAlignment 00000001 +# PE32-NEXT:FileAlignment 00000001 +# PE32-NEXT:MajorOSystemVersion 0 +# PE32-NEXT:MinorOSystemVersion 0 +# PE32-NEXT:MajorImageVersion 0 +# PE32-NEXT:MinorImageVersion 0 +# PE32-NEXT:MajorSubsystemVersion 0 +# PE32-NEXT:MinorSubsystemVersion 0 +# PE32-NEXT:Win32Version 00000000 +# PE32-NEXT:SizeOfImage 000001a4 +# PE32-NEXT:SizeOfHeaders 000001a0 +# PE32-NEXT:CheckSum 00000000 +# PE32-NEXT:Subsystem 0000000a (EFI application) +# PE32-NEXT:DllCharacteristics 0000ffe0 +# PE32-NEXT: HIGH_ENTROPY_VA +# PE32-NEXT: DYNAMIC_BASE +# PE32-NEXT: FORCE_INTEGRITY +# PE32-NEXT: NX_COMPAT +# PE32-NEXT: NO_ISOLATION +# PE32-NEXT: NO_SEH +# PE32-NEXT: NO_BIND +# PE32-NEXT: APPCONTAINER +# PE32-NEXT: WDM_DRIVER +# PE32-NEXT: GUARD_CF +# PE32-NEXT: TERMINAL_SERVER_AWARE +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_RELOCS_STRIPPED, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LINE_NUMS_STRIPPED, + IMAGE_FILE_LOCAL_SYMS_STRIPPED, IMAGE_FILE_AGGRESSIVE_WS_TRIM, IMAGE_FILE_LARGE_ADDRESS_AWARE, + IMAGE_FILE_BYTES_REVERSED_LO, IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DEBUG_STRIPPED, + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, IMAGE_FILE_NET_RUN_FROM_SWAP, IMAGE_FILE_SYSTEM, + IMAGE_FILE_DLL, IMAGE_FILE_UP_SYSTEM_ONLY, IMAGE_FILE_BYTES_REVERSED_HI ] +OptionalHeader: + Subsystem: IMAGE_SUBSYSTEM_EFI_APPLICATION + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, + IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, + IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION, IMAGE_DLL_CHARACTERISTICS_NO_SEH, + IMAGE_DLL_CHARACTERISTICS_NO_BIND, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER, + IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER, IMAGE_DLL_CHARACTERISTICS_GUARD_CF, + IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 4 + SectionData: C0035FD6 +symbols: diff --git a/llvm/tools/llvm-objdump/COFFDump.h b/llvm/tools/llvm-objdump/COFFDump.h --- a/llvm/tools/llvm-objdump/COFFDump.h +++ b/llvm/tools/llvm-objdump/COFFDump.h @@ -28,7 +28,7 @@ llvm::SmallVectorImpl &Result); void printCOFFUnwindInfo(const object::COFFObjectFile *O); -void printCOFFFileHeader(const object::ObjectFile *O); +void printCOFFFileHeader(const object::COFFObjectFile &Obj); void printCOFFSymbolTable(const object::COFFImportFile *I); void printCOFFSymbolTable(const object::COFFObjectFile *O); } // namespace objdump diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp --- a/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/llvm/tools/llvm-objdump/COFFDump.cpp @@ -31,6 +31,159 @@ using namespace llvm::object; using namespace llvm::Win64EH; +namespace { +template struct EnumEntry { + T Value; + StringRef Name; +}; + +class COFFDumper { +public: + explicit COFFDumper(const llvm::object::COFFObjectFile &Obj) : Obj(Obj) { + Is64 = !Obj.getPE32Header(); + } + + template void printPEHeader(const PEHeader &Hdr) const; + +private: + template FormattedNumber formatAddr(T V) const { + return format_hex_no_prefix(V, Is64 ? 16 : 8); + }; + + uint32_t getBaseOfData(const void *Hdr) const { + return Is64 ? 0 : static_cast(Hdr)->BaseOfData; + } + + const llvm::object::COFFObjectFile &Obj; + bool Is64; +}; +} // namespace + +constexpr EnumEntry PEHeaderMagic[] = { + {uint16_t(COFF::PE32Header::PE32), "PE32"}, + {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"}, +}; + +constexpr EnumEntry PEWindowsSubsystem[] = { + {COFF::IMAGE_SUBSYSTEM_UNKNOWN, "unspecified"}, + {COFF::IMAGE_SUBSYSTEM_NATIVE, "NT native"}, + {COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, "Windows GUI"}, + {COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, "Windows CUI"}, + {COFF::IMAGE_SUBSYSTEM_POSIX_CUI, "POSIX CUI"}, + {COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, "Wince CUI"}, + {COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application"}, + {COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver"}, + {COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver"}, + {COFF::IMAGE_SUBSYSTEM_EFI_ROM, "SAL runtime driver"}, + {COFF::IMAGE_SUBSYSTEM_XBOX, "XBOX"}, +}; + +template +static void printOptionalEnumName(T Value, + ArrayRef> EnumValues) { + for (const EnumEntry &I : EnumValues) + if (I.Value == Value) { + outs() << "\t(" << I.Name << ')'; + return; + } +} + +template +void COFFDumper::printPEHeader(const PEHeader &Hdr) const { + auto print = [](const char *K, auto V, const char *Fmt = "%d\n") { + outs() << format("%-23s ", K) << format(Fmt, V); + }; + auto printU16 = [&](const char *K, support::ulittle16_t V, + const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); }; + auto printU32 = [&](const char *K, support::ulittle32_t V, + const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); }; + auto printAddr = [=](const char *K, uint64_t V) { + outs() << format("%-23s ", K) << formatAddr(V) << '\n'; + }; + + printU16("Magic", Hdr.Magic, "%04x"); + printOptionalEnumName(Hdr.Magic, makeArrayRef(PEHeaderMagic)); + outs() << '\n'; + print("MajorLinkerVersion", Hdr.MajorLinkerVersion); + print("MinorLinkerVersion", Hdr.MinorLinkerVersion); + printAddr("SizeOfCode", Hdr.SizeOfCode); + printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData); + printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData); + printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint); + printAddr("BaseOfCode", Hdr.BaseOfCode); + if (!Is64) + printAddr("BaseOfData", getBaseOfData(&Hdr)); + printAddr("ImageBase", Hdr.ImageBase); + printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n"); + printU32("FileAlignment", Hdr.FileAlignment, "%08x\n"); + printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion); + printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion); + printU16("MajorImageVersion", Hdr.MajorImageVersion); + printU16("MinorImageVersion", Hdr.MinorImageVersion); + printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion); + printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion); + printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n"); + printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n"); + printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n"); + printU32("CheckSum", Hdr.CheckSum, "%08x\n"); + printU16("Subsystem", Hdr.Subsystem, "%08x"); + printOptionalEnumName(Hdr.Subsystem, makeArrayRef(PEWindowsSubsystem)); + outs() << '\n'; + + printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n"); +#define FLAG(Name) \ + if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \ + outs() << "\t\t\t\t\t" << #Name << '\n'; + FLAG(HIGH_ENTROPY_VA); + FLAG(DYNAMIC_BASE); + FLAG(FORCE_INTEGRITY); + FLAG(NX_COMPAT); + FLAG(NO_ISOLATION); + FLAG(NO_SEH); + FLAG(NO_BIND); + FLAG(APPCONTAINER); + FLAG(WDM_DRIVER); + FLAG(GUARD_CF); + FLAG(TERMINAL_SERVER_AWARE); +#undef FLAG + + printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve); + printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit); + printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve); + printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit); + printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n"); + printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n"); + + static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = { + "Export Directory [.edata (or where ever we found it)]", + "Import Directory [parts of .idata]", + "Resource Directory [.rsrc]", + "Exception Directory [.pdata]", + "Security Directory", + "Base Relocation Directory [.reloc]", + "Debug Directory", + "Description Directory", + "Special Directory", + "Thread Storage Directory [.tls]", + "Load Configuration Directory", + "Bound Import Directory", + "Import Address Table Directory", + "Delay Import Directory", + "CLR Runtime Header", + "Reserved", + }; + outs() << "\nThe Data Directory\n"; + for (uint32_t I = 0; I != array_lengthof(DirName); ++I) { + uint32_t Addr = 0, Size = 0; + if (const data_directory *Data = Obj.getDataDirectory(I)) { + Addr = Data->RelativeVirtualAddress; + Size = Data->Size; + } + outs() << format("Entry %x ", I) << formatAddr(Addr) + << format(" %08x %s\n", uint32_t(Size), DirName[I]); + } +} + // Returns the name of the unwind code. static StringRef getUnwindCodeTypeName(uint8_t Code) { switch(Code) { @@ -622,12 +775,47 @@ } } -void objdump::printCOFFFileHeader(const object::ObjectFile *Obj) { - const COFFObjectFile *file = dyn_cast(Obj); - printTLSDirectory(file); - printLoadConfiguration(file); - printImportTables(file); - printExportTable(file); +void objdump::printCOFFFileHeader(const COFFObjectFile &Obj) { + COFFDumper CD(Obj); + const uint16_t Cha = Obj.getCharacteristics(); + outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n'; +#define FLAG(F, Name) \ + if (Cha & F) \ + outs() << '\t' << Name << '\n'; + FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped"); + FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable"); + FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped"); + FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped"); + FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware"); + FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian"); + FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words"); + FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed"); + FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, + "copy to swap file if on removable media"); + FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP, + "copy to swap file if on network media"); + FLAG(COFF::IMAGE_FILE_SYSTEM, "system file"); + FLAG(COFF::IMAGE_FILE_DLL, "DLL"); + FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine"); + FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian"); +#undef FLAG + + // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO. + // Since ctime(3) returns a 26 character string of the form: + // "Sun Sep 16 01:03:52 1973\n\0" + // just print 24 characters. + const time_t Timestamp = Obj.getTimeDateStamp(); + outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp)); + + if (const pe32_header *Hdr = Obj.getPE32Header()) + CD.printPEHeader(*Hdr); + else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader()) + CD.printPEHeader(*Hdr); + + printTLSDirectory(&Obj); + printLoadConfiguration(&Obj); + printImportTables(&Obj); + printExportTable(&Obj); } void objdump::printCOFFSymbolTable(const object::COFFImportFile *i) { diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2245,7 +2245,7 @@ return; } if (O->isCOFF()) - return printCOFFFileHeader(O); + return printCOFFFileHeader(cast(*O)); if (O->isWasm()) return printWasmFileHeader(O); if (O->isMachO()) {