From 224ac26e36a017666289508afd06e82e1387862f Mon Sep 17 00:00:00 2001
From: dd86k
Date: Mon, 11 Nov 2024 07:32:25 -0500
Subject: [PATCH] pe: Temporarily rework POGO dump data
---
dumper/format/pe.d | 30 +++++--
dumper/main.d | 4 +-
src/adbg/objects/pe.d | 188 ++++++++++++++++++++++++++++++++++++++----
3 files changed, 194 insertions(+), 28 deletions(-)
diff --git a/dumper/format/pe.d b/dumper/format/pe.d
index 2636d79..8c605df 100644
--- a/dumper/format/pe.d
+++ b/dumper/format/pe.d
@@ -12,6 +12,7 @@ import adbg.objects.pe;
import adbg.objects.mz : mz_header_t;
import adbg.utils.date : ctime32;
import adbg.utils.uid, adbg.utils.bit;
+import adbg.utils.strings;
import adbg.error;
import core.stdc.stdlib;
import core.stdc.string : strncmp;
@@ -717,9 +718,13 @@ void dump_pe_debug(adbg_object_t *o) {
debug_.SizeOfData, cast(uint)pe_debug_data_pogo_entry_t.sizeof);
continue;
}
- uint sig = *cast(uint*)data;
+
+ void *pogomax = data + debug_.SizeOfData;
+
+ pe_debug_data_pogo_entry_t* pogo = cast(pe_debug_data_pogo_entry_t*)data;
+
const(char) *pgotypestr = void;
- switch (sig) {
+ switch (pogo.Magic) {
case PE_IMAGE_DEBUG_MAGIC_POGO_LTCG:
pgotypestr = "POGO LTCG (Link-Time Code Generation)";
break;
@@ -729,14 +734,23 @@ void dump_pe_debug(adbg_object_t *o) {
default:
pgotypestr = "POGO (Unknown)";
}
- print_x32("Signature", sig, pgotypestr);
-
- //TODO: Check if multiple entries.
- pe_debug_data_pogo_entry_t* pogo = cast(pe_debug_data_pogo_entry_t*)data;
+ print_x32("Signature", pogo.Magic, pgotypestr);
print_x32("RVA", pogo.Rva);
print_x32("Size", pogo.Size);
- print_stringl("Size", pogo.Name.ptr,
- cast(int)(debug_.SizeOfData - pe_debug_data_pogo_entry_t.sizeof));
+
+ // Temporary
+ hexdump("POGO data", pogo.Name.ptr, debug_.SizeOfData - pe_debug_data_pogo_entry_t.sizeof - 1);
+ /*
+ size_t pogoleft = debug_.SizeOfData - pe_debug_data_pogo_entry_t.sizeof - 1;
+ const(char) *pogoname = pogo.Name.ptr;
+ Lpogostr: // multiple string entries
+ size_t strl = adbg_nstrlen(pogoname, pogoleft);
+ print_stringl("Name", pogoname, cast(int)strl);
+
+ pogoname += strl + 1;
+ if (pogoname < pogomax)
+ goto Lpogostr;
+ */
break;
case PE_IMAGE_DEBUG_TYPE_R2R_PERFMAP:
if (debug_.SizeOfData < pe_debug_data_r2r_perfmap_t.sizeof) {
diff --git a/dumper/main.d b/dumper/main.d
index 93e5931..1128cd6 100644
--- a/dumper/main.d
+++ b/dumper/main.d
@@ -17,7 +17,7 @@ import core.stdc.stdio;
import dumper;
import common.errormgmt;
import common.cli;
-import common.utils : unformat64;
+import common.utils;
private:
@@ -141,7 +141,7 @@ int cliopt_disasm_stats() {
return 0;
}
int cliopt_origin(const(char) *val) {
- return unformat64(&opt_baseaddress, val);
+ return parse64(&opt_baseaddress, val);
}
int cliopt_extract() {
diff --git a/src/adbg/objects/pe.d b/src/adbg/objects/pe.d
index fb9daec..3916021 100644
--- a/src/adbg/objects/pe.d
+++ b/src/adbg/objects/pe.d
@@ -358,6 +358,10 @@ struct pe_import_entry64_t { align(1):
}
}
+//
+// ANCHOR Debug information
+//
+
struct pe_debug_directory_entry_t { align(1):
uint Characteristics; /// reserved, must be zero
uint TimeDateStamp; /// time and date that the debug data was created
@@ -406,7 +410,7 @@ enum : uint {
/// Incremental Link Time Code Generation.
/// See: https://devblogs.microsoft.com/cppblog/speeding-up-the-incremental-developer-build-scenario/
PE_IMAGE_DEBUG_TYPE_ILTCG = 14,
- /// Uses Intel MPX
+ /// Intel MPX
PE_IMAGE_DEBUG_TYPE_MPX = 15,
/// PE determinism or reproducibility.
PE_IMAGE_DEBUG_TYPE_REPRO = 16,
@@ -437,14 +441,13 @@ enum : uint {
// Mono source has it set as 0x4244504d
PE_IMAGE_DEBUG_MAGIC_EMBEDDED_PPDB = CHAR32!"MPDB", /// Portable PDB
PE_IMAGE_DEBUG_MAGIC_PPDB = CHAR32!"BSJB", /// Portable PDB
- // Source: SystemInformer, except for full names
+ // Source: SystemInformer, except for descriptive names
PE_IMAGE_DEBUG_MAGIC_POGO_LTCG = CHAR32!"LTCG", /// Link-Time Code Generation
PE_IMAGE_DEBUG_MAGIC_POGO_PGU = CHAR32!"PGU\0", /// Profile Guided Update (/LTCG:PGUPDATE)
}
/// PDB 2.0 and above
struct pe_debug_data_codeview_pdb20_t { align(1):
- // Old PE32 doc mentions "NB05" -- CodeView 4.0 or earlier?
char[4] Signature; /// Magic: "NB09"/"NB10"/"NB11" bytes
/// Offset to the start of the actual debug information from the
/// beginning of the CodeView data. Zero if it's another file.
@@ -466,13 +469,17 @@ struct pe_debug_data_codeview_pdb70_t { align(1):
// This information tells the debugger how to interpret nonstandard stack frames,
// which use the EBP register for a purpose other than as a frame pointer.
-enum FRAME_FPO = 0;
-enum FRAME_TRAP = 1;
-enum FRAME_TSS = 2; // i286 Task Switch
+enum {
+ FRAME_FPO = 0,
+ FRAME_TRAP = 1,
+ FRAME_TSS = 2, // i286 Task Switch
+ FRAME_NONFPO = 3,
+}
+enum SIZEOF_RFPO_DATA = 16;
struct pe_debug_data_fpo_t { // struct _FPO_DATA
- uint ulOffStart; // offset 1st byte of function code
- uint cbProcSize; // # bytes in function
- uint cdwLocals; // # bytes in locals/4
+ uint ulOffStart; // offset 1st byte of function code
+ uint cbProcSize; // # bytes in function
+ uint cdwLocals; // # bytes in locals/4
ushort cdwParams; // # bytes in params/4
ushort Flags;
//WORD cbProlog : 8; // # bytes in prolog
@@ -485,7 +492,7 @@ struct pe_debug_data_fpo_t { // struct _FPO_DATA
// Debug entry 4: The location of a DBG file.
-struct pe_debug_data_misc_t { align(1):
+struct pe_debug_data_misc_t { align(1): // _IMAGE_DEBUG_MISC
union {
char[4] Signature; ///
uint Signature32;
@@ -493,9 +500,51 @@ struct pe_debug_data_misc_t { align(1):
uint DataType; /// Must be 1
uint Length; /// Multiple of four; Total length of data block
bool Unicode; /// If true, Unicode string
- byte[3] Reserved;
- byte[1] Data;
-}
+ ubyte[3] Reserved;
+ ubyte[1] Data; // Data pointer
+}
+
+/// Header of .DBG files
+struct pe_debug_data_header_t { // _IMAGE_SEPARATE_DEBUG_HEADER
+ ushort Signature;
+ ushort Flags;
+ ushort Machine;
+ ushort Characteristics;
+ uint TimeDateStamp;
+ uint CheckSum;
+ uint ImageBase;
+ uint SizeOfImage;
+ uint NumberOfSections;
+ uint ExportedNamesSize;
+ uint DebugDirectorySize;
+ uint SectionAlignment;
+ uint[2] Reserved;
+}
+///
+struct pe_debug_data_non_paged_header_t { // _NON_PAGED_DEBUG_INFO
+ ushort Signature;
+ ushort Flags;
+ uint Size;
+ ushort Machine;
+ ushort Characteristics;
+ uint TimeDateStamp;
+ uint CheckSum;
+ uint SizeOfImage;
+ ulong ImageBase; // ULONGLONG
+ //DebugDirectorySize
+ //IMAGE_DEBUG_DIRECTORY
+}
+
+version (LittleEndian) { // #ifndef _MAC
+ enum PE_IMAGE_SEPARATE_DEBUG_SIGNATURE = 0x4944;
+ enum PE_NON_PAGED_DEBUG_SIGNATURE = 0x494E;
+} else {
+ enum PE_IMAGE_SEPARATE_DEBUG_SIGNATURE = 0x4449; // DI
+ enum PE_NON_PAGED_DEBUG_SIGNATURE = 0x4E49; // NI
+}
+
+enum PE_IMAGE_SEPARATE_DEBUG_FLAGS_MASK = 0x8000;
+enum PE_IMAGE_SEPARATE_DEBUG_MISMATCH = 0x8000;
// Debug entry 12: VC Features
@@ -510,6 +559,17 @@ struct pe_debug_data_vc_feat_t { align(1):
// Debug entry 13: POGO
+enum { // POGO SubTypes
+ // POGOTypePGU represents a signature for an undocumented PGO sub type.
+ POGOTypePGU = CHAR32!"PGU\0", // 0x50475500
+ // POGOTypePGI represents a signature for an undocumented PGO sub type.
+ POGOTypePGI = CHAR32!"PGI\0", // 0x50474900,
+ // POGOTypePGO represents a signature for an undocumented PGO sub type.
+ POGOTypePGO = CHAR32!"PGO\0", // 0x50474F00,
+ // POGOTypeLTCG represents a signature for an undocumented PGO sub type.
+ POGOTypeLTCG = CHAR32!"LTCG", // 0x4c544347,
+}
+
/// POGO Entry containing filename. Should be ending with .PGD (Profile-Guided Database).
struct pe_debug_data_pogo_entry_t {
uint Magic;
@@ -564,7 +624,16 @@ struct pe_debug_data_ppdb_stream_t {
char[1] Name;
}
-// Debug type 21: R2R PerfMap
+// Debug entry 20: Extended DLL characteristics bits.
+// IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS
+
+// Indicates that the image is CET compatible.
+enum PE_IMAGE_DLLCHARACTARISTICS_EX_CET_COMPAT = 0x01;
+enum PE_IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE = 0x02;
+enum PE_IMAGE_DLLCHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE = 0x04;
+enum PE_IMAGE_DLLCHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC = 0x08;
+
+// Debug entry 21: R2R PerfMap
/// Declares that the image has an associated PerfMap file containing a table
/// mapping symbols to offsets for ready to run compilations.
@@ -583,7 +652,7 @@ struct pe_debug_data_r2r_perfmap_t { align(1):
}
//
-// Load configuration directory
+// ANCHOR Load configuration directory
//
struct pe_load_config_code_integrity_t { align(1):
@@ -815,23 +884,28 @@ struct internal_pe_t {
mz_header_t mz_header;
pe_image_data_directory_t directory;
+
size_t locsections;
pe_section_entry_t *sections;
bool *r_sections;
+
// export directory
pe_export_descriptor_t *export_directory;
bool *r_export_entries;
+
// import directory
pe_import_descriptor_t *import_directory; // not allocated
pe_section_entry_t *import_section; // associated section, not allocated
void *import_buffer; // section buffer
//bool *r_import_desc;
//bool *r_import_entries; // Current only, cleared when selecting other descriptor
+
// debug directory
pe_debug_directory_entry_t *debug_directory; // not allocated
pe_section_entry_t *debug_section;
void *debug_buffer; // section buffer
bool *r_debug_entries;
+
// load configuration directory
union {
pe_loadconfig32_t *load32_directory;
@@ -1386,7 +1460,7 @@ pe_section_entry_t* adbg_object_pe_section(adbg_object_t *o, size_t index) {
// - [ ] CLRHeader
//
-// Export directory functions
+// ANCHOR Export directory functions
//
// One descriptor table, multiple entries, because one module emits one table.
@@ -1572,7 +1646,7 @@ const(char)* adbg_object_pe_export_name_string(adbg_object_t *o,
}
//
-// Import directory functions
+// ANCHOR Import directory functions
//
// NOTE: Import directory handling
@@ -1709,7 +1783,7 @@ const(char)* adbg_object_pe_import_module_name(adbg_object_t *o, pe_import_descr
return cast(const(char)*)name;
}
-//TODO: Byte-swap import look-up table entries
+// TODO: Byte-swap import look-up table entries
pe_import_entry32_t* adbg_object_pe_import_entry32(adbg_object_t *o, pe_import_descriptor_t *import_, size_t index) {
if (o == null || import_ == null) {
@@ -2030,6 +2104,7 @@ const(char)* adbg_object_pe_import_entry_string(adbg_object_t *o, pe_import_desc
return cast(const(char)*)hint;
}
+
//
// Debug directory functions
//
@@ -2229,6 +2304,83 @@ void* adbg_object_pe_loadconfig(adbg_object_t *o) {
return internal.load32_directory;
}
+//
+// ANCHOR CLR/COM+ directory stuff
+//
+
+enum {// ReplacesCorHdrNumericDefines
+ // COM+ Header entry point flags.
+ COMIMAGE_FLAGS_ILONLY = 0x00000001,
+ COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002,
+ COMIMAGE_FLAGS_IL_LIBRARY = 0x00000004,
+ COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008,
+ COMIMAGE_FLAGS_NATIVE_ENTRYPOINT = 0x00000010,
+ COMIMAGE_FLAGS_TRACKDEBUGDATA = 0x00010000,
+ COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000,
+
+ // Version flags for image.
+ COR_VERSION_MAJOR_V2 = 2,
+ COR_VERSION_MAJOR = COR_VERSION_MAJOR_V2,
+ COR_VERSION_MINOR = 5,
+ COR_DELETED_NAME_LENGTH = 8,
+ COR_VTABLEGAP_NAME_LENGTH = 8,
+
+ // Maximum size of a NativeType descriptor.
+ NATIVE_TYPE_MAX_CB = 1,
+ COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE= 0xFF,
+
+ // #defines for the MIH FLAGS
+ IMAGE_COR_MIH_METHODRVA = 0x01,
+ IMAGE_COR_MIH_EHRVA = 0x02,
+ IMAGE_COR_MIH_BASICBLOCK = 0x08,
+
+ // V-table constants
+ COR_VTABLE_32BIT = 0x01, // V-table slots are 32-bits in size.
+ COR_VTABLE_64BIT = 0x02, // V-table slots are 64-bits in size.
+ COR_VTABLE_FROM_UNMANAGED = 0x04, // If set, transition from unmanaged.
+ COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN = 0x08, // If set, transition from unmanaged with keeping the current appdomain.
+ COR_VTABLE_CALL_MOST_DERIVED = 0x10, // Call most derived method described by
+
+ // EATJ constants
+ IMAGE_COR_EATJ_THUNK_SIZE =32, // Size of a jump thunk reserved range.
+
+ // Max name lengths
+ //@todo: Change to unlimited name lengths.
+ MAX_CLASS_NAME = 1024,
+ MAX_PACKAGE_NAME = 1024,
+}
+
+// CLR 2.0 header structure.
+struct pe_cor20_header_t { align(1): // IMAGE_COR20_HEADER
+ // Header versioning
+ uint cb;
+ ushort MajorRuntimeVersion;
+ ushort MinorRuntimeVersion;
+
+ // Symbol table and startup information
+ pe_image_data_directory_t MetaData;
+ uint Flags;
+
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
+ union {
+ uint EntryPointToken;
+ uint EntryPointRVA;
+ }
+
+ // Binding information
+ pe_image_data_directory_t Resources;
+ pe_image_data_directory_t StrongNameSignature;
+
+ // Regular fixup and binding information
+ pe_image_data_directory_t CodeManagerTable;
+ pe_image_data_directory_t VTableFixups;
+ pe_image_data_directory_t ExportAddressTableJumps;
+
+ // Precompiled image info (internal use only - set to zero)
+ pe_image_data_directory_t ManagedNativeHeader;
+}
+
//
// Other helpers
//