aboutsummaryrefslogtreecommitdiff
path: root/core/debug
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-09-17 18:45:33 +0100
committergingerBill <bill@gingerbill.org>2022-09-17 18:45:33 +0100
commit729ffeee0946a5b8124c7266ed7cd4696de22989 (patch)
tree798e2a3eb292096c03e40a66c8eed5ec23b5fc25 /core/debug
parent0092995f9d0a23ae9402a334706e2491a46d2ad9 (diff)
Begin work on `core:debug/pe`
Diffstat (limited to 'core/debug')
-rw-r--r--core/debug/pe/pe.odin221
-rw-r--r--core/debug/pe/section.odin131
-rw-r--r--core/debug/pe/symbol.odin108
3 files changed, 460 insertions, 0 deletions
diff --git a/core/debug/pe/pe.odin b/core/debug/pe/pe.odin
new file mode 100644
index 000000000..587c01e8e
--- /dev/null
+++ b/core/debug/pe/pe.odin
@@ -0,0 +1,221 @@
+package debug_pe
+
+PE_SIGNATURE_OFFSET_INDEX_POS :: 0x3c
+PE_SIGNATURE :: u32le(0x0000_4550) // "PE\x00\x00"
+PE_SIGNATURE_STRING :: "PE\x00\x00"
+
+OPTIONAL_HEADER_MAGIC :: enum u16le {
+ PE32 = 0x010b,
+ PE32_PLUS = 0x020b,
+}
+
+Optional_Header_Base :: struct #packed {
+ magic: OPTIONAL_HEADER_MAGIC,
+ major_linker_version: u8,
+ minor_linker_version: u8,
+ size_of_code: u32le,
+ size_of_initialized_data: u32le,
+ size_of_uninitialized_data: u32le,
+ address_of_entry_point: u32le,
+ base_of_code: u32le,
+}
+
+File_Header :: struct #packed {
+ machine: IMAGE_FILE_MACHINE,
+ number_of_sections: u16le,
+ time_date_stamp: u32le,
+ pointer_to_symbol_table: u32le,
+ number_of_symbols: u32le,
+ size_of_optional_header: u16le,
+ characteristics: IMAGE_FILE_CHARACTERISTICS,
+}
+
+Data_Directory :: struct #packed {
+ virtual_address: u32le,
+ size: u32le,
+}
+
+Optional_Header32 :: struct #packed {
+ using base: Optional_Header_Base,
+ base_of_data: u32le,
+ image_base: u32le,
+ section_alignment: u32le,
+ file_alignment: u32le,
+ major_operating_system_version: u16le,
+ minor_operating_system_version: u16le,
+ major_image_version: u16le,
+ minor_image_version: u16le,
+ major_subsystem_version: u16le,
+ minor_subsystem_version: u16le,
+ win32_version_value: u32le,
+ size_of_image: u32le,
+ size_of_headers: u32le,
+ check_sum: u32le,
+ subsystem: IMAGE_SUBSYSTEM,
+ dll_characteristics: IMAGE_DLLCHARACTERISTICS,
+ size_of_stack_reserve: u32le,
+ size_of_stack_commit: u32le,
+ size_of_heap_reserve: u32le,
+ size_of_heap_commit: u32le,
+ loader_flags: u32le,
+ number_of_rva_and_sizes: u32le,
+ data_directory: [16]Data_Directory,
+}
+
+Optional_Header64 :: struct #packed {
+ using base: Optional_Header_Base,
+ image_base: u64le,
+ section_alignment: u32le,
+ file_alignment: u32le,
+ major_operating_system_version: u16le,
+ minor_operating_system_version: u16le,
+ major_image_version: u16le,
+ minor_image_version: u16le,
+ major_subsystem_version: u16le,
+ minor_subsystem_version: u16le,
+ win32_version_value: u32le,
+ size_of_image: u32le,
+ size_of_headers: u32le,
+ check_sum: u32le,
+ subsystem: IMAGE_SUBSYSTEM,
+ dll_characteristics: IMAGE_DLLCHARACTERISTICS,
+ size_of_stack_reserve: u64le,
+ size_of_stack_commit: u64le,
+ size_of_heap_reserve: u64le,
+ size_of_heap_commit: u64le,
+ loader_flags: u32le,
+ number_of_rva_and_sizes: u32le,
+ data_directory: [16]Data_Directory,
+}
+
+// .debug section
+Debug_Directory_Entry :: struct {
+ characteristics: u32le,
+ time_date_stamp: u32le,
+ major_version: u16le,
+ minor_version: u16le,
+ type: IMAGE_DEBUG_TYPE,
+ size_of_data: u32le,
+ address_of_raw_data: u32le,
+ pointer_to_raw_data: u32le,
+}
+
+
+IMAGE_FILE_MACHINE :: enum u16le {
+ UNKNOWN = 0x0,
+ AM33 = 0x1d3,
+ AMD64 = 0x8664,
+ ARM = 0x1c0,
+ ARMNT = 0x1c4,
+ ARM64 = 0xaa64,
+ EBC = 0xebc,
+ I386 = 0x14c,
+ IA64 = 0x200,
+ LOONGARCH32 = 0x6232,
+ LOONGARCH64 = 0x6264,
+ M32R = 0x9041,
+ MIPS16 = 0x266,
+ MIPSFPU = 0x366,
+ MIPSFPU16 = 0x466,
+ POWERPC = 0x1f0,
+ POWERPCFP = 0x1f1,
+ R4000 = 0x166,
+ SH3 = 0x1a2,
+ SH3DSP = 0x1a3,
+ SH4 = 0x1a6,
+ SH5 = 0x1a8,
+ THUMB = 0x1c2,
+ WCEMIPSV2 = 0x169,
+}
+
+// IMAGE_DIRECTORY_ENTRY constants
+IMAGE_DIRECTORY_ENTRY :: enum u8 {
+ EXPORT = 0,
+ IMPORT = 1,
+ RESOURCE = 2,
+ EXCEPTION = 3,
+ SECURITY = 4,
+ BASERELOC = 5,
+ DEBUG = 6,
+ ARCHITECTURE = 7, // reserved
+ GLOBALPTR = 8,
+ TLS = 9,
+ LOAD_CONFIG = 10,
+ BOUND_IMPORT = 11,
+ IAT = 12,
+ DELAY_IMPORT = 13,
+ COM_DESCRIPTOR = 14, // DLR Runtime headers
+ _RESERVED = 15,
+}
+#assert(len(IMAGE_DIRECTORY_ENTRY) == 16)
+
+
+IMAGE_FILE_CHARACTERISTICS :: distinct bit_set[IMAGE_FILE_CHARACTERISTIC; u16le]
+IMAGE_FILE_CHARACTERISTIC :: enum u16le {
+ RELOCS_STRIPPED = 0,
+ EXECUTABLE_IMAGE = 1,
+ LINE_NUMS_STRIPPED = 2,
+ LOCAL_SYMS_STRIPPED = 3,
+ AGGRESIVE_WS_TRIM = 4,
+ LARGE_ADDRESS_AWARE = 5,
+
+ BYTES_REVERSED_LO = 7,
+ MACHINE_32BIT = 8, // IMAGE_FILE_32BIT_MACHINE originally
+ DEBUG_STRIPPED = 9,
+ REMOVABLE_RUN_FROM_SWAP = 10,
+ NET_RUN_FROM_SWAP = 11,
+ SYSTEM = 12,
+ DLL = 13,
+ UP_SYSTEM_ONLY = 14,
+ BYTES_REVERSED_HI = 15,
+}
+
+IMAGE_SUBSYSTEM :: enum u16le {
+ UNKNOWN = 0,
+ NATIVE = 1,
+ WINDOWS_GUI = 2,
+ WINDOWS_CUI = 3,
+ OS2_CUI = 5,
+ POSIX_CUI = 7,
+ NATIVE_WINDOWS = 8,
+ WINDOWS_CE_GUI = 9,
+ EFI_APPLICATION = 10,
+ EFI_BOOT_SERVICE_DRIVER = 11,
+ EFI_RUNTIME_DRIVER = 12,
+ EFI_ROM = 13,
+ XBOX = 14,
+ WINDOWS_BOOT_APPLICATION = 16,
+}
+
+IMAGE_DLLCHARACTERISTICS :: distinct bit_set[IMAGE_DLLCHARACTERISTIC; u16le]
+IMAGE_DLLCHARACTERISTIC :: enum u16le {
+ HIGH_ENTROPY_VA = 5,
+ DYNAMIC_BASE = 6,
+ FORCE_INTEGRITY = 7,
+ NX_COMPAT = 8,
+ NO_ISOLATION = 9,
+ NO_SEH = 10,
+ NO_BIND = 11,
+ APPCONTAINER = 12,
+ WDM_DRIVER = 13,
+ GUARD_CF = 14,
+ TERMINAL_SERVER_AWARE = 15,
+}
+
+IMAGE_DEBUG_TYPE :: enum u32le {
+ UNKNOWN = 0, // An unknown value that is ignored by all tools.
+ COFF = 1, // The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
+ CODEVIEW = 2, // The Visual C++ debug information.
+ FPO = 3, // The frame pointer omission (FPO) information. 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.
+ MISC = 4, // The location of DBG file.
+ EXCEPTION = 5, // A copy of .pdata section.
+ FIXUP = 6, // Reserved.
+ OMAP_TO_SRC = 7, // The mapping from an RVA in image to an RVA in source image.
+ OMAP_FROM_SRC = 8, // The mapping from an RVA in source image to an RVA in image.
+ BORLAND = 9, // Reserved for Borland.
+ RESERVED10 = 10, // Reserved.
+ CLSID = 11, // Reserved.
+ REPRO = 16, // PE determinism or reproducibility.
+ EX_DLLCHARACTERISTICS = 20, // Extended DLL characteristics bits.
+}
+
diff --git a/core/debug/pe/section.odin b/core/debug/pe/section.odin
new file mode 100644
index 000000000..809da8bb4
--- /dev/null
+++ b/core/debug/pe/section.odin
@@ -0,0 +1,131 @@
+package debug_pe
+
+import "core:runtime"
+import "core:io"
+
+Section_Header32 :: struct {
+ name: [8]u8,
+ virtual_size: u32le,
+ virtual_address: u32le,
+ size_of_raw_data: u32le,
+ pointer_to_raw_data: u32le,
+ pointer_to_relocations: u32le,
+ pointer_to_line_numbers: u32le,
+ number_of_relocations: u16le,
+ number_of_line_numbers: u16le,
+ characteristics: IMAGE_SCN_CHARACTERISTICS,
+}
+
+Reloc :: struct {
+ virtual_address: u32le,
+ symbol_table_index: u32le,
+ type: IMAGE_REL,
+}
+
+IMAGE_SCN_CHARACTERISTICS :: enum u32le {
+ TYPE_NO_PAD = 0x00000008, // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. = 0x00000010, // Reserved for future use.
+ CNT_CODE = 0x00000020, // The section contains executable code.
+ CNT_INITIALIZED_DATA = 0x00000040, // The section contains initialized data.
+ CNT_UNINITIALIZED_DATA = 0x00000080, // The section contains uninitialized data.
+ LNK_OTHER = 0x00000100, // Reserved for future use.
+ LNK_INFO = 0x00000200, // The section contains comments or other information. The .drectve section has this type. This is valid for object files only. = 0x00000400, // Reserved for future use.
+ LNK_REMOVE = 0x00000800, // The section will not become part of the image. This is valid only for object files.
+ LNK_COMDAT = 0x00001000, // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
+ GPREL = 0x00008000, // The section contains data referenced through the global pointer (GP).
+ MEM_PURGEABLE = 0x00020000, // Reserved for future use.
+ MEM_16BIT = 0x00020000, // Reserved for future use.
+ MEM_LOCKED = 0x00040000, // Reserved for future use.
+ MEM_PRELOAD = 0x00080000, // Reserved for future use.
+ ALIGN_1BYTES = 0x00100000, // Align data on a 1-byte boundary. Valid only for object files.
+ ALIGN_2BYTES = 0x00200000, // Align data on a 2-byte boundary. Valid only for object files.
+ ALIGN_4BYTES = 0x00300000, // Align data on a 4-byte boundary. Valid only for object files.
+ ALIGN_8BYTES = 0x00400000, // Align data on an 8-byte boundary. Valid only for object files.
+ ALIGN_16BYTES = 0x00500000, // Align data on a 16-byte boundary. Valid only for object files.
+ ALIGN_32BYTES = 0x00600000, // Align data on a 32-byte boundary. Valid only for object files.
+ ALIGN_64BYTES = 0x00700000, // Align data on a 64-byte boundary. Valid only for object files.
+ ALIGN_128BYTES = 0x00800000, // Align data on a 128-byte boundary. Valid only for object files.
+ ALIGN_256BYTES = 0x00900000, // Align data on a 256-byte boundary. Valid only for object files.
+ ALIGN_512BYTES = 0x00A00000, // Align data on a 512-byte boundary. Valid only for object files.
+ ALIGN_1024BYTES = 0x00B00000, // Align data on a 1024-byte boundary. Valid only for object files.
+ ALIGN_2048BYTES = 0x00C00000, // Align data on a 2048-byte boundary. Valid only for object files.
+ ALIGN_4096BYTES = 0x00D00000, // Align data on a 4096-byte boundary. Valid only for object files.
+ ALIGN_8192BYTES = 0x00E00000, // Align data on an 8192-byte boundary. Valid only for object files.
+ LNK_NRELOC_OVFL = 0x01000000, // The section contains extended relocations.
+ MEM_DISCARDABLE = 0x02000000, // The section can be discarded as needed.
+ MEM_NOT_CACHED = 0x04000000, // The section cannot be cached.
+ MEM_NOT_PAGED = 0x08000000, // The section is not pageable.
+ MEM_SHARED = 0x10000000, // The section can be shared in memory.
+ MEM_EXECUTE = 0x20000000, // The section can be executed as code.
+ MEM_READ = 0x40000000, // The section can be read.
+ MEM_WRITE = 0x80000000, // The section can be written to.
+}
+
+
+IMAGE_REL :: enum u16le {
+ I386_ABSOLUTE = 0x0000,
+ I386_DIR16 = 0x0001,
+ I386_REL16 = 0x0002,
+ I386_DIR32 = 0x0006,
+ I386_DIR32NB = 0x0007,
+ I386_SEG12 = 0x0009,
+ I386_SECTION = 0x000A,
+ I386_SECREL = 0x000B,
+ I386_TOKEN = 0x000C,
+ I386_SECREL7 = 0x000D,
+ I386_REL32 = 0x0014,
+
+ AMD64_ABSOLUTE = 0x0000,
+ AMD64_ADDR64 = 0x0001,
+ AMD64_ADDR32 = 0x0002,
+ AMD64_ADDR32NB = 0x0003,
+ AMD64_REL32 = 0x0004,
+ AMD64_REL32_1 = 0x0005,
+ AMD64_REL32_2 = 0x0006,
+ AMD64_REL32_3 = 0x0007,
+ AMD64_REL32_4 = 0x0008,
+ AMD64_REL32_5 = 0x0009,
+ AMD64_SECTION = 0x000A,
+ AMD64_SECREL = 0x000B,
+ AMD64_SECREL7 = 0x000C,
+ AMD64_TOKEN = 0x000D,
+ AMD64_SREL32 = 0x000E,
+ AMD64_PAIR = 0x000F,
+ AMD64_SSPAN32 = 0x0010,
+
+ ARM_ABSOLUTE = 0x0000,
+ ARM_ADDR32 = 0x0001,
+ ARM_ADDR32NB = 0x0002,
+ ARM_BRANCH24 = 0x0003,
+ ARM_BRANCH11 = 0x0004,
+ ARM_SECTION = 0x000E,
+ ARM_SECREL = 0x000F,
+ ARM_MOV32 = 0x0010,
+
+ THUMB_MOV32 = 0x0011,
+ THUMB_BRANCH20 = 0x0012,
+ THUMB_BRANCH24 = 0x0014,
+ THUMB_BLX23 = 0x0015,
+
+ ARM_PAIR = 0x0016,
+
+ ARM64_ABSOLUTE = 0x0000,
+ ARM64_ADDR32 = 0x0001,
+ ARM64_ADDR32NB = 0x0002,
+ ARM64_BRANCH26 = 0x0003,
+ ARM64_PAGEBASE_REL21 = 0x0004,
+ ARM64_REL21 = 0x0005,
+ ARM64_PAGEOFFSET_12A = 0x0006,
+ ARM64_PAGEOFFSET_12L = 0x0007,
+ ARM64_SECREL = 0x0008,
+ ARM64_SECREL_LOW12A = 0x0009,
+ ARM64_SECREL_HIGH12A = 0x000A,
+ ARM64_SECREL_LOW12L = 0x000B,
+ ARM64_TOKEN = 0x000C,
+ ARM64_SECTION = 0x000D,
+ ARM64_ADDR64 = 0x000E,
+ ARM64_BRANCH19 = 0x000F,
+ ARM64_BRANCH14 = 0x0010,
+ ARM64_REL32 = 0x0011,
+}
+
+PE_CODE_VIEW_SIGNATURE_RSDS :: u32le(0x5344_5352) \ No newline at end of file
diff --git a/core/debug/pe/symbol.odin b/core/debug/pe/symbol.odin
new file mode 100644
index 000000000..288c6bd58
--- /dev/null
+++ b/core/debug/pe/symbol.odin
@@ -0,0 +1,108 @@
+package debug_pe
+
+COFF_SYMBOL_SIZE :: 18
+
+COFF_Symbol :: struct {
+ name: [8]u8,
+ value: u32le,
+ section_number: i16le,
+ type: IMAGE_SYM_TYPE,
+ storage_class: IMAGE_SYM_CLASS,
+ number_of_aux_symbols: u8,
+}
+
+// COFF_Symbol_Aux_Format5 describes the expected form of an aux symbol
+// attached to a section definition symbol. The PE format defines a
+// number of different aux symbol formats: format 1 for function
+// definitions, format 2 for .be and .ef symbols, and so on. Format 5
+// holds extra info associated with a section definition, including
+// number of relocations + line numbers, as well as COMDAT info. See
+// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
+// for more on what's going on here.
+COFF_Symbol_Aux_Format5 :: struct {
+ size: u32le,
+ num_relocs: u16le,
+ num_line_numbers: u16le,
+ checksum: u32le,
+ sec_num: u16le,
+ selection: IMAGE_COMDAT_SELECT,
+ _: [3]u8, // padding
+}
+
+IMAGE_COMDAT_SELECT :: enum u8 {
+ NODUPLICATES = 1,
+ ANY = 2,
+ SAME_SIZE = 3,
+ EXACT_MATCH = 4,
+ ASSOCIATIVE = 5,
+ LARGEST = 6,
+}
+
+
+// The symbol record is not yet assigned a section. A value of zero indicates
+// that a reference to an external symbol is defined elsewhere. A value of
+// non-zero is a common symbol with a size that is specified by the value.
+IMAGE_SYM_UNDEFINED :: 0
+// The symbol has an absolute (non-relocatable) value and is not an address.
+IMAGE_SYM_ABSOLUTE :: -1
+// The symbol provides general type or debugging information but does not
+// correspond to a section. Microsoft tools use this setting along
+// with .file records (storage class FILE).
+IMAGE_SYM_DEBUG :: -2
+
+IMAGE_SYM_TYPE :: enum u16le {
+ NULL = 0,
+ VOID = 1,
+ CHAR = 2,
+ SHORT = 3,
+ INT = 4,
+ LONG = 5,
+ FLOAT = 6,
+ DOUBLE = 7,
+ STRUCT = 8,
+ UNION = 9,
+ ENUM = 10,
+ MOE = 11,
+ BYTE = 12,
+ WORD = 13,
+ UINT = 14,
+ DWORD = 15,
+ PCODE = 32768,
+
+ DTYPE_NULL = 0,
+ DTYPE_POINTER = 0x10,
+ DTYPE_FUNCTION = 0x20,
+ DTYPE_ARRAY = 0x30,
+}
+
+IMAGE_SYM_CLASS :: enum u8 {
+ NULL = 0,
+ AUTOMATIC = 1,
+ EXTERNAL = 2,
+ STATIC = 3,
+ REGISTER = 4,
+ EXTERNAL_DEF = 5,
+ LABEL = 6,
+ UNDEFINED_LABEL = 7,
+ MEMBER_OF_STRUCT = 8,
+ ARGUMENT = 9,
+ STRUCT_TAG = 10,
+ MEMBER_OF_UNION = 11,
+ UNION_TAG = 12,
+ TYPE_DEFINITION = 13,
+ UNDEFINED_STATIC = 14,
+ ENUM_TAG = 15,
+ MEMBER_OF_ENUM = 16,
+ REGISTER_PARAM = 17,
+ BIT_FIELD = 18,
+ FAR_EXTERNAL = 68, // Not in PECOFF v8 spec
+ BLOCK = 100,
+ FUNCTION = 101,
+ END_OF_STRUCT = 102,
+ FILE = 103,
+ SECTION = 104,
+ WEAK_EXTERNAL = 105,
+ CLR_TOKEN = 107,
+
+ END_OF_FUNCTION = 255,
+}