From 41d4bcfe11709ded0d4543900cf631e36e274eaa Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Jan 2025 16:10:28 -0800 Subject: [PATCH 01/53] notes --- src/raddbg/raddbg_main.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index ac53ce43..0c1b5f27 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -1,6 +1,31 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: feature cleanup, code dedup, code elimination pass: +// +// [ ] frontend config entities, serialization/deserialization, remove hacks, +// etc. - the entity structure should be dramatically simplified & made +// to reflect a more flexible string-tree data structure which can be +// more trivially derived from config, and more flexibly rearranged. +// drag/drop watch rows -> tabs, tabs -> watch rows, etc. +// [ ] frontend entities need to be the "upstream state" for windows, panels, +// tabs, etc. - entities can be mapped to caches of window/panel/view state +// in purely immediate-mode fashion, so the only *state* part of the +// equation only has to do with the string tree. +// [ ] config hot-reloading using the wins from the previous points +// [ ] undo/redo, using the wins from the previous points +// [ ] watch table UI - hidden table boundaries, special-cased control hacks +// [ ] hash store -> need to somehow hold on to hash blobs which are still +// depended upon by usage layers, e.g. extra dependency refcount, e.g. +// text cache can explicitly correllate nodes in its cache to hashes, +// bump their refcount - this would keep the hash correllated to its key +// and it would prevent it from being evicted (output debug string perf) +// [ ] autocompletion lister, file lister, function lister, command lister, +// etc., all need to be merged, and optionally contextualized/filtered. +// right-clicking a tab should be equivalent to spawning a command lister, +// but only with commands that are directly + //////////////////////////////// //~ rjf: post-0.9.12 TODO notes // From be81533f63e31721e458979db4c9dd4b45e94184 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 12 Dec 2024 13:04:18 -0800 Subject: [PATCH 02/53] removed coff guid and added missing defrange symbol --- src/codeview/codeview.h | 66 ++++++++++++++++++++++++----------------- src/coff/coff.h | 10 ------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index 721c51da..c8112ded 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -1179,7 +1179,7 @@ struct CV_SymSLink32 typedef struct CV_SymOEM CV_SymOEM; struct CV_SymOEM { - COFF_Guid id; + Guid id; CV_TypeId itype; // padding align(4) }; @@ -1210,27 +1210,27 @@ CV_EncodedFramePtrRegEnum; typedef U32 CV_FrameprocFlags; enum { - CV_FrameprocFlag_UsesAlloca = (1 << 0), - CV_FrameprocFlag_UsesSetJmp = (1 << 1), - CV_FrameprocFlag_UsesLongJmp = (1 << 2), - CV_FrameprocFlag_UsesInlAsm = (1 << 3), - CV_FrameprocFlag_UsesEH = (1 << 4), - CV_FrameprocFlag_Inline = (1 << 5), - CV_FrameprocFlag_HasSEH = (1 << 6), - CV_FrameprocFlag_Naked = (1 << 7), + CV_FrameprocFlag_UsesAlloca = (1 << 0), + CV_FrameprocFlag_UsesSetJmp = (1 << 1), + CV_FrameprocFlag_UsesLongJmp = (1 << 2), + CV_FrameprocFlag_UsesInlAsm = (1 << 3), + CV_FrameprocFlag_UsesEH = (1 << 4), + CV_FrameprocFlag_Inline = (1 << 5), + CV_FrameprocFlag_HasSEH = (1 << 6), + CV_FrameprocFlag_Naked = (1 << 7), CV_FrameprocFlag_HasSecurityChecks = (1 << 8), - CV_FrameprocFlag_AsyncEH = (1 << 9), + CV_FrameprocFlag_AsyncEH = (1 << 9), CV_FrameprocFlag_GSNoStackOrdering = (1 << 10), - CV_FrameprocFlag_WasInlined = (1 << 11), - CV_FrameprocFlag_GSCheck = (1 << 12), - CV_FrameprocFlag_SafeBuffers = (1 << 13), + CV_FrameprocFlag_WasInlined = (1 << 11), + CV_FrameprocFlag_GSCheck = (1 << 12), + CV_FrameprocFlag_SafeBuffers = (1 << 13), // LocalBasePointer: 14,15 // ParamBasePointer: 16,17 - CV_FrameprocFlag_PogoOn = (1 << 18), - CV_FrameprocFlag_PogoCountsValid = (1 << 19), - CV_FrameprocFlag_OptSpeed = (1 << 20), - CV_FrameprocFlag_HasCFG = (1 << 21), - CV_FrameprocFlag_HasCFW = (1 << 22), + CV_FrameprocFlag_PogoOn = (1 << 18), + CV_FrameprocFlag_PogoCountsValid = (1 << 19), + CV_FrameprocFlag_OptSpeed = (1 << 20), + CV_FrameprocFlag_HasCFG = (1 << 21), + CV_FrameprocFlag_HasCFW = (1 << 22), }; #define CV_FrameprocFlags_ExtractLocalBasePointer(f) (((f) >> 14)&3) #define CV_FrameprocFlags_ExtractParamBasePointer(f) (((f) >> 16)&3) @@ -1795,6 +1795,16 @@ enum CV_RangeAttrib_Maybe = (1 << 0), }; +//- (SymKind: DEFRANGE) + +typedef struct CV_SymDefrange CV_SymDefrange; +struct CV_SymDefrange +{ + U32 program; + CV_LvarAddrRange range; + // variable-width: CV_LvarAddrGap gaps; +}; + //- (SymKind: DEFRANGE_SUBFIELD) typedef struct CV_SymDefrangeSubfield CV_SymDefrangeSubfield; @@ -2322,7 +2332,7 @@ struct CV_LeafTypeServer typedef struct CV_LeafTypeServer2 CV_LeafTypeServer2; struct CV_LeafTypeServer2 { - COFF_Guid sig70; + Guid sig70; U32 age; // U8[] name (null terminated) }; @@ -2357,8 +2367,8 @@ struct CV_LeafLabel typedef U16 CV_ModifierFlags; enum { - CV_ModifierFlag_Const = (1 << 0), - CV_ModifierFlag_Volatile = (1 << 1), + CV_ModifierFlag_Const = (1 << 0), + CV_ModifierFlag_Volatile = (1 << 1), CV_ModifierFlag_Unaligned = (1 << 2), }; @@ -2376,15 +2386,15 @@ enum { // Kind: [0:4] // Mode: [5:7] - CV_PointerAttrib_IsFlat = (1 << 8), - CV_PointerAttrib_Volatile = (1 << 9), - CV_PointerAttrib_Const = (1 << 10), - CV_PointerAttrib_Unaligned = (1 << 11), + CV_PointerAttrib_IsFlat = (1 << 8), + CV_PointerAttrib_Volatile = (1 << 9), + CV_PointerAttrib_Const = (1 << 10), + CV_PointerAttrib_Unaligned = (1 << 11), CV_PointerAttrib_Restricted = (1 << 12), // Size: [13,18] - CV_PointerAttrib_MOCOM = (1 << 19), - CV_PointerAttrib_LRef = (1 << 21), - CV_PointerAttrib_RRef = (1 << 22) + CV_PointerAttrib_MOCOM = (1 << 19), + CV_PointerAttrib_LRef = (1 << 21), + CV_PointerAttrib_RRef = (1 << 22) }; #define CV_PointerAttribs_ExtractKind(a) ((a)&0x1F) diff --git a/src/coff/coff.h b/src/coff/coff.h index cc79a86a..bdbce261 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -11,16 +11,6 @@ typedef U32 COFF_TimeStamp; #pragma pack(push,1) -typedef struct COFF_Guid COFF_Guid; -struct COFF_Guid -{ - U32 data1; - U16 data2; - U16 data3; - U32 data4; - U32 data5; -}; - typedef U16 COFF_Flags; enum { From 3961f93d1ad613599b7c53fb1a2ecf02c5d3329b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 12 Dec 2024 14:00:59 -0800 Subject: [PATCH 03/53] moved CodeView parser code into separate file --- src/codeview/codeview.c | 1408 +------------- src/codeview/codeview.h | 2704 ++++++++++++-------------- src/codeview/codeview_parse.c | 1396 +++++++++++++ src/codeview/codeview_parse.h | 253 +++ src/linker/codeview_ext/codeview.h | 16 - src/linker/lnk.c | 3 + src/pdb/pdb_parse.c | 4 +- src/pdb/pdb_parse.h | 2 +- src/raddbg/raddbg_main.c | 4 +- src/rdi_from_pdb/rdi_from_pdb.c | 2 +- src/rdi_from_pdb/rdi_from_pdb_main.c | 4 +- 11 files changed, 2901 insertions(+), 2895 deletions(-) create mode 100644 src/codeview/codeview_parse.c create mode 100644 src/codeview/codeview_parse.h diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index 92ba9a59..ca5d0f3a 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -114,9 +114,9 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg) case CV_Arch_8086: { switch (encoded_reg) - { + { case CV_EncodedFramePtrReg_None : break; - case CV_EncodedFramePtrReg_StackPtr: AssertAlways(!"TODO(nick): not tested, this is a guess"); + case CV_EncodedFramePtrReg_StackPtr: AssertAlways(!"TODO: not tested, this is a guess"); fp_reg = CV_Regx86_ESP; break; case CV_EncodedFramePtrReg_FramePtr: fp_reg = CV_Regx86_EBP; break; case CV_EncodedFramePtrReg_BasePtr : fp_reg = CV_Regx86_EBX; break; @@ -126,7 +126,7 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg) case CV_Arch_X64: { switch (encoded_reg) - { + { case CV_EncodedFramePtrReg_None : break; case CV_EncodedFramePtrReg_StackPtr: fp_reg = CV_Regx64_RSP; break; case CV_EncodedFramePtrReg_FramePtr: fp_reg = CV_Regx64_RBP; break; @@ -139,1402 +139,6 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg) return fp_reg; } -//////////////////////////////// -//~ CodeView Common Decoding Helper Functions - -internal U64 -cv_hash_from_string(String8 string) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + string.str[i]; - } - return result; -} - -internal U64 -cv_hash_from_item_id(CV_ItemId item_id) -{ - U64 result = cv_hash_from_string(str8_struct(&item_id)); - return result; -} - -internal CV_NumericParsed -cv_numeric_from_data_range(U8 *first, U8 *opl) -{ - CV_NumericParsed result = {0}; - if(first + 2 <= opl) - { - U16 x = *(U16*)first; - if(x < 0x8000) - { - result.kind = CV_NumericKind_USHORT; - result.val = first; - result.encoded_size = 2; - } - else - { - U64 val_size = 0; - switch(x) - { - case CV_NumericKind_CHAR: val_size = 1; break; - case CV_NumericKind_SHORT: - case CV_NumericKind_USHORT: val_size = 2; break; - case CV_NumericKind_LONG: - case CV_NumericKind_ULONG: val_size = 4; break; - case CV_NumericKind_FLOAT32: val_size = 4; break; - case CV_NumericKind_FLOAT64: val_size = 8; break; - case CV_NumericKind_FLOAT80: val_size = 10; break; - case CV_NumericKind_FLOAT128: val_size = 16; break; - case CV_NumericKind_QUADWORD: - case CV_NumericKind_UQUADWORD: val_size = 8; break; - case CV_NumericKind_FLOAT48: val_size = 6; break; - case CV_NumericKind_COMPLEX32: val_size = 8; break; - case CV_NumericKind_COMPLEX64: val_size = 16; break; - case CV_NumericKind_COMPLEX80: val_size = 20; break; - case CV_NumericKind_COMPLEX128:val_size = 32; break; - case CV_NumericKind_VARSTRING: val_size = 0; break; // TODO: ??? - case CV_NumericKind_OCTWORD: - case CV_NumericKind_UOCTWORD: val_size = 16; break; - case CV_NumericKind_DECIMAL: val_size = 0; break; // TODO: ??? - case CV_NumericKind_DATE: val_size = 0; break; // TODO: ??? - case CV_NumericKind_UTF8STRING:val_size = 0; break; // TODO: ??? - case CV_NumericKind_FLOAT16: val_size = 2; break; - } - if(first + 2 + val_size <= opl) - { - result.kind = x; - result.val = (first + 2); - result.encoded_size = 2 + val_size; - } - } - } - return result; -} - -internal U64 -cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out) -{ - *out = cv_numeric_from_data_range(data.str + offset, data.str + data.size); - return out->encoded_size; -} - -internal B32 -cv_numeric_fits_in_u64(CV_NumericParsed *num) -{ - B32 result = 0; - switch(num->kind) - { - case CV_NumericKind_USHORT: - case CV_NumericKind_ULONG: - case CV_NumericKind_UQUADWORD: - { - result = 1; - }break; - } - return result; -} - -internal B32 -cv_numeric_fits_in_s64(CV_NumericParsed *num) -{ - B32 result = 0; - switch(num->kind) - { - case CV_NumericKind_CHAR: - case CV_NumericKind_SHORT: - case CV_NumericKind_LONG: - case CV_NumericKind_QUADWORD: - { - result = 1; - }break; - } - return result; -} - -internal B32 -cv_numeric_fits_in_f64(CV_NumericParsed *num) -{ - B32 result = 0; - switch(num->kind) - { - case CV_NumericKind_FLOAT32: - case CV_NumericKind_FLOAT64: - { - result = 1; - }break; - } - return result; -} - -internal U64 -cv_u64_from_numeric(CV_NumericParsed *num) -{ - U64 result = 0; - switch(num->kind) - { - case CV_NumericKind_USHORT: {result = *(U16*)num->val;}break; - case CV_NumericKind_ULONG: {result = *(U32*)num->val;}break; - case CV_NumericKind_UQUADWORD:{result = *(U64*)num->val;}break; - } - return result; -} - -internal S64 -cv_s64_from_numeric(CV_NumericParsed *num) -{ - S64 result = 0; - switch(num->kind) - { - case CV_NumericKind_CHAR: {result = *(S8*)num->val;}break; - case CV_NumericKind_SHORT: {result = *(S16*)num->val;}break; - case CV_NumericKind_LONG: {result = *(S32*)num->val;}break; - case CV_NumericKind_QUADWORD: {result = *(S64*)num->val;}break; - } - return(result); -} - -internal F64 -cv_f64_from_numeric(CV_NumericParsed *num) -{ - F64 result = 0; - switch(num->kind) - { - case CV_NumericKind_FLOAT32:{result = *(F32*)num->val;}break; - case CV_NumericKind_FLOAT64:{result = *(F64*)num->val;}break; - } - return(result); -} - -internal U64 -cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value) -{ - U64 cursor = offset; - - // rjf: read header - U8 header = 0; - cursor += str8_deserial_read_struct(data, cursor, &header); - - // rjf: decode value - U32 value = 0; - { - // 1 byte - if((header & 0x80) == 0) - { - value = header; - } - - // 2 bytes - else if((header & 0xC0) == 0x80 && cursor+1 <= data.size) - { - U8 second_byte; - cursor += str8_deserial_read_struct(data, cursor, &second_byte); - value = ((header & 0x3F) << 8) | second_byte; - } - - // 4 bytes - else if((header & 0xE0) == 0xC0 && cursor+3 <= data.size) - { - U8 second_byte, third_byte, fourth_byte; - cursor += str8_deserial_read_struct(data, cursor, &second_byte); - cursor += str8_deserial_read_struct(data, cursor, &third_byte); - cursor += str8_deserial_read_struct(data, cursor, &fourth_byte); - value = (((U32)header & 0x1F) << 24) | ((U32)second_byte << 16) | ((U32)third_byte << 8) | (U32)fourth_byte; - } - - // bad encode - else if((header & 0xE0) == 0xE0) - { - value = max_U32; - } - } - - // rjf: output results - if(out_value) - { - *out_value = value; - } - - U64 read_size = cursor - offset; - return read_size; -} - -internal U64 -cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value) -{ - U32 value; - U64 read_size = cv_decode_inline_annot_u32(data, offset, &value); - if(value & 1) - { - value = -(value >> 1); - } - else - { - value = value >> 1; - } - *out_value = (S32)value; - return read_size; -} - -internal S32 -cv_inline_annot_signed_from_unsigned_operand(U32 value) -{ - if(value & 1) - { - value = -(value >> 1); - } - else - { - value = value >> 1; - } - S32 result = (S32)value; - return result; -} - -//////////////////////////////// - -internal CV_TypeIndexInfo * -cv_symbol_type_index_info_push(Arena *arena, CV_TypeIndexInfoList *list, CV_TypeIndexSource source, U64 offset) -{ - CV_TypeIndexInfo *info = push_array_no_zero(arena, CV_TypeIndexInfo, 1); - info->next = 0; - info->offset = offset; - info->source = source; - - SLLQueuePush(list->first, list->last, info); - list->count += 1; - - return info; -} - -internal CV_TypeIndexInfoList -cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data) -{ - CV_TypeIndexInfoList list = {0}; - switch (kind) { - case CV_SymKind_BUILDINFO: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymBuildInfo, id)); - } break; - case CV_SymKind_GDATA32: - case CV_SymKind_LDATA32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymData32, itype)); - } break; - case CV_SymKind_LPROC32_ID: - case CV_SymKind_GPROC32_ID: - case CV_SymKind_LPROC32_DPC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymProc32, itype)); - } break; - case CV_SymKind_GPROC32: - case CV_SymKind_LPROC32: - case CV_SymKind_LPROC32_DPC: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymProc32, itype)); - } break; - case CV_SymKind_UDT: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymUDT, itype)); - } break; - case CV_SymKind_GTHREAD32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymThread32, itype)); - } break; - case CV_SymKind_FILESTATIC: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymFileStatic, itype)); - } break; - case CV_SymKind_LOCAL: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymLocal, itype)); - } break; - case CV_SymKind_REGREL32: - case CV_SymKind_BPREL32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegrel32, itype)); - } break; - case CV_SymKind_REGISTER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegister, itype)); - } break; - case CV_SymKind_CONSTANT: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymConstant, itype)); - } break; - case CV_SymKind_CALLSITEINFO: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymCallSiteInfo, itype)); - } break; - case CV_SymKind_CALLERS: - case CV_SymKind_CALLEES: - case CV_SymKind_INLINEES: { - Assert(data.size >= sizeof(CV_SymFunctionList)); - CV_SymFunctionList *func_list = (CV_SymFunctionList*)data.str; - for (U64 i = 0; i < func_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_SymFunctionList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_SymKind_INLINESITE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymInlineSite, inlinee)); - } break; - case CV_SymKind_HEAPALLOCSITE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymHeapAllocSite, itype)); - } break; - } - return list; -} - -internal CV_TypeIndexInfoList -cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data) -{ - CV_TypeIndexInfoList list = {0}; - switch (leaf_kind) { - case CV_LeafKind_NOTYPE: - case CV_LeafKind_VTSHAPE: - case CV_LeafKind_LABEL: - case CV_LeafKind_NULL: - case CV_LeafKind_NOTTRAN: { - // no type indices - } break; - case CV_LeafKind_MODIFIER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafModifier, itype)); - } break; - case CV_LeafKind_POINTER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafPointer, itype)); - CV_LeafPointer *ptr = (CV_LeafPointer *)data.str; - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs); - if (ptr_kind == CV_PointerKind_BaseType) { - // TODO: add CV_LeafPointerBaseType - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); - } else { - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs); - if (ptr_mode == CV_PointerMode_PtrMem || ptr_mode == CV_PointerMode_PtrMethod) { - // TODO: add type for the CvLeafPointerMember to syms_cv.mc - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); - } - } - } break; - case CV_LeafKind_ARRAY: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, entry_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, index_itype)); - } break; - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - case CV_LeafKind_INTERFACE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, field_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, derived_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, vshape_itype)); - } break; - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, field_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, derived_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, vshape_itype)); - } break; - case CV_LeafKind_UNION: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUnion, field_itype)); - } break; - case CV_LeafKind_ALIAS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafAlias, itype)); - } break; - case CV_LeafKind_FUNC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafFuncId, scope_string_id)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafFuncId, itype)); - } break; - case CV_LeafKind_MFUNC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, owner_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, itype)); - } break; - case CV_LeafKind_STRING_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafStringId, substr_list_id)); - } break; - case CV_LeafKind_UDT_SRC_LINE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTSrcLine, udt_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTSrcLine, src_string_id)); - } break; - case CV_LeafKind_UDT_MOD_SRC_LINE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTModSrcLine, udt_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTModSrcLine, src_string_id)); - } break; - case CV_LeafKind_BUILDINFO: { - Assert(data.size >= sizeof(CV_LeafBuildInfo)); - CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo *)data.str; - for (U16 i = 0; i < build_info->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafBuildInfo) + i * sizeof(CV_ItemId)); - } - } break; - case CV_LeafKind_ENUM: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, base_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, field_itype)); - } break; - case CV_LeafKind_PROCEDURE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, ret_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, arg_itype)); - } break; - case CV_LeafKind_MFUNCTION: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, ret_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, class_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, this_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, arg_itype)); - } break; - case CV_LeafKind_VFTABLE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, owner_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, base_table_itype)); - } break; - case CV_LeafKind_VFTPATH: { - Assert(sizeof(CV_LeafVFPath) <= data.size); - CV_LeafVFPath *vfpath = (CV_LeafVFPath *)data.str; - for (U32 i = 0; i < vfpath->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafVFPath) + i * sizeof(CV_TypeId)); - } - } break; - case CV_LeafKind_TYPESERVER: - case CV_LeafKind_TYPESERVER2: - case CV_LeafKind_TYPESERVER_ST: { - // no type indices - } break; - case CV_LeafKind_SKIP: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafSkip, itype)); - } break; - case CV_LeafKind_SUBSTR_LIST: { - Assert(sizeof(CV_LeafArgList) <= data.size); - CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; - for (U32 i = 0; i < arg_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_LeafKind_ARGLIST: { - Assert(sizeof(CV_LeafArgList) <= data.size); - CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; - for (U32 i = 0; i < arg_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_LeafKind_LIST: - case CV_LeafKind_FIELDLIST: { - for (U64 cursor = 0; cursor < data.size; ) { - CV_LeafKind list_member_kind = 0; - U64 read_size = str8_deserial_read_struct(data, cursor, &list_member_kind); - - if(read_size != sizeof(list_member_kind)) { - Assert(!"malformed LF_FIELDLIST"); - break; - } - cursor += read_size; - - switch (list_member_kind) { - default: Assert(!"TODO: handle malformed field member"); break; - case CV_LeafKind_INDEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafIndex, itype)); - cursor += sizeof(CV_LeafIndex); - } break; - case CV_LeafKind_MEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMember, itype)); - cursor += sizeof(CV_LeafMember); - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_STMEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafStMember, itype)); - cursor += sizeof(CV_LeafStMember); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_METHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethod, list_itype)); - cursor += sizeof(CV_LeafMethod); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_ONEMETHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafOneMethod, itype)); - - CV_LeafOneMethod onemethod; - cursor += str8_deserial_read_struct(data, cursor, &onemethod); - - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(onemethod.attribs); - if(prop == CV_MethodProp_PureIntro || prop == CV_MethodProp_Intro) - { - cursor += sizeof(U32); // virtoff - } - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_ENUMERATE: { - // no type index - cursor += sizeof(CV_LeafEnumerate); - CV_NumericParsed value; - cursor += cv_read_numeric(data, cursor, &value); - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_NESTTYPE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestType, itype)); - cursor += sizeof(CV_LeafNestType); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_NESTTYPEEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestTypeEx, itype)); - - cursor += sizeof(CV_LeafNestTypeEx); - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_BCLASS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafBClass, itype)); - - cursor += sizeof(CV_LeafBClass); - CV_NumericParsed offset; - cursor += cv_read_numeric(data, cursor, &offset); - } break; - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVBClass, itype)); - cursor += sizeof(CV_LeafVBClass); - - CV_NumericParsed virtual_base_pointer; - cursor += cv_read_numeric(data, cursor, &virtual_base_pointer); - - CV_NumericParsed virtual_base_offset; - cursor += cv_read_numeric(data, cursor, &virtual_base_offset); - } break; - case CV_LeafKind_VFUNCTAB: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncTab, itype)); - cursor += sizeof(CV_LeafVFuncTab); - } break; - case CV_LeafKind_VFUNCOFF: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncOff, itype)); - cursor += sizeof(CV_LeafVFuncOff); - } break; - } - cursor = AlignPow2(cursor, 4); - } - } break; - case CV_LeafKind_METHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMethod, list_itype)); - } break; - case CV_LeafKind_METHODLIST: { - for (U64 cursor = 0; cursor < data.size; ) { - // read method - CV_LeafMethodListMember method; - U64 read_size = str8_deserial_read_struct(data, cursor, &method); - - // error check read - if (read_size != sizeof(method)) { - Assert(!"malformed LF_METHODLIST"); - break; - } - - // push type index offset - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethodListMember, itype)); - - // take into account intro virtual offset - CV_MethodProp mprop = CV_FieldAttribs_ExtractMethodProp(method.attribs); - if (mprop == CV_MethodProp_Intro || mprop == CV_MethodProp_PureIntro) { - read_size += sizeof(U32); - } - - // advance - cursor += read_size; - } - } break; - case CV_LeafKind_ONEMETHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafOneMethod, itype)); - } break; - case CV_LeafKind_BITFIELD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafBitField, itype)); - } break; - case CV_LeafKind_PRECOMP: - case CV_LeafKind_REFSYM: { - // no type indices - } break; - case CV_LeafKind_INDEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafIndex, itype)); - } break; - case CV_LeafKind_MEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMember, itype)); - } break; - case CV_LeafKind_VFUNCTAB: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncTab, itype)); - } break; - case CV_LeafKind_VFUNCOFF: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncOff, itype)); - } break; - case CV_LeafKind_NESTTYPE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestType, itype)); - } break; - case CV_LeafKind_NESTTYPEEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestTypeEx, itype)); - } break; - default: { - NotImplemented; - } break; - } - return list; -} - -internal CV_TypeIndexInfoList -cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data) -{ - CV_TypeIndexInfoList list = {0}; - - U64 cursor = 0; - - // first four bytes are always signature - CV_C13InlineeLinesSig sig = max_U32; - cursor += str8_deserial_read_struct(raw_data, cursor, &sig); - - while(cursor < raw_data.size) - { - // read header - CV_C13InlineeSourceLineHeader *header = (CV_C13InlineeSourceLineHeader *) str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(CV_C13InlineeSourceLineHeader)); - - // store type index offset - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, cursor + OffsetOf(CV_C13InlineeSourceLineHeader, inlinee)); - - // advance past header - cursor += sizeof(*header); - - // skip extra files - B32 has_extra_files = (sig == CV_C13InlineeLinesSig_EXTRA_FILES); - if (has_extra_files) - { - U32 file_count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &file_count); - cursor += /* file id: */ sizeof(U32) * file_count; - } - } - - return list; -} - -internal String8Array -cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data) -{ - String8Array result; - if(ti_list.count > 0) - { - result.count = ti_list.count + 1; - result.v = push_array_no_zero(arena, String8, result.count); - - U64 cursor = 0; - U64 ti_idx = 0; - - for(CV_TypeIndexInfo *ti_info = ti_list.first; ti_info != 0; ti_info = ti_info->next, ++ti_idx) - { - result.v[ti_idx].size = ti_info->offset - cursor; - result.v[ti_idx].str = data.str + cursor; - cursor = ti_info->offset + sizeof(CV_TypeIndex); - } - - result.v[result.count-1].size = data.size - cursor; - result.v[result.count-1].str = data.str + cursor; - } - else - { - result.count = 1; - result.v = push_array_no_zero(arena, String8, 1); - result.v[0] = data; - } - return result; -} - -internal CV_TypeIndexSource -cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind) -{ - CV_TypeIndexSource source; - if(leaf_kind == CV_LeafKind_FUNC_ID || - leaf_kind == CV_LeafKind_MFUNC_ID || - leaf_kind == CV_LeafKind_BUILDINFO || - leaf_kind == CV_LeafKind_SUBSTR_LIST || - leaf_kind == CV_LeafKind_STRING_ID || - leaf_kind == CV_LeafKind_UDT_SRC_LINE || - leaf_kind == CV_LeafKind_UDT_MOD_SRC_LINE) - { - source = CV_TypeIndexSource_IPI; - } - else if(leaf_kind == CV_LeafKind_NOTYPE) - { - source = CV_TypeIndexSource_NULL; - } - else - { - source = CV_TypeIndexSource_TPI; - } - return source; -} - -internal U64 -cv_name_offset_from_symbol(CV_SymKind kind, String8 data) -{ - U64 offset = data.size; - switch (kind) { - case CV_SymKind_COMPILE: break; - case CV_SymKind_OBJNAME: break; - case CV_SymKind_THUNK32: { - offset = sizeof(CV_SymThunk32); - } break; - case CV_SymKind_LABEL32: { - offset = sizeof(CV_SymLabel32); - } break; - case CV_SymKind_REGISTER: { - offset = sizeof(CV_SymRegister); - } break; - case CV_SymKind_CONSTANT: { - offset = sizeof(CV_SymConstant); - CV_NumericParsed size; - offset += cv_read_numeric(data, offset, &size); - } break; - case CV_SymKind_UDT: { - offset = sizeof(CV_SymUDT); - } break; - case CV_SymKind_BPREL32: { - offset = sizeof(CV_SymBPRel32); - } break; - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: { - offset = sizeof(CV_SymData32); - } break; - case CV_SymKind_PUB32: { - offset = sizeof(CV_SymPub32); - } break; - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - case CV_SymKind_LPROC32_ID: - case CV_SymKind_GPROC32_ID: { - offset = sizeof(CV_SymProc32); - } break; - case CV_SymKind_REGREL32: { - offset = sizeof(CV_SymRegrel32); - } break; - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: { - offset = sizeof(CV_SymData32); - } break; - case CV_SymKind_COMPILE2: break; - case CV_SymKind_LOCALSLOT: { - offset = sizeof(CV_SymSlot); - } break; - case CV_SymKind_PROCREF: - case CV_SymKind_LPROCREF: - case CV_SymKind_DATAREF: { - offset = sizeof(CV_SymRef2); - } break; - case CV_SymKind_TRAMPOLINE: break; - case CV_SymKind_LOCAL: { - offset = sizeof(CV_SymLocal); - } break; - default: InvalidPath; - } - return offset; -} - -internal String8 -cv_name_from_symbol(CV_SymKind kind, String8 data) -{ - U64 buf_off = cv_name_offset_from_symbol(kind, data); - U8 *buf_ptr = data.str + buf_off; - U8 *buf_opl = data.str + data.size; - String8 name = str8_cstring_capped(buf_ptr, buf_opl); - return name; -} - -internal CV_UDTInfo -cv_get_udt_info(CV_LeafKind kind, String8 data) -{ - String8 name = str8_zero(); - String8 unique_name = str8_zero(); - CV_TypeProps props = 0; - - switch(kind) { - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - case CV_LeafKind_INTERFACE: { - U64 cursor = 0; - - CV_LeafStruct udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if (udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: { - U64 cursor = 0; - - CV_LeafStruct2 udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if (udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_UNION: { - U64 cursor = 0; - - CV_LeafUnion udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - props = udt.props; - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if(udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_ENUM: { - U64 cursor = 0; - - CV_LeafEnum udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if(udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - // dbi/tpi.cpp:1332 - case CV_LeafKind_UDT_SRC_LINE: { - CV_LeafUDTSrcLine *src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTSrcLine)); - name = str8_struct(&src_line->udt_itype); - } break; - case CV_LeafKind_UDT_MOD_SRC_LINE: { - CV_LeafUDTModSrcLine *mod_src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTModSrcLine)); - name = str8_struct(&mod_src_line->udt_itype); - } break; - - case CV_LeafKind_ALIAS: { - str8_deserial_read_cstr(data, 0, &name); - } break; - - default: { - InvalidPath; - } break; - } - - CV_UDTInfo info = {0}; - info.name = name; - info.unique_name = unique_name; - info.props = props; - return info; -} - -internal String8 -cv_name_from_udt_info(CV_UDTInfo udt_info) -{ - if (udt_info.props & CV_TypeProp_HasUniqueName) { - return udt_info.unique_name; - } - return udt_info.name; -} - -internal B32 -cv_is_udt_name_anon(String8 name) -{ - // corresponds to fUDTAnon from dbi/tm.cpp:817 - B32 is_anon = str8_match(str8_lit(""), name, 0) || - str8_match(str8_lit("__unnamed"), name, 0) || - str8_match(str8_lit("::"), name, StringMatchFlag_RightSideSloppy) || - str8_match(str8_lit("::__unnamed"), name, StringMatchFlag_RightSideSloppy); - return is_anon; -} - -internal B32 -cv_is_udt(CV_LeafKind kind) -{ - B32 is_udt = kind == CV_LeafKind_CLASS || - kind == CV_LeafKind_STRUCTURE || - kind == CV_LeafKind_CLASS2 || - kind == CV_LeafKind_STRUCT2 || - kind == CV_LeafKind_INTERFACE || - kind == CV_LeafKind_UNION || - kind == CV_LeafKind_ENUM || - kind == CV_LeafKind_UDT_MOD_SRC_LINE || - kind == CV_LeafKind_UDT_SRC_LINE || - kind == CV_LeafKind_ALIAS; - return is_udt; -} - -internal B32 -cv_is_global_symbol(CV_SymKind kind) -{ - B32 is_global_symbol = kind == CV_SymKind_CONSTANT || - kind == CV_SymKind_GDATA16 || - kind == CV_SymKind_GDATA32_16t || - kind == CV_SymKind_GDATA32_ST || - kind == CV_SymKind_GDATA32 || - kind == CV_SymKind_GTHREAD32_16t || - kind == CV_SymKind_GTHREAD32_ST || - kind == CV_SymKind_GTHREAD32; - return is_global_symbol; -} - -internal B32 -cv_is_typedef(CV_SymKind kind) -{ - B32 is_typedef = kind == CV_SymKind_UDT_16t || - kind == CV_SymKind_UDT_ST || - kind == CV_SymKind_UDT; - return is_typedef; -} - -internal B32 -cv_is_scope_symbol(CV_SymKind kind) -{ - B32 is_scope = kind == CV_SymKind_GPROC32 || - kind == CV_SymKind_LPROC32 || - kind == CV_SymKind_BLOCK32 || - kind == CV_SymKind_THUNK32 || - kind == CV_SymKind_INLINESITE || - kind == CV_SymKind_INLINESITE2 || - kind == CV_SymKind_WITH32 || - kind == CV_SymKind_SEPCODE || - kind == CV_SymKind_GPROC32_ID || - kind == CV_SymKind_LPROC32_ID; - return is_scope; -} - -internal B32 -cv_is_end_symbol(CV_SymKind kind) -{ - B32 is_end = kind == CV_SymKind_END || - kind == CV_SymKind_PROC_ID_END || - kind == CV_SymKind_INLINESITE_END; - return is_end; -} - -internal B32 -cv_is_leaf_type_server(CV_LeafKind kind) -{ - B32 is_type_server = kind == CV_LeafKind_TYPESERVER || - kind == CV_LeafKind_TYPESERVER2 || - kind == CV_LeafKind_TYPESERVER_ST; - return is_type_server; -} - -internal B32 -cv_is_leaf_pch(CV_LeafKind kind) -{ - B32 is_pch = kind == CV_LeafKind_PRECOMP || - kind == CV_LeafKind_PRECOMP_ST || - kind == CV_LeafKind_PRECOMP_16t; - return is_pch; -} - -//////////////////////////////// -//~ CodeView Parsing Functions - -//- rjf: record range stream parsing - -internal CV_RecRangeStream* -cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align) -{ - Assert(1 <= sym_align && IsPow2OrZero(sym_align)); - CV_RecRangeStream *result = push_array(arena, CV_RecRangeStream, 1); - U8 *data = sym_data.str; - U64 cursor = 0; - U64 cap = sym_data.size; - for(;cursor + sizeof(CV_RecHeader) <= cap;) - { - // setup a new chunk - CV_RecRangeChunk *cur_chunk = push_array_aligned(arena, CV_RecRangeChunk, 1, 64); - SLLQueuePush(result->first_chunk, result->last_chunk, cur_chunk); - U64 partial_count = 0; - for(;partial_count < CV_REC_RANGE_CHUNK_SIZE && cursor + sizeof(CV_RecHeader) <= cap; partial_count += 1) - { - // compute cap - CV_RecHeader *hdr = (CV_RecHeader*)(data + cursor); - U64 symbol_cap_unclamped = cursor + 2 + hdr->size; - U64 symbol_cap = ClampTop(symbol_cap_unclamped, cap); - - // push on range - cur_chunk->ranges[partial_count].off = cursor + 2; - cur_chunk->ranges[partial_count].hdr = *hdr; - - // update cursor - U32 next_pos = AlignPow2(symbol_cap, sym_align); - cursor = next_pos; - } - result->total_count += partial_count; - } - return result; -} - -internal CV_RecRangeArray -cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream) -{ - U64 total_count = stream->total_count; - CV_RecRange *ranges = push_array_no_zero_aligned(arena, CV_RecRange, total_count, 8); - U64 idx = 0; - for(CV_RecRangeChunk *chunk = stream->first_chunk; chunk != 0; chunk = chunk->next) - { - U64 copy_count_raw = total_count - idx; - U64 copy_count = ClampTop(copy_count_raw, CV_REC_RANGE_CHUNK_SIZE); - MemoryCopy(ranges + idx, chunk->ranges, copy_count*sizeof(CV_RecRange)); - idx += copy_count; - } - CV_RecRangeArray result = {0}; - result.ranges = ranges; - result.count = total_count; - return result; -} - -//- rjf: sym stream parsing - -internal CV_SymParsed * -cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align) -{ - Assert(1 <= sym_align && IsPow2OrZero(sym_align)); - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: gather symbols - CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align); - - //- rjf: convert to result, fill basics - CV_SymParsed *result = push_array(arena, CV_SymParsed, 1); - result->data = sym_data; - result->sym_align = sym_align; - result->sym_ranges = cv_rec_range_array_from_stream(arena, stream); - - //- rjf: extract top-level-info - { - CV_RecRange *range = result->sym_ranges.ranges; - CV_RecRange *opl = range + result->sym_ranges.count; - for(;range < opl; range += 1) - { - U8 *first = sym_data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - switch(range->hdr.kind) - { - case CV_SymKind_COMPILE: - if(sizeof(CV_SymCompile) <= cap) - { - CV_SymCompile *compile = (CV_SymCompile*)first; - String8 ver_str = str8_cstring_capped((char*)(compile + 1), (char *)(first + cap)); - result->info.arch = compile->machine; - result->info.language = CV_CompileFlags_ExtractLanguage(compile->flags);; - result->info.compiler_name = ver_str; - }break; - case CV_SymKind_COMPILE2: - if(sizeof(CV_SymCompile2) <= cap) - { - CV_SymCompile2 *compile2 = (CV_SymCompile2*)first; - String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), (char*)(first + cap)); - String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", - str8_varg(ver_str), - compile2->ver_major, - compile2->ver_minor, - compile2->ver_build); - result->info.arch = compile2->machine; - result->info.language = CV_Compile2Flags_ExtractLanguage(compile2->flags);; - result->info.compiler_name = compiler_name; - }break; - case CV_SymKind_COMPILE3: - if(sizeof(CV_SymCompile3) <= cap) - { - CV_SymCompile3 *compile3 = (CV_SymCompile3*)first; - String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), (char *)(first + cap)); - String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", - str8_varg(ver_str), - compile3->ver_major, - compile3->ver_minor, - compile3->ver_build); - result->info.arch = compile3->machine; - result->info.language = CV_Compile3Flags_ExtractLanguage(compile3->flags);; - result->info.compiler_name = compiler_name; - }break; - } - } - } - - scratch_end(scratch); - ProfEnd(); - return result; -} - -//- rjf: leaf stream parsing - -internal CV_LeafParsed * -cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - // gather up symbols - CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1); - - // convert to result - CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1); - result->data = leaf_data; - result->itype_first = itype_first; - result->itype_opl = itype_first + stream->total_count; - result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream); - - scratch_end(scratch); - ProfEnd(); - return result; -} - -//////////////////////////////// -//~ CodeView C13 Parser Functions - -internal CV_C13Parsed * -cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections) -{ - ProfBeginFunction(); - - ////////////////////////////// - //- rjf: gather c13 sub-sections - // - CV_C13SubSectionNode *file_chksms = 0; - CV_C13SubSectionNode *first = 0; - CV_C13SubSectionNode *last = 0; - U64 count = 0; - { - U32 cursor = 0; - for(; cursor + sizeof(CV_C13SubSectionHeader) <= c13_data.size;) - { - // read header - CV_C13SubSectionHeader *hdr = (CV_C13SubSectionHeader*)(c13_data.str + cursor); - - // get sub section info - U32 sub_section_off = cursor + sizeof(*hdr); - U32 sub_section_size_raw = hdr->size; - U32 after_sub_section_off_unclamped = sub_section_off + sub_section_size_raw; - U32 after_sub_section_off = ClampTop(after_sub_section_off_unclamped, c13_data.size); - U32 sub_section_size = after_sub_section_off - sub_section_off; - - // emit sub section - if(!(hdr->kind & CV_C13SubSectionKind_IgnoreFlag)) - { - CV_C13SubSectionNode *node = push_array(arena, CV_C13SubSectionNode, 1); - SLLQueuePush(first, last, node); - count += 1; - node->kind = hdr->kind; - node->off = sub_section_off; - node->size = sub_section_size; - if(hdr->kind == CV_C13SubSectionKind_FileChksms) - { - file_chksms = node; - } - } - - // move cursor - cursor = AlignPow2(after_sub_section_off, 4); - } - } - - ////////////////////////////// - //- rjf: parse each sub-section - // - U64 inlinee_lines_parsed_slots_count = 4096; - CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots = push_array(arena, CV_C13InlineeLinesParsedNode *, inlinee_lines_parsed_slots_count); - for(CV_C13SubSectionNode *node = first; - node != 0; - node = node->next) - { - U8 *first = c13_data.str + node->off; - U32 cap = node->size; - switch(node->kind) - { - default:{}break; - - ////////////////////////// - //- rjf: line info sub-section - // - case CV_C13SubSectionKind_Lines: - if(sizeof(CV_C13SubSecLinesHeader) <= cap) - { - // read header - U32 read_off = 0; - U64 read_off_opl = node->size; - CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off); - read_off += sizeof(*hdr); - - // rjf: extract section index - U32 sec_idx = hdr->sec; - - // rjf: bad section index -> skip - if(sec_idx < 1 || sections.count < sec_idx) - { - continue; - } - - // extract top level info - B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns); - U64 secrel_off = hdr->sec_off; - U64 secrel_opl = secrel_off + hdr->len; - U64 sec_base_off = sections.v[sec_idx - 1].voff; - - // read files - for(;read_off+sizeof(CV_C13File) <= read_off_opl;) - { - // rjf: grab next file header - CV_C13File *file = (CV_C13File*)(first + read_off); - U32 file_off = file->file_off; - U32 line_count_unclamped = file->num_lines; - U32 block_size = file->block_size; - - // file_name from file_off - String8 file_name = {0}; - if(file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off); - U32 name_off = checksum->name_off; - file_name = str8_cstring_capped((char*)(strtbl.str + name_off), - (char*)(strtbl.str + strtbl.size)); - } - - // array layouts - U32 line_item_size = sizeof(CV_C13Line); - if (has_cols){ - line_item_size += sizeof(CV_C13Column); - } - - U32 line_array_off = read_off + sizeof(*file); - U32 line_count_max = (read_off_opl - line_array_off) / line_item_size; - U32 line_count = ClampTop(line_count_unclamped, line_count_max); - - U32 col_array_off = line_array_off + line_count*sizeof(CV_C13Line); - - // parse lines - U64 *voffs = push_array_no_zero(arena, U64, line_count + 1); - U32 *line_nums = push_array_no_zero(arena, U32, line_count); - - { - CV_C13Line *line_ptr = (CV_C13Line*)(first + line_array_off); - CV_C13Line *line_opl = line_ptr + line_count; - - // TODO(allen): check order correctness here - - U32 i = 0; - for (; line_ptr < line_opl; line_ptr += 1, i += 1){ - voffs[i] = line_ptr->off + secrel_off + sec_base_off; - line_nums[i] = CV_C13LineFlags_ExtractLineNumber(line_ptr->flags); - } - voffs[i] = secrel_opl + sec_base_off; - } - - // emit parsed lines - CV_C13LinesParsedNode *lines_parsed_node = push_array(arena, CV_C13LinesParsedNode, 1); - CV_C13LinesParsed *lines_parsed = &lines_parsed_node->v; - lines_parsed->sec_idx = sec_idx; - lines_parsed->file_off = file_off; - lines_parsed->secrel_base_off = secrel_off; - lines_parsed->file_name = file_name; - lines_parsed->voffs = voffs; - lines_parsed->line_nums = line_nums; - lines_parsed->line_count = line_count; - SLLQueuePush(node->lines_first, node->lines_last, lines_parsed_node); - - // rjf: advance - read_off += sizeof(*file); - read_off += line_item_size*line_count; - } - }break; - - ////////////////////////// - //- rjf: inlinee line info sub-section - // - case CV_C13SubSectionKind_InlineeLines: - if(sizeof(CV_C13InlineeLinesSig) <= cap) - { - // rjf: read sig - U32 read_off = 0; - U64 read_off_opl = node->size; - CV_C13InlineeLinesSig *sig = (CV_C13InlineeLinesSig *)(first + read_off); - read_off += sizeof(*sig); - - // rjf: read source lines - for(;read_off + sizeof(CV_C13InlineeSourceLineHeader) <= read_off_opl;) - { - // rjf: read next header - CV_C13InlineeSourceLineHeader *hdr = (CV_C13InlineeSourceLineHeader *)(first + read_off); - read_off += sizeof(*hdr); - - // rjf: file_off -> file_name - String8 file_name = {0}; - if(hdr->file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off); - U32 name_off = checksum->name_off; - file_name = str8_cstring_capped((char*)(strtbl.str + name_off), - (char*)(strtbl.str + strtbl.size)); - } - - // rjf: parse extra files - U32 extra_file_count = 0; - U32 *extra_files = 0; - if(*sig == CV_C13InlineeLinesSig_EXTRA_FILES && read_off+sizeof(U32) <= read_off_opl) - { - U32 *extra_file_count_ptr = (U32 *)(first + read_off); - read_off += sizeof(*extra_file_count_ptr); - U32 max_extra_file_count = (read_off_opl-read_off)/sizeof(U32); - extra_file_count = Min(*extra_file_count_ptr, max_extra_file_count); - extra_files = (U32 *)(first + read_off); - read_off += sizeof(*extra_files)*extra_file_count; - } - - // rjf: push node for this inlinee lines parsed into this subsection's list - CV_C13InlineeLinesParsedNode *n = push_array(arena, CV_C13InlineeLinesParsedNode, 1); - SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n); - n->v.inlinee = hdr->inlinee; - n->v.file_name = file_name; - n->v.file_off = hdr->file_off; - n->v.first_source_ln = hdr->first_source_ln; - n->v.extra_file_count = extra_file_count; - n->v.extra_files = extra_files; - - // rjf: push node into inlinee parse hash table - U64 hash = cv_hash_from_item_id(hdr->inlinee); - U64 slot_idx = hash%inlinee_lines_parsed_slots_count; - SLLStackPush_N(inlinee_lines_parsed_slots[slot_idx], n, hash_next); - } - }break; - } - } - - ////////////////////////////// - //- rjf: fill output - // - CV_C13Parsed *result = push_array(arena, CV_C13Parsed, 1); - result->data = c13_data; - result->first_sub_section = first; - result->last_sub_section = last; - result->sub_section_count = count; - result->file_chksms_sub_section = file_chksms; - result->inlinee_lines_parsed_slots = inlinee_lines_parsed_slots; - result->inlinee_lines_parsed_slots_count = inlinee_lines_parsed_slots_count; - ProfEnd(); - return result; -} - //////////////////////////////// //~ Enum <-> String @@ -1542,9 +146,9 @@ internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source) { switch (ti_source) { - case CV_TypeIndexSource_NULL: return str8_lit(""); break; - case CV_TypeIndexSource_TPI: return str8_lit("TPI"); break; - case CV_TypeIndexSource_IPI: return str8_lit("IPI"); break; + case CV_TypeIndexSource_NULL: return str8_lit(""); break; + case CV_TypeIndexSource_TPI: return str8_lit("TPI"); break; + case CV_TypeIndexSource_IPI: return str8_lit("IPI"); break; case CV_TypeIndexSource_COUNT: break; } return str8_zero(); diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index c8112ded..f432035f 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -12,7 +12,7 @@ #define CV_MinComplexTypeIndex 0x1000 #define CV_TypeIndex_Max max_U32 -typedef U32 CV_TypeIndex; +typedef U32 CV_TypeIndex; typedef CV_TypeIndex CV_TypeId; typedef CV_TypeIndex CV_ItemId; @@ -30,254 +30,262 @@ read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF; #include "generated/codeview.meta.h" +//////////////////////////////// +//~ Aligns + +#define CV_LeafAlign 4 +#define CV_SymbolAlign 1 +#define CV_C13SubSectionAlign 4 +#define CV_FileCheckSumsAlign 4 + //////////////////////////////// //~ rjf: Registers // X(NAME, CODE, (RDI_RegCode_X86) NAME, BYTE_POS, BYTE_SIZE) -#define CV_Reg_X86_XList(X) \ -X(NONE, 0, nil, 0, 0)\ -X(AL, 1, eax, 0, 1)\ -X(CL, 2, ecx, 0, 1)\ -X(DL, 3, edx, 0, 1)\ -X(BL, 4, ebx, 0, 1)\ -X(AH, 5, eax, 1, 1)\ -X(CH, 6, ecx, 1, 1)\ -X(DH, 7, edx, 1, 1)\ -X(BH, 8, ebx, 1, 1)\ -X(AX, 9, eax, 0, 2)\ -X(CX, 10, ecx, 0, 2)\ -X(DX, 11, edx, 0, 2)\ -X(BX, 12, ebx, 0, 2)\ -X(SP, 13, esp, 0, 2)\ -X(BP, 14, ebp, 0, 2)\ -X(SI, 15, esi, 0, 2)\ -X(DI, 16, edi, 0, 2)\ -X(EAX, 17, eax, 0, 4)\ -X(ECX, 18, ecx, 0, 4)\ -X(EDX, 19, edx, 0, 4)\ -X(EBX, 20, ebx, 0, 4)\ -X(ESP, 21, esp, 0, 4)\ -X(EBP, 22, ebp, 0, 4)\ -X(ESI, 23, esi, 0, 4)\ -X(EDI, 24, edi, 0, 4)\ -X(ES, 25, es, 0, 2)\ -X(CS, 26, cs, 0, 2)\ -X(SS, 27, ss, 0, 2)\ -X(DS, 28, ds, 0, 2)\ -X(FS, 29, fs, 0, 2)\ -X(GS, 30, gs, 0, 2)\ -X(IP, 31, eip, 0, 2)\ -X(FLAGS, 32, eflags, 0, 2)\ -X(EIP, 33, eip, 0, 4)\ -X(EFLAGS, 34, eflags, 0, 4)\ -X(MM0, 146, fpr0, 0, 8)\ -X(MM1, 147, fpr1, 0, 8)\ -X(MM2, 148, fpr2, 0, 8)\ -X(MM3, 149, fpr3, 0, 8)\ -X(MM4, 150, fpr4, 0, 8)\ -X(MM5, 151, fpr5, 0, 8)\ -X(MM6, 152, fpr6, 0, 8)\ -X(MM7, 153, fpr7, 0, 8)\ -X(XMM0, 154, ymm0, 0, 16)\ -X(XMM1, 155, ymm1, 0, 16)\ -X(XMM2, 156, ymm2, 0, 16)\ -X(XMM3, 157, ymm3, 0, 16)\ -X(XMM4, 158, ymm4, 0, 16)\ -X(XMM5, 159, ymm5, 0, 16)\ -X(XMM6, 160, ymm6, 0, 16)\ -X(XMM7, 161, ymm7, 0, 16)\ -X(XMM00, 162, ymm0, 0, 4)\ -X(XMM01, 163, ymm0, 4, 4)\ -X(XMM02, 164, ymm0, 8, 4)\ -X(XMM03, 165, ymm0, 12, 4)\ -X(XMM10, 166, ymm1, 0, 4)\ -X(XMM11, 167, ymm1, 4, 4)\ -X(XMM12, 168, ymm1, 8, 4)\ -X(XMM13, 169, ymm1, 12, 4)\ -X(XMM20, 170, ymm2, 0, 4)\ -X(XMM21, 171, ymm2, 4, 4)\ -X(XMM22, 172, ymm2, 8, 4)\ -X(XMM23, 173, ymm2, 12, 4)\ -X(XMM30, 174, ymm3, 0, 4)\ -X(XMM31, 175, ymm3, 4, 4)\ -X(XMM32, 176, ymm3, 8, 4)\ -X(XMM33, 177, ymm3, 12, 4)\ -X(XMM40, 178, ymm4, 0, 4)\ -X(XMM41, 179, ymm4, 4, 4)\ -X(XMM42, 180, ymm4, 8, 4)\ -X(XMM43, 181, ymm4, 12, 4)\ -X(XMM50, 182, ymm5, 0, 4)\ -X(XMM51, 183, ymm5, 4, 4)\ -X(XMM52, 184, ymm5, 8, 4)\ -X(XMM53, 185, ymm5, 12, 4)\ -X(XMM60, 186, ymm6, 0, 4)\ -X(XMM61, 187, ymm6, 4, 4)\ -X(XMM62, 188, ymm6, 8, 4)\ -X(XMM63, 189, ymm6, 12, 4)\ -X(XMM70, 190, ymm7, 0, 4)\ -X(XMM71, 191, ymm7, 4, 4)\ -X(XMM72, 192, ymm7, 8, 4)\ -X(XMM73, 193, ymm7, 12, 4)\ -X(XMM0L, 194, ymm0, 0, 8)\ -X(XMM1L, 195, ymm1, 0, 8)\ -X(XMM2L, 196, ymm2, 0, 8)\ -X(XMM3L, 197, ymm3, 0, 8)\ -X(XMM4L, 198, ymm4, 0, 8)\ -X(XMM5L, 199, ymm5, 0, 8)\ -X(XMM6L, 200, ymm6, 0, 8)\ -X(XMM7L, 201, ymm7, 0, 8)\ -X(XMM0H, 202, ymm0, 8, 8)\ -X(XMM1H, 203, ymm1, 8, 8)\ -X(XMM2H, 204, ymm2, 8, 8)\ -X(XMM3H, 205, ymm3, 8, 8)\ -X(XMM4H, 206, ymm4, 8, 8)\ -X(XMM5H, 207, ymm5, 8, 8)\ -X(XMM6H, 208, ymm6, 8, 8)\ -X(XMM7H, 209, ymm7, 8, 8)\ -X(YMM0, 252, ymm0, 0, 32)\ -X(YMM1, 253, ymm1, 0, 32)\ -X(YMM2, 254, ymm2, 0, 32)\ -X(YMM3, 255, ymm3, 0, 32)\ -X(YMM4, 256, ymm4, 0, 32)\ -X(YMM5, 257, ymm5, 0, 32)\ -X(YMM6, 258, ymm6, 0, 32)\ -X(YMM7, 259, ymm7, 0, 32)\ -X(YMM0H, 260, ymm0, 16, 16)\ -X(YMM1H, 261, ymm1, 16, 16)\ -X(YMM2H, 262, ymm2, 16, 16)\ -X(YMM3H, 263, ymm3, 16, 16)\ -X(YMM4H, 264, ymm4, 16, 16)\ -X(YMM5H, 265, ymm5, 16, 16)\ -X(YMM6H, 266, ymm6, 16, 16)\ -X(YMM7H, 267, ymm7, 16, 16)\ -X(YMM0I0, 268, ymm0, 0, 8)\ -X(YMM0I1, 269, ymm0, 8, 8)\ -X(YMM0I2, 270, ymm0, 16, 8)\ -X(YMM0I3, 271, ymm0, 24, 8)\ -X(YMM1I0, 272, ymm1, 0, 8)\ -X(YMM1I1, 273, ymm1, 8, 8)\ -X(YMM1I2, 274, ymm1, 16, 8)\ -X(YMM1I3, 275, ymm1, 24, 8)\ -X(YMM2I0, 276, ymm2, 0, 8)\ -X(YMM2I1, 277, ymm2, 8, 8)\ -X(YMM2I2, 278, ymm2, 16, 8)\ -X(YMM2I3, 279, ymm2, 24, 8)\ -X(YMM3I0, 280, ymm3, 0, 8)\ -X(YMM3I1, 281, ymm3, 8, 8)\ -X(YMM3I2, 282, ymm3, 16, 8)\ -X(YMM3I3, 283, ymm3, 24, 8)\ -X(YMM4I0, 284, ymm4, 0, 8)\ -X(YMM4I1, 285, ymm4, 8, 8)\ -X(YMM4I2, 286, ymm4, 16, 8)\ -X(YMM4I3, 287, ymm4, 24, 8)\ -X(YMM5I0, 288, ymm5, 0, 8)\ -X(YMM5I1, 289, ymm5, 8, 8)\ -X(YMM5I2, 290, ymm5, 16, 8)\ -X(YMM5I3, 291, ymm5, 24, 8)\ -X(YMM6I0, 292, ymm6, 0, 8)\ -X(YMM6I1, 293, ymm6, 8, 8)\ -X(YMM6I2, 294, ymm6, 16, 8)\ -X(YMM6I3, 295, ymm6, 24, 8)\ -X(YMM7I0, 296, ymm7, 0, 8)\ -X(YMM7I1, 297, ymm7, 8, 8)\ -X(YMM7I2, 298, ymm7, 16, 8)\ -X(YMM7I3, 299, ymm7, 24, 8)\ -X(YMM0F0, 300, ymm0, 0, 4)\ -X(YMM0F1, 301, ymm0, 4, 4)\ -X(YMM0F2, 302, ymm0, 8, 4)\ -X(YMM0F3, 303, ymm0, 12, 4)\ -X(YMM0F4, 304, ymm0, 16, 4)\ -X(YMM0F5, 305, ymm0, 20, 4)\ -X(YMM0F6, 306, ymm0, 24, 4)\ -X(YMM0F7, 307, ymm0, 28, 4)\ -X(YMM1F0, 308, ymm1, 0, 4)\ -X(YMM1F1, 309, ymm1, 4, 4)\ -X(YMM1F2, 310, ymm1, 8, 4)\ -X(YMM1F3, 311, ymm1, 12, 4)\ -X(YMM1F4, 312, ymm1, 16, 4)\ -X(YMM1F5, 313, ymm1, 20, 4)\ -X(YMM1F6, 314, ymm1, 24, 4)\ -X(YMM1F7, 315, ymm1, 28, 4)\ -X(YMM2F0, 316, ymm2, 0, 4)\ -X(YMM2F1, 317, ymm2, 4, 4)\ -X(YMM2F2, 318, ymm2, 8, 4)\ -X(YMM2F3, 319, ymm2, 12, 4)\ -X(YMM2F4, 320, ymm2, 16, 4)\ -X(YMM2F5, 321, ymm2, 20, 4)\ -X(YMM2F6, 322, ymm2, 24, 4)\ -X(YMM2F7, 323, ymm2, 28, 4)\ -X(YMM3F0, 324, ymm3, 0, 4)\ -X(YMM3F1, 325, ymm3, 4, 4)\ -X(YMM3F2, 326, ymm3, 8, 4)\ -X(YMM3F3, 327, ymm3, 12, 4)\ -X(YMM3F4, 328, ymm3, 16, 4)\ -X(YMM3F5, 329, ymm3, 20, 4)\ -X(YMM3F6, 330, ymm3, 24, 4)\ -X(YMM3F7, 331, ymm3, 28, 4)\ -X(YMM4F0, 332, ymm4, 0, 4)\ -X(YMM4F1, 333, ymm4, 4, 4)\ -X(YMM4F2, 334, ymm4, 8, 4)\ -X(YMM4F3, 335, ymm4, 12, 4)\ -X(YMM4F4, 336, ymm4, 16, 4)\ -X(YMM4F5, 337, ymm4, 20, 4)\ -X(YMM4F6, 338, ymm4, 24, 4)\ -X(YMM4F7, 339, ymm4, 28, 4)\ -X(YMM5F0, 340, ymm5, 0, 4)\ -X(YMM5F1, 341, ymm5, 4, 4)\ -X(YMM5F2, 342, ymm5, 8, 4)\ -X(YMM5F3, 343, ymm5, 12, 4)\ -X(YMM5F4, 344, ymm5, 16, 4)\ -X(YMM5F5, 345, ymm5, 20, 4)\ -X(YMM5F6, 346, ymm5, 24, 4)\ -X(YMM5F7, 347, ymm5, 28, 4)\ -X(YMM6F0, 348, ymm6, 0, 4)\ -X(YMM6F1, 349, ymm6, 4, 4)\ -X(YMM6F2, 350, ymm6, 8, 4)\ -X(YMM6F3, 351, ymm6, 12, 4)\ -X(YMM6F4, 352, ymm6, 16, 4)\ -X(YMM6F5, 353, ymm6, 20, 4)\ -X(YMM6F6, 354, ymm6, 24, 4)\ -X(YMM6F7, 355, ymm6, 28, 4)\ -X(YMM7F0, 356, ymm7, 0, 4)\ -X(YMM7F1, 357, ymm7, 4, 4)\ -X(YMM7F2, 358, ymm7, 8, 4)\ -X(YMM7F3, 359, ymm7, 12, 4)\ -X(YMM7F4, 360, ymm7, 16, 4)\ -X(YMM7F5, 361, ymm7, 20, 4)\ -X(YMM7F6, 362, ymm7, 24, 4)\ -X(YMM7F7, 363, ymm7, 28, 4)\ -X(YMM0D0, 364, ymm0, 0, 8)\ -X(YMM0D1, 365, ymm0, 8, 8)\ -X(YMM0D2, 366, ymm0, 16, 8)\ -X(YMM0D3, 367, ymm0, 24, 8)\ -X(YMM1D0, 368, ymm1, 0, 8)\ -X(YMM1D1, 369, ymm1, 8, 8)\ -X(YMM1D2, 370, ymm1, 16, 8)\ -X(YMM1D3, 371, ymm1, 24, 8)\ -X(YMM2D0, 372, ymm2, 0, 8)\ -X(YMM2D1, 373, ymm2, 8, 8)\ -X(YMM2D2, 374, ymm2, 16, 8)\ -X(YMM2D3, 375, ymm2, 24, 8)\ -X(YMM3D0, 376, ymm3, 0, 8)\ -X(YMM3D1, 377, ymm3, 8, 8)\ -X(YMM3D2, 378, ymm3, 16, 8)\ -X(YMM3D3, 379, ymm3, 24, 8)\ -X(YMM4D0, 380, ymm4, 0, 8)\ -X(YMM4D1, 381, ymm4, 8, 8)\ -X(YMM4D2, 382, ymm4, 16, 8)\ -X(YMM4D3, 383, ymm4, 24, 8)\ -X(YMM5D0, 384, ymm5, 0, 8)\ -X(YMM5D1, 385, ymm5, 8, 8)\ -X(YMM5D2, 386, ymm5, 16, 8)\ -X(YMM5D3, 387, ymm5, 24, 8)\ -X(YMM6D0, 388, ymm6, 0, 8)\ -X(YMM6D1, 389, ymm6, 8, 8)\ -X(YMM6D2, 390, ymm6, 16, 8)\ -X(YMM6D3, 391, ymm6, 24, 8)\ -X(YMM7D0, 392, ymm7, 0, 8)\ -X(YMM7D1, 393, ymm7, 8, 8)\ -X(YMM7D2, 394, ymm7, 16, 8)\ -X(YMM7D3, 395, ymm7, 24, 8) +#define CV_Reg_X86_XList(X) \ + X(NONE, 0, nil, 0, 0) \ + X(AL, 1, eax, 0, 1) \ + X(CL, 2, ecx, 0, 1) \ + X(DL, 3, edx, 0, 1) \ + X(BL, 4, ebx, 0, 1) \ + X(AH, 5, eax, 1, 1) \ + X(CH, 6, ecx, 1, 1) \ + X(DH, 7, edx, 1, 1) \ + X(BH, 8, ebx, 1, 1) \ + X(AX, 9, eax, 0, 2) \ + X(CX, 10, ecx, 0, 2) \ + X(DX, 11, edx, 0, 2) \ + X(BX, 12, ebx, 0, 2) \ + X(SP, 13, esp, 0, 2) \ + X(BP, 14, ebp, 0, 2) \ + X(SI, 15, esi, 0, 2) \ + X(DI, 16, edi, 0, 2) \ + X(EAX, 17, eax, 0, 4) \ + X(ECX, 18, ecx, 0, 4) \ + X(EDX, 19, edx, 0, 4) \ + X(EBX, 20, ebx, 0, 4) \ + X(ESP, 21, esp, 0, 4) \ + X(EBP, 22, ebp, 0, 4) \ + X(ESI, 23, esi, 0, 4) \ + X(EDI, 24, edi, 0, 4) \ + X(ES, 25, es, 0, 2) \ + X(CS, 26, cs, 0, 2) \ + X(SS, 27, ss, 0, 2) \ + X(DS, 28, ds, 0, 2) \ + X(FS, 29, fs, 0, 2) \ + X(GS, 30, gs, 0, 2) \ + X(IP, 31, eip, 0, 2) \ + X(FLAGS, 32, eflags, 0, 2) \ + X(EIP, 33, eip, 0, 4) \ + X(EFLAGS, 34, eflags, 0, 4) \ + X(MM0, 146, fpr0, 0, 8) \ + X(MM1, 147, fpr1, 0, 8) \ + X(MM2, 148, fpr2, 0, 8) \ + X(MM3, 149, fpr3, 0, 8) \ + X(MM4, 150, fpr4, 0, 8) \ + X(MM5, 151, fpr5, 0, 8) \ + X(MM6, 152, fpr6, 0, 8) \ + X(MM7, 153, fpr7, 0, 8) \ + X(XMM0, 154, ymm0, 0, 16) \ + X(XMM1, 155, ymm1, 0, 16) \ + X(XMM2, 156, ymm2, 0, 16) \ + X(XMM3, 157, ymm3, 0, 16) \ + X(XMM4, 158, ymm4, 0, 16) \ + X(XMM5, 159, ymm5, 0, 16) \ + X(XMM6, 160, ymm6, 0, 16) \ + X(XMM7, 161, ymm7, 0, 16) \ + X(XMM00, 162, ymm0, 0, 4) \ + X(XMM01, 163, ymm0, 4, 4) \ + X(XMM02, 164, ymm0, 8, 4) \ + X(XMM03, 165, ymm0, 12, 4) \ + X(XMM10, 166, ymm1, 0, 4) \ + X(XMM11, 167, ymm1, 4, 4) \ + X(XMM12, 168, ymm1, 8, 4) \ + X(XMM13, 169, ymm1, 12, 4) \ + X(XMM20, 170, ymm2, 0, 4) \ + X(XMM21, 171, ymm2, 4, 4) \ + X(XMM22, 172, ymm2, 8, 4) \ + X(XMM23, 173, ymm2, 12, 4) \ + X(XMM30, 174, ymm3, 0, 4) \ + X(XMM31, 175, ymm3, 4, 4) \ + X(XMM32, 176, ymm3, 8, 4) \ + X(XMM33, 177, ymm3, 12, 4) \ + X(XMM40, 178, ymm4, 0, 4) \ + X(XMM41, 179, ymm4, 4, 4) \ + X(XMM42, 180, ymm4, 8, 4) \ + X(XMM43, 181, ymm4, 12, 4) \ + X(XMM50, 182, ymm5, 0, 4) \ + X(XMM51, 183, ymm5, 4, 4) \ + X(XMM52, 184, ymm5, 8, 4) \ + X(XMM53, 185, ymm5, 12, 4) \ + X(XMM60, 186, ymm6, 0, 4) \ + X(XMM61, 187, ymm6, 4, 4) \ + X(XMM62, 188, ymm6, 8, 4) \ + X(XMM63, 189, ymm6, 12, 4) \ + X(XMM70, 190, ymm7, 0, 4) \ + X(XMM71, 191, ymm7, 4, 4) \ + X(XMM72, 192, ymm7, 8, 4) \ + X(XMM73, 193, ymm7, 12, 4) \ + X(XMM0L, 194, ymm0, 0, 8) \ + X(XMM1L, 195, ymm1, 0, 8) \ + X(XMM2L, 196, ymm2, 0, 8) \ + X(XMM3L, 197, ymm3, 0, 8) \ + X(XMM4L, 198, ymm4, 0, 8) \ + X(XMM5L, 199, ymm5, 0, 8) \ + X(XMM6L, 200, ymm6, 0, 8) \ + X(XMM7L, 201, ymm7, 0, 8) \ + X(XMM0H, 202, ymm0, 8, 8) \ + X(XMM1H, 203, ymm1, 8, 8) \ + X(XMM2H, 204, ymm2, 8, 8) \ + X(XMM3H, 205, ymm3, 8, 8) \ + X(XMM4H, 206, ymm4, 8, 8) \ + X(XMM5H, 207, ymm5, 8, 8) \ + X(XMM6H, 208, ymm6, 8, 8) \ + X(XMM7H, 209, ymm7, 8, 8) \ + X(YMM0, 252, ymm0, 0, 32) \ + X(YMM1, 253, ymm1, 0, 32) \ + X(YMM2, 254, ymm2, 0, 32) \ + X(YMM3, 255, ymm3, 0, 32) \ + X(YMM4, 256, ymm4, 0, 32) \ + X(YMM5, 257, ymm5, 0, 32) \ + X(YMM6, 258, ymm6, 0, 32) \ + X(YMM7, 259, ymm7, 0, 32) \ + X(YMM0H, 260, ymm0, 16, 16) \ + X(YMM1H, 261, ymm1, 16, 16) \ + X(YMM2H, 262, ymm2, 16, 16) \ + X(YMM3H, 263, ymm3, 16, 16) \ + X(YMM4H, 264, ymm4, 16, 16) \ + X(YMM5H, 265, ymm5, 16, 16) \ + X(YMM6H, 266, ymm6, 16, 16) \ + X(YMM7H, 267, ymm7, 16, 16) \ + X(YMM0I0, 268, ymm0, 0, 8) \ + X(YMM0I1, 269, ymm0, 8, 8) \ + X(YMM0I2, 270, ymm0, 16, 8) \ + X(YMM0I3, 271, ymm0, 24, 8) \ + X(YMM1I0, 272, ymm1, 0, 8) \ + X(YMM1I1, 273, ymm1, 8, 8) \ + X(YMM1I2, 274, ymm1, 16, 8) \ + X(YMM1I3, 275, ymm1, 24, 8) \ + X(YMM2I0, 276, ymm2, 0, 8) \ + X(YMM2I1, 277, ymm2, 8, 8) \ + X(YMM2I2, 278, ymm2, 16, 8) \ + X(YMM2I3, 279, ymm2, 24, 8) \ + X(YMM3I0, 280, ymm3, 0, 8) \ + X(YMM3I1, 281, ymm3, 8, 8) \ + X(YMM3I2, 282, ymm3, 16, 8) \ + X(YMM3I3, 283, ymm3, 24, 8) \ + X(YMM4I0, 284, ymm4, 0, 8) \ + X(YMM4I1, 285, ymm4, 8, 8) \ + X(YMM4I2, 286, ymm4, 16, 8) \ + X(YMM4I3, 287, ymm4, 24, 8) \ + X(YMM5I0, 288, ymm5, 0, 8) \ + X(YMM5I1, 289, ymm5, 8, 8) \ + X(YMM5I2, 290, ymm5, 16, 8) \ + X(YMM5I3, 291, ymm5, 24, 8) \ + X(YMM6I0, 292, ymm6, 0, 8) \ + X(YMM6I1, 293, ymm6, 8, 8) \ + X(YMM6I2, 294, ymm6, 16, 8) \ + X(YMM6I3, 295, ymm6, 24, 8) \ + X(YMM7I0, 296, ymm7, 0, 8) \ + X(YMM7I1, 297, ymm7, 8, 8) \ + X(YMM7I2, 298, ymm7, 16, 8) \ + X(YMM7I3, 299, ymm7, 24, 8) \ + X(YMM0F0, 300, ymm0, 0, 4) \ + X(YMM0F1, 301, ymm0, 4, 4) \ + X(YMM0F2, 302, ymm0, 8, 4) \ + X(YMM0F3, 303, ymm0, 12, 4) \ + X(YMM0F4, 304, ymm0, 16, 4) \ + X(YMM0F5, 305, ymm0, 20, 4) \ + X(YMM0F6, 306, ymm0, 24, 4) \ + X(YMM0F7, 307, ymm0, 28, 4) \ + X(YMM1F0, 308, ymm1, 0, 4) \ + X(YMM1F1, 309, ymm1, 4, 4) \ + X(YMM1F2, 310, ymm1, 8, 4) \ + X(YMM1F3, 311, ymm1, 12, 4) \ + X(YMM1F4, 312, ymm1, 16, 4) \ + X(YMM1F5, 313, ymm1, 20, 4) \ + X(YMM1F6, 314, ymm1, 24, 4) \ + X(YMM1F7, 315, ymm1, 28, 4) \ + X(YMM2F0, 316, ymm2, 0, 4) \ + X(YMM2F1, 317, ymm2, 4, 4) \ + X(YMM2F2, 318, ymm2, 8, 4) \ + X(YMM2F3, 319, ymm2, 12, 4) \ + X(YMM2F4, 320, ymm2, 16, 4) \ + X(YMM2F5, 321, ymm2, 20, 4) \ + X(YMM2F6, 322, ymm2, 24, 4) \ + X(YMM2F7, 323, ymm2, 28, 4) \ + X(YMM3F0, 324, ymm3, 0, 4) \ + X(YMM3F1, 325, ymm3, 4, 4) \ + X(YMM3F2, 326, ymm3, 8, 4) \ + X(YMM3F3, 327, ymm3, 12, 4) \ + X(YMM3F4, 328, ymm3, 16, 4) \ + X(YMM3F5, 329, ymm3, 20, 4) \ + X(YMM3F6, 330, ymm3, 24, 4) \ + X(YMM3F7, 331, ymm3, 28, 4) \ + X(YMM4F0, 332, ymm4, 0, 4) \ + X(YMM4F1, 333, ymm4, 4, 4) \ + X(YMM4F2, 334, ymm4, 8, 4) \ + X(YMM4F3, 335, ymm4, 12, 4) \ + X(YMM4F4, 336, ymm4, 16, 4) \ + X(YMM4F5, 337, ymm4, 20, 4) \ + X(YMM4F6, 338, ymm4, 24, 4) \ + X(YMM4F7, 339, ymm4, 28, 4) \ + X(YMM5F0, 340, ymm5, 0, 4) \ + X(YMM5F1, 341, ymm5, 4, 4) \ + X(YMM5F2, 342, ymm5, 8, 4) \ + X(YMM5F3, 343, ymm5, 12, 4) \ + X(YMM5F4, 344, ymm5, 16, 4) \ + X(YMM5F5, 345, ymm5, 20, 4) \ + X(YMM5F6, 346, ymm5, 24, 4) \ + X(YMM5F7, 347, ymm5, 28, 4) \ + X(YMM6F0, 348, ymm6, 0, 4) \ + X(YMM6F1, 349, ymm6, 4, 4) \ + X(YMM6F2, 350, ymm6, 8, 4) \ + X(YMM6F3, 351, ymm6, 12, 4) \ + X(YMM6F4, 352, ymm6, 16, 4) \ + X(YMM6F5, 353, ymm6, 20, 4) \ + X(YMM6F6, 354, ymm6, 24, 4) \ + X(YMM6F7, 355, ymm6, 28, 4) \ + X(YMM7F0, 356, ymm7, 0, 4) \ + X(YMM7F1, 357, ymm7, 4, 4) \ + X(YMM7F2, 358, ymm7, 8, 4) \ + X(YMM7F3, 359, ymm7, 12, 4) \ + X(YMM7F4, 360, ymm7, 16, 4) \ + X(YMM7F5, 361, ymm7, 20, 4) \ + X(YMM7F6, 362, ymm7, 24, 4) \ + X(YMM7F7, 363, ymm7, 28, 4) \ + X(YMM0D0, 364, ymm0, 0, 8) \ + X(YMM0D1, 365, ymm0, 8, 8) \ + X(YMM0D2, 366, ymm0, 16, 8) \ + X(YMM0D3, 367, ymm0, 24, 8) \ + X(YMM1D0, 368, ymm1, 0, 8) \ + X(YMM1D1, 369, ymm1, 8, 8) \ + X(YMM1D2, 370, ymm1, 16, 8) \ + X(YMM1D3, 371, ymm1, 24, 8) \ + X(YMM2D0, 372, ymm2, 0, 8) \ + X(YMM2D1, 373, ymm2, 8, 8) \ + X(YMM2D2, 374, ymm2, 16, 8) \ + X(YMM2D3, 375, ymm2, 24, 8) \ + X(YMM3D0, 376, ymm3, 0, 8) \ + X(YMM3D1, 377, ymm3, 8, 8) \ + X(YMM3D2, 378, ymm3, 16, 8) \ + X(YMM3D3, 379, ymm3, 24, 8) \ + X(YMM4D0, 380, ymm4, 0, 8) \ + X(YMM4D1, 381, ymm4, 8, 8) \ + X(YMM4D2, 382, ymm4, 16, 8) \ + X(YMM4D3, 383, ymm4, 24, 8) \ + X(YMM5D0, 384, ymm5, 0, 8) \ + X(YMM5D1, 385, ymm5, 8, 8) \ + X(YMM5D2, 386, ymm5, 16, 8) \ + X(YMM5D3, 387, ymm5, 24, 8) \ + X(YMM6D0, 388, ymm6, 0, 8) \ + X(YMM6D1, 389, ymm6, 8, 8) \ + X(YMM6D2, 390, ymm6, 16, 8) \ + X(YMM6D3, 391, ymm6, 24, 8) \ + X(YMM7D0, 392, ymm7, 0, 8) \ + X(YMM7D1, 393, ymm7, 8, 8) \ + X(YMM7D2, 394, ymm7, 16, 8) \ + X(YMM7D3, 395, ymm7, 24, 8) typedef U16 CV_Regx86; typedef enum CV_Regx86Enum @@ -289,712 +297,712 @@ typedef enum CV_Regx86Enum CV_Regx86Enum; // X(NAME, CODE, (RDI_RegisterCode_X64) NAME, BYTE_POS, BYTE_SIZE) -#define CV_Reg_X64_XList(X) \ -X(NONE, 0, nil, 0, 0)\ -X(AL, 1, rax, 0, 1)\ -X(CL, 2, rcx, 0, 1)\ -X(DL, 3, rdx, 0, 1)\ -X(BL, 4, rbx, 0, 1)\ -X(AH, 5, rax, 1, 1)\ -X(CH, 6, rcx, 1, 1)\ -X(DH, 7, rdx, 1, 1)\ -X(BH, 8, rbx, 1, 1)\ -X(AX, 9, rax, 0, 2)\ -X(CX, 10, rcx, 0, 2)\ -X(DX, 11, rdx, 0, 2)\ -X(BX, 12, rbx, 0, 2)\ -X(SP, 13, rsp, 0, 2)\ -X(BP, 14, rbp, 0, 2)\ -X(SI, 15, rsi, 0, 2)\ -X(DI, 16, rdi, 0, 2)\ -X(EAX, 17, rax, 0, 4)\ -X(ECX, 18, rcx, 0, 4)\ -X(EDX, 19, rdx, 0, 4)\ -X(EBX, 20, rbx, 0, 4)\ -X(ESP, 21, rsp, 0, 4)\ -X(EBP, 22, rbp, 0, 4)\ -X(ESI, 23, rsi, 0, 4)\ -X(EDI, 24, rdi, 0, 4)\ -X(ES, 25, es, 0, 2)\ -X(CS, 26, cs, 0, 2)\ -X(SS, 27, ss, 0, 2)\ -X(DS, 28, ds, 0, 2)\ -X(FS, 29, fs, 0, 2)\ -X(GS, 30, gs, 0, 2)\ -X(FLAGS, 32, rflags, 0, 2)\ -X(RIP, 33, rip, 0, 8)\ -X(EFLAGS, 34, rflags, 0, 4)\ -/* TODO: possibly missing control registers in x64 definitions? */ \ -X(CR0, 80, nil, 0, 0)\ -X(CR1, 81, nil, 0, 0)\ -X(CR2, 82, nil, 0, 0)\ -X(CR3, 83, nil, 0, 0)\ -X(CR4, 84, nil, 0, 0)\ -X(CR8, 88, nil, 0, 0)\ -X(DR0, 90, dr0, 0, 4)\ -X(DR1, 91, dr1, 0, 4)\ -X(DR2, 92, dr2, 0, 4)\ -X(DR3, 93, dr3, 0, 4)\ -X(DR4, 94, dr4, 0, 4)\ -X(DR5, 95, dr5, 0, 4)\ -X(DR6, 96, dr6, 0, 4)\ -X(DR7, 97, dr7, 0, 4)\ -/* TODO: possibly missing debug registers 8-15 in x64 definitions? */ \ -X(DR8, 98, nil, 0, 0)\ -X(DR9, 99, nil, 0, 0)\ -X(DR10, 100, nil, 0, 0)\ -X(DR11, 101, nil, 0, 0)\ -X(DR12, 102, nil, 0, 0)\ -X(DR13, 103, nil, 0, 0)\ -X(DR14, 104, nil, 0, 0)\ -X(DR15, 105, nil, 0, 0)\ -/* TODO: possibly missing ~whatever these are~ in x64 definitions? */ \ -X(GDTR, 110, nil, 0, 0)\ -X(GDTL, 111, nil, 0, 0)\ -X(IDTR, 112, nil, 0, 0)\ -X(IDTL, 113, nil, 0, 0)\ -X(LDTR, 114, nil, 0, 0)\ -X(TR, 115, nil, 0, 0)\ -X(ST0, 128, st0, 0, 10)\ -X(ST1, 129, st1, 0, 10)\ -X(ST2, 130, st2, 0, 10)\ -X(ST3, 131, st3, 0, 10)\ -X(ST4, 132, st4, 0, 10)\ -X(ST5, 133, st5, 0, 10)\ -X(ST6, 134, st6, 0, 10)\ -X(ST7, 135, st7, 0, 10)\ -/* TODO: possibly missing these, or not sure how they map to our x64 definitions? */ \ -X(CTRL, 136, nil, 0, 0)\ -X(STAT, 137, nil, 0, 0)\ -X(TAG, 138, nil, 0, 0)\ -X(FPIP, 139, nil, 0, 0)\ -X(FPCS, 140, nil, 0, 0)\ -X(FPDO, 141, nil, 0, 0)\ -X(FPDS, 142, nil, 0, 0)\ -X(ISEM, 143, nil, 0, 0)\ -X(FPEIP, 144, nil, 0, 0)\ -X(FPEDO, 145, nil, 0, 0)\ -X(MM0, 146, fpr0, 0, 8)\ -X(MM1, 147, fpr1, 0, 8)\ -X(MM2, 148, fpr2, 0, 8)\ -X(MM3, 149, fpr3, 0, 8)\ -X(MM4, 150, fpr4, 0, 8)\ -X(MM5, 151, fpr5, 0, 8)\ -X(MM6, 152, fpr6, 0, 8)\ -X(MM7, 153, fpr7, 0, 8)\ -X(XMM0, 154, zmm0, 0, 16)\ -X(XMM1, 155, zmm1, 0, 16)\ -X(XMM2, 156, zmm2, 0, 16)\ -X(XMM3, 157, zmm3, 0, 16)\ -X(XMM4, 158, zmm4, 0, 16)\ -X(XMM5, 159, zmm5, 0, 16)\ -X(XMM6, 160, zmm6, 0, 16)\ -X(XMM7, 161, zmm7, 0, 16)\ -X(XMM0_0, 162, zmm0, 0, 4)\ -X(XMM0_1, 163, zmm0, 4, 4)\ -X(XMM0_2, 164, zmm0, 8, 4)\ -X(XMM0_3, 165, zmm0, 12, 4)\ -X(XMM1_0, 166, zmm1, 0, 4)\ -X(XMM1_1, 167, zmm1, 4, 4)\ -X(XMM1_2, 168, zmm1, 8, 4)\ -X(XMM1_3, 169, zmm1, 12, 4)\ -X(XMM2_0, 170, zmm2, 0, 4)\ -X(XMM2_1, 171, zmm2, 4, 4)\ -X(XMM2_2, 172, zmm2, 8, 4)\ -X(XMM2_3, 173, zmm2, 12, 4)\ -X(XMM3_0, 174, zmm3, 0, 4)\ -X(XMM3_1, 175, zmm3, 4, 4)\ -X(XMM3_2, 176, zmm3, 8, 4)\ -X(XMM3_3, 177, zmm3, 12, 4)\ -X(XMM4_0, 178, zmm4, 0, 4)\ -X(XMM4_1, 179, zmm4, 4, 4)\ -X(XMM4_2, 180, zmm4, 8, 4)\ -X(XMM4_3, 181, zmm4, 12, 4)\ -X(XMM5_0, 182, zmm5, 0, 4)\ -X(XMM5_1, 183, zmm5, 4, 4)\ -X(XMM5_2, 184, zmm5, 8, 4)\ -X(XMM5_3, 185, zmm5, 12, 4)\ -X(XMM6_0, 186, zmm6, 0, 4)\ -X(XMM6_1, 187, zmm6, 4, 4)\ -X(XMM6_2, 188, zmm6, 8, 4)\ -X(XMM6_3, 189, zmm6, 12, 4)\ -X(XMM7_0, 190, zmm7, 0, 4)\ -X(XMM7_1, 191, zmm7, 4, 4)\ -X(XMM7_2, 192, zmm7, 8, 4)\ -X(XMM7_3, 193, zmm7, 12, 4)\ -X(XMM0L, 194, zmm0, 0, 8)\ -X(XMM1L, 195, zmm1, 0, 8)\ -X(XMM2L, 196, zmm2, 0, 8)\ -X(XMM3L, 197, zmm3, 0, 8)\ -X(XMM4L, 198, zmm4, 0, 8)\ -X(XMM5L, 199, zmm5, 0, 8)\ -X(XMM6L, 200, zmm6, 0, 8)\ -X(XMM7L, 201, zmm7, 0, 8)\ -X(XMM0H, 202, zmm0, 8, 8)\ -X(XMM1H, 203, zmm1, 8, 8)\ -X(XMM2H, 204, zmm2, 8, 8)\ -X(XMM3H, 205, zmm3, 8, 8)\ -X(XMM4H, 206, zmm4, 8, 8)\ -X(XMM5H, 207, zmm5, 8, 8)\ -X(XMM6H, 208, zmm6, 8, 8)\ -X(XMM7H, 209, zmm7, 8, 8)\ -X(MXCSR, 211, mxcsr, 0, 4)\ -X(EMM0L, 220, zmm0, 0, 8)\ -X(EMM1L, 221, zmm1, 0, 8)\ -X(EMM2L, 222, zmm2, 0, 8)\ -X(EMM3L, 223, zmm3, 0, 8)\ -X(EMM4L, 224, zmm4, 0, 8)\ -X(EMM5L, 225, zmm5, 0, 8)\ -X(EMM6L, 226, zmm6, 0, 8)\ -X(EMM7L, 227, zmm7, 0, 8)\ -X(EMM0H, 228, zmm0, 8, 8)\ -X(EMM1H, 229, zmm1, 8, 8)\ -X(EMM2H, 230, zmm2, 8, 8)\ -X(EMM3H, 231, zmm3, 8, 8)\ -X(EMM4H, 232, zmm4, 8, 8)\ -X(EMM5H, 233, zmm5, 8, 8)\ -X(EMM6H, 234, zmm6, 8, 8)\ -X(EMM7H, 235, zmm7, 8, 8)\ -X(MM00, 236, fpr0, 0, 4)\ -X(MM01, 237, fpr0, 4, 4)\ -X(MM10, 238, fpr1, 0, 4)\ -X(MM11, 239, fpr1, 4, 4)\ -X(MM20, 240, fpr2, 0, 4)\ -X(MM21, 241, fpr2, 4, 4)\ -X(MM30, 242, fpr3, 0, 4)\ -X(MM31, 243, fpr3, 4, 4)\ -X(MM40, 244, fpr4, 0, 4)\ -X(MM41, 245, fpr4, 4, 4)\ -X(MM50, 246, fpr5, 0, 4)\ -X(MM51, 247, fpr5, 4, 4)\ -X(MM60, 248, fpr6, 0, 4)\ -X(MM61, 249, fpr6, 4, 4)\ -X(MM70, 250, fpr7, 0, 4)\ -X(MM71, 251, fpr7, 4, 4)\ -X(XMM8, 252, zmm8, 0, 16)\ -X(XMM9, 253, zmm9, 0, 16)\ -X(XMM10, 254, zmm10, 0, 16)\ -X(XMM11, 255, zmm11, 0, 16)\ -X(XMM12, 256, zmm12, 0, 16)\ -X(XMM13, 257, zmm13, 0, 16)\ -X(XMM14, 258, zmm14, 0, 16)\ -X(XMM15, 259, zmm15, 0, 16)\ -X(XMM8_0, 260, zmm8, 0, 16)\ -X(XMM8_1, 261, zmm8, 4, 16)\ -X(XMM8_2, 262, zmm8, 8, 16)\ -X(XMM8_3, 263, zmm8, 12, 16)\ -X(XMM9_0, 264, zmm9, 0, 4)\ -X(XMM9_1, 265, zmm9, 4, 4)\ -X(XMM9_2, 266, zmm9, 8, 4)\ -X(XMM9_3, 267, zmm9, 12, 4)\ -X(XMM10_0, 268, zmm10, 0, 4)\ -X(XMM10_1, 269, zmm10, 4, 4)\ -X(XMM10_2, 270, zmm10, 8, 4)\ -X(XMM10_3, 271, zmm10, 12, 4)\ -X(XMM11_0, 272, zmm11, 0, 4)\ -X(XMM11_1, 273, zmm11, 4, 4)\ -X(XMM11_2, 274, zmm11, 8, 4)\ -X(XMM11_3, 275, zmm11, 12, 4)\ -X(XMM12_0, 276, zmm12, 0, 4)\ -X(XMM12_1, 277, zmm12, 4, 4)\ -X(XMM12_2, 278, zmm12, 8, 4)\ -X(XMM12_3, 279, zmm12, 12, 4)\ -X(XMM13_0, 280, zmm13, 0, 4)\ -X(XMM13_1, 281, zmm13, 4, 4)\ -X(XMM13_2, 282, zmm13, 8, 4)\ -X(XMM13_3, 283, zmm13, 12, 4)\ -X(XMM14_0, 284, zmm14, 0, 4)\ -X(XMM14_1, 285, zmm14, 4, 4)\ -X(XMM14_2, 286, zmm14, 8, 4)\ -X(XMM14_3, 287, zmm14, 12, 4)\ -X(XMM15_0, 288, zmm15, 0, 4)\ -X(XMM15_1, 289, zmm15, 4, 4)\ -X(XMM15_2, 290, zmm15, 8, 4)\ -X(XMM15_3, 291, zmm15, 12, 4)\ -X(XMM8L, 292, zmm8, 0, 8)\ -X(XMM9L, 293, zmm9, 0, 8)\ -X(XMM10L, 294, zmm10, 0, 8)\ -X(XMM11L, 295, zmm11, 0, 8)\ -X(XMM12L, 296, zmm12, 0, 8)\ -X(XMM13L, 297, zmm13, 0, 8)\ -X(XMM14L, 298, zmm14, 0, 8)\ -X(XMM15L, 299, zmm15, 0, 8)\ -X(XMM8H, 300, zmm8, 8, 8)\ -X(XMM9H, 301, zmm9, 8, 8)\ -X(XMM10H, 302, zmm10, 8, 8)\ -X(XMM11H, 303, zmm11, 8, 8)\ -X(XMM12H, 304, zmm12, 8, 8)\ -X(XMM13H, 305, zmm13, 8, 8)\ -X(XMM14H, 306, zmm14, 8, 8)\ -X(XMM15H, 307, zmm15, 8, 8)\ -X(EMM8L, 308, zmm8, 0, 8)\ -X(EMM9L, 309, zmm9, 0, 8)\ -X(EMM10L, 310, zmm10, 0, 8)\ -X(EMM11L, 311, zmm11, 0, 8)\ -X(EMM12L, 312, zmm12, 0, 8)\ -X(EMM13L, 313, zmm13, 0, 8)\ -X(EMM14L, 314, zmm14, 0, 8)\ -X(EMM15L, 315, zmm15, 0, 8)\ -X(EMM8H, 316, zmm8, 8, 8)\ -X(EMM9H, 317, zmm9, 8, 8)\ -X(EMM10H, 318, zmm10, 8, 8)\ -X(EMM11H, 319, zmm11, 8, 8)\ -X(EMM12H, 320, zmm12, 8, 8)\ -X(EMM13H, 321, zmm13, 8, 8)\ -X(EMM14H, 322, zmm14, 8, 8)\ -X(EMM15H, 323, zmm15, 8, 8)\ -X(SIL, 324, rsi, 0, 1)\ -X(DIL, 325, rdi, 0, 1)\ -X(BPL, 326, rbp, 0, 1)\ -X(SPL, 327, rsp, 0, 1)\ -X(RAX, 328, rax, 0, 8)\ -X(RBX, 329, rbx, 0, 8)\ -X(RCX, 330, rcx, 0, 8)\ -X(RDX, 331, rdx, 0, 8)\ -X(RSI, 332, rsi, 0, 8)\ -X(RDI, 333, rdi, 0, 8)\ -X(RBP, 334, rbp, 0, 8)\ -X(RSP, 335, rsp, 0, 8)\ -X(R8, 336, r8, 0, 8)\ -X(R9, 337, r9, 0, 8)\ -X(R10, 338, r10, 0, 8)\ -X(R11, 339, r11, 0, 8)\ -X(R12, 340, r12, 0, 8)\ -X(R13, 341, r13, 0, 8)\ -X(R14, 342, r14, 0, 8)\ -X(R15, 343, r15, 0, 8)\ -X(R8B, 344, r8, 0, 1)\ -X(R9B, 345, r9, 0, 1)\ -X(R10B, 346, r10, 0, 1)\ -X(R11B, 347, r11, 0, 1)\ -X(R12B, 348, r12, 0, 1)\ -X(R13B, 349, r13, 0, 1)\ -X(R14B, 350, r14, 0, 1)\ -X(R15B, 351, r15, 0, 1)\ -X(R8W, 352, r8, 0, 2)\ -X(R9W, 353, r9, 0, 2)\ -X(R10W, 354, r10, 0, 2)\ -X(R11W, 355, r11, 0, 2)\ -X(R12W, 356, r12, 0, 2)\ -X(R13W, 357, r13, 0, 2)\ -X(R14W, 358, r14, 0, 2)\ -X(R15W, 359, r15, 0, 2)\ -X(R8D, 360, r8, 0, 4)\ -X(R9D, 361, r9, 0, 4)\ -X(R10D, 362, r10, 0, 4)\ -X(R11D, 363, r11, 0, 4)\ -X(R12D, 364, r12, 0, 4)\ -X(R13D, 365, r13, 0, 4)\ -X(R14D, 366, r14, 0, 4)\ -X(R15D, 367, r15, 0, 4)\ -X(YMM0, 368, zmm0, 0, 32)\ -X(YMM1, 369, zmm1, 0, 32)\ -X(YMM2, 370, zmm2, 0, 32)\ -X(YMM3, 371, zmm3, 0, 32)\ -X(YMM4, 372, zmm4, 0, 32)\ -X(YMM5, 373, zmm5, 0, 32)\ -X(YMM6, 374, zmm6, 0, 32)\ -X(YMM7, 375, zmm7, 0, 32)\ -X(YMM8, 376, zmm8, 0, 32)\ -X(YMM9, 377, zmm9, 0, 32)\ -X(YMM10, 378, zmm10, 0, 32)\ -X(YMM11, 379, zmm11, 0, 32)\ -X(YMM12, 380, zmm12, 0, 32)\ -X(YMM13, 381, zmm13, 0, 32)\ -X(YMM14, 382, zmm14, 0, 32)\ -X(YMM15, 383, zmm15, 0, 32)\ -X(YMM0H, 384, zmm0, 16, 32)\ -X(YMM1H, 385, zmm1, 16, 32)\ -X(YMM2H, 386, zmm2, 16, 32)\ -X(YMM3H, 387, zmm3, 16, 32)\ -X(YMM4H, 388, zmm4, 16, 32)\ -X(YMM5H, 389, zmm5, 16, 32)\ -X(YMM6H, 390, zmm6, 16, 32)\ -X(YMM7H, 391, zmm7, 16, 32)\ -X(YMM8H, 392, zmm8, 16, 32)\ -X(YMM9H, 393, zmm9, 16, 32)\ -X(YMM10H, 394, zmm10, 16, 32)\ -X(YMM11H, 395, zmm11, 16, 32)\ -X(YMM12H, 396, zmm12, 16, 32)\ -X(YMM13H, 397, zmm13, 16, 32)\ -X(YMM14H, 398, zmm14, 16, 32)\ -X(YMM15H, 399, zmm15, 16, 32)\ -X(XMM0IL, 400, zmm0, 0, 8)\ -X(XMM1IL, 401, zmm1, 0, 8)\ -X(XMM2IL, 402, zmm2, 0, 8)\ -X(XMM3IL, 403, zmm3, 0, 8)\ -X(XMM4IL, 404, zmm4, 0, 8)\ -X(XMM5IL, 405, zmm5, 0, 8)\ -X(XMM6IL, 406, zmm6, 0, 8)\ -X(XMM7IL, 407, zmm7, 0, 8)\ -X(XMM8IL, 408, zmm8, 0, 8)\ -X(XMM9IL, 409, zmm9, 0, 8)\ -X(XMM10IL, 410, zmm10, 0, 8)\ -X(XMM11IL, 411, zmm11, 0, 8)\ -X(XMM12IL, 412, zmm12, 0, 8)\ -X(XMM13IL, 413, zmm13, 0, 8)\ -X(XMM14IL, 414, zmm14, 0, 8)\ -X(XMM15IL, 415, zmm15, 0, 8)\ -X(XMM0IH, 416, zmm0, 8, 8)\ -X(XMM1IH, 417, zmm1, 8, 8)\ -X(XMM2IH, 418, zmm2, 8, 8)\ -X(XMM3IH, 419, zmm3, 8, 8)\ -X(XMM4IH, 420, zmm4, 8, 8)\ -X(XMM5IH, 421, zmm5, 8, 8)\ -X(XMM6IH, 422, zmm6, 8, 8)\ -X(XMM7IH, 423, zmm7, 8, 8)\ -X(XMM8IH, 424, zmm8, 8, 8)\ -X(XMM9IH, 425, zmm9, 8, 8)\ -X(XMM10IH, 426, zmm10, 8, 8)\ -X(XMM11IH, 427, zmm11, 8, 8)\ -X(XMM12IH, 428, zmm12, 8, 8)\ -X(XMM13IH, 429, zmm13, 8, 8)\ -X(XMM14IH, 430, zmm14, 8, 8)\ -X(XMM15IH, 431, zmm15, 8, 8)\ -X(YMM0I0, 432, zmm0, 0, 8)\ -X(YMM0I1, 433, zmm0, 8, 8)\ -X(YMM0I2, 434, zmm0, 16, 8)\ -X(YMM0I3, 435, zmm0, 24, 8)\ -X(YMM1I0, 436, zmm1, 0, 8)\ -X(YMM1I1, 437, zmm1, 8, 8)\ -X(YMM1I2, 438, zmm1, 16, 8)\ -X(YMM1I3, 439, zmm1, 24, 8)\ -X(YMM2I0, 440, zmm2, 0, 8)\ -X(YMM2I1, 441, zmm2, 8, 8)\ -X(YMM2I2, 442, zmm2, 16, 8)\ -X(YMM2I3, 443, zmm2, 24, 8)\ -X(YMM3I0, 444, zmm3, 0, 8)\ -X(YMM3I1, 445, zmm3, 8, 8)\ -X(YMM3I2, 446, zmm3, 16, 8)\ -X(YMM3I3, 447, zmm3, 24, 8)\ -X(YMM4I0, 448, zmm4, 0, 8)\ -X(YMM4I1, 449, zmm4, 8, 8)\ -X(YMM4I2, 450, zmm4, 16, 8)\ -X(YMM4I3, 451, zmm4, 24, 8)\ -X(YMM5I0, 452, zmm5, 0, 8)\ -X(YMM5I1, 453, zmm5, 8, 8)\ -X(YMM5I2, 454, zmm5, 16, 8)\ -X(YMM5I3, 455, zmm5, 24, 8)\ -X(YMM6I0, 456, zmm6, 0, 8)\ -X(YMM6I1, 457, zmm6, 8, 8)\ -X(YMM6I2, 458, zmm6, 16, 8)\ -X(YMM6I3, 459, zmm6, 24, 8)\ -X(YMM7I0, 460, zmm7, 0, 8)\ -X(YMM7I1, 461, zmm7, 8, 8)\ -X(YMM7I2, 462, zmm7, 16, 8)\ -X(YMM7I3, 463, zmm7, 24, 8)\ -X(YMM8I0, 464, zmm8, 0, 8)\ -X(YMM8I1, 465, zmm8, 8, 8)\ -X(YMM8I2, 466, zmm8, 16, 8)\ -X(YMM8I3, 467, zmm8, 24, 8)\ -X(YMM9I0, 468, zmm9, 0, 8)\ -X(YMM9I1, 469, zmm9, 8, 8)\ -X(YMM9I2, 470, zmm9, 16, 8)\ -X(YMM9I3, 471, zmm9, 24, 8)\ -X(YMM10I0, 472, zmm10, 0, 8)\ -X(YMM10I1, 473, zmm10, 8, 8)\ -X(YMM10I2, 474, zmm10, 16, 8)\ -X(YMM10I3, 475, zmm10, 24, 8)\ -X(YMM11I0, 476, zmm11, 0, 8)\ -X(YMM11I1, 477, zmm11, 8, 8)\ -X(YMM11I2, 478, zmm11, 16, 8)\ -X(YMM11I3, 479, zmm11, 24, 8)\ -X(YMM12I0, 480, zmm12, 0, 8)\ -X(YMM12I1, 481, zmm12, 8, 8)\ -X(YMM12I2, 482, zmm12, 16, 8)\ -X(YMM12I3, 483, zmm12, 24, 8)\ -X(YMM13I0, 484, zmm13, 0, 8)\ -X(YMM13I1, 485, zmm13, 8, 8)\ -X(YMM13I2, 486, zmm13, 16, 8)\ -X(YMM13I3, 487, zmm13, 24, 8)\ -X(YMM14I0, 488, zmm14, 0, 8)\ -X(YMM14I1, 489, zmm14, 8, 8)\ -X(YMM14I2, 490, zmm14, 16, 8)\ -X(YMM14I3, 491, zmm14, 24, 8)\ -X(YMM15I0, 492, zmm15, 0, 8)\ -X(YMM15I1, 493, zmm15, 8, 8)\ -X(YMM15I2, 494, zmm15, 16, 8)\ -X(YMM15I3, 495, zmm15, 24, 8)\ -X(YMM0F0, 496, zmm0, 0, 4)\ -X(YMM0F1, 497, zmm0, 4, 4)\ -X(YMM0F2, 498, zmm0, 8, 4)\ -X(YMM0F3, 499, zmm0, 12, 4)\ -X(YMM0F4, 500, zmm0, 16, 4)\ -X(YMM0F5, 501, zmm0, 20, 4)\ -X(YMM0F6, 502, zmm0, 24, 4)\ -X(YMM0F7, 503, zmm0, 28, 4)\ -X(YMM1F0, 504, zmm1, 0, 4)\ -X(YMM1F1, 505, zmm1, 4, 4)\ -X(YMM1F2, 506, zmm1, 8, 4)\ -X(YMM1F3, 507, zmm1, 12, 4)\ -X(YMM1F4, 508, zmm1, 16, 4)\ -X(YMM1F5, 509, zmm1, 20, 4)\ -X(YMM1F6, 510, zmm1, 24, 4)\ -X(YMM1F7, 511, zmm1, 28, 4)\ -X(YMM2F0, 512, zmm2, 0, 4)\ -X(YMM2F1, 513, zmm2, 4, 4)\ -X(YMM2F2, 514, zmm2, 8, 4)\ -X(YMM2F3, 515, zmm2, 12, 4)\ -X(YMM2F4, 516, zmm2, 16, 4)\ -X(YMM2F5, 517, zmm2, 20, 4)\ -X(YMM2F6, 518, zmm2, 24, 4)\ -X(YMM2F7, 519, zmm2, 28, 4)\ -X(YMM3F0, 520, zmm3, 0, 4)\ -X(YMM3F1, 521, zmm3, 4, 4)\ -X(YMM3F2, 522, zmm3, 8, 4)\ -X(YMM3F3, 523, zmm3, 12, 4)\ -X(YMM3F4, 524, zmm3, 16, 4)\ -X(YMM3F5, 525, zmm3, 20, 4)\ -X(YMM3F6, 526, zmm3, 24, 4)\ -X(YMM3F7, 527, zmm3, 28, 4)\ -X(YMM4F0, 528, zmm4, 0, 4)\ -X(YMM4F1, 529, zmm4, 4, 4)\ -X(YMM4F2, 530, zmm4, 8, 4)\ -X(YMM4F3, 531, zmm4, 12, 4)\ -X(YMM4F4, 532, zmm4, 16, 4)\ -X(YMM4F5, 533, zmm4, 20, 4)\ -X(YMM4F6, 534, zmm4, 24, 4)\ -X(YMM4F7, 535, zmm4, 28, 4)\ -X(YMM5F0, 536, zmm5, 0, 4)\ -X(YMM5F1, 537, zmm5, 4, 4)\ -X(YMM5F2, 538, zmm5, 8, 4)\ -X(YMM5F3, 539, zmm5, 12, 4)\ -X(YMM5F4, 540, zmm5, 16, 4)\ -X(YMM5F5, 541, zmm5, 20, 4)\ -X(YMM5F6, 542, zmm5, 24, 4)\ -X(YMM5F7, 543, zmm5, 28, 4)\ -X(YMM6F0, 544, zmm6, 0, 4)\ -X(YMM6F1, 545, zmm6, 4, 4)\ -X(YMM6F2, 546, zmm6, 8, 4)\ -X(YMM6F3, 547, zmm6, 12, 4)\ -X(YMM6F4, 548, zmm6, 16, 4)\ -X(YMM6F5, 549, zmm6, 20, 4)\ -X(YMM6F6, 550, zmm6, 24, 4)\ -X(YMM6F7, 551, zmm6, 28, 4)\ -X(YMM7F0, 552, zmm7, 0, 4)\ -X(YMM7F1, 553, zmm7, 4, 4)\ -X(YMM7F2, 554, zmm7, 8, 4)\ -X(YMM7F3, 555, zmm7, 12, 4)\ -X(YMM7F4, 556, zmm7, 16, 4)\ -X(YMM7F5, 557, zmm7, 20, 4)\ -X(YMM7F6, 558, zmm7, 24, 4)\ -X(YMM7F7, 559, zmm7, 28, 4)\ -X(YMM8F0, 560, zmm8, 0, 4)\ -X(YMM8F1, 561, zmm8, 4, 4)\ -X(YMM8F2, 562, zmm8, 8, 4)\ -X(YMM8F3, 563, zmm8, 12, 4)\ -X(YMM8F4, 564, zmm8, 16, 4)\ -X(YMM8F5, 565, zmm8, 20, 4)\ -X(YMM8F6, 566, zmm8, 24, 4)\ -X(YMM8F7, 567, zmm8, 28, 4)\ -X(YMM9F0, 568, zmm9, 0, 4)\ -X(YMM9F1, 569, zmm9, 4, 4)\ -X(YMM9F2, 570, zmm9, 8, 4)\ -X(YMM9F3, 571, zmm9, 12, 4)\ -X(YMM9F4, 572, zmm9, 16, 4)\ -X(YMM9F5, 573, zmm9, 20, 4)\ -X(YMM9F6, 574, zmm9, 24, 4)\ -X(YMM9F7, 575, zmm9, 28, 4)\ -X(YMM10F0, 576, zmm10, 0, 4)\ -X(YMM10F1, 577, zmm10, 4, 4)\ -X(YMM10F2, 578, zmm10, 8, 4)\ -X(YMM10F3, 579, zmm10, 12, 4)\ -X(YMM10F4, 580, zmm10, 16, 4)\ -X(YMM10F5, 581, zmm10, 20, 4)\ -X(YMM10F6, 582, zmm10, 24, 4)\ -X(YMM10F7, 583, zmm10, 28, 4)\ -X(YMM11F0, 584, zmm11, 0, 4)\ -X(YMM11F1, 585, zmm11, 4, 4)\ -X(YMM11F2, 586, zmm11, 8, 4)\ -X(YMM11F3, 587, zmm11, 12, 4)\ -X(YMM11F4, 588, zmm11, 16, 4)\ -X(YMM11F5, 589, zmm11, 20, 4)\ -X(YMM11F6, 590, zmm11, 24, 4)\ -X(YMM11F7, 591, zmm11, 28, 4)\ -X(YMM12F0, 592, zmm12, 0, 4)\ -X(YMM12F1, 593, zmm12, 4, 4)\ -X(YMM12F2, 594, zmm12, 8, 4)\ -X(YMM12F3, 595, zmm12, 12, 4)\ -X(YMM12F4, 596, zmm12, 16, 4)\ -X(YMM12F5, 597, zmm12, 20, 4)\ -X(YMM12F6, 598, zmm12, 24, 4)\ -X(YMM12F7, 599, zmm12, 28, 4)\ -X(YMM13F0, 600, zmm13, 0, 4)\ -X(YMM13F1, 601, zmm13, 4, 4)\ -X(YMM13F2, 602, zmm13, 8, 4)\ -X(YMM13F3, 603, zmm13, 12, 4)\ -X(YMM13F4, 604, zmm13, 16, 4)\ -X(YMM13F5, 605, zmm13, 20, 4)\ -X(YMM13F6, 606, zmm13, 24, 4)\ -X(YMM13F7, 607, zmm13, 28, 4)\ -X(YMM14F0, 608, zmm14, 0, 4)\ -X(YMM14F1, 609, zmm14, 4, 4)\ -X(YMM14F2, 610, zmm14, 8, 4)\ -X(YMM14F3, 611, zmm14, 12, 4)\ -X(YMM14F4, 612, zmm14, 16, 4)\ -X(YMM14F5, 613, zmm14, 20, 4)\ -X(YMM14F6, 614, zmm14, 24, 4)\ -X(YMM14F7, 615, zmm14, 28, 4)\ -X(YMM15F0, 616, zmm15, 0, 4)\ -X(YMM15F1, 617, zmm15, 4, 4)\ -X(YMM15F2, 618, zmm15, 8, 4)\ -X(YMM15F3, 619, zmm15, 12, 4)\ -X(YMM15F4, 620, zmm15, 16, 4)\ -X(YMM15F5, 621, zmm15, 20, 4)\ -X(YMM15F6, 622, zmm15, 24, 4)\ -X(YMM15F7, 623, zmm15, 28, 4)\ -X(YMM0D0, 624, zmm0, 0, 8)\ -X(YMM0D1, 625, zmm0, 8, 8)\ -X(YMM0D2, 626, zmm0, 16, 8)\ -X(YMM0D3, 627, zmm0, 24, 8)\ -X(YMM1D0, 628, zmm1, 0, 8)\ -X(YMM1D1, 629, zmm1, 8, 8)\ -X(YMM1D2, 630, zmm1, 16, 8)\ -X(YMM1D3, 631, zmm1, 24, 8)\ -X(YMM2D0, 632, zmm2, 0, 8)\ -X(YMM2D1, 633, zmm2, 8, 8)\ -X(YMM2D2, 634, zmm2, 16, 8)\ -X(YMM2D3, 635, zmm2, 24, 8)\ -X(YMM3D0, 636, zmm3, 0, 8)\ -X(YMM3D1, 637, zmm3, 8, 8)\ -X(YMM3D2, 638, zmm3, 16, 8)\ -X(YMM3D3, 639, zmm3, 24, 8)\ -X(YMM4D0, 640, zmm4, 0, 8)\ -X(YMM4D1, 641, zmm4, 8, 8)\ -X(YMM4D2, 642, zmm4, 16, 8)\ -X(YMM4D3, 643, zmm4, 24, 8)\ -X(YMM5D0, 644, zmm5, 0, 8)\ -X(YMM5D1, 645, zmm5, 8, 8)\ -X(YMM5D2, 646, zmm5, 16, 8)\ -X(YMM5D3, 647, zmm5, 24, 8)\ -X(YMM6D0, 648, zmm6, 0, 8)\ -X(YMM6D1, 649, zmm6, 8, 8)\ -X(YMM6D2, 650, zmm6, 16, 8)\ -X(YMM6D3, 651, zmm6, 24, 8)\ -X(YMM7D0, 652, zmm7, 0, 8)\ -X(YMM7D1, 653, zmm7, 8, 8)\ -X(YMM7D2, 654, zmm7, 16, 8)\ -X(YMM7D3, 655, zmm7, 24, 8)\ -X(YMM8D0, 656, zmm8, 0, 8)\ -X(YMM8D1, 657, zmm8, 8, 8)\ -X(YMM8D2, 658, zmm8, 16, 8)\ -X(YMM8D3, 659, zmm8, 24, 8)\ -X(YMM9D0, 660, zmm9, 0, 8)\ -X(YMM9D1, 661, zmm9, 8, 8)\ -X(YMM9D2, 662, zmm9, 16, 8)\ -X(YMM9D3, 663, zmm9, 24, 8)\ -X(YMM10D0, 664, zmm10, 0, 8)\ -X(YMM10D1, 665, zmm10, 8, 8)\ -X(YMM10D2, 666, zmm10, 16, 8)\ -X(YMM10D3, 667, zmm10, 24, 8)\ -X(YMM11D0, 668, zmm11, 0, 8)\ -X(YMM11D1, 669, zmm11, 8, 8)\ -X(YMM11D2, 670, zmm11, 16, 8)\ -X(YMM11D3, 671, zmm11, 24, 8)\ -X(YMM12D0, 672, zmm12, 0, 8)\ -X(YMM12D1, 673, zmm12, 8, 8)\ -X(YMM12D2, 674, zmm12, 16, 8)\ -X(YMM12D3, 675, zmm12, 24, 8)\ -X(YMM13D0, 676, zmm13, 0, 8)\ -X(YMM13D1, 677, zmm13, 8, 8)\ -X(YMM13D2, 678, zmm13, 16, 8)\ -X(YMM13D3, 679, zmm13, 24, 8)\ -X(YMM14D0, 680, zmm14, 0, 8)\ -X(YMM14D1, 681, zmm14, 8, 8)\ -X(YMM14D2, 682, zmm14, 16, 8)\ -X(YMM14D3, 683, zmm14, 24, 8)\ -X(YMM15D0, 684, zmm15, 0, 8)\ -X(YMM15D1, 685, zmm15, 8, 8)\ -X(YMM15D2, 686, zmm15, 16, 8)\ -X(YMM15D3, 687, zmm15, 24, 8)\ -X(XMM16, 694, zmm16, 0, 16)\ -X(XMM17, 695, zmm17, 0, 16)\ -X(XMM18, 696, zmm18, 0, 16)\ -X(XMM19, 697, zmm19, 0, 16)\ -X(XMM20, 698, zmm20, 0, 16)\ -X(XMM21, 699, zmm21, 0, 16)\ -X(XMM22, 700, zmm22, 0, 16)\ -X(XMM23, 701, zmm23, 0, 16)\ -X(XMM24, 702, zmm24, 0, 16)\ -X(XMM25, 703, zmm25, 0, 16)\ -X(XMM26, 704, zmm26, 0, 16)\ -X(XMM27, 705, zmm27, 0, 16)\ -X(XMM28, 706, zmm28, 0, 16)\ -X(XMM29, 707, zmm29, 0, 16)\ -X(XMM30, 708, zmm30, 0, 16)\ -X(XMM31, 709, zmm31, 0, 16)\ -X(YMM16, 710, zmm16, 0, 32)\ -X(YMM17, 711, zmm17, 0, 32)\ -X(YMM18, 712, zmm18, 0, 32)\ -X(YMM19, 713, zmm19, 0, 32)\ -X(YMM20, 714, zmm20, 0, 32)\ -X(YMM21, 715, zmm21, 0, 32)\ -X(YMM22, 716, zmm22, 0, 32)\ -X(YMM23, 717, zmm23, 0, 32)\ -X(YMM24, 718, zmm24, 0, 32)\ -X(YMM25, 719, zmm25, 0, 32)\ -X(YMM26, 720, zmm26, 0, 32)\ -X(YMM27, 721, zmm27, 0, 32)\ -X(YMM28, 722, zmm28, 0, 32)\ -X(YMM29, 723, zmm29, 0, 32)\ -X(YMM30, 724, zmm30, 0, 32)\ -X(YMM31, 725, zmm31, 0, 32)\ -X(ZMM0, 726, zmm0, 0, 64)\ -X(ZMM1, 727, zmm1, 0, 64)\ -X(ZMM2, 728, zmm2, 0, 64)\ -X(ZMM3, 729, zmm3, 0, 64)\ -X(ZMM4, 730, zmm4, 0, 64)\ -X(ZMM5, 731, zmm5, 0, 64)\ -X(ZMM6, 732, zmm6, 0, 64)\ -X(ZMM7, 733, zmm7, 0, 64)\ -X(ZMM8, 734, zmm8, 0, 64)\ -X(ZMM9, 735, zmm9, 0, 64)\ -X(ZMM10, 736, zmm10, 0, 64)\ -X(ZMM11, 737, zmm11, 0, 64)\ -X(ZMM12, 738, zmm12, 0, 64)\ -X(ZMM13, 739, zmm13, 0, 64)\ -X(ZMM14, 740, zmm14, 0, 64)\ -X(ZMM15, 741, zmm15, 0, 64)\ -X(ZMM16, 742, zmm16, 0, 64)\ -X(ZMM17, 743, zmm17, 0, 64)\ -X(ZMM18, 744, zmm18, 0, 64)\ -X(ZMM19, 745, zmm19, 0, 64)\ -X(ZMM20, 746, zmm20, 0, 64)\ -X(ZMM21, 747, zmm21, 0, 64)\ -X(ZMM22, 748, zmm22, 0, 64)\ -X(ZMM23, 749, zmm23, 0, 64)\ -X(ZMM24, 750, zmm24, 0, 64)\ -X(ZMM25, 751, zmm25, 0, 64)\ -X(ZMM26, 752, zmm26, 0, 64)\ -X(ZMM27, 753, zmm27, 0, 64)\ -X(ZMM28, 754, zmm28, 0, 64)\ -X(ZMM29, 755, zmm29, 0, 64)\ -X(ZMM30, 756, zmm30, 0, 64)\ -X(ZMM31, 757, zmm31, 0, 64)\ -X(K0, 758, k0, 0, 8)\ -X(K1, 759, k1, 0, 8)\ -X(K2, 760, k2, 0, 8)\ -X(K3, 761, k3, 0, 8)\ -X(K4, 762, k4, 0, 8)\ -X(K5, 763, k5, 0, 8)\ -X(K6, 764, k6, 0, 8)\ -X(K7, 765, k7, 0, 8)\ -X(ZMM0H, 766, zmm0, 32, 32)\ -X(ZMM1H, 767, zmm1, 32, 32)\ -X(ZMM2H, 768, zmm2, 32, 32)\ -X(ZMM3H, 769, zmm3, 32, 32)\ -X(ZMM4H, 770, zmm4, 32, 32)\ -X(ZMM5H, 771, zmm5, 32, 32)\ -X(ZMM6H, 772, zmm6, 32, 32)\ -X(ZMM7H, 773, zmm7, 32, 32)\ -X(ZMM8H, 774, zmm8, 32, 32)\ -X(ZMM9H, 775, zmm9, 32, 32)\ -X(ZMM10H, 776, zmm10, 32, 32)\ -X(ZMM11H, 777, zmm11, 32, 32)\ -X(ZMM12H, 778, zmm12, 32, 32)\ -X(ZMM13H, 779, zmm13, 32, 32)\ -X(ZMM14H, 780, zmm14, 32, 32)\ -X(ZMM15H, 781, zmm15, 32, 32) +#define CV_Reg_X64_XList(X) \ + X(NONE, 0, nil, 0, 0) \ + X(AL, 1, rax, 0, 1) \ + X(CL, 2, rcx, 0, 1) \ + X(DL, 3, rdx, 0, 1) \ + X(BL, 4, rbx, 0, 1) \ + X(AH, 5, rax, 1, 1) \ + X(CH, 6, rcx, 1, 1) \ + X(DH, 7, rdx, 1, 1) \ + X(BH, 8, rbx, 1, 1) \ + X(AX, 9, rax, 0, 2) \ + X(CX, 10, rcx, 0, 2) \ + X(DX, 11, rdx, 0, 2) \ + X(BX, 12, rbx, 0, 2) \ + X(SP, 13, rsp, 0, 2) \ + X(BP, 14, rbp, 0, 2) \ + X(SI, 15, rsi, 0, 2) \ + X(DI, 16, rdi, 0, 2) \ + X(EAX, 17, rax, 0, 4) \ + X(ECX, 18, rcx, 0, 4) \ + X(EDX, 19, rdx, 0, 4) \ + X(EBX, 20, rbx, 0, 4) \ + X(ESP, 21, rsp, 0, 4) \ + X(EBP, 22, rbp, 0, 4) \ + X(ESI, 23, rsi, 0, 4) \ + X(EDI, 24, rdi, 0, 4) \ + X(ES, 25, es, 0, 2) \ + X(CS, 26, cs, 0, 2) \ + X(SS, 27, ss, 0, 2) \ + X(DS, 28, ds, 0, 2) \ + X(FS, 29, fs, 0, 2) \ + X(GS, 30, gs, 0, 2) \ + X(FLAGS, 32, rflags, 0, 2) \ + X(RIP, 33, rip, 0, 8) \ + X(EFLAGS, 34, rflags, 0, 4) \ + /* TODO: possibly missing control registers in x64 definitions? */ \ + X(CR0, 80, nil, 0, 0) \ + X(CR1, 81, nil, 0, 0) \ + X(CR2, 82, nil, 0, 0) \ + X(CR3, 83, nil, 0, 0) \ + X(CR4, 84, nil, 0, 0) \ + X(CR8, 88, nil, 0, 0) \ + X(DR0, 90, dr0, 0, 4) \ + X(DR1, 91, dr1, 0, 4) \ + X(DR2, 92, dr2, 0, 4) \ + X(DR3, 93, dr3, 0, 4) \ + X(DR4, 94, dr4, 0, 4) \ + X(DR5, 95, dr5, 0, 4) \ + X(DR6, 96, dr6, 0, 4) \ + X(DR7, 97, dr7, 0, 4) \ + /* TODO: possibly missing debug registers 8-15 in x64 definitions? */ \ + X(DR8, 98, nil, 0, 0) \ + X(DR9, 99, nil, 0, 0) \ + X(DR10, 100, nil, 0, 0) \ + X(DR11, 101, nil, 0, 0) \ + X(DR12, 102, nil, 0, 0) \ + X(DR13, 103, nil, 0, 0) \ + X(DR14, 104, nil, 0, 0) \ + X(DR15, 105, nil, 0, 0) \ + /* TODO: possibly missing ~whatever these are~ in x64 definitions? */ \ + X(GDTR, 110, nil, 0, 0) \ + X(GDTL, 111, nil, 0, 0) \ + X(IDTR, 112, nil, 0, 0) \ + X(IDTL, 113, nil, 0, 0) \ + X(LDTR, 114, nil, 0, 0) \ + X(TR, 115, nil, 0, 0) \ + X(ST0, 128, st0, 0, 10) \ + X(ST1, 129, st1, 0, 10) \ + X(ST2, 130, st2, 0, 10) \ + X(ST3, 131, st3, 0, 10) \ + X(ST4, 132, st4, 0, 10) \ + X(ST5, 133, st5, 0, 10) \ + X(ST6, 134, st6, 0, 10) \ + X(ST7, 135, st7, 0, 10) \ + /* TODO: possibly missing these, or not sure how they map to our x64 definitions? */ \ + X(CTRL, 136, nil, 0, 0) \ + X(STAT, 137, nil, 0, 0) \ + X(TAG, 138, nil, 0, 0) \ + X(FPIP, 139, nil, 0, 0) \ + X(FPCS, 140, nil, 0, 0) \ + X(FPDO, 141, nil, 0, 0) \ + X(FPDS, 142, nil, 0, 0) \ + X(ISEM, 143, nil, 0, 0) \ + X(FPEIP, 144, nil, 0, 0) \ + X(FPEDO, 145, nil, 0, 0) \ + X(MM0, 146, fpr0, 0, 8) \ + X(MM1, 147, fpr1, 0, 8) \ + X(MM2, 148, fpr2, 0, 8) \ + X(MM3, 149, fpr3, 0, 8) \ + X(MM4, 150, fpr4, 0, 8) \ + X(MM5, 151, fpr5, 0, 8) \ + X(MM6, 152, fpr6, 0, 8) \ + X(MM7, 153, fpr7, 0, 8) \ + X(XMM0, 154, zmm0, 0, 16) \ + X(XMM1, 155, zmm1, 0, 16) \ + X(XMM2, 156, zmm2, 0, 16) \ + X(XMM3, 157, zmm3, 0, 16) \ + X(XMM4, 158, zmm4, 0, 16) \ + X(XMM5, 159, zmm5, 0, 16) \ + X(XMM6, 160, zmm6, 0, 16) \ + X(XMM7, 161, zmm7, 0, 16) \ + X(XMM0_0, 162, zmm0, 0, 4) \ + X(XMM0_1, 163, zmm0, 4, 4) \ + X(XMM0_2, 164, zmm0, 8, 4) \ + X(XMM0_3, 165, zmm0, 12, 4) \ + X(XMM1_0, 166, zmm1, 0, 4) \ + X(XMM1_1, 167, zmm1, 4, 4) \ + X(XMM1_2, 168, zmm1, 8, 4) \ + X(XMM1_3, 169, zmm1, 12, 4) \ + X(XMM2_0, 170, zmm2, 0, 4) \ + X(XMM2_1, 171, zmm2, 4, 4) \ + X(XMM2_2, 172, zmm2, 8, 4) \ + X(XMM2_3, 173, zmm2, 12, 4) \ + X(XMM3_0, 174, zmm3, 0, 4) \ + X(XMM3_1, 175, zmm3, 4, 4) \ + X(XMM3_2, 176, zmm3, 8, 4) \ + X(XMM3_3, 177, zmm3, 12, 4) \ + X(XMM4_0, 178, zmm4, 0, 4) \ + X(XMM4_1, 179, zmm4, 4, 4) \ + X(XMM4_2, 180, zmm4, 8, 4) \ + X(XMM4_3, 181, zmm4, 12, 4) \ + X(XMM5_0, 182, zmm5, 0, 4) \ + X(XMM5_1, 183, zmm5, 4, 4) \ + X(XMM5_2, 184, zmm5, 8, 4) \ + X(XMM5_3, 185, zmm5, 12, 4) \ + X(XMM6_0, 186, zmm6, 0, 4) \ + X(XMM6_1, 187, zmm6, 4, 4) \ + X(XMM6_2, 188, zmm6, 8, 4) \ + X(XMM6_3, 189, zmm6, 12, 4) \ + X(XMM7_0, 190, zmm7, 0, 4) \ + X(XMM7_1, 191, zmm7, 4, 4) \ + X(XMM7_2, 192, zmm7, 8, 4) \ + X(XMM7_3, 193, zmm7, 12, 4) \ + X(XMM0L, 194, zmm0, 0, 8) \ + X(XMM1L, 195, zmm1, 0, 8) \ + X(XMM2L, 196, zmm2, 0, 8) \ + X(XMM3L, 197, zmm3, 0, 8) \ + X(XMM4L, 198, zmm4, 0, 8) \ + X(XMM5L, 199, zmm5, 0, 8) \ + X(XMM6L, 200, zmm6, 0, 8) \ + X(XMM7L, 201, zmm7, 0, 8) \ + X(XMM0H, 202, zmm0, 8, 8) \ + X(XMM1H, 203, zmm1, 8, 8) \ + X(XMM2H, 204, zmm2, 8, 8) \ + X(XMM3H, 205, zmm3, 8, 8) \ + X(XMM4H, 206, zmm4, 8, 8) \ + X(XMM5H, 207, zmm5, 8, 8) \ + X(XMM6H, 208, zmm6, 8, 8) \ + X(XMM7H, 209, zmm7, 8, 8) \ + X(MXCSR, 211, mxcsr, 0, 4) \ + X(EMM0L, 220, zmm0, 0, 8) \ + X(EMM1L, 221, zmm1, 0, 8) \ + X(EMM2L, 222, zmm2, 0, 8) \ + X(EMM3L, 223, zmm3, 0, 8) \ + X(EMM4L, 224, zmm4, 0, 8) \ + X(EMM5L, 225, zmm5, 0, 8) \ + X(EMM6L, 226, zmm6, 0, 8) \ + X(EMM7L, 227, zmm7, 0, 8) \ + X(EMM0H, 228, zmm0, 8, 8) \ + X(EMM1H, 229, zmm1, 8, 8) \ + X(EMM2H, 230, zmm2, 8, 8) \ + X(EMM3H, 231, zmm3, 8, 8) \ + X(EMM4H, 232, zmm4, 8, 8) \ + X(EMM5H, 233, zmm5, 8, 8) \ + X(EMM6H, 234, zmm6, 8, 8) \ + X(EMM7H, 235, zmm7, 8, 8) \ + X(MM00, 236, fpr0, 0, 4) \ + X(MM01, 237, fpr0, 4, 4) \ + X(MM10, 238, fpr1, 0, 4) \ + X(MM11, 239, fpr1, 4, 4) \ + X(MM20, 240, fpr2, 0, 4) \ + X(MM21, 241, fpr2, 4, 4) \ + X(MM30, 242, fpr3, 0, 4) \ + X(MM31, 243, fpr3, 4, 4) \ + X(MM40, 244, fpr4, 0, 4) \ + X(MM41, 245, fpr4, 4, 4) \ + X(MM50, 246, fpr5, 0, 4) \ + X(MM51, 247, fpr5, 4, 4) \ + X(MM60, 248, fpr6, 0, 4) \ + X(MM61, 249, fpr6, 4, 4) \ + X(MM70, 250, fpr7, 0, 4) \ + X(MM71, 251, fpr7, 4, 4) \ + X(XMM8, 252, zmm8, 0, 16) \ + X(XMM9, 253, zmm9, 0, 16) \ + X(XMM10, 254, zmm10, 0, 16) \ + X(XMM11, 255, zmm11, 0, 16) \ + X(XMM12, 256, zmm12, 0, 16) \ + X(XMM13, 257, zmm13, 0, 16) \ + X(XMM14, 258, zmm14, 0, 16) \ + X(XMM15, 259, zmm15, 0, 16) \ + X(XMM8_0, 260, zmm8, 0, 16) \ + X(XMM8_1, 261, zmm8, 4, 16) \ + X(XMM8_2, 262, zmm8, 8, 16) \ + X(XMM8_3, 263, zmm8, 12, 16) \ + X(XMM9_0, 264, zmm9, 0, 4) \ + X(XMM9_1, 265, zmm9, 4, 4) \ + X(XMM9_2, 266, zmm9, 8, 4) \ + X(XMM9_3, 267, zmm9, 12, 4) \ + X(XMM10_0, 268, zmm10, 0, 4) \ + X(XMM10_1, 269, zmm10, 4, 4) \ + X(XMM10_2, 270, zmm10, 8, 4) \ + X(XMM10_3, 271, zmm10, 12, 4) \ + X(XMM11_0, 272, zmm11, 0, 4) \ + X(XMM11_1, 273, zmm11, 4, 4) \ + X(XMM11_2, 274, zmm11, 8, 4) \ + X(XMM11_3, 275, zmm11, 12, 4) \ + X(XMM12_0, 276, zmm12, 0, 4) \ + X(XMM12_1, 277, zmm12, 4, 4) \ + X(XMM12_2, 278, zmm12, 8, 4) \ + X(XMM12_3, 279, zmm12, 12, 4) \ + X(XMM13_0, 280, zmm13, 0, 4) \ + X(XMM13_1, 281, zmm13, 4, 4) \ + X(XMM13_2, 282, zmm13, 8, 4) \ + X(XMM13_3, 283, zmm13, 12, 4) \ + X(XMM14_0, 284, zmm14, 0, 4) \ + X(XMM14_1, 285, zmm14, 4, 4) \ + X(XMM14_2, 286, zmm14, 8, 4) \ + X(XMM14_3, 287, zmm14, 12, 4) \ + X(XMM15_0, 288, zmm15, 0, 4) \ + X(XMM15_1, 289, zmm15, 4, 4) \ + X(XMM15_2, 290, zmm15, 8, 4) \ + X(XMM15_3, 291, zmm15, 12, 4) \ + X(XMM8L, 292, zmm8, 0, 8) \ + X(XMM9L, 293, zmm9, 0, 8) \ + X(XMM10L, 294, zmm10, 0, 8) \ + X(XMM11L, 295, zmm11, 0, 8) \ + X(XMM12L, 296, zmm12, 0, 8) \ + X(XMM13L, 297, zmm13, 0, 8) \ + X(XMM14L, 298, zmm14, 0, 8) \ + X(XMM15L, 299, zmm15, 0, 8) \ + X(XMM8H, 300, zmm8, 8, 8) \ + X(XMM9H, 301, zmm9, 8, 8) \ + X(XMM10H, 302, zmm10, 8, 8) \ + X(XMM11H, 303, zmm11, 8, 8) \ + X(XMM12H, 304, zmm12, 8, 8) \ + X(XMM13H, 305, zmm13, 8, 8) \ + X(XMM14H, 306, zmm14, 8, 8) \ + X(XMM15H, 307, zmm15, 8, 8) \ + X(EMM8L, 308, zmm8, 0, 8) \ + X(EMM9L, 309, zmm9, 0, 8) \ + X(EMM10L, 310, zmm10, 0, 8) \ + X(EMM11L, 311, zmm11, 0, 8) \ + X(EMM12L, 312, zmm12, 0, 8) \ + X(EMM13L, 313, zmm13, 0, 8) \ + X(EMM14L, 314, zmm14, 0, 8) \ + X(EMM15L, 315, zmm15, 0, 8) \ + X(EMM8H, 316, zmm8, 8, 8) \ + X(EMM9H, 317, zmm9, 8, 8) \ + X(EMM10H, 318, zmm10, 8, 8) \ + X(EMM11H, 319, zmm11, 8, 8) \ + X(EMM12H, 320, zmm12, 8, 8) \ + X(EMM13H, 321, zmm13, 8, 8) \ + X(EMM14H, 322, zmm14, 8, 8) \ + X(EMM15H, 323, zmm15, 8, 8) \ + X(SIL, 324, rsi, 0, 1) \ + X(DIL, 325, rdi, 0, 1) \ + X(BPL, 326, rbp, 0, 1) \ + X(SPL, 327, rsp, 0, 1) \ + X(RAX, 328, rax, 0, 8) \ + X(RBX, 329, rbx, 0, 8) \ + X(RCX, 330, rcx, 0, 8) \ + X(RDX, 331, rdx, 0, 8) \ + X(RSI, 332, rsi, 0, 8) \ + X(RDI, 333, rdi, 0, 8) \ + X(RBP, 334, rbp, 0, 8) \ + X(RSP, 335, rsp, 0, 8) \ + X(R8, 336, r8, 0, 8) \ + X(R9, 337, r9, 0, 8) \ + X(R10, 338, r10, 0, 8) \ + X(R11, 339, r11, 0, 8) \ + X(R12, 340, r12, 0, 8) \ + X(R13, 341, r13, 0, 8) \ + X(R14, 342, r14, 0, 8) \ + X(R15, 343, r15, 0, 8) \ + X(R8B, 344, r8, 0, 1) \ + X(R9B, 345, r9, 0, 1) \ + X(R10B, 346, r10, 0, 1) \ + X(R11B, 347, r11, 0, 1) \ + X(R12B, 348, r12, 0, 1) \ + X(R13B, 349, r13, 0, 1) \ + X(R14B, 350, r14, 0, 1) \ + X(R15B, 351, r15, 0, 1) \ + X(R8W, 352, r8, 0, 2) \ + X(R9W, 353, r9, 0, 2) \ + X(R10W, 354, r10, 0, 2) \ + X(R11W, 355, r11, 0, 2) \ + X(R12W, 356, r12, 0, 2) \ + X(R13W, 357, r13, 0, 2) \ + X(R14W, 358, r14, 0, 2) \ + X(R15W, 359, r15, 0, 2) \ + X(R8D, 360, r8, 0, 4) \ + X(R9D, 361, r9, 0, 4) \ + X(R10D, 362, r10, 0, 4) \ + X(R11D, 363, r11, 0, 4) \ + X(R12D, 364, r12, 0, 4) \ + X(R13D, 365, r13, 0, 4) \ + X(R14D, 366, r14, 0, 4) \ + X(R15D, 367, r15, 0, 4) \ + X(YMM0, 368, zmm0, 0, 32) \ + X(YMM1, 369, zmm1, 0, 32) \ + X(YMM2, 370, zmm2, 0, 32) \ + X(YMM3, 371, zmm3, 0, 32) \ + X(YMM4, 372, zmm4, 0, 32) \ + X(YMM5, 373, zmm5, 0, 32) \ + X(YMM6, 374, zmm6, 0, 32) \ + X(YMM7, 375, zmm7, 0, 32) \ + X(YMM8, 376, zmm8, 0, 32) \ + X(YMM9, 377, zmm9, 0, 32) \ + X(YMM10, 378, zmm10, 0, 32) \ + X(YMM11, 379, zmm11, 0, 32) \ + X(YMM12, 380, zmm12, 0, 32) \ + X(YMM13, 381, zmm13, 0, 32) \ + X(YMM14, 382, zmm14, 0, 32) \ + X(YMM15, 383, zmm15, 0, 32) \ + X(YMM0H, 384, zmm0, 16, 32) \ + X(YMM1H, 385, zmm1, 16, 32) \ + X(YMM2H, 386, zmm2, 16, 32) \ + X(YMM3H, 387, zmm3, 16, 32) \ + X(YMM4H, 388, zmm4, 16, 32) \ + X(YMM5H, 389, zmm5, 16, 32) \ + X(YMM6H, 390, zmm6, 16, 32) \ + X(YMM7H, 391, zmm7, 16, 32) \ + X(YMM8H, 392, zmm8, 16, 32) \ + X(YMM9H, 393, zmm9, 16, 32) \ + X(YMM10H, 394, zmm10, 16, 32) \ + X(YMM11H, 395, zmm11, 16, 32) \ + X(YMM12H, 396, zmm12, 16, 32) \ + X(YMM13H, 397, zmm13, 16, 32) \ + X(YMM14H, 398, zmm14, 16, 32) \ + X(YMM15H, 399, zmm15, 16, 32) \ + X(XMM0IL, 400, zmm0, 0, 8) \ + X(XMM1IL, 401, zmm1, 0, 8) \ + X(XMM2IL, 402, zmm2, 0, 8) \ + X(XMM3IL, 403, zmm3, 0, 8) \ + X(XMM4IL, 404, zmm4, 0, 8) \ + X(XMM5IL, 405, zmm5, 0, 8) \ + X(XMM6IL, 406, zmm6, 0, 8) \ + X(XMM7IL, 407, zmm7, 0, 8) \ + X(XMM8IL, 408, zmm8, 0, 8) \ + X(XMM9IL, 409, zmm9, 0, 8) \ + X(XMM10IL, 410, zmm10, 0, 8) \ + X(XMM11IL, 411, zmm11, 0, 8) \ + X(XMM12IL, 412, zmm12, 0, 8) \ + X(XMM13IL, 413, zmm13, 0, 8) \ + X(XMM14IL, 414, zmm14, 0, 8) \ + X(XMM15IL, 415, zmm15, 0, 8) \ + X(XMM0IH, 416, zmm0, 8, 8) \ + X(XMM1IH, 417, zmm1, 8, 8) \ + X(XMM2IH, 418, zmm2, 8, 8) \ + X(XMM3IH, 419, zmm3, 8, 8) \ + X(XMM4IH, 420, zmm4, 8, 8) \ + X(XMM5IH, 421, zmm5, 8, 8) \ + X(XMM6IH, 422, zmm6, 8, 8) \ + X(XMM7IH, 423, zmm7, 8, 8) \ + X(XMM8IH, 424, zmm8, 8, 8) \ + X(XMM9IH, 425, zmm9, 8, 8) \ + X(XMM10IH, 426, zmm10, 8, 8) \ + X(XMM11IH, 427, zmm11, 8, 8) \ + X(XMM12IH, 428, zmm12, 8, 8) \ + X(XMM13IH, 429, zmm13, 8, 8) \ + X(XMM14IH, 430, zmm14, 8, 8) \ + X(XMM15IH, 431, zmm15, 8, 8) \ + X(YMM0I0, 432, zmm0, 0, 8) \ + X(YMM0I1, 433, zmm0, 8, 8) \ + X(YMM0I2, 434, zmm0, 16, 8) \ + X(YMM0I3, 435, zmm0, 24, 8) \ + X(YMM1I0, 436, zmm1, 0, 8) \ + X(YMM1I1, 437, zmm1, 8, 8) \ + X(YMM1I2, 438, zmm1, 16, 8) \ + X(YMM1I3, 439, zmm1, 24, 8) \ + X(YMM2I0, 440, zmm2, 0, 8) \ + X(YMM2I1, 441, zmm2, 8, 8) \ + X(YMM2I2, 442, zmm2, 16, 8) \ + X(YMM2I3, 443, zmm2, 24, 8) \ + X(YMM3I0, 444, zmm3, 0, 8) \ + X(YMM3I1, 445, zmm3, 8, 8) \ + X(YMM3I2, 446, zmm3, 16, 8) \ + X(YMM3I3, 447, zmm3, 24, 8) \ + X(YMM4I0, 448, zmm4, 0, 8) \ + X(YMM4I1, 449, zmm4, 8, 8) \ + X(YMM4I2, 450, zmm4, 16, 8) \ + X(YMM4I3, 451, zmm4, 24, 8) \ + X(YMM5I0, 452, zmm5, 0, 8) \ + X(YMM5I1, 453, zmm5, 8, 8) \ + X(YMM5I2, 454, zmm5, 16, 8) \ + X(YMM5I3, 455, zmm5, 24, 8) \ + X(YMM6I0, 456, zmm6, 0, 8) \ + X(YMM6I1, 457, zmm6, 8, 8) \ + X(YMM6I2, 458, zmm6, 16, 8) \ + X(YMM6I3, 459, zmm6, 24, 8) \ + X(YMM7I0, 460, zmm7, 0, 8) \ + X(YMM7I1, 461, zmm7, 8, 8) \ + X(YMM7I2, 462, zmm7, 16, 8) \ + X(YMM7I3, 463, zmm7, 24, 8) \ + X(YMM8I0, 464, zmm8, 0, 8) \ + X(YMM8I1, 465, zmm8, 8, 8) \ + X(YMM8I2, 466, zmm8, 16, 8) \ + X(YMM8I3, 467, zmm8, 24, 8) \ + X(YMM9I0, 468, zmm9, 0, 8) \ + X(YMM9I1, 469, zmm9, 8, 8) \ + X(YMM9I2, 470, zmm9, 16, 8) \ + X(YMM9I3, 471, zmm9, 24, 8) \ + X(YMM10I0, 472, zmm10, 0, 8) \ + X(YMM10I1, 473, zmm10, 8, 8) \ + X(YMM10I2, 474, zmm10, 16, 8) \ + X(YMM10I3, 475, zmm10, 24, 8) \ + X(YMM11I0, 476, zmm11, 0, 8) \ + X(YMM11I1, 477, zmm11, 8, 8) \ + X(YMM11I2, 478, zmm11, 16, 8) \ + X(YMM11I3, 479, zmm11, 24, 8) \ + X(YMM12I0, 480, zmm12, 0, 8) \ + X(YMM12I1, 481, zmm12, 8, 8) \ + X(YMM12I2, 482, zmm12, 16, 8) \ + X(YMM12I3, 483, zmm12, 24, 8) \ + X(YMM13I0, 484, zmm13, 0, 8) \ + X(YMM13I1, 485, zmm13, 8, 8) \ + X(YMM13I2, 486, zmm13, 16, 8) \ + X(YMM13I3, 487, zmm13, 24, 8) \ + X(YMM14I0, 488, zmm14, 0, 8) \ + X(YMM14I1, 489, zmm14, 8, 8) \ + X(YMM14I2, 490, zmm14, 16, 8) \ + X(YMM14I3, 491, zmm14, 24, 8) \ + X(YMM15I0, 492, zmm15, 0, 8) \ + X(YMM15I1, 493, zmm15, 8, 8) \ + X(YMM15I2, 494, zmm15, 16, 8) \ + X(YMM15I3, 495, zmm15, 24, 8) \ + X(YMM0F0, 496, zmm0, 0, 4) \ + X(YMM0F1, 497, zmm0, 4, 4) \ + X(YMM0F2, 498, zmm0, 8, 4) \ + X(YMM0F3, 499, zmm0, 12, 4) \ + X(YMM0F4, 500, zmm0, 16, 4) \ + X(YMM0F5, 501, zmm0, 20, 4) \ + X(YMM0F6, 502, zmm0, 24, 4) \ + X(YMM0F7, 503, zmm0, 28, 4) \ + X(YMM1F0, 504, zmm1, 0, 4) \ + X(YMM1F1, 505, zmm1, 4, 4) \ + X(YMM1F2, 506, zmm1, 8, 4) \ + X(YMM1F3, 507, zmm1, 12, 4) \ + X(YMM1F4, 508, zmm1, 16, 4) \ + X(YMM1F5, 509, zmm1, 20, 4) \ + X(YMM1F6, 510, zmm1, 24, 4) \ + X(YMM1F7, 511, zmm1, 28, 4) \ + X(YMM2F0, 512, zmm2, 0, 4) \ + X(YMM2F1, 513, zmm2, 4, 4) \ + X(YMM2F2, 514, zmm2, 8, 4) \ + X(YMM2F3, 515, zmm2, 12, 4) \ + X(YMM2F4, 516, zmm2, 16, 4) \ + X(YMM2F5, 517, zmm2, 20, 4) \ + X(YMM2F6, 518, zmm2, 24, 4) \ + X(YMM2F7, 519, zmm2, 28, 4) \ + X(YMM3F0, 520, zmm3, 0, 4) \ + X(YMM3F1, 521, zmm3, 4, 4) \ + X(YMM3F2, 522, zmm3, 8, 4) \ + X(YMM3F3, 523, zmm3, 12, 4) \ + X(YMM3F4, 524, zmm3, 16, 4) \ + X(YMM3F5, 525, zmm3, 20, 4) \ + X(YMM3F6, 526, zmm3, 24, 4) \ + X(YMM3F7, 527, zmm3, 28, 4) \ + X(YMM4F0, 528, zmm4, 0, 4) \ + X(YMM4F1, 529, zmm4, 4, 4) \ + X(YMM4F2, 530, zmm4, 8, 4) \ + X(YMM4F3, 531, zmm4, 12, 4) \ + X(YMM4F4, 532, zmm4, 16, 4) \ + X(YMM4F5, 533, zmm4, 20, 4) \ + X(YMM4F6, 534, zmm4, 24, 4) \ + X(YMM4F7, 535, zmm4, 28, 4) \ + X(YMM5F0, 536, zmm5, 0, 4) \ + X(YMM5F1, 537, zmm5, 4, 4) \ + X(YMM5F2, 538, zmm5, 8, 4) \ + X(YMM5F3, 539, zmm5, 12, 4) \ + X(YMM5F4, 540, zmm5, 16, 4) \ + X(YMM5F5, 541, zmm5, 20, 4) \ + X(YMM5F6, 542, zmm5, 24, 4) \ + X(YMM5F7, 543, zmm5, 28, 4) \ + X(YMM6F0, 544, zmm6, 0, 4) \ + X(YMM6F1, 545, zmm6, 4, 4) \ + X(YMM6F2, 546, zmm6, 8, 4) \ + X(YMM6F3, 547, zmm6, 12, 4) \ + X(YMM6F4, 548, zmm6, 16, 4) \ + X(YMM6F5, 549, zmm6, 20, 4) \ + X(YMM6F6, 550, zmm6, 24, 4) \ + X(YMM6F7, 551, zmm6, 28, 4) \ + X(YMM7F0, 552, zmm7, 0, 4) \ + X(YMM7F1, 553, zmm7, 4, 4) \ + X(YMM7F2, 554, zmm7, 8, 4) \ + X(YMM7F3, 555, zmm7, 12, 4) \ + X(YMM7F4, 556, zmm7, 16, 4) \ + X(YMM7F5, 557, zmm7, 20, 4) \ + X(YMM7F6, 558, zmm7, 24, 4) \ + X(YMM7F7, 559, zmm7, 28, 4) \ + X(YMM8F0, 560, zmm8, 0, 4) \ + X(YMM8F1, 561, zmm8, 4, 4) \ + X(YMM8F2, 562, zmm8, 8, 4) \ + X(YMM8F3, 563, zmm8, 12, 4) \ + X(YMM8F4, 564, zmm8, 16, 4) \ + X(YMM8F5, 565, zmm8, 20, 4) \ + X(YMM8F6, 566, zmm8, 24, 4) \ + X(YMM8F7, 567, zmm8, 28, 4) \ + X(YMM9F0, 568, zmm9, 0, 4) \ + X(YMM9F1, 569, zmm9, 4, 4) \ + X(YMM9F2, 570, zmm9, 8, 4) \ + X(YMM9F3, 571, zmm9, 12, 4) \ + X(YMM9F4, 572, zmm9, 16, 4) \ + X(YMM9F5, 573, zmm9, 20, 4) \ + X(YMM9F6, 574, zmm9, 24, 4) \ + X(YMM9F7, 575, zmm9, 28, 4) \ + X(YMM10F0, 576, zmm10, 0, 4) \ + X(YMM10F1, 577, zmm10, 4, 4) \ + X(YMM10F2, 578, zmm10, 8, 4) \ + X(YMM10F3, 579, zmm10, 12, 4) \ + X(YMM10F4, 580, zmm10, 16, 4) \ + X(YMM10F5, 581, zmm10, 20, 4) \ + X(YMM10F6, 582, zmm10, 24, 4) \ + X(YMM10F7, 583, zmm10, 28, 4) \ + X(YMM11F0, 584, zmm11, 0, 4) \ + X(YMM11F1, 585, zmm11, 4, 4) \ + X(YMM11F2, 586, zmm11, 8, 4) \ + X(YMM11F3, 587, zmm11, 12, 4) \ + X(YMM11F4, 588, zmm11, 16, 4) \ + X(YMM11F5, 589, zmm11, 20, 4) \ + X(YMM11F6, 590, zmm11, 24, 4) \ + X(YMM11F7, 591, zmm11, 28, 4) \ + X(YMM12F0, 592, zmm12, 0, 4) \ + X(YMM12F1, 593, zmm12, 4, 4) \ + X(YMM12F2, 594, zmm12, 8, 4) \ + X(YMM12F3, 595, zmm12, 12, 4) \ + X(YMM12F4, 596, zmm12, 16, 4) \ + X(YMM12F5, 597, zmm12, 20, 4) \ + X(YMM12F6, 598, zmm12, 24, 4) \ + X(YMM12F7, 599, zmm12, 28, 4) \ + X(YMM13F0, 600, zmm13, 0, 4) \ + X(YMM13F1, 601, zmm13, 4, 4) \ + X(YMM13F2, 602, zmm13, 8, 4) \ + X(YMM13F3, 603, zmm13, 12, 4) \ + X(YMM13F4, 604, zmm13, 16, 4) \ + X(YMM13F5, 605, zmm13, 20, 4) \ + X(YMM13F6, 606, zmm13, 24, 4) \ + X(YMM13F7, 607, zmm13, 28, 4) \ + X(YMM14F0, 608, zmm14, 0, 4) \ + X(YMM14F1, 609, zmm14, 4, 4) \ + X(YMM14F2, 610, zmm14, 8, 4) \ + X(YMM14F3, 611, zmm14, 12, 4) \ + X(YMM14F4, 612, zmm14, 16, 4) \ + X(YMM14F5, 613, zmm14, 20, 4) \ + X(YMM14F6, 614, zmm14, 24, 4) \ + X(YMM14F7, 615, zmm14, 28, 4) \ + X(YMM15F0, 616, zmm15, 0, 4) \ + X(YMM15F1, 617, zmm15, 4, 4) \ + X(YMM15F2, 618, zmm15, 8, 4) \ + X(YMM15F3, 619, zmm15, 12, 4) \ + X(YMM15F4, 620, zmm15, 16, 4) \ + X(YMM15F5, 621, zmm15, 20, 4) \ + X(YMM15F6, 622, zmm15, 24, 4) \ + X(YMM15F7, 623, zmm15, 28, 4) \ + X(YMM0D0, 624, zmm0, 0, 8) \ + X(YMM0D1, 625, zmm0, 8, 8) \ + X(YMM0D2, 626, zmm0, 16, 8) \ + X(YMM0D3, 627, zmm0, 24, 8) \ + X(YMM1D0, 628, zmm1, 0, 8) \ + X(YMM1D1, 629, zmm1, 8, 8) \ + X(YMM1D2, 630, zmm1, 16, 8) \ + X(YMM1D3, 631, zmm1, 24, 8) \ + X(YMM2D0, 632, zmm2, 0, 8) \ + X(YMM2D1, 633, zmm2, 8, 8) \ + X(YMM2D2, 634, zmm2, 16, 8) \ + X(YMM2D3, 635, zmm2, 24, 8) \ + X(YMM3D0, 636, zmm3, 0, 8) \ + X(YMM3D1, 637, zmm3, 8, 8) \ + X(YMM3D2, 638, zmm3, 16, 8) \ + X(YMM3D3, 639, zmm3, 24, 8) \ + X(YMM4D0, 640, zmm4, 0, 8) \ + X(YMM4D1, 641, zmm4, 8, 8) \ + X(YMM4D2, 642, zmm4, 16, 8) \ + X(YMM4D3, 643, zmm4, 24, 8) \ + X(YMM5D0, 644, zmm5, 0, 8) \ + X(YMM5D1, 645, zmm5, 8, 8) \ + X(YMM5D2, 646, zmm5, 16, 8) \ + X(YMM5D3, 647, zmm5, 24, 8) \ + X(YMM6D0, 648, zmm6, 0, 8) \ + X(YMM6D1, 649, zmm6, 8, 8) \ + X(YMM6D2, 650, zmm6, 16, 8) \ + X(YMM6D3, 651, zmm6, 24, 8) \ + X(YMM7D0, 652, zmm7, 0, 8) \ + X(YMM7D1, 653, zmm7, 8, 8) \ + X(YMM7D2, 654, zmm7, 16, 8) \ + X(YMM7D3, 655, zmm7, 24, 8) \ + X(YMM8D0, 656, zmm8, 0, 8) \ + X(YMM8D1, 657, zmm8, 8, 8) \ + X(YMM8D2, 658, zmm8, 16, 8) \ + X(YMM8D3, 659, zmm8, 24, 8) \ + X(YMM9D0, 660, zmm9, 0, 8) \ + X(YMM9D1, 661, zmm9, 8, 8) \ + X(YMM9D2, 662, zmm9, 16, 8) \ + X(YMM9D3, 663, zmm9, 24, 8) \ + X(YMM10D0, 664, zmm10, 0, 8) \ + X(YMM10D1, 665, zmm10, 8, 8) \ + X(YMM10D2, 666, zmm10, 16, 8) \ + X(YMM10D3, 667, zmm10, 24, 8) \ + X(YMM11D0, 668, zmm11, 0, 8) \ + X(YMM11D1, 669, zmm11, 8, 8) \ + X(YMM11D2, 670, zmm11, 16, 8) \ + X(YMM11D3, 671, zmm11, 24, 8) \ + X(YMM12D0, 672, zmm12, 0, 8) \ + X(YMM12D1, 673, zmm12, 8, 8) \ + X(YMM12D2, 674, zmm12, 16, 8) \ + X(YMM12D3, 675, zmm12, 24, 8) \ + X(YMM13D0, 676, zmm13, 0, 8) \ + X(YMM13D1, 677, zmm13, 8, 8) \ + X(YMM13D2, 678, zmm13, 16, 8) \ + X(YMM13D3, 679, zmm13, 24, 8) \ + X(YMM14D0, 680, zmm14, 0, 8) \ + X(YMM14D1, 681, zmm14, 8, 8) \ + X(YMM14D2, 682, zmm14, 16, 8) \ + X(YMM14D3, 683, zmm14, 24, 8) \ + X(YMM15D0, 684, zmm15, 0, 8) \ + X(YMM15D1, 685, zmm15, 8, 8) \ + X(YMM15D2, 686, zmm15, 16, 8) \ + X(YMM15D3, 687, zmm15, 24, 8) \ + X(XMM16, 694, zmm16, 0, 16) \ + X(XMM17, 695, zmm17, 0, 16) \ + X(XMM18, 696, zmm18, 0, 16) \ + X(XMM19, 697, zmm19, 0, 16) \ + X(XMM20, 698, zmm20, 0, 16) \ + X(XMM21, 699, zmm21, 0, 16) \ + X(XMM22, 700, zmm22, 0, 16) \ + X(XMM23, 701, zmm23, 0, 16) \ + X(XMM24, 702, zmm24, 0, 16) \ + X(XMM25, 703, zmm25, 0, 16) \ + X(XMM26, 704, zmm26, 0, 16) \ + X(XMM27, 705, zmm27, 0, 16) \ + X(XMM28, 706, zmm28, 0, 16) \ + X(XMM29, 707, zmm29, 0, 16) \ + X(XMM30, 708, zmm30, 0, 16) \ + X(XMM31, 709, zmm31, 0, 16) \ + X(YMM16, 710, zmm16, 0, 32) \ + X(YMM17, 711, zmm17, 0, 32) \ + X(YMM18, 712, zmm18, 0, 32) \ + X(YMM19, 713, zmm19, 0, 32) \ + X(YMM20, 714, zmm20, 0, 32) \ + X(YMM21, 715, zmm21, 0, 32) \ + X(YMM22, 716, zmm22, 0, 32) \ + X(YMM23, 717, zmm23, 0, 32) \ + X(YMM24, 718, zmm24, 0, 32) \ + X(YMM25, 719, zmm25, 0, 32) \ + X(YMM26, 720, zmm26, 0, 32) \ + X(YMM27, 721, zmm27, 0, 32) \ + X(YMM28, 722, zmm28, 0, 32) \ + X(YMM29, 723, zmm29, 0, 32) \ + X(YMM30, 724, zmm30, 0, 32) \ + X(YMM31, 725, zmm31, 0, 32) \ + X(ZMM0, 726, zmm0, 0, 64) \ + X(ZMM1, 727, zmm1, 0, 64) \ + X(ZMM2, 728, zmm2, 0, 64) \ + X(ZMM3, 729, zmm3, 0, 64) \ + X(ZMM4, 730, zmm4, 0, 64) \ + X(ZMM5, 731, zmm5, 0, 64) \ + X(ZMM6, 732, zmm6, 0, 64) \ + X(ZMM7, 733, zmm7, 0, 64) \ + X(ZMM8, 734, zmm8, 0, 64) \ + X(ZMM9, 735, zmm9, 0, 64) \ + X(ZMM10, 736, zmm10, 0, 64) \ + X(ZMM11, 737, zmm11, 0, 64) \ + X(ZMM12, 738, zmm12, 0, 64) \ + X(ZMM13, 739, zmm13, 0, 64) \ + X(ZMM14, 740, zmm14, 0, 64) \ + X(ZMM15, 741, zmm15, 0, 64) \ + X(ZMM16, 742, zmm16, 0, 64) \ + X(ZMM17, 743, zmm17, 0, 64) \ + X(ZMM18, 744, zmm18, 0, 64) \ + X(ZMM19, 745, zmm19, 0, 64) \ + X(ZMM20, 746, zmm20, 0, 64) \ + X(ZMM21, 747, zmm21, 0, 64) \ + X(ZMM22, 748, zmm22, 0, 64) \ + X(ZMM23, 749, zmm23, 0, 64) \ + X(ZMM24, 750, zmm24, 0, 64) \ + X(ZMM25, 751, zmm25, 0, 64) \ + X(ZMM26, 752, zmm26, 0, 64) \ + X(ZMM27, 753, zmm27, 0, 64) \ + X(ZMM28, 754, zmm28, 0, 64) \ + X(ZMM29, 755, zmm29, 0, 64) \ + X(ZMM30, 756, zmm30, 0, 64) \ + X(ZMM31, 757, zmm31, 0, 64) \ + X(K0, 758, k0, 0, 8) \ + X(K1, 759, k1, 0, 8) \ + X(K2, 760, k2, 0, 8) \ + X(K3, 761, k3, 0, 8) \ + X(K4, 762, k4, 0, 8) \ + X(K5, 763, k5, 0, 8) \ + X(K6, 764, k6, 0, 8) \ + X(K7, 765, k7, 0, 8) \ + X(ZMM0H, 766, zmm0, 32, 32) \ + X(ZMM1H, 767, zmm1, 32, 32) \ + X(ZMM2H, 768, zmm2, 32, 32) \ + X(ZMM3H, 769, zmm3, 32, 32) \ + X(ZMM4H, 770, zmm4, 32, 32) \ + X(ZMM5H, 771, zmm5, 32, 32) \ + X(ZMM6H, 772, zmm6, 32, 32) \ + X(ZMM7H, 773, zmm7, 32, 32) \ + X(ZMM8H, 774, zmm8, 32, 32) \ + X(ZMM9H, 775, zmm9, 32, 32) \ + X(ZMM10H, 776, zmm10, 32, 32) \ + X(ZMM11H, 777, zmm11, 32, 32) \ + X(ZMM12H, 778, zmm12, 32, 32) \ + X(ZMM13H, 779, zmm13, 32, 32) \ + X(ZMM14H, 780, zmm14, 32, 32) \ + X(ZMM15H, 781, zmm15, 32, 32) typedef U16 CV_Regx64; typedef enum CV_Regx64Enum @@ -1007,11 +1015,11 @@ CV_Regx64Enum; #define CV_SignatureXList(X) \ -X(C6, 0)\ -X(C7, 1)\ -X(C11, 2)\ -X(C13, 4)\ -X(RESERVED, 5) + X(C6, 0) \ + X(C7, 1) \ + X(C11, 2) \ + X(C13, 4) \ + X(RESERVED, 5) typedef U32 CV_Signature; typedef enum CV_SignatureEnum @@ -1024,23 +1032,23 @@ CV_SignatureEnum; #define CV_LanguageXList(X) \ -X(C, 0x00)\ -X(CXX, 0x01)\ -X(FORTRAN, 0x02)\ -X(MASM, 0x03)\ -X(PASCAL, 0x04)\ -X(BASIC, 0x05)\ -X(COBOL, 0x06)\ -X(LINK, 0x07)\ -X(CVTRES, 0x08)\ -X(CVTPGD, 0x09)\ -X(CSHARP, 0x0A)\ -X(VB, 0x0B)\ -X(ILASM, 0x0C)\ -X(JAVA, 0x0D)\ -X(JSCRIPT, 0x0E)\ -X(MSIL, 0x0F)\ -X(HLSL, 0x10) + X(C, 0x00) \ + X(CXX, 0x01) \ + X(FORTRAN, 0x02) \ + X(MASM, 0x03) \ + X(PASCAL, 0x04) \ + X(BASIC, 0x05) \ + X(COBOL, 0x06) \ + X(LINK, 0x07) \ + X(CVTRES, 0x08) \ + X(CVTPGD, 0x09) \ + X(CSHARP, 0x0A) \ + X(VB, 0x0B) \ + X(ILASM, 0x0C) \ + X(JAVA, 0x0D) \ + X(JSCRIPT, 0x0E) \ + X(MSIL, 0x0F) \ + X(HLSL, 0x10) typedef U16 CV_Language; typedef enum CV_LanguageEnum @@ -1056,6 +1064,12 @@ CV_LanguageEnum; //////////////////////////////// //~ rjf: CodeView Format "Sym" and "Leaf" Header Type +#define CV_LeafSize_Max max_U16 +typedef U16 CV_LeafSize; + +#define CV_SymSize_Max max_U16 +typedef U16 CV_SymSize; + typedef struct CV_RecHeader CV_RecHeader; struct CV_RecHeader { @@ -1101,8 +1115,8 @@ enum typedef struct CV_LocalVarAttr CV_LocalVarAttr; struct CV_LocalVarAttr { - U32 off; - U16 seg; + U32 off; + U16 seg; CV_LocalFlags flags; }; @@ -1119,7 +1133,7 @@ typedef U32 CV_CompileFlags; typedef struct CV_SymCompile CV_SymCompile; struct CV_SymCompile { - U8 machine; + U8 machine; CV_CompileFlags flags; // U8[] ver_str (null terminated) }; @@ -1141,11 +1155,11 @@ typedef U8 CV_GenericStyle; typedef enum CV_GenericStyleEnum { CV_GenericStyle_VOID, - CV_GenericStyle_REG, // "return data is in register" - CV_GenericStyle_ICAN, // "indirect caller allocated near" - CV_GenericStyle_ICAF, // "indirect caller allocated far" - CV_GenericStyle_IRAN, // "indirect returnee allocated near" - CV_GenericStyle_IRAF, // "indirect returnee allocated far" + CV_GenericStyle_REG, // "return data is in register" + CV_GenericStyle_ICAN, // "indirect caller allocated near" + CV_GenericStyle_ICAF, // "indirect caller allocated far" + CV_GenericStyle_IRAN, // "indirect returnee allocated near" + CV_GenericStyle_IRAF, // "indirect returnee allocated far" CV_GenericStyle_UNUSED, } CV_GenericStyleEnum; @@ -1179,7 +1193,7 @@ struct CV_SymSLink32 typedef struct CV_SymOEM CV_SymOEM; struct CV_SymOEM { - Guid id; + Guid id; CV_TypeId itype; // padding align(4) }; @@ -1191,8 +1205,8 @@ struct CV_SymVPath32 { CV_TypeId root; CV_TypeId path; - U32 off; - U16 seg; + U32 off; + U16 seg; }; //- (SymKind: FRAMEPROC) @@ -1238,12 +1252,12 @@ enum typedef struct CV_SymFrameproc CV_SymFrameproc; struct CV_SymFrameproc { - U32 frame_size; - U32 pad_size; - U32 pad_off; - U32 save_reg_size; - U32 eh_off; - CV_SectionIndex eh_sec; + U32 frame_size; + U32 pad_size; + U32 pad_off; + U32 save_reg_size; + U32 eh_off; + CV_SectionIndex eh_sec; CV_FrameprocFlags flags; }; @@ -1285,12 +1299,12 @@ CV_ThunkOrdinalEnum; typedef struct CV_SymThunk32 CV_SymThunk32; struct CV_SymThunk32 { - U32 parent; - U32 end; - U32 next; - U32 off; - U16 sec; - U16 len; + U32 parent; + U32 end; + U32 next; + U32 off; + U16 sec; + U16 len; CV_ThunkOrdinal ord; // U8[] name (null terminated) // U8[] variant (null terminated) @@ -1314,8 +1328,8 @@ struct CV_SymBlock32 typedef struct CV_SymLabel32 CV_SymLabel32; struct CV_SymLabel32 { - U32 off; - U16 sec; + U32 off; + U16 sec; CV_ProcFlags flags; // U8[] name (null terminated) }; @@ -1326,7 +1340,7 @@ typedef struct CV_SymRegister CV_SymRegister; struct CV_SymRegister { CV_TypeId itype; - U16 reg; + U16 reg; // U8[] name (null terminated) }; @@ -1355,7 +1369,7 @@ typedef struct CV_SymManyreg CV_SymManyreg; struct CV_SymManyreg { CV_TypeId itype; - U8 count; + U8 count; // U8[count] regs; }; @@ -1364,7 +1378,7 @@ struct CV_SymManyreg typedef struct CV_SymBPRel32 CV_SymBPRel32; struct CV_SymBPRel32 { - U32 off; + U32 off; CV_TypeId itype; // U8[] name (null terminated) }; @@ -1374,8 +1388,8 @@ struct CV_SymBPRel32 typedef struct CV_SymData32 CV_SymData32; struct CV_SymData32 { - CV_TypeId itype; - U32 off; + CV_TypeId itype; + U32 off; CV_SectionIndex sec; // U8[] name (null terminated) }; @@ -1394,8 +1408,8 @@ enum typedef struct CV_SymPub32 CV_SymPub32; struct CV_SymPub32 { - CV_Pub32Flags flags; - U32 off; + CV_Pub32Flags flags; + U32 off; CV_SectionIndex sec; // U8[] name (null terminated) }; @@ -1405,15 +1419,15 @@ struct CV_SymPub32 typedef struct CV_SymProc32 CV_SymProc32; struct CV_SymProc32 { - U32 parent; - U32 end; - U32 next; - U32 len; - U32 dbg_start; - U32 dbg_end; - CV_TypeId itype; - U32 off; - U16 sec; + U32 parent; + U32 end; + U32 next; + U32 len; + U32 dbg_start; + U32 dbg_end; + CV_TypeId itype; + U32 off; + U16 sec; CV_ProcFlags flags; // U8[] name (null terminated) }; @@ -1423,9 +1437,9 @@ struct CV_SymProc32 typedef struct CV_SymRegrel32 CV_SymRegrel32; struct CV_SymRegrel32 { - U32 reg_off; + U32 reg_off; CV_TypeId itype; - CV_Reg reg; + CV_Reg reg; // U8[] name (null terminated) }; @@ -1435,8 +1449,8 @@ typedef struct CV_SymThread32 CV_SymThread32; struct CV_SymThread32 { CV_TypeId itype; - U32 tls_off; - U16 tls_seg; + U32 tls_off; + U16 tls_seg; // U8[] name (null terminated) }; @@ -1458,13 +1472,13 @@ typedef struct CV_SymCompile2 CV_SymCompile2; struct CV_SymCompile2 { CV_Compile2Flags flags; - CV_Arch machine; - U16 ver_fe_major; - U16 ver_fe_minor; - U16 ver_fe_build; - U16 ver_major; - U16 ver_minor; - U16 ver_build; + CV_Arch machine; + U16 ver_fe_major; + U16 ver_fe_minor; + U16 ver_fe_build; + U16 ver_major; + U16 ver_minor; + U16 ver_build; // U8[] ver_str (null terminated) }; @@ -1474,7 +1488,7 @@ typedef struct CV_SymManyreg2 CV_SymManyreg2; struct CV_SymManyreg2 { CV_TypeId itype; - U16 count; + U16 count; // U16[count] regs; }; @@ -1483,7 +1497,7 @@ struct CV_SymManyreg2 typedef struct CV_SymSlot CV_SymSlot; struct CV_SymSlot { - U32 slot_index; + U32 slot_index; CV_TypeId itype; // U8[] name (null terminated) }; @@ -1493,8 +1507,8 @@ struct CV_SymSlot typedef struct CV_SymAttrFrameRel CV_SymAttrFrameRel; struct CV_SymAttrFrameRel { - U32 off; - CV_TypeId itype; + U32 off; + CV_TypeId itype; CV_LocalVarAttr attr; // U8[] name (null terminated) }; @@ -1504,9 +1518,9 @@ struct CV_SymAttrFrameRel typedef struct CV_SymAttrReg CV_SymAttrReg; struct CV_SymAttrReg { - CV_TypeId itype; + CV_TypeId itype; CV_LocalVarAttr attr; - U16 reg; + U16 reg; // U8[] name (null terminated) }; @@ -1516,9 +1530,9 @@ struct CV_SymAttrReg typedef struct CV_SymAttrManyReg CV_SymAttrManyReg; struct CV_SymAttrManyReg { - CV_TypeId itype; + CV_TypeId itype; CV_LocalVarAttr attr; - U8 count; + U8 count; // U8[count] regs // U8[] name (null terminated) }; @@ -1528,9 +1542,9 @@ struct CV_SymAttrManyReg typedef struct CV_SymAttrRegRel CV_SymAttrRegRel; struct CV_SymAttrRegRel { - U32 off; - CV_TypeId itype; - U16 reg; + U32 off; + CV_TypeId itype; + U16 reg; CV_LocalVarAttr attr; // U8[] name (null terminated) }; @@ -1554,8 +1568,8 @@ struct CV_SymUNamespace typedef struct CV_SymRef2 CV_SymRef2; struct CV_SymRef2 { - U32 suc_name; - U32 sym_off; + U32 suc_name; + U32 sym_off; CV_ModIndex imod; // U8[] name (null terminated) }; @@ -1574,11 +1588,11 @@ typedef struct CV_SymTrampoline CV_SymTrampoline; struct CV_SymTrampoline { CV_TrampolineKind kind; - U16 thunk_size; - U32 thunk_sec_off; - U32 target_sec_off; - CV_SectionIndex thunk_sec; - CV_SectionIndex target_sec; + U16 thunk_size; + U32 thunk_sec_off; + U32 target_sec_off; + CV_SectionIndex thunk_sec; + CV_SectionIndex target_sec; }; //- (SymKind: SEPCODE) @@ -1593,14 +1607,14 @@ enum typedef struct CV_SymSepcode CV_SymSepcode; struct CV_SymSepcode { - U32 parent; - U32 end; - U32 len; + U32 parent; + U32 end; + U32 len; CV_SepcodeFlags flags; - U32 sec_off; - U32 sec_parent_off; - U16 sec; - U16 sec_parent; + U32 sec_off; + U32 sec_parent_off; + U16 sec; + U16 sec_parent; }; //- (SymKind: SECTION) @@ -1609,8 +1623,8 @@ typedef struct CV_SymSection CV_SymSection; struct CV_SymSection { U16 sec_index; - U8 align; - U8 pad; + U8 align; + U8 pad; U32 rva; U32 size; U32 characteristics; @@ -1645,7 +1659,7 @@ enum typedef struct CV_SymExport CV_SymExport; struct CV_SymExport { - U16 ordinal; + U16 ordinal; CV_ExportFlags flags; // U8[] name (null terminated) }; @@ -1655,9 +1669,9 @@ struct CV_SymExport typedef struct CV_SymCallSiteInfo CV_SymCallSiteInfo; struct CV_SymCallSiteInfo { - U32 off; - U16 sec; - U16 pad; + U32 off; + U16 sec; + U16 pad; CV_TypeId itype; }; @@ -1676,10 +1690,10 @@ CV_FrameCookieKindEnum; typedef struct CV_SymFrameCookie CV_SymFrameCookie; struct CV_SymFrameCookie { - U32 off; - CV_Reg reg; + U32 off; + CV_Reg reg; CV_FrameCookieKind kind; - U8 flags; + U8 flags; }; //- (SymKind: DISCARDED) @@ -1697,8 +1711,8 @@ typedef struct CV_SymDiscarded CV_SymDiscarded; struct CV_SymDiscarded { CV_DiscardedKind kind; - U32 file_id; - U32 file_ln; + U32 file_id; + U32 file_ln; // U8[] data (rest of data) }; @@ -1741,15 +1755,15 @@ typedef struct CV_SymCompile3 CV_SymCompile3; struct CV_SymCompile3 { CV_Compile3Flags flags; - CV_Arch machine; - U16 ver_fe_major; - U16 ver_fe_minor; - U16 ver_fe_build; - U16 ver_feqfe; - U16 ver_major; - U16 ver_minor; - U16 ver_build; - U16 ver_qfe; + CV_Arch machine; + U16 ver_fe_major; + U16 ver_fe_minor; + U16 ver_fe_build; + U16 ver_feqfe; + U16 ver_major; + U16 ver_minor; + U16 ver_build; + U16 ver_qfe; // U8[] ver_str (null terminated) }; @@ -1767,7 +1781,7 @@ struct CV_SymEnvBlock typedef struct CV_SymLocal CV_SymLocal; struct CV_SymLocal { - CV_TypeId itype; + CV_TypeId itype; CV_LocalFlags flags; // U8[] name (null terminated) }; @@ -1800,7 +1814,7 @@ enum typedef struct CV_SymDefrange CV_SymDefrange; struct CV_SymDefrange { - U32 program; + U32 program; CV_LvarAddrRange range; // variable-width: CV_LvarAddrGap gaps; }; @@ -1810,8 +1824,8 @@ struct CV_SymDefrange typedef struct CV_SymDefrangeSubfield CV_SymDefrangeSubfield; struct CV_SymDefrangeSubfield { - U32 program; - U32 off_in_parent; + U32 program; + U32 off_in_parent; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) }; @@ -1821,8 +1835,8 @@ struct CV_SymDefrangeSubfield typedef struct CV_SymDefrangeRegister CV_SymDefrangeRegister; struct CV_SymDefrangeRegister { - CV_Reg reg; - CV_RangeAttribs attribs; + CV_Reg reg; + CV_RangeAttribs attribs; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) }; @@ -1832,7 +1846,7 @@ struct CV_SymDefrangeRegister typedef struct CV_SymDefrangeFramepointerRel CV_SymDefrangeFramepointerRel; struct CV_SymDefrangeFramepointerRel { - S32 off; + S32 off; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) }; @@ -1844,9 +1858,9 @@ struct CV_SymDefrangeFramepointerRel typedef struct CV_SymDefrangeSubfieldRegister CV_SymDefrangeSubfieldRegister; struct CV_SymDefrangeSubfieldRegister { - CV_Reg reg; - CV_RangeAttribs attribs; - U32 field_offset; + CV_Reg reg; + CV_RangeAttribs attribs; + U32 field_offset; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) }; @@ -1871,10 +1885,10 @@ enum typedef struct CV_SymDefrangeRegisterRel CV_SymDefrangeRegisterRel; struct CV_SymDefrangeRegisterRel { - CV_Reg reg; + CV_Reg reg; CV_DefrangeRegisterRelFlags flags; - S32 reg_off; - CV_LvarAddrRange range; + S32 reg_off; + CV_LvarAddrRange range; // CV_LvarAddGap[] gaps (rest of data) }; @@ -1919,8 +1933,8 @@ CV_InlineRangeKindEnum; typedef struct CV_SymInlineSite CV_SymInlineSite; struct CV_SymInlineSite { - U32 parent; - U32 end; + U32 parent; + U32 end; CV_ItemId inlinee; // U8 annotations[] (rest of data) }; @@ -1930,10 +1944,10 @@ struct CV_SymInlineSite typedef struct CV_SymInlineSite2 CV_SymInlineSite2; struct CV_SymInlineSite2 { - U32 parent_off; - U32 end_off; + U32 parent_off; + U32 end_off; CV_ItemId inlinee; - U32 invocations; + U32 invocations; // U8 annotations[] (rest of data) }; @@ -1944,8 +1958,8 @@ struct CV_SymInlineSite2 typedef struct CV_SymFileStatic CV_SymFileStatic; struct CV_SymFileStatic { - CV_TypeId itype; - U32 mod_offset; + CV_TypeId itype; + U32 mod_offset; CV_LocalFlags flags; // U8[] name (null terminated) }; @@ -1972,14 +1986,14 @@ CV_ArmSwitchKindEnum; typedef struct CV_SymArmSwitchTable CV_SymArmSwitchTable; struct CV_SymArmSwitchTable { - U32 off_base; - U16 sec_base; + U32 off_base; + U16 sec_base; CV_ArmSwitchKind kind; - U32 off_branch; - U32 off_table; - U16 sec_branch; - U16 sec_table; - U32 entry_count; + U32 off_branch; + U32 off_table; + U16 sec_branch; + U16 sec_table; + U32 entry_count; }; //- (SymKind: CALLEES, CALLERS) @@ -2008,9 +2022,9 @@ struct CV_SymPogoInfo typedef struct CV_SymHeapAllocSite CV_SymHeapAllocSite; struct CV_SymHeapAllocSite { - U32 off; - U16 sec; - U16 call_inst_len; + U32 off; + U16 sec; + U16 call_inst_len; CV_TypeId itype; }; @@ -2032,8 +2046,8 @@ struct CV_SymModTypeRef { CV_ModTypeRefFlags flags; // contain stream number or module index depending on flags (undocumented) - U32 word0; - U32 word1; + U32 word0; + U32 word1; }; //- (SymKind: REF_MINIPDB) @@ -2051,8 +2065,8 @@ enum typedef struct CV_SymRefMiniPdb CV_SymRefMiniPdb; struct CV_SymRefMiniPdb { - U32 data; - CV_ModIndex imod; + U32 data; + CV_ModIndex imod; CV_RefMiniPdbFlags flags; // U8[] name (null terminated) }; @@ -2074,7 +2088,7 @@ enum typedef struct CV_SymFastLink CV_SymFastLink; struct CV_SymFastLink { - CV_TypeId itype; + CV_TypeId itype; CV_FastLinkFlags flags; // U8[] name (null terminated) }; @@ -2097,13 +2111,13 @@ struct CV_SymInlinees #define CV_TypeId_Variadic 0 #define CV_BasicPointerKindXList(X) \ -X(VALUE, 0x0)\ -X(16BIT, 0x1)\ -X(FAR_16BIT, 0x2)\ -X(HUGE_16BIT, 0x3)\ -X(32BIT, 0x4)\ -X(16_32BIT, 0x5)\ -X(64BIT, 0x6) + X(VALUE, 0x0) \ + X(16BIT, 0x1) \ + X(FAR_16BIT, 0x2) \ + X(HUGE_16BIT, 0x3) \ + X(32BIT, 0x4) \ + X(16_32BIT, 0x5) \ + X(64BIT, 0x6) typedef U8 CV_BasicPointerKind; typedef enum @@ -2113,7 +2127,7 @@ typedef enum #undef X } CV_BasicPointerKindEnum; -#define CV_BasicTypeFromTypeId(x) ((x)&0xFF) +#define CV_BasicTypeFromTypeId(x) ((x)&0xFF) #define CV_BasicPointerKindFromTypeId(x) (((x)>>8)&0xFF) typedef U8 CV_HFAKind; @@ -2123,8 +2137,7 @@ typedef enum CV_HFAKindEnum CV_HFAKind_Float, CV_HFAKind_Double, CV_HFAKind_Other -} -CV_HFAKindEnum; +} CV_HFAKindEnum; typedef U8 CV_MoComUDTKind; typedef enum CV_MoComUDTKindEnum @@ -2133,25 +2146,24 @@ typedef enum CV_MoComUDTKindEnum CV_MoComUDTKind_Ref, CV_MoComUDTKind_Value, CV_MoComUDTKind_Interface -} -CV_MoComUDTKindEnum; +} CV_MoComUDTKindEnum; typedef U16 CV_TypeProps; enum { - CV_TypeProp_Packed = (1<<0), - CV_TypeProp_HasConstructorsDestructors = (1<<1), - CV_TypeProp_OverloadedOperators = (1<<2), - CV_TypeProp_IsNested = (1<<3), - CV_TypeProp_ContainsNested = (1<<4), - CV_TypeProp_OverloadedAssignment = (1<<5), - CV_TypeProp_OverloadedCasting = (1<<6), - CV_TypeProp_FwdRef = (1<<7), - CV_TypeProp_Scoped = (1<<8), - CV_TypeProp_HasUniqueName = (1<<9), - CV_TypeProp_Sealed = (1<<10), + CV_TypeProp_Packed = (1 << 0), + CV_TypeProp_HasConstructorsDestructors = (1 << 1), + CV_TypeProp_OverloadedOperators = (1 << 2), + CV_TypeProp_IsNested = (1 << 3), + CV_TypeProp_ContainsNested = (1 << 4), + CV_TypeProp_OverloadedAssignment = (1 << 5), + CV_TypeProp_OverloadedCasting = (1 << 6), + CV_TypeProp_FwdRef = (1 << 7), + CV_TypeProp_Scoped = (1 << 8), + CV_TypeProp_HasUniqueName = (1 << 9), + CV_TypeProp_Sealed = (1 << 10), // HFA: 11,12 - CV_TypeProp_Intrinsic = (1<<13), + CV_TypeProp_Intrinsic = (1 << 13), // MOCOM: 14,15 }; #define CV_TypeProps_ExtractHFA(f) (((f)>>11)&0x3) @@ -2160,9 +2172,9 @@ enum typedef U8 CV_PointerKind; typedef enum CV_PointerKindEnum { - CV_PointerKind_Near, // 16 bit - CV_PointerKind_Far, // 16:16 bit - CV_PointerKind_Huge, // 16:16 bit + CV_PointerKind_Near, // 16 bit + CV_PointerKind_Far, // 16:16 bit + CV_PointerKind_Huge, // 16:16 bit CV_PointerKind_BaseSeg, CV_PointerKind_BaseVal, CV_PointerKind_BaseSegVal, @@ -2170,11 +2182,10 @@ typedef enum CV_PointerKindEnum CV_PointerKind_BaseSegAddr, CV_PointerKind_BaseType, CV_PointerKind_BaseSelf, - CV_PointerKind_Near32, // 32 bit - CV_PointerKind_Far32, // 16:32 bit - CV_PointerKind_64, // 64 bit -} -CV_PointerKindEnum; + CV_PointerKind_Near32, // 32 bit + CV_PointerKind_Far32, // 16:32 bit + CV_PointerKind_64, // 64 bit +} CV_PointerKindEnum; typedef U8 CV_PointerMode; typedef enum CV_PointerModeEnum @@ -2248,7 +2259,7 @@ enum CV_FieldAttrib_CompilerGenated = (1<<8), CV_FieldAttrib_Sealed = (1<<9), }; -#define CV_FieldAttribs_ExtractAccess(f) ((f)&0x3) +#define CV_FieldAttribs_ExtractAccess(f) ((f)&0x3) #define CV_FieldAttribs_ExtractMethodProp(f) (((f)>>2)&0x7) typedef U16 CV_LabelKind; @@ -2333,7 +2344,7 @@ typedef struct CV_LeafTypeServer2 CV_LeafTypeServer2; struct CV_LeafTypeServer2 { Guid sig70; - U32 age; + U32 age; // U8[] name (null terminated) }; @@ -2375,7 +2386,7 @@ enum typedef struct CV_LeafModifier CV_LeafModifier; struct CV_LeafModifier { - CV_TypeId itype; + CV_TypeId itype; CV_ModifierFlags flags; }; @@ -2404,7 +2415,7 @@ enum typedef struct CV_LeafPointer CV_LeafPointer; struct CV_LeafPointer { - CV_TypeId itype; + CV_TypeId itype; CV_PointerAttribs attribs; }; @@ -2413,11 +2424,11 @@ struct CV_LeafPointer typedef struct CV_LeafProcedure CV_LeafProcedure; struct CV_LeafProcedure { - CV_TypeId ret_itype; - CV_CallKind call_kind; + CV_TypeId ret_itype; + CV_CallKind call_kind; CV_FunctionAttribs attribs; - U16 arg_count; - CV_TypeId arg_itype; + U16 arg_count; + CV_TypeId arg_itype; }; //- (LeafKind: MFUNCTION) @@ -2425,14 +2436,14 @@ struct CV_LeafProcedure typedef struct CV_LeafMFunction CV_LeafMFunction; struct CV_LeafMFunction { - CV_TypeId ret_itype; - CV_TypeId class_itype; - CV_TypeId this_itype; - CV_CallKind call_kind; + CV_TypeId ret_itype; + CV_TypeId class_itype; + CV_TypeId this_itype; + CV_CallKind call_kind; CV_FunctionAttribs attribs; - U16 arg_count; - CV_TypeId arg_itype; - S32 this_adjust; + U16 arg_count; + CV_TypeId arg_itype; + S32 this_adjust; }; //- (LeafKind: ARGLIST) @@ -2450,8 +2461,8 @@ typedef struct CV_LeafBitField CV_LeafBitField; struct CV_LeafBitField { CV_TypeId itype; - U8 len; - U8 pos; + U8 len; + U8 pos; }; //- (LeafKind: METHODLIST) @@ -2461,8 +2472,8 @@ typedef struct CV_LeafMethodListMember CV_LeafMethodListMember; struct CV_LeafMethodListMember { CV_FieldAttribs attribs; - U16 pad; - CV_TypeId itype; + U16 pad; + CV_TypeId itype; // U32 vbaseoff (when Intro or PureIntro) }; @@ -2471,7 +2482,7 @@ struct CV_LeafMethodListMember typedef struct CV_LeafIndex CV_LeafIndex; struct CV_LeafIndex { - U16 pad; + U16 pad; CV_TypeId itype; }; @@ -2490,11 +2501,11 @@ struct CV_LeafArray typedef struct CV_LeafStruct CV_LeafStruct; struct CV_LeafStruct { - U16 count; + U16 count; CV_TypeProps props; - CV_TypeId field_itype; - CV_TypeId derived_itype; - CV_TypeId vshape_itype; + CV_TypeId field_itype; + CV_TypeId derived_itype; + CV_TypeId vshape_itype; // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) @@ -2505,9 +2516,9 @@ struct CV_LeafStruct typedef struct CV_LeafUnion CV_LeafUnion; struct CV_LeafUnion { - U16 count; + U16 count; CV_TypeProps props; - CV_TypeId field_itype; + CV_TypeId field_itype; // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) @@ -2518,10 +2529,10 @@ struct CV_LeafUnion typedef struct CV_LeafEnum CV_LeafEnum; struct CV_LeafEnum { - U16 count; + U16 count; CV_TypeProps props; - CV_TypeId base_itype; - CV_TypeId field_itype; + CV_TypeId base_itype; + CV_TypeId field_itype; // U8[] name (null terminated) // U8[] unique_name (null terminated) }; @@ -2541,7 +2552,7 @@ typedef struct CV_LeafMember CV_LeafMember; struct CV_LeafMember { CV_FieldAttribs attribs; - CV_TypeId itype; + CV_TypeId itype; // CV_Numeric offset // U8[] name (null terminated) }; @@ -2552,7 +2563,7 @@ typedef struct CV_LeafStMember CV_LeafStMember; struct CV_LeafStMember { CV_FieldAttribs attribs; - CV_TypeId itype; + CV_TypeId itype; // U8[] name (null terminated) }; @@ -2561,7 +2572,7 @@ struct CV_LeafStMember typedef struct CV_LeafMethod CV_LeafMethod; struct CV_LeafMethod { - U16 count; + U16 count; CV_TypeId list_itype; // U8[] name (null terminated) }; @@ -2572,7 +2583,7 @@ typedef struct CV_LeafOneMethod CV_LeafOneMethod; struct CV_LeafOneMethod { CV_FieldAttribs attribs; - CV_TypeId itype; + CV_TypeId itype; // U32 vbaseoff (when Intro or PureIntro) // U8[] name (null terminated) }; @@ -2592,7 +2603,7 @@ struct CV_LeafEnumerate typedef struct CV_LeafNestType CV_LeafNestType; struct CV_LeafNestType { - U16 pad; + U16 pad; CV_TypeId itype; // U8[] name (null terminated) }; @@ -2603,7 +2614,7 @@ typedef struct CV_LeafNestTypeEx CV_LeafNestTypeEx; struct CV_LeafNestTypeEx { CV_FieldAttribs attribs; - CV_TypeId itype; + CV_TypeId itype; // U8[] name (null terminated) }; @@ -2613,7 +2624,7 @@ typedef struct CV_LeafBClass CV_LeafBClass; struct CV_LeafBClass { CV_FieldAttribs attribs; - CV_TypeId itype; + CV_TypeId itype; // CV_Numeric offset }; @@ -2623,8 +2634,8 @@ typedef struct CV_LeafVBClass CV_LeafVBClass; struct CV_LeafVBClass { CV_FieldAttribs attribs; - CV_TypeId itype; - CV_TypeId vbptr_itype; + CV_TypeId itype; + CV_TypeId vbptr_itype; // CV_Numeric vbptr_off // CV_Numeric vtable_off }; @@ -2634,7 +2645,7 @@ struct CV_LeafVBClass typedef struct CV_LeafVFuncTab CV_LeafVFuncTab; struct CV_LeafVFuncTab { - U16 pad; + U16 pad; CV_TypeId itype; }; @@ -2643,9 +2654,9 @@ struct CV_LeafVFuncTab typedef struct CV_LeafVFuncOff CV_LeafVFuncOff; struct CV_LeafVFuncOff { - U16 pad; + U16 pad; CV_TypeId itype; - U32 off; + U32 off; }; //- (LeafKind: VFTABLE) @@ -2655,8 +2666,8 @@ struct CV_LeafVFTable { CV_TypeId owner_itype; CV_TypeId base_table_itype; - U32 offset_in_object_layout; - U32 names_len; + U32 offset_in_object_layout; + U32 names_len; // U8[] names (multiple null terminated strings) }; @@ -2676,11 +2687,11 @@ struct CV_LeafStruct2 { // NOTE: still reverse engineering this - if you find docs please help! CV_TypeProps props; - U16 unknown1; - CV_TypeId field_itype; - CV_TypeId derived_itype; - CV_TypeId vshape_itype; - U16 unknown2; + U16 unknown1; + CV_TypeId field_itype; + CV_TypeId derived_itype; + CV_TypeId vshape_itype; + U16 unknown2; // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) @@ -2750,7 +2761,7 @@ struct CV_LeafUDTSrcLine { CV_TypeId udt_itype; CV_ItemId src_string_id; - U32 line; + U32 line; }; //- (LeafIDKind: UDT_MOD_SRC_LINE) @@ -2758,9 +2769,9 @@ struct CV_LeafUDTSrcLine typedef struct CV_LeafUDTModSrcLine CV_LeafUDTModSrcLine; struct CV_LeafUDTModSrcLine { - CV_TypeId udt_itype; - CV_ItemId src_string_id; - U32 line; + CV_TypeId udt_itype; + CV_ItemId src_string_id; + U32 line; CV_ModIndex imod; }; @@ -2769,22 +2780,22 @@ struct CV_LeafUDTModSrcLine #define CV_C13SubSectionKind_IgnoreFlag 0x80000000 -#define CV_C13SubSectionKindXList(X)\ -X(Symbols, 0xF1)\ -X(Lines, 0xF2)\ -X(StringTable, 0xF3)\ -X(FileChksms, 0xF4)\ -X(FrameData, 0xF5)\ -X(InlineeLines, 0xF6)\ -X(CrossScopeImports, 0xF7)\ -X(CrossScopeExports, 0xF8)\ -X(IlLines, 0xF9)\ -X(FuncMDTokenMap, 0xFA)\ -X(TypeMDTokenMap, 0xFB)\ -X(MergedAssemblyInput, 0xFC)\ -X(CoffSymbolRVA, 0xFD)\ -X(XfgHashType, 0xFF)\ -X(XfgHashVirtual, 0x100) +#define CV_C13SubSectionKindXList(X) \ + X(Symbols, 0xF1) \ + X(Lines, 0xF2) \ + X(StringTable, 0xF3) \ + X(FileChksms, 0xF4) \ + X(FrameData, 0xF5) \ + X(InlineeLines, 0xF6) \ + X(CrossScopeImports, 0xF7) \ + X(CrossScopeExports, 0xF8) \ + X(IlLines, 0xF9) \ + X(FuncMDTokenMap, 0xFA) \ + X(TypeMDTokenMap, 0xFB) \ + X(MergedAssemblyInput, 0xFC) \ + X(CoffSymbolRVA, 0xFD) \ + X(XfgHashType, 0xFF) \ + X(XfgHashVirtual, 0x100) typedef U32 CV_C13SubSectionKind; typedef enum CV_C13SubSectionKindEnum @@ -2799,7 +2810,7 @@ typedef struct CV_C13SubSectionHeader CV_C13SubSectionHeader; struct CV_C13SubSectionHeader { CV_C13SubSectionKind kind; - U32 size; + U32 size; }; //- FileChksms sub-section @@ -2817,8 +2828,8 @@ CV_C13ChecksumKindEnum; typedef struct CV_C13Checksum CV_C13Checksum; struct CV_C13Checksum { - U32 name_off; - U8 len; + U32 name_off; + U8 len; CV_C13ChecksumKind kind; }; @@ -2833,10 +2844,10 @@ enum typedef struct CV_C13SubSecLinesHeader CV_C13SubSecLinesHeader; struct CV_C13SubSecLinesHeader { - U32 sec_off; - CV_SectionIndex sec; + U32 sec_off; + CV_SectionIndex sec; CV_C13SubSecLinesFlags flags; - U32 len; + U32 len; }; typedef struct CV_C13File CV_C13File; @@ -2857,8 +2868,8 @@ typedef U32 CV_C13LineFlags; typedef struct CV_C13Line CV_C13Line; struct CV_C13Line { - U32 off; - CV_C13LineFlags flags; + U32 off; + CV_C13LineFlags flags; }; typedef struct CV_C13Column CV_C13Column; @@ -2881,14 +2892,14 @@ enum typedef struct CV_C13FrameData CV_C13FrameData; struct CV_C13FrameData { - U32 start_voff; - U32 code_size; - U32 local_size; - U32 params_size; - U32 max_stack_size; - U32 frame_func; - U16 prolog_size; - U16 saved_reg_size; + U32 start_voff; + U32 code_size; + U32 local_size; + U32 params_size; + U32 max_stack_size; + U32 frame_func; + U16 prolog_size; + U16 saved_reg_size; CV_C13FrameDataFlags flags; }; @@ -2905,8 +2916,8 @@ typedef struct CV_C13InlineeSourceLineHeader CV_C13InlineeSourceLineHeader; struct CV_C13InlineeSourceLineHeader { CV_ItemId inlinee; // LF_FUNC_ID or LF_MFUNC_ID - U32 file_off; // offset into FileChksms sub-section - U32 first_source_ln; // base source line number for binary annotations + U32 file_off; // offset into FileChksms sub-section + U32 first_source_ln; // base source line number for binary annotations // if sig set to CV_C13InlineeLinesSig_EXTRA_FILES // U32 extra_file_count; // U32 files[]; @@ -2945,197 +2956,12 @@ struct CV_TypeIndexInfoList typedef struct CV_TypeIndexArray CV_TypeIndexArray; struct CV_TypeIndexArray { - U32 count; + U32 count; CV_TypeIndex *v; }; //////////////////////////////// -typedef struct CV_UDTInfo CV_UDTInfo; -struct CV_UDTInfo -{ - String8 name; - String8 unique_name; - CV_TypeProps props; -}; - -//////////////////////////////// -//~ CodeView Common Parser Types - -// CV_Numeric layout -// x: U16 -// buf: U8[] -// case (x < 0x8000): kind=U16 val=x -// case (x >= 0x8000): kind=x val=buf - -typedef struct CV_NumericParsed CV_NumericParsed; -struct CV_NumericParsed -{ - CV_NumericKind kind; - U8 *val; - U64 encoded_size; -}; - -typedef struct CV_RecRange CV_RecRange; -struct CV_RecRange -{ - U32 off; - CV_RecHeader hdr; -}; - -#define CV_REC_RANGE_CHUNK_SIZE 511 - -typedef struct CV_RecRangeChunk CV_RecRangeChunk; -struct CV_RecRangeChunk -{ - struct CV_RecRangeChunk *next; - CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE]; -}; - -typedef struct CV_RecRangeStream CV_RecRangeStream; -struct CV_RecRangeStream -{ - CV_RecRangeChunk *first_chunk; - CV_RecRangeChunk *last_chunk; - U64 total_count; -}; - -typedef struct CV_RecRangeArray CV_RecRangeArray; -struct CV_RecRangeArray -{ - CV_RecRange *ranges; - U64 count; -}; - -//////////////////////////////// -//~ CodeView Sym Parser Types - -typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo; -struct CV_SymTopLevelInfo -{ - CV_Arch arch; - CV_Language language; - String8 compiler_name; -}; - -typedef struct CV_SymParsed CV_SymParsed; -struct CV_SymParsed -{ - // source information - String8 data; - U64 sym_align; - - // sym index derived from source - CV_RecRangeArray sym_ranges; - - // top-level info derived from the syms - CV_SymTopLevelInfo info; -}; - -//////////////////////////////// -//~ CodeView Leaf Parser Types - -typedef struct CV_LeafParsed CV_LeafParsed; -struct CV_LeafParsed -{ - // source information - String8 data; - CV_TypeId itype_first; - CV_TypeId itype_opl; - - // leaf index derived from source - CV_RecRangeArray leaf_ranges; -}; - -//////////////////////////////// -//~ CodeView C13 Info Parser Types - -typedef struct CV_C13LinesParsed CV_C13LinesParsed; -struct CV_C13LinesParsed -{ - // raw info - U32 sec_idx; - U32 file_off; - U64 secrel_base_off; - - // parsed info - String8 file_name; - U64 *voffs; // [line_count + 1] - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - U32 line_count; -}; - -typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode; -struct CV_C13LinesParsedNode -{ - CV_C13LinesParsedNode *next; - CV_C13LinesParsed v; -}; - -typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed; -struct CV_C13InlineeLinesParsed -{ - CV_ItemId inlinee; - U32 file_off; - String8 file_name; - U32 first_source_ln; - U32 extra_file_count; - U32 *extra_files; -}; - -typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode; -struct CV_C13InlineeLinesParsedNode -{ - CV_C13InlineeLinesParsedNode *next; - CV_C13InlineeLinesParsedNode *hash_next; - CV_C13InlineeLinesParsed v; -}; - -typedef struct CV_C13SubSectionNode CV_C13SubSectionNode; -struct CV_C13SubSectionNode -{ - struct CV_C13SubSectionNode *next; - CV_C13SubSectionKind kind; - U32 off; - U32 size; - CV_C13LinesParsedNode *lines_first; - CV_C13LinesParsedNode *lines_last; - CV_C13InlineeLinesParsedNode *inlinee_lines_first; - CV_C13InlineeLinesParsedNode *inlinee_lines_last; -}; - -typedef struct CV_C13Parsed CV_C13Parsed; -struct CV_C13Parsed -{ - // rjf: source data - String8 data; - - // rjf: full sub-section list - CV_C13SubSectionNode *first_sub_section; - CV_C13SubSectionNode *last_sub_section; - U64 sub_section_count; - - // rjf: fastpath to file checksums section - CV_C13SubSectionNode *file_chksms_sub_section; - - // rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly - CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots; - U64 inlinee_lines_parsed_slots_count; -}; - -//////////////////////////////// -//~ CodeView Compound Types - -typedef struct CV_TypeIdArray CV_TypeIdArray; -struct CV_TypeIdArray -{ - CV_TypeId *itypes; - U64 count; -}; - -//////////////////////////////// - internal CV_Arch cv_arch_from_coff_machine(COFF_MachineType machine); internal U64 cv_size_from_reg_x86(CV_Reg reg); internal U64 cv_size_from_reg_x64(CV_Reg reg); @@ -3144,66 +2970,6 @@ internal B32 cv_is_reg_sp(CV_Arch arch, CV_Reg reg); internal CV_EncodedFramePtrReg cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B32 is_local_param); internal CV_Reg cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg); -//////////////////////////////// -//~ CodeView Common Decoding Helper Functions - -internal U64 cv_hash_from_string(String8 string); -internal U64 cv_hash_from_item_id(CV_ItemId item_id); - -internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl); -internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out); - -internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num); -internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num); -internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num); - -internal U64 cv_u64_from_numeric(CV_NumericParsed *num); -internal S64 cv_s64_from_numeric(CV_NumericParsed *num); -internal F64 cv_f64_from_numeric(CV_NumericParsed *num); - -internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value); -internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value); - -internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value); - -//////////////////////////////// - -internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data); -internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data); -internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data); -internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data); -internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind); - -internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data); -internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data); - -internal B32 cv_is_udt_name_anon(String8 name); -internal B32 cv_is_udt(CV_LeafKind kind); -internal B32 cv_is_global_symbol(CV_SymKind kind); -internal B32 cv_is_typedef(CV_SymKind kind); -internal B32 cv_is_scope_symbol(CV_SymKind kind); -internal B32 cv_is_end_symbol(CV_SymKind kind); -internal B32 cv_is_leaf_type_server(CV_LeafKind kind); -internal B32 cv_is_leaf_pch(CV_LeafKind kind); - -//////////////////////////////// -//~ CodeView Parsing Functions - -//- rjf: record range stream parsing -internal CV_RecRangeStream *cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align); -internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream); - -//- rjf: sym stream parsing -internal CV_SymParsed *cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align); - -//- rjf: leaf stream parsing -internal CV_LeafParsed *cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first); - -//////////////////////////////// -//~ CodeView C13 Parser Functions - -internal CV_C13Parsed *cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections); - //////////////////////////////// //~ Enum <-> String diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c new file mode 100644 index 00000000..da09881b --- /dev/null +++ b/src/codeview/codeview_parse.c @@ -0,0 +1,1396 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- Hasher + +internal U64 +cv_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal U64 +cv_hash_from_item_id(CV_ItemId item_id) +{ + U64 result = cv_hash_from_string(str8_struct(&item_id)); + return result; +} + +//- Numeric Decoder + +internal CV_NumericParsed +cv_numeric_from_data_range(U8 *first, U8 *opl) +{ + CV_NumericParsed result = {0}; + if(first + 2 <= opl) + { + U16 x = *(U16*)first; + if(x < 0x8000) + { + result.kind = CV_NumericKind_USHORT; + result.val = first; + result.encoded_size = 2; + } + else + { + U64 val_size = 0; + switch(x) + { + case CV_NumericKind_CHAR: val_size = 1; break; + case CV_NumericKind_SHORT: + case CV_NumericKind_USHORT: val_size = 2; break; + case CV_NumericKind_LONG: + case CV_NumericKind_ULONG: val_size = 4; break; + case CV_NumericKind_FLOAT32: val_size = 4; break; + case CV_NumericKind_FLOAT64: val_size = 8; break; + case CV_NumericKind_FLOAT80: val_size = 10; break; + case CV_NumericKind_FLOAT128: val_size = 16; break; + case CV_NumericKind_QUADWORD: + case CV_NumericKind_UQUADWORD: val_size = 8; break; + case CV_NumericKind_FLOAT48: val_size = 6; break; + case CV_NumericKind_COMPLEX32: val_size = 8; break; + case CV_NumericKind_COMPLEX64: val_size = 16; break; + case CV_NumericKind_COMPLEX80: val_size = 20; break; + case CV_NumericKind_COMPLEX128:val_size = 32; break; + case CV_NumericKind_VARSTRING: val_size = 0; break; // TODO: ??? + case CV_NumericKind_OCTWORD: + case CV_NumericKind_UOCTWORD: val_size = 16; break; + case CV_NumericKind_DECIMAL: val_size = 0; break; // TODO: ??? + case CV_NumericKind_DATE: val_size = 0; break; // TODO: ??? + case CV_NumericKind_UTF8STRING:val_size = 0; break; // TODO: ??? + case CV_NumericKind_FLOAT16: val_size = 2; break; + } + if(first + 2 + val_size <= opl) + { + result.kind = x; + result.val = (first + 2); + result.encoded_size = 2 + val_size; + } + } + } + return result; +} + +internal U64 +cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out) +{ + *out = cv_numeric_from_data_range(data.str + offset, data.str + data.size); + return out->encoded_size; +} + +internal B32 +cv_numeric_fits_in_u64(CV_NumericParsed *num) +{ + B32 result = 0; + switch(num->kind) + { + case CV_NumericKind_USHORT: + case CV_NumericKind_ULONG: + case CV_NumericKind_UQUADWORD: + { + result = 1; + }break; + } + return result; +} + +internal B32 +cv_numeric_fits_in_s64(CV_NumericParsed *num) +{ + B32 result = 0; + switch(num->kind) + { + case CV_NumericKind_CHAR: + case CV_NumericKind_SHORT: + case CV_NumericKind_LONG: + case CV_NumericKind_QUADWORD: + { + result = 1; + }break; + } + return result; +} + +internal B32 +cv_numeric_fits_in_f64(CV_NumericParsed *num) +{ + B32 result = 0; + switch(num->kind) + { + case CV_NumericKind_FLOAT32: + case CV_NumericKind_FLOAT64: + { + result = 1; + }break; + } + return result; +} + +internal U64 +cv_u64_from_numeric(CV_NumericParsed *num) +{ + U64 result = 0; + switch(num->kind) + { + case CV_NumericKind_USHORT: {result = *(U16*)num->val;}break; + case CV_NumericKind_ULONG: {result = *(U32*)num->val;}break; + case CV_NumericKind_UQUADWORD:{result = *(U64*)num->val;}break; + } + return result; +} + +internal S64 +cv_s64_from_numeric(CV_NumericParsed *num) +{ + S64 result = 0; + switch(num->kind) + { + case CV_NumericKind_CHAR: {result = *(S8*)num->val;}break; + case CV_NumericKind_SHORT: {result = *(S16*)num->val;}break; + case CV_NumericKind_LONG: {result = *(S32*)num->val;}break; + case CV_NumericKind_QUADWORD: {result = *(S64*)num->val;}break; + } + return(result); +} + +internal F64 +cv_f64_from_numeric(CV_NumericParsed *num) +{ + F64 result = 0; + switch(num->kind) + { + case CV_NumericKind_FLOAT32:{result = *(F32*)num->val;}break; + case CV_NumericKind_FLOAT64:{result = *(F64*)num->val;}break; + } + return(result); +} + +//- Inline Site Binary Annot Decoder + +internal U64 +cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value) +{ + U64 cursor = offset; + + // rjf: read header + U8 header = 0; + cursor += str8_deserial_read_struct(data, cursor, &header); + + // rjf: decode value + U32 value = 0; + { + // 1 byte + if((header & 0x80) == 0) + { + value = header; + } + + // 2 bytes + else if((header & 0xC0) == 0x80 && cursor+1 <= data.size) + { + U8 second_byte; + cursor += str8_deserial_read_struct(data, cursor, &second_byte); + value = ((header & 0x3F) << 8) | second_byte; + } + + // 4 bytes + else if((header & 0xE0) == 0xC0 && cursor+3 <= data.size) + { + U8 second_byte, third_byte, fourth_byte; + cursor += str8_deserial_read_struct(data, cursor, &second_byte); + cursor += str8_deserial_read_struct(data, cursor, &third_byte); + cursor += str8_deserial_read_struct(data, cursor, &fourth_byte); + value = (((U32)header & 0x1F) << 24) | ((U32)second_byte << 16) | ((U32)third_byte << 8) | (U32)fourth_byte; + } + + // bad encode + else if((header & 0xE0) == 0xE0) + { + value = max_U32; + } + } + + // rjf: output results + if(out_value) + { + *out_value = value; + } + + U64 read_size = cursor - offset; + return read_size; +} + +internal U64 +cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value) +{ + U32 value; + U64 read_size = cv_decode_inline_annot_u32(data, offset, &value); + if(value & 1) + { + value = -(value >> 1); + } + else + { + value = value >> 1; + } + *out_value = (S32)value; + return read_size; +} + +internal S32 +cv_inline_annot_signed_from_unsigned_operand(U32 value) +{ + if(value & 1) + { + value = -(value >> 1); + } + else + { + value = value >> 1; + } + S32 result = (S32)value; + return result; +} + +//- Symbol/Leaf Helpers + +internal B32 +cv_is_udt_name_anon(String8 name) +{ + // corresponds to fUDTAnon from dbi/tm.cpp:817 + B32 is_anon = str8_match(str8_lit(""), name, 0) || + str8_match(str8_lit("__unnamed"), name, 0) || + str8_match(str8_lit("::"), name, StringMatchFlag_RightSideSloppy) || + str8_match(str8_lit("::__unnamed"), name, StringMatchFlag_RightSideSloppy); + return is_anon; +} + +internal B32 +cv_is_udt(CV_LeafKind kind) +{ + B32 is_udt = kind == CV_LeafKind_CLASS || + kind == CV_LeafKind_STRUCTURE || + kind == CV_LeafKind_CLASS2 || + kind == CV_LeafKind_STRUCT2 || + kind == CV_LeafKind_INTERFACE || + kind == CV_LeafKind_UNION || + kind == CV_LeafKind_ENUM || + kind == CV_LeafKind_UDT_MOD_SRC_LINE || + kind == CV_LeafKind_UDT_SRC_LINE || + kind == CV_LeafKind_ALIAS; + return is_udt; +} + +internal B32 +cv_is_global_symbol(CV_SymKind kind) +{ + B32 is_global_symbol = kind == CV_SymKind_CONSTANT || + kind == CV_SymKind_GDATA16 || + kind == CV_SymKind_GDATA32_16t || + kind == CV_SymKind_GDATA32_ST || + kind == CV_SymKind_GDATA32 || + kind == CV_SymKind_GTHREAD32_16t || + kind == CV_SymKind_GTHREAD32_ST || + kind == CV_SymKind_GTHREAD32; + return is_global_symbol; +} + +internal B32 +cv_is_typedef(CV_SymKind kind) +{ + B32 is_typedef = kind == CV_SymKind_UDT_16t || + kind == CV_SymKind_UDT_ST || + kind == CV_SymKind_UDT; + return is_typedef; +} + +internal B32 +cv_is_scope_symbol(CV_SymKind kind) +{ + B32 is_scope = kind == CV_SymKind_GPROC32 || + kind == CV_SymKind_LPROC32 || + kind == CV_SymKind_BLOCK32 || + kind == CV_SymKind_THUNK32 || + kind == CV_SymKind_INLINESITE || + kind == CV_SymKind_INLINESITE2 || + kind == CV_SymKind_WITH32 || + kind == CV_SymKind_SEPCODE || + kind == CV_SymKind_GPROC32_ID || + kind == CV_SymKind_LPROC32_ID; + return is_scope; +} + +internal B32 +cv_is_end_symbol(CV_SymKind kind) +{ + B32 is_end = kind == CV_SymKind_END || + kind == CV_SymKind_PROC_ID_END || + kind == CV_SymKind_INLINESITE_END; + return is_end; +} + +internal B32 +cv_is_leaf_type_server(CV_LeafKind kind) +{ + B32 is_type_server = kind == CV_LeafKind_TYPESERVER || + kind == CV_LeafKind_TYPESERVER2 || + kind == CV_LeafKind_TYPESERVER_ST; + return is_type_server; +} + +internal B32 +cv_is_leaf_pch(CV_LeafKind kind) +{ + B32 is_pch = kind == CV_LeafKind_PRECOMP || + kind == CV_LeafKind_PRECOMP_ST || + kind == CV_LeafKind_PRECOMP_16t; + return is_pch; +} + +internal CV_TypeIndexSource +cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind) +{ + CV_TypeIndexSource source; + if(leaf_kind == CV_LeafKind_FUNC_ID || + leaf_kind == CV_LeafKind_MFUNC_ID || + leaf_kind == CV_LeafKind_BUILDINFO || + leaf_kind == CV_LeafKind_SUBSTR_LIST || + leaf_kind == CV_LeafKind_STRING_ID || + leaf_kind == CV_LeafKind_UDT_SRC_LINE || + leaf_kind == CV_LeafKind_UDT_MOD_SRC_LINE) + { + source = CV_TypeIndexSource_IPI; + } + else if(leaf_kind == CV_LeafKind_NOTYPE) + { + source = CV_TypeIndexSource_NULL; + } + else + { + source = CV_TypeIndexSource_TPI; + } + return source; +} + +internal CV_TypeIndexInfo * +cv_symbol_type_index_info_push(Arena *arena, CV_TypeIndexInfoList *list, CV_TypeIndexSource source, U64 offset) +{ + CV_TypeIndexInfo *info = push_array_no_zero(arena, CV_TypeIndexInfo, 1); + info->next = 0; + info->offset = offset; + info->source = source; + + SLLQueuePush(list->first, list->last, info); + list->count += 1; + + return info; +} + +internal CV_TypeIndexInfoList +cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data) +{ + CV_TypeIndexInfoList list = {0}; + switch (kind) { + case CV_SymKind_BUILDINFO: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymBuildInfo, id)); + } break; + case CV_SymKind_GDATA32: + case CV_SymKind_LDATA32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymData32, itype)); + } break; + case CV_SymKind_LPROC32_ID: + case CV_SymKind_GPROC32_ID: + case CV_SymKind_LPROC32_DPC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymProc32, itype)); + } break; + case CV_SymKind_GPROC32: + case CV_SymKind_LPROC32: + case CV_SymKind_LPROC32_DPC: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymProc32, itype)); + } break; + case CV_SymKind_UDT: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymUDT, itype)); + } break; + case CV_SymKind_GTHREAD32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymThread32, itype)); + } break; + case CV_SymKind_FILESTATIC: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymFileStatic, itype)); + } break; + case CV_SymKind_LOCAL: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymLocal, itype)); + } break; + case CV_SymKind_REGREL32: + case CV_SymKind_BPREL32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegrel32, itype)); + } break; + case CV_SymKind_REGISTER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegister, itype)); + } break; + case CV_SymKind_CONSTANT: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymConstant, itype)); + } break; + case CV_SymKind_CALLSITEINFO: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymCallSiteInfo, itype)); + } break; + case CV_SymKind_CALLERS: + case CV_SymKind_CALLEES: + case CV_SymKind_INLINEES: { + Assert(data.size >= sizeof(CV_SymFunctionList)); + CV_SymFunctionList *func_list = (CV_SymFunctionList*)data.str; + for (U64 i = 0; i < func_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_SymFunctionList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_SymKind_INLINESITE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymInlineSite, inlinee)); + } break; + case CV_SymKind_HEAPALLOCSITE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymHeapAllocSite, itype)); + } break; + } + return list; +} + +internal CV_TypeIndexInfoList +cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data) +{ + CV_TypeIndexInfoList list = {0}; + switch (leaf_kind) { + case CV_LeafKind_NOTYPE: + case CV_LeafKind_VTSHAPE: + case CV_LeafKind_LABEL: + case CV_LeafKind_NULL: + case CV_LeafKind_NOTTRAN: { + // no type indices + } break; + case CV_LeafKind_MODIFIER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafModifier, itype)); + } break; + case CV_LeafKind_POINTER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafPointer, itype)); + CV_LeafPointer *ptr = (CV_LeafPointer *)data.str; + CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs); + if (ptr_kind == CV_PointerKind_BaseType) { + // TODO: add CV_LeafPointerBaseType + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); + } else { + CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs); + if (ptr_mode == CV_PointerMode_PtrMem || ptr_mode == CV_PointerMode_PtrMethod) { + // TODO: add type for the CvLeafPointerMember to syms_cv.mc + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); + } + } + } break; + case CV_LeafKind_ARRAY: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, entry_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, index_itype)); + } break; + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + case CV_LeafKind_INTERFACE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, field_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, derived_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, vshape_itype)); + } break; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, field_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, derived_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, vshape_itype)); + } break; + case CV_LeafKind_UNION: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUnion, field_itype)); + } break; + case CV_LeafKind_ALIAS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafAlias, itype)); + } break; + case CV_LeafKind_FUNC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafFuncId, scope_string_id)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafFuncId, itype)); + } break; + case CV_LeafKind_MFUNC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, owner_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, itype)); + } break; + case CV_LeafKind_STRING_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafStringId, substr_list_id)); + } break; + case CV_LeafKind_UDT_SRC_LINE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTSrcLine, udt_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTSrcLine, src_string_id)); + } break; + case CV_LeafKind_UDT_MOD_SRC_LINE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTModSrcLine, udt_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTModSrcLine, src_string_id)); + } break; + case CV_LeafKind_BUILDINFO: { + Assert(data.size >= sizeof(CV_LeafBuildInfo)); + CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo *)data.str; + for (U16 i = 0; i < build_info->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafBuildInfo) + i * sizeof(CV_ItemId)); + } + } break; + case CV_LeafKind_ENUM: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, base_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, field_itype)); + } break; + case CV_LeafKind_PROCEDURE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, ret_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, arg_itype)); + } break; + case CV_LeafKind_MFUNCTION: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, ret_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, class_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, this_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, arg_itype)); + } break; + case CV_LeafKind_VFTABLE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, owner_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, base_table_itype)); + } break; + case CV_LeafKind_VFTPATH: { + Assert(sizeof(CV_LeafVFPath) <= data.size); + CV_LeafVFPath *vfpath = (CV_LeafVFPath *)data.str; + for (U32 i = 0; i < vfpath->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafVFPath) + i * sizeof(CV_TypeId)); + } + } break; + case CV_LeafKind_TYPESERVER: + case CV_LeafKind_TYPESERVER2: + case CV_LeafKind_TYPESERVER_ST: { + // no type indices + } break; + case CV_LeafKind_SKIP: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafSkip, itype)); + } break; + case CV_LeafKind_SUBSTR_LIST: { + Assert(sizeof(CV_LeafArgList) <= data.size); + CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; + for (U32 i = 0; i < arg_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_LeafKind_ARGLIST: { + Assert(sizeof(CV_LeafArgList) <= data.size); + CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; + for (U32 i = 0; i < arg_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_LeafKind_LIST: + case CV_LeafKind_FIELDLIST: { + for (U64 cursor = 0; cursor < data.size; ) { + CV_LeafKind list_member_kind = 0; + U64 read_size = str8_deserial_read_struct(data, cursor, &list_member_kind); + + if(read_size != sizeof(list_member_kind)) { + Assert(!"malformed LF_FIELDLIST"); + break; + } + cursor += read_size; + + switch (list_member_kind) { + default: Assert(!"TODO: handle malformed field member"); break; + case CV_LeafKind_INDEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafIndex, itype)); + cursor += sizeof(CV_LeafIndex); + } break; + case CV_LeafKind_MEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMember, itype)); + cursor += sizeof(CV_LeafMember); + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_STMEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafStMember, itype)); + cursor += sizeof(CV_LeafStMember); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_METHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethod, list_itype)); + cursor += sizeof(CV_LeafMethod); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_ONEMETHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafOneMethod, itype)); + + CV_LeafOneMethod onemethod; + cursor += str8_deserial_read_struct(data, cursor, &onemethod); + + CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(onemethod.attribs); + if(prop == CV_MethodProp_PureIntro || prop == CV_MethodProp_Intro) + { + cursor += sizeof(U32); // virtoff + } + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_ENUMERATE: { + // no type index + cursor += sizeof(CV_LeafEnumerate); + CV_NumericParsed value; + cursor += cv_read_numeric(data, cursor, &value); + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_NESTTYPE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestType, itype)); + cursor += sizeof(CV_LeafNestType); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_NESTTYPEEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestTypeEx, itype)); + + cursor += sizeof(CV_LeafNestTypeEx); + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_BCLASS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafBClass, itype)); + + cursor += sizeof(CV_LeafBClass); + CV_NumericParsed offset; + cursor += cv_read_numeric(data, cursor, &offset); + } break; + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVBClass, itype)); + cursor += sizeof(CV_LeafVBClass); + + CV_NumericParsed virtual_base_pointer; + cursor += cv_read_numeric(data, cursor, &virtual_base_pointer); + + CV_NumericParsed virtual_base_offset; + cursor += cv_read_numeric(data, cursor, &virtual_base_offset); + } break; + case CV_LeafKind_VFUNCTAB: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncTab, itype)); + cursor += sizeof(CV_LeafVFuncTab); + } break; + case CV_LeafKind_VFUNCOFF: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncOff, itype)); + cursor += sizeof(CV_LeafVFuncOff); + } break; + } + cursor = AlignPow2(cursor, 4); + } + } break; + case CV_LeafKind_METHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMethod, list_itype)); + } break; + case CV_LeafKind_METHODLIST: { + for (U64 cursor = 0; cursor < data.size; ) { + // read method + CV_LeafMethodListMember method; + U64 read_size = str8_deserial_read_struct(data, cursor, &method); + + // error check read + if (read_size != sizeof(method)) { + Assert(!"malformed LF_METHODLIST"); + break; + } + + // push type index offset + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethodListMember, itype)); + + // take into account intro virtual offset + CV_MethodProp mprop = CV_FieldAttribs_ExtractMethodProp(method.attribs); + if (mprop == CV_MethodProp_Intro || mprop == CV_MethodProp_PureIntro) { + read_size += sizeof(U32); + } + + // advance + cursor += read_size; + } + } break; + case CV_LeafKind_ONEMETHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafOneMethod, itype)); + } break; + case CV_LeafKind_BITFIELD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafBitField, itype)); + } break; + case CV_LeafKind_PRECOMP: + case CV_LeafKind_REFSYM: { + // no type indices + } break; + case CV_LeafKind_INDEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafIndex, itype)); + } break; + case CV_LeafKind_MEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMember, itype)); + } break; + case CV_LeafKind_VFUNCTAB: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncTab, itype)); + } break; + case CV_LeafKind_VFUNCOFF: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncOff, itype)); + } break; + case CV_LeafKind_NESTTYPE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestType, itype)); + } break; + case CV_LeafKind_NESTTYPEEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestTypeEx, itype)); + } break; + default: { + NotImplemented; + } break; + } + return list; +} + +internal CV_TypeIndexInfoList +cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data) +{ + CV_TypeIndexInfoList list = {0}; + + U64 cursor = 0; + + // first four bytes are always signature + CV_C13InlineeLinesSig sig = max_U32; + cursor += str8_deserial_read_struct(raw_data, cursor, &sig); + + while(cursor < raw_data.size) + { + // read header + CV_C13InlineeSourceLineHeader *header = (CV_C13InlineeSourceLineHeader *) str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(CV_C13InlineeSourceLineHeader)); + + // store type index offset + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, cursor + OffsetOf(CV_C13InlineeSourceLineHeader, inlinee)); + + // advance past header + cursor += sizeof(*header); + + // skip extra files + B32 has_extra_files = (sig == CV_C13InlineeLinesSig_EXTRA_FILES); + if (has_extra_files) + { + U32 file_count = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &file_count); + cursor += /* file id: */ sizeof(U32) * file_count; + } + } + + return list; +} + +internal String8Array +cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data) +{ + String8Array result; + if(ti_list.count > 0) + { + result.count = ti_list.count + 1; + result.v = push_array_no_zero(arena, String8, result.count); + + U64 cursor = 0; + U64 ti_idx = 0; + + for(CV_TypeIndexInfo *ti_info = ti_list.first; ti_info != 0; ti_info = ti_info->next, ++ti_idx) + { + result.v[ti_idx].size = ti_info->offset - cursor; + result.v[ti_idx].str = data.str + cursor; + cursor = ti_info->offset + sizeof(CV_TypeIndex); + } + + result.v[result.count-1].size = data.size - cursor; + result.v[result.count-1].str = data.str + cursor; + } + else + { + result.count = 1; + result.v = push_array_no_zero(arena, String8, 1); + result.v[0] = data; + } + return result; +} + +internal U64 +cv_name_offset_from_symbol(CV_SymKind kind, String8 data) +{ + U64 offset = data.size; + switch (kind) { + case CV_SymKind_COMPILE: break; + case CV_SymKind_OBJNAME: break; + case CV_SymKind_THUNK32: { + offset = sizeof(CV_SymThunk32); + } break; + case CV_SymKind_LABEL32: { + offset = sizeof(CV_SymLabel32); + } break; + case CV_SymKind_REGISTER: { + offset = sizeof(CV_SymRegister); + } break; + case CV_SymKind_CONSTANT: { + offset = sizeof(CV_SymConstant); + CV_NumericParsed size; + offset += cv_read_numeric(data, offset, &size); + } break; + case CV_SymKind_UDT: { + offset = sizeof(CV_SymUDT); + } break; + case CV_SymKind_BPREL32: { + offset = sizeof(CV_SymBPRel32); + } break; + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: { + offset = sizeof(CV_SymData32); + } break; + case CV_SymKind_PUB32: { + offset = sizeof(CV_SymPub32); + } break; + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + case CV_SymKind_LPROC32_ID: + case CV_SymKind_GPROC32_ID: { + offset = sizeof(CV_SymProc32); + } break; + case CV_SymKind_REGREL32: { + offset = sizeof(CV_SymRegrel32); + } break; + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: { + offset = sizeof(CV_SymData32); + } break; + case CV_SymKind_COMPILE2: break; + case CV_SymKind_LOCALSLOT: { + offset = sizeof(CV_SymSlot); + } break; + case CV_SymKind_PROCREF: + case CV_SymKind_LPROCREF: + case CV_SymKind_DATAREF: { + offset = sizeof(CV_SymRef2); + } break; + case CV_SymKind_TRAMPOLINE: break; + case CV_SymKind_LOCAL: { + offset = sizeof(CV_SymLocal); + } break; + default: InvalidPath; + } + return offset; +} + +internal String8 +cv_name_from_symbol(CV_SymKind kind, String8 data) +{ + U64 buf_off = cv_name_offset_from_symbol(kind, data); + U8 *buf_ptr = data.str + buf_off; + U8 *buf_opl = data.str + data.size; + String8 name = str8_cstring_capped(buf_ptr, buf_opl); + return name; +} + +internal CV_UDTInfo +cv_get_udt_info(CV_LeafKind kind, String8 data) +{ + String8 name = str8_zero(); + String8 unique_name = str8_zero(); + CV_TypeProps props = 0; + + switch(kind) { + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + case CV_LeafKind_INTERFACE: { + U64 cursor = 0; + + CV_LeafStruct udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if (udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; + + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: { + U64 cursor = 0; + + CV_LeafStruct2 udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if (udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; + + case CV_LeafKind_UNION: { + U64 cursor = 0; + + CV_LeafUnion udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + props = udt.props; + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if(udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; + + case CV_LeafKind_ENUM: { + U64 cursor = 0; + + CV_LeafEnum udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if(udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; + + // dbi/tpi.cpp:1332 + case CV_LeafKind_UDT_SRC_LINE: { + CV_LeafUDTSrcLine *src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTSrcLine)); + name = str8_struct(&src_line->udt_itype); + } break; + case CV_LeafKind_UDT_MOD_SRC_LINE: { + CV_LeafUDTModSrcLine *mod_src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTModSrcLine)); + name = str8_struct(&mod_src_line->udt_itype); + } break; + + case CV_LeafKind_ALIAS: { + str8_deserial_read_cstr(data, 0, &name); + } break; + + default: { + InvalidPath; + } break; + } + + CV_UDTInfo info = {0}; + info.name = name; + info.unique_name = unique_name; + info.props = props; + return info; +} + +internal String8 +cv_name_from_udt_info(CV_UDTInfo udt_info) +{ + if (udt_info.props & CV_TypeProp_HasUniqueName) { + return udt_info.unique_name; + } + return udt_info.name; +} + +//- rjf: record range stream parsing + +internal CV_RecRangeStream* +cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align) +{ + Assert(1 <= sym_align && IsPow2OrZero(sym_align)); + CV_RecRangeStream *result = push_array(arena, CV_RecRangeStream, 1); + U8 *data = sym_data.str; + U64 cursor = 0; + U64 cap = sym_data.size; + for(;cursor + sizeof(CV_RecHeader) <= cap;) + { + // setup a new chunk + CV_RecRangeChunk *cur_chunk = push_array_aligned(arena, CV_RecRangeChunk, 1, 64); + SLLQueuePush(result->first_chunk, result->last_chunk, cur_chunk); + U64 partial_count = 0; + for(;partial_count < CV_REC_RANGE_CHUNK_SIZE && cursor + sizeof(CV_RecHeader) <= cap; partial_count += 1) + { + // compute cap + CV_RecHeader *hdr = (CV_RecHeader*)(data + cursor); + U64 symbol_cap_unclamped = cursor + 2 + hdr->size; + U64 symbol_cap = ClampTop(symbol_cap_unclamped, cap); + + // push on range + cur_chunk->ranges[partial_count].off = cursor + 2; + cur_chunk->ranges[partial_count].hdr = *hdr; + + // update cursor + U32 next_pos = AlignPow2(symbol_cap, sym_align); + cursor = next_pos; + } + result->total_count += partial_count; + } + return result; +} + +internal CV_RecRangeArray +cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream) +{ + U64 total_count = stream->total_count; + CV_RecRange *ranges = push_array_no_zero_aligned(arena, CV_RecRange, total_count, 8); + U64 idx = 0; + for(CV_RecRangeChunk *chunk = stream->first_chunk; chunk != 0; chunk = chunk->next) + { + U64 copy_count_raw = total_count - idx; + U64 copy_count = ClampTop(copy_count_raw, CV_REC_RANGE_CHUNK_SIZE); + MemoryCopy(ranges + idx, chunk->ranges, copy_count*sizeof(CV_RecRange)); + idx += copy_count; + } + CV_RecRangeArray result = {0}; + result.ranges = ranges; + result.count = total_count; + return result; +} + +//- rjf: sym stream parsing + +internal CV_SymParsed * +cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align) +{ + Assert(1 <= sym_align && IsPow2OrZero(sym_align)); + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: gather symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align); + + //- rjf: convert to result, fill basics + CV_SymParsed *result = push_array(arena, CV_SymParsed, 1); + result->data = sym_data; + result->sym_align = sym_align; + result->sym_ranges = cv_rec_range_array_from_stream(arena, stream); + + //- rjf: extract top-level-info + { + CV_RecRange *range = result->sym_ranges.ranges; + CV_RecRange *opl = range + result->sym_ranges.count; + for(;range < opl; range += 1) + { + U8 *first = sym_data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + switch(range->hdr.kind) + { + case CV_SymKind_COMPILE: + if(sizeof(CV_SymCompile) <= cap) + { + CV_SymCompile *compile = (CV_SymCompile*)first; + String8 ver_str = str8_cstring_capped((char*)(compile + 1), (char *)(first + cap)); + result->info.arch = compile->machine; + result->info.language = CV_CompileFlags_ExtractLanguage(compile->flags);; + result->info.compiler_name = ver_str; + }break; + case CV_SymKind_COMPILE2: + if(sizeof(CV_SymCompile2) <= cap) + { + CV_SymCompile2 *compile2 = (CV_SymCompile2*)first; + String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), (char*)(first + cap)); + String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", + str8_varg(ver_str), + compile2->ver_major, + compile2->ver_minor, + compile2->ver_build); + result->info.arch = compile2->machine; + result->info.language = CV_Compile2Flags_ExtractLanguage(compile2->flags);; + result->info.compiler_name = compiler_name; + }break; + case CV_SymKind_COMPILE3: + if(sizeof(CV_SymCompile3) <= cap) + { + CV_SymCompile3 *compile3 = (CV_SymCompile3*)first; + String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), (char *)(first + cap)); + String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", + str8_varg(ver_str), + compile3->ver_major, + compile3->ver_minor, + compile3->ver_build); + result->info.arch = compile3->machine; + result->info.language = CV_Compile3Flags_ExtractLanguage(compile3->flags);; + result->info.compiler_name = compiler_name; + }break; + } + } + } + + scratch_end(scratch); + ProfEnd(); + return result; +} + +//- rjf: leaf stream parsing + +internal CV_LeafParsed * +cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + // gather up symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1); + + // convert to result + CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1); + result->data = leaf_data; + result->itype_first = itype_first; + result->itype_opl = itype_first + stream->total_count; + result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream); + + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal CV_C13Parsed * +cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections) +{ + ProfBeginFunction(); + + ////////////////////////////// + //- rjf: gather c13 sub-sections + // + CV_C13SubSectionNode *file_chksms = 0; + CV_C13SubSectionNode *first = 0; + CV_C13SubSectionNode *last = 0; + U64 count = 0; + { + U32 cursor = 0; + for(; cursor + sizeof(CV_C13SubSectionHeader) <= c13_data.size;) + { + // read header + CV_C13SubSectionHeader *hdr = (CV_C13SubSectionHeader*)(c13_data.str + cursor); + + // get sub section info + U32 sub_section_off = cursor + sizeof(*hdr); + U32 sub_section_size_raw = hdr->size; + U32 after_sub_section_off_unclamped = sub_section_off + sub_section_size_raw; + U32 after_sub_section_off = ClampTop(after_sub_section_off_unclamped, c13_data.size); + U32 sub_section_size = after_sub_section_off - sub_section_off; + + // emit sub section + if(!(hdr->kind & CV_C13SubSectionKind_IgnoreFlag)) + { + CV_C13SubSectionNode *node = push_array(arena, CV_C13SubSectionNode, 1); + SLLQueuePush(first, last, node); + count += 1; + node->kind = hdr->kind; + node->off = sub_section_off; + node->size = sub_section_size; + if(hdr->kind == CV_C13SubSectionKind_FileChksms) + { + file_chksms = node; + } + } + + // move cursor + cursor = AlignPow2(after_sub_section_off, 4); + } + } + + ////////////////////////////// + //- rjf: parse each sub-section + // + U64 inlinee_lines_parsed_slots_count = 4096; + CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots = push_array(arena, CV_C13InlineeLinesParsedNode *, inlinee_lines_parsed_slots_count); + for(CV_C13SubSectionNode *node = first; + node != 0; + node = node->next) + { + U8 *first = c13_data.str + node->off; + U32 cap = node->size; + switch(node->kind) + { + default:{}break; + + ////////////////////////// + //- rjf: line info sub-section + // + case CV_C13SubSectionKind_Lines: + if(sizeof(CV_C13SubSecLinesHeader) <= cap) + { + // read header + U32 read_off = 0; + U64 read_off_opl = node->size; + CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off); + read_off += sizeof(*hdr); + + // rjf: extract section index + U32 sec_idx = hdr->sec; + + // rjf: bad section index -> skip + if(sec_idx < 1 || sections.count < sec_idx) + { + continue; + } + + // extract top level info + B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns); + U64 secrel_off = hdr->sec_off; + U64 secrel_opl = secrel_off + hdr->len; + U64 sec_base_off = sections.v[sec_idx - 1].voff; + + // read files + for(;read_off+sizeof(CV_C13File) <= read_off_opl;) + { + // rjf: grab next file header + CV_C13File *file = (CV_C13File*)(first + read_off); + U32 file_off = file->file_off; + U32 line_count_unclamped = file->num_lines; + U32 block_size = file->block_size; + + // file_name from file_off + String8 file_name = {0}; + if(file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off); + U32 name_off = checksum->name_off; + file_name = str8_cstring_capped((char*)(strtbl.str + name_off), + (char*)(strtbl.str + strtbl.size)); + } + + // array layouts + U32 line_item_size = sizeof(CV_C13Line); + if (has_cols){ + line_item_size += sizeof(CV_C13Column); + } + + U32 line_array_off = read_off + sizeof(*file); + U32 line_count_max = (read_off_opl - line_array_off) / line_item_size; + U32 line_count = ClampTop(line_count_unclamped, line_count_max); + + U32 col_array_off = line_array_off + line_count*sizeof(CV_C13Line); + + // parse lines + U64 *voffs = push_array_no_zero(arena, U64, line_count + 1); + U32 *line_nums = push_array_no_zero(arena, U32, line_count); + + { + CV_C13Line *line_ptr = (CV_C13Line*)(first + line_array_off); + CV_C13Line *line_opl = line_ptr + line_count; + + // TODO(allen): check order correctness here + + U32 i = 0; + for (; line_ptr < line_opl; line_ptr += 1, i += 1){ + voffs[i] = line_ptr->off + secrel_off + sec_base_off; + line_nums[i] = CV_C13LineFlags_ExtractLineNumber(line_ptr->flags); + } + voffs[i] = secrel_opl + sec_base_off; + } + + // emit parsed lines + CV_C13LinesParsedNode *lines_parsed_node = push_array(arena, CV_C13LinesParsedNode, 1); + CV_C13LinesParsed *lines_parsed = &lines_parsed_node->v; + lines_parsed->sec_idx = sec_idx; + lines_parsed->file_off = file_off; + lines_parsed->secrel_base_off = secrel_off; + lines_parsed->file_name = file_name; + lines_parsed->voffs = voffs; + lines_parsed->line_nums = line_nums; + lines_parsed->line_count = line_count; + SLLQueuePush(node->lines_first, node->lines_last, lines_parsed_node); + + // rjf: advance + read_off += sizeof(*file); + read_off += line_item_size*line_count; + } + }break; + + ////////////////////////// + //- rjf: inlinee line info sub-section + // + case CV_C13SubSectionKind_InlineeLines: + if(sizeof(CV_C13InlineeLinesSig) <= cap) + { + // rjf: read sig + U32 read_off = 0; + U64 read_off_opl = node->size; + CV_C13InlineeLinesSig *sig = (CV_C13InlineeLinesSig *)(first + read_off); + read_off += sizeof(*sig); + + // rjf: read source lines + for(;read_off + sizeof(CV_C13InlineeSourceLineHeader) <= read_off_opl;) + { + // rjf: read next header + CV_C13InlineeSourceLineHeader *hdr = (CV_C13InlineeSourceLineHeader *)(first + read_off); + read_off += sizeof(*hdr); + + // rjf: file_off -> file_name + String8 file_name = {0}; + if(hdr->file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off); + U32 name_off = checksum->name_off; + file_name = str8_cstring_capped((char*)(strtbl.str + name_off), + (char*)(strtbl.str + strtbl.size)); + } + + // rjf: parse extra files + U32 extra_file_count = 0; + U32 *extra_files = 0; + if(*sig == CV_C13InlineeLinesSig_EXTRA_FILES && read_off+sizeof(U32) <= read_off_opl) + { + U32 *extra_file_count_ptr = (U32 *)(first + read_off); + read_off += sizeof(*extra_file_count_ptr); + U32 max_extra_file_count = (read_off_opl-read_off)/sizeof(U32); + extra_file_count = Min(*extra_file_count_ptr, max_extra_file_count); + extra_files = (U32 *)(first + read_off); + read_off += sizeof(*extra_files)*extra_file_count; + } + + // rjf: push node for this inlinee lines parsed into this subsection's list + CV_C13InlineeLinesParsedNode *n = push_array(arena, CV_C13InlineeLinesParsedNode, 1); + SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n); + n->v.inlinee = hdr->inlinee; + n->v.file_name = file_name; + n->v.file_off = hdr->file_off; + n->v.first_source_ln = hdr->first_source_ln; + n->v.extra_file_count = extra_file_count; + n->v.extra_files = extra_files; + + // rjf: push node into inlinee parse hash table + U64 hash = cv_hash_from_item_id(hdr->inlinee); + U64 slot_idx = hash%inlinee_lines_parsed_slots_count; + SLLStackPush_N(inlinee_lines_parsed_slots[slot_idx], n, hash_next); + } + }break; + } + } + + ////////////////////////////// + //- rjf: fill output + // + CV_C13Parsed *result = push_array(arena, CV_C13Parsed, 1); + result->data = c13_data; + result->first_sub_section = first; + result->last_sub_section = last; + result->sub_section_count = count; + result->file_chksms_sub_section = file_chksms; + result->inlinee_lines_parsed_slots = inlinee_lines_parsed_slots; + result->inlinee_lines_parsed_slots_count = inlinee_lines_parsed_slots_count; + ProfEnd(); + return result; +} + diff --git a/src/codeview/codeview_parse.h b/src/codeview/codeview_parse.h new file mode 100644 index 00000000..5e558d60 --- /dev/null +++ b/src/codeview/codeview_parse.h @@ -0,0 +1,253 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CODEVIEW_PARSE_H +#define CODEVIEW_PARSE_H + +//////////////////////////////// +//~ CodeView Common Parser Types + +// CV_Numeric layout +// x: U16 +// buf: U8[] +// case (x < 0x8000): kind=U16 val=x +// case (x >= 0x8000): kind=x val=buf + +typedef struct CV_NumericParsed CV_NumericParsed; +struct CV_NumericParsed +{ + CV_NumericKind kind; + U8 *val; + U64 encoded_size; +}; + +typedef struct CV_RecRange CV_RecRange; +struct CV_RecRange +{ + U32 off; + CV_RecHeader hdr; +}; + +#define CV_REC_RANGE_CHUNK_SIZE 511 + +typedef struct CV_RecRangeChunk CV_RecRangeChunk; +struct CV_RecRangeChunk +{ + struct CV_RecRangeChunk *next; + CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE]; +}; + +typedef struct CV_RecRangeStream CV_RecRangeStream; +struct CV_RecRangeStream +{ + CV_RecRangeChunk *first_chunk; + CV_RecRangeChunk *last_chunk; + U64 total_count; +}; + +typedef struct CV_RecRangeArray CV_RecRangeArray; +struct CV_RecRangeArray +{ + CV_RecRange *ranges; + U64 count; +}; + +//////////////////////////////// +//~ CodeView Sym Parser Types + +typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo; +struct CV_SymTopLevelInfo +{ + CV_Arch arch; + CV_Language language; + String8 compiler_name; +}; + +typedef struct CV_SymParsed CV_SymParsed; +struct CV_SymParsed +{ + // source information + String8 data; + U64 sym_align; + + // sym index derived from source + CV_RecRangeArray sym_ranges; + + // top-level info derived from the syms + CV_SymTopLevelInfo info; +}; + +//////////////////////////////// +//~ CodeView Leaf Parser Types + +typedef struct CV_LeafParsed CV_LeafParsed; +struct CV_LeafParsed +{ + // source information + String8 data; + CV_TypeId itype_first; + CV_TypeId itype_opl; + + // leaf index derived from source + CV_RecRangeArray leaf_ranges; +}; + +//////////////////////////////// +//~ CodeView C13 Info Parser Types + +typedef struct CV_C13LinesParsed CV_C13LinesParsed; +struct CV_C13LinesParsed +{ + // raw info + U32 sec_idx; + U32 file_off; + U64 secrel_base_off; + + // parsed info + String8 file_name; + U64 *voffs; // [line_count + 1] + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + U32 line_count; +}; + +typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode; +struct CV_C13LinesParsedNode +{ + CV_C13LinesParsedNode *next; + CV_C13LinesParsed v; +}; + +typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed; +struct CV_C13InlineeLinesParsed +{ + CV_ItemId inlinee; + U32 file_off; + String8 file_name; + U32 first_source_ln; + U32 extra_file_count; + U32 *extra_files; +}; + +typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode; +struct CV_C13InlineeLinesParsedNode +{ + CV_C13InlineeLinesParsedNode *next; + CV_C13InlineeLinesParsedNode *hash_next; + CV_C13InlineeLinesParsed v; +}; + +typedef struct CV_C13SubSectionNode CV_C13SubSectionNode; +struct CV_C13SubSectionNode +{ + struct CV_C13SubSectionNode *next; + CV_C13SubSectionKind kind; + U32 off; + U32 size; + CV_C13LinesParsedNode *lines_first; + CV_C13LinesParsedNode *lines_last; + CV_C13InlineeLinesParsedNode *inlinee_lines_first; + CV_C13InlineeLinesParsedNode *inlinee_lines_last; +}; + +typedef struct CV_C13Parsed CV_C13Parsed; +struct CV_C13Parsed +{ + // rjf: source data + String8 data; + + // rjf: full sub-section list + CV_C13SubSectionNode *first_sub_section; + CV_C13SubSectionNode *last_sub_section; + U64 sub_section_count; + + // rjf: fastpath to file checksums section + CV_C13SubSectionNode *file_chksms_sub_section; + + // rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly + CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots; + U64 inlinee_lines_parsed_slots_count; +}; + +typedef struct CV_UDTInfo CV_UDTInfo; +struct CV_UDTInfo +{ + String8 name; + String8 unique_name; + CV_TypeProps props; +}; + +//////////////////////////////// +//~ CodeView Compound Types + +typedef struct CV_TypeIdArray CV_TypeIdArray; +struct CV_TypeIdArray +{ + CV_TypeId *itypes; + U64 count; +}; + +//////////////////////////////// + +//- Hasher + +internal U64 cv_hash_from_string(String8 string); +internal U64 cv_hash_from_item_id(CV_ItemId item_id); + +//- Numeric Decoder + +internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl); +internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out); + +internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num); +internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num); +internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num); + +internal U64 cv_u64_from_numeric(CV_NumericParsed *num); +internal S64 cv_s64_from_numeric(CV_NumericParsed *num); +internal F64 cv_f64_from_numeric(CV_NumericParsed *num); + +//- Inlinee Lines Binary Annot Decoder + +internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value); +internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value); +internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value); + +//- Symbol/Leaf Helpers + +internal B32 cv_is_udt_name_anon(String8 name); + +internal B32 cv_is_global_symbol(CV_SymKind kind); +internal B32 cv_is_typedef(CV_SymKind kind); +internal B32 cv_is_scope_symbol(CV_SymKind kind); +internal B32 cv_is_end_symbol(CV_SymKind kind); + +internal B32 cv_is_udt(CV_LeafKind kind); +internal B32 cv_is_leaf_type_server(CV_LeafKind kind); +internal B32 cv_is_leaf_pch(CV_LeafKind kind); +internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind); + +internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data); +internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data); +internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data); +internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data); + +internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data); +internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data); + +internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data); +internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info); + +//- rjf: record range stream parsing +internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align); +internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream); + +//- rjf: sym stream parsing +internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align); + +//- rjf: leaf stream parsing +internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first); +internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections); + +#endif // CODEVIEW_PARSE_H + diff --git a/src/linker/codeview_ext/codeview.h b/src/linker/codeview_ext/codeview.h index 983536c2..a4bddb1c 100644 --- a/src/linker/codeview_ext/codeview.h +++ b/src/linker/codeview_ext/codeview.h @@ -3,24 +3,8 @@ #pragma once -//////////////////////////////// -// Aligns - -#define CV_LeafAlign 4 -#define CV_SymbolAlign 1 -#define CV_C13SubSectionAlign 4 -#define CV_FileCheckSumsAlign 4 - -//////////////////////////////// - //- Symbol and Leaf Headers -#define CV_LeafSize_Max max_U16 -typedef U16 CV_LeafSize; - -#define CV_SymSize_Max max_U16 -typedef U16 CV_SymSize; - typedef struct CV_LeafHeader { CV_LeafSize size; diff --git a/src/linker/lnk.c b/src/linker/lnk.c index fe3d414f..7cfacb59 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -37,6 +37,7 @@ #include "coff/coff.h" #include "pe/pe.h" #include "codeview/codeview.h" +#include "codeview/codeview_parse.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -48,6 +49,8 @@ #include "coff/coff.c" #include "pe/pe.c" #include "codeview/codeview.c" +#include "codeview/codeview_parse.c" +#include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" #include "msvc_crt/msvc_crt.c" diff --git a/src/pdb/pdb_parse.c b/src/pdb/pdb_parse.c index f03c1dbf..5ae4bff3 100644 --- a/src/pdb/pdb_parse.c +++ b/src/pdb/pdb_parse.c @@ -17,7 +17,7 @@ pdb_info_from_data(Arena *arena, String8 data){ PDB_Info *result = 0; if (header != 0){ // read guid - COFF_Guid *auth_guid = 0; + Guid *auth_guid = 0; U32 after_auth_guid_off = sizeof(*header); switch (header->version){ case PDB_InfoVersion_VC70_DEP: @@ -26,7 +26,7 @@ pdb_info_from_data(Arena *arena, String8 data){ case PDB_InfoVersion_VC110: case PDB_InfoVersion_VC140: { - auth_guid = (COFF_Guid*)(data.str + after_auth_guid_off); + auth_guid = (Guid*)(data.str + after_auth_guid_off); after_auth_guid_off = sizeof(*header) + sizeof(*auth_guid); }break; diff --git a/src/pdb/pdb_parse.h b/src/pdb/pdb_parse.h index 07875f61..eb9f56e7 100644 --- a/src/pdb/pdb_parse.h +++ b/src/pdb/pdb_parse.h @@ -44,7 +44,7 @@ typedef struct PDB_Info { PDB_InfoNode *first; PDB_InfoNode *last; - COFF_Guid auth_guid; + Guid auth_guid; } PDB_Info; typedef struct PDB_InfoHeader diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 0c1b5f27..985af73f 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -342,7 +342,7 @@ #include "coff/coff.h" #include "pe/pe.h" #include "codeview/codeview.h" -#include "codeview/codeview_stringize.h" +#include "codeview/codeview_parse.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -383,7 +383,7 @@ #include "coff/coff.c" #include "pe/pe.c" #include "codeview/codeview.c" -#include "codeview/codeview_stringize.c" +#include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index fccf23fd..26a35bf6 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3127,7 +3127,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: parse PDB auth_guid & named streams table // PDB_NamedStreamTable *named_streams = 0; - COFF_Guid auth_guid = {0}; + Guid auth_guid = {0}; if(msf != 0) ProfScope("parse PDB auth_guid & named streams table") { Temp scratch = scratch_begin(&arena, 1); diff --git a/src/rdi_from_pdb/rdi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c index fd50b2fe..d5de3918 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -23,7 +23,7 @@ #include "rdi_make/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" -#include "codeview/codeview_stringize.h" +#include "codeview/codeview_parse.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -38,7 +38,7 @@ #include "rdi_make/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" -#include "codeview/codeview_stringize.c" +#include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" From b6b64be8670f6f585f89e579a5ad12702d025ab4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 12 Dec 2024 15:07:13 -0800 Subject: [PATCH 04/53] moved enum handling code to separate files --- src/codeview/codeview.c | 33 +- src/codeview/codeview.h | 7 +- src/codeview/codeview_enum.c | 775 ++++++++++ src/codeview/codeview_enum.h | 51 + src/codeview/codeview_stringize.c | 2342 ----------------------------- src/codeview/codeview_stringize.h | 84 -- src/coff/coff.c | 453 +----- src/coff/coff.h | 22 +- src/coff/coff_enum.c | 466 ++++++ src/coff/coff_enum.h | 27 + src/linker/lnk.c | 2 + src/msvc_crt/msvc_crt_enum.c | 34 + src/msvc_crt/msvc_crt_enum.h | 9 + 13 files changed, 1398 insertions(+), 2907 deletions(-) create mode 100644 src/codeview/codeview_enum.c create mode 100644 src/codeview/codeview_enum.h delete mode 100644 src/codeview/codeview_stringize.c delete mode 100644 src/codeview/codeview_stringize.h create mode 100644 src/coff/coff_enum.c create mode 100644 src/coff/coff_enum.h create mode 100644 src/msvc_crt/msvc_crt_enum.c create mode 100644 src/msvc_crt/msvc_crt_enum.h diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index ca5d0f3a..ac8de886 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -139,18 +139,29 @@ cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg) return fp_reg; } -//////////////////////////////// -//~ Enum <-> String - -internal String8 -cv_string_from_type_index_source(CV_TypeIndexSource ti_source) +internal U32 +cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg) { - switch (ti_source) { - case CV_TypeIndexSource_NULL: return str8_lit(""); break; - case CV_TypeIndexSource_TPI: return str8_lit("TPI"); break; - case CV_TypeIndexSource_IPI: return str8_lit("IPI"); break; - case CV_TypeIndexSource_COUNT: break; + U32 r = 0; + switch (arch) { + case CV_Arch_8086: { + switch (encoded_frame_reg) { + case 0: r = 0; break; + case 1: r = CV_AllReg_VFRAME; break; + case 2: r = CV_Regx86_EBP; break; + case 3: r = CV_Regx86_EBX; break; + } + } break; + case CV_Arch_X64: { + switch (encoded_frame_reg) { + case 0: r = 0; break; + case 1: r = CV_Regx64_RSP; break; + case 2: r = CV_Regx64_RBP; break; + case 3: r = CV_Regx64_R13; break; + } + } break; + default: NotImplemented; } - return str8_zero(); + return r; } diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index f432035f..d3796d4f 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -2969,10 +2969,7 @@ internal U64 cv_size_from_reg(CV_Arch arch, CV_Reg reg); internal B32 cv_is_reg_sp(CV_Arch arch, CV_Reg reg); internal CV_EncodedFramePtrReg cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B32 is_local_param); internal CV_Reg cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg); - -//////////////////////////////// -//~ Enum <-> String - -internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source); +internal U32 cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg); #endif // CODEVIEW_H + diff --git a/src/codeview/codeview_enum.c b/src/codeview/codeview_enum.c new file mode 100644 index 00000000..ada3d2c5 --- /dev/null +++ b/src/codeview/codeview_enum.c @@ -0,0 +1,775 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 +cv_string_from_type_index_source(CV_TypeIndexSource ti_source) +{ + switch (ti_source) { + case CV_TypeIndexSource_NULL: return str8_lit(""); break; + case CV_TypeIndexSource_TPI: return str8_lit("TPI"); break; + case CV_TypeIndexSource_IPI: return str8_lit("IPI"); break; + case CV_TypeIndexSource_COUNT: break; + } + return str8_zero(); +} + +internal String8 +cv_string_from_language(CV_Language x) +{ + switch (x) { + #define X(_n,_i) case _i: return str8_lit(Stringify(_n)); +CV_LanguageXList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +cv_string_from_numeric(Arena *arena, CV_NumericParsed num) +{ + String8 result = str8_zero(); + switch (num.kind) { + case CV_NumericKind_FLOAT16: break; // TODO: format float16 + case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break; + case CV_NumericKind_FLOAT48: break; // TODO: format float48 + case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break; + case CV_NumericKind_FLOAT80: break; // TODO: format float80 + case CV_NumericKind_FLOAT128: break; // TODO: format float128 + case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break; + case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break; + case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break; + case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break; + case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break; + case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break; + case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break; + } + return result; +} + +internal String8 +cv_string_from_reg_id(CV_Arch arch, U32 id) +{ + String8 result = str8_zero(); + switch (arch) { + case CV_Arch_8086: { + switch (id) { + #define X(_name, _id,...) case _id: str8_lit(Stringify(_name)); break; + CV_Reg_X86_XList(X) + #undef X + } + } break; + case CV_Arch_X64: { + switch (id) { + #define X(_name, _id,...) case _id: str8_lit(Stringify(_name)); break; + CV_Reg_X64_XList(X) + #undef X + } + } break; + default: NotImplemented; + } + return result; +} + +internal String8 +cv_string_from_member_access(CV_MemberAccess x) +{ + switch (x) { + case CV_MemberAccess_Null: break; + case CV_MemberAccess_Private: return str8_lit("Private"); + case CV_MemberAccess_Protected: return str8_lit("Protected"); + case CV_MemberAccess_Public: return str8_lit("Public"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_method_prop(CV_MethodProp x) +{ + switch (x) { + case CV_MethodProp_Vanilla: return str8_lit("Vanilla"); + case CV_MethodProp_Virtual: return str8_lit("Virtual"); + case CV_MethodProp_Static: return str8_lit("Static"); + case CV_MethodProp_Friend: return str8_lit("Friend"); + case CV_MethodProp_Intro: return str8_lit("Intro"); + case CV_MethodProp_PureVirtual: return str8_lit("PureVirtual"); + case CV_MethodProp_PureIntro: return str8_lit("PureIntro"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_hfa(CV_HFAKind x) +{ + switch (x) { + case CV_HFAKind_None: return str8_lit("None"); + case CV_HFAKind_Float: return str8_lit("Float"); + case CV_HFAKind_Double: return str8_lit("Double"); + case CV_HFAKind_Other: return str8_lit("Other"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_mcom(CV_MoComUDTKind x) +{ + switch (x) { + case CV_MoComUDTKind_None: return str8_lit("None"); + case CV_MoComUDTKind_Ref: return str8_lit("Ref"); + case CV_MoComUDTKind_Value: return str8_lit("Value"); + case CV_MoComUDTKind_Interface: return str8_lit("Interface"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_binary_opcode(CV_InlineBinaryAnnotation x) +{ + switch (x) { + case CV_InlineBinaryAnnotation_Null: break; + case CV_InlineBinaryAnnotation_CodeOffset: return str8_lit("CodeOffset"); + case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: return str8_lit("ChangeCodeOffsetBase"); + case CV_InlineBinaryAnnotation_ChangeCodeOffset: return str8_lit("ChangeCodeOffset"); + case CV_InlineBinaryAnnotation_ChangeCodeLength: return str8_lit("ChangeCodeLength"); + case CV_InlineBinaryAnnotation_ChangeFile: return str8_lit("ChangeFile"); + case CV_InlineBinaryAnnotation_ChangeLineOffset: return str8_lit("ChangeLineOffset"); + case CV_InlineBinaryAnnotation_ChangeLineEndDelta: return str8_lit("ChangeLineEndDelta"); + case CV_InlineBinaryAnnotation_ChangeRangeKind: return str8_lit("ChangeRangeKind"); + case CV_InlineBinaryAnnotation_ChangeColumnStart: return str8_lit("ChangeColumnStart"); + case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: return str8_lit("ChangeColumnEndDelta"); + case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: return str8_lit("ChangeCodeOffsetAndLineOffset"); + case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: return str8_lit("ChangeCodeLengthAndCodeOffset"); + case CV_InlineBinaryAnnotation_ChangeColumnEnd: return str8_lit("ChangeColumnEnd"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_thunk_ordinal(CV_ThunkOrdinal x) +{ + switch (x) { + case CV_ThunkOrdinal_NoType: return str8_lit("NoType"); + case CV_ThunkOrdinal_Adjustor: return str8_lit("Adjustor"); + case CV_ThunkOrdinal_VCall: return str8_lit("VCall"); + case CV_ThunkOrdinal_PCode: return str8_lit("PCode"); + case CV_ThunkOrdinal_Load: return str8_lit("Load"); + case CV_ThunkOrdinal_TrampIncremental: return str8_lit("TrampIncremental"); + case CV_ThunkOrdinal_TrampBranchIsland: return str8_lit("TrampBranchIsland"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_frame_cookie_kind(CV_FrameCookieKind x) +{ + switch (x) { + case CV_FrameCookieKind_Copy: return str8_lit("Copy"); + case CV_FrameCookieKind_XorSP: return str8_lit("XorSP"); + case CV_FrameCookieKind_XorBP: return str8_lit("XorR13"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_generic_style(CV_GenericStyle x) +{ + switch (x) { + case CV_GenericStyle_VOID: return str8_lit("VOID"); + case CV_GenericStyle_REG: return str8_lit("REG"); + case CV_GenericStyle_ICAN: return str8_lit("ICAN"); + case CV_GenericStyle_ICAF: return str8_lit("ICAF"); + case CV_GenericStyle_IRAN: return str8_lit("IRAN"); + case CV_GenericStyle_IRAF: return str8_lit("IRAF"); + case CV_GenericStyle_UNUSED: return str8_lit("UNUSED"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_trampoline_kind(CV_TrampolineKind x) +{ + switch (x) { + case CV_TrampolineKind_Incremental: return str8_lit("Incremental"); + case CV_TrampolineKind_BranchIsland: return str8_lit("BranchIsland"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_virtual_table_shape_kind(CV_VirtualTableShape x) +{ + switch (x) { + case CV_VirtualTableShape_Near: return str8_lit("Near"); + case CV_VirtualTableShape_Far: return str8_lit("Far"); + case CV_VirtualTableShape_Thin: return str8_lit("Thin"); + case CV_VirtualTableShape_Outer: return str8_lit("Outer"); + case CV_VirtualTableShape_Meta: return str8_lit("Meta"); + case CV_VirtualTableShape_Near32: return str8_lit("Near32"); + case CV_VirtualTableShape_Far32: return str8_lit("Far32"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_call_kind(CV_CallKind x) +{ + switch (x) { + case CV_CallKind_NearC: return str8_lit("NearC"); + case CV_CallKind_FarC: return str8_lit("FarC"); + case CV_CallKind_NearPascal: return str8_lit("NearPascal"); + case CV_CallKind_FarPascal: return str8_lit("FarPascal"); + case CV_CallKind_NearFast: return str8_lit("NearFast"); + case CV_CallKind_FarFast: return str8_lit("FarFast"); + case CV_CallKind_UNUSED: return str8_lit("UNUSED"); + case CV_CallKind_NearStd: return str8_lit("NearStd"); + case CV_CallKind_FarStd: return str8_lit("FarStd"); + case CV_CallKind_NearSys: return str8_lit("NearSys"); + case CV_CallKind_FarSys: return str8_lit("FarSys"); + case CV_CallKind_This: return str8_lit("This"); + case CV_CallKind_Mips: return str8_lit("Mips"); + case CV_CallKind_Generic: return str8_lit("Generic"); + case CV_CallKind_Alpha: return str8_lit("Alpha"); + case CV_CallKind_PPC: return str8_lit("PPC"); + case CV_CallKind_HitachiSuperH: return str8_lit("HitachiSuperH"); + case CV_CallKind_Arm: return str8_lit("Arm"); + case CV_CallKind_AM33: return str8_lit("AM33"); + case CV_CallKind_TriCore: return str8_lit("TriCore"); + case CV_CallKind_HitachiSuperH5: return str8_lit("HitachiSuperH5"); + case CV_CallKind_M32R: return str8_lit("M32R"); + case CV_CallKind_Clr: return str8_lit("Clr"); + case CV_CallKind_Inline: return str8_lit("Inline"); + case CV_CallKind_NearVector: return str8_lit("NearVector"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_member_pointer_kind(CV_MemberPointerKind x) +{ + switch (x) { + case CV_MemberPointerKind_Undef: return str8_lit("Undef"); + case CV_MemberPointerKind_DataSingle: return str8_lit("DataSingle"); + case CV_MemberPointerKind_DataMultiple: return str8_lit("DataMultiple"); + case CV_MemberPointerKind_DataVirtual: return str8_lit("DataVirtual"); + case CV_MemberPointerKind_DataGeneral: return str8_lit("DataGeneral"); + case CV_MemberPointerKind_FuncSingle: return str8_lit("FuncSingle"); + case CV_MemberPointerKind_FuncMultiple: return str8_lit("FuncMultiple"); + case CV_MemberPointerKind_FuncGeneral: return str8_lit("FuncGeneral"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_pointer_kind(CV_PointerKind x) +{ + switch (x) { + case CV_PointerKind_Near: return str8_lit("Near"); + case CV_PointerKind_Far: return str8_lit("Far"); + case CV_PointerKind_Huge: return str8_lit("Huge"); + case CV_PointerKind_BaseSeg: return str8_lit("BaseSeg"); + case CV_PointerKind_BaseVal: return str8_lit("BaseVal"); + case CV_PointerKind_BaseSegVal: return str8_lit("BaseSegVal"); + case CV_PointerKind_BaseAddr: return str8_lit("BaseAddr"); + case CV_PointerKind_BaseSegAddr: return str8_lit("BaseSegAddr"); + case CV_PointerKind_BaseType: return str8_lit("BaseType"); + case CV_PointerKind_BaseSelf: return str8_lit("BaseSelf"); + case CV_PointerKind_Near32: return str8_lit("Near32"); + case CV_PointerKind_Far32: return str8_lit("Far32"); + case CV_PointerKind_64: return str8_lit("64"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_pointer_mode(CV_PointerMode x) +{ + switch (x) { + case CV_PointerMode_Ptr: return str8_lit("Ptr"); + case CV_PointerMode_LRef: return str8_lit("LRef"); + case CV_PointerMode_PtrMem: return str8_lit("PtrMem"); + case CV_PointerMode_PtrMethod: return str8_lit("PtrMethod"); + case CV_PointerMode_RRef: return str8_lit("RRef"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x) +{ + switch (x) { + case CV_C13ChecksumKind_Null: break; + case CV_C13ChecksumKind_MD5: return str8_lit("MD5"); + case CV_C13ChecksumKind_SHA1: return str8_lit("SHA1"); + case CV_C13ChecksumKind_SHA256: return str8_lit("SHA256"); + } + return str8_zero(); +} + +internal String8 +cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x) +{ + switch (x) { + #define X(_id, _name) case CV_C13SubSectionKind_##_id: return str8_lit(Stringify(_name)); + CV_C13SubSectionKindXList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_ModifierFlag_Const) { + str8_list_pushf(scratch.arena, &list, "Const"); + } + if (x & CV_ModifierFlag_Volatile) { + str8_list_pushf(scratch.arena, &list, "Volatile"); + } + if (x & CV_ModifierFlag_Unaligned) { + str8_list_pushf(scratch.arena, &list, "Unaligned"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); +} + +internal String8 +cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_PointerAttrib_IsFlat) { + str8_list_pushf(scratch.arena, &list, "IsFlat"); + } + if (x & CV_PointerAttrib_Volatile) { + str8_list_pushf(scratch.arena, &list, "Volatile"); + } + if (x & CV_PointerAttrib_Const) { + str8_list_pushf(scratch.arena, &list, "Const"); + } + if (x & CV_PointerAttrib_Unaligned) { + str8_list_pushf(scratch.arena, &list, "Unaligned"); + } + if (x & CV_PointerAttrib_Restricted) { + str8_list_pushf(scratch.arena, &list, "Restricted"); + } + if (x & CV_PointerAttrib_MOCOM) { + str8_list_pushf(scratch.arena, &list, "MOCOM"); + } + if (x & CV_PointerAttrib_LRef) { + str8_list_pushf(scratch.arena, &list, "LRef"); + } + if (x & CV_PointerAttrib_RRef) { + str8_list_pushf(scratch.arena, &list, "RRef"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_function_attribs(Arena *arena, CV_FunctionAttribs x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_FunctionAttrib_CxxReturnUDT) { + str8_list_pushf(scratch.arena, &list, "CxxReturnUDT"); + } + if (x & CV_FunctionAttrib_Constructor) { + str8_list_pushf(scratch.arena, &list, "Constructor"); + } + if (x & CV_FunctionAttrib_ConstructorVBase) { + str8_list_pushf(scratch.arena, &list, "ConstructorVBase"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_export_flags(Arena *arena, CV_ExportFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_ExportFlag_Constant) { + str8_list_pushf(scratch.arena, &list, "Constant"); + } + if (x & CV_ExportFlag_Data) { + str8_list_pushf(scratch.arena, &list, "Data"); + } + if (x & CV_ExportFlag_Private) { + str8_list_pushf(scratch.arena, &list, "Private"); + } + if (x & CV_ExportFlag_NoName) { + str8_list_pushf(scratch.arena, &list, "NoName"); + } + if (x & CV_ExportFlag_Ordinal) { + str8_list_pushf(scratch.arena, &list, "Ordinal"); + } + if (x & CV_ExportFlag_Forwarder) { + str8_list_pushf(scratch.arena, &list, "Forwarder"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x) +{ + Temp scratch = scratch_begin(&arena,1); + String8List list = {0}; + if (x & CV_SepcodeFlag_IsLexicalScope) { + str8_list_pushf(scratch.arena, &list, "IsLexicalScope"); + } + if (x & CV_SepcodeFlag_ReturnsToParent) { + str8_list_pushf(scratch.arena, &list, "ReturnsToParent"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_Pub32Flag_Code) { + str8_list_pushf(scratch.arena, &list, "Code"); + } + if (x & CV_Pub32Flag_Function) { + str8_list_pushf(scratch.arena, &list, "Function"); + } + if (x & CV_Pub32Flag_ManagedCode) { + str8_list_pushf(scratch.arena, &list, "ManagedCode"); + } + if (x & CV_Pub32Flag_MSIL) { + str8_list_pushf(scratch.arena, &list, "MSIL"); + } + String8 result = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_generic_flags(Arena *arena, CV_GenericFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_GenericFlags_CSTYLE) { + str8_list_pushf(scratch.arena, &list, "CSTYLE"); + } + if (x & CV_GenericFlags_RSCLEAN) { + str8_list_pushf(scratch.arena, &list, "RSCLEAN"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_FrameprocFlag_UsesAlloca) { + str8_list_pushf(scratch.arena, &list, "UsesAlloca"); + } + if (x & CV_FrameprocFlag_UsesSetJmp) { + str8_list_pushf(scratch.arena, &list, "UsesSetJmp"); + } + if (x & CV_FrameprocFlag_UsesLongJmp) { + str8_list_pushf(scratch.arena, &list, "UsesLongJmp"); + } + if (x & CV_FrameprocFlag_UsesInlAsm) { + str8_list_pushf(scratch.arena, &list, "UsesInlAsm"); + } + if (x & CV_FrameprocFlag_UsesEH) { + str8_list_pushf(scratch.arena, &list, "UsesEH"); + } + if (x & CV_FrameprocFlag_Inline) { + str8_list_pushf(scratch.arena, &list, "Inline"); + } + if (x & CV_FrameprocFlag_HasSEH) { + str8_list_pushf(scratch.arena, &list, "HasSEH"); + } + if (x & CV_FrameprocFlag_Naked) { + str8_list_pushf(scratch.arena, &list, "Naked"); + } + if (x & CV_FrameprocFlag_HasSecurityChecks) { + str8_list_pushf(scratch.arena, &list, "HasSecurityChecks"); + } + if (x & CV_FrameprocFlag_AsyncEH) { + str8_list_pushf(scratch.arena, &list, "AsyncEH"); + } + if (x & CV_FrameprocFlag_GSNoStackOrdering) { + str8_list_pushf(scratch.arena, &list, "GSNoStackOrdering"); + } + if (x & CV_FrameprocFlag_WasInlined) { + str8_list_pushf(scratch.arena, &list, "WasInlined"); + } + if (x & CV_FrameprocFlag_GSCheck) { + str8_list_pushf(scratch.arena, &list, "GSCheck"); + } + if (x & CV_FrameprocFlag_SafeBuffers) { + str8_list_pushf(scratch.arena, &list, "SafeBuffers"); + } + if (x & CV_FrameprocFlag_PogoOn) { + str8_list_pushf(scratch.arena, &list, "PogoOn"); + } + if (x & CV_FrameprocFlag_PogoCountsValid) { + str8_list_pushf(scratch.arena, &list, "PogoCountsValid"); + } + if (x & CV_FrameprocFlag_OptSpeed) { + str8_list_pushf(scratch.arena, &list, "OptSpeed"); + } + if (x & CV_FrameprocFlag_HasCFG) { + str8_list_pushf(scratch.arena, &list, "HasCFG"); + } + if (x & CV_FrameprocFlag_HasCFW) { + str8_list_pushf(scratch.arena, &list, "HasCFW"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_type_props(Arena *arena, CV_TypeProps x) +{ + Temp scratch = scratch_begin(&arena, 1); + U32 hfa = CV_TypeProps_Extract_HFA(x); + U32 mcom = CV_TypeProps_Extract_MOCOM(x); + + String8 flags_str; + { + String8List list = {0}; + if (x & CV_TypeProp_Packed) { + str8_list_pushf(scratch.arena, &list, "Packed"); + } + if (x & CV_TypeProp_HasConstructorsDestructors) { + str8_list_pushf(scratch.arena, &list, "HasConstructorsDestructors"); + } + if (x & CV_TypeProp_OverloadedOperators) { + str8_list_pushf(scratch.arena, &list, "OverloadedOperators"); + } + if (x & CV_TypeProp_IsNested) { + str8_list_pushf(scratch.arena, &list, "IsNested"); + } + if (x & CV_TypeProp_ContainsNested) { + str8_list_pushf(scratch.arena, &list, "ContainsNested"); + } + if (x & CV_TypeProp_OverloadedAssignment) { + str8_list_pushf(scratch.arena, &list, "OverloadedAssignment"); + } + if (x & CV_TypeProp_OverloadedCasting) { + str8_list_pushf(scratch.arena, &list, "OverloadedCasting"); + } + if (x & CV_TypeProp_FwdRef) { + str8_list_pushf(scratch.arena, &list, "FwdRef"); + } + if (x & CV_TypeProp_Scoped) { + str8_list_pushf(scratch.arena, &list, "Scoped"); + } + if (x & CV_TypeProp_HasUniqueName) { + str8_list_pushf(scratch.arena, &list, "HasUniqueName"); + } + if (x & CV_TypeProp_Sealed) { + str8_list_pushf(scratch.arena, &list, "Sealed"); + } + flags_str = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ") }); + } + + String8 hfa_str = cv_string_from_hfa(hfa); + String8 mcom_str = cv_string_from_mcom(mcom); + String8 result = push_str8f(arena, "flags = %S, HFA = %S, MCOM = %S", flags_str, hfa_str, mcom_str); + + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_local_flags(Arena *arena, CV_LocalFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_LocalFlag_Param) { + str8_list_pushf(scratch.arena, &list, "Param"); + } + if (x & CV_LocalFlag_AddrTaken) { + str8_list_pushf(scratch.arena, &list, "AddrTaken"); + } + if (x & CV_LocalFlag_Compgen) { + str8_list_pushf(scratch.arena, &list, "Compgen"); + } + if (x & CV_LocalFlag_Aggregate) { + str8_list_pushf(scratch.arena, &list, "Aggregate"); + } + if (x & CV_LocalFlag_PartOfAggregate) { + str8_list_pushf(scratch.arena, &list, "PartOfAggregate"); + } + if (x & CV_LocalFlag_Aliased) { + str8_list_pushf(scratch.arena, &list, "Aliased"); + } + if (x & CV_LocalFlag_Alias) { + str8_list_pushf(scratch.arena, &list, "Alias"); + } + if (x & CV_LocalFlag_Retval) { + str8_list_pushf(scratch.arena, &list, "Retval"); + } + if (x & CV_LocalFlag_OptOut) { + str8_list_pushf(scratch.arena, &list, "OptOut"); + } + if (x & CV_LocalFlag_Global) { + str8_list_pushf(scratch.arena, &list, "Global"); + } + if (x & CV_LocalFlag_Static) { + str8_list_pushf(scratch.arena, &list, "Static"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (x & CV_ProcFlag_NoFPO) { + str8_list_pushf(scratch.arena, &list, "NoFPO"); + } + if (x & CV_ProcFlag_IntReturn) { + str8_list_pushf(scratch.arena, &list, "IntReturn"); + } + if (x & CV_ProcFlag_FarReturn) { + str8_list_pushf(scratch.arena, &list, "FarReturn"); + } + if (x & CV_ProcFlag_NeverReturn) { + str8_list_pushf(scratch.arena, &list, "NeverReturn"); + } + if (x & CV_ProcFlag_NotReached) { + str8_list_pushf(scratch.arena, &list, "NotReached"); + } + if (x & CV_ProcFlag_CustomCall) { + str8_list_pushf(scratch.arena, &list, "CustomCall"); + } + if (x & CV_ProcFlag_NoInline) { + str8_list_pushf(scratch.arena, &list, "NoInline"); + } + if (x & CV_ProcFlag_OptDbgInfo) { + str8_list_pushf(scratch.arena, &list, "OptDbgInfo"); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + temp_end(scratch); + return result; +} + +internal String8 +cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x) +{ (void)arena; + String8 result = str8_lit("None"); + if (x == CV_RangeAttrib_Maybe) { + result = str8_lit("Maybe"); + } + return result; +} + +internal String8 +cv_string_from_defrange_register_rel_flags(Arena *arena, CV_DefrangeRegisterRelFlags x) +{ (void)arena; + String8 result = str8_lit("None"); + if (x == CV_DefrangeRegisterRelFlag_SpilledOutUDTMember) { + result = str8_lit("SpilledOutUDTMember"); + } + return result; +} + +internal String8 +cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs) +{ + Temp scratch = scratch_begin(&arena, 1); + + U32 access = CV_FieldAttribs_Extract_ACCESS(attribs); + U32 mprop = CV_FieldAttribs_Extract_MPROP(attribs); + + String8 attribs_str; + { + String8List list = {0}; + if (attribs & CV_FieldAttrib_Pseudo) { + str8_list_pushf(scratch.arena, &list, "Pseudo"); + } + if (attribs & CV_FieldAttrib_NoInherit) { + str8_list_pushf(scratch.arena, &list, "NoInherit"); + } + if (attribs & CV_FieldAttrib_NoConstruct) { + str8_list_pushf(scratch.arena, &list, "NoConstruct"); + } + if (attribs & CV_FieldAttrib_CompilerGenated) { + str8_list_pushf(scratch.arena, &list, "CompilerGenerated"); + } + if (attribs & CV_FieldAttrib_Sealed) { + str8_list_pushf(scratch.arena, &list, "Sealed"); + } + attribs_str = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=", " }); + } + + String8 access_str = cv_string_from_member_access(access); + String8 mprop_str = cv_string_from_method_prop(mprop); + String8 result = push_str8f(arena, "flags = %S, access = %S, method prop = %S", attribs_str, access_str, mprop_str); + + scratch_end(scratch); + return result; +} + +internal String8 +cv_string_from_itype(Arena *arena, CV_TypeIndex itype) +{ + String8 result = push_str8f(arena, "%x", itype); + return result; +} + +internal String8 +cv_string_from_itemid(Arena *arena, CV_ItemId itemid) +{ + String8 result = push_str8f(arena, "%x", itemid); + return result; +} + +internal String8 +cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off) +{ + return push_str8f(arena, "%S+%x", cv_string_from_reg_id(arch, reg), off); +} + +internal String8 +cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type) +{ + String8 str = cv_string_from_sym_kind(symbol_type); + String8 result = push_str8f(arena, "S_%S", str); + return result; +} + +internal String8 +cv_string_from_symbol_kind(Arena *arena, CV_SymKind kind) +{ + String8 str = cv_string_from_sym_kind(kind); + String8 result = push_str8f(arena, "S_%S", str); + return result; +} + +internal String8 +cv_string_from_leaf_name(Arena *arena, U32 leaf_type) +{ + String8 str = cv_string_from_leaf_kind(leaf_type); + String8 result = push_str8f(arena, "LF_%S", str); + return result; +} + +internal String8 +cv_string_sec_off(Arena *arena, U32 sec, U32 off) +{ + return push_str8f(arena, "%04x:%08x", sec, off); +} + diff --git a/src/codeview/codeview_enum.h b/src/codeview/codeview_enum.h new file mode 100644 index 00000000..c15392a9 --- /dev/null +++ b/src/codeview/codeview_enum.h @@ -0,0 +1,51 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CODEVIEW_ENUM_H +#define CODEVIEW_ENUM_H + +internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source); +internal String8 cv_string_from_language(CV_Language x); +internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num); +internal String8 cv_string_from_reg_id(CV_Arch arch, U32 id); +internal String8 cv_string_from_member_access(CV_MemberAccess x); +internal String8 cv_string_from_method_prop(CV_MethodProp x); +internal String8 cv_string_from_hfa(CV_HFAKind x); +internal String8 cv_string_from_mcom(CV_MoComUDTKind x); +internal String8 cv_string_from_binary_opcode(CV_InlineBinaryAnnotation x); +internal String8 cv_string_from_thunk_ordinal(CV_ThunkOrdinal x); +internal String8 cv_string_from_frame_cookie_kind(CV_FrameCookieKind x); +internal String8 cv_string_from_generic_style(CV_GenericStyle x); +internal String8 cv_string_from_trampoline_kind(CV_TrampolineKind x); +internal String8 cv_string_from_virtual_table_shape_kind(CV_VirtualTableShape x); +internal String8 cv_string_from_call_kind(CV_CallKind x); +internal String8 cv_string_from_member_pointer_kind(CV_MemberPointerKind x); +internal String8 cv_string_from_pointer_kind(CV_PointerKind x); +internal String8 cv_string_from_pointer_mode(CV_PointerMode x); +internal String8 cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x); +internal String8 cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x); +internal String8 cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x); +internal String8 cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x); +internal String8 cv_string_from_function_attribs(Arena *arena, CV_FunctionAttribs x); +internal String8 cv_string_from_export_flags(Arena *arena, CV_ExportFlags x); +internal String8 cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x); +internal String8 cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x); +internal String8 cv_string_generic_flags(Arena *arena, CV_GenericFlags x); +internal String8 cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x); +internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps x); +internal String8 cv_string_from_local_flags(Arena *arena, CV_LocalFlags x); +internal String8 cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x); +internal String8 cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x); +internal String8 cv_string_from_defrange_register_rel_flags(Arena *arena, CV_DefrangeRegisterRelFlags x); +internal String8 cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs); +internal String8 cv_string_from_itype(Arena *arena, CV_TypeIndex itype); +internal String8 cv_string_from_itemid(Arena *arena, CV_ItemId itemid); +internal String8 cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off); +internal String8 cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type); +internal String8 cv_string_from_symbol_kind(Arena *arena, CV_SymKind kind); +internal String8 cv_string_from_leaf_name(Arena *arena, U32 leaf_type); +internal String8 cv_string_sec_off(Arena *arena, U32 sec, U32 off); + +#endif // CODEVIEW_ENUM_H + + diff --git a/src/codeview/codeview_stringize.c b/src/codeview/codeview_stringize.c deleted file mode 100644 index b4e81d33..00000000 --- a/src/codeview/codeview_stringize.c +++ /dev/null @@ -1,2342 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ CodeView Common Stringize Functions - -internal void -cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num){ - String8 numeric_kind_str = cv_string_from_numeric_kind(num->kind); - str8_list_pushf(arena, out, "(%.*s)", str8_varg(numeric_kind_str)); - - if (cv_numeric_fits_in_u64(num)){ - U64 n = cv_u64_from_numeric(num); - str8_list_pushf(arena, out, "(%llu)", n); - } - else if (cv_numeric_fits_in_s64(num)){ - S64 n = cv_s64_from_numeric(num); - str8_list_pushf(arena, out, "(%lld)", n); - } - else if (cv_numeric_fits_in_f64(num)){ - F64 n = cv_f64_from_numeric(num); - str8_list_pushf(arena, out, "(%f)", n); - } -} - -internal void -cv_stringize_lvar_addr_range(Arena *arena, String8List *out, CV_LvarAddrRange *range){ - str8_list_pushf(arena, out, "{off=%x, sec=%u, len=%u}", range->off, range->sec, range->len); -} - -internal void -cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap){ - str8_list_pushf(arena, out, "{off=%x, len=%u}", gap->off, gap->len); -} - -internal void -cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, void *first, void *opl){ - U64 gap_count = ((U8*)first - (U8*)opl)/sizeof(CV_LvarAddrGap); - if (gap_count > 0){ - str8_list_push(arena, out, str8_lit(" gaps=\n")); - CV_LvarAddrGap *gap = (CV_LvarAddrGap*)first; - CV_LvarAddrGap *opl = gap + gap_count; - for (;gap < opl; gap += 1){ - str8_list_push(arena, out, str8_lit(" ")); - cv_stringize_lvar_addr_gap(arena, out, gap); - str8_list_push(arena, out, str8_lit("\n")); - } - } -} - -internal String8 -cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind){ - String8 result = str8_lit("UNRECOGNIZED_C13_SUB_SECTION_KIND"); - switch (kind){ - case 0: str8_lit("PARSE_ERROR"); break; -#define X(N,c) case CV_C13SubSectionKind_##N: result = str8_lit(#N); break; - CV_C13SubSectionKindXList(X) -#undef X - } - return(result); -} - -internal String8 -cv_string_from_reg(CV_Arch arch, CV_Reg reg){ - String8 result = {0}; - switch (arch){ - default: result = str8_lit(""); break; - - case CV_Arch_8086: - { - switch (reg){ -#define X(CVN,C,RDN,BP,BZ) case CV_Regx86_##CVN: result = str8_lit(#CVN); break; - CV_Reg_X86_XList(X) -#undef X - } - }break; - - case CV_Arch_X64: - { - switch (reg){ -#define X(CVN,C,RDN,BP,BZ) case CV_Regx64_##CVN: result = str8_lit(#CVN); break; - CV_Reg_X64_XList(X) -#undef X - } - }break; - } - return(result); -} - -internal String8 -cv_string_from_pointer_kind(CV_PointerKind ptr_kind){ - String8 result = {0}; - switch (ptr_kind){ - default: result = str8_lit(""); break; - case CV_PointerKind_Near: result = str8_lit("Near"); break; - case CV_PointerKind_Far: result = str8_lit("Far"); break; - case CV_PointerKind_Huge: result = str8_lit("Huge"); break; - case CV_PointerKind_BaseSeg: result = str8_lit("BaseSeg"); break; - case CV_PointerKind_BaseVal: result = str8_lit("BaseVal"); break; - case CV_PointerKind_BaseSegVal: result = str8_lit("BaseSegVal"); break; - case CV_PointerKind_BaseAddr: result = str8_lit("BaseAddr"); break; - case CV_PointerKind_BaseSegAddr: result = str8_lit("BaseSegAddr"); break; - case CV_PointerKind_BaseType: result = str8_lit("BaseType"); break; - case CV_PointerKind_BaseSelf: result = str8_lit("BaseSelf"); break; - case CV_PointerKind_Near32: result = str8_lit("Near32"); break; - case CV_PointerKind_Far32: result = str8_lit("Far32"); break; - case CV_PointerKind_64: result = str8_lit("64"); break; - } - return(result); -} - -internal String8 -cv_string_from_pointer_mode(CV_PointerMode ptr_mode){ - String8 result = {0}; - switch (ptr_mode){ - default: result = str8_lit(""); break; - case CV_PointerMode_Ptr: result = str8_lit("Ptr"); break; - case CV_PointerMode_LRef: result = str8_lit("LRef"); break; - case CV_PointerMode_PtrMem: result = str8_lit("PtrMem"); break; - case CV_PointerMode_PtrMethod: result = str8_lit("PtrMethod"); break; - case CV_PointerMode_RRef: result = str8_lit("RRef"); break; - } - return(result); -} - -internal String8 -cv_string_from_hfa_kind(CV_HFAKind hfa_kind){ - String8 result = {0}; - switch (hfa_kind){ - default: result = str8_lit(""); break; - case CV_HFAKind_None: result = str8_lit("None"); break; - case CV_HFAKind_Float: result = str8_lit("Float"); break; - case CV_HFAKind_Double: result = str8_lit("Double"); break; - case CV_HFAKind_Other: result = str8_lit("Other"); break; - } - return(result); -} - -internal String8 -cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind){ - String8 result = {0}; - switch (mo_com_udt_kind){ - default: result = str8_lit(""); break; - case CV_MoComUDTKind_None: result = str8_lit("None"); break; - case CV_MoComUDTKind_Ref: result = str8_lit("Ref"); break; - case CV_MoComUDTKind_Value: result = str8_lit("Value"); break; - case CV_MoComUDTKind_Interface: result = str8_lit("Interface"); break; - } - return(result); -} - -//////////////////////////////// -//~ CodeView Flags Stringize Functions - -global char cv_stringize_spaces[] = " "; - -#define SPACES cv_stringize_spaces - -internal void -cv_stringize_modifier_flags(Arena *arena, String8List *out, - U32 indent, CV_ModifierFlags flags){ - if (flags & CV_ModifierFlag_Const){ - str8_list_pushf(arena, out, "%.*sConst\n", indent, SPACES); - } - if (flags & CV_ModifierFlag_Volatile){ - str8_list_pushf(arena, out, "%.*sVolatile\n", indent, SPACES); - } - if (flags & CV_ModifierFlag_Unaligned){ - str8_list_pushf(arena, out, "%.*sUnaligned\n", indent, SPACES); - } -} - -internal void -cv_stringize_type_props(Arena *arena, String8List *out, - U32 indent, CV_TypeProps props){ - if (props & CV_TypeProp_Packed){ - str8_list_pushf(arena, out, "%.*sPacked\n", indent, SPACES); - } - if (props & CV_TypeProp_HasConstructorsDestructors){ - str8_list_pushf(arena, out, "%.*sHasConstructorsDesctructors\n", indent, SPACES); - } - if (props & CV_TypeProp_OverloadedOperators){ - str8_list_pushf(arena, out, "%.*sOverloadedOperators\n", indent, SPACES); - } - if (props & CV_TypeProp_IsNested){ - str8_list_pushf(arena, out, "%.*sIsNested\n", indent, SPACES); - } - if (props & CV_TypeProp_ContainsNested){ - str8_list_pushf(arena, out, "%.*sContainsNested\n", indent, SPACES); - } - if (props & CV_TypeProp_OverloadedAssignment){ - str8_list_pushf(arena, out, "%.*sOverloadedAssignment\n", indent, SPACES); - } - if (props & CV_TypeProp_OverloadedCasting){ - str8_list_pushf(arena, out, "%.*sOverloadedCasting\n", indent, SPACES); - } - if (props & CV_TypeProp_FwdRef){ - str8_list_pushf(arena, out, "%.*sFwdRef\n", indent, SPACES); - } - if (props & CV_TypeProp_Scoped){ - str8_list_pushf(arena, out, "%.*sScoped\n", indent, SPACES); - } - if (props & CV_TypeProp_HasUniqueName){ - str8_list_pushf(arena, out, "%.*sHasUniqueName\n", indent, SPACES); - } - if (props & CV_TypeProp_Sealed){ - str8_list_pushf(arena, out, "%.*sSealed\n", indent, SPACES); - } - if (props & CV_TypeProp_Intrinsic){ - str8_list_pushf(arena, out, "%.*sIntrinsic\n", indent, SPACES); - } - - CV_HFAKind hfa = CV_TypeProps_ExtractHFA(props); - { - String8 hfa_str = cv_string_from_hfa_kind(hfa); - str8_list_pushf(arena, out, "%.*shfa=%.*s\n", - indent, SPACES, str8_varg(hfa_str)); - } - - CV_MoComUDTKind mo_com = CV_TypeProps_ExtractMOCOM(props); - { - String8 mo_com_str = cv_string_from_mo_com_udt_kind(mo_com); - str8_list_pushf(arena, out, "%.*smocom=%.*s\n", - indent, SPACES, str8_varg(mo_com_str)); - } -} - -internal void -cv_stringize_pointer_attribs(Arena *arena, String8List *out, - U32 indent, CV_PointerAttribs attribs){ - if (attribs & CV_PointerAttrib_IsFlat){ - str8_list_pushf(arena, out, "%.*sIsFlat\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_Volatile){ - str8_list_pushf(arena, out, "%.*sVolatile\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_Const){ - str8_list_pushf(arena, out, "%.*sConst\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_Unaligned){ - str8_list_pushf(arena, out, "%.*sUnaligned\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_Restricted){ - str8_list_pushf(arena, out, "%.*sRestricted\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_MOCOM){ - str8_list_pushf(arena, out, "%.*sMOCOM\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_LRef){ - str8_list_pushf(arena, out, "%.*sLRef\n", indent, SPACES); - } - if (attribs & CV_PointerAttrib_RRef){ - str8_list_pushf(arena, out, "%.*sRRef\n", indent, SPACES); - } - - CV_PointerKind kind = CV_PointerAttribs_ExtractKind(attribs); - { - String8 kind_str = cv_string_from_pointer_kind(kind); - str8_list_pushf(arena, out, "%.*skind=%.*s\n", - indent, SPACES, str8_varg(kind_str)); - } - - CV_PointerMode mode = CV_PointerAttribs_ExtractMode(attribs); - { - String8 mode_str = cv_string_from_pointer_mode(mode); - str8_list_pushf(arena, out, "%.*smode=%.*s\n", - indent, SPACES, str8_varg(mode_str)); - } - - U32 size = CV_PointerAttribs_ExtractSize(attribs); - str8_list_pushf(arena, out, "%.*ssize=%u\n", - indent, SPACES, size); -} - -internal void -cv_stringize_local_flags(Arena *arena, String8List *out, - U32 indent, CV_LocalFlags flags){ - if (flags & CV_LocalFlag_Param){ - str8_list_pushf(arena, out, "%.*sParam\n", indent, SPACES); - } - if (flags & CV_LocalFlag_AddrTaken){ - str8_list_pushf(arena, out, "%.*sAddrTaken\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Compgen){ - str8_list_pushf(arena, out, "%.*sCompgen\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Aggregate){ - str8_list_pushf(arena, out, "%.*sAggregate\n", indent, SPACES); - } - if (flags & CV_LocalFlag_PartOfAggregate){ - str8_list_pushf(arena, out, "%.*sPartOfAggregate\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Aliased){ - str8_list_pushf(arena, out, "%.*sAliased\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Alias){ - str8_list_pushf(arena, out, "%.*sAlias\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Retval){ - str8_list_pushf(arena, out, "%.*sRetval\n", indent, SPACES); - } - if (flags & CV_LocalFlag_OptOut){ - str8_list_pushf(arena, out, "%.*sOptOut\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Global){ - str8_list_pushf(arena, out, "%.*sGlobal\n", indent, SPACES); - } - if (flags & CV_LocalFlag_Static){ - str8_list_pushf(arena, out, "%.*sStatic\n", indent, SPACES); - } -} - - -#undef SPACES - -//////////////////////////////// -//~ CodeView Sym Stringize Functions - -internal void -cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym){ - CV_StringizeSymParams params = {0}; - params.arch = sym->info.arch; - - cv_stringize_sym_array(arena, out, &sym->sym_ranges, sym->data, ¶ms); -} - -internal void -cv_stringize_sym_range(Arena *arena, String8List *out, - CV_RecRange *range, String8 data, - CV_StringizeSymParams *p){ - U64 opl_off = range->off + range->hdr.size; - if (opl_off > data.size){ - str8_list_push(arena, out, str8_lit("bad symbol range\n")); - } - - if (opl_off <= data.size){ - // [off]: kind - { - String8 kind_str = cv_string_from_sym_kind(range->hdr.kind); - str8_list_pushf(arena, out, "[%06x]: %.*s\n", - range->off + 2, str8_varg(kind_str)); - } - - // details - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - - switch (range->hdr.kind){ - default:break; - - case CV_SymKind_COMPILE: - { - if (sizeof(CV_SymCompile) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymCompile *compile = (CV_SymCompile*)first; - - // machine - String8 machine = cv_string_from_arch(compile->machine); - str8_list_pushf(arena, out, " machine=%.*s\n", - str8_varg(machine)); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", compile->flags); - - // ver_str - String8 ver_str = str8_cstring_capped((char*)(compile + 1), first + cap); - str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); - } - }break; - - case CV_SymKind_END: - { - // no contents - }break; - - case CV_SymKind_FRAMEPROC: - { - if (sizeof(CV_SymFrameproc) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)first; - - // frame sizes and offsets - str8_list_pushf(arena, out, " frame_size=%u\n", - frameproc->frame_size); - str8_list_pushf(arena, out, " pad_size=%u\n", - frameproc->pad_size); - str8_list_pushf(arena, out, " pad_off=%u\n", - frameproc->pad_off); - str8_list_pushf(arena, out, " save_reg_size=%u\n", - frameproc->save_reg_size); - str8_list_pushf(arena, out, " eh_off=%x\n", - frameproc->eh_off); - - // eh section - str8_list_pushf(arena, out, " eh_sec=%u\n", - frameproc->eh_sec); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", frameproc->flags); - } - }break; - - case CV_SymKind_OBJNAME: - { - if (sizeof(CV_SymObjName) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymObjName *objname = (CV_SymObjName*)first; - - // sig - str8_list_pushf(arena, out, " sig=%u\n", objname->sig); - - // name - String8 name = str8_cstring_capped((char*)(objname + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_THUNK32: - { - if (sizeof(CV_SymThunk32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymThunk32 *thunk32 = (CV_SymThunk32*)first; - - // members - str8_list_pushf(arena, out, " parent=%x\n", thunk32->parent); - str8_list_pushf(arena, out, " end=%x\n", thunk32->end); - str8_list_pushf(arena, out, " next=%x\n", thunk32->next); - str8_list_pushf(arena, out, " off=%u\n", thunk32->off); - str8_list_pushf(arena, out, " sec=%u\n", thunk32->sec); - str8_list_pushf(arena, out, " len=%u\n", thunk32->len); - - // ord - // TODO(allen): better ord path - str8_list_pushf(arena, out, " ord=%u\n", thunk32->ord); - - // name - String8 name = str8_cstring_capped((char*)(thunk32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - - // variant - String8 variant = str8_cstring_capped(name.str + name.size + 1, first + cap); - str8_list_pushf(arena, out, " variant='%.*s'\n", str8_varg(variant)); - } - }break; - - case CV_SymKind_BLOCK32: - { - if (sizeof(CV_SymBlock32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymBlock32 *block32 = (CV_SymBlock32*)first; - - // block attributes - str8_list_pushf(arena, out, " parent=%x\n", block32->parent); - str8_list_pushf(arena, out, " end=%x\n", block32->end); - str8_list_pushf(arena, out, " len=%u\n", block32->len); - str8_list_pushf(arena, out, " off=%x\n", block32->off); - str8_list_pushf(arena, out, " sec=%u\n", block32->sec); - - // name - String8 name = str8_cstring_capped((char*)(block32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", - str8_varg(name)); - } - }break; - - case CV_SymKind_LABEL32: - { - if (sizeof(CV_SymLabel32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymLabel32 *label32 = (CV_SymLabel32*)first; - - // label attributes - str8_list_pushf(arena, out, " off=%x\n", label32->off); - str8_list_pushf(arena, out, " sec=%u\n", label32->sec); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", label32->flags); - - // name - String8 name = str8_cstring_capped((char*)(label32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", - str8_varg(name)); - } - }break; - - case CV_SymKind_CONSTANT: - { - if (sizeof(CV_SymConstant) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymConstant *constant = (CV_SymConstant*)first; - - // itype - str8_list_pushf(arena, out, " itype=%u\n", constant->itype); - - // num - U8 *numeric_ptr = (U8*)(constant + 1); - CV_NumericParsed numeric = cv_numeric_from_data_range(numeric_ptr, first + cap); - str8_list_push(arena, out, str8_lit(" num=")); - cv_stringize_numeric(arena, out, &numeric); - str8_list_push(arena, out, str8_lit("\n")); - - // name - U8 *name_ptr = numeric_ptr + numeric.encoded_size; - String8 name = str8_cstring_capped((char*)(name_ptr), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_UDT: - { - if (sizeof(CV_SymUDT) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymUDT *udt = (CV_SymUDT*)first; - - // itype - str8_list_pushf(arena, out, " itype=%u\n", udt->itype); - - // name - String8 name = str8_cstring_capped((char*)(udt + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - if (sizeof(CV_SymData32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymData32 *data32 = (CV_SymData32*)first; - - // itype, off & sec - str8_list_pushf(arena, out, " itype=%u\n off=%x\n sec=%u\n", - data32->itype, data32->off, data32->sec); - - // name - String8 name = str8_cstring_capped((char*)(data32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_PUB32: - { - if (sizeof(CV_SymPub32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymPub32 *pub32 = (CV_SymPub32*)first; - - // flags - CV_Pub32Flags flags = pub32->flags; - str8_list_push(arena, out, str8_lit(" flags=")); - if (flags == 0){ - str8_list_push(arena, out, str8_lit("0|")); - } - else{ - if (flags&CV_Pub32Flag_Code){ - str8_list_push(arena, out, str8_lit("Code|")); - } - if (flags&CV_Pub32Flag_Function){ - str8_list_push(arena, out, str8_lit("Function|")); - } - if (flags&CV_Pub32Flag_ManagedCode){ - str8_list_push(arena, out, str8_lit("ManagedCode|")); - } - if (flags&CV_Pub32Flag_MSIL){ - str8_list_push(arena, out, str8_lit("MSIL|")); - } - } - str8_list_push(arena, out, str8_lit("\n")); - - // off & sec - str8_list_pushf(arena, out, " off=%x\n sec=%u\n", pub32->off, pub32->sec); - - // name - String8 name = str8_cstring_capped((char*)(pub32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - if (sizeof(CV_SymProc32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymProc32 *proc32 = (CV_SymProc32*)first; - - // proc attributes - str8_list_pushf(arena, out, " parent=%x\n", proc32->parent); - str8_list_pushf(arena, out, " end=%x\n", proc32->end); - str8_list_pushf(arena, out, " next=%x\n", proc32->next); - str8_list_pushf(arena, out, " len=%u\n", proc32->len); - str8_list_pushf(arena, out, " dbg_start=%x\n", proc32->dbg_start); - str8_list_pushf(arena, out, " dbg_end=%x\n", proc32->dbg_end); - str8_list_pushf(arena, out, " itype=%u\n", proc32->itype); - str8_list_pushf(arena, out, " off=%x\n", proc32->off); - str8_list_pushf(arena, out, " sec=%u\n", proc32->sec); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", proc32->flags); - - // name - String8 name = str8_cstring_capped((char*)(proc32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_REGREL32: - { - if (sizeof(CV_SymRegrel32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32*)first; - - // regrel attributes - str8_list_pushf(arena, out, " reg_off=%u\n", regrel32->reg_off); - str8_list_pushf(arena, out, " itype=%u\n", regrel32->itype); - - // reg - String8 reg = cv_string_from_reg(p->arch, regrel32->reg); - str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); - - // name - String8 name = str8_cstring_capped((char*)(regrel32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - if (sizeof(CV_SymThread32) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymThread32 *thread32 = (CV_SymThread32*)first; - - // itype, tls_off, tls_seg - str8_list_pushf(arena, out, " itype=%u\n tls_off=%x\n tls_seg=%u\n", - thread32->itype, thread32->tls_off, thread32->tls_seg); - - // name - String8 name = str8_cstring_capped((char*)(thread32 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_COMPILE2: - { - if (sizeof(CV_SymCompile2) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymCompile2 *compile2 = (CV_SymCompile2*)first; - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", compile2->flags); - - // machine - String8 machine = cv_string_from_arch(compile2->machine); - str8_list_pushf(arena, out, " machine=%.*s\n", - str8_varg(machine)); - - // ver - str8_list_pushf(arena, out, - " ver_fe_major=%u\n ver_fe_minor=%u\n ver_fe_build=%u\n" - " ver_major=%u\n ver_minor=%u\n ver_build=%u\n", - compile2->ver_fe_major, compile2->ver_fe_minor, compile2->ver_fe_build, - compile2->ver_major, compile2->ver_minor, compile2->ver_build); - - // ver_str - String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), first + cap); - str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); - } - }break; - - case CV_SymKind_UNAMESPACE: - { - CV_SymUNamespace *unamespace = (CV_SymUNamespace*)first; - - // name - String8 name = str8_cstring_capped((char*)(unamespace), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - }break; - - case CV_SymKind_PROCREF: - case CV_SymKind_DATAREF: - case CV_SymKind_LPROCREF: - { - if (sizeof(CV_SymRef2) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymRef2 *ref2 = (CV_SymRef2*)first; - - // suc_name, sym_off & imod - str8_list_pushf(arena, out, " suc_name=%u\n sym_off=%x\n imod=%u\n", - ref2->suc_name, ref2->sym_off, ref2->imod); - - // name - String8 name = str8_cstring_capped((char*)(ref2 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_TRAMPOLINE: - { - if (sizeof(CV_SymTrampoline) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymTrampoline *trampoline = (CV_SymTrampoline*)first; - - // kind - // TODO(allen): better kind path - str8_list_pushf(arena, out, " kind=%u\n", trampoline->kind); - - // members - str8_list_pushf(arena, out, " thunk_size=%u\n", trampoline->thunk_size); - str8_list_pushf(arena, out, " thunk_sec_off=%x\n", trampoline->thunk_sec_off); - str8_list_pushf(arena, out, " target_sec_off=%x\n", trampoline->target_sec_off); - str8_list_pushf(arena, out, " thunk_sec=%u\n", trampoline->thunk_sec); - str8_list_pushf(arena, out, " target_sec=%u\n", trampoline->target_sec); - } - }break; - - case CV_SymKind_SECTION: - { - if (sizeof(CV_SymSection) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymSection *section = (CV_SymSection*)first; - - // members - str8_list_pushf(arena, out, " sec_index=%u\n", section->sec_index); - str8_list_pushf(arena, out, " align=%u\n", section->align); - str8_list_pushf(arena, out, " pad=%u\n", section->pad); - str8_list_pushf(arena, out, " rva=%x\n", section->rva); - str8_list_pushf(arena, out, " size=%u\n", section->size); - str8_list_pushf(arena, out, " characteristics=%x\n", section->characteristics); - - // name - String8 name = str8_cstring_capped((char*)(section + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_COFFGROUP: - { - if (sizeof(CV_SymCoffGroup) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymCoffGroup *coff_group = (CV_SymCoffGroup*)first; - - // members - str8_list_pushf(arena, out, " size=%u\n", coff_group->size); - str8_list_pushf(arena, out, " characteristics=%x\n", coff_group->characteristics); - str8_list_pushf(arena, out, " off=%x\n", coff_group->off); - str8_list_pushf(arena, out, " sec=%u\n", coff_group->sec); - - // name - String8 name = str8_cstring_capped((char*)(coff_group + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_CALLSITEINFO: - { - if (sizeof(CV_SymCallSiteInfo) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymCallSiteInfo *callsiteinfo = (CV_SymCallSiteInfo*)first; - - // callsite info attributes - str8_list_pushf(arena, out, " off=%x\n", callsiteinfo->off); - str8_list_pushf(arena, out, " sec=%u\n", callsiteinfo->sec); - str8_list_pushf(arena, out, " pad=%u\n", callsiteinfo->pad); - str8_list_pushf(arena, out, " itype=%u\n", callsiteinfo->itype); - } - }break; - - case CV_SymKind_FRAMECOOKIE: - { - if (sizeof(CV_SymFrameCookie) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymFrameCookie *framecookie = (CV_SymFrameCookie*)first; - - // off - str8_list_pushf(arena, out, " off=%x\n", framecookie->off); - - // reg - String8 reg = cv_string_from_reg(p->arch, framecookie->reg); - str8_list_pushf(arena, out, " reg=%.*s\n", - str8_varg(reg)); - - // kind - // TODO(allen): better kind path - str8_list_pushf(arena, out, " kind=%x\n", framecookie->kind); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", framecookie->flags); - } - }break; - - case CV_SymKind_COMPILE3: - { - if (sizeof(CV_SymCompile3) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymCompile3 *compile3 = (CV_SymCompile3*)first; - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", compile3->flags); - - // machine - String8 machine = cv_string_from_arch(compile3->machine); - str8_list_pushf(arena, out, " machine=%.*s\n", - str8_varg(machine)); - - // ver - str8_list_pushf(arena, out, - " ver_fe_major=%u\n ver_fe_minor=%u\n ver_fe_build=%u\n" - " ver_major=%u\n ver_minor=%u\n ver_build=%u\n" - " ver_qfe=%u\n", - compile3->ver_fe_major, compile3->ver_fe_minor, compile3->ver_fe_build, - compile3->ver_major, compile3->ver_minor, compile3->ver_build); - // ver_str - String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), first + cap); - str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); - } - }break; - - case CV_SymKind_ENVBLOCK: - { - if (sizeof(CV_SymEnvBlock) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymEnvBlock *envblock = (CV_SymEnvBlock*)first; - - // flags - str8_list_pushf(arena, out, " flags=%x\n", envblock->flags); - - // name - str8_list_pushf(arena, out, " rgsz=\n"); - char *name_ptr = (char*)(envblock + 1); - for (;;){ - String8 name = str8_cstring_capped(name_ptr, first + cap); - if (name.size == 0){ - break; - } - str8_list_pushf(arena, out, " '%.*s'\n", str8_varg(name)); - name_ptr += name.size + 1; - } - } - }break; - - case CV_SymKind_LOCAL: - { - if (sizeof(CV_SymLocal) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymLocal *slocal = (CV_SymLocal*)first; - - // itype - str8_list_pushf(arena, out, " itype=%u\n", slocal->itype); - - // flags - str8_list_pushf(arena, out, " flags={\n"); - cv_stringize_local_flags(arena, out, 2, slocal->flags); - str8_list_pushf(arena, out, " }\n"); - - // name - String8 name = str8_cstring_capped((char*)(slocal + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_DEFRANGE_REGISTER: - { - if (sizeof(CV_SymDefrangeRegister) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)first; - - // reg - String8 reg = cv_string_from_reg(p->arch, defrange_register->reg); - str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); - - // range attribs - // TODO(allen): better range attribs - str8_list_pushf(arena, out, " attribs=%x\n", defrange_register->attribs); - - // addr range - str8_list_push(arena, out, str8_lit(" range=")); - cv_stringize_lvar_addr_range(arena, out, &defrange_register->range); - str8_list_push(arena, out, str8_lit("\n")); - - // gaps - cv_stringize_lvar_addr_gap_list(arena, out, defrange_register + 1, first + cap); - } - }break; - - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - if (sizeof(CV_SymDefrangeFramepointerRel) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)first; - - // off - str8_list_pushf(arena, out, " off=%u\n", defrange_fprel->off); - - // addr range - str8_list_push(arena, out, str8_lit(" range=")); - cv_stringize_lvar_addr_range(arena, out, &defrange_fprel->range); - str8_list_push(arena, out, str8_lit("\n")); - - // gaps - cv_stringize_lvar_addr_gap_list(arena, out, defrange_fprel + 1, first + cap); - } - }break; - - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - if (sizeof(CV_SymDefrangeSubfieldRegister) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)first; - - // reg - String8 reg = cv_string_from_reg(p->arch, defrange_subfield_register->reg); - str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); - - // range attribs - // TODO(allen): better range attribs - str8_list_pushf(arena, out, " attribs=%x\n", defrange_subfield_register->attribs); - - // offset - str8_list_pushf(arena, out, " field_offset=%u\n", - defrange_subfield_register->field_offset); - - // addr range - str8_list_push(arena, out, str8_lit(" range=")); - cv_stringize_lvar_addr_range(arena, out, &defrange_subfield_register->range); - str8_list_push(arena, out, str8_lit("\n")); - - // gaps - cv_stringize_lvar_addr_gap_list(arena, out, defrange_subfield_register + 1, first + cap); - } - }break; - - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - if (sizeof(CV_SymDefrangeFramepointerRelFullScope) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = - (CV_SymDefrangeFramepointerRelFullScope*)first; - - // off - str8_list_pushf(arena, out, " off=%u\n", defrange_fprel_full_scope->off); - } - }break; - - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - if (sizeof(CV_SymDefrangeRegisterRel) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)first; - - // reg - String8 reg = cv_string_from_reg(p->arch, defrange_register_rel->reg); - str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); - - // flags - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", defrange_register_rel->flags); - - // reg off - str8_list_pushf(arena, out, " reg_off=%u\n", defrange_register_rel->reg_off); - - // addr range - str8_list_push(arena, out, str8_lit(" range=")); - cv_stringize_lvar_addr_range(arena, out, &defrange_register_rel->range); - str8_list_push(arena, out, str8_lit("\n")); - - // gaps - cv_stringize_lvar_addr_gap_list(arena, out, defrange_register_rel + 1, first + cap); - } - }break; - - case CV_SymKind_BUILDINFO: - { - if (sizeof(CV_SymBuildInfo) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymBuildInfo *buildinfo = (CV_SymBuildInfo*)first; - - // item id - str8_list_pushf(arena, out, " id=%u\n", buildinfo->id); - } - }break; - - case CV_SymKind_INLINESITE: - { - if (sizeof(CV_SymInlineSite) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymInlineSite *inlinesite = (CV_SymInlineSite*)first; - - // members - str8_list_pushf(arena, out, " parent=%x\n", inlinesite->parent); - str8_list_pushf(arena, out, " end=%x\n", inlinesite->end); - str8_list_pushf(arena, out, " inlinee=%u\n", inlinesite->inlinee); - - // binary annotation - // TODO(allen): - } - }break; - - case CV_SymKind_INLINESITE_END: - { - // no contents - }break; - - case CV_SymKind_FILESTATIC: - { - if (sizeof(CV_SymFileStatic) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymFileStatic *file_static = (CV_SymFileStatic*)first; - - // members - str8_list_pushf(arena, out, " itype=%u\n", file_static->itype); - str8_list_pushf(arena, out, " mod_offset=%x\n", file_static->mod_offset); - // TODO(allen): better flags path - str8_list_pushf(arena, out, " flags=%x\n", file_static->flags); - - // name - String8 name = str8_cstring_capped((char*)(file_static + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_SymKind_CALLEES: - case CV_SymKind_CALLERS: - { - if (sizeof(CV_SymFunctionList) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymFunctionList *functions = (CV_SymFunctionList*)first; - - // count - str8_list_pushf(arena, out, " count=%u\n", functions->count); - - // functions - U32 function_count_max = (cap - sizeof(*functions))/sizeof(CV_TypeId); - U32 function_count = ClampTop(functions->count, function_count_max); - if (function_count > 0){ - str8_list_push(arena, out, str8_lit(" functions=\n")); - CV_TypeId *func = (CV_TypeId*)(functions + 1); - CV_TypeId *opl = func + function_count; - for (;func < opl; func += 1){ - str8_list_pushf(arena, out, " %u\n", *func); - } - } - - // invocations - U32 invocation_count_max = (cap - sizeof(*functions) - function_count*sizeof(CV_TypeId))/sizeof(U32); - U32 invocation_count = ClampTop(functions->count, invocation_count_max); - if (invocation_count > 0){ - str8_list_push(arena, out, str8_lit(" invocations=\n")); - U32 *inv = (CV_TypeId*)(functions + 1); - U32 *opl = inv + invocation_count; - for (;inv < opl; inv += 1){ - str8_list_pushf(arena, out, " %u\n", *inv); - } - } - } - }break; - - case CV_SymKind_HEAPALLOCSITE: - { - if (sizeof(CV_SymHeapAllocSite) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymHeapAllocSite *heap_alloc_site = (CV_SymHeapAllocSite*)first; - - // members - str8_list_pushf(arena, out, " off=%x\n", heap_alloc_site->off); - str8_list_pushf(arena, out, " sec=%u\n", heap_alloc_site->sec); - str8_list_pushf(arena, out, " call_inst_len=%u\n", heap_alloc_site->call_inst_len); - str8_list_pushf(arena, out, " itype=%u\n", heap_alloc_site->itype); - } - }break; - - case CV_SymKind_INLINEES: - { - if (sizeof(CV_SymInlinees) > cap){ - str8_list_push(arena, out, str8_lit(" bad symbol range\n")); - } - else{ - CV_SymInlinees *inlinees = (CV_SymInlinees*)first; - - // count - str8_list_pushf(arena, out, " count=%u\n", inlinees->count); - - // desc - U32 desc_count = (cap - sizeof(*inlinees))/sizeof(U32); - if (desc_count > 0){ - str8_list_pushf(arena, out, " desc=\n"); - U32 *desc = (U32*)(inlinees + 1); - U32 *desc_opl = desc + desc_count; - for (;desc < desc_opl; desc += 1){ - str8_list_pushf(arena, out, " %u\n", *desc); - } - } - } - }break; - - case CV_SymKind_REGISTER_16t: - case CV_SymKind_CONSTANT_16t: - case CV_SymKind_UDT_16t: - case CV_SymKind_SSEARCH: - case CV_SymKind_SKIP: - case CV_SymKind_CVRESERVE: - case CV_SymKind_OBJNAME_ST: - case CV_SymKind_ENDARG: - case CV_SymKind_COBOLUDT_16t: - case CV_SymKind_MANYREG_16t: - case CV_SymKind_RETURN: - case CV_SymKind_ENTRYTHIS: - case CV_SymKind_BPREL16: - case CV_SymKind_LDATA16: - case CV_SymKind_GDATA16: - case CV_SymKind_PUB16: - case CV_SymKind_LPROC16: - case CV_SymKind_GPROC16: - case CV_SymKind_THUNK16: - case CV_SymKind_BLOCK16: - case CV_SymKind_WITH16: - case CV_SymKind_LABEL16: - case CV_SymKind_CEXMODEL16: - case CV_SymKind_VFTABLE16: - case CV_SymKind_REGREL16: - case CV_SymKind_BPREL32_16t: - case CV_SymKind_LDATA32_16t: - case CV_SymKind_GDATA32_16t: - case CV_SymKind_PUB32_16t: - case CV_SymKind_LPROC32_16t: - case CV_SymKind_GPROC32_16t: - case CV_SymKind_THUNK32_ST: - case CV_SymKind_BLOCK32_ST: - case CV_SymKind_WITH32_ST: - case CV_SymKind_LABEL32_ST: - case CV_SymKind_CEXMODEL32: - case CV_SymKind_VFTABLE32_16t: - case CV_SymKind_REGREL32_16t: - case CV_SymKind_LTHREAD32_16t: - case CV_SymKind_GTHREAD32_16t: - case CV_SymKind_SLINK32: - case CV_SymKind_LPROCMIPS_16t: - case CV_SymKind_GPROCMIPS_16t: - case CV_SymKind_PROCREF_ST: - case CV_SymKind_DATAREF_ST: - case CV_SymKind_ALIGN: - case CV_SymKind_LPROCREF_ST: - case CV_SymKind_OEM: - case CV_SymKind_TI16_MAX: - case CV_SymKind_CONSTANT_ST: - case CV_SymKind_UDT_ST: - case CV_SymKind_COBOLUDT_ST: - case CV_SymKind_MANYREG_ST: - case CV_SymKind_BPREL32_ST: - case CV_SymKind_LDATA32_ST: - case CV_SymKind_GDATA32_ST: - case CV_SymKind_PUB32_ST: - case CV_SymKind_LPROC32_ST: - case CV_SymKind_GPROC32_ST: - case CV_SymKind_VFTABLE32: - case CV_SymKind_REGREL32_ST: - case CV_SymKind_LTHREAD32_ST: - case CV_SymKind_GTHREAD32_ST: - case CV_SymKind_LPROCMIPS_ST: - case CV_SymKind_GPROCMIPS_ST: - case CV_SymKind_COMPILE2_ST: - case CV_SymKind_MANYREG2_ST: - case CV_SymKind_LPROCIA64_ST: - case CV_SymKind_GPROCIA64_ST: - case CV_SymKind_LOCALSLOT_ST: - case CV_SymKind_PARAMSLOT_ST: - case CV_SymKind_ANNOTATION: - case CV_SymKind_GMANPROC_ST: - case CV_SymKind_LMANPROC_ST: - case CV_SymKind_RESERVED1: - case CV_SymKind_RESERVED2: - case CV_SymKind_RESERVED3: - case CV_SymKind_RESERVED4: - case CV_SymKind_LMANDATA_ST: - case CV_SymKind_GMANDATA_ST: - case CV_SymKind_MANFRAMEREL_ST: - case CV_SymKind_MANREGISTER_ST: - case CV_SymKind_MANSLOT_ST: - case CV_SymKind_MANMANYREG_ST: - case CV_SymKind_MANREGREL_ST: - case CV_SymKind_MANMANYREG2_ST: - case CV_SymKind_MANTYPREF: - case CV_SymKind_UNAMESPACE_ST: - case CV_SymKind_ST_MAX: - case CV_SymKind_WITH32: - case CV_SymKind_REGISTER: - case CV_SymKind_COBOLUDT: - case CV_SymKind_MANYREG: - case CV_SymKind_BPREL32: - case CV_SymKind_LPROCMIPS: - case CV_SymKind_GPROCMIPS: - case CV_SymKind_MANYREG2: - case CV_SymKind_LPROCIA64: - case CV_SymKind_GPROCIA64: - case CV_SymKind_LOCALSLOT: - case CV_SymKind_PARAMSLOT: - case CV_SymKind_LMANDATA: - case CV_SymKind_GMANDATA: - case CV_SymKind_MANFRAMEREL: - case CV_SymKind_MANREGISTER: - case CV_SymKind_MANSLOT: - case CV_SymKind_MANMANYREG: - case CV_SymKind_MANREGREL: - case CV_SymKind_MANMANYREG2: - case CV_SymKind_ANNOTATIONREF: - case CV_SymKind_TOKENREF: - case CV_SymKind_GMANPROC: - case CV_SymKind_LMANPROC: - case CV_SymKind_MANCONSTANT: - case CV_SymKind_ATTR_FRAMEREL: - case CV_SymKind_ATTR_REGISTER: - case CV_SymKind_ATTR_REGREL: - case CV_SymKind_ATTR_MANYREG: - case CV_SymKind_SEPCODE: - case CV_SymKind_DEFRANGE_2005: - case CV_SymKind_DEFRANGE2_2005: - case CV_SymKind_EXPORT: - case CV_SymKind_DISCARDED: - case CV_SymKind_DEFRANGE: - case CV_SymKind_DEFRANGE_SUBFIELD: - case CV_SymKind_LPROC32_ID: - case CV_SymKind_GPROC32_ID: - case CV_SymKind_LPROCMIPS_ID: - case CV_SymKind_GPROCMIPS_ID: - case CV_SymKind_LPROCIA64_ID: - case CV_SymKind_GPROCIA64_ID: - case CV_SymKind_PROC_ID_END: - case CV_SymKind_DEFRANGE_HLSL: - case CV_SymKind_GDATA_HLSL: - case CV_SymKind_LDATA_HLSL: - case CV_SymKind_LPROC32_DPC: - case CV_SymKind_LPROC32_DPC_ID: - case CV_SymKind_DEFRANGE_DPC_PTR_TAG: - case CV_SymKind_DPC_SYM_TAG_MAP: - case CV_SymKind_ARMSWITCHTABLE: - case CV_SymKind_POGODATA: - case CV_SymKind_INLINESITE2: - case CV_SymKind_MOD_TYPEREF: - case CV_SymKind_REF_MINIPDB: - case CV_SymKind_PDBMAP: - case CV_SymKind_GDATA_HLSL32: - case CV_SymKind_LDATA_HLSL32: - case CV_SymKind_GDATA_HLSL32_EX: - case CV_SymKind_LDATA_HLSL32_EX: - case CV_SymKind_FASTLINK: - { - str8_list_push(arena, out, str8_lit(" no stringizer path\n")); - }break; - } - } -} - -internal void -cv_stringize_sym_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, String8 data, - CV_StringizeSymParams *p){ - CV_RecRange *ptr = ranges->ranges; - CV_RecRange *opl = ranges->ranges + ranges->count; - for (;ptr < opl; ptr += 1){ - cv_stringize_sym_range(arena, out, ptr, data, p); - str8_list_push(arena, out, str8_lit("\n")); - } -} - -//////////////////////////////// -//~ CodeView Leaf Stringize Functions - -internal void -cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf){ - CV_StringizeLeafParams params = {0}; - - cv_stringize_leaf_array(arena, out, &leaf->leaf_ranges, leaf->itype_first, - leaf->data, ¶ms); -} - -internal void -cv_stringize_leaf_range(Arena *arena, String8List *out, - CV_RecRange *range, CV_TypeId itype, String8 data, - CV_StringizeLeafParams *p){ - U64 opl_off = range->off + range->hdr.size; - if (opl_off > data.size){ - str8_list_push(arena, out, str8_lit("bad leaf range\n")); - } - - if (opl_off <= data.size){ - // [off] (itype): kind - { - String8 kind_str = cv_string_from_leaf_kind(range->hdr.kind); - str8_list_pushf(arena, out, "[%06x] (%u): %.*s\n", - range->off + 2, itype, str8_varg(kind_str)); - } - - // details - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - - switch (range->hdr.kind){ - case CV_LeafKind_VTSHAPE: - { - if (sizeof(CV_LeafVTShape) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafVTShape *vtshape = (CV_LeafVTShape*)first; - - str8_list_pushf(arena, out, " count=%u\n", vtshape->count); - - str8_list_push(arena, out, str8_lit(" shapes=\n")); - U8 *shapes = (U8*)(vtshape + 1); - U32 max_count = (cap - sizeof(*vtshape))*2; - U32 clamped_count = ClampTop(vtshape->count, max_count); - for (U32 i = 0; i < clamped_count; i += 1){ - U32 j = (i >> 1); - U8 s = shapes[j]; - if (j & 1){ - s >>= 4; - } - CV_VirtualTableShape shape = (s & 0xF); - // TODO(allen): better shape path - str8_list_pushf(arena, out, " %u\n", shape); - } - } - }break; - - case CV_LeafKind_LABEL: - { - if (sizeof(CV_LeafLabel) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafLabel *label = (CV_LeafLabel*)first; - - // TODO(allen): better LabelKind path - str8_list_pushf(arena, out, " kind=%x\n", label->kind); - } - }break; - - case CV_LeafKind_MODIFIER: - { - if (sizeof(CV_LeafModifier) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafModifier *modifier = (CV_LeafModifier*)first; - - str8_list_pushf(arena, out, " itype=%u\n", modifier->itype); - str8_list_pushf(arena, out, " flags={\n"); - cv_stringize_modifier_flags(arena, out, 2, modifier->flags); - str8_list_pushf(arena, out, " }\n"); - } - }break; - - case CV_LeafKind_POINTER: - { - if (sizeof(CV_LeafPointer) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafPointer *pointer = (CV_LeafPointer*)first; - - str8_list_pushf(arena, out, " itype=%u\n", pointer->itype); - str8_list_pushf(arena, out, " attribs={\n"); - cv_stringize_pointer_attribs(arena, out, 2, pointer->attribs); - str8_list_pushf(arena, out, " }\n"); - } - }break; - - case CV_LeafKind_PROCEDURE: - { - if (sizeof(CV_LeafProcedure) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafProcedure *procedure = (CV_LeafProcedure*)first; - - str8_list_pushf(arena, out, " ret_itype=%u\n", procedure->ret_itype); - // TODO(allen): better CallKind path - str8_list_pushf(arena, out, " call_kind=%u\n", procedure->call_kind); - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", procedure->attribs); - str8_list_pushf(arena, out, " arg_count=%u\n", procedure->arg_count); - str8_list_pushf(arena, out, " arg_itype=%u\n", procedure->arg_itype); - } - }break; - - case CV_LeafKind_MFUNCTION: - { - if (sizeof(CV_LeafMFunction) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafMFunction *mfunction = (CV_LeafMFunction*)first; - - str8_list_pushf(arena, out, " ret_itype=%u\n", mfunction->ret_itype); - str8_list_pushf(arena, out, " class_itype=%u\n", mfunction->class_itype); - str8_list_pushf(arena, out, " this_itype=%u\n", mfunction->this_itype); - // TODO(allen): better CallKind path - str8_list_pushf(arena, out, " call_kind=%u\n", mfunction->call_kind); - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", mfunction->attribs); - str8_list_pushf(arena, out, " arg_count=%u\n", mfunction->arg_count); - str8_list_pushf(arena, out, " arg_itype=%u\n", mfunction->arg_itype); - str8_list_pushf(arena, out, " this_adjust=%d\n", mfunction->this_adjust); - } - }break; - - case CV_LeafKind_ARGLIST: - { - if (sizeof(CV_LeafArgList) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafArgList *arg_list = (CV_LeafArgList*)first; - - str8_list_pushf(arena, out, " count=%u\n", arg_list->count); - str8_list_push(arena, out, str8_lit(" itypes=\n")); - - CV_TypeId *itypes = (CV_TypeId*)(arg_list + 1); - U32 max_count = (cap - sizeof(*arg_list))/sizeof(U32); - U32 clamped_count = ClampTop(arg_list->count, max_count); - for (U32 i = 0; i < clamped_count; i += 1){ - str8_list_pushf(arena, out, " %u\n", itypes[i]); - } - } - }break; - - case CV_LeafKind_FIELDLIST: - { - U64 cursor = 0; - for (;cursor + sizeof(CV_LeafKind) <= cap;){ - CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); - String8 field_kind_str = cv_string_from_leaf_kind(field_kind); - - str8_list_pushf(arena, out, " field kind: %.*s\n", - str8_varg(field_kind_str)); - - U64 list_item_off = cursor + 2; - - // if we hit an error or forget to set next cursor for a case - // default to exiting the loop - U64 list_item_opl_off = cap; - - switch (field_kind){ - default: - { - str8_list_push(arena, out, str8_lit(" unexpected field kind\n")); - }break; - - case CV_LeafKind_MEMBER: - { - if (list_item_off + sizeof(CV_LeafMember) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafMember *member = (CV_LeafMember*)(first + list_item_off); - - U64 num_off = list_item_off + sizeof(*member); - CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); - - U64 name_off = num_off + num.encoded_size; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", member->attribs); - str8_list_pushf(arena, out, " itype=%u\n", member->itype); - str8_list_push(arena, out, str8_lit(" offset=")); - cv_stringize_numeric(arena, out, &num); - str8_list_push(arena, out, str8_lit("\n")); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_STMEMBER: - { - if (list_item_off + sizeof(CV_LeafStMember) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafStMember *stmember = (CV_LeafStMember*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*stmember); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", stmember->attribs); - str8_list_pushf(arena, out, " itype=%u\n", stmember->itype); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_METHOD: - { - if (list_item_off + sizeof(CV_LeafMethod) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafMethod *method = (CV_LeafMethod*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*method); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - str8_list_pushf(arena, out, " count=%u\n", method->count); - str8_list_pushf(arena, out, " list_itype=%u\n", method->list_itype); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_ONEMETHOD: - { - if (list_item_off + sizeof(CV_LeafOneMethod) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafOneMethod *one_method = (CV_LeafOneMethod*)(first + list_item_off); - - U64 vbaseoff_off = list_item_off + sizeof(*one_method); - U64 vbaseoff_opl_off = vbaseoff_off; - U32 vbaseoff = 0; - { - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); - if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ - vbaseoff = *(U32*)(first + vbaseoff_off); - vbaseoff_opl_off += sizeof(vbaseoff); - } - } - - U64 name_off = vbaseoff_opl_off; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", one_method->attribs); - str8_list_pushf(arena, out, " itype=%u\n", one_method->itype); - str8_list_pushf(arena, out, " vbaseoff=%u\n", vbaseoff); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_ENUMERATE: - { - if (list_item_off + sizeof(CV_LeafEnumerate) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafEnumerate *enumerate = (CV_LeafEnumerate*)(first + list_item_off); - - U64 num_off = list_item_off + sizeof(*enumerate); - CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); - - U64 name_off = num_off + num.encoded_size; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - // TODO(allen): better flags path - str8_list_pushf(arena, out, " attribs=%x\n", enumerate->attribs); - str8_list_push(arena, out, str8_lit(" val=")); - cv_stringize_numeric(arena, out, &num); - str8_list_push(arena, out, str8_lit("\n")); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_NESTTYPE: - { - if (list_item_off + sizeof(CV_LeafNestType) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafNestType *nest_type = (CV_LeafNestType*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*nest_type); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - str8_list_pushf(arena, out, " itype=%u\n", nest_type->itype); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_NESTTYPEEX: - { - if (list_item_off + sizeof(CV_LeafNestTypeEx) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafNestTypeEx *nest_type = (CV_LeafNestTypeEx*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*nest_type); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // print data - // TODO(allen): better flags printing - str8_list_pushf(arena, out, " attribs=%x\n", nest_type->attribs); - str8_list_pushf(arena, out, " itype=%u\n", nest_type->itype); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_BCLASS: - { - if (list_item_off + sizeof(CV_LeafBClass) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafBClass *bclass = (CV_LeafBClass*)(first + list_item_off); - - U64 num_off = list_item_off + sizeof(*bclass); - CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); - - list_item_opl_off = num_off + num.encoded_size; - - // print data - // TODO(allen): better flags printing - str8_list_pushf(arena, out, " attribs=%x\n", bclass->attribs); - str8_list_pushf(arena, out, " itype=%u\n", bclass->itype); - str8_list_push(arena, out, str8_lit(" offset=")); - cv_stringize_numeric(arena, out, &num); - str8_list_push(arena, out, str8_lit("\n")); - } - }break; - - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - { - if (list_item_off + sizeof(CV_LeafVBClass) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafVBClass *vbclass = (CV_LeafVBClass*)(first + list_item_off); - - U64 num1_off = list_item_off + sizeof(*vbclass); - CV_NumericParsed num1 = cv_numeric_from_data_range(first + num1_off, first + cap); - - U64 num2_off = num1_off + num1.encoded_size; - CV_NumericParsed num2 = cv_numeric_from_data_range(first + num2_off, first + cap); - - list_item_opl_off = num2_off + num2.encoded_size; - - // print data - // TODO(allen): better flags printing - str8_list_pushf(arena, out, " attribs=%x\n", vbclass->attribs); - str8_list_pushf(arena, out, " itype=%u\n", vbclass->itype); - str8_list_pushf(arena, out, " vbptr_itype=%u\n", vbclass->vbptr_itype); - str8_list_push(arena, out, str8_lit(" vbptr_off=")); - cv_stringize_numeric(arena, out, &num1); - str8_list_push(arena, out, str8_lit("\n")); - str8_list_push(arena, out, str8_lit(" vtable_off=")); - cv_stringize_numeric(arena, out, &num2); - str8_list_push(arena, out, str8_lit("\n")); - } - }break; - - case CV_LeafKind_INDEX: - { - if (list_item_off + sizeof(CV_LeafIndex) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); - - list_item_opl_off = list_item_off + sizeof(*index); - - // print data - str8_list_pushf(arena, out, " itype=%u\n", index->itype); - } - }break; - - case CV_LeafKind_VFUNCTAB: - { - if (list_item_off + sizeof(CV_LeafVFuncTab) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafVFuncTab *vfunctab = (CV_LeafVFuncTab*)(first + list_item_off); - - list_item_opl_off = list_item_off + sizeof(*vfunctab); - - // print data - str8_list_pushf(arena, out, " itype=%u\n", vfunctab->itype); - } - }break; - - case CV_LeafKind_VFUNCOFF: - { - if (list_item_off + sizeof(CV_LeafVFuncOff) > cap){ - str8_list_push(arena, out, str8_lit(" bad field list range\n")); - } - else{ - // compute whole layout - CV_LeafVFuncOff *vfuncoff = (CV_LeafVFuncOff*)(first + list_item_off); - - list_item_opl_off = list_item_off + sizeof(*vfuncoff); - - // print data - str8_list_pushf(arena, out, " itype=%u\n", vfuncoff->itype); - str8_list_pushf(arena, out, " off=%u\n", vfuncoff->off); - } - }break; - } - - // update cursor - U64 next_cursor = AlignPow2(list_item_opl_off, 4); - cursor = next_cursor; - } - }break; - - case CV_LeafKind_BITFIELD: - { - if (sizeof(CV_LeafBitField) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafBitField *bit_field = (CV_LeafBitField*)first; - - str8_list_pushf(arena, out, " itype=%u\n", bit_field->itype); - str8_list_pushf(arena, out, " len=%u\n", bit_field->len); - str8_list_pushf(arena, out, " pos=%u\n", bit_field->pos); - } - }break; - - case CV_LeafKind_METHODLIST: - { - U64 cursor = 0; - for (;cursor + sizeof(CV_LeafMethodListMember) <= cap;){ - CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)(first + cursor); - - // extract vbaseoff - U64 next_cursor = cursor + sizeof(*method); - U32 vbaseoff = 0; - { - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs); - if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ - if (cursor + sizeof(*method) + 4 <= cap){ - vbaseoff = *(U32*)(method + 1); - } - next_cursor += 4; - } - } - - // print - // TODO(allen): better flags path - str8_list_pushf(arena, out, " method\n", method->attribs); - str8_list_pushf(arena, out, " attribs=%x\n", method->attribs); - str8_list_pushf(arena, out, " itype=%u\n", method->itype); - str8_list_pushf(arena, out, " vbaseoff=%u\n", vbaseoff); - - // update cursor - cursor = next_cursor; - } - }break; - - case CV_LeafKind_ARRAY: - { - if (sizeof(CV_LeafArray) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafArray *array = (CV_LeafArray*)first; - - str8_list_pushf(arena, out, " entry_itype=%u\n", array->entry_itype); - str8_list_pushf(arena, out, " index_itype=%u\n", array->index_itype); - - // count - U8 *numeric_ptr = (U8*)(array + 1); - CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, first + cap); - str8_list_pushf(arena, out, " count="); - cv_stringize_numeric(arena, out, &array_count); - str8_list_push(arena, out, str8_lit("\n")); - } - }break; - - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - if (sizeof(CV_LeafStruct) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; - - str8_list_pushf(arena, out, " count=%u\n", lf_struct->count); - str8_list_pushf(arena, out, " props=%x (\n", lf_struct->props); - cv_stringize_type_props(arena, out, 2, lf_struct->props); - str8_list_pushf(arena, out, " )\n"); - str8_list_pushf(arena, out, " field_itype=%u\n", lf_struct->field_itype); - str8_list_pushf(arena, out, " derived_itype=%u\n", lf_struct->derived_itype); - str8_list_pushf(arena, out, " vshape_itype=%u\n", lf_struct->vshape_itype); - - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - str8_list_pushf(arena, out, " size="); - cv_stringize_numeric(arena, out, &size); - str8_list_push(arena, out, str8_lit("\n")); - - String8 name = str8_cstring_capped((U8*)(numeric_ptr + size.encoded_size), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - - String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); - str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); - } - }break; - - case CV_LeafKind_UNION: - { - if (sizeof(CV_LeafUnion) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafUnion *lf_union = (CV_LeafUnion*)first; - - str8_list_pushf(arena, out, " count=%u\n", lf_union->count); - str8_list_pushf(arena, out, " props=%x (\n", lf_union->props); - cv_stringize_type_props(arena, out, 2, lf_union->props); - str8_list_pushf(arena, out, " )\n"); - str8_list_pushf(arena, out, " field_itype=%u\n", lf_union->field_itype); - - U8 *numeric_ptr = (U8*)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - str8_list_pushf(arena, out, " size="); - cv_stringize_numeric(arena, out, &size); - str8_list_push(arena, out, str8_lit("\n")); - - String8 name = str8_cstring_capped((U8*)(numeric_ptr + size.encoded_size), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - - String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); - str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); - } - }break; - - case CV_LeafKind_ENUM: - { - if (sizeof(CV_LeafEnum) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; - - str8_list_pushf(arena, out, " count=%u\n", lf_enum->count); - str8_list_pushf(arena, out, " props=%x (\n", lf_enum->props); - cv_stringize_type_props(arena, out, 2, lf_enum->props); - str8_list_pushf(arena, out, " )\n"); - str8_list_pushf(arena, out, " base_itype=%u\n", lf_enum->base_itype); - str8_list_pushf(arena, out, " field_itype=%u\n", lf_enum->field_itype); - - String8 name = str8_cstring_capped((U8*)(lf_enum + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - - String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); - str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); - } - }break; - - case CV_LeafKind_VFTABLE: - { - if (sizeof(CV_LeafVFTable) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafVFTable *vftable = (CV_LeafVFTable*)first; - - str8_list_pushf(arena, out, " owner_itype=%u\n", vftable->owner_itype); - str8_list_pushf(arena, out, " base_table_itype=%u\n", vftable->base_table_itype); - str8_list_pushf(arena, out, " offset_in_object_layout=%u\n", - vftable->offset_in_object_layout); - str8_list_pushf(arena, out, " names_len=%u\n", vftable->names_len); - - U64 names_cap = Min(sizeof(*vftable) + vftable->names_len, cap); - - str8_list_push(arena, out, str8_lit(" names=\n")); - U8 *ptr = (U8*)(vftable + 1); - U8 *opl = first + names_cap; - for (;ptr < opl;){ - String8 name = str8_cstring_capped(ptr, opl); - str8_list_pushf(arena, out, " '%.*s'\n", str8_varg(name)); - ptr += name.size + 1; - } - } - }break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - if (sizeof(CV_LeafStruct2) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafStruct2 *struct2 = (CV_LeafStruct2*)first; - - str8_list_pushf(arena, out, " props=%x (\n", struct2->props); - cv_stringize_type_props(arena, out, 2, struct2->props); - str8_list_pushf(arena, out, " )\n"); - str8_list_pushf(arena, out, " unknown1=%u\n", struct2->unknown1); - str8_list_pushf(arena, out, " field_itype=%u\n", struct2->field_itype); - str8_list_pushf(arena, out, " derived_itype=%u\n", struct2->derived_itype); - str8_list_pushf(arena, out, " vshape_itype=%u\n", struct2->vshape_itype); - str8_list_pushf(arena, out, " unknown2=0x%x\n", struct2->unknown2); - //str8_list_pushf(arena, out, " size=%u\n", struct2->size); - - String8 name = str8_cstring_capped((U8*)(struct2 + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - - String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); - str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); - } - }break; - - case CV_LeafKind_FUNC_ID: - { - if (sizeof(CV_LeafFuncId) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafFuncId *func_id = (CV_LeafFuncId*)first; - - str8_list_pushf(arena, out, " scope_string_id=%u\n", func_id->scope_string_id); - str8_list_pushf(arena, out, " itype=%u\n", func_id->itype); - - String8 name = str8_cstring_capped((U8*)(func_id + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_MFUNC_ID: - { - if (sizeof(CV_LeafMFuncId) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)first; - - str8_list_pushf(arena, out, " owner_itype=%u\n", mfunc_id->owner_itype); - str8_list_pushf(arena, out, " itype=%u\n", mfunc_id->itype); - - String8 name = str8_cstring_capped((U8*)(mfunc_id + 1), first + cap); - str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); - } - }break; - - case CV_LeafKind_BUILDINFO: - { - if (sizeof(CV_LeafBuildInfo) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo*)first; - - str8_list_pushf(arena, out, " count=%u\n", build_info->count); - - CV_ItemId *item_ids = (CV_ItemId*)(build_info + 1); - str8_list_pushf(arena, out, " items=\n"); - U32 max_count = (cap - sizeof(*build_info))/sizeof(CV_ItemId); - U32 clamped_count = ClampTop(build_info->count, max_count); - for (U32 i = 0; i < clamped_count; i += 1){ - CV_ItemId item_id = item_ids[i]; - str8_list_pushf(arena, out, " %u\n", item_id); - } - } - }break; - - case CV_LeafKind_SUBSTR_LIST: - { - if (sizeof(CV_LeafSubstrList) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafSubstrList *substr_list = (CV_LeafSubstrList*)first; - - str8_list_pushf(arena, out, " count=%u\n", substr_list->count); - - str8_list_pushf(arena, out, " items=\n"); - U32 max_count = (cap - sizeof(CV_LeafSubstrList))/sizeof(CV_ItemId); - CV_ItemId *item_ids = (CV_ItemId*)(substr_list + 1); - U32 clamped_count = ClampTop(substr_list->count, max_count); - for (U32 i = 0; i < clamped_count; i += 1){ - CV_ItemId item_id = item_ids[i]; - str8_list_pushf(arena, out, " %u\n", item_id); - } - } - }break; - - case CV_LeafKind_STRING_ID: - { - if (sizeof(CV_LeafStringId) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafStringId *string_id = (CV_LeafStringId*)first; - - str8_list_pushf(arena, out, " substr_list_id=%u\n", string_id->substr_list_id); - - String8 string = str8_cstring_capped((U8*)(string_id + 1), first + cap); - str8_list_pushf(arena, out, " string='%.*s'\n", str8_varg(string)); - } - }break; - - case CV_LeafKind_UDT_SRC_LINE: - { - if (sizeof(CV_LeafUDTSrcLine) > cap){ - str8_list_push(arena, out, str8_lit(" bad leaf range\n")); - } - else{ - CV_LeafUDTSrcLine *udt_src_line = (CV_LeafUDTSrcLine*)first; - - str8_list_pushf(arena, out, " udt_itype=%u\n", udt_src_line->udt_itype); - str8_list_pushf(arena, out, " src_string_id=%u\n", udt_src_line->src_string_id); - str8_list_pushf(arena, out, " line=%u\n", udt_src_line->line); - } - }break; - - - default: - - // Leaf Kinds - case CV_LeafKind_MODIFIER_16t: - case CV_LeafKind_POINTER_16t: - case CV_LeafKind_ARRAY_16t: - case CV_LeafKind_CLASS_16t: - case CV_LeafKind_STRUCTURE_16t: - case CV_LeafKind_UNION_16t: - case CV_LeafKind_ENUM_16t: - case CV_LeafKind_PROCEDURE_16t: - case CV_LeafKind_MFUNCTION_16t: - //case CV_LeafKind_VTSHAPE: - case CV_LeafKind_COBOL0_16t: - case CV_LeafKind_COBOL1: - case CV_LeafKind_BARRAY_16t: - //case CV_LeafKind_LABEL: - case CV_LeafKind_NULL: - case CV_LeafKind_NOTTRAN: - case CV_LeafKind_DIMARRAY_16t: - case CV_LeafKind_VFTPATH_16t: - case CV_LeafKind_PRECOMP_16t: - case CV_LeafKind_ENDPRECOMP: - case CV_LeafKind_OEM_16t: - case CV_LeafKind_TYPESERVER_ST: - case CV_LeafKind_SKIP_16t: - case CV_LeafKind_ARGLIST_16t: - case CV_LeafKind_DEFARG_16t: - case CV_LeafKind_LIST: - case CV_LeafKind_FIELDLIST_16t: - case CV_LeafKind_DERIVED_16t: - case CV_LeafKind_BITFIELD_16t: - case CV_LeafKind_METHODLIST_16t: - case CV_LeafKind_DIMCONU_16t: - case CV_LeafKind_DIMCONLU_16t: - case CV_LeafKind_DIMVARU_16t: - case CV_LeafKind_DIMVARLU_16t: - case CV_LeafKind_REFSYM: - case CV_LeafKind_BCLASS_16t: - case CV_LeafKind_VBCLASS_16t: - case CV_LeafKind_IVBCLASS_16t: - case CV_LeafKind_ENUMERATE_ST: - case CV_LeafKind_FRIENDFCN_16t: - case CV_LeafKind_INDEX_16t: - case CV_LeafKind_MEMBER_16t: - case CV_LeafKind_STMEMBER_16t: - case CV_LeafKind_METHOD_16t: - case CV_LeafKind_NESTTYPE_16t: - case CV_LeafKind_VFUNCTAB_16t: - case CV_LeafKind_FRIENDCLS_16t: - case CV_LeafKind_ONEMETHOD_16t: - case CV_LeafKind_VFUNCOFF_16t: - case CV_LeafKind_TI16_MAX: - //case CV_LeafKind_MODIFIER: - //case CV_LeafKind_POINTER: - case CV_LeafKind_ARRAY_ST: - case CV_LeafKind_CLASS_ST: - case CV_LeafKind_STRUCTURE_ST: - case CV_LeafKind_UNION_ST: - case CV_LeafKind_ENUM_ST: - //case CV_LeafKind_PROCEDURE: - //case CV_LeafKind_MFUNCTION: - case CV_LeafKind_COBOL0: - case CV_LeafKind_BARRAY: - case CV_LeafKind_DIMARRAY_ST: - case CV_LeafKind_VFTPATH: - case CV_LeafKind_PRECOMP_ST: - case CV_LeafKind_OEM: - case CV_LeafKind_ALIAS_ST: - case CV_LeafKind_OEM2: - case CV_LeafKind_SKIP: - //case CV_LeafKind_ARGLIST: - case CV_LeafKind_DEFARG_ST: - //case CV_LeafKind_FIELDLIST: - case CV_LeafKind_DERIVED: - //case CV_LeafKind_BITFIELD: - //case CV_LeafKind_METHODLIST: - case CV_LeafKind_DIMCONU: - case CV_LeafKind_DIMCONLU: - case CV_LeafKind_DIMVARU: - case CV_LeafKind_DIMVARLU: - case CV_LeafKind_BCLASS: - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - case CV_LeafKind_FRIENDFCN_ST: - //case CV_LeafKind_INDEX: - case CV_LeafKind_MEMBER_ST: - case CV_LeafKind_STMEMBER_ST: - case CV_LeafKind_METHOD_ST: - case CV_LeafKind_NESTTYPE_ST: - case CV_LeafKind_VFUNCTAB: - case CV_LeafKind_FRIENDCLS: - case CV_LeafKind_ONEMETHOD_ST: - case CV_LeafKind_VFUNCOFF: - case CV_LeafKind_NESTTYPEEX_ST: - case CV_LeafKind_MEMBERMODIFY_ST: - case CV_LeafKind_MANAGED_ST: - case CV_LeafKind_ST_MAX: - case CV_LeafKind_TYPESERVER: - case CV_LeafKind_ENUMERATE: - //case CV_LeafKind_ARRAY: - //case CV_LeafKind_CLASS: - //case CV_LeafKind_STRUCTURE: - //case CV_LeafKind_UNION: - //case CV_LeafKind_ENUM: - case CV_LeafKind_DIMARRAY: - case CV_LeafKind_PRECOMP: - case CV_LeafKind_ALIAS: - case CV_LeafKind_DEFARG: - case CV_LeafKind_FRIENDFCN: - case CV_LeafKind_MEMBER: - case CV_LeafKind_STMEMBER: - case CV_LeafKind_METHOD: - case CV_LeafKind_NESTTYPE: - case CV_LeafKind_ONEMETHOD: - case CV_LeafKind_NESTTYPEEX: - case CV_LeafKind_MEMBERMODIFY: - case CV_LeafKind_MANAGED: - case CV_LeafKind_TYPESERVER2: - case CV_LeafKind_STRIDED_ARRAY: - case CV_LeafKind_HLSL: - case CV_LeafKind_MODIFIER_EX: - case CV_LeafKind_INTERFACE: - case CV_LeafKind_BINTERFACE: - case CV_LeafKind_VECTOR: - case CV_LeafKind_MATRIX: - //case CV_LeafKind_VFTABLE: - - // Leaf ID Kinds - //case CV_LeafIDKind_FUNC_ID: - //case CV_LeafIDKind_MFUNC_ID: - //case CV_LeafIDKind_BUILDINFO: - //case CV_LeafIDKind_SUBSTR_LIST: - //case CV_LeafIDKind_STRING_ID: - //case CV_LeafIDKind_UDT_SRC_LINE: - case CV_LeafKind_UDT_MOD_SRC_LINE: - - { - str8_list_push(arena, out, str8_lit(" no stringizer path\n")); - }break; - } - } -} - -internal void -cv_stringize_leaf_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, CV_TypeId itype_first, String8 data, - CV_StringizeLeafParams *p){ - CV_RecRange *ptr = ranges->ranges; - CV_RecRange *opl = ranges->ranges + ranges->count; - CV_TypeId itype = itype_first; - for (;ptr < opl; ptr += 1, itype += 1){ - cv_stringize_leaf_range(arena, out, ptr, itype, data, p); - str8_list_push(arena, out, str8_lit("\n")); - } -} - -//////////////////////////////// -//~ CodeView C13 Stringize Functions - -internal void -cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13){ - for(CV_C13SubSectionNode *node = c13->first_sub_section; - node != 0; - node = node->next) - { - String8 kind_str = cv_string_from_c13_sub_section_kind(node->kind); - str8_list_pushf(arena, out, "C13 Sub Section [%llx] (%.*s):\n", - node->off, str8_varg(kind_str)); - - switch(node->kind) - { - case CV_C13SubSectionKind_Lines: - { - if (node->lines_first == 0) - { - str8_list_push(arena, out, str8_lit(" failed to extract info\n")); - } - else for(CV_C13LinesParsedNode *n = node->lines_first; n != 0; n = n->next) - { - CV_C13LinesParsed *lines = &n->v; - - str8_list_pushf(arena, out, " section: %u\n", lines->sec_idx); - str8_list_pushf(arena, out, " file off: %u\n", lines->file_off); - str8_list_pushf(arena, out, " file name: %.*s\n", str8_varg(lines->file_name)); - str8_list_pushf(arena, out, " line count: %u\n", lines->line_count); - - U64 base_off = lines->secrel_base_off; - U64 *line_offs = lines->voffs; - U32 *line_nums = lines->line_nums; - - U32 line_count = lines->line_count; - for (U32 i = 0; i < line_count; i += 1){ - str8_list_pushf(arena, out, " {secrel_off=%llx, line_num=%u}\n", - line_offs[i], line_nums[i]); - } - - str8_list_pushf(arena, out, " {secrel_off=%x, ender}\n", line_offs[line_count]); - } - }break; - - case CV_C13SubSectionKind_FileChksms: - { - str8_list_push(arena, out, str8_lit(" no stringizer path\n")); - }break; - - case CV_C13SubSectionKind_InlineeLines: - { - str8_list_push(arena, out, str8_lit(" no stringizer path\n")); - }break; - - default: - { - str8_list_push(arena, out, str8_lit(" no stringizer path\n")); - }break; - } - - str8_list_push(arena, out, str8_lit("\n")); - } -} - -internal String8 -cv_string_from_inline_range_kind(CV_InlineRangeKind kind) -{ - String8 result = str8_zero(); - switch (kind) { - case CV_InlineRangeKind_Expr: result = str8_lit("Expr"); break; - case CV_InlineRangeKind_Stmt: result = str8_lit("Stmt"); break; - } - return result; -} - diff --git a/src/codeview/codeview_stringize.h b/src/codeview/codeview_stringize.h deleted file mode 100644 index 0184d92a..00000000 --- a/src/codeview/codeview_stringize.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef CODEVIEW_STRINGIZE_H -#define CODEVIEW_STRINGIZE_H - -//////////////////////////////// -//~ CodeView Stringize Helper Types - -typedef struct CV_StringizeSymParams{ - CV_Arch arch; -} CV_StringizeSymParams; - -typedef struct CV_StringizeLeafParams{ - U32 dummy; -} CV_StringizeLeafParams; - -//////////////////////////////// -//~ CodeView Common Stringize Functions - -internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num); - -internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out, - CV_LvarAddrRange *range); -internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap); -internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, - void *first, void *opl); - -internal String8 cv_string_from_basic_type(CV_BasicType basic_type); -internal String8 cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind); -internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg); -internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind); -internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode); -internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind); -internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind); - -//////////////////////////////// -//~ CodeView Flags Stringize Functions - -internal void cv_stringize_modifier_flags(Arena *arena, String8List *out, - U32 indent, CV_ModifierFlags flags); - -internal void cv_stringize_type_props(Arena *arena, String8List *out, - U32 indent, CV_TypeProps props); - -internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out, - U32 indent, CV_PointerAttribs attribs); - -internal void cv_stringize_local_flags(Arena *arena, String8List *out, - U32 indent, CV_LocalFlags flags); - -//////////////////////////////// -//~ CodeView Sym Stringize Functions - -internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym); - -internal void cv_stringize_sym_range(Arena *arena, String8List *out, - CV_RecRange *range, String8 data, - CV_StringizeSymParams *p); -internal void cv_stringize_sym_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, String8 data, - CV_StringizeSymParams *p); - -//////////////////////////////// -//~ CodeView Leaf Stringize Functions - -internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf); - -internal void cv_stringize_leaf_range(Arena *arena, String8List *out, - CV_RecRange *range, CV_TypeId itype, String8 data, - CV_StringizeLeafParams *p); -internal void cv_stringize_leaf_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, CV_TypeId itype_first, - String8 data, - CV_StringizeLeafParams *p); - -//////////////////////////////// -//~ CodeView C13 Stringize Functions - -internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13); - -internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind); - -#endif // CODEVIEW_STRINGIZE_H diff --git a/src/coff/coff.c b/src/coff/coff.c index 12108b38..0e29f25b 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -1322,452 +1322,17 @@ coff_archive_parse_from_data(String8 data) return null_parse; } -//////////////////////////////// - -read_only struct -{ - String8 string; - COFF_MachineType machine; -} g_coff_machine_map[] = { - { str8_lit_comp(""), COFF_MachineType_UNKNOWN }, - { str8_lit_comp("X86"), COFF_MachineType_X86 }, - { str8_lit_comp("AMD64"), COFF_MachineType_X64 }, - { str8_lit_comp("X64"), COFF_MachineType_X64 }, - { str8_lit_comp("AM33"), COFF_MachineType_AM33 }, - { str8_lit_comp("ARM"), COFF_MachineType_ARM }, - { str8_lit_comp("ARM64"), COFF_MachineType_ARM64 }, - { str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT }, - { str8_lit_comp("EBC"), COFF_MachineType_EBC }, - { str8_lit_comp("IA64"), COFF_MachineType_IA64 }, - { str8_lit_comp("M32R"), COFF_MachineType_M32R }, - { str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 }, - { str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU }, - { str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 }, - { str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC }, - { str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP }, - { str8_lit_comp("R4000"), COFF_MachineType_R4000 }, - { str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 }, - { str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 }, - { str8_lit_comp("SH3"), COFF_MachineType_SH3 }, - { str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP }, - { str8_lit_comp("SH4"), COFF_MachineType_SH4 }, - { str8_lit_comp("SH5"), COFF_MachineType_SH5 }, - { str8_lit_comp("THUMB"), COFF_MachineType_THUMB }, - { str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 }, -}; - -read_only static struct { - char * name; - COFF_ImportHeaderType type; -} g_coff_import_header_type_map[] = { - { "CODE", COFF_ImportHeaderType_CODE }, - { "DATA", COFF_ImportHeaderType_DATA }, - { "CONST", COFF_ImportHeaderType_CONST }, -}; - -internal String8 -coff_string_from_comdat_select_type(COFF_ComdatSelectType select) -{ - String8 result = str8(0,0); - switch (select) { - case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break; - case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break; - case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break; - case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break; - case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break; - case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break; - case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break; - } - return result; -} - -internal String8 -coff_string_from_machine_type(COFF_MachineType machine) -{ - for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { - if (g_coff_machine_map[i].machine == machine) { - return g_coff_machine_map[i].string; - } - } - return str8_zero(); -} - -internal String8 -coff_string_from_flags(Arena *arena, COFF_Flags flags) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - - if (flags & COFF_Flag_RELOC_STRIPPED) { - str8_list_pushf(scratch.arena, &list, "Relocs Stripped"); - } - if (flags & COFF_Flag_EXECUTABLE_IMAGE) { - str8_list_pushf(scratch.arena, &list, "Executable"); - } - if (flags & COFF_Flag_LINE_NUMS_STRIPPED) { - str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped"); - } - if (flags & COFF_Flag_SYM_STRIPPED) { - str8_list_pushf(scratch.arena, &list, "Symbols Stripped"); - } - if (flags & COFF_Flag_LARGE_ADDRESS_AWARE) { - str8_list_pushf(scratch.arena, &list, "Large Address Aware"); - } - if (flags & COFF_Flag_32BIT_MACHINE) { - str8_list_pushf(scratch.arena, &list, "32-Bit Machine"); - } - if (flags & COFF_Flag_DEBUG_STRIPPED) { - str8_list_pushf(scratch.arena, &list, "Debug Stripped"); - } - if (flags & COFF_Flag_REMOVABLE_RUN_FROM_SWAP) { - str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap"); - } - if (flags & COFF_Flag_NET_RUN_FROM_SWAP) { - str8_list_pushf(scratch.arena, &list, "Net Run From Swap"); - } - if (flags & COFF_Flag_SYSTEM) { - str8_list_pushf(scratch.arena, &list, "System"); - } - if (flags & COFF_Flag_DLL) { - str8_list_pushf(scratch.arena, &list, "DLL"); - } - if (flags & COFF_Flag_UP_SYSTEM_ONLY) { - str8_list_pushf(scratch.arena, &list, "Up System Only"); - } - - String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); - - scratch_end(scratch); - return result; -} - -internal String8 -coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - - if (flags & COFF_SectionFlag_TYPE_NO_PAD) { - str8_list_pushf(scratch.arena, &list, "TYPE_NO_PAD"); - } - if (flags & COFF_SectionFlag_CNT_CODE) { - str8_list_pushf(scratch.arena, &list, "CNT_CODE"); - } - if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &list, "CNT_INITIALIZED_DATA"); - } - if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &list, "CNT_UNINITIALIZED_DATA"); - } - if (flags & COFF_SectionFlag_LNK_OTHER) { - str8_list_pushf(scratch.arena, &list, "LNK_OTHER"); - } - if (flags & COFF_SectionFlag_LNK_INFO) { - str8_list_pushf(scratch.arena, &list, "LNK_INFO"); - } - if (flags & COFF_SectionFlag_LNK_COMDAT) { - str8_list_pushf(scratch.arena, &list, "LNK_COMDAT"); - } - if (flags & COFF_SectionFlag_GPREL) { - str8_list_pushf(scratch.arena, &list, "GPREL"); - } - if (flags & COFF_SectionFlag_MEM_16BIT) { - str8_list_pushf(scratch.arena, &list, "MEM_16BIT"); - } - if (flags & COFF_SectionFlag_MEM_LOCKED) { - str8_list_pushf(scratch.arena, &list, "MEM_LOCKED"); - } - if (flags & COFF_SectionFlag_MEM_PRELOAD) { - str8_list_pushf(scratch.arena, &list, "MEM_PRELOAD"); - } - if (flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { - str8_list_pushf(scratch.arena, &list, "LNK_NRELOC_OVFL"); - } - if (flags & COFF_SectionFlag_MEM_DISCARDABLE) { - str8_list_pushf(scratch.arena, &list, "MEM_DISCARDABLE"); - } - if (flags & COFF_SectionFlag_MEM_NOT_CACHED) { - str8_list_pushf(scratch.arena, &list, "MEM_NOT_CACHED"); - } - if (flags & COFF_SectionFlag_MEM_NOT_PAGED) { - str8_list_pushf(scratch.arena, &list, "MEM_NOT_PAGED"); - } - if (flags & COFF_SectionFlag_MEM_SHARED) { - str8_list_pushf(scratch.arena, &list, "MEM_SHARED"); - } - if (flags & COFF_SectionFlag_MEM_EXECUTE) { - str8_list_pushf(scratch.arena, &list, "MEM_EXECUTE"); - } - if (flags & COFF_SectionFlag_MEM_READ) { - str8_list_pushf(scratch.arena, &list, "MEM_READ"); - } - if (flags & COFF_SectionFlag_MEM_WRITE) { - str8_list_pushf(scratch.arena, &list, "MEM_WRITE"); - } - - U64 align = coff_align_size_from_section_flags(flags); - if (align) { - str8_list_pushf(scratch.arena, &list, "Align=%u", align); - } - - if (!list.node_count) { - str8_list_pushf(scratch.arena, &list, "None"); - } - - StringJoin join = {0}; - join.sep = str8_lit(", "); - String8 result = str8_list_join(arena, &list, &join); - - scratch_end(scratch); - return result; -} - -internal String8 -coff_string_from_import_header_type(COFF_ImportHeaderType type) -{ - for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { - if (g_coff_import_header_type_map[i].type == type) { - return str8_cstring(g_coff_import_header_type_map[i].name); - } - } - return str8(0,0); -} - -internal String8 -coff_string_from_sym_dtype(COFF_SymDType x) -{ - switch (x) { - case COFF_SymDType_NULL: return str8_lit("NULL"); - case COFF_SymDType_PTR : return str8_lit("PTR"); - case COFF_SymDType_FUNC: return str8_lit("FUNC"); - case COFF_SymDType_ARRAY: return str8_lit("ARRAY"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_sym_type(COFF_SymType x) -{ - switch (x) { - case COFF_SymType_NULL: return str8_lit("NULL"); - case COFF_SymType_VOID: return str8_lit("VOID"); - case COFF_SymType_CHAR: return str8_lit("CHAR"); - case COFF_SymType_SHORT: return str8_lit("SHORT"); - case COFF_SymType_INT: return str8_lit("INT"); - case COFF_SymType_LONG: return str8_lit("LONG"); - case COFF_SymType_FLOAT: return str8_lit("FLOAT"); - case COFF_SymType_DOUBLE: return str8_lit("DOUBLE"); - case COFF_SymType_STRUCT: return str8_lit("STRUCT"); - case COFF_SymType_UNION: return str8_lit("UNION"); - case COFF_SymType_ENUM: return str8_lit("ENUM"); - case COFF_SymType_MOE: return str8_lit("MOE"); - case COFF_SymType_BYTE: return str8_lit("BYTE"); - case COFF_SymType_WORD: return str8_lit("WORD"); - case COFF_SymType_UINT: return str8_lit("UINT"); - case COFF_SymType_DWORD: return str8_lit("DWORD"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_sym_storage_class(COFF_SymStorageClass x) -{ - switch (x) { - case COFF_SymStorageClass_NULL: break; - case COFF_SymStorageClass_END_OF_FUNCTION: return str8_lit("EOF"); - case COFF_SymStorageClass_AUTOMATIC: return str8_lit("AUTOMATIC"); - case COFF_SymStorageClass_EXTERNAL: return str8_lit("EXTERNAL"); - case COFF_SymStorageClass_STATIC: return str8_lit("STATIC"); - case COFF_SymStorageClass_REGISTER: return str8_lit("REGISTER"); - case COFF_SymStorageClass_EXTERNAL_DEF: return str8_lit("DEF"); - case COFF_SymStorageClass_LABEL: return str8_lit("LABEL"); - case COFF_SymStorageClass_UNDEFINED_LABEL: return str8_lit("LABEL"); - case COFF_SymStorageClass_MEMBER_OF_STRUCT: return str8_lit("STRUCT"); - case COFF_SymStorageClass_ARGUMENT: return str8_lit("ARGUMENT"); - case COFF_SymStorageClass_STRUCT_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_MEMBER_OF_UNION: return str8_lit("UNION"); - case COFF_SymStorageClass_UNION_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_TYPE_DEFINITION: return str8_lit("DEFINITION"); - case COFF_SymStorageClass_UNDEFINED_STATIC: return str8_lit("STATIC"); - case COFF_SymStorageClass_ENUM_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_MEMBER_OF_ENUM: return str8_lit("ENUM"); - case COFF_SymStorageClass_REGISTER_PARAM: return str8_lit("PARAM"); - case COFF_SymStorageClass_BIT_FIELD: return str8_lit("FIELD"); - case COFF_SymStorageClass_BLOCK: return str8_lit("BLOCK"); - case COFF_SymStorageClass_FUNCTION: return str8_lit("FUNCTION"); - case COFF_SymStorageClass_END_OF_STRUCT: return str8_lit("STRUCT"); - case COFF_SymStorageClass_FILE: return str8_lit("FILE"); - case COFF_SymStorageClass_SECTION: return str8_lit("SECTION"); - case COFF_SymStorageClass_WEAK_EXTERNAL: return str8_lit("EXTERNAL"); - case COFF_SymStorageClass_CLR_TOKEN: return str8_lit("TOKEN"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_weak_ext_type(COFF_WeakExtType x) -{ - switch (x) { - case COFF_WeakExtType_NOLIBRARY: return str8_lit("NOLIBRARY"); - case COFF_WeakExtType_SEARCH_LIBRARY: return str8_lit("SEARCH_LIBRARY"); - case COFF_WeakExtType_SEARCH_ALIAS: return str8_lit("SEARCH_ALIAS"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_selection(COFF_ComdatSelectType x) -{ - switch (x) { - case COFF_ComdatSelectType_NULL: break; - case COFF_ComdatSelectType_NODUPLICATES: return str8_lit("NODUPLICATES"); - case COFF_ComdatSelectType_ANY: return str8_lit("ANY"); - case COFF_ComdatSelectType_SAME_SIZE: return str8_lit("SIZE"); - case COFF_ComdatSelectType_EXACT_MATCH: return str8_lit("MATCH"); - case COFF_ComdatSelectType_ASSOCIATIVE: return str8_lit("ASSOCIATIVE"); - case COFF_ComdatSelectType_LARGEST: return str8_lit("LARGEST"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc_x86(COFF_RelocTypeX86 x) -{ - switch (x) { - case COFF_RelocTypeX86_ABS: return str8_lit("ABS"); - case COFF_RelocTypeX86_DIR16: return str8_lit("DIR16"); - case COFF_RelocTypeX86_REL16: return str8_lit("REL16"); - case COFF_RelocTypeX86_UNKNOWN0: return str8_lit("UNKNOWN0"); - case COFF_RelocTypeX86_UNKNOWN2: return str8_lit("UNKNOWN2"); - case COFF_RelocTypeX86_UNKNOWN3: return str8_lit("UNKNOWN3"); - case COFF_RelocTypeX86_DIR32: return str8_lit("DIR32"); - case COFF_RelocTypeX86_DIR32NB: return str8_lit("DIR32NB"); - case COFF_RelocTypeX86_SEG12: return str8_lit("SEG12"); - case COFF_RelocTypeX86_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeX86_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeX86_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeX86_SECREL7: return str8_lit("SECREL7"); - case COFF_RelocTypeX86_UNKNOWN4: return str8_lit("UNKNOWN4"); - case COFF_RelocTypeX86_UNKNOWN5: return str8_lit("UNKNOWN5"); - case COFF_RelocTypeX86_UNKNOWN6: return str8_lit("UNKNOWN6"); - case COFF_RelocTypeX86_UNKNOWN7: return str8_lit("UNKNOWN7"); - case COFF_RelocTypeX86_UNKNOWN8: return str8_lit("UNKNOWN8"); - case COFF_RelocTypeX86_UNKNOWN9: return str8_lit("UNKNOWN9"); - case COFF_RelocTypeX86_REL32: return str8_lit("REL32"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc_x64(COFF_RelocTypeX64 x) -{ - switch (x) { - case COFF_RelocTypeX64_ABS: return str8_lit("ABS"); - case COFF_RelocTypeX64_ADDR64: return str8_lit("ADDR64"); - case COFF_RelocTypeX64_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeX64_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeX64_REL32: return str8_lit("REL32"); - case COFF_RelocTypeX64_REL32_1: return str8_lit("REL32_1"); - case COFF_RelocTypeX64_REL32_2: return str8_lit("REL32_2"); - case COFF_RelocTypeX64_REL32_3: return str8_lit("REL32_3"); - case COFF_RelocTypeX64_REL32_4: return str8_lit("REL32_4"); - case COFF_RelocTypeX64_REL32_5: return str8_lit("REL32_5"); - case COFF_RelocTypeX64_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeX64_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeX64_SECREL7: return str8_lit("SECREL7"); - case COFF_RelocTypeX64_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeX64_SREL32: return str8_lit("SREL32"); - case COFF_RelocTypeX64_PAIR: return str8_lit("PAIR"); - case COFF_RelocTypeX64_SSPAN32: return str8_lit("SSPAN32"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc_arm(COFF_RelocTypeARM x) -{ - switch (x) { - case COFF_RelocTypeARM_ABS: return str8_lit("ABS"); - case COFF_RelocTypeARM_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeARM_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeARM_BRANCH24: return str8_lit("BRANCH24"); - case COFF_RelocTypeARM_BRANCH11: return str8_lit("BRANCH11"); - case COFF_RelocTypeARM_UNKNOWN1: return str8_lit("UNKNOWN1"); - case COFF_RelocTypeARM_UNKNOWN2: return str8_lit("UNKNOWN2"); - case COFF_RelocTypeARM_UNKNOWN3: return str8_lit("UNKNOWN3"); - case COFF_RelocTypeARM_UNKNOWN4: return str8_lit("UNKNOWN4"); - case COFF_RelocTypeARM_UNKNOWN5: return str8_lit("UNKNOWN5"); - case COFF_RelocTypeARM_REL32: return str8_lit("REL32"); - case COFF_RelocTypeARM_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeARM_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeARM_MOV32: return str8_lit("MOV32"); - case COFF_RelocTypeARM_THUMB_MOV32: return str8_lit("THUMB_MOV32"); - case COFF_RelocTypeARM_THUMB_BRANCH20: return str8_lit("THUMB_BRANCH20"); - case COFF_RelocTypeARM_UNUSED: return str8_lit("UNUSED"); - case COFF_RelocTypeARM_THUMB_BRANCH24: return str8_lit("THUMB_BRANCH24"); - case COFF_RelocTypeARM_THUMB_BLX23: return str8_lit("THUMB_BLX23"); - case COFF_RelocTypeARM_PAIR: return str8_lit("PAIR"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x) -{ - switch (x) { - case COFF_RelocTypeARM64_ABS: return str8_lit("ABS"); - case COFF_RelocTypeARM64_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeARM64_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeARM64_BRANCH26: return str8_lit("BRANCH26"); - case COFF_RelocTypeARM64_PAGEBASE_REL21: return str8_lit("PAGEBASE_REL21"); - case COFF_RelocTypeARM64_REL21: return str8_lit("REL21"); - case COFF_RelocTypeARM64_PAGEOFFSET_12A: return str8_lit("PAGEOFFSET_12A"); - case COFF_RelocTypeARM64_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeARM64_SECREL_LOW12A: return str8_lit("SECREL_LOW12A"); - case COFF_RelocTypeARM64_SECREL_HIGH12A: return str8_lit("SECREL_HIGH12A"); - case COFF_RelocTypeARM64_SECREL_LOW12L: return str8_lit("SECREL_LOW12L"); - case COFF_RelocTypeARM64_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeARM64_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeARM64_ADDR64: return str8_lit("ADDR64"); - case COFF_RelocTypeARM64_BRANCH19: return str8_lit("BRANCH19"); - case COFF_RelocTypeARM64_BRANCH14: return str8_lit("BRANCH14"); - case COFF_RelocTypeARM64_REL32: return str8_lit("REL32"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x) +internal Arch +arch_from_coff_machine(COFF_MachineType machine) { + Arch result = Arch_Null; switch (machine) { - case COFF_MachineType_X86: return coff_string_from_reloc_x86(x); - case COFF_MachineType_X64: return coff_string_from_reloc_x64(x); - case COFF_MachineType_ARM: return coff_string_from_reloc_arm(x); - case COFF_MachineType_ARM64: return coff_string_from_reloc_arm64(x); + case COFF_MachineType_UNKNOWN: break; + case COFF_MachineType_X86: result = Arch_x86; break; + case COFF_MachineType_X64: result = Arch_x64; break; + case COFF_MachineType_ARM: result = Arch_arm32; break; + case COFF_MachineType_ARM64: result = Arch_arm64; break; } - return str8_zero(); + return result; } -internal COFF_MachineType -coff_machine_from_string(String8 string) -{ - for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { - if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) { - return g_coff_machine_map[i].machine; - } - } - return COFF_MachineType_UNKNOWN; -} - -internal COFF_ImportHeaderType -coff_import_header_type_from_string(String8 name) -{ - for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { - if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) { - return g_coff_import_header_type_map[i].type; - } - } - return COFF_ImportHeaderType_COUNT; -} - - diff --git a/src/coff/coff.h b/src/coff/coff.h index bdbce261..ccf905bb 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -895,26 +895,6 @@ internal COFF_ArchiveParse coff_archive_from_data(String8 data); internal COFF_ArchiveParse coff_thin_archive_from_data(String8 data); internal COFF_ArchiveParse coff_archive_parse_from_data(String8 data); -//////////////////////////////// -// String <-> Enum - -internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select); -internal String8 coff_string_from_machine_type(COFF_MachineType machine); -internal String8 coff_string_from_flags(Arena *arena, COFF_Flags flags); -internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags); -internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type); -internal String8 coff_string_from_sym_dtype(COFF_SymDType x); -internal String8 coff_string_from_sym_type(COFF_SymType x); -internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x); -internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x); -internal String8 coff_string_from_selection(COFF_ComdatSelectType x); -internal String8 coff_string_from_reloc_x86(COFF_RelocTypeX86 x); -internal String8 coff_string_from_reloc_x64(COFF_RelocTypeX64 x); -internal String8 coff_string_from_reloc_arm(COFF_RelocTypeARM x); -internal String8 coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x); -internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x); - -internal COFF_MachineType coff_machine_from_string(String8 string); -internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name); +internal Arch arch_from_coff_machine(COFF_MachineType machine); #endif //COFF_H diff --git a/src/coff/coff_enum.c b/src/coff/coff_enum.c new file mode 100644 index 00000000..0830f2aa --- /dev/null +++ b/src/coff/coff_enum.c @@ -0,0 +1,466 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 +coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp) +{ + String8 result; + if (time_stamp == 0) { + result = str8_lit("0"); + } else if (time_stamp >= max_U32) { + result = str8_lit("-1"); + } else { + DateTime dt = date_time_from_unix_time(time_stamp); + result = push_date_time_string(arena, &dt); + } + return result; +} + +read_only struct +{ + String8 string; + COFF_MachineType machine; +} g_coff_machine_map[] = { + { str8_lit_comp(""), COFF_MachineType_UNKNOWN }, + { str8_lit_comp("X86"), COFF_MachineType_X86 }, + { str8_lit_comp("AMD64"), COFF_MachineType_X64 }, + { str8_lit_comp("X64"), COFF_MachineType_X64 }, + { str8_lit_comp("AM33"), COFF_MachineType_AM33 }, + { str8_lit_comp("ARM"), COFF_MachineType_ARM }, + { str8_lit_comp("ARM64"), COFF_MachineType_ARM64 }, + { str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT }, + { str8_lit_comp("EBC"), COFF_MachineType_EBC }, + { str8_lit_comp("IA64"), COFF_MachineType_IA64 }, + { str8_lit_comp("M32R"), COFF_MachineType_M32R }, + { str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 }, + { str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU }, + { str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 }, + { str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC }, + { str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP }, + { str8_lit_comp("R4000"), COFF_MachineType_R4000 }, + { str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 }, + { str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 }, + { str8_lit_comp("SH3"), COFF_MachineType_SH3 }, + { str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP }, + { str8_lit_comp("SH4"), COFF_MachineType_SH4 }, + { str8_lit_comp("SH5"), COFF_MachineType_SH5 }, + { str8_lit_comp("THUMB"), COFF_MachineType_THUMB }, + { str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 }, +}; + +read_only static struct { + char * name; + COFF_ImportHeaderType type; +} g_coff_import_header_type_map[] = { + { "CODE", COFF_ImportHeaderType_CODE }, + { "DATA", COFF_ImportHeaderType_DATA }, + { "CONST", COFF_ImportHeaderType_CONST }, +}; + +internal String8 +coff_string_from_comdat_select_type(COFF_ComdatSelectType select) +{ + String8 result = str8(0,0); + switch (select) { + case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break; + case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break; + case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break; + case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break; + case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break; + case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break; + case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break; + } + return result; +} + +internal String8 +coff_string_from_machine_type(COFF_MachineType machine) +{ + for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { + if (g_coff_machine_map[i].machine == machine) { + return g_coff_machine_map[i].string; + } + } + return str8_zero(); +} + +internal String8 +coff_string_from_flags(Arena *arena, COFF_Flags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + if (flags & COFF_Flag_RELOC_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Relocs Stripped"); + } + if (flags & COFF_Flag_EXECUTABLE_IMAGE) { + str8_list_pushf(scratch.arena, &list, "Executable"); + } + if (flags & COFF_Flag_LINE_NUMS_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped"); + } + if (flags & COFF_Flag_SYM_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Symbols Stripped"); + } + if (flags & COFF_Flag_LARGE_ADDRESS_AWARE) { + str8_list_pushf(scratch.arena, &list, "Large Address Aware"); + } + if (flags & COFF_Flag_32BIT_MACHINE) { + str8_list_pushf(scratch.arena, &list, "32-Bit Machine"); + } + if (flags & COFF_Flag_DEBUG_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Debug Stripped"); + } + if (flags & COFF_Flag_REMOVABLE_RUN_FROM_SWAP) { + str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap"); + } + if (flags & COFF_Flag_NET_RUN_FROM_SWAP) { + str8_list_pushf(scratch.arena, &list, "Net Run From Swap"); + } + if (flags & COFF_Flag_SYSTEM) { + str8_list_pushf(scratch.arena, &list, "System"); + } + if (flags & COFF_Flag_DLL) { + str8_list_pushf(scratch.arena, &list, "DLL"); + } + if (flags & COFF_Flag_UP_SYSTEM_ONLY) { + str8_list_pushf(scratch.arena, &list, "Up System Only"); + } + + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + + scratch_end(scratch); + return result; +} + +internal String8 +coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + if (flags & COFF_SectionFlag_TYPE_NO_PAD) { + str8_list_pushf(scratch.arena, &list, "TYPE_NO_PAD"); + } + if (flags & COFF_SectionFlag_CNT_CODE) { + str8_list_pushf(scratch.arena, &list, "CNT_CODE"); + } + if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &list, "CNT_INITIALIZED_DATA"); + } + if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &list, "CNT_UNINITIALIZED_DATA"); + } + if (flags & COFF_SectionFlag_LNK_OTHER) { + str8_list_pushf(scratch.arena, &list, "LNK_OTHER"); + } + if (flags & COFF_SectionFlag_LNK_INFO) { + str8_list_pushf(scratch.arena, &list, "LNK_INFO"); + } + if (flags & COFF_SectionFlag_LNK_COMDAT) { + str8_list_pushf(scratch.arena, &list, "LNK_COMDAT"); + } + if (flags & COFF_SectionFlag_GPREL) { + str8_list_pushf(scratch.arena, &list, "GPREL"); + } + if (flags & COFF_SectionFlag_MEM_16BIT) { + str8_list_pushf(scratch.arena, &list, "MEM_16BIT"); + } + if (flags & COFF_SectionFlag_MEM_LOCKED) { + str8_list_pushf(scratch.arena, &list, "MEM_LOCKED"); + } + if (flags & COFF_SectionFlag_MEM_PRELOAD) { + str8_list_pushf(scratch.arena, &list, "MEM_PRELOAD"); + } + if (flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { + str8_list_pushf(scratch.arena, &list, "LNK_NRELOC_OVFL"); + } + if (flags & COFF_SectionFlag_MEM_DISCARDABLE) { + str8_list_pushf(scratch.arena, &list, "MEM_DISCARDABLE"); + } + if (flags & COFF_SectionFlag_MEM_NOT_CACHED) { + str8_list_pushf(scratch.arena, &list, "MEM_NOT_CACHED"); + } + if (flags & COFF_SectionFlag_MEM_NOT_PAGED) { + str8_list_pushf(scratch.arena, &list, "MEM_NOT_PAGED"); + } + if (flags & COFF_SectionFlag_MEM_SHARED) { + str8_list_pushf(scratch.arena, &list, "MEM_SHARED"); + } + if (flags & COFF_SectionFlag_MEM_EXECUTE) { + str8_list_pushf(scratch.arena, &list, "MEM_EXECUTE"); + } + if (flags & COFF_SectionFlag_MEM_READ) { + str8_list_pushf(scratch.arena, &list, "MEM_READ"); + } + if (flags & COFF_SectionFlag_MEM_WRITE) { + str8_list_pushf(scratch.arena, &list, "MEM_WRITE"); + } + + U64 align = coff_align_size_from_section_flags(flags); + if (align) { + str8_list_pushf(scratch.arena, &list, "Align=%u", align); + } + + if (!list.node_count) { + str8_list_pushf(scratch.arena, &list, "None"); + } + + StringJoin join = {0}; + join.sep = str8_lit(", "); + String8 result = str8_list_join(arena, &list, &join); + + scratch_end(scratch); + return result; +} + +internal String8 +coff_string_from_import_header_type(COFF_ImportHeaderType type) +{ + for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { + if (g_coff_import_header_type_map[i].type == type) { + return str8_cstring(g_coff_import_header_type_map[i].name); + } + } + return str8(0,0); +} + +internal String8 +coff_string_from_sym_dtype(COFF_SymDType x) +{ + switch (x) { + case COFF_SymDType_NULL: return str8_lit("NULL"); + case COFF_SymDType_PTR : return str8_lit("PTR"); + case COFF_SymDType_FUNC: return str8_lit("FUNC"); + case COFF_SymDType_ARRAY: return str8_lit("ARRAY"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_sym_type(COFF_SymType x) +{ + switch (x) { + case COFF_SymType_NULL: return str8_lit("NULL"); + case COFF_SymType_VOID: return str8_lit("VOID"); + case COFF_SymType_CHAR: return str8_lit("CHAR"); + case COFF_SymType_SHORT: return str8_lit("SHORT"); + case COFF_SymType_INT: return str8_lit("INT"); + case COFF_SymType_LONG: return str8_lit("LONG"); + case COFF_SymType_FLOAT: return str8_lit("FLOAT"); + case COFF_SymType_DOUBLE: return str8_lit("DOUBLE"); + case COFF_SymType_STRUCT: return str8_lit("STRUCT"); + case COFF_SymType_UNION: return str8_lit("UNION"); + case COFF_SymType_ENUM: return str8_lit("ENUM"); + case COFF_SymType_MOE: return str8_lit("MOE"); + case COFF_SymType_BYTE: return str8_lit("BYTE"); + case COFF_SymType_WORD: return str8_lit("WORD"); + case COFF_SymType_UINT: return str8_lit("UINT"); + case COFF_SymType_DWORD: return str8_lit("DWORD"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_sym_storage_class(COFF_SymStorageClass x) +{ + switch (x) { + case COFF_SymStorageClass_NULL: break; + case COFF_SymStorageClass_END_OF_FUNCTION: return str8_lit("EOF"); + case COFF_SymStorageClass_AUTOMATIC: return str8_lit("AUTOMATIC"); + case COFF_SymStorageClass_EXTERNAL: return str8_lit("EXTERNAL"); + case COFF_SymStorageClass_STATIC: return str8_lit("STATIC"); + case COFF_SymStorageClass_REGISTER: return str8_lit("REGISTER"); + case COFF_SymStorageClass_EXTERNAL_DEF: return str8_lit("DEF"); + case COFF_SymStorageClass_LABEL: return str8_lit("LABEL"); + case COFF_SymStorageClass_UNDEFINED_LABEL: return str8_lit("LABEL"); + case COFF_SymStorageClass_MEMBER_OF_STRUCT: return str8_lit("STRUCT"); + case COFF_SymStorageClass_ARGUMENT: return str8_lit("ARGUMENT"); + case COFF_SymStorageClass_STRUCT_TAG: return str8_lit("TAG"); + case COFF_SymStorageClass_MEMBER_OF_UNION: return str8_lit("UNION"); + case COFF_SymStorageClass_UNION_TAG: return str8_lit("TAG"); + case COFF_SymStorageClass_TYPE_DEFINITION: return str8_lit("DEFINITION"); + case COFF_SymStorageClass_UNDEFINED_STATIC: return str8_lit("STATIC"); + case COFF_SymStorageClass_ENUM_TAG: return str8_lit("TAG"); + case COFF_SymStorageClass_MEMBER_OF_ENUM: return str8_lit("ENUM"); + case COFF_SymStorageClass_REGISTER_PARAM: return str8_lit("PARAM"); + case COFF_SymStorageClass_BIT_FIELD: return str8_lit("FIELD"); + case COFF_SymStorageClass_BLOCK: return str8_lit("BLOCK"); + case COFF_SymStorageClass_FUNCTION: return str8_lit("FUNCTION"); + case COFF_SymStorageClass_END_OF_STRUCT: return str8_lit("STRUCT"); + case COFF_SymStorageClass_FILE: return str8_lit("FILE"); + case COFF_SymStorageClass_SECTION: return str8_lit("SECTION"); + case COFF_SymStorageClass_WEAK_EXTERNAL: return str8_lit("EXTERNAL"); + case COFF_SymStorageClass_CLR_TOKEN: return str8_lit("TOKEN"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_weak_ext_type(COFF_WeakExtType x) +{ + switch (x) { + case COFF_WeakExtType_NOLIBRARY: return str8_lit("NOLIBRARY"); + case COFF_WeakExtType_SEARCH_LIBRARY: return str8_lit("SEARCH_LIBRARY"); + case COFF_WeakExtType_SEARCH_ALIAS: return str8_lit("SEARCH_ALIAS"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_selection(COFF_ComdatSelectType x) +{ + switch (x) { + case COFF_ComdatSelectType_NULL: break; + case COFF_ComdatSelectType_NODUPLICATES: return str8_lit("NODUPLICATES"); + case COFF_ComdatSelectType_ANY: return str8_lit("ANY"); + case COFF_ComdatSelectType_SAME_SIZE: return str8_lit("SIZE"); + case COFF_ComdatSelectType_EXACT_MATCH: return str8_lit("MATCH"); + case COFF_ComdatSelectType_ASSOCIATIVE: return str8_lit("ASSOCIATIVE"); + case COFF_ComdatSelectType_LARGEST: return str8_lit("LARGEST"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_reloc_x86(COFF_RelocTypeX86 x) +{ + switch (x) { + case COFF_RelocTypeX86_ABS: return str8_lit("ABS"); + case COFF_RelocTypeX86_DIR16: return str8_lit("DIR16"); + case COFF_RelocTypeX86_REL16: return str8_lit("REL16"); + case COFF_RelocTypeX86_UNKNOWN0: return str8_lit("UNKNOWN0"); + case COFF_RelocTypeX86_UNKNOWN2: return str8_lit("UNKNOWN2"); + case COFF_RelocTypeX86_UNKNOWN3: return str8_lit("UNKNOWN3"); + case COFF_RelocTypeX86_DIR32: return str8_lit("DIR32"); + case COFF_RelocTypeX86_DIR32NB: return str8_lit("DIR32NB"); + case COFF_RelocTypeX86_SEG12: return str8_lit("SEG12"); + case COFF_RelocTypeX86_SECTION: return str8_lit("SECTION"); + case COFF_RelocTypeX86_SECREL: return str8_lit("SECREL"); + case COFF_RelocTypeX86_TOKEN: return str8_lit("TOKEN"); + case COFF_RelocTypeX86_SECREL7: return str8_lit("SECREL7"); + case COFF_RelocTypeX86_UNKNOWN4: return str8_lit("UNKNOWN4"); + case COFF_RelocTypeX86_UNKNOWN5: return str8_lit("UNKNOWN5"); + case COFF_RelocTypeX86_UNKNOWN6: return str8_lit("UNKNOWN6"); + case COFF_RelocTypeX86_UNKNOWN7: return str8_lit("UNKNOWN7"); + case COFF_RelocTypeX86_UNKNOWN8: return str8_lit("UNKNOWN8"); + case COFF_RelocTypeX86_UNKNOWN9: return str8_lit("UNKNOWN9"); + case COFF_RelocTypeX86_REL32: return str8_lit("REL32"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_reloc_x64(COFF_RelocTypeX64 x) +{ + switch (x) { + case COFF_RelocTypeX64_ABS: return str8_lit("ABS"); + case COFF_RelocTypeX64_ADDR64: return str8_lit("ADDR64"); + case COFF_RelocTypeX64_ADDR32: return str8_lit("ADDR32"); + case COFF_RelocTypeX64_ADDR32NB: return str8_lit("ADDR32NB"); + case COFF_RelocTypeX64_REL32: return str8_lit("REL32"); + case COFF_RelocTypeX64_REL32_1: return str8_lit("REL32_1"); + case COFF_RelocTypeX64_REL32_2: return str8_lit("REL32_2"); + case COFF_RelocTypeX64_REL32_3: return str8_lit("REL32_3"); + case COFF_RelocTypeX64_REL32_4: return str8_lit("REL32_4"); + case COFF_RelocTypeX64_REL32_5: return str8_lit("REL32_5"); + case COFF_RelocTypeX64_SECTION: return str8_lit("SECTION"); + case COFF_RelocTypeX64_SECREL: return str8_lit("SECREL"); + case COFF_RelocTypeX64_SECREL7: return str8_lit("SECREL7"); + case COFF_RelocTypeX64_TOKEN: return str8_lit("TOKEN"); + case COFF_RelocTypeX64_SREL32: return str8_lit("SREL32"); + case COFF_RelocTypeX64_PAIR: return str8_lit("PAIR"); + case COFF_RelocTypeX64_SSPAN32: return str8_lit("SSPAN32"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_reloc_arm(COFF_RelocTypeARM x) +{ + switch (x) { + case COFF_RelocTypeARM_ABS: return str8_lit("ABS"); + case COFF_RelocTypeARM_ADDR32: return str8_lit("ADDR32"); + case COFF_RelocTypeARM_ADDR32NB: return str8_lit("ADDR32NB"); + case COFF_RelocTypeARM_BRANCH24: return str8_lit("BRANCH24"); + case COFF_RelocTypeARM_BRANCH11: return str8_lit("BRANCH11"); + case COFF_RelocTypeARM_UNKNOWN1: return str8_lit("UNKNOWN1"); + case COFF_RelocTypeARM_UNKNOWN2: return str8_lit("UNKNOWN2"); + case COFF_RelocTypeARM_UNKNOWN3: return str8_lit("UNKNOWN3"); + case COFF_RelocTypeARM_UNKNOWN4: return str8_lit("UNKNOWN4"); + case COFF_RelocTypeARM_UNKNOWN5: return str8_lit("UNKNOWN5"); + case COFF_RelocTypeARM_REL32: return str8_lit("REL32"); + case COFF_RelocTypeARM_SECTION: return str8_lit("SECTION"); + case COFF_RelocTypeARM_SECREL: return str8_lit("SECREL"); + case COFF_RelocTypeARM_MOV32: return str8_lit("MOV32"); + case COFF_RelocTypeARM_THUMB_MOV32: return str8_lit("THUMB_MOV32"); + case COFF_RelocTypeARM_THUMB_BRANCH20: return str8_lit("THUMB_BRANCH20"); + case COFF_RelocTypeARM_UNUSED: return str8_lit("UNUSED"); + case COFF_RelocTypeARM_THUMB_BRANCH24: return str8_lit("THUMB_BRANCH24"); + case COFF_RelocTypeARM_THUMB_BLX23: return str8_lit("THUMB_BLX23"); + case COFF_RelocTypeARM_PAIR: return str8_lit("PAIR"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x) +{ + switch (x) { + case COFF_RelocTypeARM64_ABS: return str8_lit("ABS"); + case COFF_RelocTypeARM64_ADDR32: return str8_lit("ADDR32"); + case COFF_RelocTypeARM64_ADDR32NB: return str8_lit("ADDR32NB"); + case COFF_RelocTypeARM64_BRANCH26: return str8_lit("BRANCH26"); + case COFF_RelocTypeARM64_PAGEBASE_REL21: return str8_lit("PAGEBASE_REL21"); + case COFF_RelocTypeARM64_REL21: return str8_lit("REL21"); + case COFF_RelocTypeARM64_PAGEOFFSET_12A: return str8_lit("PAGEOFFSET_12A"); + case COFF_RelocTypeARM64_SECREL: return str8_lit("SECREL"); + case COFF_RelocTypeARM64_SECREL_LOW12A: return str8_lit("SECREL_LOW12A"); + case COFF_RelocTypeARM64_SECREL_HIGH12A: return str8_lit("SECREL_HIGH12A"); + case COFF_RelocTypeARM64_SECREL_LOW12L: return str8_lit("SECREL_LOW12L"); + case COFF_RelocTypeARM64_TOKEN: return str8_lit("TOKEN"); + case COFF_RelocTypeARM64_SECTION: return str8_lit("SECTION"); + case COFF_RelocTypeARM64_ADDR64: return str8_lit("ADDR64"); + case COFF_RelocTypeARM64_BRANCH19: return str8_lit("BRANCH19"); + case COFF_RelocTypeARM64_BRANCH14: return str8_lit("BRANCH14"); + case COFF_RelocTypeARM64_REL32: return str8_lit("REL32"); + } + return str8_zero(); +} + +internal String8 +coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x) +{ + switch (machine) { + case COFF_MachineType_X86: return coff_string_from_reloc_x86(x); + case COFF_MachineType_X64: return coff_string_from_reloc_x64(x); + case COFF_MachineType_ARM: return coff_string_from_reloc_arm(x); + case COFF_MachineType_ARM64: return coff_string_from_reloc_arm64(x); + } + return str8_zero(); +} + +internal COFF_MachineType +coff_machine_from_string(String8 string) +{ + for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { + if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) { + return g_coff_machine_map[i].machine; + } + } + return COFF_MachineType_UNKNOWN; +} + +internal COFF_ImportHeaderType +coff_import_header_type_from_string(String8 name) +{ + for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { + if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) { + return g_coff_import_header_type_map[i].type; + } + } + return COFF_ImportHeaderType_COUNT; +} + + + diff --git a/src/coff/coff_enum.h b/src/coff/coff_enum.h new file mode 100644 index 00000000..7eb174e7 --- /dev/null +++ b/src/coff/coff_enum.h @@ -0,0 +1,27 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef COFF_ENUM_H +#define COFF_ENUM_H + +internal String8 coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp); +internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select); +internal String8 coff_string_from_machine_type(COFF_MachineType machine); +internal String8 coff_string_from_flags(Arena *arena, COFF_Flags flags); +internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags); +internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type); +internal String8 coff_string_from_sym_dtype(COFF_SymDType x); +internal String8 coff_string_from_sym_type(COFF_SymType x); +internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x); +internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x); +internal String8 coff_string_from_selection(COFF_ComdatSelectType x); +internal String8 coff_string_from_reloc_x86(COFF_RelocTypeX86 x); +internal String8 coff_string_from_reloc_x64(COFF_RelocTypeX64 x); +internal String8 coff_string_from_reloc_arm(COFF_RelocTypeARM x); +internal String8 coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x); +internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x); + +internal COFF_MachineType coff_machine_from_string(String8 string); +internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name); + +#endif // COFF_ENUM_H diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7cfacb59..adab3ac3 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -35,6 +35,7 @@ #include "os/os_inc.h" #include "path/path.h" #include "coff/coff.h" +#include "coff/coff_enum.h" #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" @@ -47,6 +48,7 @@ #include "os/os_inc.c" #include "path/path.c" #include "coff/coff.c" +#include "coff/coff_enum.c" #include "pe/pe.c" #include "codeview/codeview.c" #include "codeview/codeview_parse.c" diff --git a/src/msvc_crt/msvc_crt_enum.c b/src/msvc_crt/msvc_crt_enum.c new file mode 100644 index 00000000..e70e4ed0 --- /dev/null +++ b/src/msvc_crt/msvc_crt_enum.c @@ -0,0 +1,34 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 +mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List adj_list = {0}; + if (adjectives & MSCRT_EhHandlerTypeFlag_IsConst) { + str8_list_pushf(scratch.arena, &adj_list, "Const"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsVolatile) { + str8_list_pushf(scratch.arena, &adj_list, "Volatile"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsUnaligned) { + str8_list_pushf(scratch.arena, &adj_list, "Unaligned"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsReference) { + str8_list_pushf(scratch.arena, &adj_list, "Reference"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsResumable) { + str8_list_pushf(scratch.arena, &adj_list, "Resumable"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsStdDotDot) { + str8_list_pushf(scratch.arena, &adj_list, "StdDotDot"); + } + if (adjectives & MSCRT_EhHandlerTypeFlag_IsComplusEH) { + str8_list_pushf(scratch.arena, &adj_list, "ComplusEH"); + } + String8 result = str8_list_join(arena, &adj_list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + diff --git a/src/msvc_crt/msvc_crt_enum.h b/src/msvc_crt/msvc_crt_enum.h new file mode 100644 index 00000000..ac71508d --- /dev/null +++ b/src/msvc_crt/msvc_crt_enum.h @@ -0,0 +1,9 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef MSVC_CRT_ENUM_H +#define MSVC_CRT_ENUM_H + +internal String8 mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives); + +#endif // MSVC_CRT_ENUM_H From 76b742ceb83bd5719462eb71acac2fc9b77d0862 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 12 Dec 2024 15:09:59 -0800 Subject: [PATCH 05/53] coffdump -> raddump --- build.bat | 6 +- src/dumpers/coffdump.c | 2860 ----------------------- src/raddump/raddump.c | 4448 ++++++++++++++++++++++++++++++++++++ src/raddump/raddump.h | 142 ++ src/raddump/raddump_main.c | 182 ++ 5 files changed, 4775 insertions(+), 2863 deletions(-) delete mode 100644 src/dumpers/coffdump.c create mode 100644 src/raddump/raddump.c create mode 100644 src/raddump/raddump.h create mode 100644 src/raddump/raddump_main.c diff --git a/build.bat b/build.bat index c45e5d6d..5c84db91 100644 --- a/build.bat +++ b/build.bat @@ -106,8 +106,9 @@ if not "%no_meta%"=="1" ( :: --- Build Everything (@build_targets) -------------------------------------- pushd build if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1 -if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1 -if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1 +if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1 +if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1 +if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 2 if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1 if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1 @@ -117,7 +118,6 @@ if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratc if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1 if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1 if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1 -if "%coffdump%"=="1" set didbuild=1 && %compile% ..\src\dumpers\coffdump.c %compile_link% %out%coffdump.exe || exit /b 1 if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 diff --git a/src/dumpers/coffdump.c b/src/dumpers/coffdump.c deleted file mode 100644 index f4413640..00000000 --- a/src/dumpers/coffdump.c +++ /dev/null @@ -1,2860 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#define BUILD_CONSOLE_INTERFACE 1 -#define BUILD_TITLE "Epic Games Tools (R) COFF/PE Dumper" - -//////////////////////////////// - -#include "third_party/xxHash/xxhash.c" -#include "third_party/xxHash/xxhash.h" -#include "third_party/radsort/radsort.h" -#include "third_party/zydis/zydis.h" -#include "third_party/zydis/zydis.c" - -//////////////////////////////// - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "path/path.h" -#include "coff/coff.h" -#include "pe/pe.h" -#include "msvc_crt/msvc_crt.h" -#include "codeview/codeview.h" -#include "msf/msf.h" -#include "msf/msf_parse.h" -#include "pdb/pdb.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "path/path.c" -#include "coff/coff.c" -#include "pe/pe.c" -#include "msvc_crt/msvc_crt.c" -#include "codeview/codeview.c" -#include "msf/msf_parse.c" -#include "pdb/pdb.c" - -#include "linker/base_ext/base_core.h" -#include "linker/base_ext/base_core.c" -#include "linker/path_ext/path.h" -#include "linker/path_ext/path.c" -#include "linker/hash_table.h" -#include "linker/hash_table.c" - -//////////////////////////////// - -#define COFF_INDENT_WIDTH 4 -#define COFF_INDENT_MAX 4096 - -#define coff_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__) -#define coff_newline() str8_list_pushf(arena, out, ""); -#define coff_errorf(f, ...) coff_printf("ERROR: "f, __VA_ARGS__) -#define coff_indent() do { if (indent.size + COFF_INDENT_WIDTH <= COFF_INDENT_MAX) { indent.size += COFF_INDENT_WIDTH; } else { Assert(!"indent overflow"); } } while (0) -#define coff_unindent() do { if (indent.size >= COFF_INDENT_WIDTH) { indent.size -= COFF_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) - -//////////////////////////////// - -typedef U64 Coffdump_Option; -enum Coffdump_OptionEnum -{ - Coffdump_Option_Help = (1 << 0), - Coffdump_Option_Version = (1 << 1), - Coffdump_Option_Headers = (1 << 2), - Coffdump_Option_Sections = (1 << 3), - Coffdump_Option_Debug = (1 << 4), - Coffdump_Option_Imports = (1 << 5), - Coffdump_Option_Exports = (1 << 6), - Coffdump_Option_Disasm = (1 << 7), - Coffdump_Option_Rawdata = (1 << 8), - Coffdump_Option_Tls = (1 << 9), - Coffdump_Option_Codeview = (1 << 10), - Coffdump_Option_Symbols = (1 << 11), - Coffdump_Option_Relocs = (1 << 12), - Coffdump_Option_Exceptions = (1 << 13), - Coffdump_Option_LoadConfig = (1 << 14), - Coffdump_Option_Resources = (1 << 15), - Coffdump_Option_LongNames = (1 << 16), -}; - - global read_only struct { - Coffdump_Option opt; - char *name; - char *help; -} g_coffdump_option_map[] = { - { Coffdump_Option_Help, "help", "Print help and exit" }, - { Coffdump_Option_Version, "v", "Print version and exit" }, - { Coffdump_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, - { Coffdump_Option_Sections, "sections", "Dump section headers as table" }, - { Coffdump_Option_Rawdata, "rawdata", "Dump raw section data" }, - { Coffdump_Option_Codeview, "cv", "Dump relocations" }, - { Coffdump_Option_Disasm, "disasm", "Disassemble code sections" }, - { Coffdump_Option_Symbols, "symbols", "Dump COFF symbol table" }, - { Coffdump_Option_Relocs, "relocs", "Dump relocations" }, - { Coffdump_Option_Exceptions, "exceptions", "Dump exceptions" }, - { Coffdump_Option_Tls, "tls", "Dump Thread Local Storage directory" }, - { Coffdump_Option_Debug, "debug", "Dump debug directory" }, - { Coffdump_Option_Imports, "imports", "Dump import table" }, - { Coffdump_Option_Exports, "exports", "Dump export table" }, - { Coffdump_Option_LoadConfig, "loadconfig", "Dump load config" }, - { Coffdump_Option_Resources, "resources", "Dump resource directory" }, - { Coffdump_Option_LongNames, "longnames", "Dump archive long names" }, -}; - -//////////////////////////////// - -typedef struct -{ - U64 off; - String8 string; -} Marker; - -typedef struct -{ - U64 count; - Marker *v; -} MarkerArray; - -typedef struct MarkerNode -{ - struct MarkerNode *next; - Marker v; -} MarkerNode; - -typedef struct -{ - U64 count; - MarkerNode *first; - MarkerNode *last; -} MarkerList; - -internal int -marker_is_before(void *a, void *b) -{ - return u64_is_before(&((Marker*)a)->off, &((Marker*)b)->off); -} - -internal MarkerArray * -section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols) -{ - Temp scratch = scratch_begin(&arena, 1); - - // extract markers from symbol table - MarkerList *markers = push_array(scratch.arena, MarkerList, section_count); - for (U64 symbol_idx = 0; symbol_idx < symbols.count; ++symbol_idx) { - COFF_Symbol32 *symbol = &symbols.v[symbol_idx]; - - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); - B32 is_marker = interp == COFF_SymbolValueInterp_REGULAR && - symbol->aux_symbol_count == 0 && - (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC); - - if (is_marker) { - String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); - - struct MarkerNode *n = push_array(scratch.arena, struct MarkerNode, 1); - n->v.off = symbol->value; - n->v.string = name; - - MarkerList *list = &markers[symbol->section_number-1]; - SLLQueuePush(list->first, list->last, n); - ++list->count; - } - - symbol_idx += symbol->aux_symbol_count; - } - - // lists -> arrays - MarkerArray *result = push_array(arena, MarkerArray, section_count); - for (U64 i = 0; i < section_count; ++i) { - result[i].count = 0; - result[i].v = push_array(arena, Marker, markers[i].count); - for (MarkerNode *n = markers[i].first; n != 0; n = n->next) { - result[i].v[result[i].count++] = n->v; - } - } - - // sort arrays - for (U64 i = 0; i < section_count; ++i) { - radsort(result[i].v, result[i].count, marker_is_before); - } - - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ Disasm - -typedef struct -{ - String8 text; - U64 size; -} DisasmResult; - -internal DisasmResult -disasm_next_instruction(Arena *arena, COFF_MachineType machine, U64 addr, String8 raw_code) -{ - DisasmResult result = {0}; - - switch (machine) { - case COFF_MachineType_UNKNOWN: break; - - case COFF_MachineType_X64: - case COFF_MachineType_X86: { - ZydisMachineMode machine_mode = machine == COFF_MachineType_X86 ? ZYDIS_MACHINE_MODE_LEGACY_32 : ZYDIS_MACHINE_MODE_LONG_64; - ZydisDisassembledInstruction inst = {0}; - ZyanStatus status = ZydisDisassemble(machine_mode, addr, raw_code.str, raw_code.size, &inst, ZYDIS_FORMATTER_STYLE_INTEL); - - String8 text = str8_cstring_capped(inst.text, inst.text+sizeof(inst.text)); - result.text = push_str8_copy(arena, text); - result.size = inst.info.length; - } break; - - default: NotImplemented; - } - - return result; -} - -internal void -format_disasm(Arena *arena, - String8List *out, - String8 indent, - COFF_MachineType machine, - U64 image_base, - U64 sect_off, - U64 marker_count, - Marker *markers, - String8 raw_code) -{ - Temp scratch = scratch_begin(&arena, 1); - - U64 bytes_buffer_max = 256; - U8 *bytes_buffer = push_array(scratch.arena, U8, bytes_buffer_max); - - U64 decode_off = 0; - U64 marker_cursor = 0; - String8 to_decode = raw_code; - - for (; to_decode.size > 0; ) { - Temp temp = temp_begin(scratch.arena); - - // decode instruction - U64 addr = image_base + sect_off + decode_off; - DisasmResult disasm_result = disasm_next_instruction(temp.arena, machine, addr, to_decode); - - // format instruction bytes - String8 bytes; - { - U64 bytes_size = 0; - for (U64 i = 0; i < disasm_result.size; ++i) { - bytes_size += raddbg_snprintf(bytes_buffer + bytes_size, bytes_buffer_max-bytes_size, "%s%02x", i > 0 ? " " : "", to_decode.str[i]); - } - bytes = str8(bytes_buffer, bytes_size); - } - - // print address marker - if (marker_cursor < marker_count) { - Marker *m = &markers[marker_cursor]; - // NOTE: markers must be sorted on address - if (decode_off <= m->off && m->off < decode_off + disasm_result.size) { - if (m->off != decode_off) { - U64 off = m->off - decode_off; - coff_printf("; %S+%#llx", m->string, addr); - } else { - coff_printf("; %S", m->string); - } - marker_cursor += 1; - } - } - - // print final line - coff_printf("%#08x: %-32S %S", addr, bytes, disasm_result.text); - - // advance - to_decode = str8_skip(to_decode, disasm_result.size); - decode_off += disasm_result.size; - - temp_end(temp); - } - - scratch_end(scratch); -} - -//////////////////////////////// -//~ Raw Data - -internal void -format_raw_data(Arena *arena, - String8List *out, - String8 indent, - U64 bytes_per_row, - U64 marker_count, - Marker *markers, - String8 raw_data) -{ - AssertAlways(bytes_per_row > 0); - - U8 temp_buffer[1024]; - - String8 to_format = raw_data; - for (; to_format.size > 0; ) { - String8 raw_row = str8_prefix(to_format, bytes_per_row); - - U64 temp_cursor = 0; - - // offset - U64 offset = (U64)(raw_row.str-raw_data.str); - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08x: ", offset); - - // hex - for (U64 i = 0; i < raw_row.size; ++i) { - U8 b = raw_row.str[i]; - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%s%02x", i>0 ? " " : "", b); - } - U64 hex_indent_size = (bytes_per_row - raw_row.size) * 3; - MemorySet(temp_buffer+temp_cursor, ' ', hex_indent_size); - temp_cursor += hex_indent_size; - - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer) - temp_cursor, " "); - - // ascii - for (U64 i = 0; i < raw_row.size; ++i) { - U8 b = raw_row.str[i]; - U8 c = b; - if (c < ' ' || c > '~') { - c = '.'; - } - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%c", c); - } - - coff_printf("%.*s", temp_cursor, temp_buffer); - - // advance - to_format = str8_skip(to_format, bytes_per_row); - } -} - -//////////////////////////////// -//~ COFF - -internal String8 -coff_format_time_stamp(Arena *arena, COFF_TimeStamp time_stamp) -{ - String8 result; - if (time_stamp == 0) { - result = str8_lit("0"); - } else if (time_stamp >= max_U32) { - result = str8_lit("-1"); - } else { - DateTime dt = date_time_from_unix_time(time_stamp); - result = push_date_time_string(arena, &dt); - } - return result; -} - -internal void -coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 time_stamp = coff_format_time_stamp(scratch.arena, header.time_stamp); - - coff_printf("Name: %S" , header.name ); - coff_printf("Time Stamp: %S" , time_stamp ); - coff_printf("User ID: %u" , header.user_id ); - coff_printf("Group ID: %u" , header.group_id); - coff_printf("Mode: %S" , header.mode ); - coff_printf("Data: [%#llx-%#llx)", header.data_range.min, header.data_range.max); - - scratch_end(scratch); -} - -internal void -coff_format_section_table(Arena *arena, - String8List *out, - String8 indent, - String8 raw_data, - U64 string_table_off, - COFF_Symbol32Array symbols, - U64 sect_count, - COFF_SectionHeader *sect_headers) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 *symlinks = push_array(scratch.arena, String8, sect_count); - for (U64 i = 0; i < symbols.count; ++i) { - COFF_Symbol32 *symbol = symbols.v+i; - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); - if (interp == COFF_SymbolValueInterp_REGULAR && - symbol->aux_symbol_count == 0 && - (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC)) { - if (symbol->section_number > 0 && symbol->section_number <= symbols.count) { - COFF_SectionHeader *header = sect_headers+(symbol->section_number-1); - if (header->flags & COFF_SectionFlag_LNK_COMDAT) { - symlinks[symbol->section_number-1] = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); - } - } - } - i += symbol->aux_symbol_count; - } - - if (sect_count) { - coff_printf("# Section Table"); - coff_indent(); - - coff_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s", - "No.", - "Name", - "VirtSize", - "VirtOff", - "FileSize", - "FileOff", - "RelocOff", - "LinesOff", - "RelocCnt", - "LineCnt", - "Align", - "Flags", - "Symlink"); - - for (U64 i = 0; i < sect_count; ++i) { - COFF_SectionHeader *header = sect_headers+i; - - String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name)); - String8 full_name = coff_name_from_section_header(header, raw_data, string_table_off); - - String8 align; - { - U64 align_size = coff_align_size_from_section_flags(header->flags); - align = push_str8f(scratch.arena, "%u", align_size); - } - - String8 flags; - { - String8List mem_flags = {0}; - if (header->flags & COFF_SectionFlag_MEM_READ) { - str8_list_pushf(scratch.arena, &mem_flags, "r"); - } - if (header->flags & COFF_SectionFlag_MEM_WRITE) { - str8_list_pushf(scratch.arena, &mem_flags, "w"); - } - if (header->flags & COFF_SectionFlag_MEM_EXECUTE) { - str8_list_pushf(scratch.arena, &mem_flags, "x"); - } - - String8List cnt_flags = {0}; - if (header->flags & COFF_SectionFlag_CNT_CODE) { - str8_list_pushf(scratch.arena, &cnt_flags, "c"); - } - if (header->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &cnt_flags, "d"); - } - if (header->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &cnt_flags, "u"); - } - - String8List mem_extra_flags = {0}; - if (header->flags & COFF_SectionFlag_MEM_SHARED) { - str8_list_pushf(scratch.arena, &mem_flags, "s"); - } - if (header->flags & COFF_SectionFlag_MEM_16BIT) { - str8_list_pushf(scratch.arena, &mem_extra_flags, "h"); - } - if (header->flags & COFF_SectionFlag_MEM_LOCKED) { - str8_list_pushf(scratch.arena, &mem_extra_flags, "l"); - } - if (header->flags & COFF_SectionFlag_MEM_DISCARDABLE) { - str8_list_pushf(scratch.arena, &mem_extra_flags, "d"); - } - if (header->flags & COFF_SectionFlag_MEM_NOT_CACHED) { - str8_list_pushf(scratch.arena, &mem_extra_flags, "c"); - } - if (header->flags & COFF_SectionFlag_MEM_NOT_PAGED) { - str8_list_pushf(scratch.arena, &mem_extra_flags, "p"); - } - - String8List lnk_flags = {0}; - if (header->flags & COFF_SectionFlag_LNK_REMOVE) { - str8_list_pushf(scratch.arena, &lnk_flags, "r"); - } - if (header->flags & COFF_SectionFlag_LNK_COMDAT) { - str8_list_pushf(scratch.arena, &lnk_flags, "c"); - } - if (header->flags & COFF_SectionFlag_LNK_OTHER) { - str8_list_pushf(scratch.arena, &lnk_flags, "o"); - } - if (header->flags & COFF_SectionFlag_LNK_INFO) { - str8_list_pushf(scratch.arena, &lnk_flags, "i"); - } - if (header->flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { - str8_list_pushf(scratch.arena, &lnk_flags, "f"); - } - - String8List other_flags = {0}; - if (header->flags & COFF_SectionFlag_TYPE_NO_PAD) { - str8_list_pushf(scratch.arena, &other_flags, "n"); - } - if (header->flags & COFF_SectionFlag_GPREL) { - str8_list_pushf(scratch.arena, &other_flags, "g"); - } - - String8 mem = str8_list_join(scratch.arena, &mem_flags, 0); - String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0); - String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0); - String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0); - String8 oth = str8_list_join(scratch.arena, &other_flags, 0); - - String8List f = {0}; - str8_list_push(scratch.arena, &f, mem); - str8_list_push(scratch.arena, &f, cnt); - str8_list_push(scratch.arena, &f, ext); - str8_list_push(scratch.arena, &f, lnk); - str8_list_push(scratch.arena, &f, oth); - - flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") }); - - if (!flags.size) { - flags = str8_lit("none"); - } - } - - String8List l = {0}; - str8_list_pushf(scratch.arena, &l, "%-4x", i+1 ); - str8_list_pushf(scratch.arena, &l, "%-8S", name ); - str8_list_pushf(scratch.arena, &l, "%08x", header->vsize ); - str8_list_pushf(scratch.arena, &l, "%08x", header->voff ); - str8_list_pushf(scratch.arena, &l, "%08x", header->fsize ); - str8_list_pushf(scratch.arena, &l, "%08x", header->foff ); - str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff); - str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff ); - str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count); - str8_list_pushf(scratch.arena, &l, "%08x", header->line_count ); - str8_list_pushf(scratch.arena, &l, "%-5S", align ); - str8_list_pushf(scratch.arena, &l, "%-10S", flags ); - if (symlinks[i].size > 0) { - str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]); - } else { - str8_list_pushf(scratch.arena, &l, "[no symlink]"); - } - - String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), }); - coff_printf("%S", line); - - if (full_name.size != name.size) { - coff_indent(); - coff_printf("Full Name: %S", full_name); - coff_unindent(); - } - } - - coff_newline(); - coff_printf("Flags:"); - coff_indent(); - coff_printf("r = MEM_READ w = MEM_WRITE x = MEM_EXECUTE"); - coff_printf("c = CNT_CODE d = INITIALIZED_DATA u = UNINITIALIZED_DATA"); - coff_printf("s = MEM_SHARED h = MEM_16BIT l = MEM_LOCKED d = MEM_DISCARDABLE c = MEM_NOT_CACHED p = MEM_NOT_PAGED"); - coff_printf("r = LNK_REMOVE c = LNK_COMDAT o = LNK_OTHER i = LNK_INFO f = LNK_NRELOC_OVFL"); - coff_printf("g = GPREL n = TYPE_NO_PAD"); - coff_unindent(); - - coff_unindent(); - coff_newline(); - } - - scratch_end(scratch); -} - -internal void -coff_disasm_sections(Arena *arena, - String8List *out, - String8 indent, - String8 raw_data, - COFF_MachineType machine, - U64 image_base, - B32 is_obj, - MarkerArray *section_markers, - U64 section_count, - COFF_SectionHeader *sections) -{ - if (section_count) { - for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { - COFF_SectionHeader *sect = sections+sect_idx; - if (sect->flags & COFF_SectionFlag_CNT_CODE) { - U64 sect_off = is_obj ? sect->foff : sect->voff; - U64 sect_size = is_obj ? sect->fsize : sect->vsize; - String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); - MarkerArray markers = section_markers[sect_idx]; - - coff_printf("# Disassembly [Section No. %#llx]", (sect_idx+1)); - coff_indent(); - format_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); - coff_unindent(); - } - } - } -} - -internal void -coff_raw_data_sections(Arena *arena, - String8List *out, - String8 indent, - String8 raw_data, - B32 is_obj, - MarkerArray *section_markers, - U64 section_count, - COFF_SectionHeader *sections) -{ - if (section_count) { - for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { - COFF_SectionHeader *sect = sections+sect_idx; - if (sect->fsize > 0) { - U64 sect_size = is_obj ? sect->fsize : sect->vsize; - String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); - MarkerArray markers = section_markers[sect_idx]; - - coff_printf("# Raw Data [Section No. %#llx]", (sect_idx+1)); - coff_indent(); - format_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); - coff_unindent(); - coff_newline(); - } - } - } -} - -internal void -coff_format_relocs(Arena *arena, - String8List *out, - String8 indent, - String8 raw_data, - U64 string_table_off, - COFF_MachineType machine, - U64 sect_count, - COFF_SectionHeader *sect_headers, - COFF_Symbol32Array symbols) -{ - Temp scratch = scratch_begin(&arena, 1); - - B32 print_header = 1; - - for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) { - COFF_SectionHeader *sect_header = sect_headers+sect_idx; - COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header); - - if (reloc_info.count) { - if (print_header) { - print_header = 0; - coff_printf("# Relocations"); - coff_indent(); - } - - coff_printf("## Section %llx", sect_idx); - coff_indent(); - - coff_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName"); - - for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) { - COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx; - String8 type = coff_string_from_reloc(machine, reloc->type); - U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type); - - U64 apply_foff = sect_header->foff + reloc->apply_off; - if (apply_foff + apply_size > raw_data.size) { - coff_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx); - break; - } - - U64 raw_apply; - AssertAlways(apply_size <= sizeof(raw_apply)); - MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size); - S64 apply = extend_sign64(raw_apply, apply_size); - - if (reloc->isymbol > symbols.count) { - coff_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx); - break; - } - - COFF_Symbol32 *symbol = symbols.v+reloc->isymbol; - String8 symbol_name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); - - String8List line = {0}; - str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx ); - str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off); - str8_list_pushf(scratch.arena, &line, "%-16S", type ); - str8_list_pushf(scratch.arena, &line, "%016x", apply ); - str8_list_pushf(scratch.arena, &line, "%S", symbol_name ); - - String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")}); - coff_printf("%S", l); - } - - coff_unindent(); - } - } - - if (!print_header) { - coff_unindent(); - } - coff_newline(); - - scratch_end(scratch); -} - -internal void -coff_format_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols) -{ - Temp scratch = scratch_begin(&arena, 1); - - if (symbols.count) { - coff_printf("# Symbol Table"); - coff_indent(); - - coff_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s", - "No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name"); - - for (U64 i = 0; i < symbols.count; ++i) { - COFF_Symbol32 *symbol = &symbols.v[i]; - String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); - String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb); - String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb); - String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class); - String8 section_number; - switch (symbol->section_number) { - case COFF_SYMBOL_UNDEFINED_SECTION: section_number = str8_lit("UNDEF"); break; - case COFF_SYMBOL_ABS_SECTION: section_number = str8_lit("ABS"); break; - case COFF_SYMBOL_DEBUG_SECTION: section_number = str8_lit("DEBUG"); break; - default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break; - } - - String8List line = {0}; - str8_list_pushf(scratch.arena, &line, "%-4x", i ); - str8_list_pushf(scratch.arena, &line, "%08x", symbol->value ); - str8_list_pushf(scratch.arena, &line, "%-10S", section_number ); - str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count); - str8_list_pushf(scratch.arena, &line, "%-4S", msb ); - str8_list_pushf(scratch.arena, &line, "%-4S", lsb ); - str8_list_pushf(scratch.arena, &line, "%-16S", storage_class ); - str8_list_pushf(scratch.arena, &line, "%S", name ); - - String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")}); - coff_printf("%S", l); - - coff_indent(); - for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) { - void *raw_aux = &symbols.v[k]; - switch (symbol->storage_class) { - case COFF_SymStorageClass_EXTERNAL: { - COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k]; - coff_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x", - func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func); - } break; - case COFF_SymStorageClass_FUNCTION: { - COFF_SymbolFunc *func = raw_aux; - coff_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func); - } break; - case COFF_SymStorageClass_WEAK_EXTERNAL: { - COFF_SymbolWeakExt *weak = raw_aux; - String8 type = coff_string_from_weak_ext_type(weak->characteristics); - coff_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type); - } break; - case COFF_SymStorageClass_FILE: { - COFF_SymbolFile *file = raw_aux; - String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name)); - coff_printf("Name %S", name); - } break; - case COFF_SymStorageClass_STATIC: { - COFF_SymbolSecDef *sd = raw_aux; - String8 selection = coff_string_from_selection(sd->selection); - U32 number = sd->number_lo; - if (is_big_obj) { - number |= (U32)sd->number_hi << 16; - } - if (number) { - coff_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S", - sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection); - } else { - coff_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x", - sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum); - } - } break; - default: { - coff_printf("???"); - } break; - } - } - - i += symbol->aux_symbol_count; - coff_unindent(); - } - - coff_unindent(); - coff_newline(); - } - - scratch_end(scratch); -} - -internal void -coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, header->time_stamp); - String8 machine = coff_string_from_machine_type(header->machine); - - coff_printf("# Big Obj"); - coff_indent(); - - coff_printf("Time Stamp: %S", time_stamp ); - coff_printf("Machine: %S", machine ); - coff_printf("Section Count: %u", header->section_count ); - coff_printf("Symbol Table: %#x", header->symbol_table_foff); - coff_printf("Symbol Count: %u", header->symbol_count ); - - coff_unindent(); - - scratch_end(scratch); -} - -internal void -coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, header->time_stamp); - String8 machine = coff_string_from_machine_type(header->machine); - String8 flags = coff_string_from_flags(scratch.arena, header->flags); - - coff_printf("# COFF Header"); - coff_indent(); - coff_printf("Time Stamp: %S", time_stamp ); - coff_printf("Machine: %S", machine ); - coff_printf("Section Count: %u", header->section_count ); - coff_printf("Symbol Table: %#x", header->symbol_table_foff ); - coff_printf("Symbol Count: %u", header->symbol_count ); - coff_printf("Optional Header Size: %m", header->optional_header_size); - coff_printf("Flags: %S", flags ); - coff_unindent(); - - scratch_end(scratch); -} - -internal void -coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 machine = coff_string_from_machine_type(header->machine); - String8 time_stamp = coff_format_time_stamp(scratch.arena, header->time_stamp); - - coff_printf("# Import"); - coff_indent(); - coff_printf("Version: %u", header->version ); - coff_printf("Machine: %S", machine ); - coff_printf("Time Stamp: %S", time_stamp ); - coff_printf("Data Size: %m", header->data_size); - coff_printf("Hint: %u", header->hint ); - coff_printf("Type: %u", header->type ); - coff_printf("Name Type: %u", header->name_type); - coff_printf("Function: %S", header->func_name); - coff_printf("DLL: %S", header->dll_name ); - coff_unindent(); - - scratch_end(scratch); -} - -internal void -coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, Coffdump_Option opts) -{ - Temp scratch = scratch_begin(&arena, 1); - - COFF_HeaderBigObj *big_obj = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(COFF_HeaderBigObj)); - COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sizeof(COFF_HeaderBigObj), sizeof(COFF_SectionHeader)*big_obj->section_count); - U64 string_table_off = big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count; - COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); - - if (opts & Coffdump_Option_Headers) { - coff_format_big_obj_header(arena, out, indent, big_obj); - coff_newline(); - } - - if (opts & Coffdump_Option_Sections) { - Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count); - Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count); - - if (sect_headers_range.max > raw_data.size) { - coff_errorf("not enough bytes to read big obj section headers"); - goto exit; - } - if (big_obj->symbol_count) { - if (symbols_range.max > raw_data.size) { - coff_errorf("not enough bytes to read big obj symbol table"); - goto exit; - } - if (contains_1u64(symbols_range, sect_headers_range.min) || - contains_1u64(symbols_range, sect_headers_range.max)) { - coff_errorf("section headers and symbol table ranges overlap"); - goto exit; - } - } - - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); - coff_newline(); - } - - if (opts & Coffdump_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); - coff_newline(); - } - - if (opts & Coffdump_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); - coff_newline(); - } - -exit:; - scratch_end(scratch); -} - -internal void -coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, Coffdump_Option opts) -{ - Temp scratch = scratch_begin(&arena, 1); - - COFF_Header *header = (COFF_Header *)raw_data.str; - COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); - U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; - COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); - - if (opts & Coffdump_Option_Headers) { - coff_format_header(arena, out, indent, header); - coff_newline(); - } - - if (opts & Coffdump_Option_Sections) { - Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count); - Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count); - - if (sect_headers_range.max > raw_data.size) { - coff_errorf("not enough bytes to read obj section headers"); - goto exit; - } - if (header->symbol_count) { - if (symbols_range.max > raw_data.size) { - coff_errorf("not enough bytes to read obj symbol table"); - goto exit; - } - if (contains_1u64(symbols_range, sect_headers_range.min) || - contains_1u64(symbols_range, sect_headers_range.max)) { - coff_errorf("section headers and symbol table ranges overlap"); - goto exit; - } - } - - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); - coff_newline(); - } - - if (opts & Coffdump_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); - coff_newline(); - } - - if (opts & Coffdump_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); - coff_newline(); - } - - MarkerArray *section_markers = 0; - if (opts & (Coffdump_Option_Disasm|Coffdump_Option_Rawdata)) { - section_markers = section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, header->section_count, symbols); - } - - if (opts & Coffdump_Option_Rawdata) { - coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, sections); - } - - if (opts & Coffdump_Option_Disasm) { - coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, sections); - coff_newline(); - } - -exit:; - scratch_end(scratch); -} - -internal void -coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, Coffdump_Option opts) -{ - Temp scratch = scratch_begin(&arena, 1); - - COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive); - - if (archive_parse.error.size) { - coff_errorf("%S", archive_parse.error); - return; - } - - COFF_ArchiveFirstMember first_member = archive_parse.first_member; - { - coff_printf("# First Header"); - coff_indent(); - - coff_printf("Symbol Count: %u", first_member.symbol_count); - coff_printf("String Table Size: %M", first_member.string_table.size); - - coff_printf("Members:"); - coff_indent(); - - String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0); - - if (string_table.node_count == first_member.member_offset_count) { - String8Node *string_n = string_table.first; - - for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) { - U32 offset = from_be_u32(first_member.member_offsets[i]); - coff_printf("[%4u] 0x%08x %S", i, offset, string_n->string); - } - } else { - coff_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count); - } - - coff_unindent(); - coff_unindent(); - coff_newline(); - } - - if (archive_parse.has_second_header) { - COFF_ArchiveSecondMember second_member = archive_parse.second_member; - - coff_printf("# Second Header"); - coff_indent(); - - coff_printf("Member Count: %u", second_member.member_count); - coff_printf("Symbol Count: %u", second_member.symbol_count); - coff_printf("String Table Size: %M", second_member.string_table.size); - - String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0); - - coff_printf("Members:"); - coff_indent(); - if (second_member.symbol_index_count == second_member.symbol_count) { - String8Node *string_n = string_table.first; - for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) { - U16 symbol_number = second_member.symbol_indices[i]; - if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) { - U16 symbol_idx = symbol_number - 1; - U32 member_offset = second_member.member_offsets[i]; - coff_printf("[%4u] 0x%08x %S", i, member_offset, string_n->string); - } else { - coff_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number); - break; - } - } - } else { - coff_errorf("Symbol index count %u doesn't match symbol count %u", - second_member.symbol_index_count, second_member.symbol_count); - } - coff_unindent(); - - coff_unindent(); - coff_newline(); - } - - if (archive_parse.has_long_names && opts & Coffdump_Option_LongNames) { - coff_printf("# Long Names"); - coff_indent(); - - String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0); - U64 name_idx = 0; - for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) { - U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str); - coff_printf("[%-4u] 0x%08x %S", name_idx, offset, name_n->string); - } - - coff_unindent(); - coff_newline(); - } - - U64 member_offset_count = 0; - U32 *member_offsets = 0; - if (archive_parse.has_second_header) { - member_offset_count = archive_parse.second_member.member_offset_count; - member_offsets = archive_parse.second_member.member_offsets; - } else { - HashTable *ht = hash_table_init(scratch.arena, 0x1000); - for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) { - U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]); - if (!hash_table_search_u32(ht, member_offset)) { - hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0); - } - } - member_offset_count = ht->count; - member_offsets = keys_from_hash_table_u32(scratch.arena, ht); - radsort(member_offsets, member_offset_count, u32_is_before); - } - - coff_printf("# Members"); - coff_indent(); - - for (U64 i = 0; i < member_offset_count; ++i) { - U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size; - U64 member_offset = member_offsets[i]; - String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset)); - COFF_ArchiveMember member = coff_archive_member_from_data(raw_member); - COFF_DataType member_type = coff_data_type_from_data(member.data); - - coff_printf("Member @ %#llx", member_offset); - coff_indent(); - - if (opts & Coffdump_Option_Headers) { - coff_format_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); - coff_newline(); - } - - switch (member_type) { - case COFF_DataType_BIG_OBJ: { - coff_format_big_obj(arena, out, indent, member.data, opts); - } break; - case COFF_DataType_OBJ: { - coff_format_obj(arena, out, indent, member.data, opts); - } break; - case COFF_DataType_IMPORT: { - if (opts & Coffdump_Option_Headers) { - COFF_ImportHeader header = {0}; - U64 parse_size = coff_parse_archive_import(member.data, 0, &header); - if (parse_size) { - coff_format_import(arena, out, indent, &header); - } else { - coff_errorf("not enough bytes to parse import header"); - } - } - } break; - case COFF_DataType_NULL: { - coff_errorf("unknown member format", member_offset); - } break; - } - - coff_unindent(); - coff_newline(); - } - - coff_unindent(); - - scratch_end(scratch); -} - -//////////////////////////////// -//~ MSVC CRT - -internal String8 -mscrt_format_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List adj_list = {0}; - if (adjectives & MSCRT_EhHandlerTypeFlag_IsConst) { - str8_list_pushf(scratch.arena, &adj_list, "Const"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsVolatile) { - str8_list_pushf(scratch.arena, &adj_list, "Volatile"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsUnaligned) { - str8_list_pushf(scratch.arena, &adj_list, "Unaligned"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsReference) { - str8_list_pushf(scratch.arena, &adj_list, "Reference"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsResumable) { - str8_list_pushf(scratch.arena, &adj_list, "Resumable"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsStdDotDot) { - str8_list_pushf(scratch.arena, &adj_list, "StdDotDot"); - } - if (adjectives & MSCRT_EhHandlerTypeFlag_IsComplusEH) { - str8_list_pushf(scratch.arena, &adj_list, "ComplusEH"); - } - String8 result = str8_list_join(arena, &adj_list, &(StringJoin){.sep=str8_lit(", ")}); - scratch_end(scratch); - return result; -} - -internal void -mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler) -{ - String8 catch_line = str8_zero(); // TODO: syms_line_for_voff(scratch.arena, group, handler->catch_handler_voff); - String8 adjectives_str = mscrt_format_eh_adjectives(arena, handler->adjectives); - coff_printf("Adjectives: %S", adjectives_str, handler->adjectives); - coff_printf("Descriptor: %#x", handler->descriptor_voff); - coff_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); - coff_printf("Catch Handler: %#x %S", handler->catch_handler_voff, catch_line); - coff_printf("Delta to FP Handler: %#x", handler->fp_distance); -} - -//////////////////////////////// -//~ PE - -internal B32 -is_pe(String8 raw_data) -{ - PE_DosHeader header = {0}; - str8_deserial_read_struct(raw_data, 0, &header); - return header.magic == PE_DOS_MAGIC; -} - -internal void -pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) -{ - Temp scratch = scratch_begin(&arena, 1); - coff_printf("# Data Directories"); - coff_indent(); - for (U64 i = 0; i < count; ++i) { - String8 dir_name; - if (i < PE_DataDirectoryIndex_COUNT) { - dir_name = pe_string_from_data_directory_index(i); - } else { - dir_name = push_str8f(scratch.arena, "%#x", i); - } - coff_printf("%-16S [%08x-%08x)", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size); - } - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); - String8 dll_chars = pe_string_from_dll_characteristics(scratch.arena, opt_header->dll_characteristics); - - coff_printf("# PE Optional Header 32"); - coff_indent(); - coff_printf("Magic: %#x", opt_header->magic); - coff_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); - coff_printf("Size of code: %m", opt_header->sizeof_code); - coff_printf("Size of inited data: %m", opt_header->sizeof_inited_data); - coff_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); - coff_printf("Entry point: %#x", opt_header->entry_point_va); - coff_printf("Code base: %#x", opt_header->code_base); - coff_printf("Data base: %#x", opt_header->data_base); - coff_printf("Image base: %#x", opt_header->image_base); - coff_printf("Section align: %#x", opt_header->section_alignment); - coff_printf("File align: %#x", opt_header->file_alignment); - coff_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); - coff_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); - coff_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); - coff_printf("Win32 version: %u", opt_header->win32_version_value); - coff_printf("Size of image: %m", opt_header->sizeof_image); - coff_printf("Size of headers: %m", opt_header->sizeof_headers); - coff_printf("Checksum: %#x", opt_header->check_sum); - coff_printf("Subsystem: %S", subsystem); - coff_printf("DLL Characteristics: %S", dll_chars); - coff_printf("Stack reserve: %m", opt_header->sizeof_stack_reserve); - coff_printf("Stack commit: %m", opt_header->sizeof_stack_commit); - coff_printf("Heap reserve: %m", opt_header->sizeof_heap_reserve); - coff_printf("Heap commit: %m", opt_header->sizeof_heap_commit); - coff_printf("Loader flags: %#x", opt_header->loader_flags); - coff_printf("RVA and offset count: %u", opt_header->data_dir_count); - coff_newline(); - - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); - coff_newline(); - - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); - String8 dll_chars = pe_string_from_dll_characteristics(scratch.arena, opt_header->dll_characteristics); - - coff_printf("# PE Optional Header 32+"); - coff_indent(); - coff_printf("Magic: %#x", opt_header->magic); - coff_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); - coff_printf("Size of code: %m", opt_header->sizeof_code); - coff_printf("Size of inited data: %m", opt_header->sizeof_inited_data); - coff_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); - coff_printf("Entry point: %#x", opt_header->entry_point_va); - coff_printf("Code base: %#x", opt_header->code_base); - coff_printf("Image base: %#llx", opt_header->image_base); - coff_printf("Section align: %#x", opt_header->section_alignment); - coff_printf("File align: %#x", opt_header->file_alignment); - coff_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); - coff_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); - coff_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); - coff_printf("Win32 version: %u", opt_header->win32_version_value); - coff_printf("Size of image: %m", opt_header->sizeof_image); - coff_printf("Size of headers: %m", opt_header->sizeof_headers); - coff_printf("Checksum: %#x", opt_header->check_sum); - coff_printf("Subsystem: %S", subsystem); - coff_printf("DLL Characteristics: %S", dll_chars); - coff_printf("Stack reserve: %M", opt_header->sizeof_stack_reserve); - coff_printf("Stack commit: %M", opt_header->sizeof_stack_commit); - coff_printf("Heap reserve: %M", opt_header->sizeof_heap_reserve); - coff_printf("Heap commit: %M", opt_header->sizeof_heap_commit); - coff_printf("Loader flags: %#x", opt_header->loader_flags); - coff_printf("RVA and offset count: %u", opt_header->data_dir_count); - coff_newline(); - - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); - coff_newline(); - - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, lc->time_stamp); - String8 global_flag_clear = pe_string_from_global_flags(scratch.arena, lc->global_flag_clear); - String8 global_flag_set = pe_string_from_global_flags(scratch.arena, lc->global_flag_set); - - coff_printf("# Load Config 32"); - coff_indent(); - - coff_printf("Size: %m", lc->size); - coff_printf("Time stamp: %#x (%S)", lc->time_stamp, time_stamp); - coff_printf("Version: %u.%u", lc->major_version, lc->minor_version); - coff_printf("Global flag clear: %#x %S", global_flag_clear); - coff_printf("Global flag set: %#x %S", global_flag_set); - coff_printf("Critical section timeout: %u", lc->critical_section_timeout); - coff_printf("Decommit free block threshold: %#x", lc->decommit_free_block_threshold); - coff_printf("Decommit total free threshold: %#x", lc->decommit_total_free_threshold); - coff_printf("Lock prefix table: %#x", lc->lock_prefix_table); - coff_printf("Maximum alloc size: %m", lc->maximum_allocation_size); - coff_printf("Virtual memory threshold: %m", lc->virtual_memory_threshold); - coff_printf("Process affinity mask: %#x", lc->process_affinity_mask); - coff_printf("Process heap flags: %#x", lc->process_heap_flags); - coff_printf("CSD version: %u", lc->csd_version); - coff_printf("Edit list: %#x", lc->edit_list); - coff_printf("Security Cookie: %#x", lc->security_cookie); - if (lc->size < OffsetOf(PE_LoadConfig64, seh_handler_table)) { - goto exit; - } - coff_newline(); - - coff_printf("SEH Handler Table: %#x", lc->seh_handler_table); - coff_printf("SEH Handler Count: %u", lc->seh_handler_count); - if (lc->size < OffsetOf(PE_LoadConfig64, guard_cf_check_func_ptr)) { - goto exit; - } - coff_newline(); - - coff_printf("Guard CF Check Function: %#x", lc->guard_cf_check_func_ptr); - coff_printf("Guard CF Dispatch Function: %#x", lc->guard_cf_dispatch_func_ptr); - coff_printf("Guard CF Function Table: %#x", lc->guard_cf_func_table); - coff_printf("Guard CF Function Count: %u", lc->guard_cf_func_count); - coff_printf("Guard Flags: %#x", lc->guard_flags); - if (lc->size < OffsetOf(PE_LoadConfig64, code_integrity)) { - goto exit; - } - coff_newline(); - - coff_printf("Code integrity: { Flags = %#x, Catalog = %#x, Catalog Offset = %#x }", - lc->code_integrity.flags, lc->code_integrity.catalog, lc->code_integrity.catalog_offset); - coff_printf("Guard address taken IAT entry table: %#x", lc->guard_address_taken_iat_entry_table); - coff_printf("Guard address taken IAT entry count: %u", lc->guard_address_taken_iat_entry_count); - coff_printf("Guard long jump target table: %#x", lc->guard_long_jump_target_table); - coff_printf("Guard long jump target count: %u", lc->guard_long_jump_target_count); - coff_printf("Dynamic value reloc table: %#x", lc->dynamic_value_reloc_table); - coff_printf("CHPE Metadata ptr: %#x", lc->chpe_metadata_ptr); - coff_printf("Guard RF failure routine: %#x", lc->guard_rf_failure_routine); - coff_printf("Guard RF failure routine func ptr: %#x", lc->guard_rf_failure_routine_func_ptr); - coff_printf("Dynamic value reloc section: %#x", lc->dynamic_value_reloc_table_section); - coff_printf("Dynamic value reloc section offset: %#x", lc->dynamic_value_reloc_table_offset); - coff_printf("Guard RF verify SP func ptr: %#x", lc->guard_rf_verify_stack_pointer_func_ptr); - coff_printf("Hot patch table offset: %#x", lc->hot_patch_table_offset); - if (lc->size < OffsetOf(PE_LoadConfig64, enclave_config_ptr)) { - goto exit; - } - coff_newline(); - - coff_printf("Enclave config ptr: %#x", lc->enclave_config_ptr); - coff_printf("Volatile metadata ptr: %#x", lc->volatile_metadata_ptr); - coff_printf("Guard EH continuation table: %#x", lc->guard_eh_continue_table); - coff_printf("Guard EH continuation count: %u", lc->guard_eh_continue_count); - coff_printf("Guard XFG check func ptr: %#x", lc->guard_xfg_check_func_ptr); - coff_printf("Guard XFG dispatch func ptr: %#x", lc->guard_xfg_dispatch_func_ptr); - coff_printf("Guard XFG table dispatch func ptr: %#x", lc->guard_xfg_table_dispatch_func_ptr); - coff_printf("Cast guard OS determined failure mode: %#x", lc->cast_guard_os_determined_failure_mode); - coff_newline(); - -exit:; - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, lc->time_stamp); - String8 global_flag_clear = pe_string_from_global_flags(scratch.arena, lc->global_flag_clear); - String8 global_flag_set = pe_string_from_global_flags(scratch.arena, lc->global_flag_set); - - coff_printf("# Load Config 64"); - coff_indent(); - - coff_printf("Size: %m", lc->size); - coff_printf("Time stamp: %#x (%S)", lc->time_stamp, time_stamp); - coff_printf("Version: %u.%u", lc->major_version, lc->minor_version); - coff_printf("Global flag clear: %#x %S", lc->global_flag_clear, global_flag_clear); - coff_printf("Global flag set: %#x %S", lc->global_flag_set, global_flag_set); - coff_printf("Critical section timeout: %u", lc->critical_section_timeout); - coff_printf("Decommit free block threshold: %#llx", lc->decommit_free_block_threshold); - coff_printf("Decommit total free threshold: %#llx", lc->decommit_total_free_threshold); - coff_printf("Lock prefix table: %#llx", lc->lock_prefix_table); - coff_printf("Maximum alloc size: %M", lc->maximum_allocation_size); - coff_printf("Virtual memory threshold: %M", lc->virtual_memory_threshold); - coff_printf("Process affinity mask: %#x", lc->process_affinity_mask); - coff_printf("Process heap flags: %#x", lc->process_heap_flags); - coff_printf("CSD version: %u", lc->csd_version); - coff_printf("Edit list: %#llx", lc->edit_list); - coff_printf("Security Cookie: %#llx", lc->security_cookie); - if (lc->size < OffsetOf(PE_LoadConfig64, seh_handler_table)) { - goto exit; - } - coff_newline(); - - coff_printf("SEH Handler Table: %#llx", lc->seh_handler_table); - coff_printf("SEH Handler Count: %llu", lc->seh_handler_count); - if (lc->size < OffsetOf(PE_LoadConfig64, guard_cf_check_func_ptr)) { - goto exit; - } - coff_newline(); - - coff_printf("Guard CF Check Function: %#llx", lc->guard_cf_check_func_ptr); - coff_printf("Guard CF Dispatch Function: %#llx", lc->guard_cf_dispatch_func_ptr); - coff_printf("Guard CF Function Table: %#llx", lc->guard_cf_func_table); - coff_printf("Guard CF Function Count: %llu", lc->guard_cf_func_count); - coff_printf("Guard Flags: %#x", lc->guard_flags); - if (lc->size < OffsetOf(PE_LoadConfig64, code_integrity)) { - goto exit; - } - coff_newline(); - - coff_printf("Code integrity: { Flags = %#x, Catalog = %#x, Catalog Offset = %#x }", - lc->code_integrity.flags, lc->code_integrity.catalog, lc->code_integrity.catalog_offset); - coff_printf("Guard address taken IAT entry table: %#llx", lc->guard_address_taken_iat_entry_table); - coff_printf("Guard address taken IAT entry count: %llu", lc->guard_address_taken_iat_entry_count); - coff_printf("Guard long jump target table: %#llx", lc->guard_long_jump_target_table); - coff_printf("Guard long jump target count: %llu", lc->guard_long_jump_target_count); - coff_printf("Dynamic value reloc table: %#llx", lc->dynamic_value_reloc_table); - coff_printf("CHPE Metadata ptr: %#llx", lc->chpe_metadata_ptr); - coff_printf("Guard RF failure routine: %#llx", lc->guard_rf_failure_routine); - coff_printf("Guard RF failure routine func ptr: %#llx", lc->guard_rf_failure_routine_func_ptr); - coff_printf("Dynamic value reloc section: %#llx", lc->dynamic_value_reloc_table_section); - coff_printf("Dynamic value reloc section offset: %#llx", lc->dynamic_value_reloc_table_offset); - coff_printf("Guard RF verify SP func ptr: %#llx", lc->guard_rf_verify_stack_pointer_func_ptr); - coff_printf("Hot patch table offset: %#llx", lc->hot_patch_table_offset); - if (lc->size < OffsetOf(PE_LoadConfig64, enclave_config_ptr)) { - goto exit; - } - coff_newline(); - - coff_printf("Enclave config ptr: %#llx", lc->enclave_config_ptr); - coff_printf("Volatile metadata ptr: %#llx", lc->volatile_metadata_ptr); - coff_printf("Guard EH continuation table: %#llx", lc->guard_eh_continue_table); - coff_printf("Guard EH continuation count: %llu", lc->guard_eh_continue_count); - coff_printf("Guard XFG check func ptr: %#llx", lc->guard_xfg_check_func_ptr); - coff_printf("Guard XFG dispatch func ptr: %#llx", lc->guard_xfg_dispatch_func_ptr); - coff_printf("Guard XFG table dispatch func ptr: %#llx", lc->guard_xfg_table_dispatch_func_ptr); - coff_printf("Cast guard OS determined failure mode: %#llx", lc->cast_guard_os_determined_failure_mode); - coff_newline(); - -exit:; - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) -{ - Temp scratch = scratch_begin(&arena, 1); - - coff_printf("# TLS"); - coff_indent(); - - String8 tls_chars = coff_string_from_section_flags(scratch.arena, tls.header.characteristics); - coff_printf("Raw data start: %#llx", tls.header.raw_data_start); - coff_printf("Raw data end: %#llx", tls.header.raw_data_end); - coff_printf("Index address: %#llx", tls.header.index_address); - coff_printf("Callbacks address: %#llx", tls.header.callbacks_address); - coff_printf("Zero-fill size: %m", tls.header.zero_fill_size); - coff_printf("Characteristics: %S", tls_chars); - - if (tls.callback_count) { - coff_newline(); - coff_printf("## Callbacks"); - coff_indent(); - for (U64 i = 0; i < tls.callback_count; ++i) { - coff_printf("%#llx", tls.callback_addrs[i]); - } - coff_unindent(); - } - - coff_unindent(); - coff_newline(); - - scratch_end(scratch); -} - -internal void -pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) -{ - Temp scratch = scratch_begin(&arena, 1); - - coff_printf("# Debug"); - coff_indent(); - - U64 entry_count = raw_dir.size / sizeof(PE_DebugDirectory); - PE_DebugDirectory *entries = str8_deserial_get_raw_ptr(raw_dir, 0, sizeof(*entries)*entry_count); - for (U64 i = 0; i < entry_count; ++i) { - PE_DebugDirectory *de = entries+i; - if (i > 0) { - coff_newline(); - } - coff_printf("Entry[%u]", i); - coff_indent(); - - { - String8 time_stamp = coff_format_time_stamp(scratch.arena, de->time_stamp); - String8 type = pe_string_from_debug_directory_type(de->type); - - coff_printf("Characteristics: %#x", de->characteristics); - coff_printf("Time Stamp: %S", time_stamp); - coff_printf("Version: %u.%u", de->major_ver, de->minor_ver); - coff_printf("Type: %S", type); - coff_printf("Size: %u", de->size); - coff_printf("Data virt off: %#x", de->voff); - coff_printf("Data file off: %#x", de->foff); - coff_newline(); - } - - String8 raw_entry = str8_substr(raw_data, rng_1u64(de->foff, de->foff+de->size)); - if (raw_entry.size != de->size) { - coff_errorf("unable to read debug entry @ %#x", de->foff); - break; - } - - coff_indent(); - switch (de->type) { - case PE_DebugDirectoryType_ILTCG: - case PE_DebugDirectoryType_MPX: - case PE_DebugDirectoryType_EXCEPTION: - case PE_DebugDirectoryType_FIXUP: - case PE_DebugDirectoryType_OMAP_TO_SRC: - case PE_DebugDirectoryType_OMAP_FROM_SRC: - case PE_DebugDirectoryType_BORLAND: - case PE_DebugDirectoryType_CLSID: - case PE_DebugDirectoryType_REPRO: - case PE_DebugDirectoryType_EX_DLLCHARACTERISTICS: { - NotImplemented; - } break; - case PE_DebugDirectoryType_COFF_GROUP: { - U64 off = 0; - - // TODO: is this version? - U32 unknown = 0; - off += str8_deserial_read_struct(raw_entry, off, &unknown); - if (unknown != 0) { - coff_printf("TODO: unknown: %u", unknown); - } - - coff_printf("%-8s %-8s %-8s", "VOFF", "Size", "Name"); - for (; off < raw_entry.size; ) { - U32 voff = 0; - U32 size = 0; - String8 name = str8_zero(); - - off += str8_deserial_read_struct(raw_entry, off, &voff); - off += str8_deserial_read_struct(raw_entry, off, &size); - if (voff == 0 && size == 0) { - break; - } - off += str8_deserial_read_cstr(raw_entry, off, &name); - off = AlignPow2(off, 4); - - coff_printf("%08x %08x %S", voff, size, name); - } - } break; - case PE_DebugDirectoryType_VC_FEATURE: { - MSCRT_VCFeatures *feat = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*feat)); - if (feat) { - coff_printf("Pre-VC++ 11.0: %u", feat->pre_vcpp); - coff_printf("C/C++: %u", feat->c_cpp); - coff_printf("/GS: %u", feat->gs); - coff_printf("/sdl: %u", feat->sdl); - coff_printf("guardN: %u", feat->guard_n); - } else { - coff_errorf("not enough bytes to read VC Features"); - } - } break; - case PE_DebugDirectoryType_FPO: { - PE_DebugFPO *fpo = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*fpo)); - if (fpo) { - U8 prolog_size = PE_FPOEncoded_Extract_PROLOG_SIZE(fpo->flags); - U8 saved_regs_size = PE_FPOEncoded_Extract_SAVED_REGS_SIZE(fpo->flags); - PE_FPOType type = PE_FPOEncoded_Extract_FRAME_TYPE(fpo->flags); - PE_FPOFlags flags = PE_FPOEncoded_Extract_FLAGS(fpo->flags); - - String8 type_string = pe_string_from_fpo_type(type); - String8 flags_string = pe_string_from_fpo_flags(scratch.arena, flags); - - coff_printf("Function offset: %#x", fpo->func_code_off); - coff_printf("Function size: %#x", fpo->func_size); - coff_printf("Locals size: %u", fpo->locals_size); - coff_printf("Params size: %u", fpo->params_size); - coff_printf("Prolog size: %u", prolog_size); - coff_printf("Saved regs size: %u", saved_regs_size); - coff_printf("Type: %S", type_string); - coff_printf("Flags: %S", flags_string); - } else { - coff_errorf("not enough bytes to read FPO"); - } - } break; - - case PE_DebugDirectoryType_CODEVIEW: { - U32 magic = 0; - str8_deserial_read_struct(raw_entry, 0, &magic); - switch (magic) { - case PE_CODEVIEW_PDB20_MAGIC: { - PE_CvHeaderPDB20 *cv20 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv20)); - String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv20), &name); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, cv20->time_stamp); - - coff_printf("Time stamp: %S", time_stamp); - coff_printf("Age: %u", cv20->age); - coff_printf("Name: %S", name); - } break; - case PE_CODEVIEW_PDB70_MAGIC: { - PE_CvHeaderPDB70 *cv70 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv70)); - String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv70), &name); - - String8 guid = string_from_guid(scratch.arena, cv70->guid); - - coff_printf("GUID: %S", guid); - coff_printf("Age: %u", cv70->age); - coff_printf("Name: %S", name); - } break; - default: { - coff_errorf("unknown CodeView magic %#x", magic); - } break; - } - } break; - case PE_DebugDirectoryType_MISC: { - PE_DebugMisc *misc = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*misc)); - - String8 type_string = pe_string_from_misc_type(misc->data_type); - - coff_printf("Data type: %S", type_string); - coff_printf("Size: %u", misc->size); - coff_printf("Unicode: %u", misc->unicode); - - switch (misc->data_type) { - case PE_DebugMiscType_EXE_NAME: { - String8 name; - str8_deserial_read_cstr(raw_entry, sizeof(*misc), &name); - coff_printf("Name: %S", name); - } break; - default: { - coff_printf("???"); - } break; - } - } break; - } - coff_unindent(); - - coff_unindent(); - } - - coff_unindent(); - coff_newline(); - scratch_end(scratch); -} - -internal void -pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 time_stamp = coff_format_time_stamp(scratch.arena, exptab.time_stamp); - - coff_printf("# Export Table"); - coff_indent(); - - coff_printf("Characteristics: %u", exptab.flags); - coff_printf("Time stamp: %S", time_stamp); - coff_printf("Version: %u.%02u", exptab.major_ver, exptab.minor_ver); - coff_printf("Ordinal base: %u", exptab.ordinal_base); - coff_printf(""); - - coff_printf("%-4s %-8s %-8s %-8s", "No.", "Oridnal", "VOff", "Name"); - - for (U64 i = 0; i < exptab.export_count; ++i) { - PE_ParsedExport *exp = exptab.exports+i; - if (exp->forwarder.size) { - coff_printf("%4u %8u %8x %S (forwarded to %S)", i, exp->ordinal, exp->voff, exp->name, exp->forwarder); - } else { - coff_printf("%4u %8u %8x %S", i, exp->ordinal, exp->voff, exp->name); - } - } - - coff_unindent(); - scratch_end(scratch); -} - -internal void -pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) -{ - Temp scratch = scratch_begin(&arena, 1); - - if (imptab.count) { - coff_printf("# Import Table"); - coff_indent(); - for (U64 dll_idx = 0; dll_idx < imptab.count; ++dll_idx) { - PE_ParsedStaticDLLImport *dll = imptab.v+dll_idx; - - coff_printf("Name: %S", dll->name); - coff_printf("Import address table: %#llx", image_base + dll->import_address_table_voff); - coff_printf("Import name table: %#llx", image_base + dll->import_name_table_voff); - coff_printf("Time stamp: %#x", dll->time_stamp); - coff_newline(); - - if (dll->import_count) { - coff_indent(); - for (U64 imp_idx = 0; imp_idx < dll->import_count; ++imp_idx) { - PE_ParsedImport *imp = dll->imports+imp_idx; - if (imp->type == PE_ParsedImport_Ordinal) { - coff_printf("%#-6x", imp->u.ordinal); - } else if (imp->type == PE_ParsedImport_Name) { - coff_printf("%#-6x %S", imp->u.name.hint, imp->u.name.string); - } - } - coff_unindent(); - coff_newline(); - } - } - coff_unindent(); - } - - scratch_end(scratch); -} - -internal void -pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) -{ - if (imptab.count) { - Temp scratch = scratch_begin(&arena, 1); - coff_printf("# Delay Import Table"); - coff_indent(); - - for (U64 dll_idx = 0; dll_idx < imptab.count; ++dll_idx) { - PE_ParsedDelayDLLImport *dll = imptab.v+dll_idx; - - coff_printf("Attributes: %#08x", dll->attributes); - coff_printf("Name: %S", dll->name); - coff_printf("HMODULE address: %#llx", image_base + dll->module_handle_voff); - coff_printf("Import address table: %#llx", image_base + dll->iat_voff); - coff_printf("Import name table: %#llx", image_base + dll->name_table_voff); - coff_printf("Bound import name table: %#llx", image_base + dll->bound_table_voff); - coff_printf("Unload import name table: %#llx", image_base + dll->unload_table_voff); - coff_printf("Time stamp: %#x", dll->time_stamp); - coff_newline(); - - coff_indent(); - for (U64 imp_idx = 0; imp_idx < dll->import_count; ++imp_idx) { - PE_ParsedImport *imp = dll->imports+imp_idx; - - String8 bound = str8_lit("NULL"); - if (imp_idx < dll->bound_table_count) { - U64 bound_addr = dll->bound_table[imp_idx]; - bound = push_str8f(scratch.arena, "%#llx", bound_addr); - } - - String8 unload = str8_lit("NULL"); - if (imp_idx < dll->unload_table_count) { - U64 unload_addr = dll->unload_table[imp_idx]; - unload = push_str8f(scratch.arena, "%#llx", unload_addr); - } - - if (imp->type == PE_ParsedImport_Ordinal) { - coff_printf("%-16S %-16S %#-4x", bound, unload, imp->u.ordinal); - } else if (imp->type == PE_ParsedImport_Name) { - coff_printf("%-16S %-16S %#-4x %S", bound, unload, imp->u.name.hint, imp->u.name.string); - } - } - coff_unindent(); - - coff_newline(); - } - - coff_unindent(); - scratch_end(scratch); - } -} - -internal void -pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) -{ - Temp scratch = scratch_begin(&arena, 1); - - // setup stack - struct stack_s { - struct stack_s *next; - B32 print_table; - B32 is_named; - PE_ResourceNode *curr_name_node; - PE_ResourceNode *curr_id_node; - U64 name_idx; - U64 id_idx; - U64 dir_idx; - U64 dir_id; - String8 dir_name; - PE_ResourceDir *table; - } *stack = push_array(scratch.arena, struct stack_s, 1); - stack->table = root; - stack->print_table = 1; - stack->is_named = 1; - stack->dir_name = str8_lit("ROOT"); - stack->curr_name_node = root->named_list.first; - stack->curr_id_node = root->id_list.first; - - if (stack) { - coff_printf("# Resources"); - - // traverse resource tree - while (stack) { - if (stack->print_table) { - stack->print_table = 0; - coff_indent(); - - if (stack->is_named) { - coff_printf("[%u] %S { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", - stack->dir_idx, - stack->dir_name, - stack->table->time_stamp, - stack->table->major_version, stack->table->minor_version, - stack->table->named_list.count, stack->table->id_list.count, - stack->table->characteristics); - } else { - B32 is_actually_leaf = stack->table->id_list.count == 1 && - stack->table->id_list.first->data.kind != PE_ResDataKind_DIR; - if (is_actually_leaf) { - coff_printf("[%u] %u { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", - stack->dir_idx, - stack->dir_id, - stack->table->time_stamp, - stack->table->major_version, stack->table->minor_version, - stack->table->named_list.count, stack->table->id_list.count, - stack->table->characteristics); - } else { - String8 id_str = pe_resource_kind_to_string(stack->dir_id); - coff_printf("[%u] %S { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", - stack->dir_idx, - id_str, - stack->dir_id, - stack->table->time_stamp, - stack->table->major_version, stack->table->minor_version, - stack->table->named_list.count, stack->table->id_list.count, - stack->table->characteristics); - } - } - } - - while (stack->curr_name_node) { - PE_ResourceNode *named_node = stack->curr_name_node; - stack->curr_name_node = stack->curr_name_node->next; - U64 name_idx = stack->name_idx++; - - PE_Resource *res = &named_node->data; - if (res->kind == PE_ResDataKind_DIR) { - struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); - frame->table = res->u.dir; - frame->print_table = 1; - frame->dir_idx = stack->name_idx; - frame->dir_name = res->id.u.string; - frame->is_named = 1; - frame->curr_name_node = frame->table->named_list.first; - frame->curr_id_node = frame->table->id_list.first; - SLLStackPush(stack, frame); - goto yield; - } else if (res->kind == PE_ResDataKind_COFF_LEAF) { - COFF_ResourceDataEntry *entry = &res->u.leaf; - coff_printf("[%u] %S Data VOFF: %#08x, Data Size: %#08x, Code Page: %u", - name_idx, res->id.u.string, entry->data_voff, entry->data_size, entry->code_page); - } else { - InvalidPath; - } - } - - while (stack->curr_id_node) { - PE_ResourceNode *id_node = stack->curr_id_node; - PE_Resource *res = &id_node->data; - stack->curr_id_node = stack->curr_id_node->next; - U64 id_idx = stack->id_idx++; - - if (res->kind == PE_ResDataKind_DIR) { - struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); - frame->table = res->u.dir; - frame->print_table = 1; - frame->dir_idx = stack->table->named_list.count + id_idx; - frame->dir_id = res->id.u.number; - frame->curr_name_node = frame->table->named_list.first; - frame->curr_id_node = frame->table->id_list.first; - SLLStackPush(stack, frame); - goto yield; - } else if (res->kind == PE_ResDataKind_COFF_LEAF) { - COFF_ResourceDataEntry *entry = &res->u.leaf; - coff_printf("[%u] ID: %u Data VOFF: %#08x, Data Size: %#08x, Code Page: %u", id_idx, res->id.u.number, entry->data_voff, entry->data_size, entry->code_page); - } else { - InvalidPath; - } - } - - if (stack->curr_id_node == 0 && stack->curr_name_node == 0) { - coff_unindent(); - } - - SLLStackPop(stack); - - yield:; - } - - coff_newline(); - } - - scratch_end(scratch); -} - -internal void -pe_format_exceptions_x8664(Arena *arena, - String8List *out, - String8 indent, - U64 section_count, - COFF_SectionHeader *sections, - String8 raw_data, - Rng1U64 except_frange) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 raw_except = str8_substr(raw_data, except_frange); - U64 count = raw_except.size / sizeof(PE_IntelPdata); - for (U64 i = 0; i < count; ++i) { - Temp temp = temp_begin(scratch.arena); - - U64 pdata_offset = i * sizeof(PE_IntelPdata); - PE_IntelPdata *pdata = str8_deserial_get_raw_ptr(raw_except, pdata_offset, sizeof(*pdata)); - - String8 pdata_name = str8_zero(); // TODO: syms_name_for_voff(arena, group, thunk_accel, thunk_table_set, pdata.voff_first); - - U64 unwind_info_offset = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info); - PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, unwind_info_offset, sizeof(*uwinfo)); - - U8 version = PE_UNWIND_INFO_VERSION_FROM_HDR(uwinfo->header); - U8 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(uwinfo->header); - U8 frame_register = PE_UNWIND_INFO_REG_FROM_FRAME(uwinfo->frame); - U8 frame_offset = PE_UNWIND_INFO_OFF_FROM_FRAME(uwinfo->frame); - - B32 is_chained = (flags & PE_UnwindInfoFlag_CHAINED) != 0; - B32 has_handler_data = !is_chained && (flags & (PE_UnwindInfoFlag_EHANDLER | PE_UnwindInfoFlag_UHANDLER)) != 0; - - String8 flags_str = str8_zero(); - { - U64 f = flags; - - String8List flags_list = {0}; - if (f & PE_UnwindInfoFlag_EHANDLER) { - f &= ~PE_UnwindInfoFlag_EHANDLER; - str8_list_pushf(scratch.arena, &flags_list, "EHANDLER"); - } - if (f & PE_UnwindInfoFlag_UHANDLER) { - f &= ~PE_UnwindInfoFlag_UHANDLER; - str8_list_pushf(scratch.arena, &flags_list, "UHANDLER"); - } - if (f & PE_UnwindInfoFlag_CHAINED) { - f &= ~PE_UnwindInfoFlag_CHAINED; - str8_list_pushf(scratch.arena, &flags_list, "CHAINED"); - } - if (f) { - str8_list_pushf(scratch.arena, &flags_list, "%#llx", f); - } - if (flags_list.node_count == 0) { - str8_list_pushf(scratch.arena, &flags_list, "%#llx", f); - } - flags_str = str8_list_join(scratch.arena, &flags_list, &(StringJoin){.sep=str8_lit(", ")}); - } - - U64 codes_offset = unwind_info_offset + sizeof(PE_UnwindInfo); - PE_UnwindCode *code_ptr = str8_deserial_get_raw_ptr(raw_data, codes_offset, sizeof(*code_ptr) * uwinfo->codes_num); - PE_UnwindCode *code_opl = code_ptr + uwinfo->codes_num; - - if (i > 0) { - coff_newline(); - } - coff_printf("%08x %08x %08x %08x%s%S", - pdata_offset, - pdata->voff_first, - pdata->voff_one_past_last, - pdata->voff_unwind_info, - pdata_name.size ? " " : "", pdata_name); - coff_printf("Version: %u", version); - coff_printf("Flags: %S", flags_str); - coff_printf("Prolog Size: %#x", uwinfo->prolog_size); - coff_printf("Code Count: %u", uwinfo->codes_num); - coff_printf("Frame: %u", uwinfo->frame); - coff_printf("Codes:"); - coff_indent(); - for (; code_ptr < code_opl;) { - Temp code_temp = temp_begin(scratch.arena); - String8List code_list = {0}; - - U8 operation_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr[0].flags); - U8 operation_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr[0].flags); - - str8_list_pushf(code_temp.arena, &code_list, "%#04x:", code_ptr[0].off_in_prolog); - switch (operation_code) { - case PE_UnwindOpCode_PUSH_NONVOL: { - String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); - str8_list_pushf(code_temp.arena, &code_list, "PUSH_NONVOL %S", gpr); - code_ptr += 1; - } break; - case PE_UnwindOpCode_ALLOC_LARGE: { - U64 size = 0; - switch (operation_info) { - case 0: { // 136B - 512K - size = code_ptr[1].u16*8; - } break; - case 1: { // 512K - 4GB - size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - } break; - default: break; - } - str8_list_pushf(code_temp.arena, &code_list, "ALLOC_LARGE size=%#x", size); - code_ptr += 2; - } break; - case PE_UnwindOpCode_ALLOC_SMALL: { - U64 size = operation_info*8 + 8; - str8_list_pushf(code_temp.arena, &code_list, "ALLOC_SMALL size=%#x", size); - code_ptr += 1; - } break; - case PE_UnwindOpCode_SET_FPREG: { - U64 offset = frame_offset*16; - String8 gpr = pe_string_from_unwind_gpr_x64(frame_register); - str8_list_pushf(code_temp.arena, &code_list, "SET_FPREG %S, offset=%#x", gpr, offset); - code_ptr += 1; - } break; - case PE_UnwindOpCode_SAVE_NONVOL: { - String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); - U64 register_offset = code_ptr[1].u16*8; - str8_list_pushf(code_temp.arena, &code_list, "SAVE_NONVOL %S, offset=%#x", gpr, register_offset); - code_ptr += 2; - } break; - case PE_UnwindOpCode_SAVE_NONVOL_FAR: { - String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); - U64 frame_offset = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - str8_list_pushf(code_temp.arena, &code_list, "SAVE_NONVOL_FAR %S, offset=%#x", gpr, frame_offset); - code_ptr += 3; - } break; - case PE_UnwindOpCode_EPILOG: { - str8_list_pushf(code_temp.arena, &code_list, "EPILOG flags=%#x", code_ptr[0].flags); - code_ptr += 1; - } break; - case PE_UnwindOpCode_SPARE_CODE: { - str8_list_pushf(code_temp.arena, &code_list, "SPARE_CODE"); - code_ptr += 1; - } break; - case PE_UnwindOpCode_SAVE_XMM128: { - String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); - U64 register_offset = code_ptr[1].u16*16; - str8_list_pushf(code_temp.arena, &code_list, "SAVE_XMM128 %S, offset=%#x", gpr, register_offset); - code_ptr += 2; - } break; - case PE_UnwindOpCode_SAVE_XMM128_FAR: { - String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); - U64 frame_offset = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - str8_list_pushf(code_temp.arena, &code_list, "SAVE_XMM128_FAR %S, offset=%#x", gpr, frame_offset); - code_ptr += 3; - } break; - case PE_UnwindOpCode_PUSH_MACHFRAME: { - str8_list_pushf(code_temp.arena, &code_list, "PUSH_MACHFRAME %s", operation_info == 1 ? "with error code" : "without error code"); - code_ptr += 1; - } break; - default: { - str8_list_pushf(code_temp.arena, &code_list, "UNKNOWN_OPCODE %#x", operation_code); - code_ptr += 1; - } break; - } - - String8 code_line = str8_list_join(code_temp.arena, &code_list, &(StringJoin){.sep=str8_lit(" ")}); - coff_printf("%S", code_line); - - temp_end(code_temp); - } - coff_unindent(); - - if (is_chained) { - U64 next_pdata_offset = codes_offset + sizeof(PE_UnwindCode) * AlignPow2(uwinfo->codes_num, 2); - PE_IntelPdata *next_pdata = str8_deserial_get_raw_ptr(raw_data, next_pdata_offset, sizeof(*next_pdata)); - coff_printf("Chained: %#08x %#08x %#08x", next_pdata->voff_first, next_pdata->voff_one_past_last, next_pdata->voff_unwind_info); - } - - if (has_handler_data) { -#define ExceptionHandlerDataFlag_FuncInfo (1 << 0) -#define ExceptionHandlerDataFlag_FuncInfo4 (1 << 1) -#define ExceptionHandlerDataFlag_ScopeTable (1 << 2) -#define ExceptionHandlerDataFlag_GS (1 << 3u) - - U64 actual_code_count = PE_UNWIND_INFO_GET_CODE_COUNT(uwinfo->codes_num); - U64 read_cursor = codes_offset + actual_code_count * sizeof(PE_UnwindCode); - - U32 handler = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler); - - String8 handler_name = str8_zero(); // TODO: syms_name_for_voff(scratch.arena, group, thunk_accel, thunk_table_set, handler); - - coff_printf("Handler: %#llx%s%S", handler, handler_name.size ? " " : "", handler_name); - - U32 handler_data_flags = 0; - if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; - } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; - } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_FuncInfo; - } else if (str8_match(handler_name, str8_lit("__C_specific_handler"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_ScopeTable; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_GS; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_SEH"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_ScopeTable|ExceptionHandlerDataFlag_GS; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0)) { - handler_data_flags = ExceptionHandlerDataFlag_FuncInfo|ExceptionHandlerDataFlag_GS; - } - - if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo) { - MSCRT_FuncInfo func_info; - read_cursor += mscrt_parse_func_info(arena, raw_data, section_count, sections, read_cursor, &func_info); - - coff_printf("Function Info:"); - coff_indent(); - coff_printf("Magic: %#x", func_info.magic); - coff_printf("Max State: %u", func_info.max_state); - coff_printf("Try Block Count: %u", func_info.try_block_map_count); - coff_printf("IP Map Count: %u", func_info.ip_map_count); - coff_printf("Frame Offset Unwind Helper: %#x", func_info.frame_offset_unwind_helper); - coff_printf("ES Flags: %#x", func_info.eh_flags); - coff_unindent(); - - if (func_info.ip_map_count > 0) { - coff_printf("IP to State Map:"); - coff_indent(); - coff_printf("%8s %8s", "State", "IP"); - for (U32 i = 0; i < func_info.ip_map_count; ++i) { - MSCRT_IPState32 state = func_info.ip_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, state.ip); - coff_printf("%8d %08x %S", state.state, state.ip, line); - } - coff_unindent(); - } - - if (func_info.max_state > 0) { - coff_printf("Unwind Map:"); - coff_indent(); - coff_printf("%13s %10s %8s", "Current State", "Next State", "Action @"); - for (U32 i = 0; i < func_info.max_state; ++i) { - MSCRT_UnwindMap32 map = func_info.unwind_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, map.action_virt_off); - coff_printf("%13u %10d %8x %S", i, map.next_state, map.action_virt_off, line); - } - coff_unindent(); - } - - for (U32 i = 0; i < func_info.try_block_map_count; ++i) { - MSCRT_TryMapBlock try_block = func_info.try_block_map[i]; - coff_printf("Try Map Block #%u", i); - coff_indent(); - coff_printf("Try State Low: %u", try_block.try_low); - coff_printf("Try State High: %u", try_block.try_high); - coff_printf("Catch State High: %u", try_block.catch_high); - coff_printf("Catch Count: %u", try_block.catch_handlers_count); - coff_printf("Catches:"); - coff_indent(); - for (U32 ihandler = 0; ihandler < try_block.catch_handlers_count; ++ihandler) { - coff_printf("Catch #%u", ihandler); - coff_indent(); - mscrt_format_eh_handler_type32(arena, out, indent, &try_block.catch_handlers[ihandler]); - coff_unindent(); - } - coff_unindent(); - coff_unindent(); - } - - if (func_info.es_type_list.count) { - coff_printf("Exception Specific Types:"); - coff_indent(); - for (U32 i = 0; i < func_info.es_type_list.count; ++i) { - if (i > 0) { - coff_newline(); - } - mscrt_format_eh_handler_type32(arena, out, indent, &func_info.es_type_list.handlers[i]); - } - coff_unindent(); - } - } - if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo4) { - U32 handler_data_voff = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler_data_voff); - - U32 unknown = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &unknown); - - U64 func_info_foff = coff_foff_from_voff(sections, section_count, handler_data_voff); - MSCRT_ParsedFuncInfoV4 func_info = {0}; - mscrt_parse_func_info_v4(arena, raw_data, section_count, sections, func_info_foff, pdata->voff_first, &func_info); - - String8 header_str = str8_zero(); - { - String8List header_list = {0}; - if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { - str8_list_pushf(arena, &header_list, "IsCatch"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { - str8_list_pushf(arena, &header_list, "IsSeparted"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { - str8_list_pushf(arena, &header_list, "IsBBT"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - str8_list_pushf(arena, &header_list, "UnwindMap"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - str8_list_pushf(arena, &header_list, "TryBlockMap"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_EHs) { - str8_list_pushf(arena, &header_list, "EHs"); - } - if (func_info.header & MSCRT_FuncInfoV4Flag_NoExcept) { - str8_list_pushf(arena, &header_list, "NoExcept"); - } - header_str = str8_list_join(arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); - } - - coff_printf("Function Info V4:"); - coff_indent(); - coff_printf("Header: %#x %S", func_info.header, header_str); - coff_printf("BBT Flags: %#x", func_info.bbt_flags); - - MSCRT_IP2State32V4 ip2state_map = func_info.ip2state_map; - coff_printf("IP To State Map:"); - coff_indent(); - coff_printf("%8s %8s", "State", "IP"); - for (U32 i = 0; i < ip2state_map.count; ++i) { - String8 line_str = str8_zero(); // TODO: syms_line_for_voff(arena, group, ip2state_map.voffs[i]); - coff_printf("%8d %08X %S", ip2state_map.states[i], ip2state_map.voffs[i], line_str); - } - coff_unindent(); - - if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - MSCRT_UnwindMapV4 unwind_map = func_info.unwind_map; - coff_printf("Unwind Map:"); - coff_indent(); - for (U32 i = 0; i < unwind_map.count; ++i) { - MSCRT_UnwindEntryV4 *ue = &unwind_map.v[i]; - String8 type_str = str8_zero(); - switch (ue->type) { - case MSCRT_UnwindMapV4Type_NoUW: type_str = str8_lit("NoUW"); break; - case MSCRT_UnwindMapV4Type_DtorWithObj: type_str = str8_lit("DtorWithObj"); break; - case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: type_str = str8_lit("DtorWithPtrToObj"); break; - case MSCRT_UnwindMapV4Type_VOFF: type_str = str8_lit("VOFF"); break; - } - if (ue->type == MSCRT_UnwindMapV4Type_DtorWithObj || ue->type == MSCRT_UnwindMapV4Type_DtorWithPtrToObj) { - coff_printf("[%2u] NextOff=%u Type=%-16S Action=%#08x Object=%#x", i, ue->next_off, type_str, ue->action, ue->object); - } else if (ue->type == MSCRT_UnwindMapV4Type_VOFF) { - coff_printf("[%2u] NextOff=%u Type=%-16S Action=%#08x", i, ue->next_off, type_str, ue->action); - } else { - coff_printf("[%2u] NextOff=%u Type=%S", i, ue->next_off, type_str); - } - } - coff_unindent(); - } - - if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - MSCRT_TryBlockMapV4Array try_block_map = func_info.try_block_map; - coff_printf("Try/Catch Blocks:"); - coff_indent(); - for (U32 i = 0; i < try_block_map.count; ++i) { - MSCRT_TryBlockMapV4 *try_block = &try_block_map.v[i]; - coff_printf("[%2u] TryLow %u TryHigh %u CatchHigh %u", i, try_block->try_low, try_block->try_high, try_block->catch_high); - if (try_block->handlers.count) { - for (U32 k = 0; k < try_block->handlers.count; ++k) { - MSCRT_EhHandlerTypeV4 *handler = &try_block->handlers.v[k]; - - String8List line_list = {0}; - str8_list_pushf(arena, &line_list, " "); - str8_list_pushf(arena, &line_list, "CatchCodeVOff=0x%08X", handler->catch_code_voff); - if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) { - String8 adjectives = mscrt_format_eh_adjectives(arena, handler->adjectives); - str8_list_pushf(arena, &line_list, "Adjectives=%S", adjectives); - } - if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) { - str8_list_pushf(arena, &line_list, "TypeVOff=%#x", handler->type_voff); - } - if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) { - str8_list_pushf(arena, &line_list, "CacthObjVOff=%#x", handler->catch_obj_voff); - } - if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) { - str8_list_pushf(arena, &line_list, "ContIsVOff"); - } - for (U32 icont = 0; icont < handler->catch_funclet_cont_addr_count; ++icont) { - str8_list_pushf(arena, &line_list, "ContAddr[%u]=%#llx", icont, handler->catch_funclet_cont_addr[icont]); - } - - String8 handler_str = str8_list_join(arena, &line_list, &(StringJoin){.sep=str8_lit(" ")}); - coff_printf("%S", handler_str); - } - } - } - coff_unindent(); - } - } - if (handler_data_flags & ExceptionHandlerDataFlag_ScopeTable) { - U32 scope_count = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &scope_count); - - PE_HandlerScope *scopes = str8_deserial_get_raw_ptr(raw_data, read_cursor, sizeof(PE_HandlerScope)*scope_count); - read_cursor += scope_count*sizeof(scopes[0]); - - coff_printf("Count of scope table entries: %u", scope_count); - coff_indent(); - coff_printf("%-8s %-8s %-8s %-8s", "Begin", "End", "Handler", "Target"); - for (U32 i = 0; i < scope_count; ++i) { - PE_HandlerScope scope = scopes[i]; - coff_printf("%08x %08x %08x %08x", scope.begin, scope.end, scope.handler, scope.target); - } - coff_unindent(); - } - if (handler_data_flags & ExceptionHandlerDataFlag_GS) { - U32 gs_data = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &gs_data); - - U32 flags = MSCRT_GSHandler_GetFlags(gs_data); - U32 cookie_offset = MSCRT_GSHandler_GetCookieOffset(gs_data); - U32 aligned_base_offset = 0; - U32 alignment = 0; - if (flags & MSCRT_GSHandlerFlag_HasAlignment) { - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &aligned_base_offset); - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &alignment); - } - - String8 flags_str; - { - String8List flags_list = {0}; - if (flags & MSCRT_GSHandlerFlag_EHandler) { - str8_list_pushf(arena, &flags_list, "EHandler"); - } - if (flags & MSCRT_GSHandlerFlag_UHandler) { - str8_list_pushf(arena, &flags_list, "UHandler"); - } - if (flags & MSCRT_GSHandlerFlag_HasAlignment) { - str8_list_pushf(arena, &flags_list, "Has Alignment"); - } - if (flags == 0) { - str8_list_pushf(arena, &flags_list, "None"); - } - flags_str = str8_list_join(arena, &flags_list, &(StringJoin){.sep=str8_lit(", ")}); - } - coff_printf("GS unwind flags: %S", flags_str); - coff_printf("Cookie offset: %x", cookie_offset); - if (flags & MSCRT_GSHandlerFlag_HasAlignment) { - coff_printf("Aligned base offset: %x", aligned_base_offset); - coff_printf("Alignment: %x", alignment); - } - } - - #undef ExceptionHandlerDataFlag_FuncInfo - #undef ExceptionHandlerDataFlag_ScopeTable - #undef ExceptionHandlerDataFlag_GS - } - - temp_end(temp); - } - - scratch_end(scratch); -} - -internal void -pe_format_exceptions(Arena *arena, - String8List *out, - String8 indent, - COFF_MachineType machine, - U64 section_count, - COFF_SectionHeader *sections, - String8 raw_data, - Rng1U64 except_frange) -{ - if (dim_1u64(except_frange)) { - coff_printf("# Exceptions"); - coff_indent(); - coff_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); - - switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X64: - case COFF_MachineType_X86: { - pe_format_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange); - } break; - default: NotImplemented; break; - } - coff_unindent(); - coff_newline(); - } -} - -internal void -pe_format_base_relocs(Arena *arena, - String8List *out, - String8 indent, - COFF_MachineType machine, - U64 image_base, - U64 section_count, - COFF_SectionHeader *sections, - String8 raw_data, - Rng1U64 base_reloc_franges) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 raw_base_relocs = str8_substr(raw_data, base_reloc_franges); - PE_BaseRelocBlockList base_relocs = pe_base_reloc_block_list_from_data(scratch.arena, raw_base_relocs); - - if (base_relocs.count) { - coff_printf("# Base Relocs"); - coff_indent(); - - U32 addr_size = 0; - switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: addr_size = 4; break; - case COFF_MachineType_X64: addr_size = 8; break; - default: NotImplemented; - } - - // convert blocks to string list - U64 iblock = 0; - for (PE_BaseRelocBlockNode *node = base_relocs.first; node != 0; node = node->next) { - PE_BaseRelocBlock *block = &node->v; - coff_printf("Block No. %u, Virt Off %#x, Reloc Count %u", iblock++, block->page_virt_off, block->entry_count); - coff_indent(); - for (U64 ientry = 0; ientry < block->entry_count; ++ientry) { - PE_BaseRelocKind type = PE_BaseRelocKindFromEntry(block->entries[ientry]); - U16 offset = PE_BaseRelocOffsetFromEntry(block->entries[ientry]); - - U64 apply_to_voff = block->page_virt_off + offset; - U64 apply_to_foff = coff_foff_from_voff(sections, section_count, apply_to_voff); - U64 apply_to = 0; - str8_deserial_read(raw_data, apply_to_foff, &apply_to, addr_size, 1); - U64 addr = image_base + apply_to; - - const char *type_str = "???"; - switch (type) { - case PE_BaseRelocKind_ABSOLUTE: type_str = "ABS"; break; - case PE_BaseRelocKind_HIGH: type_str = "HIGH"; break; - case PE_BaseRelocKind_LOW: type_str = "LOW"; break; - case PE_BaseRelocKind_HIGHLOW: type_str = "HIGHLOW"; break; - case PE_BaseRelocKind_HIGHADJ: type_str = "HIGHADJ"; break; - case PE_BaseRelocKind_DIR64: type_str = "DIR64"; break; - default: { - switch (machine) { - case COFF_MachineType_ARM: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARMNT: { - switch (type) { - case PE_BaseRelocKind_ARM_MOV32: type_str = "ARM_MOV32"; break; - case PE_BaseRelocKind_THUMB_MOV32: type_str = "THUMB_MOV32"; break; - default: NotImplemented; - } - } break; - // TODO: mips, loong, risc-v - } - } break; - } - - if (type == PE_BaseRelocKind_ABSOLUTE) { - coff_printf("%-4x %-12s", offset, type_str); - } else { - coff_printf("%-4x %-12s %016llx", offset, type_str, apply_to); - - // TODO - #if 0 - U64 reloc_voff = apply_to - image_base; - SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, reloc_voff); - SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, reloc_voff); - if (sid) { - SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); - SYMS_String8 name = syms_group_symbol_name_from_sid(arena, group, unit, sid); - syms_string_list_pushf__dev(arena, list, " %-4X %-12s %016llX %.*s", offset, type_str, apply_to, syms_expand_string(name)); - } else { - syms_string_list_pushf__dev(arena, list, " %-4X %-12s %016llX", offset, type_str, apply_to); - } - #endif - } - } - coff_unindent(); - coff_newline(); - } - - coff_unindent(); - } - - scratch_end(scratch); -} - -internal void -pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, Coffdump_Option opts) -{ - Temp scratch = scratch_begin(&arena, 1); - - PE_DosHeader *dos_header = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(*dos_header)); - if (!dos_header) { - coff_errorf("not enough bytes to read DOS header"); - goto exit; - } - Assert(dos_header->magic == PE_DOS_MAGIC); - - U32 pe_magic = 0; - str8_deserial_read_struct(raw_data, dos_header->coff_file_offset, &pe_magic); - if (pe_magic != PE_MAGIC) { - coff_errorf("PE magic check failure, input file is not of PE format"); - goto exit; - } - - U64 coff_header_off = dos_header->coff_file_offset+sizeof(pe_magic); - COFF_Header *coff_header = str8_deserial_get_raw_ptr(raw_data, coff_header_off, sizeof(*coff_header)); - if (!coff_header) { - coff_errorf("not enough bytes to read COFF header"); - goto exit; - } - - U64 opt_header_off = coff_header_off + sizeof(*coff_header); - U16 opt_header_magic = 0; - str8_deserial_read_struct(raw_data, opt_header_off, &opt_header_magic); - if (opt_header_magic != PE_PE32_MAGIC && opt_header_magic != PE_PE32PLUS_MAGIC) { - coff_errorf("unexpected optional header magic %#x", opt_header_magic); - goto exit; - } - - if (opt_header_magic == PE_PE32_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32)) { - coff_errorf("unexpected optional header size in COFF header %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32)); - goto exit; - } - - if (opt_header_magic == PE_PE32PLUS_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32Plus)) { - coff_errorf("unexpected optional header size %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32Plus)); - goto exit; - } - - U64 sections_off = coff_header_off + sizeof(*coff_header) + coff_header->optional_header_size; - COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sections_off, sizeof(*sections)*coff_header->section_count); - if (!sections) { - coff_errorf("not enough bytes to read COFF section headers"); - goto exit; - } - - U64 string_table_off = coff_header->symbol_table_foff + sizeof(COFF_Symbol16) * coff_header->symbol_count; - - COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, coff_header->symbol_table_foff, coff_header->symbol_count); - - U8 *raw_opt_header = push_array(scratch.arena, U8, coff_header->optional_header_size); - str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, coff_header->optional_header_size); - - if (opts & Coffdump_Option_Headers) { - coff_format_header(arena, out, indent, coff_header); - coff_newline(); - } - - U64 image_base = 0; - U64 dir_count = 0; - PE_DataDirectory *dirs = 0; - - if (opt_header_magic == PE_PE32_MAGIC) { - PE_OptionalHeader32 *opt_header = (PE_OptionalHeader32 *)raw_opt_header; - image_base = opt_header->image_base; - dir_count = opt_header->data_dir_count; - dirs = str8_deserial_get_raw_ptr(raw_data, opt_header_off+sizeof(*opt_header), sizeof(*dirs) * opt_header->data_dir_count); - if (!dirs) { - coff_errorf("unable to read data directories"); - goto exit; - } - - if (opts & Coffdump_Option_Headers) { - pe_format_optional_header32(arena, out, indent, opt_header, dirs); - } - } else if (opt_header_magic == PE_PE32PLUS_MAGIC) { - PE_OptionalHeader32Plus *opt_header = (PE_OptionalHeader32Plus *)raw_opt_header; - image_base = opt_header->image_base; - dir_count = opt_header->data_dir_count; - dirs = str8_deserial_get_raw_ptr(raw_data, opt_header_off+sizeof(*opt_header), sizeof(*dirs) * opt_header->data_dir_count); - if (!dirs) { - coff_errorf("unable to read data directories"); - goto exit; - } - - if (opts & Coffdump_Option_Headers) { - pe_format_optional_header32plus(arena, out, indent, opt_header, dirs); - } - } - - // map data directory RVA to file offsets - Rng1U64 *dirs_file_ranges = push_array(scratch.arena, Rng1U64, dir_count); - Rng1U64 *dirs_virt_ranges = push_array(scratch.arena, Rng1U64, dir_count); - for (U64 i = 0; i < dir_count; ++i) { - PE_DataDirectory dir = dirs[i]; - U64 file_off = coff_foff_from_voff(sections, coff_header->section_count, dir.virt_off); - dirs_file_ranges[i] = r1u64(file_off, file_off+dir.virt_size); - dirs_virt_ranges[i] = r1u64(dir.virt_off, dir.virt_off+dir.virt_size); - } - - if (opts & Coffdump_Option_Sections) { - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); - } - - if (opts & Coffdump_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); - } - - if (opts & Coffdump_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); - } - - if (opts & Coffdump_Option_Exports) { - PE_ParsedExportTable exptab = pe_exports_from_data(arena, - coff_header->section_count, - sections, - raw_data, - dirs_file_ranges[PE_DataDirectoryIndex_EXPORT], - dirs_virt_ranges[PE_DataDirectoryIndex_EXPORT]); - } - - if (opts & Coffdump_Option_Imports) { - B32 is_pe32 = opt_header_magic == PE_PE32_MAGIC; - PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); - PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); - pe_format_static_import_table(arena, out, indent, image_base, static_imptab); - pe_format_delay_import_table(arena, out, indent, image_base, delay_imptab); - } - - if (opts & Coffdump_Option_Resources) { - String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_RESOURCES]); - PE_ResourceDir *dir_root = pe_resource_table_from_directory_data(scratch.arena, raw_dir); - pe_format_resources(arena, out, indent, dir_root); - } - - if (opts & Coffdump_Option_Exceptions) { - pe_format_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS]); - } - - if (opts & Coffdump_Option_Relocs) { - pe_format_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC]); - } - - if (opts & Coffdump_Option_Debug) { - if (PE_DataDirectoryIndex_DEBUG < dir_count) { - String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DEBUG]); - pe_format_debug_directory(arena, out, indent, raw_data, raw_dir); - } - } - - if (opts & Coffdump_Option_Tls) { - if (dim_1u64(dirs_file_ranges[PE_DataDirectoryIndex_TLS])) { - PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); - pe_format_tls(arena, out, indent, tls); - } - } - - if (opts & Coffdump_Option_LoadConfig) { - String8 raw_lc = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_LOAD_CONFIG]); - if (raw_lc.size) { - switch (coff_header->machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: { - PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); - if (lc) { - pe_format_load_config32(arena, out, indent, lc); - } else { - coff_errorf("not enough bytes to parse 32bit load config"); - } - } break; - case COFF_MachineType_X64: { - PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); - if (lc) { - pe_format_load_config64(arena, out, indent, lc); - } else { - coff_errorf("not enough bytes to parse 64bit load config"); - } - } break; - default: NotImplemented; - } - } - } - - MarkerArray *section_markers = 0; - if (opts & (Coffdump_Option_Disasm|Coffdump_Option_Rawdata)) { - section_markers = section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, symbols); - } - - if (opts & Coffdump_Option_Rawdata) { - coff_raw_data_sections(arena, out, indent, raw_data, 0, section_markers, coff_header->section_count, sections); - } - - if (opts & Coffdump_Option_Disasm) { - coff_disasm_sections(arena, out, indent, raw_data, coff_header->machine, 0, 1, section_markers, coff_header->section_count, sections); - } - -exit:; - scratch_end(scratch); -} - -//////////////////////////////// - -internal void -format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) -{ - Temp scratch = scratch_begin(&arena, 1); - - char *input_type_string = "???"; - - if (coff_is_archive(raw_data)) { - input_type_string = "Archive"; - } else if (coff_is_thin_archive(raw_data)) { - input_type_string = "Thin Archive"; - } else if (coff_is_big_obj(raw_data)) { - input_type_string = "Big Obj"; - } else if (coff_is_obj(raw_data)) { - input_type_string = "Obj"; - } else if (is_pe(raw_data)) { - input_type_string = "COFF/PE"; - } - - DateTime universal_dt = os_now_universal_time(); - DateTime local_dt = os_local_time_from_universal(&universal_dt); - String8 time = push_date_time_string(scratch.arena, &local_dt); - - coff_printf("# Input"); - coff_indent(); - coff_printf("Path: %S", input_path); - coff_printf("Type: %s", input_type_string); - coff_printf("Time: %S", time); - coff_unindent(); - coff_newline(); - - scratch_end(scratch); -} - -internal void -entry_point(CmdLine *cmdline) -{ - Temp scratch = scratch_begin(0,0); - - // parse options - Coffdump_Option opts = 0; - { - for (CmdLineOpt *cmd = cmdline->options.first; cmd != 0; cmd = cmd->next) { - Coffdump_Option opt = 0; - for (U64 opt_idx = 0; opt_idx < ArrayCount(g_coffdump_option_map); ++opt_idx) { - String8 opt_name = str8_cstring(g_coffdump_option_map[opt_idx].name); - if (str8_match(cmd->string, opt_name, StringMatchFlag_CaseInsensitive)) { - opt = g_coffdump_option_map[opt_idx].opt; - break; - } else if (str8_match(cmd->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { - opt = ~0ull & ~(Coffdump_Option_Help|Coffdump_Option_Version); - break; - } - } - - if (opt == 0) { - fprintf(stderr, "Unknown argument: \"%.*s\"\n", str8_varg(cmd->string)); - os_abort(1); - } - - opts |= opt; - } - } - - // print help - if (opts & Coffdump_Option_Help) { - for (U64 opt_idx = 0; opt_idx < ArrayCount(g_coffdump_option_map); ++opt_idx) { - fprintf(stdout, "-%s %s\n", g_coffdump_option_map[opt_idx].name, g_coffdump_option_map[opt_idx].help); - } - os_abort(0); - } - - // print version - if (opts & Coffdump_Option_Version) { - fprintf(stdout, BUILD_TITLE_STRING_LITERAL "\n"); - fprintf(stdout, "\tcoffdump \n"); - os_abort(0); - } - - // input check - if (cmdline->inputs.node_count == 0) { - fprintf(stderr, "No input file specified\n"); - os_abort(1); - } else if (cmdline->inputs.node_count > 1) { - fprintf(stderr, "Too many inputs specified, expected one\n"); - os_abort(1); - } - - // read input - String8 file_path = str8_list_first(&cmdline->inputs); - String8 raw_data = os_data_from_file_path(scratch.arena, file_path); - - // is read ok? - if (raw_data.size == 0) { - fprintf(stderr, "Unable to read input file \"%.*s\"\n", str8_varg(file_path)); - os_abort(1); - } - - // make indent - String8 indent; - { - U64 indent_buffer_size = COFF_INDENT_WIDTH * COFF_INDENT_MAX; - U8 *indent_buffer = push_array(scratch.arena, U8, indent_buffer_size); - MemorySet(indent_buffer, ' ', indent_buffer_size); - indent = str8(indent_buffer, 0); - } - - // format input - String8List out = {0}; - { - format_preamble(scratch.arena, &out, indent, file_path, raw_data); - - if (coff_is_archive(raw_data) || coff_is_thin_archive(raw_data)) { - coff_format_archive(scratch.arena, &out, indent, raw_data, opts); - } else if (coff_is_big_obj(raw_data)) { - coff_format_big_obj(scratch.arena, &out, indent, raw_data, opts); - } else if (coff_is_obj(raw_data)) { - coff_format_obj(scratch.arena, &out, indent, raw_data, opts); - } else if (is_pe(raw_data)) { - pe_format(scratch.arena, &out, indent, raw_data, opts); - } else if (pe_is_res(raw_data)) { - //tool_out_coff_res(stdout, file_data); - } - } - - // print formatted string - String8 out_string = str8_list_join(scratch.arena, &out, &(StringJoin){ .sep = str8_lit("\n"),}); - fprintf(stdout, "%.*s", str8_varg(out_string)); - - scratch_end(scratch); -} - diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c new file mode 100644 index 00000000..2554f8f8 --- /dev/null +++ b/src/raddump/raddump.c @@ -0,0 +1,4448 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal int +rd_marker_is_before(void *a, void *b) +{ + return u64_is_before(&((RD_Marker*)a)->off, &((RD_Marker*)b)->off); +} + +internal RD_MarkerArray * +rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols) +{ + Temp scratch = scratch_begin(&arena, 1); + + // extract markers from symbol table + RD_MarkerList *markers = push_array(scratch.arena, RD_MarkerList, section_count); + for (U64 symbol_idx = 0; symbol_idx < symbols.count; ++symbol_idx) { + COFF_Symbol32 *symbol = &symbols.v[symbol_idx]; + + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); + B32 is_marker = interp == COFF_SymbolValueInterp_REGULAR && + symbol->aux_symbol_count == 0 && + (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC); + + if (is_marker) { + String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + + RD_MarkerNode *n = push_array(scratch.arena, RD_MarkerNode, 1); + n->v.off = symbol->value; + n->v.string = name; + + RD_MarkerList *list = &markers[symbol->section_number-1]; + SLLQueuePush(list->first, list->last, n); + ++list->count; + } + + symbol_idx += symbol->aux_symbol_count; + } + + // lists -> arrays + RD_MarkerArray *result = push_array(arena, RD_MarkerArray, section_count); + for (U64 i = 0; i < section_count; ++i) { + result[i].count = 0; + result[i].v = push_array(arena, RD_Marker, markers[i].count); + for (RD_MarkerNode *n = markers[i].first; n != 0; n = n->next) { + result[i].v[result[i].count++] = n->v; + } + } + + // sort arrays + for (U64 i = 0; i < section_count; ++i) { + radsort(result[i].v, result[i].count, rd_marker_is_before); + } + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ Disasm + +internal RD_DisasmResult +rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) +{ + RD_DisasmResult result = {0}; + + switch (arch) { + case Arch_Null: break; + + case Arch_x64: + case Arch_x86: { + ZydisMachineMode machine_mode = bit_size_from_arch(arch) == 32 ? ZYDIS_MACHINE_MODE_LEGACY_32 : ZYDIS_MACHINE_MODE_LONG_64; + ZydisDisassembledInstruction inst = {0}; + ZyanStatus status = ZydisDisassemble(machine_mode, addr, raw_code.str, raw_code.size, &inst, ZYDIS_FORMATTER_STYLE_INTEL); + + String8 text = str8_cstring_capped(inst.text, inst.text+sizeof(inst.text)); + result.text = push_str8_copy(arena, text); + result.size = inst.info.length; + } break; + + default: NotImplemented; + } + + return result; +} + +internal void +rd_format_disasm(Arena *arena, + String8List *out, + String8 indent, + Arch arch, + U64 image_base, + U64 sect_off, + U64 marker_count, + RD_Marker *markers, + String8 raw_code) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 bytes_buffer_max = 256; + U8 *bytes_buffer = push_array(scratch.arena, U8, bytes_buffer_max); + + U64 decode_off = 0; + U64 marker_cursor = 0; + String8 to_decode = raw_code; + + for (; to_decode.size > 0; ) { + Temp temp = temp_begin(scratch.arena); + + // decode instruction + U64 addr = image_base + sect_off + decode_off; + RD_DisasmResult disasm_result = rd_disasm_next_instruction(temp.arena, arch, addr, to_decode); + + // format instruction bytes + String8 bytes; + { + U64 bytes_size = 0; + for (U64 i = 0; i < disasm_result.size; ++i) { + bytes_size += raddbg_snprintf(bytes_buffer + bytes_size, bytes_buffer_max-bytes_size, "%s%02x", i > 0 ? " " : "", to_decode.str[i]); + } + bytes = str8(bytes_buffer, bytes_size); + } + + // print address marker + if (marker_cursor < marker_count) { + RD_Marker *m = &markers[marker_cursor]; + // NOTE: markers must be sorted on address + if (decode_off <= m->off && m->off < decode_off + disasm_result.size) { + if (m->off != decode_off) { + U64 off = m->off - decode_off; + rd_printf("; %S+%#llx", m->string, addr); + } else { + rd_printf("; %S", m->string); + } + marker_cursor += 1; + } + } + + // print final line + rd_printf("%#08x: %-32S %S", addr, bytes, disasm_result.text); + + // advance + to_decode = str8_skip(to_decode, disasm_result.size); + decode_off += disasm_result.size; + + temp_end(temp); + } + + scratch_end(scratch); +} + +//////////////////////////////// +//~ Raw Data + +internal String8 +rd_format_hex_array(Arena *arena, U8 *ptr, U64 size) +{ + U64 buf_max = size * 3; + U8 *buf = push_array(arena, U8, buf_max); + U64 buf_size = 0; + + for (U64 i = 0; i < size; ++i) { + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "%s%02x", i>0 ? " " : "", ptr[i]); + } + + buf[buf_size] = '\0'; + + String8 result = str8(buf, buf_size); + return result; +} + +internal void +rd_format_raw_data(Arena *arena, + String8List *out, + String8 indent, + U64 bytes_per_row, + U64 marker_count, + RD_Marker *markers, + String8 raw_data) +{ + AssertAlways(bytes_per_row > 0); + + U8 temp_buffer[1024]; + + String8 to_format = raw_data; + for (; to_format.size > 0; ) { + String8 raw_row = str8_prefix(to_format, bytes_per_row); + + U64 temp_cursor = 0; + + // offset + U64 offset = (U64)(raw_row.str-raw_data.str); + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08x: ", offset); + + // hex + for (U64 i = 0; i < raw_row.size; ++i) { + U8 b = raw_row.str[i]; + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%s%02x", i>0 ? " " : "", b); + } + U64 hex_indent_size = (bytes_per_row - raw_row.size) * 3; + MemorySet(temp_buffer+temp_cursor, ' ', hex_indent_size); + temp_cursor += hex_indent_size; + + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer) - temp_cursor, " "); + + // ascii + for (U64 i = 0; i < raw_row.size; ++i) { + U8 b = raw_row.str[i]; + U8 c = b; + if (c < ' ' || c > '~') { + c = '.'; + } + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%c", c); + } + + rd_printf("%.*s", temp_cursor, temp_buffer); + + // advance + to_format = str8_skip(to_format, bytes_per_row); + } +} + +//- CodeView + +internal void +cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) +{ + if (raw_data.size) { + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("Binary Annotations:"); + rd_indent(); + + U64 cursor = 0; + for (; cursor < raw_data.size; ) { + String8List op_list = {0}; + + U8 op; + cursor += str8_deserial_read_struct(raw_data, cursor, &op); + if (op == CV_InlineBinaryAnnotation_Null) { + break; + } + + U8 params[2]; + U32 param_count = (op == CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset) ? 2 : 1; + cursor += str8_deserial_read_array(raw_data, cursor, ¶ms[0], param_count); + + String8 opcode_str = cv_string_from_binary_opcode(op); + str8_list_pushf(scratch.arena, &op_list, "%S", opcode_str); + for (U32 i = 0; i < param_count; ++i) { + str8_list_pushf(scratch.arena, &op_list, " %x", params[i]); + } + + String8 op_str = str8_list_join(scratch.arena, &op_list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", op_str); + } + rd_unindent(); + + rd_printf("Binary Annotations Length: %u bytes (%u bytes padding)", raw_data.size, raw_data.size - cursor); + + scratch_end(scratch); + } +} + +internal void +cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range) +{ + rd_printf("Address Range: %04x:%08x Size: %#x", range.sec, range.off, range.len); +} + +internal void +cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data) +{ + U64 count = raw_data.size / sizeof(CV_LvarAddrGap); + if (count > 0) { + U64 cursor = 0; + rd_printf("# Address Gaps"); + rd_indent(); + for (U64 i = 0; i < count; ++i) { + CV_LvarAddrGap gap = {0}; + cursor += str8_deserial_read_struct(raw_data, cursor, &gap); + rd_printf("Off: %#x, Len %#x", gap.off, gap.len); + } + rd_unindent(); + } +} + +internal void +cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr) +{ + Temp scratch = scratch_begin(&arena,1); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, attr.seg, attr.off)); + rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, attr.flags)); + scratch_end(scratch); +} + +internal void +cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol) +{ + Temp scratch = scratch_begin(&arena, 1); + U64 cursor = 0; + switch (type) { + case CV_SymKind_THUNK32_ST: + case CV_SymKind_THUNK32: { + CV_SymThunk32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Parent: %x", sym.parent); + rd_printf("End: %x", sym.end); + rd_printf("Next: %x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u (bytes)", sym.len); + rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); + } break; + case CV_SymKind_FILESTATIC: { + CV_SymFileStatic sym = {0}; + String8 name = str8_zero(); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); + } break; + case CV_SymKind_CALLERS: + case CV_SymKind_CALLEES: { + CV_SymFunctionList sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + CV_TypeIndex *funcs = push_array(scratch.arena, CV_TypeIndex, sym.count); + cursor += str8_deserial_read_array(raw_symbol, cursor, &funcs[0], sym.count); + U32 invocation_count = (raw_symbol.size - cursor) / sizeof(U32); + U32 *invocations = push_array(arena, U32, invocation_count); + cursor += str8_deserial_read_array(raw_symbol, cursor, &invocations[0], invocation_count); + + rd_printf("Count: %u", sym.count); + rd_indent(); + for (U32 i = 0; i < sym.count; ++i) { + U32 invoks = i < invocation_count ? invocations[i] : 0; + rd_printf("%08x (%u)", funcs[i], invoks); + } + rd_unindent(); + } break; + case CV_SymKind_INLINEES: { + CV_SymInlinees sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Count: %u", sym.count); + rd_indent(); + for (U32 i = 0; i < sym.count; ++i) { + U32 itype; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &itype); + rd_printf("%S", cv_string_from_itype(arena, itype)); + } + rd_unindent(); + } break; + case CV_SymKind_INLINESITE: { + CV_SymInlineSite sym = {0}; + String8 raw_annots = str8_skip(raw_symbol, sizeof(CV_SymInlineSite)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_annots.size; + + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); + cv_format_binary_annots(arena, out, indent, arch, raw_annots); + } break; + case CV_SymKind_INLINESITE2: { + CV_SymInlineSite2 sym = {0}; + String8 raw_annots = str8_skip(raw_symbol, sizeof(CV_SymInlineSite2)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_annots.size; + + rd_printf("Parent: %#x", sym.parent_off); + rd_printf("End: %#x", sym.end_off); + rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); + rd_printf("Invocations: %u", sym.invocations); + cv_format_binary_annots(arena, out, indent, arch, raw_annots); + } break; + case CV_SymKind_INLINESITE_END: { + // nothing to report + } break; + case CV_SymKind_LTHREAD32_ST: + case CV_SymKind_GTHREAD32_ST: + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: { + CV_SymThread32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("TSL Address: %S", cv_string_sec_off(scratch.arena, sym.tls_seg, sym.tls_off)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_OBJNAME: { + CV_SymObjName sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Signature: %#x", sym.sig); + } break; + case CV_SymKind_BLOCK32_ST: + case CV_SymKind_BLOCK32: { + CV_SymBlock32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Parent: %x", sym.parent); + rd_printf("End: %x", sym.end); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u (bytes)", sym.len); + } break; + case CV_SymKind_LABEL32_ST: + case CV_SymKind_LABEL32: { + CV_SymLabel32 sym = {0}; + String8 name = str8_zero(); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + } break; + case CV_SymKind_COMPILE: { + Assert(!"TODO: test"); + CV_SymCompile sym = {0}; + String8 version_string = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); + + U32 language = CV_CompileFlags_Extract_Language(sym.flags); + U32 float_prec = CV_CompileFlags_ExtractFloatPrec(sym.flags); + U32 float_pkg = CV_CompileFlags_ExtractFloatPkg(sym.flags); + U32 ambient_data = CV_CompileFlags_ExtractAmbientData(sym.flags); + U32 mode = CV_CompileFlags_ExtractMode(sym.flags); + rd_printf("Arch: %S", cv_string_from_arch(sym.machine)); + rd_printf("Language: %S", cv_string_from_language(language)); + rd_printf("FloatPrec: %x", float_prec); + rd_printf("FloatPkg: %x", float_pkg); + rd_printf("Ambient Data: %x", ambient_data); + rd_printf("Mode: %x", mode); + rd_printf("Version String: %S", version_string); + } break; + case CV_SymKind_COMPILE2_ST: + case CV_SymKind_COMPILE2: { + Assert(!"TODO: test"); + CV_SymCompile2 sym = {0}; + String8 version_string = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); + + U32 language = CV_Compile2Flags_Extract_Language(sym.flags); + rd_printf("Machine: %S", cv_string_from_arch(sym.machine)); + rd_printf("Flags: %x", sym.flags); + rd_printf("Language: %S", cv_string_from_language(language)); + rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); + rd_printf("Frontend Build: %u", sym.ver_fe_build); + rd_printf("Backend Version: %u.%u", sym.ver_major, sym.ver_minor); + rd_printf("Backend Build: %u", sym.ver_build); + rd_printf("Version String: %S", version_string); + } break; + case CV_SymKind_COMPILE3: { + CV_SymCompile3 sym = {0}; + String8 version_string = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); + + U32 language = CV_Compile3Flags_Extract_Language(sym.flags); + rd_printf("Machine: %S", cv_string_from_arch(sym.machine)); + rd_printf("Flags: %x", sym.flags); + rd_printf("Language: %S", cv_string_from_language(language)); + rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); + rd_printf("Frontend Build: %u", sym.ver_fe_build); + rd_printf("Fontend QFE: %u", sym.ver_feqfe); + rd_printf("Backend Version: %u.%u", sym.ver_major, sym.ver_minor); + rd_printf("Backend Build: %u", sym.ver_build); + rd_printf("Backend QFE: %u", sym.ver_qfe); + rd_printf("Version String: %S", version_string); + } break; + case CV_SymKind_GPROC32_ST: + case CV_SymKind_LPROC32_ST: + case CV_SymKind_GPROC32_ID: + case CV_SymKind_LPROC32_ID: + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: { + CV_SymProc32 sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + String8 name = str8_zero(); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Next: %#x", sym.next); + rd_printf("Length: %u (bytes)", sym.len); + rd_printf("Debug Start: %#x", sym.dbg_start); + rd_printf("Debug End: %#x", sym.dbg_end); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + } break; + case CV_SymKind_LDATA32_ST: + case CV_SymKind_GDATA32_ST: + case CV_SymKind_GDATA32: + case CV_SymKind_LDATA32: { + CV_SymData32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + } break; + case CV_SymKind_CONSTANT_ST: + case CV_SymKind_CONSTANT: { + CV_SymConstant sym = {0}; + CV_NumericParsed size = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += cv_read_numeric(raw_symbol, cursor, &size); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, size)); + } break; + case CV_SymKind_FRAMEPROC: { + CV_SymFrameproc sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + String8 flags = cv_string_from_frame_proc_flags(scratch.arena, sym.flags); + U32 local_ptr = CV_FrameprocFlags_Extract_LocalBasePointer(sym.flags); + U32 param_ptr = CV_FrameprocFlags_Extract_ParamBasePointer(sym.flags); + rd_printf("Frame Size: %x", sym.frame_size); + rd_printf("Pad Size: %x", sym.pad_size); + rd_printf("Pad Offset: %x", sym.pad_off); + rd_printf("Save Registers Area: %u (bytes)", sym.save_reg_size); + rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); + rd_printf("Flags: %S", flags); + rd_printf("Local pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, local_ptr))); + rd_printf("Param pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, param_ptr))); + } break; + case CV_SymKind_LOCAL: { + CV_SymLocal sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); + } break; + case CV_SymKind_DEFRANGE: { + CV_SymDefrange sym = {0}; + String8 raw_gaps = str8_skip(raw_symbol, sizeof(CV_SymDefrange)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_gaps.size; + + rd_printf("Program: %#x", sym.program); + cv_format_lvar_addr_range(arena, out, indent, sym.range); + cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + } break; + case CV_SymKind_DEFRANGE_REGISTER: { + CV_SymDefrangeRegister sym = {0}; + String8 raw_gaps = str8_skip(raw_symbol, sizeof(CV_SymDefrangeRegisterRel)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_gaps.size; + + rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); + cv_format_lvar_addr_range(arena, out, indent, sym.range); + cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + } break; + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: { + CV_SymDefrangeFramepointerRel sym = {0}; + String8 raw_gaps = str8_skip(raw_symbol, sizeof(CV_SymDefrangeFramepointerRel)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Offset: %#x", sym.off); + cv_format_lvar_addr_range(arena, out, indent, sym.range); + cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + } break; + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: { + CV_SymDefrangeSubfieldRegister sym = {0}; + String8 raw_gaps = str8_skip(raw_symbol, sizeof(CV_SymDefrangeSubfieldRegister)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_gaps.size; + + rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); + rd_printf("Parent Offset: %#x", sym.field_offset); + cv_format_lvar_addr_range(arena, out, indent, sym.range); + cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + } break; + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: { + CV_SymDefrangeFramepointerRelFullScope sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + rd_printf("Offset: %#x", sym.off); + } break; + case CV_SymKind_DEFRANGE_REGISTER_REL: { + CV_SymDefrangeRegisterRel sym = {0}; + String8 raw_gaps = str8_skip(raw_symbol, sizeof(CV_SymDefrangeRegisterRel)); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += raw_gaps.size; + + rd_printf("Flags: %S", cv_string_from_defrange_register_rel_flags(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); + cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + } break; + case CV_SymKind_END: + case CV_SymKind_PROC_ID_END: { + // no data + } break; + case CV_SymKind_UDT_ST: + case CV_SymKind_UDT: { + CV_SymUDT sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_BUILDINFO: { + CV_SymBuildInfo sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + rd_printf("ID: %#x", sym.id); + } break; + case CV_SymKind_UNAMESPACE_ST: + case CV_SymKind_UNAMESPACE: { + String8 name = {0}; + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + } break; + case CV_SymKind_REGREL32_ST: + case CV_SymKind_REGREL32: { + CV_SymRegrel32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_CALLSITEINFO: { + CV_SymCallSiteInfo sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Pad: %u (bytes)", sym.pad); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_FRAMECOOKIE: { + CV_SymFrameCookie sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Address: %S", cv_string_sec_off(arena, sym.reg, sym.off)); + rd_printf("Kind: %S", cv_string_from_frame_cookie_kind(sym.kind)); + rd_printf("Flags: %#x", sym.flags); // TODO: llvm and cvinfo.h don't define these flags... + } break; + case CV_SymKind_HEAPALLOCSITE: { + CV_SymHeapAllocSite sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + String8 addr = cv_string_sec_off(arena, sym.sec, sym.off); + String8 itype = cv_string_from_itype(arena, sym.itype); + rd_printf("Address: %S", addr); + rd_printf("Type: %S", itype); + rd_printf("Call instruction length: %x (bytes)", sym.call_inst_len); + } break; + case CV_SymKind_ALIGN: { + // spec: + // Unused data. Use the length field that precedes every symbol record + // to skip this record. The pad bytes must be zero. For sstGlobalSym + // and sstGlobalPub, the length of the pad field must be at least the + // sizeof (long). There must be an S_Align symbol at the end of these + // tables with a pad field containing 0xffffffff. The sstStaticSym table + // does not have this requirement + } break; + case CV_SymKind_SKIP: { + // Unused data, tools use this symbol to reserve space for future expansion + // in incremental builds. + } break; + case CV_SymKind_ENDARG: { + // spec: + // This symbol specifies the end of symbol records used in formal arguments for a function. Use of + // this symbol is optional for OMF and required for MIPS-compiled code. In OMF format, the end + // of arguments can also be deduced from the fact that arguments for a function have a positive + // offset from the frame pointer. + } break; + case CV_SymKind_CVRESERVE: { + // Reserved for MS debugger + } break; + case CV_SymKind_SSEARCH: { + Assert(!"TODO: test"); + + CV_SymStartSearch sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Start Symbol: %#x", sym.start_symbol); + rd_printf("Segment: %#x", sym.segment); + } break; + case CV_SymKind_RETURN: { + Assert(!"TODO: test"); + + CV_SymReturn sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Flags: S", cv_string_from_generic_flags(scratch.arena, sym.flags)); + rd_printf("Style: S", cv_string_from_generic_style(sym.style)); + if (sym.style == CV_GenericStyle_REG) { + U8 count = 0; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &count); + + rd_printf("Byte Count: %u", count); + rd_printf("Data:"); + rd_indent(); + for (U8 i = 0; i < count; ++i) { + U8 v; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); + rd_printf(" %02x", v); + } + rd_unindent(); + } + } break; + case CV_SymKind_ENTRYTHIS: { + Assert(!"TODO: test"); + + U16 symbol_size = 0, symbol_type = 0; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_size); + cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_type); + String8 raw_subsym = str8_skip(raw_symbol, cursor); + + cv_format_symbol(arena, out, indent, arch, type, raw_subsym); + } break; + case CV_SymKind_SLINK32: { + Assert(!"ret"); + + CV_SymSLink32 sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Frame Size: %x", sym.frame_size); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.offset)); + } break; + case CV_SymKind_OEM: { + Assert(!"TODO: test"); + + CV_SymOEM sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + // TODO: Not clear what to do about user data that follows, are we supposed to assume that + // rest of the range is it? + // + // CV-spec doesn't even mention S_OEM just LF_OEM and cvdump.exe prints out type with guid... + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("ID: %S", string_from_guid(scratch.arena, sym.id)); + } break; + case CV_SymKind_VFTABLE32:{ + Assert(!"TODO: test"); + + CV_SymVPath32 sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Root: %S", cv_string_from_itype(scratch.arena, sym.root)); + rd_printf("Path: %S", cv_string_from_itype(scratch.arena, sym.path)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); + } break; + case CV_SymKind_PUB32_ST: + case CV_SymKind_PUB32: { + CV_SymPub32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Flags: %S", cv_string_from_pub32_flags(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + } break; + case CV_SymKind_BPREL32_ST: + case CV_SymKind_BPREL32: { + Assert(!"TODO: test"); + + CV_SymBPRel32 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Offset: %#x", sym.off); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_REGISTER: { + Assert(!"TODO: test"); + + CV_SymRegister sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_PROCREF_ST: + case CV_SymKind_DATAREF_ST: + case CV_SymKind_LPROCREF_ST: + case CV_SymKind_ANNOTATIONREF: + case CV_SymKind_LPROCREF: + case CV_SymKind_PROCREF: + case CV_SymKind_DATAREF: { + Assert(!"TODO: test"); + + CV_SymRef2 sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("SUC: %#x", sym.suc_name); + rd_printf("IMod: %#x", sym.imod); + rd_printf("Symbol Stream Offset: %#x", sym.sym_off); + } break; + case CV_SymKind_SEPCODE: { + Assert(!"TODO: test"); + + CV_SymSepcode sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Length: %u (bytes)", sym.len); + rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); + rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); + } break; + case CV_SymKind_PARAMSLOT_ST: + case CV_SymKind_LOCALSLOT_ST: + case CV_SymKind_LOCALSLOT: { + Assert(!"TODO: test"); + + CV_SymSlot sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Slot: %u", sym.slot_index); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + } break; + case CV_SymKind_TRAMPOLINE: { + Assert(!"TODO: test"); + + CV_SymTrampoline sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); + rd_printf("Thunk Size: %u (bytes)", sym.thunk_size); + rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); + rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); + } break; + case CV_SymKind_POGODATA: { + Assert(!"TODO: test"); + + CV_SymPogoInfo sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Invocations: %u", sym.invocations); + rd_printf("Dynamic instruction count: %u", sym.dynamic_inst_count); + rd_printf("Static instruction count: %u", sym.static_inst_count); + rd_printf("Post inline static instruction count: %u", sym.post_inline_static_inst_count); + } break; + case CV_SymKind_MANYREG: { + Assert(!"TODO: test"); + + CV_SymManyreg sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Reg Count: %u", sym.count); + rd_printf("Regs:"); + rd_indent(); + for (U8 i = 0; i < sym.count; ++i) { + U8 v = 0; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); + rd_printf("%S", cv_string_from_reg_id(arch, v)); + } + rd_unindent(); + } break; + case CV_SymKind_MANYREG2_ST: + case CV_SymKind_MANYREG2: { + Assert(!"TODO: test"); + + CV_SymManyreg sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Reg Count: %u", sym.count); + rd_printf("Regs:"); + rd_indent(); + for (U16 i = 0; i < sym.count; ++i) { + U16 v = 0; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); + rd_printf("%S", cv_string_from_reg_id(arch, v)); + } + rd_unindent(); + } break; + case CV_SymKind_SECTION: { + Assert(!"TODO: test"); + + CV_SymSection sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Index: %u", sym.sec_index); + rd_printf("Align: %u", sym.align); + rd_printf("Virtual Offset: %#x", sym.rva); + rd_printf("Size: %u (bytes)", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + } break; + case CV_SymKind_ENVBLOCK: { + CV_SymEnvBlock sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + for (; cursor < raw_symbol.size; ) { + String8 id = str8_zero(); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &id); + String8 path = str8_zero(); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &path); + if (id.size == 0 && path.size == 0) { + break; + } + rd_printf("%S = %S", id, path); + } + } break; + case CV_SymKind_COFFGROUP: { + Assert(!"TODO: test"); + + CV_SymCoffGroup sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Size: %u (bytes)", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + } break; + case CV_SymKind_EXPORT: { + Assert(!"TODO: test"); + + CV_SymExport sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Ordinal: %#x", sym.ordinal); + rd_printf("Flags: %S", cv_string_from_export_flags(scratch.arena, sym.flags)); + } break; + case CV_SymKind_ANNOTATION: { + Assert(!"TODO: test"); + + CV_SymAnnotation sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); + rd_printf("Count: %u", sym.count); + rd_printf("Annotations:"); + rd_indent(); + for (U16 i = 0; i < sym.count; ++i) { + String8 str = str8_zero(); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &str); + rd_printf("%S", str); + } + rd_unindent(); + } break; + case CV_SymKind_MANFRAMEREL: + case CV_SymKind_ATTR_FRAMEREL: { + Assert(!"TODO: test"); + + CV_SymAttrFrameRel sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Offset: %#x", sym.off); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + cv_format_lvar_attr(arena, out, indent, sym.attr); + } break; + case CV_SymKind_MANREGISTER: + case CV_SymKind_ATTR_REGISTER: { + Assert(!"TODO: test"); + + CV_SymAttrReg sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + cv_format_lvar_attr(arena, out, indent, sym.attr); + } break; + case CV_SymKind_ATTR_REGREL: { + Assert(!"TODO: test"); + + CV_SymAttrRegRel sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.off)); + cv_format_lvar_attr(arena, out, indent, sym.attr); + } break; + case CV_SymKind_MANYREG_ST: + case CV_SymKind_MANMANYREG: + case CV_SymKind_ATTR_MANYREG: { + Assert(!"TODO: test"); + + CV_SymAttrManyReg sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + U8 *regs = push_array(scratch.arena, U8, sym.count); + cursor += str8_deserial_read_array(raw_symbol, cursor, ®s[0], sym.count); + String8 name = str8_zero(); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Reg Count: %u", sym.count); + rd_printf("Regs:"); + rd_indent(); + for (U8 i = 0; i < sym.count; ++i) { + rd_printf("%S", cv_string_from_reg_id(arch, regs[i])); + } + rd_unindent(); + } break; + case CV_SymKind_MOD_TYPEREF: { + + Assert(!"TODO: test"); + + CV_SymModTypeRef sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + String8List flags_list = {0}; + if (sym.flags & CV_ModTypeRefFlag_None) { + str8_list_pushf(scratch.arena, &flags_list, "No TypeRef"); + } else if (sym.flags & CV_ModTypeRefFlag_OwnTMR) { + str8_list_pushf(scratch.arena, &flags_list, "/Z7 TypeRef, SN=%04X", sym.word0); + if (sym.flags & CV_ModTypeRefFlag_OwnTMPCT) { + str8_list_pushf(scratch.arena, &flags_list, "own PCH types"); + } + if (sym.flags & CV_ModTypeRefFlag_RefTMPCT) { + str8_list_pushf(scratch.arena, &flags_list, "reference PCH types in module %04X", (sym.word1+1)); + } + } else { + str8_list_pushf(scratch.arena, &flags_list, "/Zi TypeRef"); + if (sym.flags & CV_ModTypeRefFlag_OwnTM) { + str8_list_pushf(scratch.arena, &flags_list, "SN=%04X (type), SN=%04X (ID)", sym.word0, sym.word1); + } + if (sym.flags & CV_ModTypeRefFlag_RefTM) { + str8_list_pushf(scratch.arena, &flags_list, "shared with Module %04X", sym.word0+1); + } + } + String8 flags_str = str8_list_join(scratch.arena, &flags_list, &(StringJoin){.sep=str8_lit(", ")}); + + rd_printf("%S", flags_str); + } break; + case CV_SymKind_DISCARDED: { + Assert(!"TODO: test"); + + CV_SymDiscarded sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + U32 symbol_type = 0; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_type); + String8 raw_subsym = str8_skip(raw_symbol, cursor); + + rd_printf("Kind: %x", sym.kind); + rd_printf("File ID: %x", sym.file_id); + rd_printf("File Line Number: %u", sym.file_ln); + rd_printf("# Discarded Symbol"); + cv_format_symbol(arena, out, indent, arch, symbol_type, raw_subsym); + } break; + case CV_SymKind_PDBMAP: { + Assert(!"TODO: test"); + + String8 from = {0}; + String8 to = {0}; + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &from); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &to); + + rd_printf("From: %S", from); + rd_printf("To: %S", to); + } break; + case CV_SymKind_FASTLINK: { + Assert(!"TODO: test"); + + CV_SymFastLink sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Flags: %x", sym.flags); + rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + } break; + case CV_SymKind_ARMSWITCHTABLE: { + Assert(!"TODO: test"); + + CV_SymArmSwitchTable sym = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + + rd_printf("Base Address: %S", cv_string_sec_off(scratch.arena, sym.sec_base, sym.off_base)); + rd_printf("Branch Address: %S", cv_string_sec_off(scratch.arena, sym.sec_branch, sym.off_branch)); + rd_printf("Table Address: %S", cv_string_sec_off(scratch.arena, sym.sec_table, sym.off_table)); + rd_printf("Entry count: %u", sym.entry_count); + rd_printf("Switch Type: %x", sym.kind); + } break; + case CV_SymKind_REF_MINIPDB: { + Assert(!"TODO: test"); + + CV_SymRefMiniPdb sym = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); + cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Flags: %x", sym.flags); + rd_printf("IMod: %04x", sym.imod); + if (sym.flags & CV_RefMiniPdbFlag_UDT) { + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, (CV_TypeIndex)sym.data)); + } else { + rd_printf("Coff ISect: %#x", sym.data); + } + } break; + // COBOL + case CV_SymKind_CEXMODEL32: + case CV_SymKind_COBOLUDT_ST: + case CV_SymKind_COBOLUDT: + // Pascal + case CV_SymKind_WITH32_ST: + case CV_SymKind_WITH32: + //~ 16bit + case CV_SymKind_REGISTER_16t: + case CV_SymKind_CONSTANT_16t: + case CV_SymKind_UDT_16t: + case CV_SymKind_OBJNAME_ST: + case CV_SymKind_COBOLUDT_16t: + case CV_SymKind_MANYREG_16t: + case CV_SymKind_BPREL16: + case CV_SymKind_LDATA16: + case CV_SymKind_GDATA16: + case CV_SymKind_PUB16: + case CV_SymKind_LPROC16: + case CV_SymKind_GPROC16: + case CV_SymKind_THUNK16: + case CV_SymKind_BLOCK16: + case CV_SymKind_WITH16: + case CV_SymKind_LABEL16: + case CV_SymKind_CEXMODEL16: + case CV_SymKind_VFTABLE16: + case CV_SymKind_REGREL16: + case CV_SymKind_TI16_MAX: + //~ 16:32 memory model + case CV_SymKind_BPREL32_16t: + case CV_SymKind_LDATA32_16t: + case CV_SymKind_GDATA32_16t: + case CV_SymKind_PUB32_16t: + case CV_SymKind_LPROC32_16t: + case CV_SymKind_GPROC32_16t: + case CV_SymKind_VFTABLE32_16t: + case CV_SymKind_REGREL32_16t: + case CV_SymKind_LTHREAD32_16t: + case CV_SymKind_GTHREAD32_16t: + case CV_SymKind_LPROCMIPS_16t: + case CV_SymKind_GPROCMIPS_16t: + // MIPS + case CV_SymKind_LPROCMIPS_ST: + case CV_SymKind_GPROCMIPS_ST: + case CV_SymKind_LPROCMIPS: + case CV_SymKind_GPROCMIPS: + case CV_SymKind_LPROCIA64: + case CV_SymKind_GPROCIA64: + case CV_SymKind_LPROCMIPS_ID: + case CV_SymKind_GPROCMIPS_ID: + // Managed + case CV_SymKind_TOKENREF: + case CV_SymKind_GMANPROC_ST: + case CV_SymKind_LMANPROC_ST: + case CV_SymKind_LMANDATA_ST: + case CV_SymKind_GMANDATA_ST: + case CV_SymKind_MANFRAMEREL_ST: + case CV_SymKind_MANREGISTER_ST: + case CV_SymKind_MANSLOT_ST: + case CV_SymKind_MANTYPREF: + case CV_SymKind_MANMANYREG_ST: + case CV_SymKind_MANREGREL_ST: + case CV_SymKind_MANMANYREG2_ST: + case CV_SymKind_MANMANYREG2: + case CV_SymKind_MANREGREL: + case CV_SymKind_MANSLOT: + case CV_SymKind_MANCONSTANT: + case CV_SymKind_LMANDATA: + case CV_SymKind_GMANDATA: + case CV_SymKind_GMANPROC: + case CV_SymKind_LMANPROC: + // HLSL + case CV_SymKind_DEFRANGE_DPC_PTR_TAG: + case CV_SymKind_DPC_SYM_TAG_MAP: + case CV_SymKind_DEFRANGE_HLSL: + case CV_SymKind_GDATA_HLSL: + case CV_SymKind_LDATA_HLSL: + case CV_SymKind_LPROC32_DPC: + case CV_SymKind_LPROC32_DPC_ID: + case CV_SymKind_GDATA_HLSL32: + case CV_SymKind_LDATA_HLSL32: + case CV_SymKind_GDATA_HLSL32_EX: + case CV_SymKind_LDATA_HLSL32_EX: + // IA64 + case CV_SymKind_LPROCIA64_ID: + case CV_SymKind_GPROCIA64_ID: + // VS2005 + case CV_SymKind_DEFRANGE_2005: + case CV_SymKind_DEFRANGE2_2005: + case CV_SymKind_ST_MAX: + case CV_SymKind_RESERVED1: + case CV_SymKind_RESERVED2: + case CV_SymKind_RESERVED3: + case CV_SymKind_RESERVED4: { + } break; + } + scratch_end(scratch); +} + +internal U64 +cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf) +{ + Temp scratch = scratch_begin(&arena, 1); + U64 cursor = 0; + switch (kind) { + case CV_LeafKind_NOTYPE: { + // empty + } break; + case CV_LeafKind_BITFIELD: { + CV_LeafBitField lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Length: %u", lf.len); + rd_printf("Position: %u", lf.pos); + } break; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: { + CV_LeafStruct2 lf = {0}; + CV_NumericParsed size = {0}; + String8 name = str8_zero(); + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &size); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); + rd_printf("Unknown1: %x", lf.unknown1); + rd_printf("Unknown2: %x", lf.unknown2); + if (lf.props & CV_TypeProp_HasUniqueName) { + String8 unique_name = str8_zero(); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); + rd_printf("Unique Name: %S", unique_name); + } + } break; + case CV_LeafKind_PRECOMP_ST: + case CV_LeafKind_PRECOMP: { + CV_LeafPreComp lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Start Index: %x", lf.start_index); + rd_printf("Count: %u", lf.count); + rd_printf("Signature: %x", lf.sig); + } break; + case CV_LeafKind_TYPESERVER2: { + CV_LeafTypeServer2 lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Sig70: %S", string_from_guid(arena, lf.sig70)); + rd_printf("Age: %u", lf.age); + } break; + case CV_LeafKind_BUILDINFO: { + CV_LeafBuildInfo lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Entry Count: %u", lf.count); + rd_indent(); + for (U16 i = 0; i < lf.count; ++i) { + CV_ItemId id = 0; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &id); + rd_printf("%S", cv_string_from_itemid(scratch.arena, id)); + } + rd_unindent(); + } break; + case CV_LeafKind_MFUNC_ID: { + CV_LeafMFuncId lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + rd_printf("Name: %S", name); + rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, lf.owner_itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_VFUNCTAB: { + CV_LeafVFuncTab lf = {0}; + cursor += syms_based_range_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_METHODLIST: { + for (; cursor < raw_leaf.size; ) { + CV_LeafMethodListMember ml = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &ml); + U32 mprop = CV_FieldAttribs_Extract_MPROP(ml.attribs); + B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); + U32 vbase = 0; + if (has_vbase) { + cursor += str8_deserial_read_struct(raw_leaf, cursor, &vbase); + } + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, ml.attribs)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, ml.itype)); + if (has_vbase) { + rd_printf("Virtual Base: %x", vbase); + } + } + } break; + case CV_LeafKind_ONEMETHOD_ST: + case CV_LeafKind_ONEMETHOD: { + CV_LeafOneMethod lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + U32 mprop = CV_FieldAttribs_Extract_MPROP(lf.attribs); + B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); + U32 vbase = 0; + if (has_vbase) { + cursor += str8_deserial_read_struct(raw_leaf, cursor, &vbase); + } + String8 name = {0}; + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + rd_printf("Name: %S", name); + rd_printf("Field Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + if (has_vbase) { + rd_printf("Virtual Base: %#x", vbase); + } + } break; + case CV_LeafKind_METHOD_ST: + case CV_LeafKind_METHOD: { + CV_LeafMethod lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Count: %u", lf.count); + rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, lf.list_itype)); + } break; + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: { + CV_LeafVBClass lf = {0}; + CV_NumericParsed vbptr_off = {0}; + CV_NumericParsed vbtable_off = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &vbptr_off); + cursor += cv_read_numeric(raw_leaf, cursor, &vbtable_off); + + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, lf.vbptr_itype)); + rd_printf("vbpoff: %S", cv_string_from_numeric(scratch.arena, vbptr_off)); + rd_printf("vbind: %S", cv_string_from_numeric(scratch.arena, vbtable_off)); + } break; + case CV_LeafKind_BCLASS: { + CV_LeafBClass lf = {0}; + CV_NumericParsed offset = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &offset); + + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, offset)); + } break; + case CV_LeafKind_VTSHAPE: { + CV_LeafVTShape lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Entry Count: %u", lf.count); + rd_indent(); + for (U16 i = 0; i < lf.count; ++i) { + U8 packed_kind = 0; + str8_deserial_read_struct(raw_leaf, cursor + (i / 2), &packed_kind); + U8 kind = (packed_kind >> ((i % 2)*4)) & 0xF; + rd_printf("%S", cv_string_from_virtual_table_shape_kind(kind)); + } + rd_unindent(); + cursor += (lf.count * sizeof(U8) + 1) / 2; + } break; + case CV_LeafKind_STMEMBER_ST: + case CV_LeafKind_STMEMBER: { + CV_LeafStMember lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_MFUNCTION: { + CV_LeafMFunction lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, lf.class_itype)); + rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, lf.this_itype)); + rd_printf("Call Kind: %S", cv_string_from_call_kind(lf.call_kind)); + rd_printf("Function Attribs: %S", cv_string_from_function_attribs(scratch.arena, lf.attribs)); + rd_printf("Argument Count: %u", lf.arg_count); + rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + } break; + #if 0 + case CV_LeafKind_SKIP_16t: { + CV_LeafSkip_16t lf = {0}; + cursor += str8_deserial_read_struct(base, range, cursor, &lf); + + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.type)); + } break; + #endif + case CV_LeafKind_SKIP: { + // ms-symbol-pdf: + // This is used by incremental compilers to reserve space for indices. + CV_LeafSkip lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_ENUM_ST: + case CV_LeafKind_ENUM: { + CV_LeafEnum lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.base_itype)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + if (lf.props & CV_TypeProp_HasUniqueName) { + String8 unique_name = {0}; + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); + rd_printf("Unique Name: %S", unique_name); + } + } break; + case CV_LeafKind_ENUMERATE: { + CV_LeafEnumerate lf = {0}; + CV_NumericParsed value = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &value); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Value: %S", cv_string_from_numeric(scratch.arena, value)); + } break; + case CV_LeafKind_NESTTYPE_ST: + case CV_LeafKind_NESTTYPE: { + CV_LeafNestType lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + rd_printf("Name: %S", name); + rd_printf("Index: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_NOTTRAN: { + // ms-symbol-pdf: + // This is used when CVPACK encounters a type record that has no equivalent in the Microsoftsymbol information format. + } break; + case CV_LeafKind_UDT_SRC_LINE: { + CV_LeafUDTSrcLine lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Type = %S, Source File = %x, Line = %u", cv_string_from_itype(scratch.arena, lf.udt_itype), lf.src_string_id, lf.line); + } break; + case CV_LeafKind_STRING_ID: { + CV_LeafStringId lf = {0}; + String8 string = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &string); + + rd_printf("string: %S", string); + rd_printf("Substrings: %x", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead + } break; + case CV_LeafKind_POINTER: { + CV_LeafPointer lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + CV_PointerKind kind = CV_PointerAttribs_Extract_KIND(lf.attribs); + CV_PointerMode mode = CV_PointerAttribs_Extract_MODE(lf.attribs); + + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Attribs: %S", cv_string_from_pointer_attribs(arena, lf.attribs)); + rd_printf("Kind: %S", cv_string_from_pointer_kind(kind)); + rd_printf("Mode: %S", cv_string_from_pointer_mode(mode)); + rd_indent(); + if (mode == CV_PointerMode_PtrMem) { + CV_TypeIndex itype = 0; + CV_MemberPointerKind pm = 0; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); + cursor += str8_deserial_read_struct(raw_leaf, cursor, &pm); + + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, itype)); + rd_printf("Format: %S", cv_string_from_member_pointer_kind(pm)); + } else { + if (kind == CV_PointerKind_BaseSeg) { + U16 seg; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &seg); + + rd_printf("Base Segment: %#04x", seg); + } else if (kind == CV_PointerKind_BaseType) { + CV_TypeIndex base_itype = 0; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &base_itype); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, base_itype)); + rd_printf("Name: %S", name); + } + } + rd_unindent(); + } break; + case CV_LeafKind_UNION_ST: + case CV_LeafKind_UNION: { + CV_LeafUnion lf = {0}; + CV_NumericParsed num = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &num); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %s", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + } break; + case CV_LeafKind_CLASS_ST: + case CV_LeafKind_STRUCTURE_ST: + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: { + CV_LeafStruct lf = {0}; + CV_NumericParsed num = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &num); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); + rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + if (lf.props & CV_TypeProp_HasUniqueName) { + String8 unique_name = {0}; + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); + rd_printf("Unique Name: %S", unique_name); + } + } break; + case CV_LeafKind_SUBSTR_LIST: + case CV_LeafKind_ARGLIST: { + CV_LeafArgList lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Types %u", lf.count); + rd_indent(); + for (U32 i = 0; i < lf.count; ++i) { + U32 itype = 0; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); + rd_printf("%S", cv_string_from_itype(scratch.arena, itype)); + } + rd_unindent(); + } break; + case CV_LeafKind_PROCEDURE: { + CV_LeafProcedure lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + String8 call_kind = cv_string_from_call_kind(lf.call_kind); + String8 func_attribs = cv_string_from_function_attribs(scratch.arena, lf.attribs); + + rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); + rd_printf("Call Convention: %S", call_kind); + rd_printf("Function Attribs: %S", func_attribs); + rd_printf("Argumnet Count: %u", lf.arg_count); + rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + } break; + case CV_LeafKind_FUNC_ID: { + CV_LeafFuncId lf = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, lf.scope_string_id)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + } break; + case CV_LeafKind_MODIFIER: { + CV_LeafModifier lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Flags: %S", cv_string_from_modifier_flags(scratch.arena, lf.flags)); + } break; + case CV_LeafKind_ARRAY_ST: + case CV_LeafKind_ARRAY: { + CV_LeafArray lf = {0}; + CV_NumericParsed num = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &num); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, lf.entry_itype)); + rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, lf.index_itype)); + rd_printf("Length: %S", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name: %S", name); + } break; + case CV_LeafKind_FIELDLIST: { + for (U64 idx = 0; cursor < raw_leaf.size;) { + U16 member_type = 0; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &member_type); + String8 raw_member = str8_skip(raw_leaf, cursor); + + rd_printf("list[%u] = %S", idx++, cv_string_from_leaf_name(arena, member_type)); + rd_indent(); + cursor += cv_format_leaf(arena, out, indent, member_type, raw_member); + cursor = AlignPow2(cursor, 4); + rd_unindent(); + } + } break; + case CV_LeafKind_MEMBER_ST: + case CV_LeafKind_MEMBER: { + CV_LeafMember lf = {0}; + CV_NumericParsed num = {0}; + String8 name = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + cursor += cv_read_numeric(raw_leaf, cursor, &num); + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); + + rd_printf("Name: %S", name); + rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, num)); + } break; + // 16bit + case CV_LeafKind_OEM_16t: + case CV_LeafKind_MODIFIER_16t: + case CV_LeafKind_POINTER_16t: + case CV_LeafKind_ARRAY_16t: + case CV_LeafKind_CLASS_16t: + case CV_LeafKind_STRUCTURE_16t: + case CV_LeafKind_UNION_16t: + case CV_LeafKind_ENUM_16t: + case CV_LeafKind_PROCEDURE_16t: + case CV_LeafKind_MFUNCTION_16t: + case CV_LeafKind_COBOL0_16t: + case CV_LeafKind_BARRAY_16t: + case CV_LeafKind_DIMARRAY_16t: + case CV_LeafKind_VFTPATH_16t: + case CV_LeafKind_PRECOMP_16t: + case CV_LeafKind_ARGLIST_16t: + case CV_LeafKind_DEFARG_16t: + case CV_LeafKind_FIELDLIST_16t: + case CV_LeafKind_DERIVED_16t: + case CV_LeafKind_BITFIELD_16t: + case CV_LeafKind_METHODLIST_16t: + case CV_LeafKind_DIMCONU_16t: + case CV_LeafKind_DIMCONLU_16t: + case CV_LeafKind_DIMVARU_16t: + case CV_LeafKind_DIMVARLU_16t: + case CV_LeafKind_BCLASS_16t: + case CV_LeafKind_VBCLASS_16t: + case CV_LeafKind_IVBCLASS_16t: + case CV_LeafKind_ENUMERATE_ST: + case CV_LeafKind_FRIENDFCN_16t: + case CV_LeafKind_INDEX_16t: + case CV_LeafKind_MEMBER_16t: + case CV_LeafKind_STMEMBER_16t: + case CV_LeafKind_METHOD_16t: + case CV_LeafKind_NESTTYPE_16t: + case CV_LeafKind_VFUNCTAB_16t: + case CV_LeafKind_FRIENDCLS_16t: + case CV_LeafKind_ONEMETHOD_16t: + case CV_LeafKind_VFUNCOFF_16t: + case CV_LeafKind_ST_MAX: + // HLSL + case CV_LeafKind_HLSL: + // COBOL + case CV_LeafKind_COBOL0: + case CV_LeafKind_COBOL1: + // Manged + case CV_LeafKind_MANAGED_ST: + // undefined + case CV_LeafKind_LABEL: + case CV_LeafKind_ENDPRECOMP: + case CV_LeafKind_LIST: + case CV_LeafKind_REFSYM: + case CV_LeafKind_BARRAY: + case CV_LeafKind_DIMARRAY_ST: + case CV_LeafKind_VFTPATH: + case CV_LeafKind_OEM: + case CV_LeafKind_ALIAS_ST: + case CV_LeafKind_OEM2: + case CV_LeafKind_DEFARG_ST: + case CV_LeafKind_DERIVED: + case CV_LeafKind_DIMCONU: + case CV_LeafKind_DIMCONLU: + case CV_LeafKind_DIMVARU: + case CV_LeafKind_DIMVARLU: + case CV_LeafKind_FRIENDFCN_ST: + case CV_LeafKind_INDEX: + case CV_LeafKind_FRIENDCLS: + case CV_LeafKind_VFUNCOFF: + case CV_LeafKind_MEMBERMODIFY_ST: + case CV_LeafKind_TYPESERVER_ST: + case CV_LeafKind_TYPESERVER: + case CV_LeafKind_DIMARRAY: + case CV_LeafKind_ALIAS: + case CV_LeafKind_DEFARG: + case CV_LeafKind_FRIENDFCN: + case CV_LeafKind_NESTTYPEEX: + case CV_LeafKind_MEMBERMODIFY: + case CV_LeafKind_MANAGED: + case CV_LeafKind_STRIDED_ARRAY: + case CV_LeafKind_MODIFIER_EX: + case CV_LeafKind_INTERFACE: + case CV_LeafKind_BINTERFACE: + case CV_LeafKind_VECTOR: + case CV_LeafKind_MATRIX: + case CV_LeafKind_VFTABLE: + case CV_LeafKind_UDT_MOD_SRC_LINE: { + rd_errorf("TODO: %#x", kind); + } break; + } + scratch_end(scratch); + return cursor; +} + +internal void +cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t) +{ + Temp scratch = scratch_begin(&arena, 1); + for (U64 lf_idx = 0; lf_idx < debug_t.count; ++lf_idx) { + CV_Leaf lf = cv_debug_t_get_leaf(debug_t, lf_idx); + U64 offset = (U64)(lf.data.str-debug_t.v[0]); + rd_printf("%S (%#x) [%04x-%04x)", cv_string_from_leaf_kind(lf.kind), offset, offset+lf.data.size); + rd_indent(); + coff_format_leaf(arena, out, indent, lf.kind, lf.data); + rd_unindent(); + } + scratch_end(scratch); +} + +internal void +cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data) +{ + CV_Arch arch = ~0u; + + for (U64 cursor = 0; cursor < raw_data.size; ) { + CV_SymbolHeader header = {0}; + cursor += str8_deserial_read_struct(raw_data, cursor, &header); + + if (header.kind == CV_SymKind_COMPILE) { + if (header.size >= sizeof(CV_SymCompile)) { + CV_SymCompile *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE"); + } + } else if (header.kind == CV_SymKind_COMPILE2) { + if (header.size >= sizeof(CV_SymCompile2)) { + CV_SymCompile2 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE2"); + } + } else if (header.kind == CV_SymKind_COMPILE3) { + if (header.size >= sizeof(CV_SymCompile3)) { + CV_SymCompile3 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE3"); + } + } + + if (header.size >= sizeof(header.kind)) { + U64 symbol_end = cursor + (header.size - sizeof(header.kind)); + String8 raw_symbol = str8_substr(raw_data, rng_1u64(cursor, symbol_end)); + + rd_printf("%S [%04x-%04x)", cv_string_from_sym_kinds(header.kind), cursor, header.size-sizeof(header.size)); + rd_indent(); + cv_format_symbol(arena, out, indent, arch, header.kind, raw_symbol); + rd_unindent(); + + cursor = symbol_end; + } else { + rd_errorf("symbol must be at least two bytes long"); + } + } +} + +internal void +cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 cursor = 0; + + CV_C13SubSecLinesHeader header = {0}; + cursor += str8_deserial_read_struct(raw_lines, cursor, &header); + + B32 has_columns = !!(header.flags & CV_C13SubSecLinesFlag_HasColumns); + if (has_columns) { + rd_errorf("TOOD: columns"); + } + + rd_printf("%04x:%08x-%08x, flags = %04x", header.sec, header.sec_off, header.len, header.flags); + + for (; cursor < raw_lines.size; ) { + CV_C13File file = {0}; + cursor += str8_deserial_read_struct(raw_lines, cursor, &file); + + rd_printf("file = %08x, line count = %u, block size %08x", file.file_off, file.num_lines, file.block_size); + + Temp temp = temp_begin(scratch.arena); + String8List columns = {0}; + for (U32 line_idx = 0; line_idx < file.num_lines; ++line_idx) { + CV_C13Line line = {0}; + cursor += str8_deserial_read_struct(raw_lines, cursor, &line); + + B32 always_step_in_line_number = line.off == 0xFEEFEE; + B32 never_step_in_line_number = line.off == 0xF00F00; + + U32 ln = CV_C13LineFlags_ExtractLineNumber(line.flags); + //U32 delta = CV_C13LineFlags_ExtractDeltaToEnd(line.flags); + //B32 is_stmt = CV_C13LineFlags_ExtractStatement(line.flags); + + if (always_step_in_line_number || never_step_in_line_number) { + str8_list_pushf(temp.arena, &columns, "%x %08X", ln, line.off); + } else { + str8_list_pushf(temp.arena, &columns, "%5u %08X", ln, line.off); + } + + if ((line_idx+1) % 4 == 0 || (line_idx+1) == file.num_lines) { + String8 line_str = str8_list_join(scratch.arena, &columns, &(StringJoin){.sep=str8_lit("\t")}); + rd_printf("%S", line_str); + + temp_end(temp); + temp = temp_begin(scratch.arena); + MemoryZeroStruct(&columns); + } + } + temp_end(temp); + + if (cursor < raw_lines.size) { + rd_newline(); + } + } + + scratch_end(scratch); +} + +internal void +cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums) +{ + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("%8s %8s %8s %16s", "File", "Size", "Type", "Chksum"); + for (U64 cursor = 0; cursor < raw_chksums.size; ) { + CV_C13Checksum chksum = {0}; + cursor += str8_deserial_read_struct(raw_chksums, cursor, &chksum); + cursor = AlignPow2(cursor, CV_FileCheckSumsAlign); + + Temp temp = temp_begin(scratch.arena); + String8 chksum_str = str8_lit("???"); + U8 *chksum_ptr = str8_deserial_get_raw_ptr(raw_chksums, cursor, chksum.len); + if (chksum_ptr) { + chksum_str = rd_format_hex_array(temp.arena, chksum_ptr, chksum.len); + } + + rd_printf("%08x %08x %8S %S", + chksum.name_off, + chksum.len, + cv_string_from_c13_checksum_kind(chksum.kind), + chksum_str); + + temp_end(temp); + } + + scratch_end(scratch); +} + +internal void +cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab) +{ + for (U64 cursor = 0; cursor < raw_strtab.size; ) { + String8 str = {0}; + cursor += str8_deserial_read_cstr(raw_strtab, cursor, &str); + rd_printf("%08x %S", cursor, str); + } +} + +internal void +cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 cursor = 0; + + U32 inlinee_sig = ~0u; + cursor += str8_deserial_read_struct(raw_data, cursor, &inlinee_sig); + + switch (inlinee_sig) { + case CV_C13InlineeLinesSig_NORMAL: { + rd_printf("%-8s %-8s %-8s", "Inlinee", "File ID", "Base LN"); + for (; cursor < raw_data.size; ) { + CV_C13InlineeSourceLineHeader line = {0}; + cursor += str8_deserial_read_struct(raw_data, cursor, &line); + rd_printf("%08x %08x %8u", line.inlinee, line.file_off, line.first_source_ln); + } + + } break; + case CV_C13InlineeLinesSig_EXTRA_FILES: { + rd_printf("%-8s %-8s %-8s %s", "Inlinee", "File ID", "Base LN", "Extra FileIDs"); + for (; cursor < raw_data.size; ) { + Temp temp = temp_begin(scratch.arena); + + CV_C13InlineeSourceLineHeader line = {0}; + U32 extra_file_count = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &line); + cursor += str8_deserial_read_struct(raw_data, cursor, &extra_file_count); + + String8List extra_files_list = {0}; + for (U32 i = 0; i < extra_file_count; ++i) { + U32 file_id = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &file_id); + str8_list_pushf(temp.arena, &extra_files_list, "%08x", file_id); + } + String8 extra_files = str8_list_join(temp.arena, &extra_files_list, &(StringJoin){.sep=str8_lit(" ,")}); + + rd_printf("%08x %08x %u %S", line.inlinee, line.file_off, line.first_source_ln, extra_files); + + temp_end(temp); + } + } break; + } + + scratch_end(scratch); +} + +internal void +cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 cursor = 0; + U32 cv_sig = 0; + cursor += str8_deserial_read_struct(raw_ss, cursor, &cv_sig); + + for (; cursor < raw_ss.size; ) { + U64 sst_offset = 0; + CV_C13SubSectionHeader ss_header = {0}; + switch (cv_sig) { + case CV_Signature_C6: { + rd_printf("TODO: C6"); + } break; + + case CV_Signature_C7: { + rd_printf("TODO: C7"); + } break; + + case CV_Signature_C11: { + ss_header.kind = CV_C13SubSectionKind_Symbols; + ss_header.size = raw_ss.size - sizeof(cv_sig); + + rd_printf("# CodeView C11"); + rd_newline(); + } break; + case CV_Signature_C13: { + sst_offset = cursor; + cursor += str8_deserial_read_struct(raw_ss, cursor, &ss_header); + + coff_pritnf("# CodeView C13"); + rd_newline(); + } break; + } + + U64 sst_end = cursor + ss_header.size; + String8 raw_sst = str8_substr(raw_ss, rng_1u64(cursor, sst_end)); + cursor = AlignPow2(sst_end, CV_C13SubSectionAlign); + + rd_printf("# %S [%llx-%llx)", cv_string_from_c13_subsection_kind(ss_header.kind), sst_offset, sst_end); + rd_indent(); + switch (ss_header.kind) { + case CV_C13SubSectionKind_Symbols: { + cv_format_symbols_c13(arena, out, indent, raw_sst); + } break; + case CV_C13SubSectionKind_Lines: { + cv_format_lines_c13(arena, out, indent, raw_sst); + } break; + case CV_C13SubSectionKind_FileChksms: { + cv_format_file_checksums(arena, out, indent, raw_sst); + } break; + case CV_C13SubSectionKind_StringTable: { + cv_format_string_table(arena, out, indent, raw_sst); + } break; + case CV_C13SubSectionKind_InlineeLines: { + cv_format_inlinee_lines(arena, out, indent, raw_sst); + } break; + case CV_C13SubSectionKind_FrameData: + case CV_C13SubSectionKind_CrossScopeImports: + case CV_C13SubSectionKind_CrossScopeExports: + case CV_C13SubSectionKind_IlLines: + case CV_C13SubSectionKind_FuncMDTokenMap: + case CV_C13SubSectionKind_TypeMDTokenMap: + case CV_C13SubSectionKind_MergedAssemblyInput: + case CV_C13SubSectionKind_CoffSymbolRVA: + case CV_C13SubSectionKind_XfgHashType: + case CV_C13SubSectionKind_XfgHashVirtual: + default: { + rd_printf("TODO"); + } break; + } + rd_unindent(); + } + + scratch_end(scratch); +} + +//- COFF + +internal void +coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp); + + rd_printf("Name: %S" , header.name ); + rd_printf("Time Stamp: %S" , time_stamp ); + rd_printf("User ID: %u" , header.user_id ); + rd_printf("Group ID: %u" , header.group_id); + rd_printf("Mode: %S" , header.mode ); + rd_printf("Data: [%#llx-%#llx)", header.data_range.min, header.data_range.max); + + scratch_end(scratch); +} + +internal void +coff_format_section_table(Arena *arena, + String8List *out, + String8 indent, + String8 raw_data, + U64 string_table_off, + COFF_Symbol32Array symbols, + U64 sect_count, + COFF_SectionHeader *sect_headers) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 *symlinks = push_array(scratch.arena, String8, sect_count); + for (U64 i = 0; i < symbols.count; ++i) { + COFF_Symbol32 *symbol = symbols.v+i; + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); + if (interp == COFF_SymbolValueInterp_REGULAR && + symbol->aux_symbol_count == 0 && + (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC)) { + if (symbol->section_number > 0 && symbol->section_number <= symbols.count) { + COFF_SectionHeader *header = sect_headers+(symbol->section_number-1); + if (header->flags & COFF_SectionFlag_LNK_COMDAT) { + symlinks[symbol->section_number-1] = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + } + } + } + i += symbol->aux_symbol_count; + } + + if (sect_count) { + rd_printf("# Section Table"); + rd_indent(); + + rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s", + "No.", + "Name", + "VirtSize", + "VirtOff", + "FileSize", + "FileOff", + "RelocOff", + "LinesOff", + "RelocCnt", + "LineCnt", + "Align", + "Flags", + "Symlink"); + + for (U64 i = 0; i < sect_count; ++i) { + COFF_SectionHeader *header = sect_headers+i; + + String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name)); + String8 full_name = coff_name_from_section_header(header, raw_data, string_table_off); + + String8 align; + { + U64 align_size = coff_align_size_from_section_flags(header->flags); + align = push_str8f(scratch.arena, "%u", align_size); + } + + String8 flags; + { + String8List mem_flags = {0}; + if (header->flags & COFF_SectionFlag_MEM_READ) { + str8_list_pushf(scratch.arena, &mem_flags, "r"); + } + if (header->flags & COFF_SectionFlag_MEM_WRITE) { + str8_list_pushf(scratch.arena, &mem_flags, "w"); + } + if (header->flags & COFF_SectionFlag_MEM_EXECUTE) { + str8_list_pushf(scratch.arena, &mem_flags, "x"); + } + + String8List cnt_flags = {0}; + if (header->flags & COFF_SectionFlag_CNT_CODE) { + str8_list_pushf(scratch.arena, &cnt_flags, "c"); + } + if (header->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &cnt_flags, "d"); + } + if (header->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &cnt_flags, "u"); + } + + String8List mem_extra_flags = {0}; + if (header->flags & COFF_SectionFlag_MEM_SHARED) { + str8_list_pushf(scratch.arena, &mem_flags, "s"); + } + if (header->flags & COFF_SectionFlag_MEM_16BIT) { + str8_list_pushf(scratch.arena, &mem_extra_flags, "h"); + } + if (header->flags & COFF_SectionFlag_MEM_LOCKED) { + str8_list_pushf(scratch.arena, &mem_extra_flags, "l"); + } + if (header->flags & COFF_SectionFlag_MEM_DISCARDABLE) { + str8_list_pushf(scratch.arena, &mem_extra_flags, "d"); + } + if (header->flags & COFF_SectionFlag_MEM_NOT_CACHED) { + str8_list_pushf(scratch.arena, &mem_extra_flags, "c"); + } + if (header->flags & COFF_SectionFlag_MEM_NOT_PAGED) { + str8_list_pushf(scratch.arena, &mem_extra_flags, "p"); + } + + String8List lnk_flags = {0}; + if (header->flags & COFF_SectionFlag_LNK_REMOVE) { + str8_list_pushf(scratch.arena, &lnk_flags, "r"); + } + if (header->flags & COFF_SectionFlag_LNK_COMDAT) { + str8_list_pushf(scratch.arena, &lnk_flags, "c"); + } + if (header->flags & COFF_SectionFlag_LNK_OTHER) { + str8_list_pushf(scratch.arena, &lnk_flags, "o"); + } + if (header->flags & COFF_SectionFlag_LNK_INFO) { + str8_list_pushf(scratch.arena, &lnk_flags, "i"); + } + if (header->flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { + str8_list_pushf(scratch.arena, &lnk_flags, "f"); + } + + String8List other_flags = {0}; + if (header->flags & COFF_SectionFlag_TYPE_NO_PAD) { + str8_list_pushf(scratch.arena, &other_flags, "n"); + } + if (header->flags & COFF_SectionFlag_GPREL) { + str8_list_pushf(scratch.arena, &other_flags, "g"); + } + + String8 mem = str8_list_join(scratch.arena, &mem_flags, 0); + String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0); + String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0); + String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0); + String8 oth = str8_list_join(scratch.arena, &other_flags, 0); + + String8List f = {0}; + str8_list_push(scratch.arena, &f, mem); + str8_list_push(scratch.arena, &f, cnt); + str8_list_push(scratch.arena, &f, ext); + str8_list_push(scratch.arena, &f, lnk); + str8_list_push(scratch.arena, &f, oth); + + flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") }); + + if (!flags.size) { + flags = str8_lit("none"); + } + } + + String8List l = {0}; + str8_list_pushf(scratch.arena, &l, "%-4x", i+1 ); + str8_list_pushf(scratch.arena, &l, "%-8S", name ); + str8_list_pushf(scratch.arena, &l, "%08x", header->vsize ); + str8_list_pushf(scratch.arena, &l, "%08x", header->voff ); + str8_list_pushf(scratch.arena, &l, "%08x", header->fsize ); + str8_list_pushf(scratch.arena, &l, "%08x", header->foff ); + str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff); + str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff ); + str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count); + str8_list_pushf(scratch.arena, &l, "%08x", header->line_count ); + str8_list_pushf(scratch.arena, &l, "%-5S", align ); + str8_list_pushf(scratch.arena, &l, "%-10S", flags ); + if (symlinks[i].size > 0) { + str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]); + } else { + str8_list_pushf(scratch.arena, &l, "[no symlink]"); + } + + String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), }); + rd_printf("%S", line); + + if (full_name.size != name.size) { + rd_indent(); + rd_printf("Full Name: %S", full_name); + rd_unindent(); + } + } + + rd_newline(); + rd_printf("Flags:"); + rd_indent(); + rd_printf("r = MEM_READ w = MEM_WRITE x = MEM_EXECUTE"); + rd_printf("c = CNT_CODE d = INITIALIZED_DATA u = UNINITIALIZED_DATA"); + rd_printf("s = MEM_SHARED h = MEM_16BIT l = MEM_LOCKED d = MEM_DISCARDABLE c = MEM_NOT_CACHED p = MEM_NOT_PAGED"); + rd_printf("r = LNK_REMOVE c = LNK_COMDAT o = LNK_OTHER i = LNK_INFO f = LNK_NRELOC_OVFL"); + rd_printf("g = GPREL n = TYPE_NO_PAD"); + rd_unindent(); + + rd_unindent(); + rd_newline(); + } + + scratch_end(scratch); +} + +internal void +coff_disasm_sections(Arena *arena, + String8List *out, + String8 indent, + String8 raw_data, + COFF_MachineType machine, + U64 image_base, + B32 is_obj, + RD_MarkerArray *section_markers, + U64 section_count, + COFF_SectionHeader *sections) +{ + if (section_count) { + for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { + COFF_SectionHeader *sect = sections+sect_idx; + if (sect->flags & COFF_SectionFlag_CNT_CODE) { + U64 sect_off = is_obj ? sect->foff : sect->voff; + U64 sect_size = is_obj ? sect->fsize : sect->vsize; + String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); + RD_MarkerArray markers = section_markers[sect_idx]; + + rd_printf("# Disassembly [Section No. %#llx]", (sect_idx+1)); + rd_indent(); + rd_format_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); + rd_unindent(); + } + } + } +} + +internal void +coff_raw_data_sections(Arena *arena, + String8List *out, + String8 indent, + String8 raw_data, + B32 is_obj, + RD_MarkerArray *section_markers, + U64 section_count, + COFF_SectionHeader *sections) +{ + if (section_count) { + for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { + COFF_SectionHeader *sect = sections+sect_idx; + if (sect->fsize > 0) { + U64 sect_size = is_obj ? sect->fsize : sect->vsize; + String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); + RD_MarkerArray markers = section_markers[sect_idx]; + + rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1)); + rd_indent(); + rd_format_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); + rd_unindent(); + rd_newline(); + } + } + } +} + +internal void +coff_format_relocs(Arena *arena, + String8List *out, + String8 indent, + String8 raw_data, + U64 string_table_off, + COFF_MachineType machine, + U64 sect_count, + COFF_SectionHeader *sect_headers, + COFF_Symbol32Array symbols) +{ + Temp scratch = scratch_begin(&arena, 1); + + B32 print_header = 1; + + for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) { + COFF_SectionHeader *sect_header = sect_headers+sect_idx; + COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header); + + if (reloc_info.count) { + if (print_header) { + print_header = 0; + rd_printf("# Relocations"); + rd_indent(); + } + + rd_printf("## Section %llx", sect_idx); + rd_indent(); + + rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName"); + + for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) { + COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx; + String8 type = coff_string_from_reloc(machine, reloc->type); + U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type); + + U64 apply_foff = sect_header->foff + reloc->apply_off; + if (apply_foff + apply_size > raw_data.size) { + rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx); + break; + } + + U64 raw_apply; + AssertAlways(apply_size <= sizeof(raw_apply)); + MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size); + S64 apply = extend_sign64(raw_apply, apply_size); + + if (reloc->isymbol > symbols.count) { + rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx); + break; + } + + COFF_Symbol32 *symbol = symbols.v+reloc->isymbol; + String8 symbol_name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + + String8List line = {0}; + str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx ); + str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off); + str8_list_pushf(scratch.arena, &line, "%-16S", type ); + str8_list_pushf(scratch.arena, &line, "%016x", apply ); + str8_list_pushf(scratch.arena, &line, "%S", symbol_name ); + + String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", l); + } + + rd_unindent(); + } + } + + if (!print_header) { + rd_unindent(); + } + rd_newline(); + + scratch_end(scratch); +} + +internal void +coff_format_symbol_table(Arena *arena, + String8List *out, + String8 indent, + String8 raw_data, + B32 is_big_obj, + U64 string_table_off, + COFF_Symbol32Array symbols) +{ + Temp scratch = scratch_begin(&arena, 1); + + if (symbols.count) { + rd_printf("# Symbol Table"); + rd_indent(); + + rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s", + "No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name"); + + for (U64 i = 0; i < symbols.count; ++i) { + COFF_Symbol32 *symbol = &symbols.v[i]; + String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb); + String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb); + String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class); + String8 section_number; + switch (symbol->section_number) { + case COFF_SYMBOL_UNDEFINED_SECTION: section_number = str8_lit("UNDEF"); break; + case COFF_SYMBOL_ABS_SECTION: section_number = str8_lit("ABS"); break; + case COFF_SYMBOL_DEBUG_SECTION: section_number = str8_lit("DEBUG"); break; + default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break; + } + + String8List line = {0}; + str8_list_pushf(scratch.arena, &line, "%-4x", i ); + str8_list_pushf(scratch.arena, &line, "%08x", symbol->value ); + str8_list_pushf(scratch.arena, &line, "%-10S", section_number ); + str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count); + str8_list_pushf(scratch.arena, &line, "%-4S", msb ); + str8_list_pushf(scratch.arena, &line, "%-4S", lsb ); + str8_list_pushf(scratch.arena, &line, "%-16S", storage_class ); + str8_list_pushf(scratch.arena, &line, "%S", name ); + + String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")}); + rd_printf("%S", l); + + rd_indent(); + for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) { + void *raw_aux = &symbols.v[k]; + switch (symbol->storage_class) { + case COFF_SymStorageClass_EXTERNAL: { + COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k]; + rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x", + func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func); + } break; + case COFF_SymStorageClass_FUNCTION: { + COFF_SymbolFunc *func = raw_aux; + rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func); + } break; + case COFF_SymStorageClass_WEAK_EXTERNAL: { + COFF_SymbolWeakExt *weak = raw_aux; + String8 type = coff_string_from_weak_ext_type(weak->characteristics); + rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type); + } break; + case COFF_SymStorageClass_FILE: { + COFF_SymbolFile *file = raw_aux; + String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name)); + rd_printf("Name %S", name); + } break; + case COFF_SymStorageClass_STATIC: { + COFF_SymbolSecDef *sd = raw_aux; + String8 selection = coff_string_from_selection(sd->selection); + U32 number = sd->number_lo; + if (is_big_obj) { + number |= (U32)sd->number_hi << 16; + } + if (number) { + rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S", + sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection); + } else { + rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x", + sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum); + } + } break; + default: { + rd_printf("???"); + } break; + } + } + + i += symbol->aux_symbol_count; + rd_unindent(); + } + + rd_unindent(); + rd_newline(); + } + + scratch_end(scratch); +} + +internal void +coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp); + String8 machine = coff_string_from_machine_type(header->machine); + + rd_printf("# Big Obj"); + rd_indent(); + + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Machine: %S", machine ); + rd_printf("Section Count: %u", header->section_count ); + rd_printf("Symbol Table: %#x", header->symbol_table_foff); + rd_printf("Symbol Count: %u", header->symbol_count ); + + rd_unindent(); + + scratch_end(scratch); +} + +internal void +coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp); + String8 machine = coff_string_from_machine_type(header->machine); + String8 flags = coff_string_from_flags(scratch.arena, header->flags); + + rd_printf("# COFF Header"); + rd_indent(); + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Machine: %S", machine ); + rd_printf("Section Count: %u", header->section_count ); + rd_printf("Symbol Table: %#x", header->symbol_table_foff ); + rd_printf("Symbol Count: %u", header->symbol_count ); + rd_printf("Optional Header Size: %m", header->optional_header_size); + rd_printf("Flags: %S", flags ); + rd_unindent(); + + scratch_end(scratch); +} + +internal void +coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 machine = coff_string_from_machine_type(header->machine); + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp); + + rd_printf("# Import"); + rd_indent(); + rd_printf("Version: %u", header->version ); + rd_printf("Machine: %S", machine ); + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Data Size: %m", header->data_size); + rd_printf("Hint: %u", header->hint ); + rd_printf("Type: %u", header->type ); + rd_printf("Name Type: %u", header->name_type); + rd_printf("Function: %S", header->func_name); + rd_printf("DLL: %S", header->dll_name ); + rd_unindent(); + + scratch_end(scratch); +} + +internal void +coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +{ + Temp scratch = scratch_begin(&arena, 1); + + COFF_HeaderBigObj *big_obj = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(COFF_HeaderBigObj)); + COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sizeof(COFF_HeaderBigObj), sizeof(COFF_SectionHeader)*big_obj->section_count); + U64 string_table_off = big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count; + COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); + + if (opts & RD_Option_Headers) { + coff_format_big_obj_header(arena, out, indent, big_obj); + rd_newline(); + } + + if (opts & RD_Option_Sections) { + Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count); + Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count); + + if (sect_headers_range.max > raw_data.size) { + rd_errorf("not enough bytes to read big obj section headers"); + goto exit; + } + if (big_obj->symbol_count) { + if (symbols_range.max > raw_data.size) { + rd_errorf("not enough bytes to read big obj symbol table"); + goto exit; + } + if (contains_1u64(symbols_range, sect_headers_range.min) || + contains_1u64(symbols_range, sect_headers_range.max)) { + rd_errorf("section headers and symbol table ranges overlap"); + goto exit; + } + } + + coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); + rd_newline(); + } + + if (opts & RD_Option_Relocs) { + coff_format_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); + rd_newline(); + } + + if (opts & RD_Option_Symbols) { + coff_format_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); + rd_newline(); + } + +exit:; + scratch_end(scratch); +} + +internal void +coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +{ + Temp scratch = scratch_begin(&arena, 1); + + COFF_Header *header = (COFF_Header *)raw_data.str; + COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); + U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; + COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); + + if (opts & RD_Option_Headers) { + coff_format_header(arena, out, indent, header); + rd_newline(); + } + + if (opts & RD_Option_Sections) { + Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count); + Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count); + + if (sect_headers_range.max > raw_data.size) { + rd_errorf("not enough bytes to read obj section headers"); + goto exit; + } + if (header->symbol_count) { + if (symbols_range.max > raw_data.size) { + rd_errorf("not enough bytes to read obj symbol table"); + goto exit; + } + if (contains_1u64(symbols_range, sect_headers_range.min) || + contains_1u64(symbols_range, sect_headers_range.max)) { + rd_errorf("section headers and symbol table ranges overlap"); + goto exit; + } + } + + coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); + rd_newline(); + } + + if (opts & RD_Option_Relocs) { + coff_format_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); + rd_newline(); + } + + if (opts & RD_Option_Symbols) { + coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + rd_newline(); + } + + RD_MarkerArray *section_markers = 0; + if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) { + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, header->section_count, symbols); + } + + if (opts & RD_Option_Rawdata) { + coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, sections); + } + + if (opts & RD_Option_Disasm) { + coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, sections); + rd_newline(); + } + +exit:; + scratch_end(scratch); +} + +internal void +coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts) +{ + Temp scratch = scratch_begin(&arena, 1); + + COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive); + + if (archive_parse.error.size) { + rd_errorf("%S", archive_parse.error); + return; + } + + COFF_ArchiveFirstMember first_member = archive_parse.first_member; + { + rd_printf("# First Header"); + rd_indent(); + + rd_printf("Symbol Count: %u", first_member.symbol_count); + rd_printf("String Table Size: %M", first_member.string_table.size); + + rd_printf("Members:"); + rd_indent(); + + String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0); + + if (string_table.node_count == first_member.member_offset_count) { + String8Node *string_n = string_table.first; + + for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) { + U32 offset = from_be_u32(first_member.member_offsets[i]); + rd_printf("[%4u] %#08x %S", i, offset, string_n->string); + } + } else { + rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count); + } + + rd_unindent(); + rd_unindent(); + rd_newline(); + } + + if (archive_parse.has_second_header) { + COFF_ArchiveSecondMember second_member = archive_parse.second_member; + + rd_printf("# Second Header"); + rd_indent(); + + rd_printf("Member Count: %u", second_member.member_count); + rd_printf("Symbol Count: %u", second_member.symbol_count); + rd_printf("String Table Size: %M", second_member.string_table.size); + + String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0); + + rd_printf("Members:"); + rd_indent(); + if (second_member.symbol_index_count == second_member.symbol_count) { + String8Node *string_n = string_table.first; + for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) { + U16 symbol_number = second_member.symbol_indices[i]; + if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) { + U16 symbol_idx = symbol_number - 1; + U32 member_offset = second_member.member_offsets[i]; + rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string); + } else { + rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number); + break; + } + } + } else { + rd_errorf("Symbol index count %u doesn't match symbol count %u", + second_member.symbol_index_count, second_member.symbol_count); + } + rd_unindent(); + + rd_unindent(); + rd_newline(); + } + + if (archive_parse.has_long_names && opts & RD_Option_LongNames) { + rd_printf("# Long Names"); + rd_indent(); + + String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0); + U64 name_idx = 0; + for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) { + U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str); + rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string); + } + + rd_unindent(); + rd_newline(); + } + + U64 member_offset_count = 0; + U32 *member_offsets = 0; + if (archive_parse.has_second_header) { + member_offset_count = archive_parse.second_member.member_offset_count; + member_offsets = archive_parse.second_member.member_offsets; + } else { + HashTable *ht = hash_table_init(scratch.arena, 0x1000); + for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) { + U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]); + if (!hash_table_search_u32(ht, member_offset)) { + hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0); + } + } + member_offset_count = ht->count; + member_offsets = keys_from_hash_table_u32(scratch.arena, ht); + radsort(member_offsets, member_offset_count, u32_is_before); + } + + rd_printf("# Members"); + rd_indent(); + + for (U64 i = 0; i < member_offset_count; ++i) { + U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size; + U64 member_offset = member_offsets[i]; + String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset)); + COFF_ArchiveMember member = coff_archive_member_from_data(raw_member); + COFF_DataType member_type = coff_data_type_from_data(member.data); + + rd_printf("Member @ %#llx", member_offset); + rd_indent(); + + if (opts & RD_Option_Headers) { + coff_format_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); + rd_newline(); + } + + switch (member_type) { + case COFF_DataType_BIG_OBJ: { + coff_format_big_obj(arena, out, indent, member.data, opts); + } break; + case COFF_DataType_OBJ: { + coff_format_obj(arena, out, indent, member.data, opts); + } break; + case COFF_DataType_IMPORT: { + if (opts & RD_Option_Headers) { + COFF_ImportHeader header = {0}; + U64 parse_size = coff_parse_archive_import(member.data, 0, &header); + if (parse_size) { + coff_format_import(arena, out, indent, &header); + } else { + rd_errorf("not enough bytes to parse import header"); + } + } + } break; + case COFF_DataType_NULL: { + rd_errorf("unknown member format", member_offset); + } break; + } + + rd_unindent(); + rd_newline(); + } + + rd_unindent(); + + scratch_end(scratch); +} + +//- MSVC CRT + +internal void +mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler) +{ + String8 catch_line = str8_zero(); // TODO: syms_line_for_voff(scratch.arena, group, handler->catch_handler_voff); + String8 adjectives_str = mscrt_string_from_eh_adjectives(arena, handler->adjectives); + rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); + rd_printf("Descriptor: %#x", handler->descriptor_voff); + rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); + rd_printf("Catch Handler: %#x %S", handler->catch_handler_voff, catch_line); + rd_printf("Delta to FP Handler: %#x", handler->fp_distance); +} + +//////////////////////////////// +//~ PE + +internal void +pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("# Data Directories"); + rd_indent(); + for (U64 i = 0; i < count; ++i) { + String8 dir_name; + if (i < PE_DataDirectoryIndex_COUNT) { + dir_name = pe_string_from_data_directory_index(i); + } else { + dir_name = push_str8f(scratch.arena, "%#x", i); + } + rd_printf("%-16S [%08x-%08x)", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size); + } + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); + String8 dll_chars = pe_string_from_dll_characteristics(scratch.arena, opt_header->dll_characteristics); + + rd_printf("# PE Optional Header 32"); + rd_indent(); + rd_printf("Magic: %#x", opt_header->magic); + rd_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); + rd_printf("Size of code: %m", opt_header->sizeof_code); + rd_printf("Size of inited data: %m", opt_header->sizeof_inited_data); + rd_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); + rd_printf("Entry point: %#x", opt_header->entry_point_va); + rd_printf("Code base: %#x", opt_header->code_base); + rd_printf("Data base: %#x", opt_header->data_base); + rd_printf("Image base: %#x", opt_header->image_base); + rd_printf("Section align: %#x", opt_header->section_alignment); + rd_printf("File align: %#x", opt_header->file_alignment); + rd_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); + rd_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); + rd_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); + rd_printf("Win32 version: %u", opt_header->win32_version_value); + rd_printf("Size of image: %m", opt_header->sizeof_image); + rd_printf("Size of headers: %m", opt_header->sizeof_headers); + rd_printf("Checksum: %#x", opt_header->check_sum); + rd_printf("Subsystem: %S", subsystem); + rd_printf("DLL Characteristics: %S", dll_chars); + rd_printf("Stack reserve: %m", opt_header->sizeof_stack_reserve); + rd_printf("Stack commit: %m", opt_header->sizeof_stack_commit); + rd_printf("Heap reserve: %m", opt_header->sizeof_heap_reserve); + rd_printf("Heap commit: %m", opt_header->sizeof_heap_commit); + rd_printf("Loader flags: %#x", opt_header->loader_flags); + rd_printf("RVA and offset count: %u", opt_header->data_dir_count); + rd_newline(); + + pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + rd_newline(); + + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); + String8 dll_chars = pe_string_from_dll_characteristics(scratch.arena, opt_header->dll_characteristics); + + rd_printf("# PE Optional Header 32+"); + rd_indent(); + rd_printf("Magic: %#x", opt_header->magic); + rd_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); + rd_printf("Size of code: %m", opt_header->sizeof_code); + rd_printf("Size of inited data: %m", opt_header->sizeof_inited_data); + rd_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); + rd_printf("Entry point: %#x", opt_header->entry_point_va); + rd_printf("Code base: %#x", opt_header->code_base); + rd_printf("Image base: %#llx", opt_header->image_base); + rd_printf("Section align: %#x", opt_header->section_alignment); + rd_printf("File align: %#x", opt_header->file_alignment); + rd_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); + rd_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); + rd_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); + rd_printf("Win32 version: %u", opt_header->win32_version_value); + rd_printf("Size of image: %m", opt_header->sizeof_image); + rd_printf("Size of headers: %m", opt_header->sizeof_headers); + rd_printf("Checksum: %#x", opt_header->check_sum); + rd_printf("Subsystem: %S", subsystem); + rd_printf("DLL Characteristics: %S", dll_chars); + rd_printf("Stack reserve: %M", opt_header->sizeof_stack_reserve); + rd_printf("Stack commit: %M", opt_header->sizeof_stack_commit); + rd_printf("Heap reserve: %M", opt_header->sizeof_heap_reserve); + rd_printf("Heap commit: %M", opt_header->sizeof_heap_commit); + rd_printf("Loader flags: %#x", opt_header->loader_flags); + rd_printf("RVA and offset count: %u", opt_header->data_dir_count); + rd_newline(); + + pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + rd_newline(); + + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, lc->time_stamp); + String8 global_flag_clear = pe_string_from_global_flags(scratch.arena, lc->global_flag_clear); + String8 global_flag_set = pe_string_from_global_flags(scratch.arena, lc->global_flag_set); + + rd_printf("# Load Config 32"); + rd_indent(); + + rd_printf("Size: %m", lc->size); + rd_printf("Time stamp: %#x (%S)", lc->time_stamp, time_stamp); + rd_printf("Version: %u.%u", lc->major_version, lc->minor_version); + rd_printf("Global flag clear: %#x %S", global_flag_clear); + rd_printf("Global flag set: %#x %S", global_flag_set); + rd_printf("Critical section timeout: %u", lc->critical_section_timeout); + rd_printf("Decommit free block threshold: %#x", lc->decommit_free_block_threshold); + rd_printf("Decommit total free threshold: %#x", lc->decommit_total_free_threshold); + rd_printf("Lock prefix table: %#x", lc->lock_prefix_table); + rd_printf("Maximum alloc size: %m", lc->maximum_allocation_size); + rd_printf("Virtual memory threshold: %m", lc->virtual_memory_threshold); + rd_printf("Process affinity mask: %#x", lc->process_affinity_mask); + rd_printf("Process heap flags: %#x", lc->process_heap_flags); + rd_printf("CSD version: %u", lc->csd_version); + rd_printf("Edit list: %#x", lc->edit_list); + rd_printf("Security Cookie: %#x", lc->security_cookie); + if (lc->size < OffsetOf(PE_LoadConfig64, seh_handler_table)) { + goto exit; + } + rd_newline(); + + rd_printf("SEH Handler Table: %#x", lc->seh_handler_table); + rd_printf("SEH Handler Count: %u", lc->seh_handler_count); + if (lc->size < OffsetOf(PE_LoadConfig64, guard_cf_check_func_ptr)) { + goto exit; + } + rd_newline(); + + rd_printf("Guard CF Check Function: %#x", lc->guard_cf_check_func_ptr); + rd_printf("Guard CF Dispatch Function: %#x", lc->guard_cf_dispatch_func_ptr); + rd_printf("Guard CF Function Table: %#x", lc->guard_cf_func_table); + rd_printf("Guard CF Function Count: %u", lc->guard_cf_func_count); + rd_printf("Guard Flags: %#x", lc->guard_flags); + if (lc->size < OffsetOf(PE_LoadConfig64, code_integrity)) { + goto exit; + } + rd_newline(); + + rd_printf("Code integrity: { Flags = %#x, Catalog = %#x, Catalog Offset = %#x }", + lc->code_integrity.flags, lc->code_integrity.catalog, lc->code_integrity.catalog_offset); + rd_printf("Guard address taken IAT entry table: %#x", lc->guard_address_taken_iat_entry_table); + rd_printf("Guard address taken IAT entry count: %u", lc->guard_address_taken_iat_entry_count); + rd_printf("Guard long jump target table: %#x", lc->guard_long_jump_target_table); + rd_printf("Guard long jump target count: %u", lc->guard_long_jump_target_count); + rd_printf("Dynamic value reloc table: %#x", lc->dynamic_value_reloc_table); + rd_printf("CHPE Metadata ptr: %#x", lc->chpe_metadata_ptr); + rd_printf("Guard RF failure routine: %#x", lc->guard_rf_failure_routine); + rd_printf("Guard RF failure routine func ptr: %#x", lc->guard_rf_failure_routine_func_ptr); + rd_printf("Dynamic value reloc section: %#x", lc->dynamic_value_reloc_table_section); + rd_printf("Dynamic value reloc section offset: %#x", lc->dynamic_value_reloc_table_offset); + rd_printf("Guard RF verify SP func ptr: %#x", lc->guard_rf_verify_stack_pointer_func_ptr); + rd_printf("Hot patch table offset: %#x", lc->hot_patch_table_offset); + if (lc->size < OffsetOf(PE_LoadConfig64, enclave_config_ptr)) { + goto exit; + } + rd_newline(); + + rd_printf("Enclave config ptr: %#x", lc->enclave_config_ptr); + rd_printf("Volatile metadata ptr: %#x", lc->volatile_metadata_ptr); + rd_printf("Guard EH continuation table: %#x", lc->guard_eh_continue_table); + rd_printf("Guard EH continuation count: %u", lc->guard_eh_continue_count); + rd_printf("Guard XFG check func ptr: %#x", lc->guard_xfg_check_func_ptr); + rd_printf("Guard XFG dispatch func ptr: %#x", lc->guard_xfg_dispatch_func_ptr); + rd_printf("Guard XFG table dispatch func ptr: %#x", lc->guard_xfg_table_dispatch_func_ptr); + rd_printf("Cast guard OS determined failure mode: %#x", lc->cast_guard_os_determined_failure_mode); + rd_newline(); + +exit:; + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, lc->time_stamp); + String8 global_flag_clear = pe_string_from_global_flags(scratch.arena, lc->global_flag_clear); + String8 global_flag_set = pe_string_from_global_flags(scratch.arena, lc->global_flag_set); + + rd_printf("# Load Config 64"); + rd_indent(); + + rd_printf("Size: %m", lc->size); + rd_printf("Time stamp: %#x (%S)", lc->time_stamp, time_stamp); + rd_printf("Version: %u.%u", lc->major_version, lc->minor_version); + rd_printf("Global flag clear: %#x %S", lc->global_flag_clear, global_flag_clear); + rd_printf("Global flag set: %#x %S", lc->global_flag_set, global_flag_set); + rd_printf("Critical section timeout: %u", lc->critical_section_timeout); + rd_printf("Decommit free block threshold: %#llx", lc->decommit_free_block_threshold); + rd_printf("Decommit total free threshold: %#llx", lc->decommit_total_free_threshold); + rd_printf("Lock prefix table: %#llx", lc->lock_prefix_table); + rd_printf("Maximum alloc size: %M", lc->maximum_allocation_size); + rd_printf("Virtual memory threshold: %M", lc->virtual_memory_threshold); + rd_printf("Process affinity mask: %#x", lc->process_affinity_mask); + rd_printf("Process heap flags: %#x", lc->process_heap_flags); + rd_printf("CSD version: %u", lc->csd_version); + rd_printf("Edit list: %#llx", lc->edit_list); + rd_printf("Security Cookie: %#llx", lc->security_cookie); + if (lc->size < OffsetOf(PE_LoadConfig64, seh_handler_table)) { + goto exit; + } + rd_newline(); + + rd_printf("SEH Handler Table: %#llx", lc->seh_handler_table); + rd_printf("SEH Handler Count: %llu", lc->seh_handler_count); + if (lc->size < OffsetOf(PE_LoadConfig64, guard_cf_check_func_ptr)) { + goto exit; + } + rd_newline(); + + rd_printf("Guard CF Check Function: %#llx", lc->guard_cf_check_func_ptr); + rd_printf("Guard CF Dispatch Function: %#llx", lc->guard_cf_dispatch_func_ptr); + rd_printf("Guard CF Function Table: %#llx", lc->guard_cf_func_table); + rd_printf("Guard CF Function Count: %llu", lc->guard_cf_func_count); + rd_printf("Guard Flags: %#x", lc->guard_flags); + if (lc->size < OffsetOf(PE_LoadConfig64, code_integrity)) { + goto exit; + } + rd_newline(); + + rd_printf("Code integrity: { Flags = %#x, Catalog = %#x, Catalog Offset = %#x }", + lc->code_integrity.flags, lc->code_integrity.catalog, lc->code_integrity.catalog_offset); + rd_printf("Guard address taken IAT entry table: %#llx", lc->guard_address_taken_iat_entry_table); + rd_printf("Guard address taken IAT entry count: %llu", lc->guard_address_taken_iat_entry_count); + rd_printf("Guard long jump target table: %#llx", lc->guard_long_jump_target_table); + rd_printf("Guard long jump target count: %llu", lc->guard_long_jump_target_count); + rd_printf("Dynamic value reloc table: %#llx", lc->dynamic_value_reloc_table); + rd_printf("CHPE Metadata ptr: %#llx", lc->chpe_metadata_ptr); + rd_printf("Guard RF failure routine: %#llx", lc->guard_rf_failure_routine); + rd_printf("Guard RF failure routine func ptr: %#llx", lc->guard_rf_failure_routine_func_ptr); + rd_printf("Dynamic value reloc section: %#llx", lc->dynamic_value_reloc_table_section); + rd_printf("Dynamic value reloc section offset: %#llx", lc->dynamic_value_reloc_table_offset); + rd_printf("Guard RF verify SP func ptr: %#llx", lc->guard_rf_verify_stack_pointer_func_ptr); + rd_printf("Hot patch table offset: %#llx", lc->hot_patch_table_offset); + if (lc->size < OffsetOf(PE_LoadConfig64, enclave_config_ptr)) { + goto exit; + } + rd_newline(); + + rd_printf("Enclave config ptr: %#llx", lc->enclave_config_ptr); + rd_printf("Volatile metadata ptr: %#llx", lc->volatile_metadata_ptr); + rd_printf("Guard EH continuation table: %#llx", lc->guard_eh_continue_table); + rd_printf("Guard EH continuation count: %llu", lc->guard_eh_continue_count); + rd_printf("Guard XFG check func ptr: %#llx", lc->guard_xfg_check_func_ptr); + rd_printf("Guard XFG dispatch func ptr: %#llx", lc->guard_xfg_dispatch_func_ptr); + rd_printf("Guard XFG table dispatch func ptr: %#llx", lc->guard_xfg_table_dispatch_func_ptr); + rd_printf("Cast guard OS determined failure mode: %#llx", lc->cast_guard_os_determined_failure_mode); + rd_newline(); + +exit:; + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) +{ + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# TLS"); + rd_indent(); + + String8 tls_chars = coff_string_from_section_flags(scratch.arena, tls.header.characteristics); + rd_printf("Raw data start: %#llx", tls.header.raw_data_start); + rd_printf("Raw data end: %#llx", tls.header.raw_data_end); + rd_printf("Index address: %#llx", tls.header.index_address); + rd_printf("Callbacks address: %#llx", tls.header.callbacks_address); + rd_printf("Zero-fill size: %m", tls.header.zero_fill_size); + rd_printf("Characteristics: %S", tls_chars); + + if (tls.callback_count) { + rd_newline(); + rd_printf("## Callbacks"); + rd_indent(); + for (U64 i = 0; i < tls.callback_count; ++i) { + rd_printf("%#llx", tls.callback_addrs[i]); + } + rd_unindent(); + } + + rd_unindent(); + rd_newline(); + + scratch_end(scratch); +} + +internal void +pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) +{ + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# Debug"); + rd_indent(); + + U64 entry_count = raw_dir.size / sizeof(PE_DebugDirectory); + PE_DebugDirectory *entries = str8_deserial_get_raw_ptr(raw_dir, 0, sizeof(*entries)*entry_count); + for (U64 i = 0; i < entry_count; ++i) { + PE_DebugDirectory *de = entries+i; + if (i > 0) { + rd_newline(); + } + rd_printf("Entry[%u]", i); + rd_indent(); + + { + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, de->time_stamp); + String8 type = pe_string_from_debug_directory_type(de->type); + + rd_printf("Characteristics: %#x", de->characteristics); + rd_printf("Time Stamp: %S", time_stamp); + rd_printf("Version: %u.%u", de->major_ver, de->minor_ver); + rd_printf("Type: %S", type); + rd_printf("Size: %u", de->size); + rd_printf("Data virt off: %#x", de->voff); + rd_printf("Data file off: %#x", de->foff); + rd_newline(); + } + + String8 raw_entry = str8_substr(raw_data, rng_1u64(de->foff, de->foff+de->size)); + if (raw_entry.size != de->size) { + rd_errorf("unable to read debug entry @ %#x", de->foff); + break; + } + + rd_indent(); + switch (de->type) { + case PE_DebugDirectoryType_ILTCG: + case PE_DebugDirectoryType_MPX: + case PE_DebugDirectoryType_EXCEPTION: + case PE_DebugDirectoryType_FIXUP: + case PE_DebugDirectoryType_OMAP_TO_SRC: + case PE_DebugDirectoryType_OMAP_FROM_SRC: + case PE_DebugDirectoryType_BORLAND: + case PE_DebugDirectoryType_CLSID: + case PE_DebugDirectoryType_REPRO: + case PE_DebugDirectoryType_EX_DLLCHARACTERISTICS: { + NotImplemented; + } break; + case PE_DebugDirectoryType_COFF_GROUP: { + U64 off = 0; + + // TODO: is this version? + U32 unknown = 0; + off += str8_deserial_read_struct(raw_entry, off, &unknown); + if (unknown != 0) { + rd_printf("TODO: unknown: %u", unknown); + } + + rd_printf("%-8s %-8s %-8s", "VOFF", "Size", "Name"); + for (; off < raw_entry.size; ) { + U32 voff = 0; + U32 size = 0; + String8 name = str8_zero(); + + off += str8_deserial_read_struct(raw_entry, off, &voff); + off += str8_deserial_read_struct(raw_entry, off, &size); + if (voff == 0 && size == 0) { + break; + } + off += str8_deserial_read_cstr(raw_entry, off, &name); + off = AlignPow2(off, 4); + + rd_printf("%08x %08x %S", voff, size, name); + } + } break; + case PE_DebugDirectoryType_VC_FEATURE: { + MSCRT_VCFeatures *feat = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*feat)); + if (feat) { + rd_printf("Pre-VC++ 11.0: %u", feat->pre_vcpp); + rd_printf("C/C++: %u", feat->c_cpp); + rd_printf("/GS: %u", feat->gs); + rd_printf("/sdl: %u", feat->sdl); + rd_printf("guardN: %u", feat->guard_n); + } else { + rd_errorf("not enough bytes to read VC Features"); + } + } break; + case PE_DebugDirectoryType_FPO: { + PE_DebugFPO *fpo = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*fpo)); + if (fpo) { + U8 prolog_size = PE_FPOEncoded_Extract_PROLOG_SIZE(fpo->flags); + U8 saved_regs_size = PE_FPOEncoded_Extract_SAVED_REGS_SIZE(fpo->flags); + PE_FPOType type = PE_FPOEncoded_Extract_FRAME_TYPE(fpo->flags); + PE_FPOFlags flags = PE_FPOEncoded_Extract_FLAGS(fpo->flags); + + String8 type_string = pe_string_from_fpo_type(type); + String8 flags_string = pe_string_from_fpo_flags(scratch.arena, flags); + + rd_printf("Function offset: %#x", fpo->func_code_off); + rd_printf("Function size: %#x", fpo->func_size); + rd_printf("Locals size: %u", fpo->locals_size); + rd_printf("Params size: %u", fpo->params_size); + rd_printf("Prolog size: %u", prolog_size); + rd_printf("Saved regs size: %u", saved_regs_size); + rd_printf("Type: %S", type_string); + rd_printf("Flags: %S", flags_string); + } else { + rd_errorf("not enough bytes to read FPO"); + } + } break; + + case PE_DebugDirectoryType_CODEVIEW: { + U32 magic = 0; + str8_deserial_read_struct(raw_entry, 0, &magic); + switch (magic) { + case PE_CODEVIEW_PDB20_MAGIC: { + PE_CvHeaderPDB20 *cv20 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv20)); + String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv20), &name); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, cv20->time_stamp); + + rd_printf("Time stamp: %S", time_stamp); + rd_printf("Age: %u", cv20->age); + rd_printf("Name: %S", name); + } break; + case PE_CODEVIEW_PDB70_MAGIC: { + PE_CvHeaderPDB70 *cv70 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv70)); + String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv70), &name); + + String8 guid = string_from_guid(scratch.arena, cv70->guid); + + rd_printf("GUID: %S", guid); + rd_printf("Age: %u", cv70->age); + rd_printf("Name: %S", name); + } break; + default: { + rd_errorf("unknown CodeView magic %#x", magic); + } break; + } + } break; + case PE_DebugDirectoryType_MISC: { + PE_DebugMisc *misc = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*misc)); + + String8 type_string = pe_string_from_misc_type(misc->data_type); + + rd_printf("Data type: %S", type_string); + rd_printf("Size: %u", misc->size); + rd_printf("Unicode: %u", misc->unicode); + + switch (misc->data_type) { + case PE_DebugMiscType_EXE_NAME: { + String8 name; + str8_deserial_read_cstr(raw_entry, sizeof(*misc), &name); + rd_printf("Name: %S", name); + } break; + default: { + rd_printf("???"); + } break; + } + } break; + } + rd_unindent(); + + rd_unindent(); + } + + rd_unindent(); + rd_newline(); + scratch_end(scratch); +} + +internal void +pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 time_stamp = coff_string_from_time_stamp(scratch.arena, exptab.time_stamp); + + rd_printf("# Export Table"); + rd_indent(); + + rd_printf("Characteristics: %u", exptab.flags); + rd_printf("Time stamp: %S", time_stamp); + rd_printf("Version: %u.%02u", exptab.major_ver, exptab.minor_ver); + rd_printf("Ordinal base: %u", exptab.ordinal_base); + rd_printf(""); + + rd_printf("%-4s %-8s %-8s %-8s", "No.", "Oridnal", "VOff", "Name"); + + for (U64 i = 0; i < exptab.export_count; ++i) { + PE_ParsedExport *exp = exptab.exports+i; + if (exp->forwarder.size) { + rd_printf("%4u %8u %8x %S (forwarded to %S)", i, exp->ordinal, exp->voff, exp->name, exp->forwarder); + } else { + rd_printf("%4u %8u %8x %S", i, exp->ordinal, exp->voff, exp->name); + } + } + + rd_unindent(); + scratch_end(scratch); +} + +internal void +pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) +{ + Temp scratch = scratch_begin(&arena, 1); + + if (imptab.count) { + rd_printf("# Import Table"); + rd_indent(); + for (U64 dll_idx = 0; dll_idx < imptab.count; ++dll_idx) { + PE_ParsedStaticDLLImport *dll = imptab.v+dll_idx; + + rd_printf("Name: %S", dll->name); + rd_printf("Import address table: %#llx", image_base + dll->import_address_table_voff); + rd_printf("Import name table: %#llx", image_base + dll->import_name_table_voff); + rd_printf("Time stamp: %#x", dll->time_stamp); + rd_newline(); + + if (dll->import_count) { + rd_indent(); + for (U64 imp_idx = 0; imp_idx < dll->import_count; ++imp_idx) { + PE_ParsedImport *imp = dll->imports+imp_idx; + if (imp->type == PE_ParsedImport_Ordinal) { + rd_printf("%#-6x", imp->u.ordinal); + } else if (imp->type == PE_ParsedImport_Name) { + rd_printf("%#-6x %S", imp->u.name.hint, imp->u.name.string); + } + } + rd_unindent(); + rd_newline(); + } + } + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) +{ + if (imptab.count) { + Temp scratch = scratch_begin(&arena, 1); + rd_printf("# Delay Import Table"); + rd_indent(); + + for (U64 dll_idx = 0; dll_idx < imptab.count; ++dll_idx) { + PE_ParsedDelayDLLImport *dll = imptab.v+dll_idx; + + rd_printf("Attributes: %#08x", dll->attributes); + rd_printf("Name: %S", dll->name); + rd_printf("HMODULE address: %#llx", image_base + dll->module_handle_voff); + rd_printf("Import address table: %#llx", image_base + dll->iat_voff); + rd_printf("Import name table: %#llx", image_base + dll->name_table_voff); + rd_printf("Bound import name table: %#llx", image_base + dll->bound_table_voff); + rd_printf("Unload import name table: %#llx", image_base + dll->unload_table_voff); + rd_printf("Time stamp: %#x", dll->time_stamp); + rd_newline(); + + rd_indent(); + for (U64 imp_idx = 0; imp_idx < dll->import_count; ++imp_idx) { + PE_ParsedImport *imp = dll->imports+imp_idx; + + String8 bound = str8_lit("NULL"); + if (imp_idx < dll->bound_table_count) { + U64 bound_addr = dll->bound_table[imp_idx]; + bound = push_str8f(scratch.arena, "%#llx", bound_addr); + } + + String8 unload = str8_lit("NULL"); + if (imp_idx < dll->unload_table_count) { + U64 unload_addr = dll->unload_table[imp_idx]; + unload = push_str8f(scratch.arena, "%#llx", unload_addr); + } + + if (imp->type == PE_ParsedImport_Ordinal) { + rd_printf("%-16S %-16S %#-4x", bound, unload, imp->u.ordinal); + } else if (imp->type == PE_ParsedImport_Name) { + rd_printf("%-16S %-16S %#-4x %S", bound, unload, imp->u.name.hint, imp->u.name.string); + } + } + rd_unindent(); + + rd_newline(); + } + + rd_unindent(); + scratch_end(scratch); + } +} + +internal void +pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) +{ + Temp scratch = scratch_begin(&arena, 1); + + // setup stack + struct stack_s { + struct stack_s *next; + B32 print_table; + B32 is_named; + PE_ResourceNode *curr_name_node; + PE_ResourceNode *curr_id_node; + U64 name_idx; + U64 id_idx; + U64 dir_idx; + U64 dir_id; + String8 dir_name; + PE_ResourceDir *table; + } *stack = push_array(scratch.arena, struct stack_s, 1); + stack->table = root; + stack->print_table = 1; + stack->is_named = 1; + stack->dir_name = str8_lit("ROOT"); + stack->curr_name_node = root->named_list.first; + stack->curr_id_node = root->id_list.first; + + if (stack) { + rd_printf("# Resources"); + + // traverse resource tree + while (stack) { + if (stack->print_table) { + stack->print_table = 0; + rd_indent(); + + if (stack->is_named) { + rd_printf("[%u] %S { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", + stack->dir_idx, + stack->dir_name, + stack->table->time_stamp, + stack->table->major_version, stack->table->minor_version, + stack->table->named_list.count, stack->table->id_list.count, + stack->table->characteristics); + } else { + B32 is_actually_leaf = stack->table->id_list.count == 1 && + stack->table->id_list.first->data.kind != PE_ResDataKind_DIR; + if (is_actually_leaf) { + rd_printf("[%u] %u { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", + stack->dir_idx, + stack->dir_id, + stack->table->time_stamp, + stack->table->major_version, stack->table->minor_version, + stack->table->named_list.count, stack->table->id_list.count, + stack->table->characteristics); + } else { + String8 id_str = pe_resource_kind_to_string(stack->dir_id); + rd_printf("[%u] %S { Time Stamp: %u, Version %u.%u Name Count: %u, ID Count %u, Characteristics: %u }", + stack->dir_idx, + id_str, + stack->dir_id, + stack->table->time_stamp, + stack->table->major_version, stack->table->minor_version, + stack->table->named_list.count, stack->table->id_list.count, + stack->table->characteristics); + } + } + } + + while (stack->curr_name_node) { + PE_ResourceNode *named_node = stack->curr_name_node; + stack->curr_name_node = stack->curr_name_node->next; + U64 name_idx = stack->name_idx++; + + PE_Resource *res = &named_node->data; + if (res->kind == PE_ResDataKind_DIR) { + struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); + frame->table = res->u.dir; + frame->print_table = 1; + frame->dir_idx = stack->name_idx; + frame->dir_name = res->id.u.string; + frame->is_named = 1; + frame->curr_name_node = frame->table->named_list.first; + frame->curr_id_node = frame->table->id_list.first; + SLLStackPush(stack, frame); + goto yield; + } else if (res->kind == PE_ResDataKind_COFF_LEAF) { + COFF_ResourceDataEntry *entry = &res->u.leaf; + rd_printf("[%u] %S Data VOFF: %#08x, Data Size: %#08x, Code Page: %u", + name_idx, res->id.u.string, entry->data_voff, entry->data_size, entry->code_page); + } else { + InvalidPath; + } + } + + while (stack->curr_id_node) { + PE_ResourceNode *id_node = stack->curr_id_node; + PE_Resource *res = &id_node->data; + stack->curr_id_node = stack->curr_id_node->next; + U64 id_idx = stack->id_idx++; + + if (res->kind == PE_ResDataKind_DIR) { + struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); + frame->table = res->u.dir; + frame->print_table = 1; + frame->dir_idx = stack->table->named_list.count + id_idx; + frame->dir_id = res->id.u.number; + frame->curr_name_node = frame->table->named_list.first; + frame->curr_id_node = frame->table->id_list.first; + SLLStackPush(stack, frame); + goto yield; + } else if (res->kind == PE_ResDataKind_COFF_LEAF) { + COFF_ResourceDataEntry *entry = &res->u.leaf; + rd_printf("[%u] ID: %u Data VOFF: %#08x, Data Size: %#08x, Code Page: %u", id_idx, res->id.u.number, entry->data_voff, entry->data_size, entry->code_page); + } else { + InvalidPath; + } + } + + if (stack->curr_id_node == 0 && stack->curr_name_node == 0) { + rd_unindent(); + } + + SLLStackPop(stack); + + yield:; + } + + rd_newline(); + } + + scratch_end(scratch); +} + +internal void +pe_format_exceptions_x8664(Arena *arena, + String8List *out, + String8 indent, + U64 section_count, + COFF_SectionHeader *sections, + String8 raw_data, + Rng1U64 except_frange) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 raw_except = str8_substr(raw_data, except_frange); + U64 count = raw_except.size / sizeof(PE_IntelPdata); + for (U64 i = 0; i < count; ++i) { + Temp temp = temp_begin(scratch.arena); + + U64 pdata_offset = i * sizeof(PE_IntelPdata); + PE_IntelPdata *pdata = str8_deserial_get_raw_ptr(raw_except, pdata_offset, sizeof(*pdata)); + + String8 pdata_name = str8_zero(); // TODO: syms_name_for_voff(arena, group, thunk_accel, thunk_table_set, pdata.voff_first); + + U64 unwind_info_offset = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info); + PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, unwind_info_offset, sizeof(*uwinfo)); + + U8 version = PE_UNWIND_INFO_VERSION_FROM_HDR(uwinfo->header); + U8 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(uwinfo->header); + U8 frame_register = PE_UNWIND_INFO_REG_FROM_FRAME(uwinfo->frame); + U8 frame_offset = PE_UNWIND_INFO_OFF_FROM_FRAME(uwinfo->frame); + + B32 is_chained = (flags & PE_UnwindInfoFlag_CHAINED) != 0; + B32 has_handler_data = !is_chained && (flags & (PE_UnwindInfoFlag_EHANDLER | PE_UnwindInfoFlag_UHANDLER)) != 0; + + String8 flags_str = str8_zero(); + { + U64 f = flags; + + String8List flags_list = {0}; + if (f & PE_UnwindInfoFlag_EHANDLER) { + f &= ~PE_UnwindInfoFlag_EHANDLER; + str8_list_pushf(scratch.arena, &flags_list, "EHANDLER"); + } + if (f & PE_UnwindInfoFlag_UHANDLER) { + f &= ~PE_UnwindInfoFlag_UHANDLER; + str8_list_pushf(scratch.arena, &flags_list, "UHANDLER"); + } + if (f & PE_UnwindInfoFlag_CHAINED) { + f &= ~PE_UnwindInfoFlag_CHAINED; + str8_list_pushf(scratch.arena, &flags_list, "CHAINED"); + } + if (f) { + str8_list_pushf(scratch.arena, &flags_list, "%#llx", f); + } + if (flags_list.node_count == 0) { + str8_list_pushf(scratch.arena, &flags_list, "%#llx", f); + } + flags_str = str8_list_join(scratch.arena, &flags_list, &(StringJoin){.sep=str8_lit(", ")}); + } + + U64 codes_offset = unwind_info_offset + sizeof(PE_UnwindInfo); + PE_UnwindCode *code_ptr = str8_deserial_get_raw_ptr(raw_data, codes_offset, sizeof(*code_ptr) * uwinfo->codes_num); + PE_UnwindCode *code_opl = code_ptr + uwinfo->codes_num; + + if (i > 0) { + rd_newline(); + } + rd_printf("%08x %08x %08x %08x%s%S", + pdata_offset, + pdata->voff_first, + pdata->voff_one_past_last, + pdata->voff_unwind_info, + pdata_name.size ? " " : "", pdata_name); + rd_printf("Version: %u", version); + rd_printf("Flags: %S", flags_str); + rd_printf("Prolog Size: %#x", uwinfo->prolog_size); + rd_printf("Code Count: %u", uwinfo->codes_num); + rd_printf("Frame: %u", uwinfo->frame); + rd_printf("Codes:"); + rd_indent(); + for (; code_ptr < code_opl;) { + Temp code_temp = temp_begin(scratch.arena); + String8List code_list = {0}; + + U8 operation_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr[0].flags); + U8 operation_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr[0].flags); + + str8_list_pushf(code_temp.arena, &code_list, "%#04x:", code_ptr[0].off_in_prolog); + switch (operation_code) { + case PE_UnwindOpCode_PUSH_NONVOL: { + String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); + str8_list_pushf(code_temp.arena, &code_list, "PUSH_NONVOL %S", gpr); + code_ptr += 1; + } break; + case PE_UnwindOpCode_ALLOC_LARGE: { + U64 size = 0; + switch (operation_info) { + case 0: { // 136B - 512K + size = code_ptr[1].u16*8; + } break; + case 1: { // 512K - 4GB + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } break; + default: break; + } + str8_list_pushf(code_temp.arena, &code_list, "ALLOC_LARGE size=%#x", size); + code_ptr += 2; + } break; + case PE_UnwindOpCode_ALLOC_SMALL: { + U64 size = operation_info*8 + 8; + str8_list_pushf(code_temp.arena, &code_list, "ALLOC_SMALL size=%#x", size); + code_ptr += 1; + } break; + case PE_UnwindOpCode_SET_FPREG: { + U64 offset = frame_offset*16; + String8 gpr = pe_string_from_unwind_gpr_x64(frame_register); + str8_list_pushf(code_temp.arena, &code_list, "SET_FPREG %S, offset=%#x", gpr, offset); + code_ptr += 1; + } break; + case PE_UnwindOpCode_SAVE_NONVOL: { + String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); + U64 register_offset = code_ptr[1].u16*8; + str8_list_pushf(code_temp.arena, &code_list, "SAVE_NONVOL %S, offset=%#x", gpr, register_offset); + code_ptr += 2; + } break; + case PE_UnwindOpCode_SAVE_NONVOL_FAR: { + String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); + U64 frame_offset = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + str8_list_pushf(code_temp.arena, &code_list, "SAVE_NONVOL_FAR %S, offset=%#x", gpr, frame_offset); + code_ptr += 3; + } break; + case PE_UnwindOpCode_EPILOG: { + str8_list_pushf(code_temp.arena, &code_list, "EPILOG flags=%#x", code_ptr[0].flags); + code_ptr += 1; + } break; + case PE_UnwindOpCode_SPARE_CODE: { + str8_list_pushf(code_temp.arena, &code_list, "SPARE_CODE"); + code_ptr += 1; + } break; + case PE_UnwindOpCode_SAVE_XMM128: { + String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); + U64 register_offset = code_ptr[1].u16*16; + str8_list_pushf(code_temp.arena, &code_list, "SAVE_XMM128 %S, offset=%#x", gpr, register_offset); + code_ptr += 2; + } break; + case PE_UnwindOpCode_SAVE_XMM128_FAR: { + String8 gpr = pe_string_from_unwind_gpr_x64(operation_info); + U64 frame_offset = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + str8_list_pushf(code_temp.arena, &code_list, "SAVE_XMM128_FAR %S, offset=%#x", gpr, frame_offset); + code_ptr += 3; + } break; + case PE_UnwindOpCode_PUSH_MACHFRAME: { + str8_list_pushf(code_temp.arena, &code_list, "PUSH_MACHFRAME %s", operation_info == 1 ? "with error code" : "without error code"); + code_ptr += 1; + } break; + default: { + str8_list_pushf(code_temp.arena, &code_list, "UNKNOWN_OPCODE %#x", operation_code); + code_ptr += 1; + } break; + } + + String8 code_line = str8_list_join(code_temp.arena, &code_list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", code_line); + + temp_end(code_temp); + } + rd_unindent(); + + if (is_chained) { + U64 next_pdata_offset = codes_offset + sizeof(PE_UnwindCode) * AlignPow2(uwinfo->codes_num, 2); + PE_IntelPdata *next_pdata = str8_deserial_get_raw_ptr(raw_data, next_pdata_offset, sizeof(*next_pdata)); + rd_printf("Chained: %#08x %#08x %#08x", next_pdata->voff_first, next_pdata->voff_one_past_last, next_pdata->voff_unwind_info); + } + + if (has_handler_data) { +#define ExceptionHandlerDataFlag_FuncInfo (1 << 0) +#define ExceptionHandlerDataFlag_FuncInfo4 (1 << 1) +#define ExceptionHandlerDataFlag_ScopeTable (1 << 2) +#define ExceptionHandlerDataFlag_GS (1 << 3u) + + U64 actual_code_count = PE_UNWIND_INFO_GET_CODE_COUNT(uwinfo->codes_num); + U64 read_cursor = codes_offset + actual_code_count * sizeof(PE_UnwindCode); + + U32 handler = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler); + + String8 handler_name = str8_zero(); // TODO: syms_name_for_voff(scratch.arena, group, thunk_accel, thunk_table_set, handler); + + rd_printf("Handler: %#llx%s%S", handler, handler_name.size ? " " : "", handler_name); + + U32 handler_data_flags = 0; + if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; + } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; + } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_FuncInfo; + } else if (str8_match(handler_name, str8_lit("__C_specific_handler"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_ScopeTable; + } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_GS; + } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_SEH"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_ScopeTable|ExceptionHandlerDataFlag_GS; + } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0)) { + handler_data_flags = ExceptionHandlerDataFlag_FuncInfo|ExceptionHandlerDataFlag_GS; + } + + if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo) { + MSCRT_FuncInfo func_info; + read_cursor += mscrt_parse_func_info(arena, raw_data, section_count, sections, read_cursor, &func_info); + + rd_printf("Function Info:"); + rd_indent(); + rd_printf("Magic: %#x", func_info.magic); + rd_printf("Max State: %u", func_info.max_state); + rd_printf("Try Block Count: %u", func_info.try_block_map_count); + rd_printf("IP Map Count: %u", func_info.ip_map_count); + rd_printf("Frame Offset Unwind Helper: %#x", func_info.frame_offset_unwind_helper); + rd_printf("ES Flags: %#x", func_info.eh_flags); + rd_unindent(); + + if (func_info.ip_map_count > 0) { + rd_printf("IP to State Map:"); + rd_indent(); + rd_printf("%8s %8s", "State", "IP"); + for (U32 i = 0; i < func_info.ip_map_count; ++i) { + MSCRT_IPState32 state = func_info.ip_map[i]; + String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, state.ip); + rd_printf("%8d %08x %S", state.state, state.ip, line); + } + rd_unindent(); + } + + if (func_info.max_state > 0) { + rd_printf("Unwind Map:"); + rd_indent(); + rd_printf("%13s %10s %8s", "Current State", "Next State", "Action @"); + for (U32 i = 0; i < func_info.max_state; ++i) { + MSCRT_UnwindMap32 map = func_info.unwind_map[i]; + String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, map.action_virt_off); + rd_printf("%13u %10d %8x %S", i, map.next_state, map.action_virt_off, line); + } + rd_unindent(); + } + + for (U32 i = 0; i < func_info.try_block_map_count; ++i) { + MSCRT_TryMapBlock try_block = func_info.try_block_map[i]; + rd_printf("Try Map Block #%u", i); + rd_indent(); + rd_printf("Try State Low: %u", try_block.try_low); + rd_printf("Try State High: %u", try_block.try_high); + rd_printf("Catch State High: %u", try_block.catch_high); + rd_printf("Catch Count: %u", try_block.catch_handlers_count); + rd_printf("Catches:"); + rd_indent(); + for (U32 ihandler = 0; ihandler < try_block.catch_handlers_count; ++ihandler) { + rd_printf("Catch #%u", ihandler); + rd_indent(); + mscrt_format_eh_handler_type32(arena, out, indent, &try_block.catch_handlers[ihandler]); + rd_unindent(); + } + rd_unindent(); + rd_unindent(); + } + + if (func_info.es_type_list.count) { + rd_printf("Exception Specific Types:"); + rd_indent(); + for (U32 i = 0; i < func_info.es_type_list.count; ++i) { + if (i > 0) { + rd_newline(); + } + mscrt_format_eh_handler_type32(arena, out, indent, &func_info.es_type_list.handlers[i]); + } + rd_unindent(); + } + } + if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo4) { + U32 handler_data_voff = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler_data_voff); + + U32 unknown = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &unknown); + + U64 func_info_foff = coff_foff_from_voff(sections, section_count, handler_data_voff); + MSCRT_ParsedFuncInfoV4 func_info = {0}; + mscrt_parse_func_info_v4(arena, raw_data, section_count, sections, func_info_foff, pdata->voff_first, &func_info); + + String8 header_str = str8_zero(); + { + String8List header_list = {0}; + if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { + str8_list_pushf(arena, &header_list, "IsCatch"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { + str8_list_pushf(arena, &header_list, "IsSeparted"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { + str8_list_pushf(arena, &header_list, "IsBBT"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { + str8_list_pushf(arena, &header_list, "UnwindMap"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { + str8_list_pushf(arena, &header_list, "TryBlockMap"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_EHs) { + str8_list_pushf(arena, &header_list, "EHs"); + } + if (func_info.header & MSCRT_FuncInfoV4Flag_NoExcept) { + str8_list_pushf(arena, &header_list, "NoExcept"); + } + header_str = str8_list_join(arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); + } + + rd_printf("Function Info V4:"); + rd_indent(); + rd_printf("Header: %#x %S", func_info.header, header_str); + rd_printf("BBT Flags: %#x", func_info.bbt_flags); + + MSCRT_IP2State32V4 ip2state_map = func_info.ip2state_map; + rd_printf("IP To State Map:"); + rd_indent(); + rd_printf("%8s %8s", "State", "IP"); + for (U32 i = 0; i < ip2state_map.count; ++i) { + String8 line_str = str8_zero(); // TODO: syms_line_for_voff(arena, group, ip2state_map.voffs[i]); + rd_printf("%8d %08X %S", ip2state_map.states[i], ip2state_map.voffs[i], line_str); + } + rd_unindent(); + + if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { + MSCRT_UnwindMapV4 unwind_map = func_info.unwind_map; + rd_printf("Unwind Map:"); + rd_indent(); + for (U32 i = 0; i < unwind_map.count; ++i) { + MSCRT_UnwindEntryV4 *ue = &unwind_map.v[i]; + String8 type_str = str8_zero(); + switch (ue->type) { + case MSCRT_UnwindMapV4Type_NoUW: type_str = str8_lit("NoUW"); break; + case MSCRT_UnwindMapV4Type_DtorWithObj: type_str = str8_lit("DtorWithObj"); break; + case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: type_str = str8_lit("DtorWithPtrToObj"); break; + case MSCRT_UnwindMapV4Type_VOFF: type_str = str8_lit("VOFF"); break; + } + if (ue->type == MSCRT_UnwindMapV4Type_DtorWithObj || ue->type == MSCRT_UnwindMapV4Type_DtorWithPtrToObj) { + rd_printf("[%2u] NextOff=%u Type=%-16S Action=%#08x Object=%#x", i, ue->next_off, type_str, ue->action, ue->object); + } else if (ue->type == MSCRT_UnwindMapV4Type_VOFF) { + rd_printf("[%2u] NextOff=%u Type=%-16S Action=%#08x", i, ue->next_off, type_str, ue->action); + } else { + rd_printf("[%2u] NextOff=%u Type=%S", i, ue->next_off, type_str); + } + } + rd_unindent(); + } + + if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { + MSCRT_TryBlockMapV4Array try_block_map = func_info.try_block_map; + rd_printf("Try/Catch Blocks:"); + rd_indent(); + for (U32 i = 0; i < try_block_map.count; ++i) { + MSCRT_TryBlockMapV4 *try_block = &try_block_map.v[i]; + rd_printf("[%2u] TryLow %u TryHigh %u CatchHigh %u", i, try_block->try_low, try_block->try_high, try_block->catch_high); + if (try_block->handlers.count) { + for (U32 k = 0; k < try_block->handlers.count; ++k) { + MSCRT_EhHandlerTypeV4 *handler = &try_block->handlers.v[k]; + + String8List line_list = {0}; + str8_list_pushf(arena, &line_list, " "); + str8_list_pushf(arena, &line_list, "CatchCodeVOff=%#08X", handler->catch_code_voff); + if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) { + String8 adjectives = mscrt_string_from_eh_adjectives(arena, handler->adjectives); + str8_list_pushf(arena, &line_list, "Adjectives=%S", adjectives); + } + if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) { + str8_list_pushf(arena, &line_list, "TypeVOff=%#x", handler->type_voff); + } + if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) { + str8_list_pushf(arena, &line_list, "CacthObjVOff=%#x", handler->catch_obj_voff); + } + if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) { + str8_list_pushf(arena, &line_list, "ContIsVOff"); + } + for (U32 icont = 0; icont < handler->catch_funclet_cont_addr_count; ++icont) { + str8_list_pushf(arena, &line_list, "ContAddr[%u]=%#llx", icont, handler->catch_funclet_cont_addr[icont]); + } + + String8 handler_str = str8_list_join(arena, &line_list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", handler_str); + } + } + } + rd_unindent(); + } + } + if (handler_data_flags & ExceptionHandlerDataFlag_ScopeTable) { + U32 scope_count = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &scope_count); + + PE_HandlerScope *scopes = str8_deserial_get_raw_ptr(raw_data, read_cursor, sizeof(PE_HandlerScope)*scope_count); + read_cursor += scope_count*sizeof(scopes[0]); + + rd_printf("Count of scope table entries: %u", scope_count); + rd_indent(); + rd_printf("%-8s %-8s %-8s %-8s", "Begin", "End", "Handler", "Target"); + for (U32 i = 0; i < scope_count; ++i) { + PE_HandlerScope scope = scopes[i]; + rd_printf("%08x %08x %08x %08x", scope.begin, scope.end, scope.handler, scope.target); + } + rd_unindent(); + } + if (handler_data_flags & ExceptionHandlerDataFlag_GS) { + U32 gs_data = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &gs_data); + + U32 flags = MSCRT_GSHandler_GetFlags(gs_data); + U32 cookie_offset = MSCRT_GSHandler_GetCookieOffset(gs_data); + U32 aligned_base_offset = 0; + U32 alignment = 0; + if (flags & MSCRT_GSHandlerFlag_HasAlignment) { + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &aligned_base_offset); + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &alignment); + } + + String8 flags_str; + { + String8List flags_list = {0}; + if (flags & MSCRT_GSHandlerFlag_EHandler) { + str8_list_pushf(arena, &flags_list, "EHandler"); + } + if (flags & MSCRT_GSHandlerFlag_UHandler) { + str8_list_pushf(arena, &flags_list, "UHandler"); + } + if (flags & MSCRT_GSHandlerFlag_HasAlignment) { + str8_list_pushf(arena, &flags_list, "Has Alignment"); + } + if (flags == 0) { + str8_list_pushf(arena, &flags_list, "None"); + } + flags_str = str8_list_join(arena, &flags_list, &(StringJoin){.sep=str8_lit(", ")}); + } + rd_printf("GS unwind flags: %S", flags_str); + rd_printf("Cookie offset: %x", cookie_offset); + if (flags & MSCRT_GSHandlerFlag_HasAlignment) { + rd_printf("Aligned base offset: %x", aligned_base_offset); + rd_printf("Alignment: %x", alignment); + } + } + + #undef ExceptionHandlerDataFlag_FuncInfo + #undef ExceptionHandlerDataFlag_ScopeTable + #undef ExceptionHandlerDataFlag_GS + } + + temp_end(temp); + } + + scratch_end(scratch); +} + +internal void +pe_format_exceptions(Arena *arena, + String8List *out, + String8 indent, + COFF_MachineType machine, + U64 section_count, + COFF_SectionHeader *sections, + String8 raw_data, + Rng1U64 except_frange) +{ + if (dim_1u64(except_frange)) { + rd_printf("# Exceptions"); + rd_indent(); + rd_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); + + switch (machine) { + case COFF_MachineType_UNKNOWN: break; + case COFF_MachineType_X64: + case COFF_MachineType_X86: { + pe_format_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange); + } break; + default: NotImplemented; break; + } + rd_unindent(); + rd_newline(); + } +} + +internal void +pe_format_base_relocs(Arena *arena, + String8List *out, + String8 indent, + COFF_MachineType machine, + U64 image_base, + U64 section_count, + COFF_SectionHeader *sections, + String8 raw_data, + Rng1U64 base_reloc_franges) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 raw_base_relocs = str8_substr(raw_data, base_reloc_franges); + PE_BaseRelocBlockList base_relocs = pe_base_reloc_block_list_from_data(scratch.arena, raw_base_relocs); + + if (base_relocs.count) { + rd_printf("# Base Relocs"); + rd_indent(); + + U32 addr_size = 0; + switch (machine) { + case COFF_MachineType_UNKNOWN: break; + case COFF_MachineType_X86: addr_size = 4; break; + case COFF_MachineType_X64: addr_size = 8; break; + default: NotImplemented; + } + + // convert blocks to string list + U64 iblock = 0; + for (PE_BaseRelocBlockNode *node = base_relocs.first; node != 0; node = node->next) { + PE_BaseRelocBlock *block = &node->v; + rd_printf("Block No. %u, Virt Off %#x, Reloc Count %u", iblock++, block->page_virt_off, block->entry_count); + rd_indent(); + for (U64 ientry = 0; ientry < block->entry_count; ++ientry) { + PE_BaseRelocKind type = PE_BaseRelocKindFromEntry(block->entries[ientry]); + U16 offset = PE_BaseRelocOffsetFromEntry(block->entries[ientry]); + + U64 apply_to_voff = block->page_virt_off + offset; + U64 apply_to_foff = coff_foff_from_voff(sections, section_count, apply_to_voff); + U64 apply_to = 0; + str8_deserial_read(raw_data, apply_to_foff, &apply_to, addr_size, 1); + U64 addr = image_base + apply_to; + + const char *type_str = "???"; + switch (type) { + case PE_BaseRelocKind_ABSOLUTE: type_str = "ABS"; break; + case PE_BaseRelocKind_HIGH: type_str = "HIGH"; break; + case PE_BaseRelocKind_LOW: type_str = "LOW"; break; + case PE_BaseRelocKind_HIGHLOW: type_str = "HIGHLOW"; break; + case PE_BaseRelocKind_HIGHADJ: type_str = "HIGHADJ"; break; + case PE_BaseRelocKind_DIR64: type_str = "DIR64"; break; + default: { + switch (machine) { + case COFF_MachineType_ARM: + case COFF_MachineType_ARM64: + case COFF_MachineType_ARMNT: { + switch (type) { + case PE_BaseRelocKind_ARM_MOV32: type_str = "ARM_MOV32"; break; + case PE_BaseRelocKind_THUMB_MOV32: type_str = "THUMB_MOV32"; break; + default: NotImplemented; + } + } break; + // TODO: mips, loong, risc-v + } + } break; + } + + if (type == PE_BaseRelocKind_ABSOLUTE) { + rd_printf("%-4x %-12s", offset, type_str); + } else { + rd_printf("%-4x %-12s %016llx", offset, type_str, apply_to); + + // TODO + #if 0 + U64 reloc_voff = apply_to - image_base; + SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, reloc_voff); + SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, reloc_voff); + if (sid) { + SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); + String8 name = syms_group_symbol_name_from_sid(arena, group, unit, sid); + str8_list_pushf(arena, list, " %-4X %-12s %016llX %.*s", offset, type_str, apply_to, syms_expand_string(name)); + } else { + str8_list_pushf(arena, list, " %-4X %-12s %016llX", offset, type_str, apply_to); + } + #endif + } + } + rd_unindent(); + rd_newline(); + } + + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +{ + Temp scratch = scratch_begin(&arena, 1); + + PE_DosHeader *dos_header = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(*dos_header)); + if (!dos_header) { + rd_errorf("not enough bytes to read DOS header"); + goto exit; + } + Assert(dos_header->magic == PE_DOS_MAGIC); + + U32 pe_magic = 0; + str8_deserial_read_struct(raw_data, dos_header->coff_file_offset, &pe_magic); + if (pe_magic != PE_MAGIC) { + rd_errorf("PE magic check failure, input file is not of PE format"); + goto exit; + } + + U64 coff_header_off = dos_header->coff_file_offset+sizeof(pe_magic); + COFF_Header *coff_header = str8_deserial_get_raw_ptr(raw_data, coff_header_off, sizeof(*coff_header)); + if (!coff_header) { + rd_errorf("not enough bytes to read COFF header"); + goto exit; + } + + U64 opt_header_off = coff_header_off + sizeof(*coff_header); + U16 opt_header_magic = 0; + str8_deserial_read_struct(raw_data, opt_header_off, &opt_header_magic); + if (opt_header_magic != PE_PE32_MAGIC && opt_header_magic != PE_PE32PLUS_MAGIC) { + rd_errorf("unexpected optional header magic %#x", opt_header_magic); + goto exit; + } + + if (opt_header_magic == PE_PE32_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32)) { + rd_errorf("unexpected optional header size in COFF header %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32)); + goto exit; + } + + if (opt_header_magic == PE_PE32PLUS_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32Plus)) { + rd_errorf("unexpected optional header size %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32Plus)); + goto exit; + } + + U64 sections_off = coff_header_off + sizeof(*coff_header) + coff_header->optional_header_size; + COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sections_off, sizeof(*sections)*coff_header->section_count); + if (!sections) { + rd_errorf("not enough bytes to read COFF section headers"); + goto exit; + } + + U64 string_table_off = coff_header->symbol_table_foff + sizeof(COFF_Symbol16) * coff_header->symbol_count; + + COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, coff_header->symbol_table_foff, coff_header->symbol_count); + + U8 *raw_opt_header = push_array(scratch.arena, U8, coff_header->optional_header_size); + str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, coff_header->optional_header_size); + + if (opts & RD_Option_Headers) { + coff_format_header(arena, out, indent, coff_header); + rd_newline(); + } + + U64 image_base = 0; + U64 dir_count = 0; + PE_DataDirectory *dirs = 0; + + if (opt_header_magic == PE_PE32_MAGIC) { + PE_OptionalHeader32 *opt_header = (PE_OptionalHeader32 *)raw_opt_header; + image_base = opt_header->image_base; + dir_count = opt_header->data_dir_count; + dirs = str8_deserial_get_raw_ptr(raw_data, opt_header_off+sizeof(*opt_header), sizeof(*dirs) * opt_header->data_dir_count); + if (!dirs) { + rd_errorf("unable to read data directories"); + goto exit; + } + + if (opts & RD_Option_Headers) { + pe_format_optional_header32(arena, out, indent, opt_header, dirs); + } + } else if (opt_header_magic == PE_PE32PLUS_MAGIC) { + PE_OptionalHeader32Plus *opt_header = (PE_OptionalHeader32Plus *)raw_opt_header; + image_base = opt_header->image_base; + dir_count = opt_header->data_dir_count; + dirs = str8_deserial_get_raw_ptr(raw_data, opt_header_off+sizeof(*opt_header), sizeof(*dirs) * opt_header->data_dir_count); + if (!dirs) { + rd_errorf("unable to read data directories"); + goto exit; + } + + if (opts & RD_Option_Headers) { + pe_format_optional_header32plus(arena, out, indent, opt_header, dirs); + } + } + + // map data directory RVA to file offsets + Rng1U64 *dirs_file_ranges = push_array(scratch.arena, Rng1U64, dir_count); + Rng1U64 *dirs_virt_ranges = push_array(scratch.arena, Rng1U64, dir_count); + for (U64 i = 0; i < dir_count; ++i) { + PE_DataDirectory dir = dirs[i]; + U64 file_off = coff_foff_from_voff(sections, coff_header->section_count, dir.virt_off); + dirs_file_ranges[i] = r1u64(file_off, file_off+dir.virt_size); + dirs_virt_ranges[i] = r1u64(dir.virt_off, dir.virt_off+dir.virt_size); + } + + if (opts & RD_Option_Sections) { + coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); + } + + if (opts & RD_Option_Relocs) { + coff_format_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); + } + + if (opts & RD_Option_Symbols) { + coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + } + + if (opts & RD_Option_Exports) { + PE_ParsedExportTable exptab = pe_exports_from_data(arena, + coff_header->section_count, + sections, + raw_data, + dirs_file_ranges[PE_DataDirectoryIndex_EXPORT], + dirs_virt_ranges[PE_DataDirectoryIndex_EXPORT]); + } + + if (opts & RD_Option_Imports) { + B32 is_pe32 = opt_header_magic == PE_PE32_MAGIC; + PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); + PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); + pe_format_static_import_table(arena, out, indent, image_base, static_imptab); + pe_format_delay_import_table(arena, out, indent, image_base, delay_imptab); + } + + if (opts & RD_Option_Resources) { + String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_RESOURCES]); + PE_ResourceDir *dir_root = pe_resource_table_from_directory_data(scratch.arena, raw_dir); + pe_format_resources(arena, out, indent, dir_root); + } + + if (opts & RD_Option_Exceptions) { + pe_format_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS]); + } + + if (opts & RD_Option_Relocs) { + pe_format_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC]); + } + + if (opts & RD_Option_Debug) { + if (PE_DataDirectoryIndex_DEBUG < dir_count) { + String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DEBUG]); + pe_format_debug_directory(arena, out, indent, raw_data, raw_dir); + } + } + + if (opts & RD_Option_Tls) { + if (dim_1u64(dirs_file_ranges[PE_DataDirectoryIndex_TLS])) { + PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); + pe_format_tls(arena, out, indent, tls); + } + } + + if (opts & RD_Option_LoadConfig) { + String8 raw_lc = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_LOAD_CONFIG]); + if (raw_lc.size) { + switch (coff_header->machine) { + case COFF_MachineType_UNKNOWN: break; + case COFF_MachineType_X86: { + PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); + if (lc) { + pe_format_load_config32(arena, out, indent, lc); + } else { + rd_errorf("not enough bytes to parse 32bit load config"); + } + } break; + case COFF_MachineType_X64: { + PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); + if (lc) { + pe_format_load_config64(arena, out, indent, lc); + } else { + rd_errorf("not enough bytes to parse 64bit load config"); + } + } break; + default: NotImplemented; + } + } + } + + RD_MarkerArray *section_markers = 0; + if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) { + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, symbols); + } + + if (opts & RD_Option_Rawdata) { + coff_raw_data_sections(arena, out, indent, raw_data, 0, section_markers, coff_header->section_count, sections); + } + + if (opts & RD_Option_Disasm) { + coff_disasm_sections(arena, out, indent, raw_data, coff_header->machine, 0, 1, section_markers, coff_header->section_count, sections); + } + +exit:; + scratch_end(scratch); +} + +internal B32 +is_pe(String8 raw_data) +{ + PE_DosHeader header = {0}; + str8_deserial_read_struct(raw_data, 0, &header); + return header.magic == PE_DOS_MAGIC; +} + +internal void +format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + char *input_type_string = "???"; + + if (coff_is_archive(raw_data)) { + input_type_string = "Archive"; + } else if (coff_is_thin_archive(raw_data)) { + input_type_string = "Thin Archive"; + } else if (coff_is_big_obj(raw_data)) { + input_type_string = "Big Obj"; + } else if (coff_is_obj(raw_data)) { + input_type_string = "Obj"; + } else if (is_pe(raw_data)) { + input_type_string = "COFF/PE"; + } + + DateTime universal_dt = os_now_universal_time(); + DateTime local_dt = os_local_time_from_universal(&universal_dt); + String8 time = push_date_time_string(scratch.arena, &local_dt); + + rd_printf("# Input"); + rd_indent(); + rd_printf("Path: %S", input_path); + rd_printf("Type: %s", input_type_string); + rd_printf("Time: %S", time); + rd_unindent(); + rd_newline(); + + scratch_end(scratch); +} + diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h new file mode 100644 index 00000000..c835f576 --- /dev/null +++ b/src/raddump/raddump.h @@ -0,0 +1,142 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDUMP_H +#define RADDUMP_H + +#define RD_INDENT_WIDTH 4 +#define RD_INDENT_MAX 4096 + +#define rd_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__) +#define rd_newline() str8_list_pushf(arena, out, ""); +#define rd_errorf(f, ...) rd_printf("ERROR: "f, __VA_ARGS__) +#define rd_indent() do { if (indent.size + RD_INDENT_WIDTH <= RD_INDENT_MAX) { indent.size += RD_INDENT_WIDTH; } else { Assert(!"indent overflow"); } } while (0) +#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) + +typedef U64 RD_Option; +enum RD_OptionEnum +{ + RD_Option_Help = (1 << 0), + RD_Option_Version = (1 << 1), + RD_Option_Headers = (1 << 2), + RD_Option_Sections = (1 << 3), + RD_Option_Debug = (1 << 4), + RD_Option_Imports = (1 << 5), + RD_Option_Exports = (1 << 6), + RD_Option_Disasm = (1 << 7), + RD_Option_Rawdata = (1 << 8), + RD_Option_Tls = (1 << 9), + RD_Option_Codeview = (1 << 10), + RD_Option_Symbols = (1 << 11), + RD_Option_Relocs = (1 << 12), + RD_Option_Exceptions = (1 << 13), + RD_Option_LoadConfig = (1 << 14), + RD_Option_Resources = (1 << 15), + RD_Option_LongNames = (1 << 16), +}; + +typedef struct RD_Marker +{ + U64 off; + String8 string; +} RD_Marker; + +typedef struct RD_MarkerArray +{ + U64 count; + RD_Marker *v; +} RD_MarkerArray; + +typedef struct MarkerNode +{ + struct MarkerNode *next; + RD_Marker v; +} RD_MarkerNode; + +typedef struct RD_MarkerList +{ + U64 count; + RD_MarkerNode *first; + RD_MarkerNode *last; +} RD_MarkerList; + +typedef struct RD_DisasmResult +{ + String8 text; + U64 size; +} RD_DisasmResult; + +//////////////////////////////// + +//- Markers + +internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols); + +//- Disasm + +internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code); +internal void rd_format_disasm(Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); + +//- Raw Data + +internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); +internal void rd_format_raw_data(Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); + +//- CodeView + +internal void cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); +internal void cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range); +internal void cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr); +internal void cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol); +internal U64 cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf); +internal void cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t); +internal void cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines); +internal void cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums); +internal void cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab); +internal void cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss); + +//- COFF + +internal void coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); +internal void coff_format_section_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); +internal void coff_disasm_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_raw_data_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_format_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); +internal void coff_format_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); +internal void coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); +internal void coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header); +internal void coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); +internal void coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); + +//- MSVC CRT + +internal void mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler); + +//- PE + +internal void pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs); +internal void pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs); +internal void pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs); +internal void pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); +internal void pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); +internal void pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); +internal void pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); +internal void pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); +internal void pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); +internal void pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); +internal void pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root); +internal void pe_format_exceptions_x8664(Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); +internal void pe_format_exceptions(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); +internal void pe_format_base_relocs(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges); +internal void pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); + +//////////////////////////////// + +internal void format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); + +#endif // RADDUMP_H diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c new file mode 100644 index 00000000..432651fe --- /dev/null +++ b/src/raddump/raddump_main.c @@ -0,0 +1,182 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define BUILD_CONSOLE_INTERFACE 1 +#define BUILD_TITLE "Epic Games Tools (R) RAD Dumper" + +//////////////////////////////// + +#include "third_party/xxHash/xxhash.c" +#include "third_party/xxHash/xxhash.h" +#include "third_party/radsort/radsort.h" +#include "third_party/zydis/zydis.h" +#include "third_party/zydis/zydis.c" + +//////////////////////////////// + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "path/path.h" +#include "coff/coff.h" +#include "coff/coff_enum.h" +#include "pe/pe.h" +#include "msvc_crt/msvc_crt.h" +#include "msvc_crt/msvc_crt_enum.h" +#include "codeview/codeview.h" +#include "codeview/codeview_parse.h" +#include "codeview/codeview_enum.h" +#include "msf/msf.h" +#include "msf/msf_parse.h" +#include "pdb/pdb.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "path/path.c" +#include "coff/coff.c" +#include "coff/coff_enum.c" +#include "pe/pe.c" +#include "msvc_crt/msvc_crt.c" +#include "msvc_crt/msvc_crt_enum.c" +#include "codeview/codeview.c" +#include "codeview/codeview_parse.c" +#include "codeview/codeview_enum.c" +#include "msf/msf.c" +#include "msf/msf_parse.c" +#include "pdb/pdb.c" + +#include "linker/base_ext/base_core.h" +#include "linker/base_ext/base_core.c" +#include "linker/path_ext/path.h" +#include "linker/path_ext/path.c" +#include "linker/thread_pool/thread_pool.h" +#include "linker/thread_pool/thread_pool.c" +#include "linker/codeview_ext/codeview.h" +#include "linker/codeview_ext/codeview.c" +#include "linker/hash_table.h" +#include "linker/hash_table.c" + +#include "raddump/raddump.h" +#include "raddump/raddump.c" + +//////////////////////////////// + +global read_only struct +{ + RD_Option opt; + char *name; + char *help; +} g_rd_dump_option_map[] = { + { RD_Option_Help, "help", "Print help and exit" }, + { RD_Option_Version, "v", "Print version and exit" }, + { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, + { RD_Option_Sections, "sections", "Dump section headers as table" }, + { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, + { RD_Option_Codeview, "cv", "Dump CodeView" }, + { RD_Option_Disasm, "disasm", "Disassemble code sections" }, + { RD_Option_Symbols, "symbols", "Dump COFF symbol table" }, + { RD_Option_Relocs, "relocs", "Dump relocations" }, + { RD_Option_Exceptions, "exceptions", "Dump exceptions" }, + { RD_Option_Tls, "tls", "Dump Thread Local Storage directory" }, + { RD_Option_Debug, "debug", "Dump debug directory" }, + { RD_Option_Imports, "imports", "Dump import table" }, + { RD_Option_Exports, "exports", "Dump export table" }, + { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, + { RD_Option_Resources, "resources", "Dump resource directory" }, + { RD_Option_LongNames, "longnames", "Dump archive long names" }, +}; + +internal void +entry_point(CmdLine *cmdline) +{ + Temp scratch = scratch_begin(0,0); + + // parse options + RD_Option opts = 0; + { + for (CmdLineOpt *cmd = cmdline->options.first; cmd != 0; cmd = cmd->next) { + RD_Option opt = 0; + for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { + String8 opt_name = str8_cstring(g_rd_dump_option_map[opt_idx].name); + if (str8_match(cmd->string, opt_name, StringMatchFlag_CaseInsensitive)) { + opt = g_rd_dump_option_map[opt_idx].opt; + break; + } else if (str8_match(cmd->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { + opt = ~0ull & ~(RD_Option_Help|RD_Option_Version); + break; + } + } + + if (opt == 0) { + fprintf(stderr, "Unknown argument: \"%.*s\"\n", str8_varg(cmd->string)); + os_abort(1); + } + + opts |= opt; + } + } + + // print help + if (opts & RD_Option_Help) { + for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { + fprintf(stdout, "-%s %s\n", g_rd_dump_option_map[opt_idx].name, g_rd_dump_option_map[opt_idx].help); + } + os_abort(0); + } + + // print version + if (opts & RD_Option_Version) { + fprintf(stdout, BUILD_TITLE_STRING_LITERAL "\n"); + fprintf(stdout, "\traddump \n"); + os_abort(0); + } + + // input check + if (cmdline->inputs.node_count == 0) { + fprintf(stderr, "No input file specified\n"); + os_abort(1); + } else if (cmdline->inputs.node_count > 1) { + fprintf(stderr, "Too many inputs specified, expected one\n"); + os_abort(1); + } + + // read input + String8 file_path = str8_list_first(&cmdline->inputs); + String8 raw_data = os_data_from_file_path(scratch.arena, file_path); + + // is read ok? + if (raw_data.size == 0) { + fprintf(stderr, "Unable to read input file \"%.*s\"\n", str8_varg(file_path)); + os_abort(1); + } + + // make indent + String8 indent; + { + U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX; + U8 *indent_buffer = push_array(scratch.arena, U8, indent_buffer_size); + MemorySet(indent_buffer, ' ', indent_buffer_size); + indent = str8(indent_buffer, 0); + } + + // format input + String8List out = {0}; + format_preamble(scratch.arena, &out, indent, file_path, raw_data); + if (coff_is_archive(raw_data) || coff_is_thin_archive(raw_data)) { + coff_format_archive(scratch.arena, &out, indent, raw_data, opts); + } else if (coff_is_big_obj(raw_data)) { + coff_format_big_obj(scratch.arena, &out, indent, raw_data, opts); + } else if (coff_is_obj(raw_data)) { + coff_format_obj(scratch.arena, &out, indent, raw_data, opts); + } else if (is_pe(raw_data)) { + pe_format(scratch.arena, &out, indent, raw_data, opts); + } else if (pe_is_res(raw_data)) { + //tool_out_coff_res(stdout, file_data); + } + + // print formatted string + String8 out_string = str8_list_join(scratch.arena, &out, &(StringJoin){ .sep = str8_lit("\n"),}); + fprintf(stdout, "%.*s", str8_varg(out_string)); + + scratch_end(scratch); +} + From b27b783e6f36d1c477bbeefb2d2e40687fbeb203 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 26 Dec 2024 21:54:25 -0800 Subject: [PATCH 06/53] Dwarf parser WIP Copied the parser from internal repo and integrated with the base layer (not tested) Parser uses based/range pattern for which we have an alternative in string layer (str8_deserial_*) --- src/base/base_math.c | 19 + src/base/base_math.h | 1 + src/base/base_strings.c | 64 + src/base/base_strings.h | 2 + src/dwarf/dwarf_enum.h | 11 + src/dwarf/dwarf_expr.c | 1433 +++++++++++++++++++++++ src/dwarf/dwarf_expr.h | 301 +++++ src/dwarf/dwarf_notes.txt | 42 + src/dwarf/dwarf_parse.c | 2340 +++++++++++++++++++++++++++++++++++++ src/dwarf/dwarf_parse.h | 491 ++++++++ src/dwarf/dwarf_unwind.c | 1157 ++++++++++++++++++ src/dwarf/dwarf_unwind.h | 224 ++++ 12 files changed, 6085 insertions(+) create mode 100644 src/dwarf/dwarf_enum.h create mode 100644 src/dwarf/dwarf_expr.c create mode 100644 src/dwarf/dwarf_expr.h create mode 100644 src/dwarf/dwarf_notes.txt create mode 100644 src/dwarf/dwarf_parse.c create mode 100644 src/dwarf/dwarf_parse.h create mode 100644 src/dwarf/dwarf_unwind.c create mode 100644 src/dwarf/dwarf_unwind.h diff --git a/src/base/base_math.c b/src/base/base_math.c index 8f0be22e..2c6201f3 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -600,6 +600,25 @@ rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng) list->count += 1; } +internal void +rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat) +{ + if(to_concat->first) + { + if(list->first) + { + list->last->next = to_concat->first; + list->last = to_concat->last; + } + else + { + list->first = to_concat->first; + list->last = to_concat->last; + } + MemoryZeroStruct(to_concat); + } +} + internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list) { diff --git a/src/base/base_math.h b/src/base/base_math.h index dc404fb3..b6063ad5 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -666,6 +666,7 @@ internal U32 u32_from_rgba(Vec4F32 rgba); //~ rjf: List Type Functions internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); +internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 085e27ae..1e47ac37 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -2370,3 +2370,67 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) *block_out = str8_substr(string, range); return block_out->size; } + +internal U64 +str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for( ;; ++cursor, shift += 7u) + { + U8 byte = 0; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + if(bytes_read != sizeof(byte)) + { + break; + } + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + if((byte & 0x80u) == 0) + { + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for( ;; ++cursor) + { + U8 byte; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + if(bytes_read != sizeof(byte)) + { + break; + } + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + shift += 7u; + if((byte & 0x80u) == 0) + { + if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) + { + value |= -(S64)(1ull << shift); + } + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 1b578b5c..fc946dd8 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -404,6 +404,8 @@ internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size); internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out); internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out); +internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out); +internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out); #define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr))) #define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1) diff --git a/src/dwarf/dwarf_enum.h b/src/dwarf/dwarf_enum.h new file mode 100644 index 00000000..6158c409 --- /dev/null +++ b/src/dwarf/dwarf_enum.h @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 dw_string_from_expr_op(Arena *arena, DW_ExprOp op); +internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind); +internal String8 dw_string_from_attrib_kind(Arena *arena, DW_AttribKind kind); +internal String8 dw_string_from_form_kind(Arena *arena, DW_FormKind kind); + +//internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); + + diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c new file mode 100644 index 00000000..094ad78c --- /dev/null +++ b/src/dwarf/dwarf_expr.c @@ -0,0 +1,1433 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- analyzers + +internal DW_SimpleLoc +dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) +{ + DW_SimpleLoc result = {DW_SimpleLocKind_Empty}; + + U8 op = 0; + if (based_range_read(base, range, 0, 1, &op)) { + // step params + U64 size_param = 0; + B32 is_signed = 0; + + // step + U64 step_cursor = 1; + switch (op) { + + //// literal encodings //// + + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: + { + U64 x = op - DW_ExprOp_Lit0; + result.kind = DW_SimpleLocKind_Address; + result.addr = x; + } break; + + case DW_ExprOp_Const1U:size_param = 1; goto const_n; + case DW_ExprOp_Const2U:size_param = 2; goto const_n; + case DW_ExprOp_Const4U:size_param = 4; goto const_n; + case DW_ExprOp_Const8U:size_param = 8; goto const_n; + case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n; + case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n; + case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n; + case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; + const_n: + { + U64 x = 0; + step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + + if (is_signed) { + x = extend_sign64(x, size_param); + } + + result.kind = DW_SimpleLocKind_Address; + result.addr = x; + } break; + + case DW_ExprOp_Addr: + { + U64 offset = 0; + step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + U64 x = text_section_base + offset; + result.kind = DW_SimpleLocKind_Address; + result.addr = x; + } break; + + case DW_ExprOp_ConstU: + { + U64 x = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + result.kind = DW_SimpleLocKind_Address; + result.addr = x; + } break; + + case DW_ExprOp_ConstS: + { + U64 x = 0; + step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + result.kind = DW_SimpleLocKind_Address; + result.addr = x; + } break; + + + //// register location descriptions //// + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: + { + U64 reg_idx = op - DW_ExprOp_Reg0; + result.kind = DW_SimpleLocKind_Register; + result.reg_idx = reg_idx; + } break; + + case DW_ExprOp_RegX: + { + U64 reg_idx = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); + result.kind = DW_SimpleLocKind_Register; + result.reg_idx = reg_idx; + } break; + + + //// implicit location descriptions //// + + case DW_ExprOp_ImplicitValue: + { + U64 size = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + if (step_cursor + size <= range.max) { + result.kind = DW_SimpleLocKind_ValueLong; + result.val_long.str = (U8*)base + range.min + step_cursor; + result.val_long.size = size; + } + step_cursor += size; + } break; + + case DW_ExprOp_StackValue: + { + // this op pops from the value stack, so if it comes first the dwarf expression is bad. + result.kind = DW_SimpleLocKind_Fail; + result.fail_kind = DW_LocFailKind_BadData; + } break; + + + //// composite location descriptions //// + + // if the first and only op is a piece, the expression is empty + + case DW_ExprOp_Piece: + { + U64 size = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + result.kind = DW_SimpleLocKind_Empty; + } break; + + case DW_ExprOp_BitPiece: + { + U64 bit_size = 0, bit_off = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + result.kind = DW_SimpleLocKind_Empty; + } break; + + + //// final fallback //// + + default: + { + result.kind = DW_SimpleLocKind_Fail; + result.fail_kind = DW_LocFailKind_TooComplicated; + } break; + } + + // check this was the whole expression + if (range.min + step_cursor < range.max) { + result.kind = DW_SimpleLocKind_Fail; + result.fail_kind = DW_LocFailKind_TooComplicated; + } + } + + return result; +} + +internal DW_ExprAnalysis +dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConfig *call_config) +{ + Temp scratch = scratch_begin(0, 0); + + DW_ExprAnalysis result = {0}; + + // are we resolving calls? + B32 has_call_func = (call_config != 0 && call_config->func != 0); + + // tasks + DW_ExprAnalysisTask *unfinished_tasks = 0; + DW_ExprAnalysisTask *finished_tasks = 0; + + // convert range input to string + String8 in_data = str8((U8*)in_base + in_range.min, in_range.max - in_range.min); + + // put input task onto the list + { + DW_ExprAnalysisTask *new_task = push_array(scratch.arena, DW_ExprAnalysisTask, 1); + new_task->p = max_U64; + new_task->data = in_data; + SLLStackPush(unfinished_tasks, new_task); + } + + // state for checking implicit locations + B32 last_was_implicit_loc = 0; + + // task loop + for (;;) { + // get next task to handle + DW_ExprAnalysisTask *task = unfinished_tasks; + if (task == 0) { + break; + } + + String8 task_data = task->data; + U8 *task_base = task_data.str; + Rng1U64 task_range = rng_1u64(0, task_data.size); + + // move the task to finished now + SLLStackPop(unfinished_tasks); + SLLStackPush(finished_tasks, task); + + // analysis loop + for (U64 cursor = 0;;) { + // decode op + U64 op_offset = cursor; + U8 op = 0; + if (based_range_read(task_base, task_range, op_offset, 1, &op)) { + U64 after_op_off = cursor + 1; + + // require piece op after 'implicit' location descriptions + if (last_was_implicit_loc) { + if (op != DW_ExprOp_Piece && op != DW_ExprOp_BitPiece) { + result.flags |= DW_ExprFlag_BadData; + goto finish; + } + } + + // step params + U64 size_param = 0; + B32 is_signed = 0; + + // step + U64 step_cursor = after_op_off; + switch (op) { + + //// literal encodings //// + + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: + break; + + case DW_ExprOp_Const1U:size_param = 1; goto const_n; + case DW_ExprOp_Const2U:size_param = 2; goto const_n; + case DW_ExprOp_Const4U:size_param = 4; goto const_n; + case DW_ExprOp_Const8U:size_param = 8; goto const_n; + case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n; + case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n; + case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n; + case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; + const_n: + { + U64 x = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &x); + } break; + + case DW_ExprOp_Addr: + { + U64 offset = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, 8, &offset); + result.flags |= DW_ExprFlag_UsesTextBase; + } break; + + case DW_ExprOp_ConstU: + { + U64 x = 0; + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &x); + } break; + + case DW_ExprOp_ConstS: + { + U64 x = 0; + step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, (S64*)&x); + } break; + + + //// register based addressing //// + + case DW_ExprOp_FBReg: + { + S64 offset = 0; + step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + result.flags |= DW_ExprFlag_UsesFrameBase; + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: + { + S64 offset = 0; + step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + result.flags |= DW_ExprFlag_UsesRegisters; + } break; + + case DW_ExprOp_BRegX: + { + U64 reg_idx = 0; S64 offset = 0; + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, ®_idx); + step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + result.flags |= DW_ExprFlag_UsesRegisters; + } break; + + + //// stack operations //// + + case DW_ExprOp_Dup: + case DW_ExprOp_Drop: + break; + + case DW_ExprOp_Pick: + { + U64 idx = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &idx); + } break; + + case DW_ExprOp_Over: + case DW_ExprOp_Swap: + case DW_ExprOp_Rot: + break; + + case DW_ExprOp_Deref: + { + result.flags |= DW_ExprFlag_UsesMemory; + } break; + + case DW_ExprOp_DerefSize: + { + U64 size = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &size); + result.flags |= DW_ExprFlag_UsesMemory; + } break; + + case DW_ExprOp_XDeref: + case DW_ExprOp_XDerefSize: + { + result.flags |= DW_ExprFlag_NotSupported; + } goto finish; + + case DW_ExprOp_PushObjectAddress: + { + result.flags |= DW_ExprFlag_UsesObjectAddress; + } break; + + case DW_ExprOp_GNU_PushTlsAddress: + case DW_ExprOp_FormTlsAddress: + { + result.flags |= DW_ExprFlag_UsesTLSAddress; + } break; + + case DW_ExprOp_CallFrameCfa: + { + result.flags |= DW_ExprFlag_UsesCFA; + } break; + + + //// arithmetic and logical operations //// + + case DW_ExprOp_Abs: + case DW_ExprOp_And: + case DW_ExprOp_Div: + case DW_ExprOp_Minus: + case DW_ExprOp_Mod: + case DW_ExprOp_Mul: + case DW_ExprOp_Neg: + case DW_ExprOp_Not: + case DW_ExprOp_Or: + case DW_ExprOp_Plus: + break; + + case DW_ExprOp_PlusUConst: + { + U64 y = 0; + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &y); + } break; + + case DW_ExprOp_Shl: + case DW_ExprOp_Shr: + case DW_ExprOp_Shra: + case DW_ExprOp_Xor: + break; + + + //// control flow operations //// + + case DW_ExprOp_Le: + case DW_ExprOp_Ge: + case DW_ExprOp_Eq: + case DW_ExprOp_Lt: + case DW_ExprOp_Gt: + case DW_ExprOp_Ne: + break; + + case DW_ExprOp_Skip: + case DW_ExprOp_Bra: + { + S16 d = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, 2, &d); + result.flags |= DW_ExprFlag_NonLinearFlow; + } break; + + case DW_ExprOp_Call2:size_param = 2; goto callN; + case DW_ExprOp_Call4:size_param = 4; goto callN; + callN: + { + U64 p = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &p); + result.flags |= DW_ExprFlag_UsesCallResolution|DW_ExprFlag_NonLinearFlow; + + // add to task list + if (has_call_func) { + DW_ExprAnalysisTask *existing = dw_expr__analysis_task_from_p(unfinished_tasks, p); + if (existing == 0) { + existing = dw_expr__analysis_task_from_p(finished_tasks, p);; + } + if (existing == 0) { + DW_ExprAnalysisTask *new_task = push_array(scratch.arena, DW_ExprAnalysisTask, 1); + new_task->p = p; + new_task->data = call_config->func(call_config->user_ptr, p); + SLLStackPush(unfinished_tasks, new_task); + } + } + } break; + + case DW_ExprOp_CallRef: + { + result.flags |= DW_ExprFlag_NotSupported; + } goto finish; + + + //// special operations //// + + case DW_ExprOp_Nop:break; + + + //// register location descriptions //// + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: + { + last_was_implicit_loc = 1; + } break; + + case DW_ExprOp_RegX: + { + U64 reg_idx = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, ®_idx); + last_was_implicit_loc = 1; + } break; + + + //// implicit location descriptions //// + + case DW_ExprOp_ImplicitValue: + { + U64 size = 0; + step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &size); + if (step_cursor + size > task_range.max) { + result.flags |= DW_ExprFlag_BadData; + goto finish; + } + step_cursor += size; + last_was_implicit_loc = 1; + } break; + + case DW_ExprOp_StackValue: + { + last_was_implicit_loc = 1; + } break; + + + //// composite location descriptions //// + + case DW_ExprOp_Piece: + { + U64 size = 0; + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &size); + result.flags |= DW_ExprFlag_UsesComposite; + + last_was_implicit_loc = 0; + } break; + + case DW_ExprOp_BitPiece: + { + U64 bit_size = 0; U64 bit_off = 0; + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_size); + step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_off); + result.flags |= DW_ExprFlag_UsesComposite; + + last_was_implicit_loc = 0; + } break; + + + //// final fallback //// + + default: + { + result.flags |= DW_ExprFlag_NotSupported; + } goto finish; + } + + // increment cursor + cursor = step_cursor; + } + + // check for end of task + if (cursor < task_data.size) { + goto finish_task; + } + } + + finish_task:; + } + finish:; + + scratch_end(scratch); + return result; +} + +//- full eval + +internal DW_Location +dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_ExprMachineConfig *config) +{ + Temp scratch = scratch_begin(&arena_optional, 1); + + DW_Location result = {0}; + + // setup stack + DW_ExprStack stack = dw_expr__stack_make(scratch.arena); + + // adjust expr range + void *expr_ptr = (U8*)expr_base + expr_range.min; + U64 expr_size = expr_range.max - expr_range.min; + + // setup call stack + DW_ExprCallStack call_stack = {0}; + dw_expr__call_push(scratch.arena, &call_stack, expr_ptr, expr_size); + + // state variables + DW_SimpleLoc stashed_loc = {DW_SimpleLocKind_Address}; + + // run loop + U64 max_step_count = config->max_step_count; + U64 step_counter = 0; + for (;;) { + // check top of stack + DW_ExprCall *call = dw_expr__call_top(&call_stack); + if (call == 0) { + goto finish; + } + + // grab top of stack details + void *base = call->ptr; + Rng1U64 range = rng_1u64(0, call->size); + U64 cursor = call->cursor; + + // decode op + U64 op_offset = cursor; + U8 op = 0; + if (based_range_read(base, range, op_offset, 1, &op)) { + U64 after_op_off = cursor + 1; + + // require piece op after 'implicit' location descriptions + if (stashed_loc.kind != DW_SimpleLocKind_Address) { + if (op != DW_ExprOp_Piece && op != DW_ExprOp_BitPiece) { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_BadData; + goto finish; + } + } + + // step params + U64 size_param = 0; + B32 is_signed = 0; + + // step + U64 step_cursor = after_op_off; + switch (op) { + + //// literal encodings //// + + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: + { + U64 x = op - DW_ExprOp_Lit0; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Const1U:size_param = 1; goto const_n; + case DW_ExprOp_Const2U:size_param = 2; goto const_n; + case DW_ExprOp_Const4U:size_param = 4; goto const_n; + case DW_ExprOp_Const8U:size_param = 8; goto const_n; + case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n; + case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n; + case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n; + case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; + const_n: + { + U64 x = 0; + step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + if (is_signed) { + x = extend_sign64(x, size_param); + } + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Addr: + { + U64 offset = 0; + step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + + // earlier versions of GCC emit TLS offset with DW_ExprOp_Addr. + B32 is_text_relative; + { + U8 next_op = 0; + based_range_read_struct(base, range, step_cursor, &next_op); + is_text_relative = (next_op != DW_ExprOp_GNU_PushTlsAddress); + } + + U64 addr = offset; + + if (is_text_relative) { + if (config->text_section_base != 0) { + addr += *config->text_section_base; + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingTextBase; + goto finish; + } + } + + dw_expr__stack_push(scratch.arena, &stack, addr); + } break; + + case DW_ExprOp_ConstU: + { + U64 x = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_ConstS: + { + U64 x = 0; + step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + + //// register based addressing //// + + case DW_ExprOp_FBReg: + { + S64 offset = 0; + step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + if (config->frame_base != 0) { + U64 x = *config->frame_base + offset; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingFrameBase; + goto finish; + } + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: + { + S64 offset = 0; + step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + U64 reg_idx = op - DW_ExprOp_BReg0; + DW_RegsX64 *regs = config->regs; + if (regs != 0) { + if (reg_idx < ArrayCount(regs->r)) { + U64 x = regs->r[reg_idx] + offset; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_BadData; + stashed_loc.fail_data = op_offset; + goto finish; + } + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingRegisters; + goto finish; + } + } break; + + case DW_ExprOp_BRegX: + { + U64 reg_idx = 0; S64 offset = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); + step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + + DW_RegsX64 *regs = config->regs; + if (regs != 0) { + if (reg_idx < ArrayCount(regs->r)) { + U64 x = regs->r[reg_idx] + offset; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_BadData; + stashed_loc.fail_data = op_offset; + goto finish; + } + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingRegisters; + goto finish; + } + } break; + + + //// stack operations //// + + case DW_ExprOp_Dup: + { + U64 x = dw_expr__stack_pick(&stack, 0); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Drop: + { + dw_expr__stack_pop(&stack); + } break; + + case DW_ExprOp_Pick: + { + U64 idx = 0; + step_cursor += based_range_read(base, range, step_cursor, 1, &idx); + U64 x = dw_expr__stack_pick(&stack, idx); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Over: + { + U64 x = dw_expr__stack_pick(&stack, 1); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Swap: + { + U64 a = dw_expr__stack_pop(&stack); + U64 b = dw_expr__stack_pop(&stack); + dw_expr__stack_push(scratch.arena, &stack, b); + dw_expr__stack_push(scratch.arena, &stack, a); + } break; + + case DW_ExprOp_Rot: + { + U64 a = dw_expr__stack_pop(&stack); + U64 b = dw_expr__stack_pop(&stack); + U64 c = dw_expr__stack_pop(&stack); + dw_expr__stack_push(scratch.arena, &stack, a); + dw_expr__stack_push(scratch.arena, &stack, c); + dw_expr__stack_push(scratch.arena, &stack, b); + } break; + + case DW_ExprOp_Deref: + { + U64 addr = dw_expr__stack_pop(&stack); + + B32 read_success = 0; + if (config->read_memory) { + U64 x = 0; + if (config->read_memory(addr, sizeof(x), &x, config->read_memory_ud) == sizeof(x)) { + dw_expr__stack_push(scratch.arena, &stack, x); + read_success = 1; + } + } + + if (!read_success) { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingMemory; + stashed_loc.fail_data = addr; + goto finish; + } + } break; + + case DW_ExprOp_DerefSize: + { + U64 raw_size = 0; + step_cursor += based_range_read(base, range, step_cursor, 1, &raw_size); + + U64 size = ClampTop(raw_size, 8); + U64 addr = dw_expr__stack_pop(&stack); + + B32 read_success = 0; + if (config->read_memory) { + U64 x = 0; + if (config->read_memory(addr, size, &x, config->read_memory_ud) == sizeof(x)) { + dw_expr__stack_push(scratch.arena, &stack, x); + read_success = 1; + } + } + if (!read_success) { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingMemory; + stashed_loc.fail_data = addr; + goto finish; + } + } break; + + case DW_ExprOp_XDeref: + case DW_ExprOp_XDerefSize: + { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_NotSupported; + goto finish; + } break; + + case DW_ExprOp_PushObjectAddress: + { + if (config->object_address != 0) { + U64 x = *config->object_address; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingObjectAddress; + goto finish; + } + } break; + + // NOTE: pop offset from stack, convert it to TLS address, then push it back. + case DW_ExprOp_GNU_PushTlsAddress: + case DW_ExprOp_FormTlsAddress: + { + S64 s = (S64)dw_expr__stack_pop(&stack); + + if (config->tls_address != 0) { + U64 x = *config->tls_address + s; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingTLSAddress; + goto finish; + } + } break; + + case DW_ExprOp_CallFrameCfa: + { + if (config->cfa != 0) { + U64 x = *config->cfa; + dw_expr__stack_push(scratch.arena, &stack, x); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingCFA; + goto finish; + } + } break; + + + //// arithmetic and logical operations //// + + case DW_ExprOp_Abs: + { + S64 s = (S64)dw_expr__stack_pop(&stack); + S64 x = abs_s64(s); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_And: + { + U64 x = dw_expr__stack_pop(&stack); + U64 y = dw_expr__stack_pop(&stack); + dw_expr__stack_push(scratch.arena, &stack, x&y); + } break; + + case DW_ExprOp_Div: + { + S64 d = (S64)dw_expr__stack_pop(&stack); + S64 n = (S64)dw_expr__stack_pop(&stack); + S64 x = (d == 0)?0:n/d; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Minus: + { + U64 b = dw_expr__stack_pop(&stack); + U64 a = dw_expr__stack_pop(&stack); + U64 x = a - b; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Mod: + { + S64 d = (S64)dw_expr__stack_pop(&stack); + S64 n = (S64)dw_expr__stack_pop(&stack); + S64 x = (d == 0)?0:n%d; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Mul: + { + U64 b = dw_expr__stack_pop(&stack); + U64 a = dw_expr__stack_pop(&stack); + U64 x = a*b; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Neg: + { + S64 s = (S64)dw_expr__stack_pop(&stack); + S64 x = -s; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Not: + { + U64 y = dw_expr__stack_pop(&stack); + U64 x = ~y; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Or: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = y | z; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Plus: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = y + z; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_PlusUConst: + { + U64 y = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &y); + U64 z = dw_expr__stack_pop(&stack); + U64 x = y + z; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Shl: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = 0; + if (y < 64) { + x = z << y; + } + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Shr: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = 0; + if (y < 64) { + x = z >> y; + } + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Shra: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = 0; + if (y < 64) { + x = z >> y; + // sign extensions + if (y > 0 && (z & (1ull << 63))) { + x |= ~((1 << (64 - y)) - 1); + } + } + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Xor: + { + U64 y = dw_expr__stack_pop(&stack); + U64 z = dw_expr__stack_pop(&stack); + U64 x = y ^ z; + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + + //// control flow operations //// + + case DW_ExprOp_Le: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a <= b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Ge: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a >= b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Eq: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a == b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Lt: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a < b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Gt: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a > b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Ne: + { + S64 b = (S64)dw_expr__stack_pop(&stack); + S64 a = (S64)dw_expr__stack_pop(&stack); + U64 x = (a != b); + dw_expr__stack_push(scratch.arena, &stack, x); + } break; + + case DW_ExprOp_Skip: + { + S16 d = 0; + step_cursor += based_range_read(base, range, step_cursor, 2, &d); + step_cursor = step_cursor + d; + } break; + + case DW_ExprOp_Bra: + { + S16 d = 0; + step_cursor += based_range_read(base, range, step_cursor, 2, &d); + U64 b = dw_expr__stack_pop(&stack); + if (b != 0) { + step_cursor = step_cursor + d; + } + } break; + + case DW_ExprOp_Call2: + { + U16 p = 0; + step_cursor += based_range_read(base, range, step_cursor, 2, &p); + if (config->call.func != 0) { + String8 sub_data = config->call.func(config->call.user_ptr, p); + dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingCallResolution; + goto finish; + } + } break; + + case DW_ExprOp_Call4: + { + U32 p = 0; + step_cursor += based_range_read(base, range, step_cursor, 4, &p); + if (config->call.func != 0) { + String8 sub_data = config->call.func(config->call.user_ptr, p); + dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingCallResolution; + goto finish; + } + } break; + + case DW_ExprOp_CallRef: + { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_NotSupported; + goto finish; + } break; + + + //// special operations //// + + case DW_ExprOp_Nop:break; + + + //// register location descriptions //// + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: + { + U64 reg_idx = op - DW_ExprOp_Reg0; + stashed_loc.kind = DW_SimpleLocKind_Register; + stashed_loc.reg_idx = reg_idx; + } break; + + case DW_ExprOp_RegX: + { + U64 reg_idx = 0; + step_cursor += based_range_read(base, range, step_cursor, size_param, ®_idx); + stashed_loc.kind = DW_SimpleLocKind_Register; + stashed_loc.reg_idx = reg_idx; + } break; + + + //// implicit location descriptions //// + + case DW_ExprOp_ImplicitValue: + { + U64 size = 0; + step_cursor += based_range_read(base, range, step_cursor, size_param, &size); + if (step_cursor + size <= range.max) { + void *data = (U8*)base + range.min + step_cursor; + stashed_loc.kind = DW_SimpleLocKind_ValueLong; + stashed_loc.val_long.str = (U8*)data; + stashed_loc.val_long.size = size; + } else { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_BadData; + goto finish; + } + step_cursor += size; + } break; + + case DW_ExprOp_StackValue: + { + U64 x = dw_expr__stack_pop(&stack); + stashed_loc.kind = DW_SimpleLocKind_Value; + stashed_loc.val = x; + } break; + + + //// composite location descriptions //// + + case DW_ExprOp_Piece: + case DW_ExprOp_BitPiece: + { + if (arena_optional == 0) { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_MissingArenaForComposite; + goto finish; + } else { + // determine this piece's size & offset + U64 bit_size = 0; + U64 bit_off = 0; + B32 is_bit_loc = 0; + switch (op) { + case DW_ExprOp_Piece: + { + U64 size = 0; + step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + bit_size = size*8; + } break; + case DW_ExprOp_BitPiece: + { + step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + is_bit_loc = 1; + } break; + } + + // determine this piece's location information + DW_SimpleLoc piece_loc = stashed_loc; + if (piece_loc.kind == DW_SimpleLocKind_Address) { + if (dw_expr__stack_is_empty(&stack)) { + piece_loc.kind = DW_SimpleLocKind_Empty; + } else { + U64 x = dw_expr__stack_pop(&stack); + piece_loc.addr = x; + } + } + + // push the piece + DW_Piece *piece = push_array(arena_optional, DW_Piece, 1); + SLLQueuePush(result.first_piece, result.last_piece, piece); + piece->loc = piece_loc; + piece->bit_size = bit_size; + piece->bit_off = bit_off; + piece->is_bit_loc = is_bit_loc; + + // zero the stached loc + MemoryZeroStruct(&stashed_loc); + } + } break; + + + //// final fallback //// + + default: + { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_NotSupported; + goto finish; + } break; + } + + // increment cursor + cursor = step_cursor; + } + + // advance cursor or finish call + if (cursor < call->size) { + call->cursor = cursor; + } else { + dw_expr__call_pop(&call_stack); + } + + // advance step counter + step_counter += 1; + if (step_counter == max_step_count) { + stashed_loc.kind = DW_SimpleLocKind_Fail; + stashed_loc.fail_kind = DW_LocFailKind_TimeOut; + goto finish; + } + } + + finish:; + + // non-piece location + { + DW_SimpleLoc loc = stashed_loc; + if (result.first_piece == 0) { + + // normal location resolution + loc = stashed_loc; + if (loc.kind == DW_SimpleLocKind_Address) { + if (dw_expr__stack_is_empty(&stack)) { + loc.kind = DW_SimpleLocKind_Empty; + } else { + U64 x = dw_expr__stack_pop(&stack); + loc.addr = x; + } + } + } + // non-piece location resolution after composite + else { + + // change the default kind to empty + if (loc.kind == DW_SimpleLocKind_Address) { + loc.kind = DW_SimpleLocKind_Empty; + } + + // the non-piece should either be empty or fail + if (loc.kind != DW_SimpleLocKind_Empty && + loc.kind != DW_SimpleLocKind_Fail) { + loc.kind = DW_SimpleLocKind_Fail; + loc.fail_kind = DW_LocFailKind_BadData; + } + } + + result.non_piece_loc = loc; + } + + // clear stack + scratch_end(scratch); + return result; +} + +//- dw expr val stack + +internal DW_ExprStack +dw_expr__stack_make(Arena *arena) +{ + DW_ExprStack result = {0}; + return result; +} + +internal void +dw_expr__stack_push(Arena *arena, DW_ExprStack *stack, U64 x) +{ + DW_ExprStackNode *node = stack->free_nodes; + if (node == 0) { + SLLStackPop(stack->free_nodes); + } else { + node = push_array(arena, DW_ExprStackNode, 1); + } + SLLStackPush(stack->stack, node); + node->val = x; + stack->count += 1; +} + +internal U64 +dw_expr__stack_pop(DW_ExprStack *stack) +{ + U64 result = 0; + DW_ExprStackNode *node = stack->stack; + if (node != 0) { + SLLStackPop(stack->stack); + stack->count -= 1; + result = node->val; + } + return result; +} + +internal U64 +dw_expr__stack_pick(DW_ExprStack *stack, U64 idx) +{ + U64 result = 0; + if (idx < stack->count) { + U64 counter = idx; + DW_ExprStackNode *node = stack->stack; + for (;node != 0 && counter > 0; node = node->next, counter -= 1); + if (counter == 0 && node != 0) { + result = node->val; + } + } + return result; +} + +internal B32 +dw_expr__stack_is_empty(DW_ExprStack *stack) +{ + B32 result = (stack->count == 0); + return result; +} + +//- dw expr call stack + +internal DW_ExprCall* +dw_expr__call_top(DW_ExprCallStack *stack) +{ + DW_ExprCall *call = stack->stack; + return call; +} + +internal void +dw_expr__call_push(Arena *arena, DW_ExprCallStack *stack, void *ptr, U64 size) +{ + DW_ExprCall *call = 0; + if (call != 0) { + SLLStackPop(stack->free_calls); + } else { + call = push_array(arena, DW_ExprCall, 1); + } + MemoryZeroStruct(call); + SLLStackPush(stack->stack, call); + stack->depth += 1; +} + +internal void +dw_expr__call_pop(DW_ExprCallStack *stack) +{ + DW_ExprCall *top = stack->stack; + if (top != 0) + { + SLLStackPop(stack->stack); + SLLStackPush(stack->free_calls, top); + } +} + +//- analysis tasks + +internal DW_ExprAnalysisTask* +dw_expr__analysis_task_from_p(DW_ExprAnalysisTask *first, U64 p) +{ + DW_ExprAnalysisTask *result = 0; + for (DW_ExprAnalysisTask *task = first; task != 0; task = task->next) { + if (task->p == p) { + result = task; + break; + } + } + return result; +} + diff --git a/src/dwarf/dwarf_expr.h b/src/dwarf/dwarf_expr.h new file mode 100644 index 00000000..0d8cb10a --- /dev/null +++ b/src/dwarf/dwarf_expr.h @@ -0,0 +1,301 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_EXPR_H +#define DWARF_EXPR_H + +//////////////////////////////// +//~ Dwarf Register Layout + +typedef struct DW_RegsX64 +{ + union { + struct { + U64 rax; + U64 rdx; + U64 rcx; + U64 rbx; + U64 rsi; + U64 rdi; + U64 rbp; + U64 rsp; + U64 r8; + U64 r9; + U64 r10; + U64 r11; + U64 r12; + U64 r13; + U64 r14; + U64 r15; + U64 rip; + }; + U64 r[17]; + }; +} DW_RegsX64; + +//////////////////////////////// +//~ Dwarf Expression Eval Types + +#define DW_READ_MEMORY_SIG(name) U64 name(U64 addr, U64 size, void *out, void *ud) +typedef DW_READ_MEMORY_SIG(DW_ReadMemorySig); + +//- machine configuration types +typedef String8 DW_ExprResolveCallFunc(void *call_user_ptr, U64 p); + +typedef struct DW_ExprMachineCallConfig +{ + void *user_ptr; + DW_ExprResolveCallFunc *func; +} DW_ExprMachineCallConfig; + +typedef struct DW_ExprMachineConfig +{ + U64 max_step_count; // (read only in the eval functions) + DW_ReadMemorySig *read_memory; + void *read_memory_ud; + DW_RegsX64 *regs; + U64 *text_section_base; + U64 *frame_base; + U64 *object_address; + U64 *tls_address; + U64 *cfa; + DW_ExprMachineCallConfig call; +} DW_ExprMachineConfig; + + +//- detail analysis types +typedef U32 DW_ExprFlags; +enum +{ + DW_ExprFlag_UsesTextBase = (1 << 0), + DW_ExprFlag_UsesMemory = (1 << 1), + DW_ExprFlag_UsesRegisters = (1 << 2), + DW_ExprFlag_UsesFrameBase = (1 << 3), + DW_ExprFlag_UsesObjectAddress = (1 << 4), + DW_ExprFlag_UsesTLSAddress = (1 << 5), + DW_ExprFlag_UsesCFA = (1 << 6), + DW_ExprFlag_UsesCallResolution = (1 << 7), + DW_ExprFlag_UsesComposite = (1 << 8), + + DW_ExprFlag_NotSupported = (1 << 16), + DW_ExprFlag_BadData = (1 << 17), + DW_ExprFlag_NonLinearFlow = (1 << 18) +}; + +typedef struct DW_ExprAnalysis +{ + DW_ExprFlags flags; +} DW_ExprAnalysis; + +typedef struct DW_ExprAnalysisTask +{ + struct DW_ExprAnalysisTask *next; + U64 p; + String8 data; +} DW_ExprAnalysisTask; + + +//- location types +typedef enum DW_SimpleLocKind +{ + DW_SimpleLocKind_Address, + DW_SimpleLocKind_Register, + DW_SimpleLocKind_Value, + DW_SimpleLocKind_ValueLong, + DW_SimpleLocKind_Empty, + DW_SimpleLocKind_Fail, +} DW_SimpleLocKind; + +typedef enum DW_LocFailKind +{ + // Interpreting Fail Kinds + // + // BadData: the evaluator detected that the dwarf expression operation is incorrectly formed + // NotSupported: the evaluator does not support a dwarf feature that was found in the dwarf expression + // TimeOut: the evaluator hit the maximum step count + // TooComplicated: used by analyzer when it the expression uses features outside of the analyzer's scope + // Missing*: the dwarf machine config was missing necessary information to finish the evaluation + + DW_LocFailKind_BadData, + DW_LocFailKind_NotSupported, + DW_LocFailKind_TimeOut, + DW_LocFailKind_TooComplicated, + DW_LocFailKind_MissingTextBase, + DW_LocFailKind_MissingMemory, + DW_LocFailKind_MissingRegisters, + DW_LocFailKind_MissingFrameBase, + DW_LocFailKind_MissingObjectAddress, + DW_LocFailKind_MissingTLSAddress, + DW_LocFailKind_MissingCFA, + DW_LocFailKind_MissingCallResolution, + DW_LocFailKind_MissingArenaForComposite, +} DW_LocFailKind; + +typedef struct DW_SimpleLoc +{ + DW_SimpleLocKind kind; + union { + U64 addr; + U64 reg_idx; + U64 val; + String8 val_long; + struct { + DW_LocFailKind fail_kind; + U64 fail_data; + }; + }; +} DW_SimpleLoc; + +typedef struct DW_Piece +{ + // Hint for Interpreting Pieces + // + // src = decode(loc, is_bit_loc, bit_size); + // dst |= (src >> bit_off) << bit_cursor; + // bit_cursor += bit_size; + + struct DW_Piece *next; + DW_SimpleLoc loc; + U64 bit_size; + U64 bit_off; + B32 is_bit_loc; +} DW_Piece; + +typedef struct DW_Location +{ + // Interpreting a Dwarf Location + // + // CASE (any number of pieces, fail in the non-piece): + // this is how errors are reported, error information is in the non-piece + // the 'fail' location kind should never show up in a piece + // if there are any pieces they can be treated as correct information that + // was successfully decoded before the error was encountered + // + // CASE (no pieces, empty non-piece): + // the data is completely optimized out and unrecoverable + // + // CASE (no pieces, non-empty non-piece): + // the size of the data is not known by the location, but something in the + // surrounding context of the location (eg type info) should know the size + // + // CASE (one-or-more pieces, empty non-piece): + // the data is described by the pieces + // + // CASE (one-or-more pieces, non-empty non-fail non-piece): + // this is supposed to be impossible; the non-piece either carries an error + // or *all* of the location information about the data, there should never + // be a mix of piece-based location and non-piece-based location data. + + DW_Piece *first_piece; + DW_Piece *last_piece; + U64 count; + + DW_SimpleLoc non_piece_loc; +} DW_Location; + + +//- full evaluator state types +typedef struct DW_ExprStackNode +{ + struct DW_ExprStackNode *next; + U64 val; +} DW_ExprStackNode; + +typedef struct DW_ExprStack +{ + DW_ExprStackNode *stack; + DW_ExprStackNode *free_nodes; + U64 count; +} DW_ExprStack; + +typedef struct DW_ExprCall +{ + struct DW_ExprCall *next; + void *ptr; + U64 size; + U64 cursor; +} DW_ExprCall; + +typedef struct DW_ExprCallStack +{ + DW_ExprCall *stack; + DW_ExprCall *free_calls; + U64 depth; +} DW_ExprCallStack; + +//////////////////////////////// +//~ Dwarf Expression Analysis & Eval Functions + +//- analyzers + +// This analyzer provides the most simplified dwarf expression +// decoding. If the expression consists of a single op that can be interpreted +// as a valid dwarf expression, then it represents that expression as a simple +// location. +// +// If there is a single 'piece' op that is represeted here as an empty simple +// location, losing whatever additional size information from the piece. +// +// If there is an op that requires the machine configuration data the analyzer +// fails with "too complicated" - unless the required configuration data is the +// text section base which this analyzer treats as a non-optional parameter and +// always decodes successfully. +// +// If the expression contains more than one op than the analyzer fails with +// "too complicated". + +internal DW_SimpleLoc dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base); + +// This analyzer does a one-pass scan through the expression to +// help a caller determine what to expect before doing a full evaluation which +// has to maintain value stacks, perform more checks, and execute any loops +// that may appear in the expression, etc. +// +// For each piece of data that can be equipped to a machine config there is a +// 'Uses' flag in the analysis. A user can use these flags to determine what to +// prepare and equip before a full eval. This can be a lot more efficient than +// always preparing everything, or iteratively equipping and retrying after +// each failure. +// +// The analysis can also catch some cases of bad data and unsupported features. +// These flags are useful for short circuit style optimizations, but they are +// not definitive, some bad data can only be caught by the full evaluator. +// Sometimes the full evaluator might miss bad data that this analyzer will see +// if control flow in the evaluator completely skips the bad data. A forgiving +// interpretation of dwarf expression data would only rely on the results of +// the full evaluator. A more strict interpretation would consider it an error +// if either this analyzer or the evaluator finds bad data. +// +// The analyzer also determines if there is any possibility for non-linear +// flow. Jumps, branches, and call ops all create non-linear flow. An +// expression that doesn't have non-linear flow is trivially gauranteed to +// terminate and therefore a good candidate for conversion to a human readable +// expression. +// +// The call config is optional (may be null). If is provided the analysis +// includes features seen in all of the expressions that might be reached by +// call ops from the initial expression. + +internal DW_ExprAnalysis dw_expr__analyze_details(void *base, Rng1U64 range, DW_ExprMachineCallConfig *call_config); + +//- full eval +internal DW_Location dw_expr__eval(Arena *arena_optional, void *base, Rng1U64 range, DW_ExprMachineConfig *config); + +//- dw expr val stack +internal DW_ExprStack dw_expr__stack_make(Arena *arena); +internal void dw_expr__stack_push(Arena *arena, DW_ExprStack *stack, U64 x); +internal U64 dw_expr__stack_pop(DW_ExprStack *stack); +internal U64 dw_expr__stack_pick(DW_ExprStack *stack, U64 idx); +internal B32 dw_expr__stack_is_empty(DW_ExprStack *stack); + +//- dw expr call stack +internal DW_ExprCall* dw_expr__call_top(DW_ExprCallStack *stack); +internal void dw_expr__call_push(Arena *arena, DW_ExprCallStack *stack, void *ptr, U64 size); +internal void dw_expr__call_pop(DW_ExprCallStack *stack); + + +//- analysis tasks +internal DW_ExprAnalysisTask* dw_expr__analysis_task_from_p(DW_ExprAnalysisTask *first, U64 p); + +#endif //DWARF_EXPR_H + diff --git a/src/dwarf/dwarf_notes.txt b/src/dwarf/dwarf_notes.txt new file mode 100644 index 00000000..2c02214f --- /dev/null +++ b/src/dwarf/dwarf_notes.txt @@ -0,0 +1,42 @@ +--- DWARF NOTES --------------------------------------------------------------- + +DWARF V4 Spec: http://www.dwarfstd.org/doc/DWARF4.pdf +DWARF V5 Spec: http://www.dwarfstd.org/doc/DWARF5.pdf + +------------------------------------------------------------------------------- + +$ (2021/04/30) On .debug_pubtypes, .debug_pubnames, and .debug_names: + +.debug_pubtypes and .debug_pubnames are tables that map from a string (the name +of a type or function respectively) to an offset into .debug_info, which is the +offset of the Debug Information Entry (DIE, in DWARF terminology) of the info +associated with the string. THESE TWO SECTIONS ARE OPTIONAL. They don't show up +in every DWARF-holding file, and so they cannot be relied upon as acceleration +structures. But we're going to support parsing them, to make things a bit nicer +in cases where they are present. DWARF doesn't have much in the way of acceler- +ation structures built in, so our rationale is that we should take anything we +can get to make the format a bit more in some subset of the possible cases. + +.debug_names is a DWARF V5 section that is intended to replace .debug_pubtypes +and .debug_pubnames. However, even in cases when DWARF V5 is produced at the +time of writing this, we have not found .debug_names sections being produced. +We did not exhaustively test all compilers and configurations, but it seems +that it is not well-supported at all by major compilers, and there's a very low +probability that a user will have that section, so our current thinking is +that there's no point in supporting it right now. + +------------------------------------------------------------------------------- + +$ (2021/04/30) On producing DWARF V5 with Clang: + +https://lists.llvm.org/pipermail/llvm-dev/2018-August/125068.html + +By default it looks like (at the time of writing this) that Clang, by default, +will produce DWARF V4. To produce DWARF V5, however, you can use the -gdwarf-5 +option. Even when that option is used, it seems that some features of V5 are +not used (for example, .debug_names). + +The above link also says that this will produce .debug_names, but it doesn't as +of Clang 10. + +------------------------------------------------------------------------------- diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c new file mode 100644 index 00000000..d1919758 --- /dev/null +++ b/src/dwarf/dwarf_parse.c @@ -0,0 +1,2340 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// TODO(rjf): +// +// [ ] Any time we encode a subrange of a section inside of a +// DW_AttribValue, we need to do that consistently, regardless of +// whether or not it is a string, memory block, etc. We should just use +// the DW_SectionKind and then the min/max pair. +// +// [ ] Things we are not reporting, or haven't figured out: +// @dwarf_expr @dwarf_v5 @dw_cross_unit +// [ ] currently, we're filtering out template arguments in the member accelerator. +// this is because they don't correspond one-to-one with anything in PDB, but +// they do contain useful information that we might want to expose another way +// somehow. +// [ ] DWARF V5 features that nobody seems to use right now +// [ ] ref_addr_desc + next_info_ctx +// apparently these are necessary when dereferencing some DWARF V5 ways of +// forming references. They don't seem to come up at all for any real data +// but might be a case somewhere. +// [ ] case when only .debug_line and .debug_line_str is available, without +// compilation unit debug info? do we care about this at all? +// [ ] DW_Form_RefSig8, which requires using .debug_names +// to do a lookup for a reference +// [ ] DWARF V5, but also V1 & V2 for dw_range_list_from_range_offset +// [ ] DW_AttribClass_RngList and DW_Form_RngListx +// [ ] DW_OpCode_XDEREF_SIZE + DW_OpCode_XDEREF +// [ ] DW_OpCode_PIECE + DW_OpCode_BIT_PIECE +// [ ] DW_ExtOpcode_DefineFile, for line info +// [ ] DWARF procedures in DWARF expr evaluation +// [ ] DW_Attrib_DataMemberLocation is not being *fully* handled right +// now; full handling requires evaluating a DWARF expression to find out the +// offset of a member. Right now we handle the common case, which is when it +// is encoded as a constant value. +// [ ] inline information +// [ ] full info we are not handling: +// [ ] friend classes +// [ ] DWARF macro info +// [ ] whether or not a function is the entry point +// [ ] attributes we are not handling that may be important: +// [ ] DW_Attrib_AbstractOrigin +// - ??? +// [ ] DW_Attrib_VariableParameter +// - determines whether or not a parameter to a function is mutable, I think? +// [ ] DW_Attrib_Mutable +// - I think this is for specific keywords, may not be relevant to C/++ +// [ ] DW_Attrib_CallColumn +// - column position of an inlined subroutine +// [ ] DW_Attrib_CallFile +// - file of inlined subroutine +// [ ] DW_Attrib_CallLine +// - line number of inlined subroutine +// [ ] DW_Attrib_ConstExpr +// - ??? maybe C++ constexpr? +// [ ] DW_Attrib_EnumClass +// - c++ thing that's an enum with a backing type +// [ ] DW_Attrib_LinkageName +// - name used to do linking + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +dw_hash_from_string(String8 string) +{ + XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size); + return hash64; +} + +internal DW_AttribClass +dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib_kind, DW_FormKind form_kind) +{ + // NOTE(rjf): DWARF's spec specifies two mappings: + // (DW_AttribKind) => List(DW_AttribClass) + // (DW_FormKind) => List(DW_AttribClass) + // + // This function's purpose is to find the overlapping class between an + // DW_AttribKind and DW_FormKind. + + DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind); + DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind); + + // rust compiler is busted, it writes version 5 attributes + if(ver == DW_Version_2 && lang == DW_Language_Rust && (attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null)) + { + attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_5, ext, attrib_kind); + form_class = dw_attrib_class_from_form_kind(DW_Version_5, form_kind); + } + + DW_AttribClass result = DW_AttribClass_Null; + if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null) + { + result = DW_AttribClass_Undefined; + + for(U32 i = 0; i < 32; ++i) + { + U32 n = 1u << i; + if((attrib_class & n) != 0 && (form_class & n) != 0) + { + result = ((DW_AttribClass) n); + break; + } + } + + Assert(result != DW_AttribClass_Undefined); + } + + return result; +} + +//////////////////////////////// +//~ rjf: DWARF-Specific Based Range Reads + +internal U64 +based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) +{ + String8 data = str8((U8*)base+range.min, dim_1u64(range)); + return str8_deserial_read(data, offset, out, size, 1); +} + +#define based_range_read_struct(base, range, offset, out) based_range_read(base, range, offset, sizeof(*out), out) + +internal String8 +based_range_read_string(void *base, Rng1U64 range, U64 offset) +{ + String8 data = str8((U8*)base+range.min, dim_1u64(range)); + String8 result = {0}; + str8_deserial_read_cstr(data, offset, &result); + return result; +} + +internal void * +based_range_ptr(void *base, Rng1U64 range, U64 offset) +{ + Assert(offset < dim_1u64(range)); + U8 *data = (U8*)base + range.min + offset; + return data; +} + +internal U64 +based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) +{ + U64 value = 0; + U64 bytes_read = 0; + U64 shift = 0; + U8 byte = 0; + for(U64 read_offset = offset; + based_range_read_struct(base, range, read_offset, &byte) == 1; + read_offset += 1) + { + bytes_read += 1; + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + if((byte&0x80u) == 0) + { + break; + } + shift += 7u; + } + if(out_value != 0) + { + *out_value = value; + } + return bytes_read; +} + +internal U64 +based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) +{ + U64 value = 0; + U64 bytes_read = 0; + U64 shift = 0; + U8 byte = 0; + for(U64 read_offset = offset; + based_range_read_struct(base, range, read_offset, &byte) == 1; + read_offset += 1) + { + bytes_read += 1; + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + shift += 7u; + if((byte&0x80u) == 0) + { + if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) + { + value |= -(S64)(1ull << shift); + } + break; + } + } + if(out_value != 0) + { + *out_value = value; + } + return bytes_read; +} + +//////////////////////////////// + +internal U64 +dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value) +{ + U64 bytes_read = 0; + U64 value = 0; + U32 first32 = 0; + if(based_range_read_struct(base, range, offset, &first32)) + { + // NOTE(rjf): DWARF 32-bit => use the first 32 bits as the size. + if(first32 != max_U32) + { + value = (U64)first32; + bytes_read = sizeof(U32); + } + // NOTE(rjf): DWARF 64-bit => first 32 are just a marker, use the next 64 bits as the size. + else if(based_range_read_struct(base, range, offset + sizeof(U32), &value)) + { + value = 0; + bytes_read = sizeof(U32) + sizeof(U64); + } + } + if(out_value != 0) + { + *out_value = value; + } + return bytes_read; +} + +internal U64 +dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev) +{ + U64 total_bytes_read = 0; + + //- rjf: parse ID + U64 id_off = offset; + U64 sub_kind_off = id_off; + U64 id = 0; + { + U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); + sub_kind_off += bytes_read; + total_bytes_read += bytes_read; + } + + //- rjf: parse sub-kind + U64 sub_kind = 0; + U64 next_off = sub_kind_off; + if(id != 0) + { + U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; + total_bytes_read += bytes_read; + } + + //- rjf: parse whether this tag has children + U8 has_children = 0; + if(id != 0) + { + total_bytes_read += based_range_read_struct(base, range, next_off, &has_children); + } + + //- rjf: fill abbrev + if(out_abbrev != 0) + { + DW_Abbrev abbrev = {0}; + abbrev.kind = DW_Abbrev_Tag; + abbrev.abbrev_range = rng_1u64(range.min+offset, range.min+offset+total_bytes_read); + abbrev.sub_kind = sub_kind; + abbrev.id = id; + if(has_children) + { + abbrev.flags |= DW_AbbrevFlag_HasChildren; + } + *out_abbrev = abbrev; + } + + return total_bytes_read; +} + +internal U64 +dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev) +{ + U64 total_bytes_read = 0; + + //- rjf: parse ID + U64 id_off = offset; + U64 sub_kind_off = id_off; + U64 id = 0; + { + U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); + sub_kind_off += bytes_read; + total_bytes_read += bytes_read; + } + + //- rjf: parse sub-kind (form-kind) + U64 sub_kind = 0; + U64 next_off = sub_kind_off; + { + U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; + total_bytes_read += bytes_read; + } + + //- rjf: parse implicit const + U64 implicit_const = 0; + if(sub_kind == DW_Form_ImplicitConst) + { + U64 bytes_read = based_range_read_uleb128(base, range, next_off, &implicit_const); + total_bytes_read += bytes_read; + } + + //- rjf: fill abbrev + if(out_abbrev != 0) + { + DW_Abbrev abbrev = {0}; + abbrev.kind = DW_Abbrev_Attrib; + abbrev.abbrev_range = rng_1u64(offset, offset+total_bytes_read); + abbrev.sub_kind = sub_kind; + abbrev.id = id; + if(sub_kind == DW_Form_ImplicitConst) + { + abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; + abbrev.const_value = implicit_const; + } + *out_abbrev = abbrev; + } + + return total_bytes_read; +} + +internal U64 +dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out) +{ + U64 bytes_read = 0; + U64 bytes_to_read = 0; + DW_AttribValue form_value = {0}; + + switch(form_kind) + { + case DW_Form_Null: break; + + //- rjf: 1-byte uint reads + case DW_Form_Ref1: case DW_Form_Data1: case DW_Form_Flag: + case DW_Form_Strx1: case DW_Form_Addrx1: + bytes_to_read = 1; goto read_fixed_uint; + + //- rjf: 2-byte uint reads + case DW_Form_Ref2: case DW_Form_Data2: case DW_Form_Strx2: + case DW_Form_Addrx2: + bytes_to_read = 2; goto read_fixed_uint; + + //- rjf: 3-byte uint reads + case DW_Form_Strx3: case DW_Form_Addrx3: + bytes_to_read = 3; goto read_fixed_uint; + + //- rjf: 4-byte uint reads + case DW_Form_Data4: case DW_Form_Ref4: case DW_Form_RefSup4: case DW_Form_Strx4: case DW_Form_Addrx4: + bytes_to_read = 4; goto read_fixed_uint; + + //- rjf: 8-byte uint reads + case DW_Form_Data8: case DW_Form_Ref8: case DW_Form_RefSig8: case DW_Form_RefSup8: + bytes_to_read = 8; goto read_fixed_uint; + + //- rjf: address-size reads + case DW_Form_Addr: bytes_to_read = address_size; goto read_fixed_uint; + + //- rjf: offset-size reads + case DW_Form_RefAddr: case DW_Form_SecOffset: case DW_Form_LineStrp: + case DW_Form_Strp: case DW_Form_StrpSup: + bytes_to_read = dw_offset_size_from_mode(mode); goto read_fixed_uint; + + //- rjf: fixed-size uint reads + { + read_fixed_uint:; + U64 value = 0; + bytes_read = based_range_read(base, range, offset, bytes_to_read, &value); + form_value.v[0] = value; + } break; + + //- rjf: uleb128 reads + case DW_Form_UData: case DW_Form_RefUData: case DW_Form_Strx: + case DW_Form_Addrx: case DW_Form_LocListx: case DW_Form_RngListx: + { + U64 value = 0; + bytes_read = based_range_read_uleb128(base, range, offset, &value); + form_value.v[0] = value; + } break; + + //- rjf: sleb128 reads + case DW_Form_SData: + { + S64 value = 0; + bytes_read = based_range_read_sleb128(base, range, offset, &value); + form_value.v[0] = value; + } break; + + //- rjf: fixed-size uint read + skip + case DW_Form_Block1: bytes_to_read = 1; goto read_fixed_uint_skip; + case DW_Form_Block2: bytes_to_read = 2; goto read_fixed_uint_skip; + case DW_Form_Block4: bytes_to_read = 4; goto read_fixed_uint_skip; + { + read_fixed_uint_skip:; + U64 size = 0; + bytes_read = based_range_read(base, range, offset, bytes_to_read, &size); + form_value.v[0] = size; + form_value.v[1] = offset; + bytes_read += size; + } break; + + //- rjf: uleb 128 read + skip + case DW_Form_Block: + { + U64 size = 0; + bytes_read = based_range_read_uleb128(base, range, offset, &size); + form_value.v[0] = size; + form_value.v[1] = offset; + bytes_read += size; + } break; + + //- rjf: u64 ranges + case DW_Form_Data16: + { + U64 value1 = 0; + U64 value2 = 0; + bytes_read += based_range_read_struct(base, range, offset, &value1); + bytes_read += based_range_read_struct(base, range, offset + sizeof(U64), &value2); + form_value.v[0] = value1; + form_value.v[1] = value2; + } break; + + //- rjf: strings + case DW_Form_String: + { + String8 string = based_range_read_string(base, range, offset); + bytes_read = string.size + 1; + U64 string_offset = offset; + U64 string_size = (offset + bytes_read) - string_offset; + form_value.v[0] = string_offset; + form_value.v[1] = string_offset+string_size-1; + } break; + + //- rjf: implicit const + case DW_Form_ImplicitConst: + { + // Special case. + // Unlike other forms that have their values stored in the .debug_info section, + // This one defines it's value in the .debug_abbrev section. + form_value.v[0] = implicit_const; + } break; + + //- rjf: expr loc + case DW_Form_ExprLoc: + { + U64 size = 0; + bytes_read = based_range_read_uleb128(base, range, offset, &size); + form_value.v[0] = offset + bytes_read; + form_value.v[1] = size; + bytes_read += size; + } break; + + //- rjf: flag present + case DW_Form_FlagPresent: + { + form_value.v[0] = 1; + } break; + + case DW_Form_Indirect: + { + InvalidPath; + } break; + } + + if(form_value_out != 0) + { + *form_value_out = form_value; + } + + return bytes_read; +} + +//- rjf: important DWARF section base/range accessors + +internal DW_Mode +dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind) +{ + if(sections->v[kind].data.size > 0xffffffff) + { + return DW_Mode_64Bit; + } + else + { + return DW_Mode_32Bit; + } +} + +internal Rng1U64 +dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind) +{ + Rng1U64 result = rng_1u64(0, sections->v[kind].data.size); + return result; +} + +internal void * +dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind) +{ + return sections->v[kind].data.str; +} + +//////////////////////////////// +//~ rjf: Abbrev Table + +internal DW_AbbrevTable +dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 abbrev_offset) +{ + void *file_base = dw_base_from_sec(sections, DW_Section_Abbrev); + Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); + + //- rjf: count the tags we have + U64 tag_count = 0; + for(U64 abbrev_read_off = abbrev_offset - abbrev_range.min;;) + { + DW_Abbrev tag; + { + U64 bytes_read = dw_based_range_read_abbrev_tag(file_base, abbrev_range, abbrev_read_off, &tag); + abbrev_read_off += bytes_read; + if(bytes_read == 0 || tag.id == 0) + { + break; + } + } + for(;;) + { + DW_Abbrev attrib = {0}; + U64 bytes_read = dw_based_range_read_abbrev_attrib_info(file_base, abbrev_range, abbrev_read_off, &attrib); + abbrev_read_off += bytes_read; + if(bytes_read == 0 || attrib.id == 0) + { + break; + } + } + tag_count += 1; + } + + //- rjf: build table + DW_AbbrevTable table = {0}; + table.count = tag_count; + table.entries = push_array(arena, DW_AbbrevTableEntry, table.count); + MemorySet(table.entries, 0, sizeof(DW_AbbrevTableEntry)*table.count); + + U64 tag_idx = 0; + for(U64 abbrev_read_off = abbrev_offset - abbrev_range.min;;) + { + DW_Abbrev tag; + { + U64 bytes_read = dw_based_range_read_abbrev_tag(file_base, abbrev_range, abbrev_read_off, &tag); + abbrev_read_off += bytes_read; + if(bytes_read == 0 || tag.id == 0) + { + break; + } + } + + // rjf: insert this tag into the table + { + table.entries[tag_idx].id = tag.id; + table.entries[tag_idx].off = tag.abbrev_range.min; + tag_idx += 1; + } + + for(;;) + { + DW_Abbrev attrib = {0}; + U64 bytes_read = dw_based_range_read_abbrev_attrib_info(file_base, abbrev_range, abbrev_read_off, &attrib); + abbrev_read_off += bytes_read; + if(bytes_read == 0 || attrib.id == 0) + { + break; + } + } + tag_count += 1; + } + + return table; +} + +internal U64 +dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id) +{ + U64 abbrev_offset = max_U64; + if(table.count > 0) + { + S64 min = 0; + S64 max = (S64)table.count - 1; + while(min <= max) + { + S64 mid = (min + max) / 2; + if (abbrev_id > table.entries[mid].id) + { + min = mid + 1; + } + else if (abbrev_id < table.entries[mid].id) + { + max = mid - 1; + } + else + { + abbrev_offset = table.entries[mid].off; + break; + } + } + } + return abbrev_offset; +} + +//////////////////////////////// +//~ rjf: Miscellaneous DWARF Section Parsing + +//- rjf: .debug_ranges (DWARF V4) + +internal Rng1U64List +dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off) +{ + void *base = dw_base_from_sec(sections, DW_Section_Ranges); + Rng1U64 rng = dw_range_from_sec(sections, DW_Section_Ranges); + + Rng1U64List list = {0}; + + U64 read_off = range_off; + U64 base_addr = comp_unit_base_addr; + + for(;read_off < rng.max;) + { + U64 v0 = 0; + U64 v1 = 0; + read_off += based_range_read(base, rng, read_off, addr_size, &v0); + read_off += based_range_read(base, rng, read_off, addr_size, &v1); + + //- rjf: base address entry + if((addr_size == 4 && v0 == 0xffffffff) || + (addr_size == 8 && v0 == 0xffffffffffffffff)) + { + base_addr = v1; + } + //- rjf: end-of-list entry + else if(v0 == 0 && v1 == 0) + { + break; + } + //- rjf: range list entry + else + { + U64 min_addr = v0 + base_addr; + U64 max_addr = v1 + base_addr; + rng1u64_list_push(arena, &list, rng_1u64(min_addr, max_addr)); + } + } + + return list; +} + +//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4) + +internal DW_PubStringsTable +dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_PubStringsTable names_table = {0}; + + // TODO(rjf): Arbitrary choice. + names_table.size = 16384; + names_table.buckets = push_array(arena, DW_PubStringsBucket*, names_table.size); + + void *base = dw_base_from_sec(sections, section_kind); + Rng1U64 rng = dw_range_from_sec(sections, section_kind); + DW_Mode mode = sections->v[section_kind].mode; + U64 off_size = dw_offset_size_from_mode(mode); + U64 cursor = 0; + + U64 table_length = 0; + U16 unit_version = 0; + U64 cu_info_off = 0; + U64 cu_info_len = 0; + cursor += dw_based_range_read_length(base, rng, cursor, &table_length); + cursor += based_range_read_struct(base, rng, cursor, &unit_version); + cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); + + for(;;) + { + U64 info_off = 0; + { + U64 bytes_read = based_range_read(base, rng, cursor, off_size, &info_off); + cursor += bytes_read; + if(bytes_read == 0) + { + break; + } + } + + //- rjf: if we got a nonzero .debug_info offset, we've found a valid entry. + if(info_off != 0) + { + String8 string = based_range_read_string(base, rng, cursor); + cursor += string.size + 1; + + U64 hash = dw_hash_from_string(string); + U64 bucket_idx = hash % names_table.size; + + DW_PubStringsBucket *bucket = push_array(arena, DW_PubStringsBucket, 1); + bucket->next = names_table.buckets[bucket_idx]; + bucket->string = string; + bucket->info_off = info_off; + bucket->cu_info_off = cu_info_off; + names_table.buckets[bucket_idx] = bucket; + } + + //- rjf: if we did not read a proper entry in the table, we need to try to + // read the header of the next table. + else + { + U64 next_table_length = 0; + { + U64 bytes_read = dw_based_range_read_length(base, rng, cursor, &next_table_length); + if(bytes_read == 0 || next_table_length == 0) + { + break; + } + cursor += bytes_read; + } + cursor += based_range_read_struct(base, rng, cursor, &unit_version); + cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); + } + } + + scratch_end(scratch); + + return names_table; +} + +//- rjf: .debug_str_offsets (DWARF V5) + +internal U64 +dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index) +{ + U64 result = 0; + + DW_Mode mode = sections->v[section].mode; + void *sec_base = dw_base_from_sec(sections, section); + Rng1U64 rng = dw_range_from_sec(sections, section); + U64 cursor = base; + + //- rjf: get the length of each entry + U64 entry_len = mode == DW_Mode_64Bit ? 8 : 4; + + //- rjf: parse the unit's length (not including the length itself) + U64 unit_length = 0; + cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); + + //- rjf: parse version + U16 version = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &version); + Assert(version == 5); // must be 5 as of V5. + + //- rjf: parse padding + U16 padding = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &padding); + Assert(padding == 0); // must be 0 as of V5. + + //- rjf: read + if (unit_length >= sizeof(U16)*2) + { + void *entries = (U8 *)sec_base + cursor; + U64 count = (unit_length - sizeof(U16)*2) / entry_len; + if(0 <= index && index < count) + { + switch(entry_len) + { + default: break; + case 4: result = ((U32 *)entries)[index]; break; + case 8: result = ((U64 *)entries)[index]; break; + } + } + } + + return result; +} + +//- rjf: .debug_addr parsing + +internal U64 +dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index) +{ + U64 result = 0; + + void *sec_base = dw_base_from_sec(sections, section); + Rng1U64 rng = dw_range_from_sec(sections, section); + U64 cursor = base; + + //- rjf: parse the unit's length (not including the length itself) + U64 unit_length = 0; + cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); + + //- rjf: parse version + U16 version = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &version); + Assert(version == 5); // must be 5 as of V5. + + //- rjf: parse address size + U8 address_size = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + + //- rjf: parse segment selector size + U8 segment_selector_size = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + + //- rjf: read + U64 entry_size = address_size + segment_selector_size; + U64 count = (unit_length - sizeof(U16)*2) / entry_size; + if(0 <= index && index < count) + { + void *entry = (U8 *)based_range_ptr(sec_base, rng, cursor) + entry_size*index; + Rng1U64 entry_rng = rng_1u64(0, entry_size); + U64 segment = 0; + U64 addr = 0; + based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); + based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); + result = addr; + } + + return result; +} + +//- rjf: .debug_rnglists + .debug_loclists parsing + +internal U64 +dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index) +{ + // + // NOTE(rjf): This is only appropriate to call when DW_Form_RngListx is + // used to access a range list, *OR* when DW_Form_LocListx is used to + // access a location list. Otherwise, DW_Form_SecOffset is required. + // + // See the DWARF V5 spec (February 13, 2017), page 242. (rnglists) + // See the DWARF V5 spec (February 13, 2017), page 215. (loclists) + // + + U64 result = 0; + + DW_Mode mode = sections->v[section_kind].mode; + void *sec_base = dw_base_from_sec(sections, section_kind); + Rng1U64 rng = dw_range_from_sec(sections, section_kind); + U64 cursor = base; + + //- rjf: get the length of each entry + U64 entry_len = mode == DW_Mode_64Bit ? 8 : 4; + + //- rjf: parse the unit's length (not including the length itself) + U64 unit_length = 0; + cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); + + //- rjf: parse version + U16 version = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &version); + Assert(version == 5); // must be 5 as of V5. + + //- rjf: parse address size + U8 address_size = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + + //- rjf: parse segment selector size + U8 segment_selector_size = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + + //- rjf: parse offset entry count + U32 offset_entry_count = 0; + cursor += based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); + + //- rjf: read from offsets array + U64 table_off = cursor; + void *offsets_arr = based_range_ptr(sec_base, rng, cursor); + if(0 <= index && index < (U64)offset_entry_count) + { + U64 rnglist_offset = 0; + switch(entry_len) + { + default: break; + case 4: rnglist_offset = ((U32 *)offsets_arr)[index]; break; + case 8: rnglist_offset = ((U64 *)offsets_arr)[index]; break; + } + result = rnglist_offset+table_off; + } + + return result; +} + +internal Rng1U64List +dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset) +{ + Rng1U64List list = {0}; + + void *base = dw_base_from_sec(sections, section); + Rng1U64 rng = dw_range_from_sec(sections, section); + U64 cursor = offset; + + U64 base_addr = 0; + + for(B32 done = 0; !done;) + { + U8 kind8 = 0; + cursor += based_range_read_struct(base, rng, cursor, &kind8); + DW_RngListEntryKind kind = (DW_RngListEntryKind)kind8; + + switch(kind) + { + //- rjf: can be used in split and non-split units: + default: + case DW_RngListEntryKind_EndOfList: + { + done = 1; + } break; + + case DW_RngListEntryKind_BaseAddressX: + { + U64 base_addr_idx = 0; + cursor += based_range_read_uleb128(base, rng, cursor, &base_addr_idx); + base_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, base_addr_idx); + } break; + + case DW_RngListEntryKind_StartxEndx: + { + U64 start_addr_idx = 0; + U64 end_addr_idx = 0; + cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += based_range_read_uleb128(base, rng, cursor, &end_addr_idx); + U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); + U64 end_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, end_addr_idx); + rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); + } break; + + case DW_RngListEntryKind_StartxLength: + { + U64 start_addr_idx = 0; + U64 length = 0; + cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += based_range_read_uleb128(base, rng, cursor, &length); + U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); + U64 end_addr = start_addr + length; + rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); + } break; + + case DW_RngListEntryKind_OffsetPair: + { + U64 start_offset = 0; + U64 end_offset = 0; + cursor += based_range_read_uleb128(base, rng, cursor, &start_offset); + cursor += based_range_read_uleb128(base, rng, cursor, &end_offset); + rng1u64_list_push(arena, &list, rng_1u64(start_offset + base_addr, end_offset + base_addr)); + } break; + + //- rjf: non-split units only: + + case DW_RngListEntryKind_BaseAddress: + { + U64 new_base_addr = 0; + cursor += based_range_read(base, rng, cursor, addr_size, &new_base_addr); + base_addr = new_base_addr; + } break; + + case DW_RngListEntryKind_StartEnd: + { + U64 start = 0; + U64 end = 0; + cursor += based_range_read(base, rng, cursor, addr_size, &start); + cursor += based_range_read(base, rng, cursor, addr_size, &end); + rng1u64_list_push(arena, &list, rng_1u64(start, end)); + } break; + + case DW_RngListEntryKind_StartLength: + { + U64 start = 0; + U64 length = 0; + cursor += based_range_read(base, rng, cursor, addr_size, &start); + cursor += based_range_read_uleb128(base, rng, cursor, &length); + rng1u64_list_push(arena, &list, rng_1u64(start, start+length)); + } break; + } + } + + return list; +} + +//////////////////////////////// +//~ rjf: Attrib Value Parsing + +internal DW_AttribValueResolveParams +dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root) +{ + DW_AttribValueResolveParams params = {0}; + params.version = root->version; + params.language = root->language; + params.addr_size = root->address_size; + params.containing_unit_info_off = root->info_off; + params.debug_addrs_base = root->addrs_base; + params.debug_rnglists_base = root->rnglist_base; + params.debug_str_offs_base = root->stroffs_base; + params.debug_loclists_base = root->loclist_base; + return params; +} + +internal DW_AttribValue +dw_attrib_value_from_form_value(DW_SectionArray *sections, + DW_AttribValueResolveParams resolve_params, + DW_FormKind form_kind, + DW_AttribClass value_class, + DW_AttribValue form_value) +{ + DW_AttribValue value = {0}; + + //~ rjf: DWARF V5 value parsing + + //- rjf: (DWARF V5 ONLY) the form value is storing an address index (ADDRess indeX), which we + // must resolve to an actual address using the containing comp unit's contribution to the + // .debug_addr section. + if(resolve_params.version >= DW_Version_5 && + value_class == DW_AttribClass_Address && + (form_kind == DW_Form_Addrx || form_kind == DW_Form_Addrx1 || + form_kind == DW_Form_Addrx2 || form_kind == DW_Form_Addrx3 || + form_kind == DW_Form_Addrx4)) + { + U64 addr_index = form_value.v[0]; + U64 addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, resolve_params.debug_addrs_base, addr_index); + value.v[0] = addr; + } + //- rjf: (DWARF V5 ONLY) lookup into the .debug_loclists section via an index + else if(resolve_params.version >= DW_Version_5 && + value_class == DW_AttribClass_LocList && + form_kind == DW_Form_LocListx) + { + U64 loclist_index = form_value.v[0]; + U64 loclist_offset = dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(sections, DW_Section_LocLists, resolve_params.debug_loclists_base, loclist_index); + value.section = DW_Section_LocLists; + value.v[0] = loclist_offset; + } + //- rjf: (DWARF V5 ONLY) lookup into the .debug_loclists section via an offset + else if(resolve_params.version >= DW_Version_5 && + (value_class == DW_AttribClass_LocList || value_class == DW_AttribClass_LocListPtr) && + form_kind == DW_Form_SecOffset) + { + U64 loclist_offset = form_value.v[0]; + value.section = DW_Section_LocLists; + value.v[0] = loclist_offset; + } + //- rjf: (DWARF V5 ONLY) lookup into the .debug_rnglists section via an index + else if(resolve_params.version >= DW_Version_5 && + (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && + form_kind == DW_Form_RngListx) + { + U64 rnglist_index = form_value.v[0]; + U64 rnglist_offset = dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(sections, DW_Section_RngLists, resolve_params.debug_rnglists_base, rnglist_index); + value.section = DW_Section_RngLists; + value.v[0] = rnglist_offset; + } + //- rjf: (DWARF V5 ONLY) lookup into the .debug_rnglists section via an offset + else if(resolve_params.version >= DW_Version_5 && + (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && + form_kind != DW_Form_RngListx) + { + U64 rnglist_offset = form_value.v[0]; + value.section = DW_Section_RngLists; + value.v[0] = rnglist_offset; + } + //- rjf: (DWARF V5 ONLY) .debug_str_offsets table index, that we need to resolve + // using the containing compilation unit's contribution to the section + else if(resolve_params.version >= DW_Version_5 && + value_class == DW_AttribClass_String && + (form_kind == DW_Form_Strx || + form_kind == DW_Form_Strx1 || + form_kind == DW_Form_Strx2 || + form_kind == DW_Form_Strx3 || + form_kind == DW_Form_Strx4)) + { + DW_SectionKind section = DW_Section_Str; + U64 str_index = form_value.v[0]; + U64 str_offset = dw_v5_offset_from_offs_section_base_index(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base, str_index); + void *base = dw_base_from_sec(sections, section); + Rng1U64 range = dw_range_from_sec(sections, section); + String8 string = based_range_read_string(base, range, str_offset); + value.section = section; + value.v[0] = str_offset; + value.v[1] = value.v[0] + string.size; + } + //- rjf: (DWARF V5 ONLY) reference that we should resolve through ref_addr_desc + else if(resolve_params.version >= DW_Version_5 && + value_class == DW_AttribClass_Reference && + form_kind == DW_Form_RefAddr) + { + // TODO(nick): DWARF 5 @dwarf_v5 + } + //- TODO(rjf): (DWARF V5 ONLY) reference resolution using the .debug_names section + else if(resolve_params.version >= DW_Version_5 && + form_kind == DW_Form_RefSig8) + { + // TODO(nick): DWARF 5: We need to handle .debug_names section in order to resolve this value. @dwarf_v5 + value.v[0] = max_U64; + } + + //~ rjf: All other value parsing (DWARF V4 and below) + + //- rjf: reference to an offset relative to the compilation unit's info base + else if (value_class == DW_AttribClass_Reference && + (form_kind == DW_Form_Ref1 || + form_kind == DW_Form_Ref2 || + form_kind == DW_Form_Ref4 || + form_kind == DW_Form_Ref8 || + form_kind == DW_Form_RefUData)) + { + value.v[0] = resolve_params.containing_unit_info_off + form_value.v[0]; + } + + //- rjf: info-section string -- this is a string that is just pasted straight + // into the .debug_info section + else if(value_class == DW_AttribClass_String && form_kind == DW_Form_String) + { + value = form_value; + value.section = DW_Section_Info; + } + + //- rjf: string-section string -- this is a string that's inside the .debug_str + // section, and we've been provided an offset to it + else if(value_class == DW_AttribClass_String && + (form_kind == DW_Form_Strp || + form_kind == DW_Form_StrpSup)) + { + + DW_SectionKind section = DW_Section_Str; + void *base = dw_base_from_sec(sections, section); + Rng1U64 range = dw_range_from_sec(sections, section); + String8 string = based_range_read_string(base, range, form_value.v[0]); + value.section = section; + value.v[0] = form_value.v[0]; + value.v[1] = value.v[0] + string.size; + } + //- rjf: line-string + else if(value_class == DW_AttribClass_String && form_kind == DW_Form_LineStrp) + { + DW_SectionKind section = DW_Section_LineStr; + void *base = dw_base_from_sec(sections, section); + Rng1U64 range = dw_range_from_sec(sections, section); + String8 string = based_range_read_string(base, range, form_value.v[0]); + value.section = section; + value.v[0] = form_value.v[0]; + value.v[1] = value.v[0] + string.size; + } + //- rjf: .debug_ranges + else if(resolve_params.version < DW_Version_5 && + (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && + (form_kind == DW_Form_SecOffset)) + { + U64 ranges_offset = form_value.v[0]; + value.section = DW_Section_Ranges; + value.v[0] = ranges_offset; + } + //- rjf: .debug_loc + else if(resolve_params.version < DW_Version_5 && + (value_class == DW_AttribClass_LocListPtr || value_class == DW_AttribClass_LocList) && + (form_kind == DW_Form_SecOffset)) + { + U64 offset = form_value.v[0]; + value.section = DW_Section_Loc; + value.v[0] = offset; + } + //- rjf: invalid attribute class + else if(value_class == 0) + { + Assert(!"attribute class was not resolved"); + } + //- rjf: in all other cases, we can accept the form_value as the correct + // representation for the parsed value, so we can just copy it over. + else + { + value = form_value; + } + + return value; +} + +internal String8 +dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value) +{ + DW_SectionKind section_kind = value.section; + void *base = dw_base_from_sec(sections, section_kind); + Rng1U64 range = dw_range_from_sec(sections, section_kind); + + String8 string = {0}; + string.str = (U8 *)based_range_ptr(base, range, value.v[0]); + string.size = value.v[1] - value.v[0]; + return string; +} + +internal Rng1U64List +dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value) +{ + Rng1U64List list = {0}; + switch(ranges_value.section) + { + //- rjf: (DWARF V5 ONLY) .debug_rnglists offset + case DW_Section_RngLists: + { + list = dw_v5_range_list_from_rnglist_offset(arena, sections, ranges_value.section, address_size, addr_section_base, ranges_value.v[0]); + } break; + + //- rjf: (DWARF V4 and earlier) .debug_ranges parsing + case DW_Section_Ranges: + { + list = dw_v4_range_list_from_range_offset(arena, sections, address_size, comp_unit_base_addr, ranges_value.v[0]); + } break; + + //- rjf: fall back to trying to use low/high PCs + default: + { + rng1u64_list_push(arena, &list, rng_1u64(low_pc, high_pc)); + } break; + } + return list; +} + +//////////////////////////////// +//~ rjf: Tag Parsing + +internal DW_AttribListParseResult +dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, + DW_SectionArray *sections, + DW_Version ver, + DW_Ext ext, + DW_Language lang, + U64 address_size, + U64 info_off, + U64 abbrev_off) +{ + //- rjf: set up prereqs + DW_Mode info_mode = sections->v[DW_Section_Info].mode; + DW_Mode abbrev_mode = sections->v[DW_Section_Abbrev].mode; + void *info_base = dw_base_from_sec(sections, DW_Section_Info); + void *abbrev_base = dw_base_from_sec(sections, DW_Section_Abbrev); + Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); + Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); + + //- rjf: set up read offsets + U64 info_read_off = info_off; + U64 abbrev_read_off = abbrev_off; + + //- rjf: parse all attributes + DW_AttribListParseResult result = {0}; + for(B32 good_abbrev = 1; good_abbrev;) + { + U64 attrib_info_offset = info_read_off; + + //- rjf: parse abbrev attrib info + DW_Abbrev abbrev = {0}; + { + U64 bytes_read = dw_based_range_read_abbrev_attrib_info(abbrev_base, abbrev_range, abbrev_read_off, &abbrev); + abbrev_read_off += bytes_read; + good_abbrev = abbrev.id != 0; + } + + //- rjf: extract attrib info from abbrev + DW_AttribKind attrib_kind = (DW_AttribKind)abbrev.id; + DW_FormKind form_kind = (DW_FormKind)abbrev.sub_kind; + DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, attrib_kind, form_kind); + + //- rjf: parse the form value from the file + DW_AttribValue form_value = {0}; + if(good_abbrev) + { + // NOTE(nick): This is a special case form. Basically it let's user to + // define attribute form in the .debug_info. + if(form_kind == DW_Form_Indirect) + { + U64 override_form_kind = 0; + info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); + form_kind = (DW_FormKind)override_form_kind; + } + U64 bytes_read = dw_based_range_read_attrib_form_value(info_base, info_range, info_read_off, info_mode, address_size, + form_kind, abbrev.const_value, &form_value); + info_read_off += bytes_read; + } + + //- rjf: push this parsed attrib to the list + if(good_abbrev) + { + DW_AttribNode *node = push_array(arena, DW_AttribNode, 1); + node->attrib.info_off = attrib_info_offset; + node->attrib.abbrev_id = abbrev.id; + node->attrib.attrib_kind = attrib_kind; + node->attrib.form_kind = form_kind; + node->attrib.value_class = attrib_class; + node->attrib.form_value = form_value; + result.attribs.count += 1; + SLLQueuePush(result.attribs.first, result.attribs.last, node); + } + } + + result.max_info_off = info_read_off; + result.max_abbrev_off = abbrev_read_off; + return result; +} + +internal DW_Tag * +dw_tag_from_info_offset(Arena *arena, + DW_SectionArray *sections, + DW_AbbrevTable abbrev_table, + DW_Version ver, + DW_Ext ext, + DW_Language lang, + U64 address_size, + U64 info_offset) +{ + void *info_base = dw_base_from_sec(sections, DW_Section_Info); + Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); + void *abbrev_base = dw_base_from_sec(sections, DW_Section_Abbrev); + Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); + + DW_Tag *tag = push_array(arena, DW_Tag, 1); + + //- rjf: calculate .debug_info read cursor, relative to info range minimum + U64 info_read_off = info_offset - info_range.min; + + //- rjf: read abbrev ID + U64 abbrev_id = 0; + info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); + B32 good_abbrev_id = abbrev_id != 0; + + //- rjf: figure out abbrev offset for this ID + U64 abbrev_offset = 0; + if(good_abbrev_id) + { + abbrev_offset = dw_abbrev_offset_from_abbrev_id(abbrev_table, abbrev_id); + } + + //- rjf: calculate .debug_abbrev read cursor, relative to abbrev range minimum + U64 abbrev_read_off = abbrev_offset - abbrev_range.min; + + //- rjf: parse abbrev tag info + DW_Abbrev abbrev_tag_info = {0}; + B32 good_tag_abbrev = 0; + if(good_abbrev_id) + { + abbrev_read_off += dw_based_range_read_abbrev_tag(abbrev_base, abbrev_range, abbrev_read_off, &abbrev_tag_info); + good_tag_abbrev = 1;//abbrev_tag_info.id != 0; + } + + //- rjf: parse all attributes for this tag + U64 attribs_info_off = 0; + U64 attribs_abbrev_off = 0; + DW_AttribList attribs = {0}; + if(good_tag_abbrev) + { + DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off); + attribs_info_off = info_read_off; + attribs_abbrev_off = abbrev_read_off; + info_read_off = attribs_parse.max_info_off; + abbrev_read_off = attribs_parse.max_abbrev_off; + attribs = attribs_parse.attribs; + } + + //- rjf: fill tag + { + tag->abbrev_id = abbrev_id; + tag->info_range = rng_1u64(info_offset, info_range.min + info_read_off); + tag->abbrev_range = rng_1u64(abbrev_offset, abbrev_range.min + abbrev_read_off); + tag->has_children = !!(abbrev_tag_info.flags & DW_AbbrevFlag_HasChildren); + tag->kind = (DW_TagKind)abbrev_tag_info.sub_kind; + tag->attribs_info_off = attribs_info_off; + tag->attribs_abbrev_off = attribs_abbrev_off; + tag->attribs = attribs; + } + + return tag; +} + +//////////////////////////////// + +internal U64 +dw_v5_header_offset_from_table_offset(DW_SectionArray *sections, DW_SectionKind section, U64 table_off) +{ + // NOTE(rjf): From the DWARF V5 spec (February 13, 2017), page 401: + // + // " + // Each skeleton compilation unit also has a DW_AT_addr_base attribute, + // which provides the relocated offset to that compilation unit’s + // contribution in the executable’s .debug_addr section. Unlike the + // DW_AT_stmt_list attribute, the offset refers to the first address table + // slot, not to the section header. In this example, we see that the first + // address (slot 0) from demo1.o begins at offset 48. Because the + // .debug_addr section contains an 8-byte header, the object file’s + // contribution to the section actually begins at offset 40 (for a 64-bit + // DWARF object, the header would be 16 bytes long, and the value for the + // DW_AT_addr_base attribute would then be 56). All attributes in demo1.dwo + // that use DW_FORM_addrx, DW_FORM_addrx1, DW_FORM_addrx2, DW_FORM_addrx3 + // or DW_FORM_addrx4 would then refer to address table slots relative to + // that offset. Likewise, the .debug_addr contribution from demo2.dwo begins + // at offset 72, and its first address slot is at offset 80. Because these + // contributions have been processed by the linker, they contain relocated + // values for the addresses in the program that are referred to by the + // debug information. + // " + // + // This seems to at least partially explain why the addr_base is showing up + // 8 bytes later than we are expecting it to. We can't actually just store + // the base that we read from the DW_Attrib_AddrBase attrib, because + // it's showing up *after* the header, so we need to bump it back. + + // NOTE(rjf): From the DWARF V5 spec (February 13, 2017), page 66: + // + // " + // A DW_AT_rnglists_base attribute, whose value is of class rnglistsptr. This + // attribute points to the beginning of the offsets table (immediately + // following the header) of the compilation unit's contribution to the + // .debug_rnglists section. References to range lists (using DW_FORM_rnglistx) + // within the compilation unit are interpreted relative to this base. + // " + // + // Similarly, we need to figure out where to go to parse the header. + + U64 max_header_size = 0; + U64 min_header_size = 0; + switch(section) + { + default: + case DW_Section_Addr: + { + max_header_size = 16; + min_header_size = 8; + } break; + case DW_Section_StrOffsets: + { + max_header_size = 16; + min_header_size = 8; + } break; + case DW_Section_RngLists: + { + max_header_size = 20; + min_header_size = 12; + } break; + case DW_Section_LocLists: + { + // TODO(rjf) + NotImplemented; + } break; + } + + U64 past_header = table_off; + void *addr_base = dw_base_from_sec(sections, section); + Rng1U64 addr_rng = dw_range_from_sec(sections, section); + + //- rjf: figure out which sized header we have + U64 header_size = 0; + { + // rjf: try max header, and if it works, the header is the max size, otherwise we will + // need to rely on the min header size + U32 first32 = 0; + based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); + if(first32 == max_U32) + { + header_size = max_header_size; + } + else + { + header_size = min_header_size; + } + } + + return table_off - header_size; +} + +internal Rng1U64List +dw_comp_unit_ranges_from_info(Arena *arena, DW_Section info) +{ + Rng1U64List result = {0}; + void *base = info.data.str; + Rng1U64 range = rng_1u64(0, info.data.size); + for(U64 cursor = 0; cursor < info.data.size; ) + { + // read unit length + U64 unit_length = 0; + U64 bytes_read = dw_based_range_read_length(base, range, cursor, &unit_length); + + // was read ok? + if(bytes_read == 0) + { + break; + } + + // push unit range + rng1u64_list_push(arena, &result, rng_1u64(cursor, cursor+unit_length+bytes_read)); + + // advance + cursor += unit_length+bytes_read; + } + return result; +} + +internal DW_CompRoot +dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) +{ + Temp scratch = scratch_begin(&arena, 1); + + void *info_base = dw_base_from_sec(sections, DW_Section_Info); + B32 is_info_dwo = sections->v[DW_Section_Info].is_dwo; + + //- rjf: up-front known parsing offsets (yep, that's right, it's only 1!) + U64 size_off = 0; + + //- rjf: parse size of this compilation unit's data + U64 size = 0; + U64 version_off = size_off; + { + U64 bytes_read = dw_based_range_read_length(info_base, range, size_off, &size); + version_off += bytes_read; + } + + //- rjf: parse version + B32 got_version = 0; + DW_Version version = 0; + U64 unit_off = version_off; + if(based_range_read_struct(info_base, range, version_off, &version)) + { + unit_off += sizeof(version); + got_version = 1; + } + + //- rjf: parse unit kind, abbrev_base, address size + B32 got_unit_kind = 0; + U64 next_off = unit_off; + DW_CompUnitKind unit_kind = DW_CompUnitKind_Reserved; + U64 abbrev_base = max_U64; + U64 address_size = 0; + U64 spec_dwo_id = 0; + if(got_version) + { + switch(version) + { + default: break; + case DW_Version_2: { + abbrev_base = 0; + next_off += based_range_read(info_base, range, next_off, 4, &abbrev_base); + next_off += based_range_read(info_base, range, next_off, 1, &address_size); + got_unit_kind = 1; + } break; + case DW_Version_3: + case DW_Version_4: + { + next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); + next_off += based_range_read(info_base, range, next_off, 1, &address_size); + got_unit_kind = 1; + } break; + case DW_Version_5: + { + next_off += based_range_read_struct(info_base, range, next_off, &unit_kind); + next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); + got_unit_kind = 1; + + //- rjf: parse DWO ID if appropriate + if(unit_kind == DW_CompUnitKind_Skeleton || is_info_dwo) + { + next_off += based_range_read(info_base, range, next_off, 8, &spec_dwo_id); + } + } break; + } + } + + //- rjf: build abbrev table + DW_AbbrevTable abbrev_table = {0}; + if(got_unit_kind) + { + abbrev_table = dw_make_abbrev_table(arena, sections, abbrev_base); + } + + //- rjf: parse compilation unit's tag + B32 got_comp_unit_tag = 0; + DW_Tag *comp_unit_tag = 0; + if(got_unit_kind) + { + U64 comp_root_tag_off = range.min + next_off; + comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off); + got_comp_unit_tag = 1; + } + + //- rjf: get all of the attribute values we need to start resolving attribute values + DW_AttribValueResolveParams resolve_params = { .version = version }; + if(got_comp_unit_tag) + { + for(DW_AttribNode *attrib_n = comp_unit_tag->attribs.first; attrib_n; attrib_n = attrib_n->next) + { + DW_Attrib *attrib = &attrib_n->attrib; + + // NOTE(rjf): We'll have to rely on just the form value at this point, + // since we can't use the unit yet (since we're currently in the process + // of building it). This should always be enough, otherwise there would + // be a cyclic dependency in the requirements of each part of the + // compilation unit's parse. DWARF is pretty crazy, but not *that* crazy, + // so this should be good. + switch(attrib->attrib_kind) + { + default: break; + case DW_Attrib_AddrBase: resolve_params.debug_addrs_base = attrib->form_value.v[0]; break; + case DW_Attrib_StrOffsetsBase: resolve_params.debug_str_offs_base = attrib->form_value.v[0]; break; + case DW_Attrib_RngListsBase: resolve_params.debug_rnglists_base = attrib->form_value.v[0]; break; + case DW_Attrib_LocListsBase: resolve_params.debug_loclists_base = attrib->form_value.v[0]; break; + } + } + } + + //- rjf: correct table offsets to header offsets (since DWARF V5 insists on being as useless as possible) + if(got_comp_unit_tag && version >= DW_Version_5) + { + resolve_params.debug_addrs_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_Addr, resolve_params.debug_addrs_base); + resolve_params.debug_str_offs_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base); + resolve_params.debug_loclists_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_LocLists, resolve_params.debug_loclists_base); + resolve_params.debug_rnglists_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_RngLists, resolve_params.debug_rnglists_base); + } + + //- rjf: parse the rest of the compilation unit tag's attributes that we'd + // like to cache + String8 name = {0}; + String8 producer = {0}; + String8 compile_dir = {0}; + String8 external_dwo_name = {0}; + String8 external_gnu_dwo_name = {0}; + U64 gnu_dwo_id = 0; + U64 language = 0; + U64 name_case = 0; + B32 use_utf8 = 0; + U64 low_pc = 0; + U64 high_pc = 0; + B32 high_pc_is_relative = 0; + DW_AttribValue ranges_attrib_value = {DW_Section_Null}; + U64 line_base = 0; + if(got_comp_unit_tag) + { + for(DW_AttribNode *attrib_n = comp_unit_tag->attribs.first; attrib_n; attrib_n = attrib_n->next) + { + DW_Attrib *attrib = &attrib_n->attrib; + + //- rjf: form value => value + DW_AttribValue value = {0}; + B32 good_value = 0; + { + if(dw_are_attrib_class_and_form_kind_compatible(version, attrib->value_class, attrib->form_kind)) + { + value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + good_value = 1; + } + } + + //- rjf: map value to extracted info + if(good_value) + { + switch(attrib->attrib_kind) + { + case DW_Attrib_Name: name = dw_string_from_attrib_value(sections, value); break; + case DW_Attrib_Producer: producer = dw_string_from_attrib_value(sections, value); break; + case DW_Attrib_CompDir: compile_dir = dw_string_from_attrib_value(sections, value); break; + case DW_Attrib_DwoName: external_dwo_name = dw_string_from_attrib_value(sections, value); break; + case DW_Attrib_GNU_DwoName: external_gnu_dwo_name = dw_string_from_attrib_value(sections, value); break; + case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; + case DW_Attrib_Language: language = value.v[0]; break; + case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; + case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; + case DW_Attrib_LowPc: low_pc = value.v[0]; break; + case DW_Attrib_HighPc: high_pc = value.v[0]; high_pc_is_relative = attrib->value_class != DW_AttribClass_Address; break; + case DW_Attrib_Ranges: ranges_attrib_value = value; break; + case DW_Attrib_StmtList: line_base = value.v[0]; break; + default: break; + } + } + } + } + + //- rjf: build+fill unit + DW_CompRoot unit = {0}; + + //- rjf: fill header data + unit.size = size; + unit.kind = unit_kind; + unit.version = version; + unit.ext = DW_Ext_Null; + unit.address_size = address_size; + unit.abbrev_off = abbrev_base; + unit.info_off = range.min; + unit.tags_info_range = rng_1u64(range.min+next_off, range.max); + unit.abbrev_table = abbrev_table; + + //- rjf: fill out offsets we need for attrib value resolution + unit.rnglist_base = resolve_params.debug_rnglists_base; + unit.loclist_base = resolve_params.debug_loclists_base; + unit.addrs_base = resolve_params.debug_addrs_base; + unit.stroffs_base = resolve_params.debug_str_offs_base; + + //- rjf: fill out general info + unit.name = name; + unit.producer = producer; + unit.compile_dir = compile_dir; + unit.external_dwo_name = external_dwo_name.size != 0 ? external_dwo_name : external_gnu_dwo_name; + if(external_dwo_name.size) + { + unit.dwo_id = spec_dwo_id; + } + else if(external_gnu_dwo_name.size) + { + unit.dwo_id = gnu_dwo_id; + } + unit.language = (DW_Language)language; + unit.name_case = name_case; + unit.use_utf8 = use_utf8; + unit.line_off = line_base; + unit.low_pc = low_pc; + unit.high_pc = high_pc; + unit.ranges_attrib_value = ranges_attrib_value; + + //- rjf: fill fixup of low/high PC situation + if(high_pc_is_relative) + { + unit.high_pc += unit.low_pc; + } + + //- rjf: fill base address + { + unit.base_addr = unit.low_pc; + } + + //- rjf: build+fill directory and file tables + { + DW_Mode line_mode = dw_mode_from_sec(sections, DW_Section_Line); + void *line_base = dw_base_from_sec(sections, DW_Section_Line); + Rng1U64 line_rng = dw_range_from_sec(sections, DW_Section_Line); + DW_LineVMHeader vm_header = {0}; + U64 read_size = dw_read_line_vm_header(arena, line_base, line_rng, unit.line_off, line_mode, sections, &unit, &vm_header); + if (read_size > 0) { + unit.dir_table = vm_header.dir_table; + unit.file_table = vm_header.file_table; + } + } + + scratch_end(scratch); + return unit; +} + +internal DW_ExtDebugRef +dw_ext_debug_ref_from_comp_root(DW_CompRoot *root) +{ + DW_ExtDebugRef ref = {0}; + ref.dwo_path = root->external_dwo_name; + ref.dwo_id = root->dwo_id; + return ref; +} + +//- rjf: line info + +internal void +dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt) +{ + state->address = 0; + state->op_index = 0; + state->file_index = 1; + state->line = 1; + state->column = 0; + state->is_stmt = default_is_stmt; + state->basic_block = 0; + state->prologue_end = 0; + state->epilogue_begin = 0; + state->isa = 0; + state->discriminator = 0; +} + +internal void +dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst) +{ + U64 op_index = state->op_index + advance; + state->address += min_inst_len*(op_index/max_ops_for_inst); + state->op_index = op_index % max_ops_for_inst; +} + +internal DW_LineSeqNode * +dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl) +{ + DW_LineSeqNode *new_seq = push_array(arena, DW_LineSeqNode, 1); + SLLQueuePush(parsed_tbl->first_seq, parsed_tbl->last_seq, new_seq); + parsed_tbl->seq_count += 1; + return new_seq; +} + +internal DW_LineNode * +dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence) +{ + DW_LineNode *n = 0; + if(vm_state->busted_seq == 0) + { + DW_LineSeqNode *seq = tbl->last_seq; + if(seq == 0 || start_of_sequence) + { + // ERROR! do not emit sequences with only one line... + if (seq) Assert(seq->count > 1); + + seq = dw_push_line_seq(arena, tbl); + } + + n = push_array(arena, DW_LineNode, 1); + n->v.file_index = vm_state->file_index; + n->v.line = vm_state->line; + n->v.column = vm_state->column; + n->v.voff = vm_state->address; + + SLLQueuePush(seq->first, seq->last, n); + seq->count += 1; + } + return n; +} + +internal DW_LineTableParseResult +dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root) +{ + DW_Mode mode = sections->v[DW_Section_Line].mode; + void *base = dw_base_from_sec(sections, DW_Section_Line); + Rng1U64 line_info_range = dw_range_from_sec(sections, DW_Section_Line); + U64 read_off_start = root->line_off - line_info_range.min; + U64 cursor = read_off_start; + + DW_LineVMHeader vm_header = {0}; + cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, root, &vm_header); + + //- rjf: prep state for VM + DW_LineVMState vm_state = {0}; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + + //- rjf: VM loop; build output list + DW_LineTableParseResult result = {0}; + B32 end_of_seq = 0; + B32 error = 0; + for (;!error && cursor < vm_header.unit_opl;) { + //- rjf: parse opcode + U8 opcode = 0; + cursor += based_range_read_struct(base, line_info_range, cursor, &opcode); + + //- rjf: do opcode action + switch (opcode) { + default: + { + //- rjf: special opcode case + if(opcode >= vm_header.opcode_base) + { + U32 adjusted_opcode = (U32)(opcode - vm_header.opcode_base); + U32 op_advance = adjusted_opcode / vm_header.line_range; + S32 line_inc = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; + // TODO: can we just call dw_advance_line_vm_state_pc + U64 addr_inc = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); + + vm_state.address += addr_inc; + vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; + vm_state.line = (U32)((S32)vm_state.line + line_inc); + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + vm_state.discriminator = 0; + + dw_push_line(arena, &result, &vm_state, end_of_seq); + end_of_seq = 0; + +#if 0 + // NOTE(rjf): DWARF has dummy lines at the end of groups of line ranges, where we'd like + // to break line info into sequences. + if(vm_state.line == 0) + { + end_of_seq = 1; + } +#endif + } + // Skipping unknown opcode. This is a valid case and + // it works because compiler stores operand lengths. + else + { + if(opcode > 0 && opcode <= vm_header.num_opcode_lens) + { + U8 num_operands = vm_header.opcode_lens[opcode - 1]; + for(U8 i = 0; i < num_operands; ++i) + { + U64 operand = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &operand); + } + } + else + { + error = 1; + goto exit; + } + } + } break; + + //- Standard opcodes + + case DW_StdOpcode_Copy: + { + dw_push_line(arena, &result, &vm_state, end_of_seq); + end_of_seq = 0; + vm_state.discriminator = 0; + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + } break; + + case DW_StdOpcode_AdvancePc: + { + U64 advance = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &advance); + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + } break; + + case DW_StdOpcode_AdvanceLine: + { + S64 s = 0; + cursor += based_range_read_sleb128(base, line_info_range, cursor, &s); + vm_state.line += s; + } break; + + case DW_StdOpcode_SetFile: + { + U64 file_index = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_index); + vm_state.file_index = file_index; + } break; + + case DW_StdOpcode_SetColumn: + { + U64 column = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &column); + vm_state.column = column; + } break; + + case DW_StdOpcode_NegateStmt: + { + vm_state.is_stmt = !vm_state.is_stmt; + } break; + + case DW_StdOpcode_SetBasicBlock: + { + vm_state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: + { + U64 advance = (0xffu - vm_header.opcode_base)/vm_header.line_range; + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + } break; + + case DW_StdOpcode_FixedAdvancePc: + { + U16 operand = 0; + cursor += based_range_read_struct(base, line_info_range, cursor, &operand); + vm_state.address += operand; + vm_state.op_index = 0; + } break; + + case DW_StdOpcode_SetPrologueEnd: + { + vm_state.prologue_end = 1; + } break; + + case DW_StdOpcode_SetEpilogueBegin: + { + vm_state.epilogue_begin = 1; + } break; + + case DW_StdOpcode_SetIsa: + { + U64 v = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + vm_state.isa = v; + } break; + + //- Extended opcodes + case DW_StdOpcode_ExtendedOpcode: + { + U64 length = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &length); + U64 start_off = cursor; + U8 extended_opcode = 0; + cursor += based_range_read_struct(base, line_info_range, cursor, &extended_opcode); + + switch (extended_opcode) { + case DW_ExtOpcode_EndSequence: + { + vm_state.end_sequence = 1; + dw_push_line(arena, &result, &vm_state, 0); + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + end_of_seq = 1; + } break; + + case DW_ExtOpcode_SetAddress: + { + U64 address = 0; + cursor += based_range_read(base, line_info_range, cursor, root->address_size, &address); + vm_state.address = address; + vm_state.op_index = 0; + vm_state.busted_seq = address != 0; // !(dbg->acceptable_vrange.min <= address && address < dbg->acceptable_vrange.max); + } break; + + case DW_ExtOpcode_DefineFile: + { + String8 file_name = based_range_read_string(base, line_info_range, cursor); + U64 dir_index = 0; + U64 modify_time = 0; + U64 file_size = 0; + cursor += file_name.size + 1; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &dir_index); + cursor += based_range_read_uleb128(base, line_info_range, cursor, &modify_time); + cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_size); + + // TODO(rjf): Not fully implemented. By the DWARF V4 spec, the above is + // all that needs to be parsed, but the rest of the work that needs to + // happen here---allowing this file to be used by further opcodes---is + // not implemented. + // + // See the DWARF V4 spec (June 10, 2010), page 122. + error = 1; + AssertAlways(!"UNHANDLED DEFINE FILE!!!"); + } break; + + case DW_ExtOpcode_SetDiscriminator: + { + U64 v = 0; + cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + vm_state.discriminator = v; + } break; + + default: break; + } + + U64 num_skip = cursor - (start_off + length); + cursor += num_skip; + if (based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { + error = 1; + } + + } break; + } + } + exit:; + + return result; +} + +internal U64 +dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out) +{ + MemoryZeroStruct(line_file_out); + + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(unit); + U64 line_off_start = line_off; + for (U64 format_idx = 0; format_idx < format_count; ++format_idx) + { + DW_LNCT lnct = (DW_LNCT)formats[format_idx].min; + DW_FormKind form_kind = (DW_FormKind)formats[format_idx].max; + DW_AttribValue form_value = {0}; + line_off += dw_based_range_read_attrib_form_value(line_base, line_rng, line_off, mode, address_size, form_kind, 0, &form_value); + switch (lnct) + { + case DW_LNCT_Path: + { + Assert(form_kind == DW_Form_String || form_kind == DW_Form_LineStrp || + form_kind == DW_Form_Strp || form_kind == DW_Form_StrpSup || + form_kind == DW_Form_Strx || form_kind == DW_Form_Strx1 || + form_kind == DW_Form_Strx2 || form_kind == DW_Form_Strx3 || + form_kind == DW_Form_Strx4); + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_String, form_value); + line_file_out->file_name = dw_string_from_attrib_value(sections, attrib_value); + } break; + + case DW_LNCT_DirectoryIndex: + { + Assert(form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || + form_kind == DW_Form_UData); + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); + line_file_out->dir_idx = attrib_value.v[0]; + } break; + + case DW_LNCT_TimeStamp: + { + Assert(form_kind == DW_Form_UData || form_kind == DW_Form_Data4 || + form_kind == DW_Form_Data8 || form_kind == DW_Form_Block); + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Const, form_value); + line_file_out->modify_time = attrib_value.v[0]; + } break; + + case DW_LNCT_Size: + { + Assert(form_kind == DW_Form_UData || form_kind == DW_Form_Data1 || + form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || + form_kind == DW_Form_Data8); + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); + line_file_out->file_size = attrib_value.v[0]; + } break; + + case DW_LNCT_MD5: + { + Assert(form_kind == DW_Form_Data16); + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); + line_file_out->md5_digest[0] = attrib_value.v[0]; + line_file_out->md5_digest[1] = attrib_value.v[1]; + } break; + + default: + { + Assert(DW_LNCT_UserLo < lnct && lnct < DW_LNCT_UserHi); + } break; + } + } + U64 result = line_off - line_off_start; + return result; +} + +internal U64 +dw_read_line_vm_header(Arena *arena, + void *line_base, + Rng1U64 line_rng, + U64 line_off, + DW_Mode mode, + DW_SectionArray *sections, + DW_CompRoot *unit, + DW_LineVMHeader *header_out) +{ + U64 line_off_start = line_off; + + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: parse unit length + header_out->unit_length = 0; + { + line_off += dw_based_range_read_length(line_base, line_rng, line_off, &header_out->unit_length); + } + + header_out->unit_opl = line_off + header_out->unit_length; + + //- rjf: parse version and header length + line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->version); + + if (header_out->version == DW_Version_5) { + line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->address_size); + line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->segment_selector_size); + } + + { + U64 off_size = dw_offset_size_from_mode(mode); + line_off += based_range_read(line_base, line_rng, line_off, off_size, &header_out->header_length); + } + + //- rjf: calculate program offset + header_out->program_off = line_off + header_out->header_length; + + //- rjf: parse minimum instruction length + { + line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->min_inst_len); + } + + //- rjf: parse max ops for instruction + switch (header_out->version) + { + case DW_Version_5: + case DW_Version_4: + { + line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->max_ops_for_inst); + Assert(header_out->max_ops_for_inst > 0); + } break; + case DW_Version_3: + case DW_Version_2: + case DW_Version_1: + { + header_out->max_ops_for_inst = 1; + } break; + default: break; + } + + //- rjf: parse rest of program info + based_range_read_struct(line_base, line_rng, line_off + 0 * sizeof(U8), &header_out->default_is_stmt); + based_range_read_struct(line_base, line_rng, line_off + 1 * sizeof(U8), &header_out->line_base); + based_range_read_struct(line_base, line_rng, line_off + 2 * sizeof(U8), &header_out->line_range); + based_range_read_struct(line_base, line_rng, line_off + 3 * sizeof(U8), &header_out->opcode_base); + line_off += 4 * sizeof(U8); + Assert(header_out->opcode_base != 0 && header_out->opcode_base > 0); + + //- rjf: calculate opcode length array + header_out->num_opcode_lens = header_out->opcode_base - 1u; + header_out->opcode_lens = (U8 *)based_range_ptr(line_base, line_rng, line_off); + line_off += header_out->num_opcode_lens * sizeof(U8); + + if (header_out->version == DW_Version_5) { + //- parse directory names + U8 directory_entry_format_count = 0; + line_off += based_range_read_struct(line_base, line_rng, line_off, &directory_entry_format_count); + Assert(directory_entry_format_count == 1); + Rng1U64 *directory_entry_formats = push_array(scratch.arena, Rng1U64, directory_entry_format_count); + for (U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) + { + U64 content_type_code = 0, form_code = 0; + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + directory_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); + } + U64 directories_count = 0; + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &directories_count); + header_out->dir_table.count = directories_count; + header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); + for (U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) + { + DW_LineFile line_file; + line_off += dw_read_line_file(line_base, + line_rng, + line_off, + mode, + sections, + unit, + header_out->address_size, + directory_entry_format_count, + directory_entry_formats, + &line_file); + header_out->dir_table.v[dir_idx] = push_str8_copy(arena, line_file.file_name); + } + //- parse file table + U8 file_name_entry_format_count = 0; + line_off += based_range_read_struct(line_base, line_rng, line_off, &file_name_entry_format_count); + Rng1U64 *file_name_entry_formats = push_array(scratch.arena, Rng1U64, file_name_entry_format_count); + for (U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) + { + U64 content_type_code = 0, form_code = 0; + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + file_name_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); + } + U64 file_names_count = 0; + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_names_count); + header_out->file_table.count = file_names_count; + header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + for (U64 file_idx = 0; file_idx < file_names_count; ++file_idx) + { + line_off += dw_read_line_file(line_base, + line_rng, + line_off, + mode, + sections, + unit, + header_out->address_size, + file_name_entry_format_count, + file_name_entry_formats, + &header_out->file_table.v[file_idx]); + } + } + else + { + String8List dir_list = {0}; + + str8_list_push(scratch.arena, &dir_list, unit->compile_dir); + for (;;) + { + String8 dir = based_range_read_string(line_base, line_rng, line_off); + line_off += dir.size + 1; + if (dir.size == 0) + { + break; + } + str8_list_push(scratch.arena, &dir_list, dir); + } + + DW_LineVMFileList file_list = {0}; + + //- rjf: push 0-index file (compile file) + { + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = unit->name; + SLLQueuePush(file_list.first, file_list.last, node); + file_list.node_count += 1; + } + + for (;;) + { + String8 file_name = based_range_read_string(line_base, line_rng, line_off); + U64 dir_index = 0; + U64 modify_time = 0; + U64 file_size = 0; + line_off += file_name.size + 1; + if (file_name.size == 0) + { + break; + } + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &dir_index); + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &modify_time); + line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_size); + + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = file_name; + node->file.dir_idx = dir_index; + node->file.modify_time = modify_time; + node->file.file_size = file_size; + SLLQueuePush(file_list.first, file_list.last, node); + file_list.node_count += 1; + } + + //- rjf: build dir table + { + header_out->dir_table.count = dir_list.node_count; + header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); + String8Node *n = dir_list.first; + for(U64 idx = 0; n != 0 && idx < header_out->dir_table.count; idx += 1, n = n->next) + { + header_out->dir_table.v[idx] = push_str8_copy(arena, n->string); + } + } + + //- rjf: build file table + { + header_out->file_table.count = file_list.node_count; + header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + U64 file_idx = 0; + DW_LineVMFileNode *file_node = file_list.first; + for(; file_node != 0; file_idx += 1, file_node = file_node->next) + { + header_out->file_table.v[file_idx].file_name = push_str8_copy(arena, file_node->file.file_name); + header_out->file_table.v[file_idx].dir_idx = file_node->file.dir_idx; + header_out->file_table.v[file_idx].modify_time = file_node->file.modify_time; + header_out->file_table.v[file_idx].file_size = file_node->file.file_size; + } + } + } + + U64 result = line_off - line_off_start; + + scratch_end(scratch); + return result; +} + diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h new file mode 100644 index 00000000..f7b8b1b2 --- /dev/null +++ b/src/dwarf/dwarf_parse.h @@ -0,0 +1,491 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_PARSE_H +#define DWARF_PARSE_H + +// NOTE(rjf): Some rules about the spaces of offsets and ranges: +// +// - Every stored/passed offset is relative to the base of its section. +// - Every stored/passed range has endpoints relative to the base of their section. +// - Upon calling a syms_based_range_* function, these offsets need to be +// converted into range-relative. + +//////////////////////////////// +//~ rjf: Constants + +#define DWARF_VOID_TYPE_ID 0xffffffffffffffffull + +//////////////////////////////// +//~ rjf: Files + External Debug References + +typedef struct DW_ExtDebugRef DW_ExtDebugRef; +struct DW_ExtDebugRef +{ + // NOTE(rjf): .dwo => an external DWARF V5 .dwo file + String8 dwo_path; + U64 dwo_id; +}; + +//////////////////////////////// +//~ rjf: Abbrev Table + +typedef struct DW_AbbrevTableEntry DW_AbbrevTableEntry; +struct DW_AbbrevTableEntry +{ + U64 id; + U64 off; +}; + +typedef struct DW_AbbrevTable DW_AbbrevTable; +struct DW_AbbrevTable +{ + U64 count; + DW_AbbrevTableEntry *entries; +}; + +//////////////////////////////// +//~ Sections + +typedef struct DW_Section DW_Section; +struct DW_Section +{ + String8 data; + DW_Mode mode; + B32 is_dwo; +}; + +typedef struct DW_SectionArray DW_SectionArray; +struct DW_SectionArray +{ + DW_Section v[DW_Section_Count]; +}; + +//////////////////////////////// +//~ rjf: Basic Line Info + +typedef struct DW_LineFile DW_LineFile; +struct DW_LineFile +{ + String8 file_name; + U64 dir_idx; + U64 modify_time; + U64 md5_digest[2]; + U64 file_size; +}; + +typedef struct DW_LineVMFileNode DW_LineVMFileNode; +struct DW_LineVMFileNode +{ + DW_LineVMFileNode *next; + DW_LineFile file; +}; + +typedef struct DW_LineVMFileList DW_LineVMFileList; +struct DW_LineVMFileList +{ + U64 node_count; + DW_LineVMFileNode *first; + DW_LineVMFileNode *last; +}; + +typedef struct DW_LineVMFileArray DW_LineVMFileArray; +struct DW_LineVMFileArray +{ + U64 count; + DW_LineFile *v; +}; + +//////////////////////////////// +//~ rjf: Abbrevs + +typedef enum DW_AbbrevKind +{ + DW_Abbrev_Null, + DW_Abbrev_Tag, + DW_Abbrev_Attrib, + DW_Abbrev_AttribSequenceEnd, + DW_Abbrev_DIEBegin, + DW_Abbrev_DIEEnd, +} +DW_AbbrevKind; + +typedef U32 DW_AbbrevFlags; +enum{ + DW_AbbrevFlag_HasImplicitConst = (1<<0), + DW_AbbrevFlag_HasChildren = (1<<1), +}; + +typedef struct DW_Abbrev DW_Abbrev; +struct DW_Abbrev +{ + DW_AbbrevKind kind; + Rng1U64 abbrev_range; + U64 sub_kind; + U64 id; + U64 const_value; + DW_AbbrevFlags flags; +}; + +//////////////////////////////// +//~ rjf: Attribs + +typedef struct DW_AttribValueResolveParams DW_AttribValueResolveParams; +struct DW_AttribValueResolveParams +{ + DW_Version version; + DW_Language language; + U64 addr_size; // NOTE(rjf): size in bytes of containing compilation unit's addresses + U64 containing_unit_info_off; // NOTE(rjf): containing compilation unit's offset into the .debug_info section + U64 debug_addrs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_addrs section (DWARF V5 ONLY) + U64 debug_rnglists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_rnglists section (DWARF V5 ONLY) + U64 debug_str_offs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_str_offsets section (DWARF V5 ONLY) + U64 debug_loclists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_loclists section (DWARF V5 ONLY) +}; + +typedef struct DW_AttribValue DW_AttribValue; +struct DW_AttribValue +{ + DW_SectionKind section; + U64 v[2]; +}; + +typedef struct DW_Attrib DW_Attrib; +struct DW_Attrib +{ + U64 info_off; + U64 abbrev_id; + DW_AttribKind attrib_kind; + DW_FormKind form_kind; + DW_AttribClass value_class; + DW_AttribValue form_value; +}; + +typedef struct DW_AttribArray DW_AttribArray; +struct DW_AttribArray +{ + DW_Attrib *v; + U64 count; +}; + +typedef struct DW_AttribNode DW_AttribNode; +struct DW_AttribNode +{ + DW_AttribNode *next; + DW_Attrib attrib; +}; + +typedef struct DW_AttribList DW_AttribList; +struct DW_AttribList +{ + DW_AttribNode *first; + DW_AttribNode *last; + U64 count; +}; + +typedef struct DW_AttribListParseResult DW_AttribListParseResult; +struct DW_AttribListParseResult +{ + DW_AttribList attribs; + U64 max_info_off; + U64 max_abbrev_off; +}; + +//////////////////////////////// +//~ rjf: Compilation Units + Accelerators + +typedef struct DW_CompRoot DW_CompRoot; +struct DW_CompRoot +{ + // NOTE(rjf): Header Data + U64 size; + DW_CompUnitKind kind; + DW_Version version; + DW_Ext ext; + U64 address_size; + U64 abbrev_off; + U64 info_off; + Rng1U64 tags_info_range; + DW_AbbrevTable abbrev_table; + + // NOTE(rjf): [parsed from DWARF attributes] Offsets For More Info (DWARF V5 ONLY) + U64 rnglist_base; // NOTE(rjf): Offset into the .debug_rnglists section where this comp unit's data is. + U64 loclist_base; // NOTE(rjf): Offset into the .debug_loclists section where this comp unit's data is. + U64 addrs_base; // NOTE(rjf): Offset into the .debug_addr section where this comp unit's data is. + U64 stroffs_base; // NOTE(rjf): Offset into the .debug_str_offsets section where this comp unit's data is. + + // NOTE(rjf): [parsed from DWARF attributes] General Info + String8 name; + String8 producer; + String8 compile_dir; + String8 external_dwo_name; + U64 dwo_id; + DW_Language language; + U64 name_case; + B32 use_utf8; + U64 line_off; + U64 low_pc; + U64 high_pc; + DW_AttribValue ranges_attrib_value; + U64 base_addr; + + // NOTE(rjf): Line/File Info For This Comp Unit + String8Array dir_table; + DW_LineVMFileArray file_table; +}; + +//////////////////////////////// +//~ rjf: Tags + +typedef struct DW_Tag DW_Tag; +struct DW_Tag +{ + DW_Tag *next_sibling; + DW_Tag *first_child; + DW_Tag *last_child; + DW_Tag *parent; + Rng1U64 info_range; + Rng1U64 abbrev_range; + B32 has_children; + U64 abbrev_id; + DW_TagKind kind; + U64 attribs_info_off; + U64 attribs_abbrev_off; + DW_AttribList attribs; +}; + +typedef U32 DW_TagStubFlags; +enum +{ + DW_TagStubFlag_HasObjectPointerArg = (1<<0), + DW_TagStubFlag_HasLocation = (1<<1), + DW_TagStubFlag_HasExternal = (1<<2), + DW_TagStubFlag_HasSpecification = (1<<3), +}; + +typedef struct DW_TagStub DW_TagStub; +struct DW_TagStub +{ + U64 info_off; + DW_TagKind kind; + DW_TagStubFlags flags; + U64 children_info_off; + U64 attribs_info_off; + U64 attribs_abbrev_off; + + // NOTE(rjf): DW_Attrib_Specification is tacked onto definitions that + // are filling out more info about a "prototype". That attribute is a reference + // that points back at the declaration tag. The declaration tag has the + // DW_Attrib_Declaration attribute, which is sort of like the reverse + // of that, except there's no reference. So what we're doing here is just storing + // a reference on both, that point back to each other, so it's always easy to + // get from decl => spec, or from spec => decl. + //SYMS_SymbolID ref; + + // NOTE(rjf): DW_Attrib_AbstractOrigin is tacked onto some definitions + // that are used to specify information more specific to inlining, while wanting + // to refer to an "abstract" function DIE, that is not specific to any inline + // sites. The DWARF generator will not duplicate information across these, so + // we will occasionally need to look at an abstract origin to get abstract + // information, like name/linkage-name/etc. + //SYMS_SymbolID abstract_origin; + + U64 _unused_; +}; + +typedef struct DW_TagStubNode DW_TagStubNode; +struct DW_TagStubNode +{ + DW_TagStubNode *next; + DW_TagStub stub; +}; + +typedef struct DW_TagStubList DW_TagStubList; +struct DW_TagStubList +{ + DW_TagStubNode *first; + DW_TagStubNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Line Info VM Types + +typedef struct DW_LineVMHeader DW_LineVMHeader; +struct DW_LineVMHeader +{ + U64 unit_length; + U64 unit_opl; + U16 version; + U8 address_size; // NOTE(nick): duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. + U8 segment_selector_size; + U64 header_length; + U64 program_off; + U8 min_inst_len; + U8 max_ops_for_inst; + U8 default_is_stmt; + S8 line_base; + U8 line_range; + U8 opcode_base; + U64 num_opcode_lens; + U8 *opcode_lens; + String8Array dir_table; + DW_LineVMFileArray file_table; +}; + +typedef struct DW_LineVMState DW_LineVMState; +struct DW_LineVMState +{ + U64 address; // NOTE(nick): Address of a machine instruction. + U32 op_index; // NOTE(nick): This is used by the VLIW instructions to indicate index of operation inside the instruction. + + // NOTE(nick): Line table doesn't contain full path to a file, instead + // DWARF encodes path as two indices. First index will point into a directory + // table, and second points into a file name table. + U32 file_index; + + U32 line; + U32 column; + + B32 is_stmt; // NOTE(nick): Indicates that "address" points to place suitable for a breakpoint. + B32 basic_block; // NOTE(nick): Indicates that the "address" is inside a basic block. + + // NOTE(nick): Indicates that "address" points to place where function starts. + // Usually prologue is the place where compiler emits instructions to + // prepare stack for a function. + B32 prologue_end; + + B32 epilogue_begin; // NOTE(nick): Indicates that "address" points to section where function exits and unwinds stack. + U64 isa; // NOTE(nick): Instruction set that is used. + U64 discriminator; // NOTE(nick): Arbitrary id that indicates to which block these instructions belong. + B32 end_sequence; // NOTE(nick): Indicates that "address" points to the first instruction in the instruction block that follows. + + // NOTE(rjf): it looks like LTO might sometimes zero out high PC and low PCs, causing a + // swath of line info to map to a range starting at 0. This causes overlapping ranges + // which we do not want to report. So this B32 will turn on emission. + B32 busted_seq; +}; + +typedef struct DW_Line DW_Line; +struct DW_Line +{ + U64 file_index; + U32 line; + U32 column; + U64 voff; +}; + +typedef struct DW_LineNode DW_LineNode; +struct DW_LineNode +{ + DW_LineNode *next; + DW_Line v; +}; + +typedef struct DW_LineSeqNode DW_LineSeqNode; +struct DW_LineSeqNode +{ + DW_LineSeqNode *next; + U64 count; + DW_LineNode *first; + DW_LineNode *last; +}; + +typedef struct DW_LineTableParseResult DW_LineTableParseResult; +struct DW_LineTableParseResult +{ + U64 seq_count; + DW_LineSeqNode *first_seq; + DW_LineSeqNode *last_seq; +}; + +//////////////////////////////// +//~ rjf: .debug_pubnames and .debug_pubtypes + +typedef struct DW_PubStringsBucket DW_PubStringsBucket; +struct DW_PubStringsBucket +{ + DW_PubStringsBucket *next; + String8 string; + U64 info_off; + U64 cu_info_off; +}; + +typedef struct DW_PubStringsTable DW_PubStringsTable; +struct DW_PubStringsTable +{ + U64 size; + DW_PubStringsBucket **buckets; +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 dw_hash_from_string(String8 string); +internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib, DW_FormKind form_kind); + +//////////////////////////////// +//~ Specific Based Range Helpers + +internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); +internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); + +internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind); +internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind); +internal void* dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind); +internal Rng1U64 dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind); + +//////////////////////////////// +//~ rjf: Abbrev Table + +internal DW_AbbrevTable dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 start_abbrev_off); +internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id); + +//////////////////////////////// +//~ rjf: Miscellaneous DWARF Section Parsing + +//- rjf: .debug_ranges (DWARF V4) +internal Rng1U64List dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off); + +//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4) +internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind); + +//- rjf: .debug_str_offsets (DWARF V5) +internal U64 dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index); + +//- rjf: .debug_addr (DWARF V5) +internal U64 dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index); + +//- rjf: .debug_rnglists parsing (DWARF V5) +internal U64 dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index); +internal Rng1U64List dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset); + +//////////////////////////////// +//~ rjf: Attrib Value Parsing + +internal DW_AttribValueResolveParams dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root); +internal DW_AttribValue dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_FormKind form_kind, DW_AttribClass value_class, DW_AttribValue form_value); +internal String8 dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value); +internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value); + +//////////////////////////////// +//~ rjf: Tag Parsing + +internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off); +internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset); +internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag); + +//- rjf: line info +internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt); +internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst); + +internal DW_LineSeqNode* dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); +internal DW_LineNode* dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); +internal DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root); +internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); +internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, DW_LineVMHeader *header_out); + +#endif // DWARF_PARSE_H + diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c new file mode 100644 index 00000000..bf86d59f --- /dev/null +++ b/src/dwarf/dwarf_unwind.c @@ -0,0 +1,1157 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// x64 Unwind Function + +internal DW_UnwindResult +dw_unwind_x64(String8 raw_text, + String8 raw_eh_frame, + String8 raw_eh_frame_hdr, + Rng1U64 text_vrange, + Rng1U64 eh_frame_vrange, + Rng1U64 eh_frame_hdr_vrange, + U64 default_image_base, + U64 image_base, + U64 stack_pointer, + DW_RegsX64 *regs, + DW_ReadMemorySig *read_memory, + void *read_memory_ud) +{ + // TODO: What if ELF has two sections with instructions and pointer is ecnoded relative to .text2? + Temp scratch = scratch_begin(0, 0); + + DW_UnwindResult result = {0}; + + dw_unwind_init_x64(); + + // rebase + U64 rebase_voff_to_vaddr = (image_base - default_image_base); + + // get ip register values + U64 ip_value = regs->rip; + U64 ip_voff = ip_value - rebase_voff_to_vaddr; + + // check sections + B32 has_needed_sections = (raw_text.size > 0 && raw_eh_frame.size > 0); + if (!has_needed_sections) { + result.is_invalid = 1; + } + + //- get frame info range + void *frame_base = raw_eh_frame.str; + Rng1U64 frame_range = rng_1u64(0, raw_eh_frame.size); + + //- section vaddrs + U64 text_base_vaddr = text_vrange.min + rebase_voff_to_vaddr; + U64 frame_base_voff = text_vrange.min; + U64 data_base_vaddr = eh_frame_hdr_vrange.min + rebase_voff_to_vaddr; + + //- find cfi records + DW_CFIRecords cfi_recs = {0}; + if (has_needed_sections) { + DW_EhPtrCtx ptr_ctx = {0}; + ptr_ctx.raw_base_vaddr = frame_base_voff; + ptr_ctx.text_vaddr = text_base_vaddr; + ptr_ctx.data_vaddr = data_base_vaddr; + ptr_ctx.func_vaddr = 0; + if (raw_eh_frame_hdr.size) { + cfi_recs = dw_unwind_eh_frame_hdr_from_ip_fast_x64(raw_eh_frame, raw_eh_frame_hdr, &ptr_ctx, ip_voff); + } else { + cfi_recs = dw_unwind_eh_frame_cfi_from_ip_slow_x64(raw_eh_frame, &ptr_ctx, ip_voff); + } + } + + //- check cfi records + if (!cfi_recs.valid) { + result.is_invalid = 1; + } + + //- cfi machine setup + DW_CFIMachine machine = {0}; + if (cfi_recs.valid) { + DW_EhPtrCtx ptr_ctx = {0}; + ptr_ctx.raw_base_vaddr = frame_base_voff; + ptr_ctx.text_vaddr = text_base_vaddr; + ptr_ctx.data_vaddr = data_base_vaddr; + ptr_ctx.func_vaddr = cfi_recs.fde.ip_voff_range.min + rebase_voff_to_vaddr; // TODO: it's not super clear how to set up this member, need more test cases + machine = dw_unwind_make_machine_x64(DW_UNWIND_X64__REG_SLOT_COUNT, &cfi_recs.cie, &ptr_ctx); + } + + // initial row + DW_CFIRow *init_row = 0; + if (cfi_recs.valid) { + Rng1U64 init_cfi_range = cfi_recs.cie.cfi_range; + DW_CFIRow *row = dw_unwind_row_alloc_x64(scratch.arena, machine.cells_per_row); + if (dw_unwind_machine_run_to_ip_x64(frame_base, init_cfi_range, &machine, max_U64, row)) { + init_row = row; + } + if (init_row == 0) { + result.is_invalid = 1; + } + } + + // main row + DW_CFIRow *main_row = 0; + if (init_row != 0) { + // upgrade machine with new equipment + dw_unwind_machine_equip_initial_row_x64(&machine, init_row); + dw_unwind_machine_equip_fde_ip_x64(&machine, cfi_recs.fde.ip_voff_range.min); + + // decode main row + Rng1U64 main_cfi_range = cfi_recs.fde.cfi_range; + DW_CFIRow *row = dw_unwind_row_alloc_x64(scratch.arena, machine.cells_per_row); + if (dw_unwind_machine_run_to_ip_x64(frame_base, main_cfi_range, &machine, ip_value, row)) { + main_row = row; + } + if (main_row == 0) { + result.is_invalid = 1; + } + } + + // apply main row to modify the registers + if (main_row != 0) { + result = dw_unwind_x64__apply_frame_rules(raw_eh_frame, main_row, text_base_vaddr, read_memory, read_memory_ud, stack_pointer, regs); + } + + scratch_end(scratch); + return result; +} + +internal DW_UnwindResult +dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, + DW_CFIRow *row, + U64 text_base_vaddr, + DW_ReadMemorySig *read_memory, + void *read_memory_ud, + U64 stack_pointer, + DW_RegsX64 *regs) +{ + DW_UnwindResult result = {0}; + + U64 missed_read_addr = 0; + + //- setup a dwarf expression machine + DW_ExprMachineConfig dwexpr_config = {0}; + dwexpr_config.max_step_count = 0xFFFF; + dwexpr_config.read_memory = read_memory; + dwexpr_config.read_memory_ud = read_memory_ud; + dwexpr_config.regs = regs; + dwexpr_config.text_section_base = &text_base_vaddr; + + //- compute cfa + U64 cfa = 0; + switch (row->cfa_cell.rule) { + case DW_CFI_CFA_Rule_RegOff: { + // TODO: have we done anything to gaurantee reg_idx here? + U64 reg_idx = row->cfa_cell.reg_idx; + + // is this a roll-over CFA? + B32 is_roll_over_cfa = 0; + if (reg_idx == DW_Reg_x64_Rsp) { + DW_CFIRegisterRule rule = row->cells[reg_idx].rule; + if (rule == DW_CFIRegisterRule_Undefined || rule == DW_CFIRegisterRule_SameValue) { + is_roll_over_cfa = 1; + } + } + + // compute cfa + if (is_roll_over_cfa) { + cfa = stack_pointer + row->cfa_cell.offset; + } else { + cfa = regs->r[reg_idx] + row->cfa_cell.offset; + } + } break; + + case DW_CFI_CFA_Rule_Expr: { + Rng1U64 expr_range = row->cfa_cell.expr; + DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); + if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { + missed_read_addr = location.non_piece_loc.fail_data; + goto error_out; + } + if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { + cfa = location.non_piece_loc.addr; + } + } break; + } + + // compute registers + { + DW_CFICell *cell = row->cells; + DW_RegsX64 new_regs = {0}; + for (U64 i = 0; i < DW_UNWIND_X64__REG_SLOT_COUNT; ++i, ++cell) { + // compute value + U64 v = 0; + switch (cell->rule) { + default: + { + Assert(!"UNEXPECTED-RULE"); + } break; + + case DW_CFIRegisterRule_Undefined: + { + Assert(!"UNDEFINED"); + } break; + + case DW_CFIRegisterRule_SameValue: + { + v = regs->r[i]; + } break; + + case DW_CFIRegisterRule_Offset: + { + U64 addr = cfa + cell->n; + U64 read_size = read_memory(addr, sizeof(v), &v, read_memory_ud); + if (read_size != sizeof(v)) { + missed_read_addr = addr; + goto error_out; + } + } break; + + case DW_CFIRegisterRule_ValOffset: + { + v = cfa + cell->n; + } break; + + case DW_CFIRegisterRule_Register: + { + v = regs->r[i]; + } break; + + case DW_CFIRegisterRule_Expression: + { + Rng1U64 expr_range = cell->expr; + U64 addr = 0; + DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); + if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { + missed_read_addr = location.non_piece_loc.fail_data; + goto error_out; + } + if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { + addr = location.non_piece_loc.addr; + } + U64 read_size = read_memory(addr, sizeof(v), &v, read_memory_ud); + if (read_size != sizeof(v)) { + missed_read_addr = addr; + goto error_out; + } + } break; + + case DW_CFIRegisterRule_ValExpression: + { + Rng1U64 expr_range = cell->expr; + DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); + if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { + missed_read_addr = location.non_piece_loc.fail_data; + goto error_out; + } + if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { + v = location.non_piece_loc.addr; + } + } break; + } + + // commit value to output slot + new_regs.r[i] = v; + } + + // commit all new regs + MemoryCopy(regs, &new_regs, sizeof(new_regs)); + } + + //- save new stack pointer + result.stack_pointer = cfa; + + error_out:; + if (missed_read_addr) { + result.is_invalid = 1; + result.missed_read = 1; + result.missed_read_addr = missed_read_addr; + } + + return result; +} + +//////////////////////////////// +// Helper Functions + +internal void +dw_unwind_init_x64(void) +{ + local_persist B32 did_init = 0; + + if (!did_init) { + did_init = 1; + + // control bits tables + dw_unwind__cfa_control_bits_kind1[DW_CFA_Nop ] = 0x000; + dw_unwind__cfa_control_bits_kind1[DW_CFA_SetLoc ] = 0x809; + dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc1 ] = 0x801; + dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc2 ] = 0x802; + dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc4 ] = 0x804; + dw_unwind__cfa_control_bits_kind1[DW_CFA_OffsetExt ] = 0x2AA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_RestoreExt ] = 0x20A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_Undefined ] = 0x20A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_SameValue ] = 0x20A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_Register ] = 0x6AA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_RememberState ] = 0x000; + dw_unwind__cfa_control_bits_kind1[DW_CFA_RestoreState ] = 0x000; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfa ] = 0x2AA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaRegister ] = 0x20A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaOffset ] = 0x00A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaExpr ] = 0x00A; + dw_unwind__cfa_control_bits_kind1[DW_CFA_Expr ] = 0x2AA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_OffsetExtSf ] = 0x2BA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaSf ] = 0x2BA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaOffsetSf ] = 0x00B; + dw_unwind__cfa_control_bits_kind1[DW_CFA_ValOffset ] = 0x2AA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_ValOffsetSf ] = 0x2BA; + dw_unwind__cfa_control_bits_kind1[DW_CFA_ValExpr ] = 0x2AA; + + dw_unwind__cfa_control_bits_kind2[DW_CFA_AdvanceLoc >> 6] = 0x800; + dw_unwind__cfa_control_bits_kind2[DW_CFA_Offset >> 6] = 0x10A; + dw_unwind__cfa_control_bits_kind2[DW_CFA_Restore >> 6] = 0x100; + } +} + +internal U64 +dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc encoding, U64 off, U64 *ptr_out) +{ + // aligned offset + U64 pointer_off = off; + if (encoding == DW_EhPtrEnc_Aligned) { + pointer_off = AlignPow2(off, 8); // TODO: align to 4 bytes when we parse x86 ELF binary + encoding = DW_EhPtrEnc_Ptr; + } + + // decode pointer value + U64 size_param = 0; + U64 after_pointer_off = 0; + U64 raw_pointer = 0; + switch (encoding & DW_EhPtrEnc_TypeMask) { + default:break; + + case DW_EhPtrEnc_Ptr : size_param = 8; goto ufixed; + case DW_EhPtrEnc_UData2: size_param = 2; goto ufixed; + case DW_EhPtrEnc_UData4: size_param = 4; goto ufixed; + case DW_EhPtrEnc_UData8: size_param = 8; goto ufixed; + ufixed: + { + based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + after_pointer_off = pointer_off + size_param; + } break; + + // TODO: Signed is actually just a flag that indicates this int is negavite. + // There shouldn't be a read for Signed. + // For instance, (DW_EhPtrEnc_UData2 | DW_EhPtrEnc_Signed) == DW_EhPtrEnc_SData etc. + case DW_EhPtrEnc_Signed:size_param = 8; goto sfixed; + + case DW_EhPtrEnc_SData2:size_param = 2; goto sfixed; + case DW_EhPtrEnc_SData4:size_param = 4; goto sfixed; + case DW_EhPtrEnc_SData8:size_param = 8; goto sfixed; + sfixed: + { + based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + after_pointer_off = pointer_off + size_param; + // sign extension + U64 sign_bit = size_param*8 - 1; + if ((raw_pointer >> sign_bit) != 0) { + raw_pointer |= (~(1 << sign_bit)) + 1; + } + } break; + + case DW_EhPtrEnc_ULEB128: + { + U64 size = based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); + after_pointer_off = pointer_off + size; + } break; + + case DW_EhPtrEnc_SLEB128: + { + U64 size = based_range_read_sleb128(frame_base, frame_range, pointer_off, + (S64*)&raw_pointer); + after_pointer_off = pointer_off + size; + } break; + } + + // apply relative bases + U64 pointer = raw_pointer; + if (pointer != 0) { + switch (encoding & DW_EhPtrEnc_ModifyMask) { + case DW_EhPtrEnc_PcRel: + { + pointer = ptr_ctx->raw_base_vaddr + frame_range.min + off + raw_pointer; + } break; + case DW_EhPtrEnc_TextRel: + { + pointer = ptr_ctx->text_vaddr + raw_pointer; + } break; + case DW_EhPtrEnc_DataRel: + { + pointer = ptr_ctx->data_vaddr + raw_pointer; + } break; + case DW_EhPtrEnc_FuncRel: + { + Assert(!"TODO: need a sample to verify implementation"); + pointer = ptr_ctx->func_vaddr + raw_pointer; + } break; + } + } + + // return + *ptr_out = pointer; + U64 result = after_pointer_off - off; + return(result); +} + +//- eh_frame parsing + +internal void +dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out) +{ + MemoryZeroStruct(cie_out); + + // get version + U64 version_off = off; + U8 version = 0; + based_range_read(base, range, version_off, 1, &version); + + // check version + if (version == 1 || version == 3) { + + // read augmentation + U64 augmentation_off = version_off + 1; + String8 augmentation = based_range_read_string(base, range, augmentation_off); + + // read code align + U64 code_align_factor_off = augmentation_off + augmentation.size + 1; + U64 code_align_factor = 0; + U64 code_align_factor_size = based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); + + // read data align + U64 data_align_factor_off = code_align_factor_off + code_align_factor_size; + S64 data_align_factor = 0; + U64 data_align_factor_size = based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); + + // return address register + U64 ret_addr_reg_off = data_align_factor_off + data_align_factor_size; + U64 after_ret_addr_reg_off = 0; + U64 ret_addr_reg = 0; + if (version == 1) { + based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); + after_ret_addr_reg_off = ret_addr_reg_off + 1; + } else { + U64 ret_addr_reg_size = based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); + after_ret_addr_reg_off = ret_addr_reg_off + ret_addr_reg_size; + } + + // TODO: + // Handle "eh" param, it indicates presence of EH Data field. + // On 32bit arch it is a 4-byte and on 64-bit 8-byte value. + // Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html + // Reference doc doesn't clarify structure for EH Data though + + // check for augmentation data + U64 aug_size_off = after_ret_addr_reg_off; + U64 after_aug_size_off = after_ret_addr_reg_off; + B32 has_augmentation_size = 0; + U64 augmentation_size = 0; + if (augmentation.size > 0 && augmentation.str[0] == 'z') { + has_augmentation_size = 1; + U64 aug_size_size = based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); + after_aug_size_off += aug_size_size; + } + + // read augmentation data + U64 aug_data_off = after_aug_size_off; + U64 after_aug_data_off = after_aug_size_off; + + DW_EhPtrEnc lsda_encoding = DW_EhPtrEnc_Omit; + U64 handler_ip = 0; + DW_EhPtrEnc addr_encoding = DW_EhPtrEnc_UData8; + + if (has_augmentation_size > 0) { + U64 aug_data_cursor = aug_data_off; + for (U8 *ptr = augmentation.str + 1, *opl = augmentation.str + augmentation.size; ptr < opl; ++ptr) { + switch (*ptr) { + case 'L': { + based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); + aug_data_cursor += sizeof(lsda_encoding); + } break; + case 'P': { + DW_EhPtrEnc handler_encoding = DW_EhPtrEnc_Omit; + based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); + + U64 ptr_off = aug_data_cursor + sizeof(handler_encoding); + U64 ptr_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, handler_encoding, ptr_off, &handler_ip); + aug_data_cursor = ptr_off + ptr_size; + } break; + case 'R': { + based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); + aug_data_cursor += sizeof(addr_encoding); + } break; + default: { + goto dbl_break_aug; + } break; + } + } + dbl_break_aug:; + after_aug_data_off = aug_data_cursor; + } + + // cfi range + U64 cfi_off = range.min + after_aug_data_off; + U64 cfi_size = 0; + if (range.max > cfi_off) { + cfi_size = range.max - cfi_off; + } + + // commit values to out + cie_out->version = version; + cie_out->lsda_encoding = lsda_encoding; + cie_out->addr_encoding = addr_encoding; + cie_out->has_augmentation_size = has_augmentation_size; + cie_out->augmentation_size = augmentation_size; + cie_out->augmentation = augmentation; + cie_out->code_align_factor = code_align_factor; + cie_out->data_align_factor = data_align_factor; + cie_out->ret_addr_reg = ret_addr_reg; + cie_out->handler_ip = handler_ip; + cie_out->cfi_range.min = cfi_off; + cie_out->cfi_range.max = cfi_off + cfi_size; + } +} + +internal void +dw_unwind_parse_fde_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *cie, U64 off, DW_FDEUnpacked *fde_out) +{ + // pull out pointer encoding field + DW_EhPtrEnc ptr_enc = cie->addr_encoding; + + // ip first + U64 ip_first_off = off; + U64 ip_first = 0; + U64 ip_first_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, ptr_enc, ip_first_off, &ip_first); + + // ip range size + U64 ip_range_size_off = ip_first_off + ip_first_size; + U64 ip_range_size = 0; + U64 ip_range_size_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, ptr_enc & DW_EhPtrEnc_TypeMask, ip_range_size_off, &ip_range_size); + + // augmentation data + U64 aug_data_off = ip_range_size_off + ip_range_size_size; + U64 after_aug_data_off = aug_data_off; + U64 lsda_ip = 0; + + if (cie->has_augmentation_size) { + // augmentation size + U64 augmentation_size = 0; + U64 aug_size_size = based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); + U64 after_aug_size_off = aug_data_off + aug_size_size; + + // extract lsda (only thing that can actually be in FDE's augmentation data as far as we know) + DW_EhPtrEnc lsda_encoding = cie->lsda_encoding; + if (lsda_encoding != DW_EhPtrEnc_Omit) { + U64 lsda_off = after_aug_size_off; + dw_unwind_parse_pointer_x64(base, range, ptr_ctx, lsda_encoding, lsda_off, &lsda_ip); + } + + // set offset at end of augmentation data + after_aug_data_off = after_aug_size_off + augmentation_size; + } + + // cfi range + U64 cfi_off = range.min + after_aug_data_off; + U64 cfi_size = 0; + if (range.max > cfi_off) { + cfi_size = range.max - cfi_off; + } + + // commit values to out + fde_out->ip_voff_range.min = ip_first; + fde_out->ip_voff_range.max = ip_first + ip_range_size; + fde_out->lsda_ip = lsda_ip; + fde_out->cfi_range.min = cfi_off; + fde_out->cfi_range.max = cfi_off + cfi_size; +} + +internal DW_CFIRecords +dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff) +{ + Temp scratch = scratch_begin(0, 0); + + DW_CFIRecords result = {0}; + + DW_CIEUnpackedNode *cie_first = 0; + DW_CIEUnpackedNode *cie_last = 0; + + U64 cursor = 0; + for (;;) { + // CIE/FDE size + U64 rec_off = cursor; + U64 after_rec_size_off = 0; + U64 rec_size = 0; + + { + str8_deserial_read(raw_eh_frame, rec_off, &rec_size, 4, 1); + after_rec_size_off = 4; + if (rec_size == max_U32) { + str8_deserial_read(raw_eh_frame, rec_off + 4, &rec_size, 8, 1); + after_rec_size_off = 12; + } + } + + // zero size is the end of the loop + if (rec_size == 0) { + break; + } + + // compute end offset + U64 rec_opl = rec_off + after_rec_size_off + rec_size; + + // sub-range the rest of the reads + Rng1U64 rec_range = rng_1u64(rec_off, rec_opl); + String8 raw_rec = str8_substr(raw_eh_frame, rec_range); + + + // discriminator + U64 discrim_off = after_rec_size_off; + U32 discrim = 0; + str8_deserial_read(raw_rec, discrim_off, &discrim, 4, 1); + + U64 after_discrim_off = discrim_off + 4; + + // CIE + if (discrim == 0) { + DW_CIEUnpacked cie = {0}; + dw_unwind_parse_cie_x64(raw_rec.str, rng_1u64(0, raw_rec.size), ptr_ctx, after_discrim_off, &cie); + if (cie.version != 0) { + DW_CIEUnpackedNode *node = push_array(scratch.arena, DW_CIEUnpackedNode, 1); + node->cie = cie; + node->offset = rec_off; + SLLQueuePush(cie_first, cie_last, node); + } + } + // FDE + else { + // compute cie offset + U64 cie_offset = rec_range.min + discrim_off - discrim; + + // get cie node + DW_CIEUnpackedNode *cie_node = 0; + for (DW_CIEUnpackedNode *node = cie_first; node != 0; node = node->next) { + if (node->offset == cie_offset) { + cie_node = node; + break; + } + } + + // parse fde + DW_FDEUnpacked fde = {0}; + if (cie_node != 0) { + dw_unwind_parse_fde_x64(raw_rec.str, rng_1u64(0,raw_rec.size), ptr_ctx, &cie_node->cie, after_discrim_off, &fde); + } + + if (contains_1u64(fde.ip_voff_range, ip_voff)) { + result.valid = 1; + result.cie = cie_node->cie; + result.fde = fde; + break; + } + } + + // advance cursor + cursor = rec_opl; + } + + scratch_end(scratch); + + return(result); +} + +internal U64 +dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 location) +{ + // Table contains only addresses for first instruction in a function and we cannot + // guarantee that result is FDE that corresponds to the input location. + // So input location must be cheked against range from FDE header again. + + U64 closest_location = max_U64; + U64 closest_address = max_U64; + + U64 cursor = 0; + + U8 version = 0; + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &version); + + if (version == 1) { +#if 0 + DW_EhPtrCtx ptr_ctx = {0}; + // Set this to base address of .eh_frame_hdr. Entries are relative + // to this section for some reason. + ptr_ctx.data_vaddr = range.min; + // If input location is VMA then set this to address of .text. + // Pointer parsing function will adjust "init_location" to correct VMA. + ptr_ctx.text_vaddr = 0; +#endif + + DW_EhPtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0; + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc); + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc); + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc); + + U64 eh_frame_ptr = 0, fde_count = 0; + cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr); + cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count); + + for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) { + U64 init_location = 0, address = 0; + cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location); + cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address); + + S64 current_delta = (S64)(location - init_location); + S64 closest_delta = (S64)(location - closest_location); + if (0 <= current_delta && current_delta < closest_delta) { + closest_location = init_location; + closest_address = address; + } + } + } + + // address where to find corresponding FDE, this is an absolute offset + // into the image file. + return closest_address; +} + +internal DW_CFIRecords +dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff) +{ + DW_CFIRecords result = {0}; + + // find FDE offset + void *eh_frame_hdr = raw_eh_frame.str; + U64 fde_offset = dw_search_eh_frame_hdr_linear_x64(raw_eh_frame_hdr, ptr_ctx, ip_voff); + + B32 is_fde_offset_valid = (fde_offset != max_U64); + if (is_fde_offset_valid) { + U64 fde_read_offset = (fde_offset - ptr_ctx->raw_base_vaddr); + + // read FDE size + U64 fde_size = 0; + fde_read_offset += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), fde_read_offset, &fde_size); + + // read FDE discriminator + U32 fde_discrim = 0; + fde_read_offset += str8_deserial_read_struct(raw_eh_frame, fde_read_offset, &fde_discrim); + + // compute parent CIE offset + U64 cie_read_offset = fde_read_offset - (fde_discrim + sizeof(fde_discrim)); + + // read CIE size + U64 cie_size = 0; + cie_read_offset += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), cie_read_offset, &cie_size); + + // read CIE discriminator + U32 cie_discrim = max_U32; + cie_read_offset += str8_deserial_read_struct(raw_eh_frame, cie_read_offset, &cie_discrim); + + B32 is_fde = (fde_discrim != 0); + B32 is_cie = (cie_discrim == 0); + if (is_fde && is_cie) { + Rng1U64 cie_range = rng_1u64(0, cie_read_offset + (cie_size - sizeof(cie_discrim))); + Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim))); + + // parse CIE + DW_CIEUnpacked cie = {0}; + dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie); + + // parse FDE + DW_FDEUnpacked fde = {0}; + dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde); + + // range check instruction pointer + if (contains_1u64(fde.ip_voff_range, ip_voff)) { + result.valid = 1; + result.cie = cie; + result.fde = fde; + } + } + } + + return result; +} + +//- cfi machine + +internal DW_CFIMachine +dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx) +{ + DW_CFIMachine result = {0}; + result.cells_per_row = cells_per_row; + result.cie = cie; + result.ptr_ctx = ptr_ctx; + return result; +} + +internal void +dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row) +{ + machine->initial_row = initial_row; +} + +internal void +dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip) +{ + machine->fde_ip = fde_ip; +} + +internal DW_CFIRow* +dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row) +{ + DW_CFIRow *result = push_array(arena, DW_CFIRow, 1); + result->cells = push_array(arena, DW_CFICell, cells_per_row); + return result; +} + +internal void +dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row) { + MemorySet(row->cells, 0, sizeof(*row->cells)*cells_per_row); + MemoryZeroStruct(&row->cfa_cell); +} + +internal void +dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row) +{ + MemoryCopy(dst->cells, src->cells, sizeof(*src->cells)*cells_per_row); + dst->cfa_cell = src->cfa_cell; +} + +internal B32 +dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row) +{ + Temp scratch = scratch_begin(0, 0); + + B32 result = 0; + + // pull out machine's equipment + DW_CIEUnpacked *cie = machine->cie; + DW_EhPtrCtx *ptr_ctx = machine->ptr_ctx; + U64 cells_per_row = machine->cells_per_row; + DW_CFIRow *initial_row = machine->initial_row; + + // start with an empty stack + DW_CFIRow *stack = 0; + DW_CFIRow *free_rows = 0; + + // initialize the row + if (initial_row != 0) { + dw_unwind_row_copy_x64(row, initial_row, cells_per_row); + } else { + dw_unwind_row_zero_x64(row, cells_per_row); + } + U64 table_ip = machine->fde_ip; + + // loop + U64 cfi_off = 0; + for (;;) { + // op variables + DW_CFA opcode = 0; + U64 operand0 = 0; + U64 operand1 = 0; + U64 operand2 = 0; + DW_CFAControlBits control_bits = 0; + + // decode opcode/operand0 + if (!based_range_read(base, range, cfi_off, 1, &opcode)) { + result = 1; + goto done; + } + if ((opcode & DW_CFAMask_OpcodeHi) != 0) { + operand0 = (opcode & DW_CFAMask_Operand); + opcode = (opcode & DW_CFAMask_OpcodeHi); + control_bits = dw_unwind__cfa_control_bits_kind2[opcode >> 6]; + } else { + if (opcode < DW_CFA_OplKind1) { + control_bits = dw_unwind__cfa_control_bits_kind1[opcode]; + } + } + + // decode operand1/operand2 + U64 decode_cursor = cfi_off + 1; + { + // setup loop ins/outs + U64 o[2]; + DW_CFADecode dec[2] = {0}; + dec[0] = (control_bits & 0xF); + dec[1] = ((control_bits >> 4) & 0xF); + + // loop + U64 *out = o; + for (U64 i = 0; i < 2; i += 1, out += 1) { + DW_CFADecode d = dec[i]; + U64 o_size = 0; + switch (d) { + case 0: { + *out = 0; + } break; + default: { + if (d <= 8) { + based_range_read(base, range, decode_cursor, d, out); + o_size = d; + } + } break; + case DW_CFADecode_Address: { + o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); + } break; + case DW_CFADecode_ULEB128: { + o_size = based_range_read_uleb128(base, range, decode_cursor, out); + } break; + case DW_CFADecode_SLEB128: { + o_size = based_range_read_sleb128(base, range, decode_cursor, (S64*)out); + } break; + } + decode_cursor += o_size; + } + + // commit out values + operand1 = o[0]; + operand2 = o[1]; + } + U64 after_decode_off = decode_cursor; + + // register checks + if (control_bits & DW_CFAControlBits_IsReg0) { + if (operand0 >= cells_per_row) { + goto done; + } + } + if (control_bits & DW_CFAControlBits_IsReg1) { + if (operand1 >= cells_per_row) { + goto done; + } + } + if (control_bits & DW_CFAControlBits_IsReg2) { + if (operand2 >= cells_per_row) { + goto done; + } + } + + // values for deferred work + U64 new_table_ip = table_ip; + + // step + U64 step_cursor = after_decode_off; + switch (opcode) { + default: goto done; + case DW_CFA_Nop:break; + + //// new row/IP opcodes //// + + case DW_CFA_SetLoc: { + new_table_ip = operand1; + } break; + case DW_CFA_AdvanceLoc: { + new_table_ip = table_ip + operand0*cie->code_align_factor; + } break; + case DW_CFA_AdvanceLoc1: + case DW_CFA_AdvanceLoc2: + case DW_CFA_AdvanceLoc4: { + U64 advance = operand1*cie->code_align_factor; + new_table_ip = table_ip + advance; + } break; + + //// change CFA (canonical frame address) opcodes //// + + case DW_CFA_DefCfa: { + row->cfa_cell.rule = DW_CFI_CFA_Rule_RegOff; + row->cfa_cell.reg_idx = operand1; + row->cfa_cell.offset = operand2; + } break; + + case DW_CFA_DefCfaSf: { + row->cfa_cell.rule = DW_CFI_CFA_Rule_RegOff; + row->cfa_cell.reg_idx = operand1; + row->cfa_cell.offset = ((S64)operand2)*cie->data_align_factor; + } break; + + case DW_CFA_DefCfaRegister: { + // check rule + if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { + goto done; + } + // commit new cfa + row->cfa_cell.reg_idx = operand1; + } break; + + case DW_CFA_DefCfaOffset: { + // check rule + if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { + goto done; + } + // commit new cfa + row->cfa_cell.offset = operand1; + } break; + + case DW_CFA_DefCfaOffsetSf: { + // check rule + if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { + goto done; + } + // commit new cfa + row->cfa_cell.offset = ((S64)operand1)*cie->data_align_factor; + } break; + + case DW_CFA_DefCfaExpr: { + // setup expr range + U64 expr_first = range.min + after_decode_off; + U64 expr_size = operand1; + step_cursor += expr_size; + + // commit new cfa + row->cfa_cell.rule = DW_CFI_CFA_Rule_Expr; + row->cfa_cell.expr.min = expr_first; + row->cfa_cell.expr.max = expr_first + expr_size; + } break; + + + //// change register rules //// + + case DW_CFA_Undefined: { + row->cells[operand1].rule = DW_CFIRegisterRule_Undefined; + } break; + + case DW_CFA_SameValue: { + row->cells[operand1].rule = DW_CFIRegisterRule_SameValue; + } break; + + case DW_CFA_Offset: { + DW_CFICell *cell = &row->cells[operand0]; + cell->rule = DW_CFIRegisterRule_Offset; + cell->n = operand1*cie->data_align_factor; + } break; + + case DW_CFA_OffsetExt: { + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_Offset; + cell->n = operand2*cie->data_align_factor; + } break; + + case DW_CFA_OffsetExtSf: { + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_Offset; + cell->n = ((S64)operand2)*cie->data_align_factor; + } break; + + case DW_CFA_ValOffset: { + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_ValOffset; + cell->n = operand2*cie->data_align_factor; + } break; + + case DW_CFA_ValOffsetSf: { + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_ValOffset; + cell->n = ((S64)operand2)*cie->data_align_factor; + } break; + + case DW_CFA_Register: { + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_Register; + cell->n = operand2; + } break; + + case DW_CFA_Expr: { + // setup expr range + U64 expr_first = range.min + after_decode_off; + U64 expr_size = operand2; + step_cursor += expr_size; + + // commit new rule + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_Expression; + cell->expr.min = expr_first; + cell->expr.max = expr_first + expr_size; + } break; + + case DW_CFA_ValExpr: { + // setup expr range + U64 expr_first = range.min + after_decode_off; + U64 expr_size = operand2; + step_cursor += expr_size; + + // commit new rule + DW_CFICell *cell = &row->cells[operand1]; + cell->rule = DW_CFIRegisterRule_ValExpression; + cell->expr.min = expr_first; + cell->expr.max = expr_first + expr_size; + } break; + + case DW_CFA_Restore: { + // check initial row + if (initial_row == 0) { + goto done; + } + // commit new rule + row->cells[operand0] = initial_row->cells[operand0]; + } break; + + case DW_CFA_RestoreExt: { + // check initial row + if (initial_row == 0) { + goto done; + } + // commit new rule + row->cells[operand1] = initial_row->cells[operand1]; + } break; + + + //// row stack //// + + case DW_CFA_RememberState: { + DW_CFIRow *stack_row = free_rows; + if (stack_row != 0) { + SLLStackPop(free_rows); + } else { + stack_row = dw_unwind_row_alloc_x64(scratch.arena, cells_per_row); + } + dw_unwind_row_copy_x64(stack_row, row, cells_per_row); + SLLStackPush(stack, stack_row); + } break; + + case DW_CFA_RestoreState: { + if (stack != 0) { + DW_CFIRow *stack_row = stack; + SLLStackPop(stack); + dw_unwind_row_copy_x64(row, stack_row, cells_per_row); + SLLStackPush(free_rows, stack_row); + } else { + dw_unwind_row_zero_x64(row, cells_per_row); + } + } break; + } + + // apply location change + if (control_bits & DW_CFAControlBits_NewRow) { + // new ip should always grow the ip + if (new_table_ip <= table_ip) { + goto done; + } + // stop if this encloses the target ip + if (table_ip <= target_ip && target_ip < new_table_ip) { + result = 1; + goto done; + } + // commit new ip + table_ip = new_table_ip; + } + + // advance + cfi_off = step_cursor; + } + done:; + + scratch_end(scratch); + return result; +} + diff --git a/src/dwarf/dwarf_unwind.h b/src/dwarf/dwarf_unwind.h new file mode 100644 index 00000000..8a0018e6 --- /dev/null +++ b/src/dwarf/dwarf_unwind.h @@ -0,0 +1,224 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_UNWIND_H +#define DWARF_UNWIND_H + +typedef struct DW_UnwindResult +{ + B32 is_invalid; + B32 missed_read; + U64 missed_read_addr; + U64 stack_pointer; +} DW_UnwindResult; + +// EH: Exception Frames + +typedef U8 DW_EhPtrEnc; +enum +{ + DW_EhPtrEnc_TypeMask = 0x0F, + DW_EhPtrEnc_Ptr = 0x00, // Pointer sized unsigned value + DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value + DW_EhPtrEnc_UData2 = 0x02, // Unsigned 16-bit value + DW_EhPtrEnc_UData4 = 0x03, // Unsigned 32-bit value + DW_EhPtrEnc_UData8 = 0x04, // Unsigned 64-bit value + DW_EhPtrEnc_Signed = 0x08, // Signed pointer + DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value + DW_EhPtrEnc_SData2 = 0x0A, // Signed 16-bit value + DW_EhPtrEnc_SData4 = 0x0B, // Signed 32-bit value + DW_EhPtrEnc_SData8 = 0x0C, // Signed 64-bit value +}; + +enum +{ + DW_EhPtrEnc_ModifyMask = 0x70, + DW_EhPtrEnc_PcRel = 0x10, // Value is relative to the current program counter. + DW_EhPtrEnc_TextRel = 0x20, // Value is relative to the .text section. + DW_EhPtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section. + DW_EhPtrEnc_FuncRel = 0x40, // Value is relative to the function. + DW_EhPtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary. +}; + +enum +{ + DW_EhPtrEnc_Indirect = 0x80, // This flag indicates that value is stored in virtual memory. + DW_EhPtrEnc_Omit = 0xFF, +}; + +typedef struct DW_EhPtrCtx +{ + U64 raw_base_vaddr; // address where pointer is being read + U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) + U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) + U64 func_vaddr; // base address of function where IP is located +} DW_EhPtrCtx; + +// CIE: Common Information Entry +typedef struct DW_CIEUnpacked +{ + U8 version; + DW_EhPtrEnc lsda_encoding; + DW_EhPtrEnc addr_encoding; + + B32 has_augmentation_size; + U64 augmentation_size; + String8 augmentation; + + U64 code_align_factor; + S64 data_align_factor; + U64 ret_addr_reg; + + U64 handler_ip; + + Rng1U64 cfi_range; +} DW_CIEUnpacked; + +typedef struct DW_CIEUnpackedNode +{ + struct DW_CIEUnpackedNode *next; + DW_CIEUnpacked cie; + U64 offset; +} DW_CIEUnpackedNode; + +// FDE: Frame Description Entry +typedef struct DW_FDEUnpacked +{ + Rng1U64 ip_voff_range; + U64 lsda_ip; + Rng1U64 cfi_range; +} DW_FDEUnpacked; + +// CFI: Call Frame Information +typedef struct DW_CFIRecords +{ + B32 valid; + DW_CIEUnpacked cie; + DW_FDEUnpacked fde; +} DW_CFIRecords; + +typedef enum DW_CFICFARule{ + DW_CFI_CFA_Rule_RegOff, + DW_CFI_CFA_Rule_Expr, +} DW_CFICFARule; + +typedef struct DW_CFICFACell +{ + DW_CFICFARule rule; + union { + struct { + U64 reg_idx; + S64 offset; + }; + Rng1U64 expr; + }; +} DW_CFICFACell; + +typedef enum DW_CFIRegisterRule +{ + DW_CFIRegisterRule_SameValue, + DW_CFIRegisterRule_Undefined, + DW_CFIRegisterRule_Offset, + DW_CFIRegisterRule_ValOffset, + DW_CFIRegisterRule_Register, + DW_CFIRegisterRule_Expression, + DW_CFIRegisterRule_ValExpression, +} DW_CFIRegisterRule; + +typedef struct DW_CFICell +{ + DW_CFIRegisterRule rule; + union { + S64 n; + Rng1U64 expr; + }; +} DW_CFICell; + +typedef struct DW_CFIRow +{ + struct DW_CFIRow *next; + DW_CFICell *cells; + DW_CFICFACell cfa_cell; +} DW_CFIRow; + +typedef struct DW_CFIMachine +{ + U64 cells_per_row; + DW_CIEUnpacked *cie; + DW_EhPtrCtx *ptr_ctx; + DW_CFIRow *initial_row; + U64 fde_ip; +} DW_CFIMachine; + +typedef U8 DW_CFADecode; +enum +{ + DW_CFADecode_Nop = 0x0, + // 1,2,4,8 reserved for literal byte sizes + DW_CFADecode_Address = 0x9, + DW_CFADecode_ULEB128 = 0xA, + DW_CFADecode_SLEB128 = 0xB, +}; + +typedef U16 DW_CFAControlBits; +enum +{ + DW_CFAControlBits_Dec1Mask = 0x00F, + DW_CFAControlBits_Dec2Mask = 0x0F0, + DW_CFAControlBits_IsReg0 = 0x100, + DW_CFAControlBits_IsReg1 = 0x200, + DW_CFAControlBits_IsReg2 = 0x400, + DW_CFAControlBits_NewRow = 0x800, +}; + +global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind1[DW_CFA_OplKind1 + 1]; +global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind2[DW_CFA_OplKind2 + 1]; + +// register codes for unwinding match the DW_RegX64 register codes +#define DW_UNWIND_X64__REG_SLOT_COUNT 17 + +//////////////////////////////// +// x64 Unwind Function + +internal DW_UnwindResult +dw_unwind_x64(String8 raw_text, + String8 raw_eh_frame, + String8 raw_eh_frame_header, + Rng1U64 text_vrange, + Rng1U64 eh_frame_vrange, + Rng1U64 eh_frame_header_vrange, + U64 default_image_base, + U64 image_base, + U64 stack_pointer, + DW_RegsX64 *regs, + DW_ReadMemorySig *read_memory, + void *read_memory_ud); + +internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, DW_CFIRow *row, U64 text_base_vaddr, DW_ReadMemorySig *read_memory, void *read_memory_ud, U64 stack_pointer, DW_RegsX64 *regs); + +//////////////////////////////// +// x64 Unwind Helper Functions + +internal void dw_unwind_init_x64(void); +internal U64 dw_unwind_parse_pointer_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc ptr_enc, U64 off, U64 *ptr_out); + +//- eh_frame parsing +internal void dw_unwind_parse_cie_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out); +internal void dw_unwind_parse_fde_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *parent_cie, U64 off, DW_FDEUnpacked *fde_out); +internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff); +internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff); + +//- cfi machine + +internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx); +internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row); +internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip); + +internal DW_CFIRow* dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row); +internal void dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row); +internal void dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row); + +internal B32 dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row_out); + +#endif // DWARF_UNWIND_H + From a5c9a1c97858c957344de2be35aeada7f59d8dce Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 26 Dec 2024 21:55:31 -0800 Subject: [PATCH 07/53] u64 array sort --- src/linker/base_ext/base_arrays.c | 6 ++++++ src/linker/base_ext/base_arrays.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/linker/base_ext/base_arrays.c b/src/linker/base_ext/base_arrays.c index 9cc83a8e..423ab684 100644 --- a/src/linker/base_ext/base_arrays.c +++ b/src/linker/base_ext/base_arrays.c @@ -63,6 +63,12 @@ u32_array_sort(U64 count, U32 *v) radsort(v, count, u32_is_before); } +internal void +u64_array_sort(U64 count, U64 *v) +{ + radsort(v, count, u64_is_before); +} + internal void u32_pair_radix_sort(U64 count, PairU32 *arr) { diff --git a/src/linker/base_ext/base_arrays.h b/src/linker/base_ext/base_arrays.h index 70531fb1..e1cd052d 100644 --- a/src/linker/base_ext/base_arrays.h +++ b/src/linker/base_ext/base_arrays.h @@ -31,6 +31,7 @@ internal U64Array u64_array_from_list(Arena *arena, U64List *list); internal U64Array u64_array_remove_duplicates(Arena *arena, U64Array in); internal void u32_array_sort(U64 count, U32 *v); +internal void u64_array_sort(U64 count, U64 *v); internal B32 u32_array_compare(U32Array a, U32Array b); internal U64 sum_array_u64(U64 count, U64 *v); From 543ee72f957c9d128595f2f392b54e9c197dd06a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 26 Dec 2024 21:56:10 -0800 Subject: [PATCH 08/53] u64 array helper --- src/linker/hash_table.c | 34 ++++++++++++++++++++++++++++++++++ src/linker/hash_table.h | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index 50ec76a2..4566eb67 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -256,6 +256,19 @@ keys_from_hash_table_u32(Arena *arena, HashTable *ht) return result; } +internal U64 * +keys_from_hash_table_u64(Arena *arena, HashTable *ht) +{ + U64 *result = push_array_no_zero(arena, U64, ht->count); + for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) { + for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) { + Assert(cursor < ht->count); + result[cursor++] = n->v.key_u64; + } + } + return result; +} + internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht) { @@ -281,3 +294,24 @@ sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count) radsort(pairs, count, key_value_pair_is_before_u64); } +internal U64Array +remove_duplicates_u64_array(Arena *arena, U64Array arr) +{ + Temp scratch = scratch_begin(&arena, 1); + + HashTable *ht = hash_table_init(scratch.arena, ((U64)(F64)arr.count * 0.5)); + + for (U64 i = 0; i < arr.count; ++i) { + KeyValuePair *is_present = hash_table_search_u64(ht, arr.v[i]); + if (!is_present) { + hash_table_push_u64_raw(scratch.arena, ht, arr.v[i], 0); + } + } + + U64Array result = {0}; + result.count = ht->count; + result.v = keys_from_hash_table_u64(arena, ht); + + scratch_end(scratch); + return result; +} diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index ad048600..51e55a0e 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -76,7 +76,12 @@ internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_o //- key-value helpers internal U32 * keys_from_hash_table_u32(Arena *arena, HashTable *ht); +internal U64 * keys_from_hash_table_u64(Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); +//////////////////////////////// + +internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr); + From 98b9427446be635c672e4e4bd8c9228af456cb73 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:13:48 -0800 Subject: [PATCH 09/53] dumper for Dwarf --- src/dwarf/dwarf.c | 266 +++ src/dwarf/dwarf.h | 1690 +++++++++++++++ src/dwarf/dwarf_enum.c | 225 ++ src/dwarf/dwarf_enum.h | 10 +- src/dwarf/dwarf_expr.c | 102 +- src/dwarf/dwarf_parse.c | 598 ++--- src/dwarf/dwarf_parse.h | 79 +- src/dwarf/dwarf_unwind.c | 38 +- src/linker/codeview_ext/codeview.c | 2 +- src/linker/lnk_debug_info.c | 18 +- src/msvc_crt/msvc_crt.c | 106 +- src/raddump/raddump.c | 3244 ++++++++++++++++++++++++---- src/raddump/raddump.h | 227 +- src/raddump/raddump_main.c | 174 +- 14 files changed, 5800 insertions(+), 979 deletions(-) create mode 100644 src/dwarf/dwarf.c create mode 100644 src/dwarf/dwarf.h create mode 100644 src/dwarf/dwarf_enum.c diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c new file mode 100644 index 00000000..6a224f34 --- /dev/null +++ b/src/dwarf/dwarf.c @@ -0,0 +1,266 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V2_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V3_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V4_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V5_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_gnu(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_GNU_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_llvm(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_LLVM_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_APPLE_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_mips(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_MIPS_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k) +{ + DW_AttribClass result = DW_AttribClass_Null; + + while (ext) { + U64 z = 64-clz64(ext); + if (z == 0) { + break; + } + U64 flag = 1 << (z-1); + ext &= ~flag; + + switch (flag) { + case DW_Ext_Null: break; + case DW_Ext_GNU: result = dw_attrib_class_from_attrib_kind_gnu(k); break; + case DW_Ext_LLVM: result = dw_attrib_class_from_attrib_kind_llvm(k); break; + case DW_Ext_APPLE: result = dw_attrib_class_from_attrib_kind_apple(k); break; + case DW_Ext_MIPS: result = dw_attrib_class_from_attrib_kind_mips(k); break; + default: InvalidPath; break; + } + + if (result != DW_AttribClass_Null) { + break; + } + } + + if (result == DW_AttribClass_Null) { + switch (ver) { + case DW_Version_Null: break; + case DW_Version_1: AssertAlways(!"DWARF V1 is not supported"); break; + case DW_Version_2: result = dw_attrib_class_from_attrib_kind_v2(k); break; + case DW_Version_3: result = dw_attrib_class_from_attrib_kind_v3(k); break; + case DW_Version_4: result = dw_attrib_class_from_attrib_kind_v4(k); break; + case DW_Version_5: result = dw_attrib_class_from_attrib_kind_v5(k); break; + default: InvalidPath; break; + } + } + + return result; +} + +internal DW_AttribClass +dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k) +{ + #define X(_N,_C) case DW_Form_##_N: return _C; + switch (ver) { + case DW_Version_5: { + switch (k) { + DW_Form_AttribClass_V5_XList(X) + } + } break; + case DW_Version_4: { + switch (k) { + DW_Form_AttribClass_V4_XList(X) + } + } break; + case DW_Version_3: { + switch (k) { + DW_Form_AttribClass_V2_XList(X) + } + } break; + case DW_Version_2: { + switch (k) { + DW_Form_AttribClass_V2_XList(X) + } + } break; + case DW_Version_1: { + } break; + case DW_Version_Null: break; + } + #undef X + + return DW_AttribClass_Null; +} + +internal B32 +dw_are_attrib_class_and_form_kind_compatible(DW_Version ver, DW_AttribClass attrib_class, DW_FormKind form_kind) +{ + DW_AttribClass compat_flags = dw_attrib_class_from_form_kind(ver, form_kind); + B32 are_compat = (attrib_class & compat_flags) != 0; + return are_compat; +} + +internal String8 +dw_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_L); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +dw_mach_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_M); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +dw_dwo_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_D); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal U64 +dw_offset_size_from_mode(DW_Mode mode) +{ + U64 result = 0; + switch (mode) { + case DW_Mode_Null: break; + case DW_Mode_32Bit: result = 4; break; + case DW_Mode_64Bit: result = 8; break; + default: InvalidPath; break; + } + return result; +} + +internal DW_AttribClass +dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib_kind, DW_FormKind form_kind) +{ + // NOTE(rjf): DWARF's spec specifies two mappings: + // (DW_AttribKind) => List(DW_AttribClass) + // (DW_FormKind) => List(DW_AttribClass) + // + // This function's purpose is to find the overlapping class between an + // DW_AttribKind and DW_FormKind. + + DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind); + DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind); + + if(relaxed) + { + if(attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null) + { + attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_Last, ext, attrib_kind); + form_class = dw_attrib_class_from_form_kind(DW_Version_Last, form_kind); + } + } + + DW_AttribClass result = DW_AttribClass_Null; + if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null) + { + result = DW_AttribClass_Undefined; + + for(U32 i = 0; i < 32; ++i) + { + U32 n = 1u << i; + if((attrib_class & n) != 0 && (form_class & n) != 0) + { + result = ((DW_AttribClass) n); + break; + } + } + } + + if (attrib_kind != DW_Attrib_Null && form_kind != DW_Form_Null) { + //Assert(result != DW_AttribClass_Null && result != DW_AttribClass_Undefined); + } + + return result; +} + diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h new file mode 100644 index 00000000..cf108131 --- /dev/null +++ b/src/dwarf/dwarf.h @@ -0,0 +1,1690 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_H +#define DWARF_H + +typedef U16 DW_Version; +typedef enum DW_VersionEnum +{ + DW_Version_Null, + DW_Version_1, + DW_Version_2, + DW_Version_3, + DW_Version_4, + DW_Version_5, + DW_Version_Last = DW_Version_5 +} DW_VersionEnum; + +typedef U64 DW_Ext; +typedef enum DW_ExtEnum +{ + DW_Ext_Null, + + DW_Ext_GNU = (1 << 0), + DW_Ext_LLVM = (1 << 1), + DW_Ext_APPLE = (1 << 2), + DW_Ext_MIPS = (1 << 3), + + DW_Ext_All = DW_Ext_GNU|DW_Ext_LLVM|DW_Ext_APPLE|DW_Ext_MIPS, +} DW_ExtEnum; + +typedef enum DW_Mode +{ + DW_Mode_Null, + DW_Mode_32Bit, + DW_Mode_64Bit +} DW_Mode; + +#define DW_SectionKind_XList(X) \ + X(Null, "", "", "" ) \ + X(Abbrev, ".debug_abbrev", "__debug_abbrev", ".debug_abbrev.dwo" ) \ + X(ARanges, ".debug_aranges", "__debug_aranges", ".debug_aranges.dwo" ) \ + X(Frame, ".debug_frame", "__debug_frame", ".debug_frame.dwo" ) \ + X(Info, ".debug_info", "__debug_info", ".debug_info.dwo" ) \ + X(Line, ".debug_line", "__debug_line", ".debug_line.dwo" ) \ + X(Loc, ".debug_loc", "__debug_loc", ".debug_loc.dwo" ) \ + X(MacInfo, ".debug_macinfo", "__debug_macinfo", ".debug_macinfo.dwo" ) \ + X(PubNames, ".debug_pubnames", "__debug_pubnames", ".debug_pubnames.dwo" ) \ + X(PubTypes, ".debug_pubtypes", "__debug_pubtypes", ".debug_pubtypes.dwo" ) \ + X(Ranges, ".debug_ranges", "__debug_ranges", ".debug_ranges.dwo" ) \ + X(Str, ".debug_str", "__debug_str", ".debug_str.dwo" ) \ + X(Addr, ".debug_addr", "__debug_addr", ".debug_addr.dwo" ) \ + X(LocLists, ".debug_loclists", "__debug_loclists", ".debug_loclists.dwo" ) \ + X(RngLists, ".debug_rnglists", "__debug_rnglists", ".debug_rnglists.dwo" ) \ + X(StrOffsets, ".debug_stroffsets", "__debug_stroffsets", ".debug_stroffsets.dwo" ) \ + X(LineStr, ".debug_linestr", "__debug_linestr", ".debug_linestr.dwo" ) \ + X(Names, ".debug_names", "__debug_names", ".debug_names.dwo" ) + +typedef U64 DW_SectionKind; +typedef enum DW_SectionKindEnum +{ +#define X(_N,...) DW_Section_##_N, + DW_SectionKind_XList(X) +#undef X + DW_Section_Count +} DW_SectionKindEnum; + +#define DW_Language_XList(X) \ + X(Null, 0x00) \ + X(C89, 0x01) \ + X(C, 0x02) \ + X(Ada83, 0x03) \ + X(CPlusPlus, 0x04) \ + X(Cobol74, 0x05) \ + X(Cobol85, 0x06) \ + X(Fortran77, 0x07) \ + X(Fortran90, 0x08) \ + X(Pascal83, 0x09) \ + X(Modula2, 0x0A) \ + X(Java, 0x0B) \ + X(C99, 0x0C) \ + X(Ada95, 0x0D) \ + X(Fortran95, 0x0E) \ + X(PLI, 0x0F) \ + X(ObjectiveC, 0x10) \ + X(ObjectiveCPlusPlus, 0x11) \ + X(UPC, 0x12) \ + X(D, 0x13) \ + X(Python, 0x14) \ + X(OpenCL, 0x15) \ + X(Go, 0x16) \ + X(Modula3, 0x17) \ + X(Haskell, 0x18) \ + X(CPlusPlus03, 0x19) \ + X(CPlusPlus11, 0x1a) \ + X(OCaml, 0x1b) \ + X(Rust, 0x1c) \ + X(C11, 0x1d) \ + X(Swift, 0x1e) \ + X(Julia, 0x1f) \ + X(Dylan, 0x20) \ + X(CPlusPlus14, 0x21) \ + X(Fortran03, 0x22) \ + X(Fortran08, 0x23) \ + X(RenderScript, 0x24) \ + X(BLISS, 0x25) \ + X(MipsAssembler, 0x8001) \ + X(GoogleRenderScript, 0x8E57) \ + X(SunAssembler, 0x9001) \ + X(BorlandDelphi, 0xB000) + +typedef U32 DW_Language; +typedef enum DW_LanguageEnum +{ +#define X(_N, _ID) DW_Language_##_N = _ID, + DW_Language_XList(X) +#undef X + DW_Language_UserLo = 0x8000, + DW_Language_UserHi = 0xffff, +} DW_LanguageEnum; + +#define DW_StdOpcode_XList(X) \ + X(ExtendedOpcode, 0x00) \ + X(Copy, 0x01) \ + X(AdvancePc, 0x02) \ + X(AdvanceLine, 0x03) \ + X(SetFile, 0x04) \ + X(SetColumn, 0x05) \ + X(NegateStmt, 0x06) \ + X(SetBasicBlock, 0x07) \ + X(ConstAddPc, 0x08) \ + X(FixedAdvancePc, 0x09) \ + X(SetPrologueEnd, 0x0A) \ + X(SetEpilogueBegin, 0x0B) \ + X(SetIsa, 0x0C) \ + +typedef enum DW_StdOpcode +{ +#define X(_N,_ID) DW_StdOpcode_##_N = _ID, + DW_StdOpcode_XList(X) +#undef X + DW_StdOpcode_Count, +} DW_StdOpcode; + +#define DW_ExtOpcode_XList(X) \ + X(Undefined, 0x00) \ + X(EndSequence, 0x01) \ + X(SetAddress, 0x02) \ + X(DefineFile, 0x03) \ + X(SetDiscriminator, 0x04) \ + X(UserLo, 0x80) \ + X(UserHi, 0xff) + +typedef enum DW_ExtOpcode +{ +#define X(_N,_ID) DW_ExtOpcode_##_N = _ID, + DW_ExtOpcode_XList(X) +#undef X + DW_ExtOpcode_Count +} DW_ExtOpcode; + +#define DW_NameCase_XList(X) \ + X(Sensitive, 0x00) \ + X(Upper, 0x01) \ + X(Lower, 0x02) \ + X(Insensitive, 0x03) + +typedef enum DW_NameCase +{ +#define X(_N,_ID) DW_NameCase_##_N = _ID, + DW_NameCase_XList(X) +#undef X + DW_NameCase_Count +} DW_NameCase; + +#define DW_Tag_V3_XList(X) \ + X(ArrayType, 0x01) \ + X(ClassType, 0x02) \ + X(EntryPoint, 0x03) \ + X(EnumerationType, 0x04) \ + X(FormalParameter, 0x05) \ + X(ImportedDeclaration, 0x08) \ + X(Label, 0x0a) \ + X(LexicalBlock, 0x0b) \ + X(Member, 0x0d) \ + X(PointerType, 0x0f) \ + X(ReferenceType, 0x10) \ + X(CompileUnit, 0x11) \ + X(StringType, 0x12) \ + X(StructureType, 0x13) \ + X(SubroutineType, 0x15) \ + X(Typedef, 0x16) \ + X(UnionType, 0x17) \ + X(UnspecifiedParameters, 0x18) \ + X(Variant, 0x19) \ + X(CommonBlock, 0x1a) \ + X(CommonInclusion, 0x1b) \ + X(Inheritance, 0x1c) \ + X(InlinedSubroutine, 0x1d) \ + X(Module, 0x1e) \ + X(PtrToMemberType, 0x1f) \ + X(SetType, 0x20) \ + X(SubrangeType, 0x21) \ + X(WithStmt, 0x22) \ + X(AccessDeclaration, 0x23) \ + X(BaseType, 0x24) \ + X(CatchBlock, 0x25) \ + X(ConstType, 0x26) \ + X(Constant, 0x27) \ + X(Enumerator, 0x28) \ + X(FileType, 0x29) \ + X(Friend, 0x2a) \ + X(NameList, 0x2b) \ + X(NameListItem, 0x2c) \ + X(PackedType, 0x2d) \ + X(SubProgram, 0x2e) \ + X(TemplateTypeParameter, 0x2f) \ + X(TemplateValueParameter, 0x30) \ + X(ThrownType, 0x31) \ + X(TryBlock, 0x32) \ + X(VariantPart, 0x33) \ + X(Variable, 0x34) \ + X(VolatileType, 0x35) \ + X(DwarfProcedure, 0x36) \ + X(RestrictType, 0x37) \ + X(InterfaceType, 0x38) \ + X(Namespace, 0x39) \ + X(ImportedModule, 0x3a) \ + X(UnspecifiedType, 0x3b) \ + X(PartialUnit, 0x3c) \ + X(ImportedUnit, 0x3d) \ + X(Condition, 0x3f) \ + X(SharedType, 0x40) + +#define DW_Tag_V5_XList(X) \ + X(TypeUnit, 0x41) \ + X(RValueReferenceType, 0x42) \ + X(TemplateAlias, 0x43) \ + X(CoarrayType, 0x44) \ + X(GenericSubrange, 0x45) \ + X(DynamicType, 0x46) \ + X(AtomicType, 0x47) \ + X(CallSite, 0x48) \ + X(CallSiteParameter, 0x49) \ + X(SkeletonUnit, 0x4A) \ + X(ImmutableType, 0x4B) + +#define DW_Tag_GNU_XList(X) \ + X(GNU_CallSite, 0x4109) \ + X(GNU_CallSiteParameter, 0x410a) + +typedef U64 DW_TagKind; +typedef enum DW_TagKindEnum +{ +#define X(_N,_ID) DW_Tag_##_N = _ID, + DW_Tag_V3_XList(X) + DW_Tag_V5_XList(X) + DW_Tag_GNU_XList(X) +#undef X + DW_Tag_UserLo = 0x4080, + DW_Tag_UserHi = 0xffff +} DW_TagKindEnum; + +//- Attrib Class Encodings + +#define DW_AttribClass_V3_XList(X) \ + X(Null, 0) \ + X(Undefined, 1) \ + X(Address, 2) \ + X(Block, 3) \ + X(Const, 4) \ + X(ExprLoc, 5) \ + X(Flag, 6) \ + X(LinePtr, 7) \ + X(LocListPtr, 8) \ + X(MacPtr, 9) \ + X(RngListPtr, 10) \ + X(Reference, 11) \ + X(String, 12) + +#define DW_AttribClass_V4_XList(X) \ + X(LocList, 13) \ + X(RngList, 14) + +#define DW_AttribClass_V5_XList(X) \ + X(StrOffsetsPtr, 15) \ + X(AddrPtr, 16) + +typedef U32 DW_AttribClass; +typedef enum DW_AttribClassEnum +{ +#define X(_N,_ID) DW_AttribClass_##_N = (1 << _ID), + DW_AttribClass_V3_XList(X) + DW_AttribClass_V4_XList(X) + DW_AttribClass_V5_XList(X) +#undef X +} DW_AttribClassEnum; + +//- Form Encodings + +#define DW_Form_V2_XList(X) \ + X(Addr, 0x1) \ + X(Block2, 0x3) \ + X(Block4, 0x4) \ + X(Data2, 0x5) \ + X(Data4, 0x6) \ + X(Data8, 0x7) \ + X(String, 0x8) \ + X(Block, 0x9) \ + X(Block1, 0xa) \ + X(Data1, 0xb) \ + X(Flag, 0xc) \ + X(SData, 0xd) \ + X(Strp, 0xe) \ + X(UData, 0xf) \ + X(RefAddr, 0x10) \ + X(Ref1, 0x11) \ + X(Ref2, 0x12) \ + X(Ref4, 0x13) \ + X(Ref8, 0x14) \ + X(RefUData, 0x15) \ + X(Indirect, 0x16) + +#define DW_Form_AttribClass_V2_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) + +#define DW_Form_V4_XList(X) \ + X(SecOffset, 0x17) \ + X(ExprLoc, 0x18) \ + X(FlagPresent, 0x19) \ + X(RefSig8, 0x20) + +#define DW_Form_AttribClass_V4_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) \ + X(SecOffset, DW_AttribClass_LinePtr|DW_AttribClass_LocListPtr|DW_AttribClass_MacPtr|DW_AttribClass_RngListPtr) \ + X(ExprLoc, DW_AttribClass_ExprLoc) \ + X(FlagPresent, DW_AttribClass_Flag) \ + X(RefSig8, DW_AttribClass_Reference) + +#define DW_Form_V5_XList(X) \ + X(Strx, 0x1a) \ + X(Addrx, 0x1b) \ + X(RefSup4, 0x1c) \ + X(StrpSup, 0x1d) \ + X(Data16, 0x1e) \ + X(LineStrp, 0x1f) \ + X(ImplicitConst, 0x21) \ + X(LocListx, 0x22) \ + X(RngListx, 0x23) \ + X(RefSup8, 0x24) \ + X(Strx1, 0x25) \ + X(Strx2, 0x26) \ + X(Strx3, 0x27) \ + X(Strx4, 0x28) \ + X(Addrx1, 0x29) \ + X(Addrx2, 0x2a) \ + X(Addrx3, 0x2b) \ + X(Addrx4, 0x2c) + +#define DW_Form_AttribClass_V5_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) \ + X(SecOffset, DW_AttribClass_AddrPtr| \ + DW_AttribClass_LinePtr| \ + DW_AttribClass_LocList| \ + DW_AttribClass_LocListPtr| \ + DW_AttribClass_MacPtr| \ + DW_AttribClass_RngList| \ + DW_AttribClass_RngListPtr| \ + DW_AttribClass_StrOffsetsPtr) \ + X(ExprLoc, DW_AttribClass_ExprLoc) \ + X(FlagPresent, DW_AttribClass_Flag) \ + X(RefSig8, DW_AttribClass_Reference) \ + X(Strx, DW_AttribClass_String) \ + X(Addrx, DW_AttribClass_Address) \ + X(RefSup4, DW_AttribClass_Reference) \ + X(StrpSup, DW_AttribClass_String) \ + X(Data16, DW_AttribClass_Const) \ + X(LineStrp, DW_AttribClass_String) \ + X(ImplicitConst, DW_AttribClass_Const) \ + X(LocListx, DW_AttribClass_LocListPtr) \ + X(RngListx, DW_AttribClass_RngListPtr) \ + X(RefSup8, DW_AttribClass_Reference) \ + X(Strx1, DW_AttribClass_String) \ + X(Strx2, DW_AttribClass_String) \ + X(Strx3, DW_AttribClass_String) \ + X(Strx4, DW_AttribClass_String) \ + X(Addrx1, DW_AttribClass_Address) \ + X(Addrx2, DW_AttribClass_Address) \ + X(Addrx3, DW_AttribClass_Address) \ + X(Addrx4, DW_AttribClass_Address) + +typedef U64 DW_FormKind; +typedef enum DW_FormEnum +{ + DW_Form_Null, +#define X(_N, _ID) DW_Form_##_N = _ID, + DW_Form_V2_XList(X) + DW_Form_V4_XList(X) + DW_Form_V5_XList(X) +#undef X +} DW_FormEnum; + +//- Attributes DWARF2 + +#define DW_AttribKind_V2_XList(X) \ + X(Sibling, 0x1) \ + X(Location, 0x2) \ + X(Name, 0x3) \ + X(Ordering, 0x9) \ + X(ByteSize, 0xB) \ + X(BitOffset, 0xC) \ + X(BitSize, 0xD) \ + X(StmtList, 0x10) \ + X(LowPc, 0x11) \ + X(HighPc, 0x12) \ + X(Language, 0x13) \ + X(Discr, 0x15) \ + X(DiscrValue, 0x16) \ + X(Visibility, 0x17) \ + X(Import, 0x18) \ + X(StringLength, 0x19) \ + X(CommonReference, 0x1a) \ + X(CompDir, 0x1b) \ + X(ConstValue, 0x1c) \ + X(ContainingType, 0x1d) \ + X(DefaultValue, 0x1e) \ + X(Inline, 0x20) \ + X(IsOptional, 0x21) \ + X(LowerBound, 0x22) \ + X(Producer, 0x25) \ + X(Prototyped, 0x27) \ + X(ReturnAddr, 0x2a) \ + X(StartScope, 0x2c) \ + X(BitStride, 0x2e) \ + X(UpperBound, 0x2f) \ + X(AbstractOrigin, 0x31) \ + X(Accessibility, 0x32) \ + X(AddressClass, 0x33) \ + X(Artificial, 0x34) \ + X(BaseTypes, 0x35) \ + X(CallingConvention, 0x36) \ + X(Count, 0x37) \ + X(DataMemberLocation, 0x38) \ + X(DeclColumn, 0x39) \ + X(DeclFile, 0x3a) \ + X(DeclLine, 0x3b) \ + X(Declaration, 0x3c) \ + X(DiscrList, 0x3d) \ + X(Encoding, 0x3e) \ + X(External, 0x3f) \ + X(FrameBase, 0x40) \ + X(Friend, 0x41) \ + X(IdentifierCase, 0x42) \ + X(MacroInfo, 0x43) \ + X(NameListItem, 0x44) \ + X(Priority, 0x45) \ + X(Segment, 0x46) \ + X(Specification, 0x47) \ + X(StaticLink, 0x48) \ + X(Type, 0x49) \ + X(UseLocation, 0x4a) \ + X(VariableParameter, 0x4b) \ + X(Virtuality, 0x4c) \ + X(VTableElemLocation, 0x4d) + +#define DW_AttribKind_ClassFlags_V2_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const) \ + X(BitOffset, DW_AttribClass_Const) \ + X(BitSize, DW_AttribClass_Const) \ + X(StmtList, DW_AttribClass_Const) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_String|DW_AttribClass_Const|DW_AttribClass_Block) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(StartScope, DW_AttribClass_Const) \ + X(BitStride, DW_AttribClass_Const) /* dwarf-v1 DW_Attrib_stride_size*/ \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Block|DW_AttribClass_Reference) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_Const) \ + X(NameListItem, DW_AttribClass_Block) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_Block|DW_AttribClass_Reference) + +//- Attributes DWARF3 + +#define DW_AttribKind_V3_XList(X) \ + X(Allocated, 0x4e) \ + X(Associated, 0x4f) \ + X(DataLocation, 0x50) \ + X(ByteStride, 0x51) \ + X(EntryPc, 0x52) \ + X(UseUtf8, 0x53) \ + X(Extension, 0x54) \ + X(Ranges, 0x55) \ + X(Trampoline, 0x56) \ + X(CallColumn, 0x57) \ + X(CallFile, 0x58) \ + X(CallLine, 0x59) \ + X(Description, 0x5a) \ + X(BinaryScale, 0x5b) \ + X(DecimalScale, 0x5c) \ + X(Small, 0x5d) \ + X(DecimalSign, 0x5e) \ + X(DigitCount, 0x5f) \ + X(PictureString, 0x60) \ + X(Mutable, 0x61) \ + X(ThreadsScaled, 0x62) \ + X(Explicit, 0x63) \ + X(ObjectPointer, 0x64) \ + X(Endianity, 0x65) \ + X(Elemental, 0x66) \ + X(Pure, 0x67) \ + X(Recursive, 0x68) + +#define DW_AttribKind_ClassFlags_V3_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const) \ + X(BitStride, DW_AttribClass_Const) \ + X(UpperBound, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_LocListPtr) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Block) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Allocated, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_Block) \ + X(ByteStride, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngListPtr) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) + +//- Attributes DWARF4 + +#define DW_AttribKind_V4_XList(X) \ + X(Signature, 0x69) \ + X(MainSubProgram, 0x6a) \ + X(DataBitOffset, 0x6b) \ + X(ConstExpr, 0x6c) \ + X(EnumClass, 0x6d) \ + X(LinkageName, 0x6e) + +#define DW_AttribKind_ClassFlags_V4_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const|DW_AttribClass_RngListPtr) \ + X(BitStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Reference) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Allocated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_ExprLoc) \ + X(ByteStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngListPtr) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) \ + X(Signature, DW_AttribClass_Reference) \ + X(MainSubProgram, DW_AttribClass_Flag) \ + X(DataBitOffset, DW_AttribClass_Const) \ + X(ConstExpr, DW_AttribClass_Flag) \ + X(EnumClass, DW_AttribClass_Flag) \ + X(LinkageName, DW_AttribClass_String) + +//- Attributes DWARF5 + +#define DW_AttribKind_V5_XList(X) \ + X(StringLengthBitSize, 0x6f) \ + X(StringLengthByteSize, 0x70) \ + X(Rank, 0x71) \ + X(StrOffsetsBase, 0x72) \ + X(AddrBase, 0x73) \ + X(RngListsBase, 0x74) \ + X(DwoName, 0x76) \ + X(Reference, 0x77) \ + X(RValueReference, 0x78) \ + X(Macros, 0x79) \ + X(CallAllCalls, 0x7a) \ + X(CallAllSourceCalls, 0x7b) \ + X(CallAllTailCalls, 0x7c) \ + X(CallReturnPc, 0x7d) \ + X(CallValue, 0x7e) \ + X(CallOrigin, 0x7f) \ + X(CallParameter, 0x80) \ + X(CallPc, 0x81) \ + X(CallTailCall, 0x82) \ + X(CallTarget, 0x83) \ + X(CallTargetClobbered, 0x84) \ + X(CallDataLocation, 0x85) \ + X(CallDataValue, 0x86) \ + X(NoReturn, 0x87) \ + X(Alignment, 0x88) \ + X(ExportSymbols, 0x89) \ + X(Deleted, 0x8a) \ + X(Defaulted, 0x8b) \ + X(LocListsBase, 0x8c) + +#define DW_AttribKind_ClassFlags_V5_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const|DW_AttribClass_RngListPtr) \ + X(BitStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Reference) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Allocated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_ExprLoc) \ + X(ByteStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngList) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) \ + X(Signature, DW_AttribClass_Reference) \ + X(MainSubProgram, DW_AttribClass_Flag) \ + X(DataBitOffset, DW_AttribClass_Const) \ + X(ConstExpr, DW_AttribClass_Flag) \ + X(EnumClass, DW_AttribClass_Flag) \ + X(LinkageName, DW_AttribClass_String) \ + X(StringLengthBitSize, DW_AttribClass_Const) \ + X(StringLengthByteSize, DW_AttribClass_Const) \ + X(Rank, DW_AttribClass_Const|DW_AttribClass_ExprLoc) \ + X(StrOffsetsBase, DW_AttribClass_StrOffsetsPtr) \ + X(AddrBase, DW_AttribClass_AddrPtr) \ + X(RngListsBase, DW_AttribClass_RngListPtr) \ + X(DwoName, DW_AttribClass_String) \ + X(Reference, DW_AttribClass_Flag) \ + X(RValueReference, DW_AttribClass_Flag) \ + X(Macros, DW_AttribClass_MacPtr) \ + X(CallAllCalls, DW_AttribClass_Flag) \ + X(CallAllSourceCalls, DW_AttribClass_Flag) \ + X(CallAllTailCalls, DW_AttribClass_Flag) \ + X(CallReturnPc, DW_AttribClass_Address) \ + X(CallValue, DW_AttribClass_ExprLoc) \ + X(CallOrigin, DW_AttribClass_ExprLoc) \ + X(CallParameter, DW_AttribClass_Reference) \ + X(CallPc, DW_AttribClass_Address) \ + X(CallTailCall, DW_AttribClass_Flag) \ + X(CallTarget, DW_AttribClass_ExprLoc) \ + X(CallTargetClobbered, DW_AttribClass_ExprLoc) \ + X(CallDataLocation, DW_AttribClass_ExprLoc) \ + X(CallDataValue, DW_AttribClass_ExprLoc) \ + X(NoReturn, DW_AttribClass_Flag) \ + X(Alignment, DW_AttribClass_Const) \ + X(ExportSymbols, DW_AttribClass_Flag) \ + X(Deleted, DW_AttribClass_Flag) \ + X(Defaulted, DW_AttribClass_Const) \ + X(LocListsBase, DW_AttribClass_LocListPtr) + +//- Attributes GNU + +#define DW_AttribKind_GNU_XList(X) \ + X(GNU_Vector, 0x2107) \ + X(GNU_GuardedBy, 0x2108) \ + X(GNU_PtGuardedBy, 0x2109) \ + X(GNU_Guarded, 0x210a) \ + X(GNU_PtGuarded, 0x210b) \ + X(GNU_LocksExcluded, 0x210c) \ + X(GNU_ExclusiveLocksRequired, 0x210d) \ + X(GNU_SharedLocksRequired, 0x210e) \ + X(GNU_OdrSignature, 0x210f) \ + X(GNU_TemplateName, 0x2110) \ + X(GNU_CallSiteValue, 0x2111) \ + X(GNU_CallSiteDataValue, 0x2112) \ + X(GNU_CallSiteTarget, 0x2113) \ + X(GNU_CallSiteTargetClobbered, 0x2114) \ + X(GNU_TailCall, 0x2115) \ + X(GNU_AllTailCallsSites, 0x2116) \ + X(GNU_AllCallSites, 0x2117) \ + X(GNU_AllSourceCallSites, 0x2118) \ + X(GNU_Macros, 0x2119) \ + X(GNU_Deleted, 0x211a) \ + X(GNU_DwoName, 0x2130) \ + X(GNU_DwoId, 0x2131) \ + X(GNU_RangesBase, 0x2132) \ + X(GNU_AddrBase, 0x2133) \ + X(GNU_PubNames, 0x2134) \ + X(GNU_PubTypes, 0x2135) \ + X(GNU_Discriminator, 0x2136) \ + X(GNU_LocViews, 0x2137) \ + X(GNU_EntryView, 0x2138) \ + X(GNU_DescriptiveType, 0x2302) \ + X(GNU_Numerator, 0x2303) \ + X(GNU_Denominator, 0x2304) \ + X(GNU_Bias, 0x2305) + +#define DW_AttribKind_ClassFlags_GNU_XList(X) \ + X(GNU_Vector, DW_AttribClass_Flag) \ + X(GNU_GuardedBy, DW_AttribClass_Undefined) \ + X(GNU_PtGuardedBy, DW_AttribClass_Undefined) \ + X(GNU_Guarded, DW_AttribClass_Undefined) \ + X(GNU_PtGuarded, DW_AttribClass_Undefined) \ + X(GNU_LocksExcluded, DW_AttribClass_Undefined) \ + X(GNU_ExclusiveLocksRequired, DW_AttribClass_Undefined) \ + X(GNU_SharedLocksRequired, DW_AttribClass_Undefined) \ + X(GNU_OdrSignature, DW_AttribClass_Undefined) \ + X(GNU_TemplateName, DW_AttribClass_Undefined) \ + X(GNU_CallSiteValue, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteDataValue, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteTarget, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteTargetClobbered, DW_AttribClass_ExprLoc) \ + X(GNU_TailCall, DW_AttribClass_Flag) \ + X(GNU_AllTailCallsSites, DW_AttribClass_Flag) \ + X(GNU_AllCallSites, DW_AttribClass_Flag) \ + X(GNU_AllSourceCallSites, DW_AttribClass_Flag) \ + X(GNU_Macros, DW_AttribClass_Flag) \ + X(GNU_Deleted, DW_AttribClass_Undefined) \ + X(GNU_DwoName, DW_AttribClass_String) \ + X(GNU_DwoId, DW_AttribClass_Const) \ + X(GNU_RangesBase, DW_AttribClass_Undefined) \ + X(GNU_AddrBase, DW_AttribClass_AddrPtr) \ + X(GNU_PubNames, DW_AttribClass_Flag) \ + X(GNU_PubTypes, DW_AttribClass_Undefined) \ + X(GNU_Discriminator, DW_AttribClass_Const) \ + X(GNU_LocViews, DW_AttribClass_Undefined) \ + X(GNU_EntryView, DW_AttribClass_Undefined) \ + X(GNU_DescriptiveType, DW_AttribClass_Undefined) \ + X(GNU_Numerator, DW_AttribClass_Undefined) \ + X(GNU_Denominator, DW_AttribClass_Undefined) \ + X(GNU_Bias, DW_AttribClass_Undefined) + +//- Attributes LLVM + +#define DW_AttribKind_LLVM_XList(X) \ + X(LLVM_IncludePath, 0x3e00) \ + X(LLVM_ConfigMacros, 0x3e01) \ + X(LLVM_SysRoot, 0x3e02) \ + X(LLVM_TagOffset, 0x3e03) \ + X(LLVM_ApiNotes, 0x3e07) + +#define DW_AttribKind_ClassFlags_LLVM_XList(X) \ + X(LLVM_IncludePath, DW_AttribClass_String) \ + X(LLVM_ConfigMacros, DW_AttribClass_String) \ + X(LLVM_SysRoot, DW_AttribClass_String) \ + X(LLVM_TagOffset, DW_AttribClass_Undefined) \ + X(LLVM_ApiNotes, DW_AttribClass_String) + +//- Attributes Apple + +#define DW_AttribKind_APPLE_XList(X) \ + X(APPLE_Optimized, 0x3fe1) \ + X(APPLE_Flags, 0x3fe2) \ + X(APPLE_Isa, 0x3fe3) \ + X(APPLE_Block, 0x3fe4) \ + X(APPLE_MajorRuntimeVers, 0x3fe5) \ + X(APPLE_RuntimeClass, 0x3fe6) \ + X(APPLE_OmitFramePtr, 0x3fe7) \ + X(APPLE_PropertyName, 0x3fe8) \ + X(APPLE_PropertyGetter, 0x3fe9) \ + X(APPLE_PropertySetter, 0x3fea) \ + X(APPLE_PropertyAttribute, 0x3feb) \ + X(APPLE_ObjcCompleteType, 0x3fec) \ + X(APPLE_Property, 0x3fed) \ + X(APPLE_ObjDirect, 0x3fee) \ + X(APPLE_Sdk, 0x3fef) + +#define DW_AttribKind_ClassFlags_APPLE_XList(X) \ + X(APPLE_Optimized, DW_AttribClass_Flag) \ + X(APPLE_Flags, DW_AttribClass_Flag) \ + X(APPLE_Isa, DW_AttribClass_Flag) \ + X(APPLE_Block, DW_AttribClass_Undefined) \ + X(APPLE_MajorRuntimeVers, DW_AttribClass_Undefined) \ + X(APPLE_RuntimeClass, DW_AttribClass_Undefined) \ + X(APPLE_OmitFramePtr, DW_AttribClass_Flag) \ + X(APPLE_PropertyName, DW_AttribClass_Undefined) \ + X(APPLE_PropertyGetter, DW_AttribClass_Undefined) \ + X(APPLE_PropertySetter, DW_AttribClass_Undefined) \ + X(APPLE_PropertyAttribute, DW_AttribClass_Undefined) \ + X(APPLE_ObjcCompleteType, DW_AttribClass_Undefined) \ + X(APPLE_Property, DW_AttribClass_Undefined) \ + X(APPLE_ObjDirect, DW_AttribClass_Undefined) \ + X(APPLE_Sdk, DW_AttribClass_String) + +//- Attributes MIPS + +#define DW_AttribKind_MIPS_XList(X) \ + X(MIPS_Fde, 0x2001) \ + X(MIPS_LoopBegin, 0x2002) \ + X(MIPS_TailLoopBegin, 0x2003) \ + X(MIPS_EpilogBegin, 0x2004) \ + X(MIPS_LoopUnrollFactor, 0x2005) \ + X(MIPS_SoftwarePipelineDepth, 0x2006) \ + X(MIPS_LinkageName, 0x2007) \ + X(MIPS_Stride, 0x2008) \ + X(MIPS_AbstractName, 0x2009) \ + X(MIPS_CloneOrigin, 0x200a) \ + X(MIPS_HasInlines, 0x200b) \ + X(MIPS_StrideByte, 0x200c) \ + X(MIPS_StrideElem, 0x200d) \ + X(MIPS_PtrDopeType, 0x200e) \ + X(MIPS_AllocatableDopeType, 0x200f) \ + X(MIPS_AssumedShapeDopeType, 0x2010) \ + X(MIPS_AssumedSize, 0x2011) + +#define DW_AttribKind_ClassFlags_MIPS_XList(X) \ + X(MIPS_Fde, DW_AttribClass_Block) \ + X(MIPS_LoopBegin, DW_AttribClass_Block) \ + X(MIPS_TailLoopBegin, DW_AttribClass_Block) \ + X(MIPS_EpilogBegin, DW_AttribClass_Block) \ + X(MIPS_LoopUnrollFactor, DW_AttribClass_Block) \ + X(MIPS_SoftwarePipelineDepth, DW_AttribClass_Block) \ + X(MIPS_LinkageName, DW_AttribClass_String) \ + X(MIPS_Stride, DW_AttribClass_Block) \ + X(MIPS_AbstractName, DW_AttribClass_String) \ + X(MIPS_CloneOrigin, DW_AttribClass_String) \ + X(MIPS_HasInlines, DW_AttribClass_Reference) \ + X(MIPS_StrideByte, DW_AttribClass_Reference) \ + X(MIPS_StrideElem, DW_AttribClass_Reference) \ + X(MIPS_PtrDopeType, DW_AttribClass_Reference) \ + X(MIPS_AllocatableDopeType, DW_AttribClass_Reference) \ + X(MIPS_AssumedShapeDopeType, DW_AttribClass_Reference) \ + X(MIPS_AssumedSize, DW_AttribClass_Reference) + +typedef U32 DW_AttribKind; +typedef enum DW_AttribKindEnum +{ + DW_Attrib_Null, +#define X(_N,_ID,...) DW_Attrib_##_N = _ID, + DW_AttribKind_V2_XList(X) + DW_AttribKind_V3_XList(X) + DW_AttribKind_V4_XList(X) + DW_AttribKind_V5_XList(X) + DW_AttribKind_GNU_XList(X) + DW_AttribKind_LLVM_XList(X) + DW_AttribKind_APPLE_XList(X) + DW_AttribKind_MIPS_XList(X) +#undef X + DW_Attrib_UserLo = 0x2000, + DW_Attrib_UserHi = 0x3fff +} DW_AttribKindEnum; + +#define DW_AttribTypeEncodingKind_XList(X) \ + X(Null, 0x00) \ + X(Address, 0x01) \ + X(Boolean, 0x02) \ + X(ComplexFloat, 0x03) \ + X(Float, 0x04) \ + X(Signed, 0x05) \ + X(SignedChar, 0x06) \ + X(Unsigned, 0x07) \ + X(UnsignedChar, 0x08) \ + X(ImaginaryFloat, 0x09) \ + X(PackedDecimal, 0x0A) \ + X(NumericString, 0x0B) \ + X(Edited, 0x0C) \ + X(SignedFixed, 0x0D) \ + X(UnsignedFixed, 0x0E) \ + X(DecimalFloat, 0x0F) \ + X(Utf, 0x10) \ + X(Ucs, 0x11) \ + X(Ascii, 0x12) + +typedef U64 DW_AttribTypeEncodingKind; +typedef enum DW_AttribTypeEncodingKindEnum +{ +#define X(_N,_ID) DW_AttribTypeEncodingKind_##_N = _ID, + DW_AttribTypeEncodingKind_XList(X) +#undef X +} DW_AttribTypeEncodingKindEnum; + +#define DW_CallingConventionKind_XList(X) \ + X(DW_CallingConvention_Normal, 0x0) \ + X(DW_CallingConvention_Program, 0x1) \ + X(DW_CallingConvention_NoCall, 0x2) \ + X(DW_CallingConvention_PassByValue, 0x1) \ + X(DW_CallingConvention_PassByReference, 0x2) + +typedef U64 DW_CallingConventionKind; +typedef enum DW_CallingConventionKindEnum +{ +#define X(_N,_ID) DW_CallingConventionKind_##_N = _ID, + DW_CallingConventionKind_XList(X) +#undef X +} DW_CallingConventionKindEnum; + +#define DW_AccessKind_XList(X) \ + X(DW_Access_Public, 0x00) \ + X(DW_Access_Private, 0x01) \ + X(DW_Access_Protected, 0x02) + +typedef U64 DW_AccessKind; +typedef enum DW_AccessKindEnum +{ +#define X(_N,_ID) DW_AccessKind_##_N = _ID, + DW_AccessKind_XList(X) +#undef X +} DW_AccessKindEnum; + +#define DW_VirtualityKind_XList(X) \ + X(None, 0x00) \ + X(Virtual, 0x01) \ + X(PureVirtual, 0x02) + +typedef U64 DW_VirtualityKind; +typedef enum DW_VirtualityEnum +{ +#define X(_N,_ID) DW_VirtualityKind_##_N = _ID, + DW_VirtualityKind_XList(X) +#undef X +} DW_VirtualityEnum; + +#define DW_RngListEntryKind(X) \ + X(EndOfList, 0x00) \ + X(BaseAddressX, 0x01) \ + X(StartxEndx, 0x02) \ + X(StartxLength, 0x03) \ + X(OffsetPair, 0x04) \ + X(BaseAddress, 0x05) \ + X(StartEnd, 0x06) \ + X(StartLength, 0x07) + +typedef U64 DW_RngListEntryKind; +typedef enum DW_RngListEntryKindEnum +{ +#define X(_N,_ID) DW_RngListEntryKind_##_N = _ID, + DW_RngListEntryKind(X) +#undef X +} DW_RngListEntryKindEnum; + +#define DW_LocListEntry_XList(X) \ + X(EndOfList, 0x00) \ + X(BaseAddressX, 0x01) \ + X(StartXEndX, 0x02) \ + X(StartXLength, 0x03) \ + X(OffsetPair, 0x04) \ + X(DefaultLocation, 0x05) \ + X(BaseAddress, 0x06) \ + X(StartEnd, 0x07) \ + X(StartLength, 0x08) + +typedef U64 DW_LocListEntryKind; +typedef enum DW_LocListEntryEnum +{ +#define X(_N,_ID) DW_LocListEntryKind_##_N = _ID, + DW_LocListEntry_XList(X) +#undef X +} DW_LocListEntryEnum; + +#define DW_CompUnitKind_XList(X) \ + X(Reserved, 0) \ + X(Compile, 1) \ + X(Type, 2) \ + X(Partial, 3) \ + X(Skeleton, 4) \ + X(SplitCompile, 5) \ + X(SplitType, 6) + +typedef U8 DW_CompUnitKind; +typedef enum DW_CompUnitKindEnum +{ +#define X(_N, _ID) DW_CompUnitKind_##_N = _ID, + DW_CompUnitKind_XList(X) +#undef X + DW_CompUnitKind_UserLo = 0x80, + DW_CompUnitKind_UserHi = 0xff +} DW_CompUnitKindEnum; + +typedef enum DW_LNCT +{ + DW_LNCT_Path = 0x1, + DW_LNCT_DirectoryIndex = 0x2, + DW_LNCT_TimeStamp = 0x3, + DW_LNCT_Size = 0x4, + DW_LNCT_MD5 = 0x5, + DW_LNCT_UserLo = 0x2000, + DW_LNCT_UserHi = 0x3fff +} DW_LNCT; + +#define DW_CFA_Kind1_XList(X) \ + X(Nop, 0x0) \ + X(SetLoc, 0x1) \ + X(AdvanceLoc1, 0x2) \ + X(AdvanceLoc2, 0x3) \ + X(AdvanceLoc4, 0x4) \ + X(OffsetExt, 0x5) \ + X(RestoreExt, 0x6) \ + X(Undefined, 0x7) \ + X(SameValue, 0x8) \ + X(Register, 0x9) \ + X(RememberState, 0xA) \ + X(RestoreState, 0xB) \ + X(DefCfa, 0xC) \ + X(DefCfaRegister, 0xD) \ + X(DefCfaOffset, 0xE) \ + X(DefCfaExpr, 0xF) \ + X(Expr, 0x10) \ + X(OffsetExtSf, 0x11) \ + X(DefCfaSf, 0x12) \ + X(DefCfaOffsetSf, 0x13) \ + X(ValOffset, 0x14) \ + X(ValOffsetSf, 0x15) \ + X(ValExpr, 0x16) + +#define DW_CFA_Kind2_XList(X) \ + X(AdvanceLoc, 0x40) \ + X(Offset, 0x80) \ + X(Restore, 0xC0) + +typedef U8 DW_CFA; +typedef enum DW_CFAEnum +{ +#define X(_N, _ID) DW_CFA_##_N = _ID, + DW_CFA_Kind1_XList(X) + DW_CFA_Kind2_XList(X) +#undef X + + DW_CFA_OplKind1 = DW_CFA_ValExpr, + DW_CFA_OplKind2 = DW_CFA_Restore, +} DW_CFAEnum; + +typedef U8 DW_CFAMask; +enum +{ + // kind1: opcode: [0,5] zeroes:[6,7]; kind2: operand:[0,5] opcode:[6,7] + DW_CFAMask_OpcodeHi = 0xC0, + DW_CFAMask_Operand = 0x3F, + DW_CFAMask_Count = 2 +}; + +//////////////////////////////// +// Expression Opcodes + +#define DW_Expr_V3_XList(X) \ + X(Null, 0x00) \ + X(Addr, 0x03) \ + X(Deref, 0x06) \ + X(Const1U, 0x08) \ + X(Const1S, 0x09) \ + X(Const2U, 0x0a) \ + X(Const2S, 0x0b) \ + X(Const4U, 0x0c) \ + X(Const4S, 0x0d) \ + X(Const8U, 0x0e) \ + X(Const8S, 0x0f) \ + X(ConstU, 0x10) \ + X(ConstS, 0x11) \ + X(Dup, 0x12) \ + X(Drop, 0x13) \ + X(Over, 0x14) \ + X(Pick, 0x15) \ + X(Swap, 0x16) \ + X(Rot, 0x17) \ + X(XDeref, 0x18) \ + X(Abs, 0x19) \ + X(And, 0x1a) \ + X(Div, 0x1b) \ + X(Minus, 0x1c) \ + X(Mod, 0x1d) \ + X(Mul, 0x1e) \ + X(Neg, 0x1f) \ + X(Not, 0x20) \ + X(Or, 0x21) \ + X(Plus, 0x22) \ + X(PlusUConst, 0x23) \ + X(Shl, 0x24) \ + X(Shr, 0x25) \ + X(Shra, 0x26) \ + X(Xor, 0x27) \ + X(Skip, 0x2f) \ + X(Bra, 0x28) \ + X(Eq, 0x29) \ + X(Ge, 0x2a) \ + X(Gt, 0x2b) \ + X(Le, 0x2c) \ + X(Lt, 0x2d) \ + X(Ne, 0x2e) \ + X(Lit0, 0x30) \ + X(Lit1, 0x31) \ + X(Lit2, 0x32) \ + X(Lit3, 0x33) \ + X(Lit4, 0x34) \ + X(Lit5, 0x35) \ + X(Lit6, 0x36) \ + X(Lit7, 0x37) \ + X(Lit8, 0x38) \ + X(Lit9, 0x39) \ + X(Lit10, 0x3a) \ + X(Lit11, 0x3b) \ + X(Lit12, 0x3c) \ + X(Lit13, 0x3d) \ + X(Lit14, 0x3e) \ + X(Lit15, 0x3f) \ + X(Lit16, 0x40) \ + X(Lit17, 0x41) \ + X(Lit18, 0x42) \ + X(Lit19, 0x43) \ + X(Lit20, 0x44) \ + X(Lit21, 0x45) \ + X(Lit22, 0x46) \ + X(Lit23, 0x47) \ + X(Lit24, 0x48) \ + X(Lit25, 0x49) \ + X(Lit26, 0x4a) \ + X(Lit27, 0x4b) \ + X(Lit28, 0x4c) \ + X(Lit29, 0x4d) \ + X(Lit30, 0x4e) \ + X(Lit31, 0x4f) \ + X(Reg0, 0x50) \ + X(Reg1, 0x51) \ + X(Reg2, 0x52) \ + X(Reg3, 0x53) \ + X(Reg4, 0x54) \ + X(Reg5, 0x55) \ + X(Reg6, 0x56) \ + X(Reg7, 0x57) \ + X(Reg8, 0x58) \ + X(Reg9, 0x59) \ + X(Reg10, 0x5a) \ + X(Reg11, 0x5b) \ + X(Reg12, 0x5c) \ + X(Reg13, 0x5d) \ + X(Reg14, 0x5e) \ + X(Reg15, 0x5f) \ + X(Reg16, 0x60) \ + X(Reg17, 0x61) \ + X(Reg18, 0x62) \ + X(Reg19, 0x63) \ + X(Reg20, 0x64) \ + X(Reg21, 0x65) \ + X(Reg22, 0x66) \ + X(Reg23, 0x67) \ + X(Reg24, 0x68) \ + X(Reg25, 0x69) \ + X(Reg26, 0x6a) \ + X(Reg27, 0x6b) \ + X(Reg28, 0x6c) \ + X(Reg29, 0x6d) \ + X(Reg30, 0x6e) \ + X(Reg31, 0x6f) \ + X(BReg0, 0x70) \ + X(BReg1, 0x71) \ + X(BReg2, 0x72) \ + X(BReg3, 0x73) \ + X(BReg4, 0x74) \ + X(BReg5, 0x75) \ + X(BReg6, 0x76) \ + X(BReg7, 0x77) \ + X(BReg8, 0x78) \ + X(BReg9, 0x79) \ + X(BReg10, 0x7a) \ + X(BReg11, 0x7b) \ + X(BReg12, 0x7c) \ + X(BReg13, 0x7d) \ + X(BReg14, 0x7e) \ + X(BReg15, 0x7f) \ + X(BReg16, 0x80) \ + X(BReg17, 0x81) \ + X(BReg18, 0x82) \ + X(BReg19, 0x83) \ + X(BReg20, 0x84) \ + X(BReg21, 0x85) \ + X(BReg22, 0x86) \ + X(BReg23, 0x87) \ + X(BReg24, 0x88) \ + X(BReg25, 0x89) \ + X(BReg26, 0x8a) \ + X(BReg27, 0x8b) \ + X(BReg28, 0x8c) \ + X(BReg29, 0x8d) \ + X(BReg30, 0x8e) \ + X(BReg31, 0x8f) \ + X(RegX, 0x90) \ + X(FBReg, 0x91) \ + X(BRegX, 0x92) \ + X(Piece, 0x93) \ + X(DerefSize, 0x94) \ + X(XDerefSize, 0x95) \ + X(Nop, 0x96) \ + X(PushObjectAddress, 0x97) \ + X(Call2, 0x98) \ + X(Call4, 0x99) \ + X(CallRef, 0x9a) \ + X(FormTlsAddress, 0x9b) \ + X(CallFrameCfa, 0x9c) \ + X(BitPiece, 0x9d) + +#define DW_Expr_V4_XList(X) \ + X(ImplicitValue, 0x9e) \ + X(StackValue, 0x9f) + +#define DW_Expr_V5_XList(X) \ + X(ImplicitPointer, 0xa0) \ + X(Addrx, 0xa1) \ + X(Constx, 0xa2) \ + X(EntryValue, 0xa3) \ + X(ConstType, 0xa4) \ + X(RegvalType, 0xa5) \ + X(DerefType, 0xa6) \ + X(XderefType, 0xa7) \ + X(Convert, 0xa8) \ + X(ReInterpret, 0xa9) + +#define DW_Expr_GNU_XList(X) \ + X(GNU_PushTlsAddress, 0xe0) \ + X(GNU_UnInit, 0xf0) +typedef U64 DW_ExprOp; +typedef enum DW_ExprOpEnum +{ +#define X(_N, _ID) DW_ExprOp_##_N = _ID, + DW_Expr_V3_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) +#undef X +} DW_ExprOpEnum; + +//- Regs + +#define DW_Regs_X86_XList(X) \ + X(Eax, 0, eax, 0, 4) \ + X(Ecx, 1, ecx, 0, 4) \ + X(Edx, 2, edx, 0, 4) \ + X(Ebx, 3, ebx, 0, 4) \ + X(Esp, 4, esp, 0, 4) \ + X(Ebp, 5, ebp, 0, 4) \ + X(Esi, 6, esi, 0, 4) \ + X(Edi, 7, edi, 0, 4) \ + X(Eip, 8, eip, 0, 4) \ + X(Eflags, 9, eflags, 0, 4) \ + X(Trapno, 10, nil, 0, 0) \ + X(St0, 11, st0, 0, 10) \ + X(St1, 12, st1, 0, 10) \ + X(St2, 13, st2, 0, 10) \ + X(St3, 14, st3, 0, 10) \ + X(St4, 15, st4, 0, 10) \ + X(St5, 16, st5, 0, 10) \ + X(St6, 17, st6, 0, 10) \ + X(St7, 18, st7, 0, 10) \ + X(Xmm0, 21, xmm0, 0, 16) \ + X(Xmm1, 22, xmm1, 0, 16) \ + X(Xmm2, 23, xmm2, 0, 16) \ + X(Xmm3, 24, xmm3, 0, 16) \ + X(Xmm4, 25, xmm4, 0, 16) \ + X(Xmm5, 26, xmm5, 0, 16) \ + X(Xmm6, 27, xmm6, 0, 16) \ + X(Xmm7, 28, xmm7, 0, 16) \ + X(Mm0, 29, mm0, 0, 4) \ + X(Mm1, 30, mm1, 0, 4) \ + X(Mm2, 31, mm2, 0, 4) \ + X(Mm3, 32, mm3, 0, 4) \ + X(Mm4, 33, mm4, 0, 4) \ + X(Mm5, 34, mm5, 0, 4) \ + X(Mm6, 35, mm6, 0, 4) \ + X(Mm7, 36, mm7, 0, 4) \ + X(Fcw, 37, fcw, 0, 2) \ + X(Fsw, 38, fsw, 0, 2) \ + X(Mxcsr, 39, mxcsr, 0, 4) \ + X(Es, 40, es, 0, 2) \ + X(Cs, 41, cs, 0, 2) \ + X(Ss, 42, ss, 0, 2) \ + X(Ds, 43, ds, 0, 2) \ + X(Fs, 44, fs, 0, 2) \ + X(Gs, 45, gs, 0, 2) \ + X(Tr, 48, nil, 0, 0) \ + X(Ldtr, 49, nil, 0, 0) + +#define DW_Regs_X64_XList(X) \ + X(Rax, 0, rax, 0, 8) \ + X(Rdx, 1, rdx, 0, 8) \ + X(Rcx, 2, rcx, 0, 8) \ + X(Rbx, 3, rbx, 0, 8) \ + X(Rsi, 4, rsi, 0, 8) \ + X(Rdi, 5, rdi, 0, 8) \ + X(Rbp, 6, rbp, 0, 8) \ + X(Rsp, 7, rsp, 0, 8) \ + X(R8, 8, r8, 0, 8) \ + X(R9, 9, r9, 0, 8) \ + X(R10, 10, r10, 0, 8) \ + X(R11, 11, r11, 0, 8) \ + X(R12, 12, r12, 0, 8) \ + X(R13, 13, r13, 0, 8) \ + X(R14, 14, r14, 0, 8) \ + X(R15, 15, r15, 0, 8) \ + X(Rip, 16, rip, 0, 8) \ + X(Xmm0, 17, ymm0, 0, 16) \ + X(Xmm1, 18, ymm1, 0, 16) \ + X(Xmm2, 19, ymm2, 0, 16) \ + X(Xmm3, 20, ymm3, 0, 16) \ + X(Xmm4, 21, ymm4, 0, 16) \ + X(Xmm5, 22, ymm5, 0, 16) \ + X(Xmm6, 23, ymm6, 0, 16) \ + X(Xmm7, 24, ymm7, 0, 16) \ + X(Xmm8, 25, ymm8, 0, 16) \ + X(Xmm9, 26, ymm9, 0, 16) \ + X(Xmm10, 27, ymm10, 0, 16) \ + X(Xmm11, 28, ymm11, 0, 16) \ + X(Xmm12, 29, ymm12, 0, 16) \ + X(Xmm13, 30, ymm13, 0, 16) \ + X(Xmm14, 31, ymm14, 0, 16) \ + X(Xmm15, 32, ymm15, 0, 16) \ + X(St0, 33, st0, 0, 10) \ + X(St1, 34, st1, 0, 10) \ + X(St2, 35, st2, 0, 10) \ + X(St3, 36, st3, 0, 10) \ + X(St4, 37, st4, 0, 10) \ + X(St5, 38, st5, 0, 10) \ + X(St6, 39, st6, 0, 10) \ + X(St7, 40, st7, 0, 10) \ + X(Mm0, 41, mm0, 0, 8) \ + X(Mm1, 42, mm1, 0, 8) \ + X(Mm2, 43, mm2, 0, 8) \ + X(Mm3, 44, mm3, 0, 8) \ + X(Mm4, 45, mm4, 0, 8) \ + X(Mm5, 46, mm5, 0, 8) \ + X(Mm6, 47, mm6, 0, 8) \ + X(Mm7, 48, mm7, 0, 8) \ + X(Rflags, 49, rflags, 0, 4) \ + X(Es, 50, es, 0, 2) \ + X(Cs, 51, cs, 0, 2) \ + X(Ss, 52, ss, 0, 2) \ + X(Ds, 53, ds, 0, 2) \ + X(Fs, 54, fs, 0, 2) \ + X(Gs, 55, gs, 0, 2) \ + X(FsBase, 58, nil, 0, 0) \ + X(GsBase, 59, nil, 0, 0) \ + X(Tr, 62, nil, 0, 0) \ + X(Ldtr, 63, nil, 0, 0) + +typedef U32 DW_RegX86; +typedef enum DW_RegX86Enum +{ +#define X(_N,_ID,...) DW_Reg_x86_##_N = _ID, + DW_Regs_X86_XList(X) +#undef X +} DW_RegX86Enum; + +typedef U32 DW_RegX64; +typedef enum DW_RegX64Enum +{ +#define X(_N,_ID,...) DW_Reg_x64_##_N = _ID, + DW_Regs_X64_XList(X) +#undef X +} DW_RegX64Enum; + +//////////////////////////////// + +//- Attrib Class Encodings + +// Speced Encodings +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k); + +// Extensions +internal DW_AttribClass dw_attrib_class_from_attrib_kind_gnu (DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_llvm (DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_mips (DW_AttribKind k); + +internal DW_AttribClass dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind v); + +//- Form Class Encodings + +internal DW_AttribClass dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k); + +internal B32 dw_are_attrib_class_and_form_kind_compatible(DW_Version ver, DW_AttribClass attrib_class, DW_FormKind form_kind); + +//- Section Names + +internal String8 dw_name_string_from_section_kind (DW_SectionKind k); +internal String8 dw_mach_name_string_from_section_kind(DW_SectionKind k); +internal String8 dw_dwo_name_string_from_section_kind (DW_SectionKind k); + +//////////////////////////////// + +internal U64 dw_offset_size_from_mode(DW_Mode mode); + +//////////////////////////////// + +internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib, DW_FormKind form_kind); + +#endif // DWARF_H diff --git a/src/dwarf/dwarf_enum.c b/src/dwarf/dwarf_enum.c new file mode 100644 index 00000000..68b29463 --- /dev/null +++ b/src/dwarf/dwarf_enum.c @@ -0,0 +1,225 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 +dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op) +{ + String8 result = {0}; + + #define X(_N,...) case DW_ExprOp_##_N: result = str8_lit(Stringify(_N)); goto exit; + switch (ext) { + case DW_Ext_Null: break; + case DW_Ext_LLVM: break; + case DW_Ext_APPLE: break; + case DW_Ext_MIPS: break; + case DW_Ext_GNU: DW_Expr_GNU_XList(X); break; + } + + switch (ver) { + case DW_Version_5: { + switch (op) { + DW_Expr_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (op) { + DW_Expr_V4_XList(X) + } + } // fall-through + case DW_Version_3: { + switch (op) { + DW_Expr_V3_XList(X) + } + } // fall-through + case DW_Version_2: + case DW_Version_1: + case DW_Version_Null: + break; + } + #undef X + + result = push_str8f(arena, "%x", op); + +exit:; + return result; +} + +internal String8 +dw_string_from_tag_kind(Arena *arena, DW_TagKind kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_Tag_##_N: return str8_lit(Stringify(_N)); + DW_Tag_V3_XList(X) + DW_Tag_V5_XList(X) + DW_Tag_GNU_XList(X) + #undef X + } + return push_str8f(arena, "%llx", kind); +} + +internal String8 +dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind) +{ + #define X(_N,...) case DW_Attrib_##_N: return str8_lit(Stringify(_N)); + + while (ext) { + U64 z = 64-clz64(ext); + if (z == 0) { + break; + } + U64 flag = 1 << (z-1); + ext &= ~flag; + + switch (flag) { + case DW_Ext_Null: break; + case DW_Ext_GNU: switch (kind) { DW_AttribKind_GNU_XList(X) } break; + case DW_Ext_LLVM: switch (kind) { DW_AttribKind_LLVM_XList(X) } break; + case DW_Ext_APPLE: switch (kind) { DW_AttribKind_APPLE_XList(X) } break; + case DW_Ext_MIPS: switch (kind) { DW_AttribKind_MIPS_XList(X) } break; + default: InvalidPath; break; + } + } + + switch (ver) { + case DW_Version_5: { + switch (kind) { + DW_AttribKind_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (kind) { + DW_AttribKind_V4_XList(X) + } + } // fall-through + case DW_Version_3: { + switch (kind) { + DW_AttribKind_V3_XList(X) + } + } // fall-through + case DW_Version_2: { + switch (kind) { + DW_AttribKind_V2_XList(X) + } + } // fall-through + case DW_Version_1: { + } // fall-through + case DW_Version_Null: break; + } + #undef X + + return str8_zero(); +} + +internal String8 +dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind) +{ + #define X(_N,...) case DW_Form_##_N: return str8_lit(Stringify(_N)); + switch (ver) { + case DW_Version_5: { + switch (kind) { + DW_Form_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (kind) { + DW_Form_V4_XList(X) + } + } // fall-through + case DW_Version_3: + case DW_Version_2: { + switch (kind) { + DW_Form_V2_XList(X) + } + } // fall-through + case DW_Version_Null: break; + } + #undef X + String8 result = push_str8f(arena, "%x", kind); + return result; +} + +internal String8 +dw_string_from_language(Arena *arena, DW_Language kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_Language_##_N: return str8_lit(Stringify(_N)); + DW_Language_XList(X) + #undef X + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_std_opcode(Arena *arena, DW_StdOpcode kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_StdOpcode_##_N: return str8_lit(Stringify(_N)); + DW_StdOpcode_XList(X) + #undef X + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_ext_opcode(Arena *arena, DW_ExtOpcode kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_ExtOpcode_##_N: return str8_lit(Stringify(_N)); + DW_ExtOpcode_XList(X) + #undef X + default: InvalidPath; break; + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_loc_list_entry_kind(Arena *arena, DW_LocListEntryKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_section_kind(Arena *arena, DW_SectionKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_rng_list_entry_kind(Arena *arena, DW_RngListEntryKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_register(Arena *arena, Arch arch, U64 reg_id) +{ + String8 reg_str = str8_zero(); + switch (arch) { + case Arch_Null: break; + case Arch_x86: { + switch (reg_id) { + #define X(_N, _ID, ...) case DW_Reg_x86_##_N: reg_str = str8_lit(Stringify(_ID)); break; + DW_Regs_X86_XList(X) + #undef X + } + } break; + case Arch_x64: { + switch (reg_id) { + #define X(_N, _ID, ...) case DW_Reg_x64_##_N: reg_str = str8_lit(Stringify(_ID)); break; + DW_Regs_X64_XList(X) + #undef X + } + } break; + case Arch_arm32: NotImplemented; break; + case Arch_arm64: NotImplemented; break; + default: InvalidPath; break; + } + if (reg_str.size == 0) { + reg_str = push_str8f(arena, "%#llx", reg_id); + } + return reg_str; +} + diff --git a/src/dwarf/dwarf_enum.h b/src/dwarf/dwarf_enum.h index 6158c409..1bbc3898 100644 --- a/src/dwarf/dwarf_enum.h +++ b/src/dwarf/dwarf_enum.h @@ -1,11 +1,15 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal String8 dw_string_from_expr_op(Arena *arena, DW_ExprOp op); +#ifndef DWARF_ENUM_H +#define DWARF_ENUM_H + +internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op); internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind); -internal String8 dw_string_from_attrib_kind(Arena *arena, DW_AttribKind kind); -internal String8 dw_string_from_form_kind(Arena *arena, DW_FormKind kind); +internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind); +internal String8 dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind); //internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); +#endif // DWARF_ENUM_H diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c index 094ad78c..fe4fd9a1 100644 --- a/src/dwarf/dwarf_expr.c +++ b/src/dwarf/dwarf_expr.c @@ -9,7 +9,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) DW_SimpleLoc result = {DW_SimpleLocKind_Empty}; U8 op = 0; - if (based_range_read(base, range, 0, 1, &op)) { + if (dw_based_range_read(base, range, 0, 1, &op)) { // step params U64 size_param = 0; B32 is_signed = 0; @@ -48,7 +48,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) const_n: { U64 x = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &x); if (is_signed) { x = extend_sign64(x, size_param); @@ -61,7 +61,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(base, range, step_cursor, 8, &offset); U64 x = text_section_base + offset; result.kind = DW_SimpleLocKind_Address; result.addr = x; @@ -70,7 +70,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &x); result.kind = DW_SimpleLocKind_Address; result.addr = x; } break; @@ -78,7 +78,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, (S64*)&x); result.kind = DW_SimpleLocKind_Address; result.addr = x; } break; @@ -106,7 +106,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, ®_idx); result.kind = DW_SimpleLocKind_Register; result.reg_idx = reg_idx; } break; @@ -117,7 +117,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); if (step_cursor + size <= range.max) { result.kind = DW_SimpleLocKind_ValueLong; result.val_long.str = (U8*)base + range.min + step_cursor; @@ -141,15 +141,15 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); result.kind = DW_SimpleLocKind_Empty; } break; case DW_ExprOp_BitPiece: { U64 bit_size = 0, bit_off = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_off); result.kind = DW_SimpleLocKind_Empty; } break; @@ -222,7 +222,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf // decode op U64 op_offset = cursor; U8 op = 0; - if (based_range_read(task_base, task_range, op_offset, 1, &op)) { + if (dw_based_range_read(task_base, task_range, op_offset, 1, &op)) { U64 after_op_off = cursor + 1; // require piece op after 'implicit' location descriptions @@ -267,26 +267,26 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf const_n: { U64 x = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &x); } break; case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 8, &offset); result.flags |= DW_ExprFlag_UsesTextBase; } break; case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &x); } break; case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, (S64*)&x); } break; @@ -295,7 +295,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_FBReg: { S64 offset = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesFrameBase; } break; @@ -312,15 +312,15 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { S64 offset = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesRegisters; } break; case DW_ExprOp_BRegX: { U64 reg_idx = 0; S64 offset = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, ®_idx); - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesRegisters; } break; @@ -334,7 +334,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Pick: { U64 idx = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &idx); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 1, &idx); } break; case DW_ExprOp_Over: @@ -350,7 +350,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_DerefSize: { U64 size = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &size); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 1, &size); result.flags |= DW_ExprFlag_UsesMemory; } break; @@ -394,7 +394,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_PlusUConst: { U64 y = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &y); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &y); } break; case DW_ExprOp_Shl: @@ -418,7 +418,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Bra: { S16 d = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 2, &d); result.flags |= DW_ExprFlag_NonLinearFlow; } break; @@ -427,7 +427,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf callN: { U64 p = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &p); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &p); result.flags |= DW_ExprFlag_UsesCallResolution|DW_ExprFlag_NonLinearFlow; // add to task list @@ -476,7 +476,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, ®_idx); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, ®_idx); last_was_implicit_loc = 1; } break; @@ -486,7 +486,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &size); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &size); if (step_cursor + size > task_range.max) { result.flags |= DW_ExprFlag_BadData; goto finish; @@ -506,7 +506,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &size); result.flags |= DW_ExprFlag_UsesComposite; last_was_implicit_loc = 0; @@ -515,8 +515,8 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_BitPiece: { U64 bit_size = 0; U64 bit_off = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &bit_off); result.flags |= DW_ExprFlag_UsesComposite; last_was_implicit_loc = 0; @@ -590,7 +590,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp // decode op U64 op_offset = cursor; U8 op = 0; - if (based_range_read(base, range, op_offset, 1, &op)) { + if (dw_based_range_read(base, range, op_offset, 1, &op)) { U64 after_op_off = cursor + 1; // require piece op after 'implicit' location descriptions @@ -639,7 +639,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp const_n: { U64 x = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &x); if (is_signed) { x = extend_sign64(x, size_param); } @@ -649,13 +649,13 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(base, range, step_cursor, 8, &offset); // earlier versions of GCC emit TLS offset with DW_ExprOp_Addr. B32 is_text_relative; { U8 next_op = 0; - based_range_read_struct(base, range, step_cursor, &next_op); + dw_based_range_read_struct(base, range, step_cursor, &next_op); is_text_relative = (next_op != DW_ExprOp_GNU_PushTlsAddress); } @@ -677,14 +677,14 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &x); dw_expr__stack_push(scratch.arena, &stack, x); } break; case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, (S64*)&x); dw_expr__stack_push(scratch.arena, &stack, x); } break; @@ -694,7 +694,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_FBReg: { S64 offset = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); if (config->frame_base != 0) { U64 x = *config->frame_base + offset; dw_expr__stack_push(scratch.arena, &stack, x); @@ -718,7 +718,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { S64 offset = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); U64 reg_idx = op - DW_ExprOp_BReg0; DW_RegsX64 *regs = config->regs; if (regs != 0) { @@ -741,8 +741,8 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_BRegX: { U64 reg_idx = 0; S64 offset = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); DW_RegsX64 *regs = config->regs; if (regs != 0) { @@ -779,7 +779,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Pick: { U64 idx = 0; - step_cursor += based_range_read(base, range, step_cursor, 1, &idx); + step_cursor += dw_based_range_read(base, range, step_cursor, 1, &idx); U64 x = dw_expr__stack_pick(&stack, idx); dw_expr__stack_push(scratch.arena, &stack, x); } break; @@ -832,7 +832,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_DerefSize: { U64 raw_size = 0; - step_cursor += based_range_read(base, range, step_cursor, 1, &raw_size); + step_cursor += dw_based_range_read(base, range, step_cursor, 1, &raw_size); U64 size = ClampTop(raw_size, 8); U64 addr = dw_expr__stack_pop(&stack); @@ -983,7 +983,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_PlusUConst: { U64 y = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &y); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &y); U64 z = dw_expr__stack_pop(&stack); U64 x = y + z; dw_expr__stack_push(scratch.arena, &stack, x); @@ -1088,14 +1088,14 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Skip: { S16 d = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &d); step_cursor = step_cursor + d; } break; case DW_ExprOp_Bra: { S16 d = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &d); U64 b = dw_expr__stack_pop(&stack); if (b != 0) { step_cursor = step_cursor + d; @@ -1105,7 +1105,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Call2: { U16 p = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &p); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &p); if (config->call.func != 0) { String8 sub_data = config->call.func(config->call.user_ptr, p); dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); @@ -1119,7 +1119,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Call4: { U32 p = 0; - step_cursor += based_range_read(base, range, step_cursor, 4, &p); + step_cursor += dw_based_range_read(base, range, step_cursor, 4, &p); if (config->call.func != 0) { String8 sub_data = config->call.func(config->call.user_ptr, p); dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); @@ -1165,7 +1165,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, ®_idx); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, ®_idx); stashed_loc.kind = DW_SimpleLocKind_Register; stashed_loc.reg_idx = reg_idx; } break; @@ -1176,7 +1176,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &size); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &size); if (step_cursor + size <= range.max) { void *data = (U8*)base + range.min + step_cursor; stashed_loc.kind = DW_SimpleLocKind_ValueLong; @@ -1216,13 +1216,13 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); bit_size = size*8; } break; case DW_ExprOp_BitPiece: { - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_off); is_bit_loc = 1; } break; } diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index d1919758..ee0df7ef 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -68,61 +68,18 @@ dw_hash_from_string(String8 string) return hash64; } -internal DW_AttribClass -dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib_kind, DW_FormKind form_kind) -{ - // NOTE(rjf): DWARF's spec specifies two mappings: - // (DW_AttribKind) => List(DW_AttribClass) - // (DW_FormKind) => List(DW_AttribClass) - // - // This function's purpose is to find the overlapping class between an - // DW_AttribKind and DW_FormKind. - - DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind); - DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind); - - // rust compiler is busted, it writes version 5 attributes - if(ver == DW_Version_2 && lang == DW_Language_Rust && (attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null)) - { - attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_5, ext, attrib_kind); - form_class = dw_attrib_class_from_form_kind(DW_Version_5, form_kind); - } - - DW_AttribClass result = DW_AttribClass_Null; - if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null) - { - result = DW_AttribClass_Undefined; - - for(U32 i = 0; i < 32; ++i) - { - U32 n = 1u << i; - if((attrib_class & n) != 0 && (form_class & n) != 0) - { - result = ((DW_AttribClass) n); - break; - } - } - - Assert(result != DW_AttribClass_Undefined); - } - - return result; -} - //////////////////////////////// //~ rjf: DWARF-Specific Based Range Reads internal U64 -based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) +dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) { String8 data = str8((U8*)base+range.min, dim_1u64(range)); return str8_deserial_read(data, offset, out, size, 1); } -#define based_range_read_struct(base, range, offset, out) based_range_read(base, range, offset, sizeof(*out), out) - internal String8 -based_range_read_string(void *base, Rng1U64 range, U64 offset) +dw_based_range_read_string(void *base, Rng1U64 range, U64 offset) { String8 data = str8((U8*)base+range.min, dim_1u64(range)); String8 result = {0}; @@ -131,23 +88,33 @@ based_range_read_string(void *base, Rng1U64 range, U64 offset) } internal void * -based_range_ptr(void *base, Rng1U64 range, U64 offset) +dw_based_range_ptr(void *base, Rng1U64 range, U64 offset) { Assert(offset < dim_1u64(range)); U8 *data = (U8*)base + range.min + offset; return data; } +internal void * +dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size) +{ + void *ptr = 0; + if (size > 0 && offset + size <= dim_1u64(range)) { + ptr = dw_based_range_ptr(base, range, offset); + } + return ptr; +} + internal U64 -based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) +dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) { U64 value = 0; U64 bytes_read = 0; U64 shift = 0; U8 byte = 0; - for(U64 read_offset = offset; - based_range_read_struct(base, range, read_offset, &byte) == 1; - read_offset += 1) + for(U64 cursor = offset; + dw_based_range_read_struct(base, range, cursor, &byte) == 1; + cursor += 1) { bytes_read += 1; U8 val = byte & 0x7fu; @@ -166,15 +133,15 @@ based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) } internal U64 -based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) +dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) { - U64 value = 0; + U64 value = 0; U64 bytes_read = 0; - U64 shift = 0; - U8 byte = 0; - for(U64 read_offset = offset; - based_range_read_struct(base, range, read_offset, &byte) == 1; - read_offset += 1) + U64 shift = 0; + U8 byte = 0; + for(U64 cursor = offset; + dw_based_range_read_struct(base, range, cursor, &byte) == 1; + cursor += 1) { bytes_read += 1; U8 val = byte & 0x7fu; @@ -196,26 +163,24 @@ based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) return bytes_read; } -//////////////////////////////// - internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value) { U64 bytes_read = 0; U64 value = 0; U32 first32 = 0; - if(based_range_read_struct(base, range, offset, &first32)) + if(dw_based_range_read_struct(base, range, offset, &first32)) { // NOTE(rjf): DWARF 32-bit => use the first 32 bits as the size. if(first32 != max_U32) { - value = (U64)first32; + value = (U64)first32; bytes_read = sizeof(U32); } // NOTE(rjf): DWARF 64-bit => first 32 are just a marker, use the next 64 bits as the size. - else if(based_range_read_struct(base, range, offset + sizeof(U32), &value)) + else if(dw_based_range_read_struct(base, range, offset + sizeof(U32), &value)) { - value = 0; + value = 0; bytes_read = sizeof(U32) + sizeof(U64); } } @@ -236,7 +201,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); + U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -246,8 +211,8 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 next_off = sub_kind_off; if(id != 0) { - U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); - next_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; total_bytes_read += bytes_read; } @@ -255,7 +220,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U8 has_children = 0; if(id != 0) { - total_bytes_read += based_range_read_struct(base, range, next_off, &has_children); + total_bytes_read += dw_based_range_read_struct(base, range, next_off, &has_children); } //- rjf: fill abbrev @@ -286,8 +251,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); - sub_kind_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); + sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -295,8 +260,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind = 0; U64 next_off = sub_kind_off; { - U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); - next_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; total_bytes_read += bytes_read; } @@ -304,7 +269,7 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 implicit_const = 0; if(sub_kind == DW_Form_ImplicitConst) { - U64 bytes_read = based_range_read_uleb128(base, range, next_off, &implicit_const); + U64 bytes_read = dw_based_range_read_uleb128(base, range, next_off, &implicit_const); total_bytes_read += bytes_read; } @@ -318,8 +283,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW abbrev.id = id; if(sub_kind == DW_Form_ImplicitConst) { - abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; - abbrev.const_value = implicit_const; + abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; + abbrev.const_value = implicit_const; } *out_abbrev = abbrev; } @@ -372,7 +337,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { read_fixed_uint:; U64 value = 0; - bytes_read = based_range_read(base, range, offset, bytes_to_read, &value); + bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &value); form_value.v[0] = value; } break; @@ -381,7 +346,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_Addrx: case DW_Form_LocListx: case DW_Form_RngListx: { U64 value = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &value); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &value); form_value.v[0] = value; } break; @@ -389,7 +354,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_SData: { S64 value = 0; - bytes_read = based_range_read_sleb128(base, range, offset, &value); + bytes_read = dw_based_range_read_sleb128(base, range, offset, &value); form_value.v[0] = value; } break; @@ -400,7 +365,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { read_fixed_uint_skip:; U64 size = 0; - bytes_read = based_range_read(base, range, offset, bytes_to_read, &size); + bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &size); form_value.v[0] = size; form_value.v[1] = offset; bytes_read += size; @@ -410,7 +375,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_Block: { U64 size = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &size); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); form_value.v[0] = size; form_value.v[1] = offset; bytes_read += size; @@ -421,8 +386,8 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { U64 value1 = 0; U64 value2 = 0; - bytes_read += based_range_read_struct(base, range, offset, &value1); - bytes_read += based_range_read_struct(base, range, offset + sizeof(U64), &value2); + bytes_read += dw_based_range_read_struct(base, range, offset, &value1); + bytes_read += dw_based_range_read_struct(base, range, offset + sizeof(U64), &value2); form_value.v[0] = value1; form_value.v[1] = value2; } break; @@ -430,7 +395,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ //- rjf: strings case DW_Form_String: { - String8 string = based_range_read_string(base, range, offset); + String8 string = dw_based_range_read_string(base, range, offset); bytes_read = string.size + 1; U64 string_offset = offset; U64 string_size = (offset + bytes_read) - string_offset; @@ -451,7 +416,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_ExprLoc: { U64 size = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &size); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); form_value.v[0] = offset + bytes_read; form_value.v[1] = size; bytes_read += size; @@ -631,8 +596,8 @@ dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 { U64 v0 = 0; U64 v1 = 0; - read_off += based_range_read(base, rng, read_off, addr_size, &v0); - read_off += based_range_read(base, rng, read_off, addr_size, &v1); + read_off += dw_based_range_read(base, rng, read_off, addr_size, &v0); + read_off += dw_based_range_read(base, rng, read_off, addr_size, &v1); //- rjf: base address entry if((addr_size == 4 && v0 == 0xffffffff) || @@ -681,15 +646,15 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section U64 cu_info_off = 0; U64 cu_info_len = 0; cursor += dw_based_range_read_length(base, rng, cursor, &table_length); - cursor += based_range_read_struct(base, rng, cursor, &unit_version); - cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); + cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); for(;;) { U64 info_off = 0; { - U64 bytes_read = based_range_read(base, rng, cursor, off_size, &info_off); + U64 bytes_read = dw_based_range_read(base, rng, cursor, off_size, &info_off); cursor += bytes_read; if(bytes_read == 0) { @@ -700,7 +665,7 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section //- rjf: if we got a nonzero .debug_info offset, we've found a valid entry. if(info_off != 0) { - String8 string = based_range_read_string(base, rng, cursor); + String8 string = dw_based_range_read_string(base, rng, cursor); cursor += string.size + 1; U64 hash = dw_hash_from_string(string); @@ -727,8 +692,8 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section } cursor += bytes_read; } - cursor += based_range_read_struct(base, rng, cursor, &unit_version); - cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); + cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); } } @@ -759,12 +724,12 @@ dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionK //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse padding U16 padding = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &padding); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &padding); Assert(padding == 0); // must be 0 as of V5. //- rjf: read @@ -803,28 +768,28 @@ dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKi //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse address size U8 address_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); //- rjf: parse segment selector size U8 segment_selector_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); //- rjf: read U64 entry_size = address_size + segment_selector_size; U64 count = (unit_length - sizeof(U16)*2) / entry_size; if(0 <= index && index < count) { - void *entry = (U8 *)based_range_ptr(sec_base, rng, cursor) + entry_size*index; + void *entry = (U8 *)dw_based_range_ptr(sec_base, rng, cursor) + entry_size*index; Rng1U64 entry_rng = rng_1u64(0, entry_size); U64 segment = 0; U64 addr = 0; - based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); - based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); + dw_based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); + dw_based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); result = addr; } @@ -861,24 +826,24 @@ dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sec //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse address size U8 address_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); //- rjf: parse segment selector size U8 segment_selector_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); //- rjf: parse offset entry count U32 offset_entry_count = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); //- rjf: read from offsets array U64 table_off = cursor; - void *offsets_arr = based_range_ptr(sec_base, rng, cursor); + void *offsets_arr = dw_based_range_ptr(sec_base, rng, cursor); if(0 <= index && index < (U64)offset_entry_count) { U64 rnglist_offset = 0; @@ -908,7 +873,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW for(B32 done = 0; !done;) { U8 kind8 = 0; - cursor += based_range_read_struct(base, rng, cursor, &kind8); + cursor += dw_based_range_read_struct(base, rng, cursor, &kind8); DW_RngListEntryKind kind = (DW_RngListEntryKind)kind8; switch(kind) @@ -923,7 +888,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW case DW_RngListEntryKind_BaseAddressX: { U64 base_addr_idx = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &base_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &base_addr_idx); base_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, base_addr_idx); } break; @@ -931,8 +896,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_addr_idx = 0; U64 end_addr_idx = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += based_range_read_uleb128(base, rng, cursor, &end_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_addr_idx); U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); U64 end_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, end_addr_idx); rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); @@ -942,8 +907,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_addr_idx = 0; U64 length = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += based_range_read_uleb128(base, rng, cursor, &length); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); U64 end_addr = start_addr + length; rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); @@ -953,8 +918,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_offset = 0; U64 end_offset = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_offset); - cursor += based_range_read_uleb128(base, rng, cursor, &end_offset); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_offset); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_offset); rng1u64_list_push(arena, &list, rng_1u64(start_offset + base_addr, end_offset + base_addr)); } break; @@ -963,7 +928,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW case DW_RngListEntryKind_BaseAddress: { U64 new_base_addr = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &new_base_addr); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &new_base_addr); base_addr = new_base_addr; } break; @@ -971,8 +936,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start = 0; U64 end = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &start); - cursor += based_range_read(base, rng, cursor, addr_size, &end); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &end); rng1u64_list_push(arena, &list, rng_1u64(start, end)); } break; @@ -980,8 +945,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start = 0; U64 length = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &start); - cursor += based_range_read_uleb128(base, rng, cursor, &length); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); rng1u64_list_push(arena, &list, rng_1u64(start, start+length)); } break; } @@ -1085,7 +1050,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, U64 str_offset = dw_v5_offset_from_offs_section_base_index(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base, str_index); void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, str_offset); + String8 string = dw_based_range_read_string(base, range, str_offset); value.section = section; value.v[0] = str_offset; value.v[1] = value.v[0] + string.size; @@ -1136,7 +1101,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_SectionKind section = DW_Section_Str; void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, form_value.v[0]); + String8 string = dw_based_range_read_string(base, range, form_value.v[0]); value.section = section; value.v[0] = form_value.v[0]; value.v[1] = value.v[0] + string.size; @@ -1147,7 +1112,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_SectionKind section = DW_Section_LineStr; void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, form_value.v[0]); + String8 string = dw_based_range_read_string(base, range, form_value.v[0]); value.section = section; value.v[0] = form_value.v[0]; value.v[1] = value.v[0] + string.size; @@ -1193,7 +1158,7 @@ dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value) Rng1U64 range = dw_range_from_sec(sections, section_kind); String8 string = {0}; - string.str = (U8 *)based_range_ptr(base, range, value.v[0]); + string.str = (U8 *)dw_based_range_ptr(base, range, value.v[0]); string.size = value.v[1] - value.v[0]; return string; } @@ -1236,7 +1201,8 @@ dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_Language lang, U64 address_size, U64 info_off, - U64 abbrev_off) + U64 abbrev_off, + B32 relaxed) { //- rjf: set up prereqs DW_Mode info_mode = sections->v[DW_Section_Info].mode; @@ -1267,18 +1233,17 @@ dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, //- rjf: extract attrib info from abbrev DW_AttribKind attrib_kind = (DW_AttribKind)abbrev.id; DW_FormKind form_kind = (DW_FormKind)abbrev.sub_kind; - DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, attrib_kind, form_kind); + DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, relaxed, attrib_kind, form_kind); //- rjf: parse the form value from the file DW_AttribValue form_value = {0}; if(good_abbrev) { - // NOTE(nick): This is a special case form. Basically it let's user to - // define attribute form in the .debug_info. + // Special case form that allows user to encode attribute form in .debug_info if(form_kind == DW_Form_Indirect) { U64 override_form_kind = 0; - info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); + info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); form_kind = (DW_FormKind)override_form_kind; } U64 bytes_read = dw_based_range_read_attrib_form_value(info_base, info_range, info_read_off, info_mode, address_size, @@ -1314,7 +1279,8 @@ dw_tag_from_info_offset(Arena *arena, DW_Ext ext, DW_Language lang, U64 address_size, - U64 info_offset) + U64 info_offset, + B32 relaxed) { void *info_base = dw_base_from_sec(sections, DW_Section_Info); Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); @@ -1328,7 +1294,7 @@ dw_tag_from_info_offset(Arena *arena, //- rjf: read abbrev ID U64 abbrev_id = 0; - info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); + info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); B32 good_abbrev_id = abbrev_id != 0; //- rjf: figure out abbrev offset for this ID @@ -1356,7 +1322,7 @@ dw_tag_from_info_offset(Arena *arena, DW_AttribList attribs = {0}; if(good_tag_abbrev) { - DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off); + DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off, relaxed); attribs_info_off = info_read_off; attribs_abbrev_off = abbrev_read_off; info_read_off = attribs_parse.max_info_off; @@ -1460,7 +1426,7 @@ dw_v5_header_offset_from_table_offset(DW_SectionArray *sections, DW_SectionKind // rjf: try max header, and if it works, the header is the max size, otherwise we will // need to rely on the min header size U32 first32 = 0; - based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); + dw_based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); if(first32 == max_U32) { header_size = max_header_size; @@ -1501,8 +1467,40 @@ dw_comp_unit_ranges_from_info(Arena *arena, DW_Section info) return result; } +internal DW_Ext +dw_ext_from_params(String8 producer, Arch arch, ImageType image_type) +{ + DW_Ext ext = DW_Ext_Null; + switch (image_type) { + case Image_Null: break; + case Image_COFF_PE: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_LLVM; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU; + } + } break; + case Image_ELF32: + case Image_ELF64: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_LLVM; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU; + } + } break; + case Image_Macho: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_LLVM | DW_Ext_APPLE; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_APPLE; + } + } break; + } + return ext; +} + internal DW_CompRoot -dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) +dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range, B32 relaxed) { Temp scratch = scratch_begin(&arena, 1); @@ -1524,7 +1522,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) B32 got_version = 0; DW_Version version = 0; U64 unit_off = version_off; - if(based_range_read_struct(info_base, range, version_off, &version)) + if(dw_based_range_read_struct(info_base, range, version_off, &version)) { unit_off += sizeof(version); got_version = 1; @@ -1544,28 +1542,28 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) default: break; case DW_Version_2: { abbrev_base = 0; - next_off += based_range_read(info_base, range, next_off, 4, &abbrev_base); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read(info_base, range, next_off, 4, &abbrev_base); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); got_unit_kind = 1; } break; case DW_Version_3: case DW_Version_4: { next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); got_unit_kind = 1; } break; case DW_Version_5: { - next_off += based_range_read_struct(info_base, range, next_off, &unit_kind); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read_struct(info_base, range, next_off, &unit_kind); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); got_unit_kind = 1; //- rjf: parse DWO ID if appropriate if(unit_kind == DW_CompUnitKind_Skeleton || is_info_dwo) { - next_off += based_range_read(info_base, range, next_off, 8, &spec_dwo_id); + next_off += dw_based_range_read(info_base, range, next_off, 8, &spec_dwo_id); } } break; } @@ -1584,7 +1582,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) if(got_unit_kind) { U64 comp_root_tag_off = range.min + next_off; - comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off); + comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off, relaxed); got_comp_unit_tag = 1; } @@ -1630,7 +1628,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) String8 external_dwo_name = {0}; String8 external_gnu_dwo_name = {0}; U64 gnu_dwo_id = 0; - U64 language = 0; + DW_Language language = 0; U64 name_case = 0; B32 use_utf8 = 0; U64 low_pc = 0; @@ -1665,13 +1663,13 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) case DW_Attrib_CompDir: compile_dir = dw_string_from_attrib_value(sections, value); break; case DW_Attrib_DwoName: external_dwo_name = dw_string_from_attrib_value(sections, value); break; case DW_Attrib_GNU_DwoName: external_gnu_dwo_name = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; - case DW_Attrib_Language: language = value.v[0]; break; - case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; - case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; - case DW_Attrib_LowPc: low_pc = value.v[0]; break; + case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; + case DW_Attrib_Language: language = safe_cast_u32(value.v[0]); break; + case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; + case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; + case DW_Attrib_LowPc: low_pc = value.v[0]; break; case DW_Attrib_HighPc: high_pc = value.v[0]; high_pc_is_relative = attrib->value_class != DW_AttribClass_Address; break; - case DW_Attrib_Ranges: ranges_attrib_value = value; break; + case DW_Attrib_Ranges: ranges_attrib_value = value; break; case DW_Attrib_StmtList: line_base = value.v[0]; break; default: break; } @@ -1686,7 +1684,6 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.size = size; unit.kind = unit_kind; unit.version = version; - unit.ext = DW_Ext_Null; unit.address_size = address_size; unit.abbrev_off = abbrev_base; unit.info_off = range.min; @@ -1700,10 +1697,10 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.stroffs_base = resolve_params.debug_str_offs_base; //- rjf: fill out general info - unit.name = name; - unit.producer = producer; - unit.compile_dir = compile_dir; - unit.external_dwo_name = external_dwo_name.size != 0 ? external_dwo_name : external_gnu_dwo_name; + unit.name = name; + unit.producer = producer; + unit.compile_dir = compile_dir; + unit.external_dwo_name = external_dwo_name.size ? external_dwo_name : external_gnu_dwo_name; if(external_dwo_name.size) { unit.dwo_id = spec_dwo_id; @@ -1712,13 +1709,14 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) { unit.dwo_id = gnu_dwo_id; } - unit.language = (DW_Language)language; - unit.name_case = name_case; - unit.use_utf8 = use_utf8; - unit.line_off = line_base; - unit.low_pc = low_pc; - unit.high_pc = high_pc; + unit.language = language; + unit.name_case = name_case; + unit.use_utf8 = use_utf8; + unit.line_off = line_base; + unit.low_pc = low_pc; + unit.high_pc = high_pc; unit.ranges_attrib_value = ranges_attrib_value; + unit.base_addr = unit.low_pc; //- rjf: fill fixup of low/high PC situation if(high_pc_is_relative) @@ -1726,24 +1724,6 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.high_pc += unit.low_pc; } - //- rjf: fill base address - { - unit.base_addr = unit.low_pc; - } - - //- rjf: build+fill directory and file tables - { - DW_Mode line_mode = dw_mode_from_sec(sections, DW_Section_Line); - void *line_base = dw_base_from_sec(sections, DW_Section_Line); - Rng1U64 line_rng = dw_range_from_sec(sections, DW_Section_Line); - DW_LineVMHeader vm_header = {0}; - U64 read_size = dw_read_line_vm_header(arena, line_base, line_rng, unit.line_off, line_mode, sections, &unit, &vm_header); - if (read_size > 0) { - unit.dir_table = vm_header.dir_table; - unit.file_table = vm_header.file_table; - } - } - scratch_end(scratch); return unit; } @@ -1802,8 +1782,7 @@ dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_stat if(seq == 0 || start_of_sequence) { // ERROR! do not emit sequences with only one line... - if (seq) Assert(seq->count > 1); - + Assert(seq && seq->count > 1); seq = dw_push_line_seq(arena, tbl); } @@ -1827,9 +1806,11 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ Rng1U64 line_info_range = dw_range_from_sec(sections, DW_Section_Line); U64 read_off_start = root->line_off - line_info_range.min; U64 cursor = read_off_start; + + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(root); DW_LineVMHeader vm_header = {0}; - cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, root, &vm_header); + cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, resolve_params, root->compile_dir, root->name, &vm_header); //- rjf: prep state for VM DW_LineVMState vm_state = {0}; @@ -1842,7 +1823,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ for (;!error && cursor < vm_header.unit_opl;) { //- rjf: parse opcode U8 opcode = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &opcode); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &opcode); //- rjf: do opcode action switch (opcode) { @@ -1887,7 +1868,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ for(U8 i = 0; i < num_operands; ++i) { U64 operand = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &operand); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &operand); } } else @@ -1913,28 +1894,28 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_AdvancePc: { U64 advance = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &advance); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &advance); dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); } break; case DW_StdOpcode_AdvanceLine: { S64 s = 0; - cursor += based_range_read_sleb128(base, line_info_range, cursor, &s); + cursor += dw_based_range_read_sleb128(base, line_info_range, cursor, &s); vm_state.line += s; } break; case DW_StdOpcode_SetFile: { U64 file_index = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_index); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_index); vm_state.file_index = file_index; } break; case DW_StdOpcode_SetColumn: { U64 column = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &column); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &column); vm_state.column = column; } break; @@ -1957,7 +1938,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_FixedAdvancePc: { U16 operand = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &operand); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &operand); vm_state.address += operand; vm_state.op_index = 0; } break; @@ -1975,7 +1956,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_SetIsa: { U64 v = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); vm_state.isa = v; } break; @@ -1983,10 +1964,10 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_ExtendedOpcode: { U64 length = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &length); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &length); U64 start_off = cursor; U8 extended_opcode = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &extended_opcode); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &extended_opcode); switch (extended_opcode) { case DW_ExtOpcode_EndSequence: @@ -2000,7 +1981,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_SetAddress: { U64 address = 0; - cursor += based_range_read(base, line_info_range, cursor, root->address_size, &address); + cursor += dw_based_range_read(base, line_info_range, cursor, root->address_size, &address); vm_state.address = address; vm_state.op_index = 0; vm_state.busted_seq = address != 0; // !(dbg->acceptable_vrange.min <= address && address < dbg->acceptable_vrange.max); @@ -2008,14 +1989,14 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_DefineFile: { - String8 file_name = based_range_read_string(base, line_info_range, cursor); + String8 file_name = dw_based_range_read_string(base, line_info_range, cursor); U64 dir_index = 0; U64 modify_time = 0; U64 file_size = 0; cursor += file_name.size + 1; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &dir_index); - cursor += based_range_read_uleb128(base, line_info_range, cursor, &modify_time); - cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_size); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &dir_index); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_size); // TODO(rjf): Not fully implemented. By the DWARF V4 spec, the above is // all that needs to be parsed, but the rest of the work that needs to @@ -2030,7 +2011,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_SetDiscriminator: { U64 v = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); vm_state.discriminator = v; } break; @@ -2039,7 +2020,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ U64 num_skip = cursor - (start_off + length); cursor += num_skip; - if (based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { + if (dw_based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { error = 1; } @@ -2051,13 +2032,53 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ return result; } +internal String8 +dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_LineFile *lf = &vm->file_table.v[file_idx]; + String8 dir = vm->dir_table.v[lf->dir_idx]; + PathStyle style = path_style_from_str8(dir); + if (style == PathStyle_Null || style == PathStyle_Relative) { + style = path_style_from_str8(lf->file_name); + } + + String8List path_list = {0}; + + if (str8_match(str8_lit(".."), dir, StringMatchFlag_RightSideSloppy)) { + String8List comp_dir_list = str8_split_path(scratch.arena, vm->dir_table.v[0]); + str8_list_concat_in_place(&path_list, &comp_dir_list); + } + + String8List dir_list = str8_split_path(scratch.arena, dir); + str8_list_concat_in_place(&path_list, &dir_list); + + str8_list_push(scratch.arena, &path_list, lf->file_name); + + str8_path_list_resolve_dots_in_place(&path_list, style); + + String8 path = str8_path_list_join_by_style(arena, &path_list, style); + + scratch_end(scratch); + return path; +} + internal U64 -dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out) +dw_read_line_file(void *line_base, + Rng1U64 line_rng, + U64 line_off, + DW_Mode mode, + DW_SectionArray *sections, + DW_AttribValueResolveParams resolve_params, + U8 address_size, + U64 format_count, + Rng1U64 *formats, + DW_LineFile *line_file_out) { MemoryZeroStruct(line_file_out); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(unit); - U64 line_off_start = line_off; + U64 line_off_start = line_off; for (U64 format_idx = 0; format_idx < format_count; ++format_idx) { DW_LNCT lnct = (DW_LNCT)formats[format_idx].min; @@ -2121,55 +2142,55 @@ dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, } internal U64 -dw_read_line_vm_header(Arena *arena, - void *line_base, - Rng1U64 line_rng, - U64 line_off, - DW_Mode mode, - DW_SectionArray *sections, - DW_CompRoot *unit, - DW_LineVMHeader *header_out) +dw_read_line_vm_header(Arena *arena, + void *line_base, + Rng1U64 line_rng, + U64 line_off, + DW_Mode mode, + DW_SectionArray *sections, + DW_AttribValueResolveParams resolve_params, + String8 compile_dir, + String8 unit_name, + DW_LineVMHeader *header_out) { - U64 line_off_start = line_off; - Temp scratch = scratch_begin(&arena, 1); + + MemoryZeroStruct(header_out); //- rjf: parse unit length - header_out->unit_length = 0; - { - line_off += dw_based_range_read_length(line_base, line_rng, line_off, &header_out->unit_length); - } - - header_out->unit_opl = line_off + header_out->unit_length; + U64 unit_length = 0; + U64 unit_length_size = dw_based_range_read_length(line_base, line_rng, line_off, &unit_length); + header_out->unit_length = unit_length; + header_out->unit_opl = line_off + unit_length + unit_length_size; + + U64 cursor = unit_length_size; + Rng1U64 parse_rng = rng_1u64(line_off, header_out->unit_opl); + //- rjf: parse version and header length - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->version); - - if (header_out->version == DW_Version_5) { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->address_size); - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->segment_selector_size); - } + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->version); + if(header_out->version == DW_Version_5) { - U64 off_size = dw_offset_size_from_mode(mode); - line_off += based_range_read(line_base, line_rng, line_off, off_size, &header_out->header_length); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->address_size); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->segment_selector_size); } + cursor += dw_based_range_read(line_base, parse_rng, cursor, dw_offset_size_from_mode(mode), &header_out->header_length); + //- rjf: calculate program offset - header_out->program_off = line_off + header_out->header_length; + header_out->program_off = parse_rng.min + cursor + header_out->header_length; //- rjf: parse minimum instruction length - { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->min_inst_len); - } + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->min_inst_len); //- rjf: parse max ops for instruction - switch (header_out->version) + switch(header_out->version) { case DW_Version_5: case DW_Version_4: { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->max_ops_for_inst); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->max_ops_for_inst); Assert(header_out->max_ops_for_inst > 0); } break; case DW_Version_3: @@ -2182,88 +2203,89 @@ dw_read_line_vm_header(Arena *arena, } //- rjf: parse rest of program info - based_range_read_struct(line_base, line_rng, line_off + 0 * sizeof(U8), &header_out->default_is_stmt); - based_range_read_struct(line_base, line_rng, line_off + 1 * sizeof(U8), &header_out->line_base); - based_range_read_struct(line_base, line_rng, line_off + 2 * sizeof(U8), &header_out->line_range); - based_range_read_struct(line_base, line_rng, line_off + 3 * sizeof(U8), &header_out->opcode_base); - line_off += 4 * sizeof(U8); - Assert(header_out->opcode_base != 0 && header_out->opcode_base > 0); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->default_is_stmt); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_base); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_range); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->opcode_base); //- rjf: calculate opcode length array - header_out->num_opcode_lens = header_out->opcode_base - 1u; - header_out->opcode_lens = (U8 *)based_range_ptr(line_base, line_rng, line_off); - line_off += header_out->num_opcode_lens * sizeof(U8); + header_out->num_opcode_lens = header_out->opcode_base > 0 ? header_out->opcode_base - 1u : 0; + header_out->opcode_lens = dw_based_range_ptr_size(line_base, parse_rng, cursor, header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0])); + cursor += header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0]); - if (header_out->version == DW_Version_5) { + if(header_out->version == DW_Version_5) + { //- parse directory names U8 directory_entry_format_count = 0; - line_off += based_range_read_struct(line_base, line_rng, line_off, &directory_entry_format_count); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &directory_entry_format_count); Assert(directory_entry_format_count == 1); Rng1U64 *directory_entry_formats = push_array(scratch.arena, Rng1U64, directory_entry_format_count); - for (U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) + for(U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) { U64 content_type_code = 0, form_code = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); directory_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); } + U64 directories_count = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &directories_count); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &directories_count); header_out->dir_table.count = directories_count; header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); - for (U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) + for(U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) { DW_LineFile line_file; - line_off += dw_read_line_file(line_base, - line_rng, - line_off, - mode, - sections, - unit, - header_out->address_size, - directory_entry_format_count, - directory_entry_formats, - &line_file); + cursor += dw_read_line_file(line_base, + parse_rng, + cursor, + mode, + sections, + resolve_params, + header_out->address_size, + directory_entry_format_count, + directory_entry_formats, + &line_file); header_out->dir_table.v[dir_idx] = push_str8_copy(arena, line_file.file_name); } + //- parse file table U8 file_name_entry_format_count = 0; - line_off += based_range_read_struct(line_base, line_rng, line_off, &file_name_entry_format_count); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &file_name_entry_format_count); Rng1U64 *file_name_entry_formats = push_array(scratch.arena, Rng1U64, file_name_entry_format_count); - for (U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) + for(U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) { U64 content_type_code = 0, form_code = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); file_name_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); } + U64 file_names_count = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_names_count); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_names_count); header_out->file_table.count = file_names_count; header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); - for (U64 file_idx = 0; file_idx < file_names_count; ++file_idx) + for(U64 file_idx = 0; file_idx < file_names_count; ++file_idx) { - line_off += dw_read_line_file(line_base, - line_rng, - line_off, - mode, - sections, - unit, - header_out->address_size, - file_name_entry_format_count, - file_name_entry_formats, - &header_out->file_table.v[file_idx]); + cursor += dw_read_line_file(line_base, + parse_rng, + cursor, + mode, + sections, + resolve_params, + header_out->address_size, + file_name_entry_format_count, + file_name_entry_formats, + &header_out->file_table.v[file_idx]); } } - else + else { - String8List dir_list = {0}; - - str8_list_push(scratch.arena, &dir_list, unit->compile_dir); + String8List dir_list = {0}; + str8_list_push(scratch.arena, &dir_list, compile_dir); for (;;) { - String8 dir = based_range_read_string(line_base, line_rng, line_off); - line_off += dir.size + 1; + String8 dir = dw_based_range_read_string(line_base, parse_rng, cursor); + cursor += dir.size + 1; if (dir.size == 0) { break; @@ -2276,25 +2298,25 @@ dw_read_line_vm_header(Arena *arena, //- rjf: push 0-index file (compile file) { DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); - node->file.file_name = unit->name; + node->file.file_name = unit_name; SLLQueuePush(file_list.first, file_list.last, node); file_list.node_count += 1; } - for (;;) + for(;;) { - String8 file_name = based_range_read_string(line_base, line_rng, line_off); + String8 file_name = dw_based_range_read_string(line_base, parse_rng, cursor); U64 dir_index = 0; U64 modify_time = 0; U64 file_size = 0; - line_off += file_name.size + 1; - if (file_name.size == 0) + cursor += file_name.size + 1; + if(file_name.size == 0) { break; } - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &dir_index); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &modify_time); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_size); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &dir_index); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_size); DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); node->file.file_name = file_name; @@ -2309,6 +2331,7 @@ dw_read_line_vm_header(Arena *arena, { header_out->dir_table.count = dir_list.node_count; header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); + String8Node *n = dir_list.first; for(U64 idx = 0; n != 0 && idx < header_out->dir_table.count; idx += 1, n = n->next) { @@ -2319,7 +2342,8 @@ dw_read_line_vm_header(Arena *arena, //- rjf: build file table { header_out->file_table.count = file_list.node_count; - header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + U64 file_idx = 0; DW_LineVMFileNode *file_node = file_list.first; for(; file_node != 0; file_idx += 1, file_node = file_node->next) @@ -2331,10 +2355,8 @@ dw_read_line_vm_header(Arena *arena, } } } - - U64 result = line_off - line_off_start; scratch_end(scratch); - return result; + return cursor; } diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index f7b8b1b2..6cce84b8 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -50,6 +50,7 @@ struct DW_AbbrevTable typedef struct DW_Section DW_Section; struct DW_Section { + String8 name; String8 data; DW_Mode mode; B32 is_dwo; @@ -201,7 +202,6 @@ struct DW_CompRoot U64 size; DW_CompUnitKind kind; DW_Version version; - DW_Ext ext; U64 address_size; U64 abbrev_off; U64 info_off; @@ -228,10 +228,6 @@ struct DW_CompRoot U64 high_pc; DW_AttribValue ranges_attrib_value; U64 base_addr; - - // NOTE(rjf): Line/File Info For This Comp Unit - String8Array dir_table; - DW_LineVMFileArray file_table; }; //////////////////////////////// @@ -314,32 +310,32 @@ struct DW_TagStubList typedef struct DW_LineVMHeader DW_LineVMHeader; struct DW_LineVMHeader { - U64 unit_length; - U64 unit_opl; - U16 version; - U8 address_size; // NOTE(nick): duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. - U8 segment_selector_size; - U64 header_length; - U64 program_off; - U8 min_inst_len; - U8 max_ops_for_inst; - U8 default_is_stmt; - S8 line_base; - U8 line_range; - U8 opcode_base; - U64 num_opcode_lens; - U8 *opcode_lens; - String8Array dir_table; - DW_LineVMFileArray file_table; + U64 unit_length; + U64 unit_opl; + DW_Version version; + U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. + U8 segment_selector_size; + U64 header_length; + U64 program_off; + U8 min_inst_len; + U8 max_ops_for_inst; + U8 default_is_stmt; + S8 line_base; + U8 line_range; + U8 opcode_base; + U64 num_opcode_lens; + U8 *opcode_lens; + String8Array dir_table; + DW_LineVMFileArray file_table; }; typedef struct DW_LineVMState DW_LineVMState; struct DW_LineVMState { - U64 address; // NOTE(nick): Address of a machine instruction. - U32 op_index; // NOTE(nick): This is used by the VLIW instructions to indicate index of operation inside the instruction. + U64 address; // Address of a machine instruction. + U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. - // NOTE(nick): Line table doesn't contain full path to a file, instead + // Line table doesn't contain full path to a file, instead // DWARF encodes path as two indices. First index will point into a directory // table, and second points into a file name table. U32 file_index; @@ -347,10 +343,10 @@ struct DW_LineVMState U32 line; U32 column; - B32 is_stmt; // NOTE(nick): Indicates that "address" points to place suitable for a breakpoint. - B32 basic_block; // NOTE(nick): Indicates that the "address" is inside a basic block. + B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint. + B32 basic_block; // Indicates that the "address" is inside a basic block. - // NOTE(nick): Indicates that "address" points to place where function starts. + // Indicates that "address" points to place where function starts. // Usually prologue is the place where compiler emits instructions to // prepare stack for a function. B32 prologue_end; @@ -421,16 +417,23 @@ struct DW_PubStringsTable //////////////////////////////// //~ rjf: Basic Helpers -internal U64 dw_hash_from_string(String8 string); -internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib, DW_FormKind form_kind); +internal U64 dw_hash_from_string(String8 string); //////////////////////////////// //~ Specific Based Range Helpers -internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); -internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); +#define dw_based_range_read_struct(base, range, offset, out) dw_based_range_read(base, range, offset, sizeof(*out), out) + +internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out); +internal String8 dw_based_range_read_string(void *base, Rng1U64 range, U64 offset); +internal void* dw_based_range_ptr(void *base, Rng1U64 range, U64 offset); +internal void* dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size); +internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value); +internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value); +internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); +internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind); internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind); @@ -473,8 +476,8 @@ internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_a //////////////////////////////// //~ rjf: Tag Parsing -internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off); -internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset); +internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off, B32 relaxed); +internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset, B32 relaxed); internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag); //- rjf: line info @@ -484,8 +487,8 @@ internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_ins internal DW_LineSeqNode* dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); internal DW_LineNode* dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); internal DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root); -internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); -internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, DW_LineVMHeader *header_out); +internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); +internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, String8 compile_dir, String8 unit_name, DW_LineVMHeader *header_out); #endif // DWARF_PARSE_H diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index bf86d59f..2731dd9c 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -338,7 +338,7 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_UData8: size_param = 8; goto ufixed; ufixed: { - based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); after_pointer_off = pointer_off + size_param; } break; @@ -352,7 +352,7 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_SData8:size_param = 8; goto sfixed; sfixed: { - based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); after_pointer_off = pointer_off + size_param; // sign extension U64 sign_bit = size_param*8 - 1; @@ -363,13 +363,13 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_ULEB128: { - U64 size = based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); + U64 size = dw_based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); after_pointer_off = pointer_off + size; } break; case DW_EhPtrEnc_SLEB128: { - U64 size = based_range_read_sleb128(frame_base, frame_range, pointer_off, + U64 size = dw_based_range_read_sleb128(frame_base, frame_range, pointer_off, (S64*)&raw_pointer); after_pointer_off = pointer_off + size; } break; @@ -415,34 +415,34 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off // get version U64 version_off = off; U8 version = 0; - based_range_read(base, range, version_off, 1, &version); + dw_based_range_read(base, range, version_off, 1, &version); // check version if (version == 1 || version == 3) { // read augmentation U64 augmentation_off = version_off + 1; - String8 augmentation = based_range_read_string(base, range, augmentation_off); + String8 augmentation = dw_based_range_read_string(base, range, augmentation_off); // read code align U64 code_align_factor_off = augmentation_off + augmentation.size + 1; U64 code_align_factor = 0; - U64 code_align_factor_size = based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); + U64 code_align_factor_size = dw_based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); // read data align U64 data_align_factor_off = code_align_factor_off + code_align_factor_size; S64 data_align_factor = 0; - U64 data_align_factor_size = based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); + U64 data_align_factor_size = dw_based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); // return address register U64 ret_addr_reg_off = data_align_factor_off + data_align_factor_size; U64 after_ret_addr_reg_off = 0; U64 ret_addr_reg = 0; if (version == 1) { - based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); + dw_based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); after_ret_addr_reg_off = ret_addr_reg_off + 1; } else { - U64 ret_addr_reg_size = based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); + U64 ret_addr_reg_size = dw_based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); after_ret_addr_reg_off = ret_addr_reg_off + ret_addr_reg_size; } @@ -459,7 +459,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off U64 augmentation_size = 0; if (augmentation.size > 0 && augmentation.str[0] == 'z') { has_augmentation_size = 1; - U64 aug_size_size = based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); + U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); after_aug_size_off += aug_size_size; } @@ -476,19 +476,19 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off for (U8 *ptr = augmentation.str + 1, *opl = augmentation.str + augmentation.size; ptr < opl; ++ptr) { switch (*ptr) { case 'L': { - based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); aug_data_cursor += sizeof(lsda_encoding); } break; case 'P': { DW_EhPtrEnc handler_encoding = DW_EhPtrEnc_Omit; - based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); U64 ptr_off = aug_data_cursor + sizeof(handler_encoding); U64 ptr_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, handler_encoding, ptr_off, &handler_ip); aug_data_cursor = ptr_off + ptr_size; } break; case 'R': { - based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); aug_data_cursor += sizeof(addr_encoding); } break; default: { @@ -547,7 +547,7 @@ dw_unwind_parse_fde_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_CIEU if (cie->has_augmentation_size) { // augmentation size U64 augmentation_size = 0; - U64 aug_size_size = based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); + U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); U64 after_aug_size_off = aug_data_off + aug_size_size; // extract lsda (only thing that can actually be in FDE's augmentation data as far as we know) @@ -863,7 +863,7 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin DW_CFAControlBits control_bits = 0; // decode opcode/operand0 - if (!based_range_read(base, range, cfi_off, 1, &opcode)) { + if (!dw_based_range_read(base, range, cfi_off, 1, &opcode)) { result = 1; goto done; } @@ -897,7 +897,7 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin } break; default: { if (d <= 8) { - based_range_read(base, range, decode_cursor, d, out); + dw_based_range_read(base, range, decode_cursor, d, out); o_size = d; } } break; @@ -905,10 +905,10 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); } break; case DW_CFADecode_ULEB128: { - o_size = based_range_read_uleb128(base, range, decode_cursor, out); + o_size = dw_based_range_read_uleb128(base, range, decode_cursor, out); } break; case DW_CFADecode_SLEB128: { - o_size = based_range_read_sleb128(base, range, decode_cursor, (S64*)out); + o_size = dw_based_range_read_sleb128(base, range, decode_cursor, (S64*)out); } break; } decode_cursor += o_size; diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index e1f1f90a..fa555c62 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1677,7 +1677,7 @@ cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13 { CV_C13Line line = raw_lines[line_idx]; result.voffs[line_idx] = sec_base + parsed_lines.sec_off_lo + line.off; - result.line_nums[line_idx] = CV_C13LineFlags_ExtractLineNumber(line.flags); + result.line_nums[line_idx] = CV_C13LineFlags_Extract_LineNumber(line.flags); } // emit voff ender diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 0e2e5c82..03e4e2bc 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3699,9 +3699,9 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) } break; case CV_LeafKind_POINTER: { CV_LeafPointer *ptr = (CV_LeafPointer *) src.data.str; - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs); - U32 ptr_size = CV_PointerAttribs_ExtractSize(ptr->attribs); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(ptr->attribs); (void)ptr_kind; // parse ahead type chain and squash modifiers @@ -4010,7 +4010,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) for (U64 cursor = 0; cursor + sizeof(CV_LeafMethodListMember) <= method_list_leaf.data.size; ) { // parse CodeView method overload info CV_LeafMethodListMember *list_member = (CV_LeafMethodListMember *) (method_list_leaf.data.str + cursor); - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(list_member->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(list_member->attribs); cursor += sizeof(CV_LeafMethodListMember); U32 vftable_offset = 0; if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) { @@ -4037,7 +4037,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) case CV_LeafKind_ONEMETHOD: { // parse CodeView method CV_LeafOneMethod *one_method = (CV_LeafOneMethod *) (src.data.str + cursor); - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(one_method->attribs); cursor += sizeof(CV_LeafOneMethod); U32 vftable_offset = 0; if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) { @@ -4493,21 +4493,21 @@ THREAD_POOL_TASK_FUNC(lnk_find_obj_compiler_info_task) AssertAlways(sizeof(CV_SymCompile) <= symbol.data.size); CV_SymCompile *compile = (CV_SymCompile *)symbol.data.str; comp_info->arch = compile->machine; - comp_info->language = CV_CompileFlags_ExtractLanguage(compile->flags); + comp_info->language = CV_CompileFlags_Extract_Language(compile->flags); comp_info->compiler_name = str8_cstring_capped(compile + 1, symbol.data.str + symbol.data.size); goto exit; } else if (symbol.kind == CV_SymKind_COMPILE2) { AssertAlways(sizeof(CV_SymCompile2) <= symbol.data.size); CV_SymCompile2 *compile2 = (CV_SymCompile2 *)symbol.data.str; comp_info->arch = compile2->machine; - comp_info->language = CV_Compile2Flags_ExtractLanguage(compile2->flags); + comp_info->language = CV_Compile2Flags_Extract_Language(compile2->flags); comp_info->compiler_name = str8_cstring_capped(compile2 + 1, symbol.data.str + symbol.data.size); goto exit; } else if (symbol.kind == CV_SymKind_COMPILE3) { AssertAlways(sizeof(CV_SymCompile3) <= symbol.data.size); CV_SymCompile3 *compile3 = (CV_SymCompile3 *)symbol.data.str; comp_info->arch = compile3->machine; - comp_info->language = CV_Compile3Flags_ExtractLanguage(compile3->flags); + comp_info->language = CV_Compile3Flags_Extract_Language(compile3->flags); comp_info->compiler_name = str8_cstring_capped(compile3 + 1, symbol.data.str + symbol.data.size); goto exit; } @@ -5104,7 +5104,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) CV_LvarAddrGap *gaps = (CV_LvarAddrGap *) (defrange_subfield_register + 1); U64 gap_count = (symbol.data.size - sizeof(*defrange_subfield_register)) / sizeof(gaps[0]); RDI_RegCode reg_rdi = rdi_reg_code_from_cv(comp_info.arch, defrange_subfield_register->reg); - U32 value_pos = CV_DefrangeSubfieldRegister_ExtractParentOffset(defrange_subfield_register->field_offset); + U32 value_pos = CV_DefrangeSubfieldRegister_Extract_ParentOffset(defrange_subfield_register->field_offset); U32 value_size = cv_size_from_reg(comp_info.arch, defrange_subfield_register->reg) - value_pos; Rng1U64 defrange = lnk_virt_range_from_sect_off_size(defrange_subfield_register->range.sec, defrange_subfield_register->range.off, defrange_subfield_register->range.len, task->image_sects, obj, symbol.kind, symbol.offset); Rng1U64List ranges = cv_make_defined_range_list_from_gaps(arena, defrange, gaps, gap_count); diff --git a/src/msvc_crt/msvc_crt.c b/src/msvc_crt/msvc_crt.c index 4927b3c4..a735341d 100644 --- a/src/msvc_crt/msvc_crt.c +++ b/src/msvc_crt/msvc_crt.c @@ -86,6 +86,50 @@ mscrt_parse_func_info(Arena *arena, //////////////////////////////// +internal U64 +mscrt_v4_parse_u32(String8 raw_data, U64 offset, U32 *uint_out) +{ + U64 cursor = offset; + + U8 one = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &one); + + if ((one & 0xF) == 15) { + U8 two = 0, three = 0, four = 0, five = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + cursor += str8_deserial_read_struct(raw_data, cursor, &four); + cursor += str8_deserial_read_struct(raw_data, cursor, &five); + *uint_out = (U32)two | ((U32)three << 8) | ((U32)four << 16) | ((U32)five << 24); + } else if ((one & 0xF) == 7) { + U8 two = 0, three = 0, four = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + cursor += str8_deserial_read_struct(raw_data, cursor, &four); + *uint_out = ((U32)one >> 4) | ((U32)two << 4) | ((U32)three << 12) | ((U32)four << 20); + } else if ((one & 0x7) == 3) { + U8 two = 0, three = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + *uint_out = ((U32)one >> 3) | ((U32)two << 5) | ((U32)three << 13); + } else if ((one & 0x3) == 1) { + U8 two = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + *uint_out = ((U32)one >> 2) | ((U32)two << 6); + } else { + *uint_out = one >> 1; + } + + U64 read_size = cursor - offset; + return read_size; +} + +internal U64 +mscrt_v4_parse_s32(String8 raw_data, U64 offset, S32 *int_out) +{ + return str8_deserial_read_struct(raw_data, offset, int_out); +} + internal U64 mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4 *handler) { @@ -93,15 +137,15 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E cursor += str8_deserial_read_struct(raw_data, cursor, &handler->flags); if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->adjectives); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->adjectives); } if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->type_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->type_voff); } if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_obj_voff); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->catch_obj_voff); } - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_code_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->catch_code_voff); U32 cont_type = (handler->flags & MSCRT_EhHandlerV4Flag_ContVOffMask) >> MSCRT_EhHandlerV4Flag_ContVOffShift; if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) { @@ -109,14 +153,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E case MSCRT_ContV4Type_NoMetadata: break; case MSCRT_ContV4Type_OneFuncRelAddr: { S32 v = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v); handler->catch_funclet_cont_addr[0] = (U64)v; handler->catch_funclet_cont_addr_count = 1; } break; case MSCRT_ContV4Type_TwoFuncRelAddr: { S32 v1 = 0, v2 = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v1); - cursor += str8_deserial_read_struct(raw_data, cursor, &v2); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v1); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v2); handler->catch_funclet_cont_addr[0] = (U64)v1; handler->catch_funclet_cont_addr[1] = (U64)v2; handler->catch_funclet_cont_addr_count = 2; @@ -128,14 +172,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E } break; case MSCRT_ContV4Type_OneFuncRelAddr: { U32 v = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v); handler->catch_funclet_cont_addr[0] = func_voff + (U64)v; handler->catch_funclet_cont_addr_count = 1; } break; case MSCRT_ContV4Type_TwoFuncRelAddr: { U32 v1 = 0, v2 = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v1); - cursor += str8_deserial_read_struct(raw_data, cursor, &v2); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v1); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v2); handler->catch_funclet_cont_addr[0] = func_voff + (U64)v1; handler->catch_funclet_cont_addr[1] = func_voff + (U64)v2; handler->catch_funclet_cont_addr_count = 2; @@ -156,7 +200,7 @@ mscrt_parse_handler_type_v4_array(Arena *arena, { U64 cursor = offset; U32 count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &count); MSCRT_EhHandlerTypeV4 *handlers = 0; if (count) { @@ -179,7 +223,7 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e U64 cursor = offset; U32 type_and_next_off = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &type_and_next_off); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &type_and_next_off); entry_out->type = type_and_next_off & 0x3; entry_out->next_off = type_and_next_off >> 2; @@ -187,11 +231,11 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e switch (entry_out->type) { case MSCRT_UnwindMapV4Type_DtorWithObj: case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: { - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action); - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->object); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &entry_out->object); } break; case MSCRT_UnwindMapV4Type_VOFF: { - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action); } break; case MSCRT_UnwindMapV4Type_NoUW: { // no action and/or object is associated with this type @@ -209,7 +253,7 @@ internal U64 mscrt_parse_unwind_map_v4(Arena *arena, String8 raw_data, U64 off, MSCRT_UnwindMapV4 *map_out) { U64 cursor = off; - cursor += str8_deserial_read_struct(raw_data, cursor, &map_out->count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &map_out->count); map_out->v = push_array(arena, MSCRT_UnwindEntryV4, map_out->count); for (U32 i = 0; i < map_out->count; ++i) { cursor += mscrt_parse_unwind_v4_entry(raw_data, cursor, &map_out->v[i]); @@ -230,17 +274,17 @@ mscrt_parse_try_block_map_array_v4(Arena *arena, U64 cursor = off; U32 try_block_map_count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block_map_count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block_map_count); MSCRT_TryBlockMapV4 *try_block_map = push_array(arena, MSCRT_TryBlockMapV4, try_block_map_count); for (U32 itry = 0; itry < try_block_map_count; ++itry) { MSCRT_TryBlockMapV4 *try_block = &try_block_map[itry]; - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_low); - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_high); - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->catch_high); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_low); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_high); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->catch_high); S32 handler_array_voff = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &handler_array_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler_array_voff); U64 handler_array_foff = coff_foff_from_voff(sections, section_count, (U32)handler_array_voff); mscrt_parse_handler_type_v4_array(arena, raw_data, handler_array_foff, func_voff, &try_block->handlers); @@ -263,7 +307,7 @@ mscrt_parse_ip2state_map_v4(Arena *arena, U64 cursor = off; U32 count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &count); U32 *voffs = push_array(arena, U32, count); S32 *states = push_array(arena, S32, count); @@ -271,13 +315,13 @@ mscrt_parse_ip2state_map_v4(Arena *arena, U32 prev_voff = func_voff; for (U32 i = 0; i < count; ++i) { // virtual offsets are encoded as deltas - cursor += str8_deserial_read_struct(raw_data, cursor, &voffs[i]); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &voffs[i]); voffs[i] += prev_voff; prev_voff = voffs[i]; // states are encoded with +1 to avoid encoding negative integers U32 encoded_state = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &encoded_state); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &encoded_state); states[i] = (S32)encoded_state - 1; } @@ -303,22 +347,22 @@ mscrt_parse_func_info_v4(Arena *arena, MSCRT_FuncInfo32V4 func_info = {0}; cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.header); if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.bbt_flags); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &func_info.bbt_flags); } if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.unwind_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.unwind_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.try_block_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.try_block_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { // TODO: separted IP state map NotImplemented; } else { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.ip_to_state_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.ip_to_state_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.wrt_frame_establisher_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.wrt_frame_establisher_voff); } MSCRT_UnwindMapV4 unwind_map = {0}; @@ -387,8 +431,8 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena, String8 handler_name = str8_zero(); /* TODO: { - SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff); - SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); + UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff); + UnitAccel *unit = syms_group_unit_from_uid(group, uid); SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, handler_voff); handler_name = syms_group_symbol_name_from_sid(temp.arena, group, unit, sid); } diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 2554f8f8..35d3e47d 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -1,6 +1,292 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +// TODO: +// +// Code View: +// [x] Test .debug$S +// [x] Test .debug$T +// +// Test dumper on following sections: +// [x] .debug_abbrev +// [ ] .debug_aranges +// [ ] .debug_frame +// [x] .debug_info +// [x] .debug_line +// [ ] .debug_loc +// [ ] .debug_macinfo +// [ ] .debug_pubnames +// [ ] .debug_pubtypes +// [x] .debug_str +// [x] .debug_ranges +// [ ] .debug_addr +// [ ] .debug_loclists +// [ ] .debug_rnglists +// [ ] .debug_stroffsets +// [ ] .debug_linestr +// [ ] .debug_names +// +// [ ] port ELF dumper from internal repo +// [ ] port COFF/PE resource dumper from internal repo +// [x] hook up RDI symbolizer + +internal void +rd_stderr(char *fmt, ...) +{ + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 f = push_str8fv(scratch.arena, fmt, args); + fprintf(stderr, "%.*s\n", str8_varg(f)); + va_end(args); + scratch_end(scratch); +} + +internal B32 +rd_invoke_rdi_converter(String8 exe_name, String8 exe_data, String8 pdb_path, String8 out_path) +{ + Temp scratch = scratch_begin(0,0); + + P2R_User2Convert user2convert = {0}; + user2convert.input_pdb_name = pdb_path; + user2convert.input_pdb_data = os_data_from_file_path(scratch.arena, pdb_path); + user2convert.input_exe_name = exe_name; + user2convert.input_exe_data = exe_data; + user2convert.output_name = out_path; + user2convert.flags = P2R_ConvertFlag_All; + + P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert); + P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake); + RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); + String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle); + B32 is_rdi_write_ok = os_write_data_list_to_file_path(user2convert.output_name, rdi_blobs); + + scratch_end(scratch); + return is_rdi_write_ok; +} + +internal RDI_Parsed * +rd_rdi_from_pe(Arena *arena, String8 data_path, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDI_Parsed *rdi = 0; + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data); + + // PDB 2.0 + COFF_TimeStamp pdb20_time_stamp = 0; + U32 pdb20_age = 0; + String8 pdb20_path = str8_zero(); + // PDB 7.0 + U32 pdb70_age = 0; + Guid pdb70_guid = {0}; + String8 pdb70_path = str8_zero(); + // RDI + String8 rdi_path = str8_zero(); + Guid rdi_guid = {0}; + if (PE_DataDirectoryIndex_DEBUG < pe.data_dir_count) { + String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); + PE_DebugDirectory *debug_entry = str8_deserial_get_raw_ptr(raw_debug_dir, 0, sizeof(*debug_entry)); + PE_DebugDirectory *debug_entry_opl = debug_entry + raw_debug_dir.size/sizeof(*debug_entry_opl); + for (PE_DebugDirectory *debug_entry_ptr = debug_entry; debug_entry_ptr < debug_entry_opl; ++debug_entry_ptr) { + if (debug_entry_ptr->type == PE_DebugDirectoryType_CODEVIEW) { + U32 cv_magic = 0; + str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv_magic); + + switch (cv_magic) { + case PE_CODEVIEW_PDB20_MAGIC: { + PE_CvHeaderPDB20 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + pdb20_time_stamp = cv.time_stamp; + pdb20_age = cv.age; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb20_path); + } else { + rd_errorf("unable to read PE_CvHeaderPDB20"); + } + } break; + case PE_CODEVIEW_PDB70_MAGIC: { + PE_CvHeaderPDB70 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + pdb70_age = cv.age; + pdb70_guid = cv.guid; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb70_path); + } else { + rd_errorf("unable to read PE_CvHeaderPDB70"); + } + } break; + case PE_CODEVIEW_RDI_MAGIC: { + PE_CvHeaderRDI cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + rdi_guid = cv.guid; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &rdi_path); + } else { + rd_errorf("unable to read PE_CvHeaderRDI"); + } + } break; + default: break; + } + } + } + } + + // convert debug info to RDI + if (!rdi_path.size && (pdb20_path.size || pdb70_path.size)) { + if (pdb20_path.size && pdb70_path.size) { + rd_warningf("multiple PDB paths defined %S, %S (picking first)", pdb70_path, pdb20_path); + } + String8 pdb_path = pdb70_path.size ? pdb70_path : pdb20_path; + String8 out_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(pdb_path)); + B32 is_rdi_ok = rd_invoke_rdi_converter(data_path, raw_data, pdb_path, out_path); + if (is_rdi_ok) { + rdi_path = out_path; + } else { + rd_errorf("unable write RDI to %S", out_path); + } + } + + if (rdi_path.size) { + String8 raw_rdi = os_data_from_file_path(arena, rdi_path); + if (raw_rdi.size > 0) { + rdi = push_array(arena, RDI_Parsed, 1); + + // TODO: check guid + RDI_ParseStatus parse_status = rdi_parse(raw_rdi.str, raw_rdi.size, rdi); + + String8 parse_status_string = str8_zero(); + if (parse_status == RDI_ParseStatus_Good) { + } else if (parse_status == RDI_ParseStatus_HeaderDoesNotMatch) { + parse_status_string = str8_lit("Header does not match"); + } else if (parse_status == RDI_ParseStatus_UnsupportedVersionNumber) { + parse_status_string = str8_lit("Unsupported version number"); + } else if (parse_status == RDI_ParseStatus_InvalidDataSecionLayout) { + parse_status_string = str8_lit("Invalid data section layout"); + } else if (parse_status == RDI_ParseStatus_MissingRequiredSection) { + parse_status_string = str8_lit("Missing required section"); + } else { + parse_status_string = push_str8f(scratch.arena, "unknown parse status code: %u", parse_status); + } + + if (parse_status_string.size) { + rdi = 0; + rd_errorf("RDI parse status(%u): %S", parse_status, parse_status_string); + } + } else { + rd_errorf("unable to open RDI: %S", rdi_path); + } + } + + scratch_end(scratch); + return rdi; +} + +internal String8 +rd_proc_name_from_voff(RDI_Parsed *rdi, U64 voff) +{ + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + RDI_Procedure *proc = rdi_procedure_from_scope(rdi, scope); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, proc->name_string_idx, &name.size); + return name; +} + +internal String8 +rd_format_proc_line(Arena *arena, RDI_Parsed *rdi, U64 voff) +{ + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + RDI_Procedure *proc = rdi_procedure_from_scope(rdi, scope); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, proc->name_string_idx, &name.size); + U64 rel = voff - scope->voff_range_first; + String8 result = str8_zero(); + if (name.size) { + if (rel) { + result = push_str8f(arena, "%S+%llx", name, rel); + } else { + result = push_str8f(arena, "%S", name); + } + } + return result; +} + +internal String8 +rd_path_from_file_path_node_idx(Arena *arena, RDI_Parsed *rdi, U32 file_path_node_idx, PathStyle style) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List parts = {0}; + for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file_path_node_idx); + fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); + fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) { + String8 p; + p.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &p.size); + str8_list_push_front(scratch.arena, &parts, p); + } + String8 path = str8_path_list_join_by_style(arena, &parts, style); + scratch_end(scratch); + return path; +} + +internal RD_Line +rd_line_from_voff(Arena *arena, RDI_Parsed *rdi, U64 voff, PathStyle path_style) +{ + RDI_Line line = rdi_line_from_voff(rdi, voff); + RDI_SourceFile *src_file = rdi_source_file_from_line(rdi, &line); + String8 file_path = rd_path_from_file_path_node_idx(arena, rdi, src_file->file_path_node_idx, path_style); + + RD_Line result = {0}; + result.file_path = file_path; + result.line_num = line.line_num; + + return result; +} + +internal String8 +rd_format_line_from_voff(Arena *arena, RDI_Parsed *rdi, U64 voff, PathStyle path_style) +{ + Temp scratch = scratch_begin(&arena, 1); + RD_Line line = rd_line_from_voff(scratch.arena, rdi, voff, path_style); + String8 result = push_str8f(arena, "%S:%u", line.file_path, line.line_num); + scratch_end(scratch); + return result; +} + +internal B32 +rd_is_pe(String8 raw_data) +{ + PE_DosHeader header = {0}; + str8_deserial_read_struct(raw_data, 0, &header); + return header.magic == PE_DOS_MAGIC; +} + +internal void +rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + char *input_type_string = "???"; + if (coff_is_archive(raw_data)) { + input_type_string = "Archive"; + } else if (coff_is_thin_archive(raw_data)) { + input_type_string = "Thin Archive"; + } else if (coff_is_big_obj(raw_data)) { + input_type_string = "Big Obj"; + } else if (coff_is_obj(raw_data)) { + input_type_string = "Obj"; + } else if (rd_is_pe(raw_data)) { + input_type_string = "COFF/PE"; + } + + DateTime universal_dt = os_now_universal_time(); + DateTime local_dt = os_local_time_from_universal(&universal_dt); + String8 time = push_date_time_string(scratch.arena, &local_dt); + String8 full_path = os_full_path_from_path(scratch.arena, input_path); + rd_printf("# %S, [%s] %S", time, input_type_string, full_path); + + scratch_end(scratch); +} + internal int rd_marker_is_before(void *a, void *b) { @@ -56,8 +342,46 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st return result; } -//////////////////////////////// -//~ Disasm +internal DW_SectionArray +rd_dw_sections_from_coff_section_table(Arena *arena, + String8 raw_image, + U64 string_table_off, + U64 section_count, + COFF_SectionHeader *sections) +{ + DW_SectionArray result = {0}; + B32 sect_status[ArrayCount(result.v)] = {0}; + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ions[i]; + Rng1U64 raw_data_range = rng_1u64(header->foff, header->foff + header->fsize); + String8 name = coff_name_from_section_header(header, raw_image, string_table_off); + + DW_SectionKind s = DW_Section_Null; + B32 is_dwo = 0; + #define X(_K,_L,_M,_W) \ + if (str8_match(name, str8_lit(_L), 0)) { s = DW_Section_##_K; } \ + if (str8_match(name, str8_lit(_M), 0)) { s = DW_Section_##_K; } \ + if (str8_match(name, str8_lit(_W), 0)) { s = DW_Section_##_K; is_dwo = 1; } + DW_SectionKind_XList(X) + #undef X + + if (s != DW_Section_Null) { + if (sect_status[s]) { + rd_warningf("file contains multiple %S sections, picking first", name); + } else { + sect_status[s] = 1; + DW_Section *d = &result.v[s]; + d->name = push_str8_copy(arena, name); + d->data = str8_substr(raw_image, raw_data_range); + d->mode = dim_1u64(raw_data_range) > max_U32 ? DW_Mode_64Bit : DW_Mode_32Bit; + d->is_dwo = is_dwo; + } + } + } + + return result; +} internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) @@ -85,7 +409,7 @@ rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) } internal void -rd_format_disasm(Arena *arena, +rd_print_disasm(Arena *arena, String8List *out, String8 indent, Arch arch, @@ -97,8 +421,8 @@ rd_format_disasm(Arena *arena, { Temp scratch = scratch_begin(&arena, 1); - U64 bytes_buffer_max = 256; - U8 *bytes_buffer = push_array(scratch.arena, U8, bytes_buffer_max); + U64 bytes_buffer_max = 256; + char *bytes_buffer = push_array(scratch.arena, char, bytes_buffer_max); U64 decode_off = 0; U64 marker_cursor = 0; @@ -118,7 +442,7 @@ rd_format_disasm(Arena *arena, for (U64 i = 0; i < disasm_result.size; ++i) { bytes_size += raddbg_snprintf(bytes_buffer + bytes_size, bytes_buffer_max-bytes_size, "%s%02x", i > 0 ? " " : "", to_decode.str[i]); } - bytes = str8(bytes_buffer, bytes_size); + bytes = str8((U8*)bytes_buffer, bytes_size); } // print address marker @@ -149,28 +473,27 @@ rd_format_disasm(Arena *arena, scratch_end(scratch); } -//////////////////////////////// -//~ Raw Data - internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size) { - U64 buf_max = size * 3; - U8 *buf = push_array(arena, U8, buf_max); - U64 buf_size = 0; + U64 buf_max = size * 8; + char *buf = push_array(arena, char, buf_max); + U64 buf_size = 0; + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "{ "); for (U64 i = 0; i < size; ++i) { - buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "%s%02x", i>0 ? " " : "", ptr[i]); + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "%s0x%02x", i>0 ? ", " : "", ptr[i]); } + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, " }"); buf[buf_size] = '\0'; - String8 result = str8(buf, buf_size); + String8 result = str8((U8*)buf, buf_size); return result; } internal void -rd_format_raw_data(Arena *arena, +rd_print_raw_data(Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, @@ -180,7 +503,7 @@ rd_format_raw_data(Arena *arena, { AssertAlways(bytes_per_row > 0); - U8 temp_buffer[1024]; + char temp_buffer[1024]; String8 to_format = raw_data; for (; to_format.size > 0; ) { @@ -190,7 +513,7 @@ rd_format_raw_data(Arena *arena, // offset U64 offset = (U64)(raw_row.str-raw_data.str); - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08x: ", offset); + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08llx: ", offset); // hex for (U64 i = 0; i < raw_row.size; ++i) { @@ -220,10 +543,2053 @@ rd_format_raw_data(Arena *arena, } } -//- CodeView +internal String8List +dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List result = {0}; + for (U64 cursor = 0; cursor < raw_data.size; ) { + U8 op = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &op); + + String8 op_value = str8_zero(); + U64 size_param = 0; + B32 is_signed = 0; + switch (op) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 x = op - DW_ExprOp_Lit0; + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_Const1U:size_param = 1; goto const_n; + case DW_ExprOp_Const2U:size_param = 2; goto const_n; + case DW_ExprOp_Const4U:size_param = 4; goto const_n; + case DW_ExprOp_Const8U:size_param = 8; goto const_n; + case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n; + case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n; + case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n; + case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; + const_n: + { + U64 x = 0; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + if (is_signed){ + U64 bit_shift = (size_param << 3) - 1; + if ((x >> bit_shift) != 0){ + x |= ~((1 << bit_shift) - 1); + } + } + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_Addr: { + U64 addr = 0; + cursor += str8_deserial_read(raw_data, cursor, &addr, address_size, 1); + op_value = push_str8f(scratch.arena, "%#llx", addr); + } break; + + case DW_ExprOp_ConstU: { + U64 x = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_ConstS: { + S64 x = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%lld", x); + } break; + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_idx = op - DW_ExprOp_Reg0; + op_value = push_str8f(scratch.arena, "%S", dw_string_from_register(scratch.arena, arch, reg_idx)); + } break; + + case DW_ExprOp_RegX: { + U64 reg_idx = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + op_value = push_str8f(scratch.arena, "register %llu (%S)", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx)); + } break; + + case DW_ExprOp_ImplicitValue: { + U64 size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &size); + op_value = push_str8f(scratch.arena, "block @ %#llx with size %u", cursor, size); + } break; + + case DW_ExprOp_Piece: { + U64 size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &size); + op_value = push_str8f(scratch.arena, "%u", size); + } break; + + case DW_ExprOp_BitPiece: { + U64 bit_size = 0, bit_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_size); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_off); + op_value = push_str8f(scratch.arena, "bit size %llu, bit offset %llu", bit_size, bit_off); + } break; + + case DW_ExprOp_Pick: { + U8 stack_idx = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &stack_idx); + op_value = push_str8f(scratch.arena, "stack index %u", stack_idx); + } break; + + case DW_ExprOp_PlusUConst: { + U64 addend = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &addend); + op_value = push_str8f(arena, "addend %llu", addend); + } break; + + case DW_ExprOp_Skip: { + S16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + + S64 new_offset = (S64)cursor + x; + if (new_offset >= 0) { + cursor = (U64)new_offset; + op_value = push_str8f(scratch.arena, "constant %lld", x); + } else { + op_value = push_str8f(scratch.arena, "ERROR: negative read offset %lld", new_offset); + } + } break; + + case DW_ExprOp_Bra: { + S16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%d", x); + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_idx = op - DW_ExprOp_BReg0; + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "%S offset %lld", dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + } break; + + case DW_ExprOp_FBReg: { + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "offset %lld", reg_off); + } break; + + case DW_ExprOp_BRegX: { + U64 reg_idx = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "register %u (%S) offset %lld", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + } break; + + case DW_ExprOp_XDerefSize: + case DW_ExprOp_DerefSize: { + U8 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%u", x); + } break; + + case DW_ExprOp_Call2: { + U16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%u", x); + } break; + case DW_ExprOp_Call4: { + U32 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(arena, "%u", x); + } break; + case DW_ExprOp_CallRef: { + U64 x = 0; + if (is_dwarf64) { + cursor += str8_deserial_read(raw_data, cursor, &x, 8, 1); + } else { + cursor += str8_deserial_read(raw_data, cursor, &x, 4, 1); + } + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_CallFrameCfa: + case DW_ExprOp_FormTlsAddress: + case DW_ExprOp_PushObjectAddress: + case DW_ExprOp_Nop: + case DW_ExprOp_Eq: + case DW_ExprOp_Ge: + case DW_ExprOp_Gt: + case DW_ExprOp_Le: + case DW_ExprOp_Lt: + case DW_ExprOp_Ne: + case DW_ExprOp_Shl: + case DW_ExprOp_Shr: + case DW_ExprOp_Shra: + case DW_ExprOp_Xor: + case DW_ExprOp_XDeref: + case DW_ExprOp_Abs: + case DW_ExprOp_And: + case DW_ExprOp_Div: + case DW_ExprOp_Minus: + case DW_ExprOp_Mod: + case DW_ExprOp_Mul: + case DW_ExprOp_Neg: + case DW_ExprOp_Not: + case DW_ExprOp_Or: + case DW_ExprOp_Plus: + case DW_ExprOp_Rot: + case DW_ExprOp_Swap: + case DW_ExprOp_Deref: + case DW_ExprOp_Dup: + case DW_ExprOp_Drop: + case DW_ExprOp_Over: + case DW_ExprOp_StackValue: { + // no operands + } break; + } + + String8 opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, op); + if (op_value.size == 0) { + str8_list_pushf(arena, &result, "DW_OP_%S", opcode_str); + } else { + str8_list_pushf(arena, &result, "DW_OP_%S = %S", opcode_str, op_value); + } + } + scratch_end(scratch); + return result; +} + +internal String8 +dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = dw_string_list_from_expression(scratch.arena, raw_data, address_size, arch, ver, ext, is_dwarf64); + String8 expression = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return expression; +} internal void -cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) +dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 address_bit_size = bit_size_from_arch(arch); + U64 address_size = address_bit_size / 8; + + for (U64 cursor = 0; cursor < raw_data.size; /* empty */) { + DW_CFA opcode = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &opcode); + + U64 operand = 0; + if ((opcode & DW_CFAMask_OpcodeHi) != 0) { + operand = opcode & DW_CFAMask_Operand; + opcode = opcode & DW_CFAMask_OpcodeHi; + } + + switch (opcode) { + case DW_CFA_Nop: { + rd_printf("DW_CFA_nop"); + } break; + case DW_CFA_SetLoc: { + U64 address = 0; + switch (arch) { + case Arch_x64: cursor += dw_unwind_parse_pointer_x64(raw_data.str, rng_1u64(0,raw_data.size), ptr_ctx, cie->addr_encoding, cursor, &address); break; + + default: NotImplemented; break; + } + rd_printf("DW_CFA_set_loc: %#llx", address); + } break; + case DW_CFA_AdvanceLoc1: { + U8 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc1: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_AdvanceLoc2: { + U16 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc2: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_AdvanceLoc4: { + U32 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc4: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_OffsetExt: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_offset_extended: register %llu (%S), offset %+llu", + reg, + dw_string_from_register(arena, arch, reg), + (S64)offset * cie->data_align_factor); + } break; + case DW_CFA_RestoreExt: { + rd_printf("DW_CFA_restore_extended"); + } break; + case DW_CFA_Undefined: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_undefined: %llu", reg); + } break; + case DW_CFA_SameValue: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_same_value: register %llu (%S)", + reg, + dw_string_from_register(scratch.arena, arch, reg)); + } break; + case DW_CFA_Register: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_register: register %llu (%S), offset %+llu", + reg, + dw_string_from_register(scratch.arena, arch, reg), + offset); + } break; + case DW_CFA_RememberState: { + rd_printf("DW_CFA_remember_state"); + } break; + case DW_CFA_RestoreState: { + rd_printf("DW_CFA_restore_state"); + } break; + case DW_CFA_DefCfa: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa: register %llu (%S), offset %llu", + reg, + dw_string_from_register(scratch.arena, arch, reg), + offset); + } break; + case DW_CFA_DefCfaRegister: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_register: %llu (%S)", + reg, + dw_string_from_register(arena, arch, reg)); + } break; + case DW_CFA_DefCfaOffset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa_offset: %llu", offset); + } break; + case DW_CFA_DefCfaExpr: { + U64 block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_def_cfa_expression: %S", + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_Expr: { + U64 reg = 0, block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_expression: register %llu (%S), expression %S", + reg, + dw_string_from_register(scratch.arena, arch, reg), + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_OffsetExtSf: { + U64 reg = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_offset_ext_sf: register %llu (%S), offset %+lld", + reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + } break; + case DW_CFA_DefCfaSf: { + U64 reg = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa_sf: register %llu (%S), offset %+lld", + reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + } break; + case DW_CFA_ValOffset: { + U64 val = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_val_offset: value %llu, offset %+llu", val, offset); + } break; + case DW_CFA_ValOffsetSf: { + U64 val = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_val_offset_sf: value %llu, offset %+lld", val, offset); + } break; + case DW_CFA_ValExpr: { + U64 val = 0; + U64 block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_val_expr: value %+llu, expression %S", + val, + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_AdvanceLoc: { + rd_printf("DW_CFA_advance_loc: %+llu", operand); + } break; + case DW_CFA_Offset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + S64 v = (S64)offset * cie->data_align_factor; + + rd_printf("DW_CFA_offset: register %llu (%S), offset %lld", operand, dw_string_from_register(arena, arch, operand), v); + } break; + case DW_CFA_Restore: { + rd_printf("DW_CFA_restore: register %llu (%S)", operand, dw_string_from_register(scratch.arena, arch, operand)); + } break; + default: { + rd_errorf("unknown CFI opcode %u", opcode); + } break; + } + } + + scratch_end(scratch); +} + +internal String8 +dw_format_eh_ptr_enc(Arena *arena, DW_EhPtrEnc enc) +{ + U8 type = enc & DW_EhPtrEnc_TypeMask; + String8 type_str = str8_lit("NULL"); + switch (type) { + case DW_EhPtrEnc_Ptr: type_str = str8_lit("PTR"); break; + case DW_EhPtrEnc_ULEB128: type_str = str8_lit("ULEB128"); break; + case DW_EhPtrEnc_UData2: type_str = str8_lit("UDATA2"); break; + case DW_EhPtrEnc_UData4: type_str = str8_lit("UDATA4"); break; + case DW_EhPtrEnc_UData8: type_str = str8_lit("UDATA8"); break; + case DW_EhPtrEnc_Signed: type_str = str8_lit("SIGNED"); break; + case DW_EhPtrEnc_SLEB128: type_str = str8_lit("SLEB128"); break; + case DW_EhPtrEnc_SData2: type_str = str8_lit("SDATA2"); break; + case DW_EhPtrEnc_SData4: type_str = str8_lit("SDATA4"); break; + case DW_EhPtrEnc_SData8: type_str = str8_lit("SDATA8"); break; + } + U8 modifier = enc & DW_EhPtrEnc_ModifyMask; + String8 modifier_str = str8_lit("NULL"); + switch (modifier) { + case DW_EhPtrEnc_PcRel: modifier_str = str8_lit("PCREL"); break; + case DW_EhPtrEnc_TextRel: modifier_str = str8_lit("TEXTREL"); break; + case DW_EhPtrEnc_DataRel: modifier_str = str8_lit("DATAREL"); break; + case DW_EhPtrEnc_FuncRel: modifier_str = str8_lit("FUNCREL"); break; + } + String8 indir_str = str8_lit(""); + if (enc & DW_EhPtrEnc_Indirect) { + indir_str = str8_lit("(INDIRECT)"); + } + return push_str8f(arena, "Type: %S, Modifier: %S %S", type_str, modifier_str, indir_str); +} + +internal void +dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx) +{ + Temp scratch = scratch_begin(&arena, 1); + DW_CIEUnpacked cie = {0}; + + for (U64 cursor = 0; cursor < raw_eh_frame.size; ) { + U64 header_offset = cursor; + + U64 length = 0; // doesn't include bytes for size + cursor += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), cursor, &length); + + if (length == 0) { + break; // encountered exit marker + } + + U64 entry_start = cursor; + U64 entry_end = cursor + length; + + U32 entry_id = 0; // always 4-bytes, even when length is encoded as 64-bit integer + cursor += str8_deserial_read_struct(raw_eh_frame, cursor, &entry_id); + + // TODO: fix the freaking DW_EhPtrEnc_PCREL encoding. + // it assumes "frame_base" points to the first byte of .eh_frame + // but here base is start of ELF and we use range to select .eh_frame + // bytes to read, which breaks parsing. + String8 raw_frame = str8_substr(raw_eh_frame, rng_1u64(cursor, cursor + length - sizeof(entry_id))); + Rng1U64 cfi_range = rng_1u64(0,0); + + // CIE + if (entry_id == 0) { + dw_unwind_parse_cie_x64(raw_frame.str, rng_1u64(0,raw_frame.size), ptr_ctx, 0, &cie); + cfi_range = cie.cfi_range; + + rd_printf("CIE @ 0x%X, Length %u", header_offset, length); + rd_indent(); + rd_printf("LSDA Encoding: %S", dw_format_eh_ptr_enc(scratch.arena, cie.lsda_encoding)); + rd_printf("Address Encoding: %S", dw_format_eh_ptr_enc(scratch.arena, cie.addr_encoding)); + rd_printf("Augmentation: %S", cie.augmentation); + rd_printf("Code Align Factor: %llu", cie.code_align_factor); + rd_printf("Data Align Factor: %lld", cie.data_align_factor); + rd_printf("Return Address Register: %u", cie.ret_addr_reg); + rd_printf("Handler IP: %#llx", cie.handler_ip); + rd_unindent(); + } + // FDE + else { + DW_FDEUnpacked fde = {0}; + dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde); + cfi_range = fde.cfi_range; + + // calc parent CIE offset + AssertAlways(entry_start >= entry_id); + U64 cie_offset = entry_start - entry_id; NotImplemented; // TODO: syms_safe_sub_u64(range.min + entry_start, entry_id); + + rd_printf("FDE @ %#llx, Length %u, Parent CIE @ %#llx", header_offset, length, cie_offset); + rd_indent(); + rd_printf("IP Range: %#llx-%#llx", fde.ip_voff_range.min, fde.ip_voff_range.max); + rd_printf("LSDA IP: %#llx", fde.lsda_ip); + rd_unindent(); + } + + // print CFI program + rd_printf("CFI Program:"); + rd_indent(); + + B32 is_dwarf64 = length > max_U32; + String8 raw_cfi = str8_substr(raw_eh_frame, cfi_range); + dw_print_cfi_program(scratch.arena, out, indent, raw_cfi, &cie, ptr_ctx, arch, ver, ext, is_dwarf64); + + rd_unindent(); + rd_newline(); + + // advance to next entry + cursor = entry_end; + } + + scratch_end(scratch); +} + +internal DW_AttribValueResolveParams +rd_dw_resolve_params_from_comp_root(DW_CompRoot comp_root) +{ + DW_AttribValueResolveParams resolve_params = {0}; + resolve_params.version = comp_root.version; + resolve_params.addr_size = comp_root.address_size; + resolve_params.containing_unit_info_off = comp_root.info_off; + resolve_params.debug_addrs_base = comp_root.addrs_base; + resolve_params.debug_rnglists_base = comp_root.rnglist_base; + resolve_params.debug_str_offs_base = comp_root.stroffs_base; + resolve_params.debug_loclists_base = comp_root.loclist_base; + return resolve_params; +} + +internal void +dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + Temp scratch = scratch_begin(&arena, 1); + + Rng1U64List comp_unit_ranges = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + if (comp_unit_ranges.count > 0) { + rd_printf("# %S", sections->v[DW_Section_Info].name); + rd_indent(); + } + + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_ranges.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + + // print comp info + rd_printf("Compilation Unit #%u", comp_idx); + rd_indent(); + rd_printf("Version: %u", comp_root.version); + rd_printf("Address Size: %llu", comp_root.address_size); + rd_printf("Abbrev Offset: %#llx", comp_root.abbrev_off); + rd_printf("Tags Range: %#llx-%#llx (Size %#llx)", comp_root.tags_info_range.min, comp_root.tags_info_range.max, dim_1u64(comp_root.tags_info_range)); + rd_newline(); + + // prase tags + U32 tag_depth = 0; + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + Temp tag_temp = temp_begin(scratch.arena); + + U64 tag_info_off = info_off; + DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + + // advance parse + info_off = tag->info_range.max; + + String8 tag_str = dw_string_from_tag_kind(tag_temp.arena, tag->kind); + rd_printf("<%x><%llx> DW_Tag_%S (Abbrev Number: %llu)", tag_depth, tag_info_off, tag_str, tag->abbrev_id); + rd_indent(); + + // parse attributes + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + Temp attrib_temp = temp_begin(tag_temp.arena); + + DW_Attrib *attrib = &attrib_node->attrib; + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + + String8List attrib_list = {0}; + + // attribute .debug_info offset + str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx> ", attrib->info_off); + + // attribute kind + String8 attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, comp_root.version, ext, attrib->attrib_kind); + if (attrib_kind_str.size == 0) { + if (relaxed) { + attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, DW_Version_Last, ext, attrib->attrib_kind); + } + } + if (attrib_kind_str.size == 0) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "Unknown(%#x) ", attrib->attrib_kind); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "DW_Attrib_%-20S ", attrib_kind_str); + } + + // form kind + String8 form_kind_str = dw_string_from_form_kind(scratch.arena, comp_root.version, attrib->form_kind); + str8_list_pushf(attrib_temp.arena, &attrib_list, "DW_Form_%-15S", form_kind_str); + + switch (attrib->value_class) { + default: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Unknown value class"); + } break; + case DW_AttribClass_Undefined: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Undefined value class"); + } break; + case DW_AttribClass_Address: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_Block: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx %#llx", attrib_value.v[0], attrib_value.v[1]); + } break; + case DW_AttribClass_Const: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + switch (attrib->attrib_kind) { + case DW_Attrib_Language: { + String8 lang_str = dw_string_from_language(attrib_temp.arena, attrib_value.v[0]); + str8_list_pushf(attrib_temp.arena, &attrib_list, " (%S)", lang_str); + } break; + } + } break; + case DW_AttribClass_ExprLoc: { + DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Info); + Rng1U64 sect_range = rng_1u64(0, sections->v[DW_Section_Info].data.size); + Rng1U64 expr_range = rng_1u64(sect_range.min+attrib_value.v[0], sect_range.min+attrib_value.v[0]+attrib_value.v[1]); + String8 raw_expr = str8_substr(sections->v[DW_Section_Info].data, expr_range); + B32 is_dwarf64 = mode == DW_Mode_32Bit ? 1 : 0; + String8 expression = dw_format_expression_single_line(attrib_temp.arena, raw_expr, comp_root.address_size, arch, comp_root.version, ext, is_dwarf64); + str8_list_push(attrib_temp.arena, &attrib_list, expression); + } break; + case DW_AttribClass_Flag: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_LinePtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_LocListPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_MacPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_RngListPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_RngList: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_Reference: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx>", attrib_value.v[0]); + } break; + case DW_AttribClass_String: { + String8 string = dw_string_from_attrib_value(sections, attrib_value); + str8_list_pushf(attrib_temp.arena, &attrib_list, "\"%S\"", string); + } break; + case DW_AttribClass_StrOffsetsPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_AddrPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + } + + String8 print = str8_list_join(attrib_temp.arena, &attrib_list, 0); + rd_printf("%S", print); + + temp_end(attrib_temp); + } + + B32 is_ender_tag = tag->abbrev_id == 0; + + if (tag->has_children) { + if (is_ender_tag) { + rd_errorf("null-tag cannot have children"); + } + rd_indent(); + tag_depth += 1; + } + + if (is_ender_tag) { + if (tag_depth == 0) { + rd_errorf("malformed data detected, too many null tags"); + } else { + rd_unindent(); + tag_depth -= 1; + } + } + + rd_unindent(); + + temp_end(tag_temp); + } + temp_end(comp_temp); + + rd_unindent(); + rd_newline(); + } + + if (comp_unit_ranges.count > 0) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_Section abbrev = sections->v[DW_Section_Abbrev]; + String8 raw_abbrev = abbrev.data; + + if (raw_abbrev.size) { + rd_printf("# %S", sections->v[DW_Section_Abbrev].name); + rd_indent(); + } + + for (U64 cursor = 0; cursor < raw_abbrev.size; ) { + U64 id = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &id); + + if (id == 0) { + continue; // end of abbrev data for CU + } + + Temp temp = temp_begin(scratch.arena); + + U64 tag = 0; + U8 has_children = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &tag); + cursor += str8_deserial_read_struct(raw_abbrev, cursor, &has_children); + + rd_printf("%llu DW_Tag_%S %s", id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "[has children]" : "[no children]"); + rd_indent(); + for (;;) { + U64 attrib_id = 0, form_id = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &attrib_id); + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &form_id); + if (attrib_id == 0) { + break; + } + String8 attrib_str = dw_string_from_attrib_kind(temp.arena, DW_Version_Last, DW_Ext_All, attrib_id); + String8 form_str = dw_string_from_form_kind(temp.arena, DW_Version_Last, form_id); + rd_printf("DW_Attrib_%-20S DW_Form_%S", attrib_str, form_str); + } + rd_unindent(); + + temp_end(temp); + } + + if (raw_abbrev.size) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_line(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Line); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Line); + void *base = dw_base_from_sec(sections, DW_Section_Line); + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + if (dim_1u64(range)) { + rd_printf("# %S", sections->v[DW_Section_Line].name); + rd_indent(); + } + + U64 cursor = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next) { + Temp comp_temp = temp_begin(scratch.arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + U64 line_table_offset = cursor; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + + DW_LineVMHeader vm_header = {0}; + cursor += dw_read_line_vm_header(arena, base, range, cursor, mode, sections, resolve_params, comp_root.compile_dir, comp_root.name, &vm_header); + + if (vm_header.unit_length == 0) { + continue; + } + + rd_printf("Line table offset: %#llx", line_table_offset); + rd_printf("Line table length: %llu", vm_header.unit_length); + rd_printf("Version: %u", vm_header.version); + rd_printf("Address size: %u", vm_header.address_size); + rd_printf("Segment selector size: %u", vm_header.segment_selector_size); + rd_printf("Header length: %llu", vm_header.header_length); + rd_printf("Program offset: %#llx", vm_header.program_off); + rd_printf("Min instruction length: %u", vm_header.min_inst_len); + rd_printf("Max ops for instruction: %u", vm_header.max_ops_for_inst); + rd_printf("Default Is Stmt: %u", vm_header.default_is_stmt); + rd_printf("Line base: %d", vm_header.line_base); + rd_printf("Line range: %u", vm_header.line_range); + rd_printf("Opcode base: %u", vm_header.opcode_base); + rd_printf("Opcode lengths: %S", rd_format_hex_array(comp_temp.arena, vm_header.opcode_lens, vm_header.num_opcode_lens)); + rd_newline(); + + rd_printf("Directory Table:"); + rd_indent(); + rd_printf("%-4s %-8s", "No.", "String"); + for (U64 dir_idx = 0; dir_idx < vm_header.dir_table.count; ++dir_idx) { + rd_printf("%-4llu %S", dir_idx, vm_header.dir_table.v[dir_idx]); + } + rd_unindent(); + rd_newline(); + + rd_printf("File Table:"); + rd_indent(); + rd_printf("%-4s %-8s %-8s %-17s %-8s %-8s", "No.", "DirIdx", "Time", "MD5", "Size", "Name"); + for (U64 file_idx = 0; file_idx < vm_header.file_table.count; ++file_idx) { + DW_LineFile *file = &vm_header.file_table.v[file_idx]; + rd_printf("%-4llu %-8llu %-8llu %08llx-%08llx %-8llu %S", + file_idx, + file->dir_idx, + file->modify_time, + file->md5_digest[0], + file->md5_digest[1], + file->file_size, + file->file_name); + } + rd_unindent(); + rd_newline(); + + B32 end_of_seq = 0; + DW_LineVMState vm_state = {0}; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + + rd_printf("Opcodes:"); + for (; cursor < vm_header.unit_opl; ) { + U64 opcode_offset = cursor; + + Temp opcode_temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // parse opcode + U8 opcode = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &opcode); + + // push opcode id + String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, opcode); + str8_list_push(arena, &list, opcode_str); + + // format operands + switch (opcode) { + default: { + if (opcode >= vm_header.opcode_base) { + U32 adjusted_opcode = 0; + U32 op_advance = 0; + S32 line_advance = 0; + U64 addr_advance = 0; + if (vm_header.line_range > 0 && vm_header.max_ops_for_inst > 0) { + adjusted_opcode = (U32)(opcode - vm_header.opcode_base); + op_advance = adjusted_opcode / vm_header.line_range; + line_advance = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; + addr_advance = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); + } + + vm_state.address += addr_advance; + vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; + vm_state.line = (U32)((S32)vm_state.line + line_advance); + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + vm_state.discriminator = 0; + + end_of_seq = 0; + + str8_list_pushf(opcode_temp.arena, &list, "advance line by %d, advance address by %lld", line_advance, addr_advance); + } else { + if (opcode > 0 && opcode <= vm_header.num_opcode_lens) { + str8_list_pushf(opcode_temp.arena, &list, "skip operands:"); + U64 num_operands = vm_header.opcode_lens[opcode - 1]; + for (U8 i = 0; i < num_operands; i += 1){ + U64 operand = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &operand); + str8_list_pushf(opcode_temp.arena, &list, " %llx", operand); + } + } + } + }break; + + case DW_StdOpcode_Copy: { + str8_list_pushf(opcode_temp.arena, &list, "Line = %u, Column = %u, Address = %#llx", vm_state.line, vm_state.column, vm_state.address); + end_of_seq = 0; + vm_state.discriminator = 0; + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + } break; + case DW_StdOpcode_AdvancePc: { + U64 advance = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &advance); + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &list, "advance %#llx ; current address %#llx", advance, vm_state.address); + } break; + + case DW_StdOpcode_AdvanceLine: { + S64 advance = 0; + cursor += dw_based_range_read_sleb128(base, range, cursor, &advance); + vm_state.line += advance; + str8_list_pushf(opcode_temp.arena, &list, "advance %lld ; current line %u", advance, vm_state.line); + } break; + + case DW_StdOpcode_SetFile: { + U64 file_idx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &file_idx); + vm_state.file_index = file_idx; + + String8 path = dw_path_from_file_idx(opcode_temp.arena, &vm_header, file_idx); + str8_list_pushf(opcode_temp.arena, &list, "%llu \"%S\"", file_idx, path); + } break; + + case DW_StdOpcode_SetColumn: { + U64 column = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &column); + vm_state.column = column; + str8_list_pushf(opcode_temp.arena, &list, "%llu", column); + } break; + + case DW_StdOpcode_NegateStmt: { + vm_state.is_stmt = !vm_state.is_stmt; + str8_list_pushf(opcode_temp.arena, &list, "is_stmt = %u", vm_state.is_stmt); + } break; + + case DW_StdOpcode_SetBasicBlock: { + vm_state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: { + U64 advance = (0xffu - vm_header.opcode_base)/vm_header.line_range; + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &list, "%lld ; address %#llx", advance, vm_state.address); + }break; + + case DW_StdOpcode_FixedAdvancePc: { + U64 operand = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &operand); + vm_state.address += operand; + vm_state.op_index = 0; + str8_list_pushf(opcode_temp.arena, &list, "%llu", operand); + } break; + + case DW_StdOpcode_SetPrologueEnd: { + vm_state.prologue_end = 1; + } break; + + case DW_StdOpcode_SetEpilogueBegin: { + vm_state.epilogue_begin = 1; + } break; + + case DW_StdOpcode_SetIsa: { + U64 v = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &v); + vm_state.isa = v; + str8_list_pushf(opcode_temp.arena, &list, "%llu", v); + } break; + + case DW_StdOpcode_ExtendedOpcode: { + U64 length = 0; + U8 ext_opcode = 0; + + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + U64 opcode_end = cursor + length; + + cursor += dw_based_range_read_struct(base, range, cursor, &ext_opcode); + + String8 ext_opcode_str = dw_string_from_ext_opcode(opcode_temp.arena, ext_opcode); + //str8_list_pushf(opcode_temp.arena, &list, "length: %u", length); + str8_list_push(opcode_temp.arena, &list, ext_opcode_str); + switch (ext_opcode) { + case DW_ExtOpcode_EndSequence: { + vm_state.end_sequence = 1; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + end_of_seq = 1; + } break; + case DW_ExtOpcode_SetAddress: { + U64 address = 0; + cursor += dw_based_range_read(base, range, cursor, comp_root.address_size, &address); + vm_state.address = address; + vm_state.op_index = 0; + vm_state.busted_seq = address != 0; + str8_list_pushf(opcode_temp.arena, &list, "%#llx", address); + } break; + case DW_ExtOpcode_DefineFile: { + String8 file_name = dw_based_range_read_string(base, range, cursor); + cursor += file_name.size + 1; + U64 dir_idx = 0, modify_time = 0, file_size = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &dir_idx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(base, range, cursor, &file_size); + str8_list_pushf(opcode_temp.arena, &list, "%S Dir: %llu, Time: %llu, Size: %llu", file_name, dir_idx, modify_time, file_size); + } break; + case DW_ExtOpcode_SetDiscriminator: { + U64 v = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &v); + vm_state.discriminator = v; + str8_list_pushf(arena, &list, "%llu", v); + } break; + } + + cursor = opcode_end; + } break; + } + + String8 string = str8_list_join(opcode_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("[%08llx] %S", opcode_offset, string); + + temp_end(opcode_temp); + } + temp_end(comp_temp); + + rd_newline(); + } + + if (dim_1u64(range)) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + String8 data = sections->v[DW_Section_Str].data; + rd_printf("# %S", sections->v[DW_Section_Str].name); + rd_indent(); + for (U64 cursor = 0, read_size = 0; cursor < data.size; cursor += read_size) { + String8 string = {0}; + read_size = str8_deserial_read_cstr(data, cursor, &string); + rd_printf("[%08llx] { %llu, \"%S\" }", cursor, string.size, string); + } + rd_unindent(); +} + +internal void +dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + DW_Section info = sections->v[DW_Section_Info]; + DW_Section loc = sections->v[DW_Section_Loc]; + + if (loc.data.size == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_Loc].name); + rd_indent(); + + // TODO: warn about overlaps in ranges + + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, info); + + // parse debug_info for attributes with LOCLIST and store .debug_loc offsets + U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); + DW_Version *ver_arr = push_array(scratch.arena, DW_Version, comp_unit_range_list.count); + DW_Ext *ext_arr = push_array(scratch.arena, DW_Ext, comp_unit_range_list.count); + + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Temp comp_temp = temp_begin(arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + + // store info about comp unit + address_sizes[comp_idx] = comp_root.address_size; + address_bases[comp_idx] = comp_root.base_addr; + ver_arr[comp_idx] = comp_root.version; + ext_arr[comp_idx] = dw_ext_from_params(comp_root.producer, arch, image_type); + + // parse tags + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + Temp tag_temp = temp_begin(scratch.arena); + + DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, ver_arr[comp_idx], ext_arr[comp_idx], comp_root.language, comp_root.address_size, info_off, relaxed); + + // parse attribs + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->attrib; + B32 is_sect_offset = attrib->value_class == DW_AttribClass_LocListPtr || (attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_SecOffset); + B32 is_sect_index = attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_LocListx; + if (is_sect_offset) { + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + } else if (is_sect_index) { + // TODO: support for section indexing + } + } + + // advance to next tag + info_off = tag->info_range.max; + + temp_end(tag_temp); + } + + temp_end(comp_temp); + } + + void *base = dw_base_from_sec(sections, DW_Section_Loc); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Loc); + + rd_printf("%S:", dw_string_from_section_kind(scratch.arena, DW_Section_Loc)); + rd_indent(); + rd_printf("%-8s %-8s %-8s %s", "Offset", "Min", "Max", "Expression"); + for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + Temp locs_temp = temp_begin(scratch.arena); + + DW_Version ver = ver_arr[comp_idx]; + DW_Ext ext = ext_arr[comp_idx]; + + U64Array locs = u64_array_from_list(locs_temp.arena, &loc_lists[comp_idx]); + u64_array_sort(locs.count, locs.v); + + U64Array locs_set = remove_duplicates_u64_array(locs_temp.arena, locs); + U64 address_size = address_sizes[comp_idx]; + U64 base_selector = (address_size == 8) ? max_U64 : max_U32; + + for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) { + U64 base_address = address_bases[comp_idx]; + for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) { + Temp range_temp = temp_begin(arena); + + String8List list = {0}; + + // offset + str8_list_pushf(range_temp.arena, &list, "%08llx", cursor); + + // parse entry + U64 v0 = 0, v1 = 0; + cursor += dw_based_range_read(base, range, cursor, address_size, &v0); + cursor += dw_based_range_read(base, range, cursor, address_size, &v1); + + B32 is_list_end = v0 == 0 && v1 == 0; + if (is_list_end) { + str8_list_pushf(range_temp.arena, &list, ""); + } else if (v0 == base_selector) { + base_address = v1; + } else { + // this is not mentioned in the spec (june 10, 2010) + // found reference in gdb/binutils/dwarf.c => display_loc_list + U16 expr_size = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &expr_size); + Rng1U64 expr_range = rng_1u64(range.min+cursor, range.min+cursor+expr_size); + cursor += expr_size; + + // format dwarf expression + B32 is_dwarf64 = (address_size == 8); + String8 raw_expr = str8((U8*)base+expr_range.min, dim_1u64(expr_range)); + String8 expression = dw_format_expression_single_line(range_temp.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64); + + // push entry + U64 min = base_address + v0; + U64 max = base_address + v1; + str8_list_pushf(range_temp.arena, &list, "%08llx %08llx %S", min, max, expression); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + // cleanup temp + temp_end(range_temp); + + // exit check + if (is_list_end) { + break; + } + } + } + + temp_end(locs_temp); + } + rd_unindent(); + + rd_unindent(); + scratch_end(scratch); +} + +internal void +dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + DW_Section ranges = sections->v[DW_Section_Ranges]; + void *base = dw_base_from_sec(sections, DW_Section_Ranges); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Ranges); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + // parse debug_info for attributes with LOCLIST and store .debug_loc offsets + U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); + + { + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(scratch.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + + // store info about comp unit + address_sizes[comp_idx] = comp_root.address_size; + address_bases[comp_idx] = comp_root.base_addr; + + // parse tags + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + DW_Tag *tag = dw_tag_from_info_offset(scratch.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + + // parse attribs + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->attrib; + B32 is_sect_offset = attrib->value_class == DW_AttribClass_RngListPtr || (attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_SecOffset); + B32 is_sect_index = attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_RngListx; + if (is_sect_offset) { + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + } else if (is_sect_index) { + // TODO: support for section indexing + } + } + info_off = tag->info_range.max; + } + } + } + + rd_printf("# %S", sections->v[DW_Section_Ranges].name); + rd_indent(); + rd_printf("%-8s %-8s %-8s", "Offset", "Min", "Max"); + for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + U64Array locs = u64_array_from_list(scratch.arena, &loc_lists[comp_idx]); + u64_array_sort(locs.count, locs.v); + U64Array locs_set = remove_duplicates_u64_array(scratch.arena, locs); + U64 address_size = address_sizes[comp_idx]; + U64 base_selector = (address_size == 8) ? max_U64 : max_U32; + + for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) { + U64 base_address = address_bases[comp_idx]; + for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) { + Temp range_temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // offset + str8_list_pushf(range_temp.arena, &list, "%08llx", cursor); + + // parse entry + U64 v0 = 0, v1 = 0; + cursor += dw_based_range_read(base, range, cursor, address_size, &v0); + cursor += dw_based_range_read(base, range, cursor, address_size, &v1); + + B32 is_list_end = v0 == 0 && v1 == 0; + if (is_list_end) { + str8_list_pushf(range_temp.arena, &list, ""); + } else if (v0 == base_selector) { + base_address = v1; + } else { + // push entry + U64 min = base_address + v0; + U64 max = base_address + v1; + str8_list_pushf(range_temp.arena, &list, "%08llx %08llx", min, max); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(range_temp); + + // exit check + if (is_list_end) { + break; + } + } + } + } +} + +internal void +dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_ARanges); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_ARanges); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_ARanges].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_length = 0; + DW_Version version = 0; + U64 debug_info_offset = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + + B32 is_dwarf64 = unit_length >= max_U32; + U64 int_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + cursor += dw_based_range_read(base, range, cursor, int_size, &debug_info_offset); + + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + cursor += tuple_size - bytes_too_far_past_boundary; + } + + rd_printf("Unit length: %llu", unit_length); + rd_printf("Version: %u", version); + rd_printf("Debug info offset: %#llx", debug_info_offset); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 2 (DWARF5 sepc, Feb 13, 2017)"); + } + + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Range"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + U64 segment_selector = 0; + U64 address = 0; + U64 length = 0; + cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector); + cursor += dw_based_range_read(base, range, cursor, address_size, &address); + cursor += dw_based_range_read(base, range, cursor, address_size, &length); + + if (segment_selector == 0 && address == 0 && length == 0) { + str8_list_pushf(temp.arena, &list, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02llu:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%llx-%llx", address, address+length); + } + + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ") }); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_Addr); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Addr); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_Addr].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_length = 0; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + + U64 unit_offset = cursor; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + + U64 unit_opl = cursor + unit_length; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + cursor += tuple_size - bytes_too_far_past_boundary; + } + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Address"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08X", cursor); + + U64 segment_selector = 0; + U64 address = 0; + cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector); + cursor += dw_based_range_read(base, range, cursor, address_size, &address); + + if (segment_selector == 0 && address == 0) { + str8_list_pushf(temp.arena, &list, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02u:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%llx", address); + } + + String8 print = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal U64 +dw_based_range_read_address(void *base, Rng1U64 range, U64 offset, Rng1U64Array segment_ranges, U8 segment_selector_size, U8 address_size, U64 *address_out) +{ + U64 read_offset = offset; + + // read segment + U64 segment_selector = 0; + read_offset += dw_based_range_read(base, range, read_offset, segment_selector_size, &segment_selector); + + // read address + U64 address = 0; + read_offset += dw_based_range_read(base, range, read_offset, address_size, &address); + + // apply segment offset + B32 is_address_segment_relative = segment_selector_size > 0; + if (is_address_segment_relative) { + if (segment_selector < segment_ranges.count) { + address += segment_ranges.v[segment_selector].min; + } else { + Assert(!"invalid segment selector"); + } + } + + U64 read_size = (read_offset - offset); + return read_size; +} + +internal void +dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_virtual_ranges, Arch arch) +{ + void *base = dw_base_from_sec(sections, DW_Section_LocLists); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_LocLists); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_LocLists].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + + U64 unit_opl = cursor + unit_length; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + U32 offset_entry_count = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count); + + U64 past_header_offset = cursor; + B32 is_dwarf64 = unit_length > max_U32; + U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + rd_printf("Offset entry count: %u", offset_entry_count); + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + if (offset_entry_count > 0) { + rd_printf("Offsets:"); + rd_indent(); + rd_printf("%-8s %-8s", "Index", "Offset"); + for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) { + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset); + } + rd_unindent(); + } + + rd_printf("Locations:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Location"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + U8 kind = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &kind); + str8_list_pushf(temp.arena, &list, "DW_LLE_%S", dw_string_from_loc_list_entry_kind(temp.arena, kind)); + + B32 has_loc_desc = 0; + switch (kind) { + case DW_LocListEntryKind_EndOfList: + break; + case DW_LocListEntryKind_DefaultLocation: { + has_loc_desc = 1; + } break; + case DW_LocListEntryKind_BaseAddress: { + U64 base_address = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &base_address); + str8_list_pushf(temp.arena, &list, "%llx", base_address); + } break; + case DW_LocListEntryKind_StartLength: { + U64 start = 0; + U64 length = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length); + } break; + case DW_LocListEntryKind_StartEnd: { + U64 start = 0; + U64 end = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &end); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end); + } break; + case DW_LocListEntryKind_BaseAddressX: { + U64 base_addressx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx); + str8_list_pushf(temp.arena, &list, "%llx", base_addressx); + } break; + case DW_LocListEntryKind_StartXEndX: { + U64 startx = 0; + U64 endx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &endx); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx); + } break; + case DW_LocListEntryKind_OffsetPair: { + U64 a = 0; + U64 b = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &a); + cursor += dw_based_range_read_uleb128(base, range, cursor, &b); + str8_list_pushf(temp.arena, &list, "%llx, %llx", a, b); + + U8 expr_length = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &expr_length); + + String8 raw_expr = str8((U8*)base+cursor, expr_length); + cursor += expr_length; + + String8 expression = dw_format_expression_single_line(temp.arena, raw_expr, address_size, arch, version, DW_Ext_Null, is_dwarf64); + str8_list_pushf(temp.arena, &list, "(%S)", expression); + } break; + case DW_LocListEntryKind_StartXLength: { + U64 startx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + U64 length = 0; + if (version < DW_Version_5) { + // pre-standard length + cursor += dw_based_range_read(base, range, cursor, sizeof(U32), &length); + } else { + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + } + } break; + } + + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_ranges) +{ + void *base = dw_base_from_sec(sections, DW_Section_RngLists); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_RngLists); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_RngLists].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + U32 offset_entry_count = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count); + + U64 past_header_offset = cursor; + B32 is_dwarf64 = unit_length > max_U32; + U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + rd_printf("Offset entry count: %u", offset_entry_count); + + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + if (offset_entry_count > 0) { + rd_printf("Offsets:"); + rd_indent(); + rd_printf("%-8s %-8s", "Index", "Offset"); + for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) { + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset); + } + rd_unindent(); + } + + rd_printf("Ranges:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Range"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // offset + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + // opcode mnemonic + U8 kind = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &kind); + str8_list_pushf(temp.arena, &list, "DW_RLE_%S", dw_string_from_rng_list_entry_kind(temp.arena, kind)); + + // operand + switch (kind) { + case DW_RngListEntryKind_EndOfList: { + // empty + } break; + case DW_RngListEntryKind_BaseAddressX: { + U64 base_addressx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx); + str8_list_pushf(temp.arena, &list, "%llx", base_addressx); + } break; + case DW_RngListEntryKind_BaseAddress: { + U64 base_address = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &base_address); + str8_list_pushf(temp.arena, &list, "%llx", base_address); + } break; + case DW_RngListEntryKind_OffsetPair: { + U64 min = 0; + U64 max = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &min); + cursor += dw_based_range_read_uleb128(base, range, cursor, &max); + str8_list_pushf(temp.arena, &list, "%llx, %llx", min, max); + } break; + case DW_RngListEntryKind_StartxLength: { + U64 startx = 0; + U64 length = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, length); + } break; + case DW_RngListEntryKind_StartxEndx: { + U64 startx = 0; + U64 endx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &endx); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx); + } break; + case DW_RngListEntryKind_StartEnd: { + U64 start = 0; + U64 end = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &end); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end); + } break; + case DW_RngListEntryKind_StartLength: { + U64 start = 0; + U64 length = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length); + } break; + } + + // output row + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, DW_SectionKind sec) +{ + void *base = dw_base_from_sec(sections, sec); + Rng1U64 range = dw_range_from_sec(sections, sec); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[sec].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + + DW_Version version = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 2"); + } + + B32 is_dwarf64 = unit_length > max_U32; + U32 sec_offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + U64 debug_info_offset = 0, debug_info_length = 0; + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_offset); + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_length); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Debug info offset: %#llx", debug_info_offset); + rd_printf("Debug info length: %#llx", debug_info_length); + + rd_printf("Entries:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "String"); + for (; cursor < unit_opl; ) { + U64 info_offset = 0; + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &info_offset); + String8 string = dw_based_range_read_string(base, range, cursor); + cursor += (string.size + 1); + + rd_printf("%08llx %S", info_offset, string); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_pubnames(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + dw_format_string_table(arena, out, indent, sections, DW_Section_PubNames); +} + +internal void +dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + dw_format_string_table(arena, out, indent, sections, DW_Section_PubTypes); +} + +internal void +dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_LineStr); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_LineStr); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_LineStr].name); + rd_indent(); + + rd_printf("%-8s %-8s", "Offset", "String"); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 offset = cursor; + String8 string = dw_based_range_read_string(base, range, cursor); + cursor += (string.size + 1); + rd_printf("%08llX %S", offset, string); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_StrOffsets); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_StrOffsets); + + void *debug_str_base = dw_base_from_sec(sections, DW_Section_Str); + Rng1U64 debug_str_range = dw_range_from_sec(sections, DW_Section_Str); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_StrOffsets].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + + DW_Version version = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + U16 padding = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &padding); + if (padding != 0) { + rd_warningf("unexpected padding byte"); + } + + B32 is_dwarf64 = unit_length > max_U32; + U32 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llX, length %lld", unit_offset, unit_length); + rd_printf("Version: %d", version); + rd_printf("Padding: %d", padding); + rd_indent(); + rd_printf("%-8s %-8s", "@", "Offset"); + for (; cursor < unit_opl; ) { + U64 read_at = cursor; + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%08llx %08llx", read_at, offset); + if (dim_1u64(debug_str_range) > 0) { + String8 string = dw_based_range_read_string(debug_str_base, debug_str_range, offset); + rd_printf(" %S", string); + } + rd_newline(); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_format(Arena *arena, String8List *out, String8 indent, RD_Option opts, DW_SectionArray *sections, Arch arch, ImageType image_type) +{ + Rng1U64Array segment_vranges = {0}; + + B32 relaxed = !!(opts & RD_Option_RelaxDwarfParser); + + if (opts & RD_Option_DebugInfo) { + dw_print_debug_info(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugAbbrev) { + dw_print_debug_abbrev(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLine) { + dw_print_debug_line(arena, out, indent, sections, relaxed); + } + if (opts & RD_Option_DebugStr) { + dw_print_debug_str(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLoc) { + dw_print_debug_loc(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugRanges) { + dw_print_debug_ranges(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugARanges) { + dw_print_debug_aranges(arena, out, indent, sections); + } + if (opts & RD_Option_DebugAddr) { + dw_print_debug_addr(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLocLists) { + dw_print_debug_loclists(arena, out, indent, sections, segment_vranges, arch); + } + if (opts & RD_Option_DebugRngLists) { + dw_print_debug_rnglists(arena, out, indent, sections, segment_vranges); + } + if (opts & RD_Option_DebugPubNames) { + dw_print_debug_pubnames(arena, out, indent, sections); + } + if (opts & RD_Option_DebugPubTypes) { + dw_print_debug_pubtypes(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLineStr) { + dw_print_debug_line_str(arena, out, indent, sections); + } + if (opts & RD_Option_DebugStrOffsets) { + dw_print_debug_str_offsets(arena, out, indent, sections); + } +} + +// CodeView + +internal void +cv_print_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) { if (raw_data.size) { Temp scratch = scratch_begin(&arena, 1); @@ -263,13 +2629,13 @@ cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch } internal void -cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range) +cv_print_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range) { rd_printf("Address Range: %04x:%08x Size: %#x", range.sec, range.off, range.len); } internal void -cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data) { U64 count = raw_data.size / sizeof(CV_LvarAddrGap); if (count > 0) { @@ -286,7 +2652,7 @@ cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 } internal void -cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr) +cv_print_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr) { Temp scratch = scratch_begin(&arena,1); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, attr.seg, attr.off)); @@ -295,7 +2661,7 @@ cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarA } internal void -cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol) +cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV_TypeIndex min_itype, CV_SymKind type, String8 raw_symbol) { Temp scratch = scratch_begin(&arena, 1); U64 cursor = 0; @@ -307,13 +2673,13 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %x", sym.parent); - rd_printf("End: %x", sym.end); - rd_printf("Next: %x", sym.next); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); + rd_printf("Name: %S", name); + rd_printf("Parent: %x", sym.parent); + rd_printf("End: %x", sym.end); + rd_printf("Next: %x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u", sym.len); + rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); } break; case CV_SymKind_FILESTATIC: { CV_SymFileStatic sym = {0}; @@ -321,7 +2687,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_CALLERS: @@ -351,7 +2717,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U for (U32 i = 0; i < sym.count; ++i) { U32 itype; cursor += str8_deserial_read_struct(raw_symbol, cursor, &itype); - rd_printf("%S", cv_string_from_itype(arena, itype)); + rd_printf("%S", cv_string_from_itype(arena, min_itype, itype)); } rd_unindent(); } break; @@ -364,7 +2730,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Parent: %#x", sym.parent); rd_printf("End: %#x", sym.end); rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); - cv_format_binary_annots(arena, out, indent, arch, raw_annots); + cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; case CV_SymKind_INLINESITE2: { CV_SymInlineSite2 sym = {0}; @@ -376,7 +2742,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("End: %#x", sym.end_off); rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); rd_printf("Invocations: %u", sym.invocations); - cv_format_binary_annots(arena, out, indent, arch, raw_annots); + cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; case CV_SymKind_INLINESITE_END: { // nothing to report @@ -392,7 +2758,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("TSL Address: %S", cv_string_sec_off(scratch.arena, sym.tls_seg, sym.tls_off)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_OBJNAME: { CV_SymObjName sym = {0}; @@ -410,23 +2776,22 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); rd_printf("Parent: %x", sym.parent); rd_printf("End: %x", sym.end); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u (bytes)", sym.len); + rd_printf("Length: %u", sym.len); + if (name.size) { + rd_printf("Name: %S", name); + } } break; case CV_SymKind_LABEL32_ST: case CV_SymKind_LABEL32: { - CV_SymLabel32 sym = {0}; - String8 name = str8_zero(); + CV_SymLabel32 sym = {0}; + String8 name = str8_zero(); cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Address: %S, Flags: %S, Name: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off), cv_string_from_proc_flags(scratch.arena, sym.flags), name); } break; case CV_SymKind_COMPILE: { Assert(!"TODO: test"); @@ -436,10 +2801,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); U32 language = CV_CompileFlags_Extract_Language(sym.flags); - U32 float_prec = CV_CompileFlags_ExtractFloatPrec(sym.flags); - U32 float_pkg = CV_CompileFlags_ExtractFloatPkg(sym.flags); - U32 ambient_data = CV_CompileFlags_ExtractAmbientData(sym.flags); - U32 mode = CV_CompileFlags_ExtractMode(sym.flags); + U32 float_prec = CV_CompileFlags_Extract_FloatPrec(sym.flags); + U32 float_pkg = CV_CompileFlags_Extract_FloatPkg(sym.flags); + U32 ambient_data = CV_CompileFlags_Extract_AmbientData(sym.flags); + U32 mode = CV_CompileFlags_Extract_Mode(sym.flags); rd_printf("Arch: %S", cv_string_from_arch(sym.machine)); rd_printf("Language: %S", cv_string_from_language(language)); rd_printf("FloatPrec: %x", float_prec); @@ -495,16 +2860,16 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U String8 name = str8_zero(); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Next: %#x", sym.next); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Debug Start: %#x", sym.dbg_start); - rd_printf("Debug End: %#x", sym.dbg_end); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Name: %S", name); + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Next: %#x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u", sym.len); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Debug Start: %#x", sym.dbg_start); + rd_printf("Debug End: %#x", sym.dbg_end); } break; case CV_SymKind_LDATA32_ST: case CV_SymKind_GDATA32_ST: @@ -516,7 +2881,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_CONSTANT_ST: @@ -529,7 +2894,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, size)); } break; case CV_SymKind_FRAMEPROC: { @@ -539,14 +2904,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U String8 flags = cv_string_from_frame_proc_flags(scratch.arena, sym.flags); U32 local_ptr = CV_FrameprocFlags_Extract_LocalBasePointer(sym.flags); U32 param_ptr = CV_FrameprocFlags_Extract_ParamBasePointer(sym.flags); - rd_printf("Frame Size: %x", sym.frame_size); - rd_printf("Pad Size: %x", sym.pad_size); - rd_printf("Pad Offset: %x", sym.pad_off); - rd_printf("Save Registers Area: %u (bytes)", sym.save_reg_size); - rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); - rd_printf("Flags: %S", flags); - rd_printf("Local pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, local_ptr))); - rd_printf("Param pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, param_ptr))); + rd_printf("Frame Size: %x", sym.frame_size); + rd_printf("Pad Size: %x", sym.pad_size); + rd_printf("Pad Offset: %x", sym.pad_off); + rd_printf("Save Registers Area: %u", sym.save_reg_size); + rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); + rd_printf("Flags: %S", flags); + rd_printf("Local pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, local_ptr))); + rd_printf("Param pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, param_ptr))); } break; case CV_SymKind_LOCAL: { CV_SymLocal sym = {0}; @@ -555,7 +2920,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_DEFRANGE: { @@ -565,8 +2930,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += raw_gaps.size; rd_printf("Program: %#x", sym.program); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_REGISTER: { CV_SymDefrangeRegister sym = {0}; @@ -574,10 +2939,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: { CV_SymDefrangeFramepointerRel sym = {0}; @@ -585,8 +2950,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); rd_printf("Offset: %#x", sym.off); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: { CV_SymDefrangeSubfieldRegister sym = {0}; @@ -594,11 +2959,11 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); rd_printf("Parent Offset: %#x", sym.field_offset); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: { CV_SymDefrangeFramepointerRelFullScope sym = {0}; @@ -613,7 +2978,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Flags: %S", cv_string_from_defrange_register_rel_flags(scratch.arena, sym.flags)); rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_END: case CV_SymKind_PROC_ID_END: { @@ -627,7 +2992,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_BUILDINFO: { CV_SymBuildInfo sym = {0}; @@ -648,17 +3013,18 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S, Type: %S, Name: %S", + cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off), + cv_string_from_itype(scratch.arena, min_itype, sym.itype), + name); } break; case CV_SymKind_CALLSITEINFO: { CV_SymCallSiteInfo sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Pad: %u (bytes)", sym.pad); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Pad: %u", sym.pad); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_FRAMECOOKIE: { CV_SymFrameCookie sym = {0}; @@ -673,10 +3039,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); String8 addr = cv_string_sec_off(arena, sym.sec, sym.off); - String8 itype = cv_string_from_itype(arena, sym.itype); + String8 itype = cv_string_from_itype(arena, min_itype, sym.itype); rd_printf("Address: %S", addr); rd_printf("Type: %S", itype); - rd_printf("Call instruction length: %x (bytes)", sym.call_inst_len); + rd_printf("Call instruction length: %x", sym.call_inst_len); } break; case CV_SymKind_ALIGN: { // spec: @@ -716,21 +3082,15 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymReturn sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Flags: S", cv_string_from_generic_flags(scratch.arena, sym.flags)); - rd_printf("Style: S", cv_string_from_generic_style(sym.style)); + rd_printf("Flags: %S", cv_string_from_generic_flags(scratch.arena, sym.flags)); + rd_printf("Style: %S", cv_string_from_generic_style(sym.style)); if (sym.style == CV_GenericStyle_REG) { U8 count = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &count); + String8 data = rd_format_hex_array(scratch.arena, raw_symbol.str, raw_symbol.size); rd_printf("Byte Count: %u", count); - rd_printf("Data:"); - rd_indent(); - for (U8 i = 0; i < count; ++i) { - U8 v; - cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf(" %02x", v); - } - rd_unindent(); + rd_printf("Data: %S", data); } } break; case CV_SymKind_ENTRYTHIS: { @@ -741,7 +3101,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_type); String8 raw_subsym = str8_skip(raw_symbol, cursor); - cv_format_symbol(arena, out, indent, arch, type, raw_subsym); + cv_print_symbol(arena, out, indent, arch, min_itype, type, raw_subsym); } break; case CV_SymKind_SLINK32: { Assert(!"ret"); @@ -762,7 +3122,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U // rest of the range is it? // // CV-spec doesn't even mention S_OEM just LF_OEM and cvdump.exe prints out type with guid... - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("ID: %S", string_from_guid(scratch.arena, sym.id)); } break; case CV_SymKind_VFTABLE32:{ @@ -771,8 +3131,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymVPath32 sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Root: %S", cv_string_from_itype(scratch.arena, sym.root)); - rd_printf("Path: %S", cv_string_from_itype(scratch.arena, sym.path)); + rd_printf("Root: %S", cv_string_from_itype(scratch.arena, min_itype, sym.root)); + rd_printf("Path: %S", cv_string_from_itype(scratch.arena, min_itype, sym.path)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); } break; case CV_SymKind_PUB32_ST: @@ -797,7 +3157,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_REGISTER: { Assert(!"TODO: test"); @@ -808,8 +3168,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_PROCREF_ST: case CV_SymKind_DATAREF_ST: @@ -836,12 +3196,12 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymSepcode sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); - rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Length: %u", sym.len); + rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); + rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); } break; case CV_SymKind_PARAMSLOT_ST: case CV_SymKind_LOCALSLOT_ST: @@ -855,7 +3215,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Slot: %u", sym.slot_index); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_TRAMPOLINE: { Assert(!"TODO: test"); @@ -863,10 +3223,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymTrampoline sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); - rd_printf("Thunk Size: %u (bytes)", sym.thunk_size); - rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); - rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); + rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); + rd_printf("Thunk Size: %u", sym.thunk_size); + rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); + rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); } break; case CV_SymKind_POGODATA: { Assert(!"TODO: test"); @@ -885,14 +3245,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { U8 v = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf("%S", cv_string_from_reg_id(arch, v)); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, v)); } rd_unindent(); } break; @@ -903,14 +3263,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U16 i = 0; i < sym.count; ++i) { U16 v = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf("%S", cv_string_from_reg_id(arch, v)); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, v)); } rd_unindent(); } break; @@ -922,12 +3282,12 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Index: %u", sym.sec_index); - rd_printf("Align: %u", sym.align); - rd_printf("Virtual Offset: %#x", sym.rva); - rd_printf("Size: %u (bytes)", sym.size); - rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Name: %S", name); + rd_printf("Index: %u", sym.sec_index); + rd_printf("Align: %u", sym.align); + rd_printf("Virtual Offset: %#x", sym.rva); + rd_printf("Size: %u", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); } break; case CV_SymKind_ENVBLOCK: { CV_SymEnvBlock sym = {0}; @@ -952,10 +3312,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Size: %u (bytes)", sym.size); - rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Name: %S", name); + rd_printf("Size: %u", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_EXPORT: { Assert(!"TODO: test"); @@ -997,8 +3357,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANREGISTER: case CV_SymKind_ATTR_REGISTER: { @@ -1010,9 +3370,9 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_ATTR_REGREL: { Assert(!"TODO: test"); @@ -1023,9 +3383,9 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.off)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANYREG_ST: case CV_SymKind_MANMANYREG: @@ -1040,13 +3400,13 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + cv_print_lvar_attr(arena, out, indent, sym.attr); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { - rd_printf("%S", cv_string_from_reg_id(arch, regs[i])); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, regs[i])); } rd_unindent(); } break; @@ -1094,7 +3454,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("File ID: %x", sym.file_id); rd_printf("File Line Number: %u", sym.file_ln); rd_printf("# Discarded Symbol"); - cv_format_symbol(arena, out, indent, arch, symbol_type, raw_subsym); + cv_print_symbol(arena, out, indent, arch, min_itype, symbol_type, raw_subsym); } break; case CV_SymKind_PDBMAP: { Assert(!"TODO: test"); @@ -1117,7 +3477,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Flags: %x", sym.flags); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); } break; case CV_SymKind_ARMSWITCHTABLE: { Assert(!"TODO: test"); @@ -1143,7 +3503,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Flags: %x", sym.flags); rd_printf("IMod: %04x", sym.imod); if (sym.flags & CV_RefMiniPdbFlag_UDT) { - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, (CV_TypeIndex)sym.data)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, (CV_TypeIndex)sym.data)); } else { rd_printf("Coff ISect: %#x", sym.data); } @@ -1248,7 +3608,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U } internal U64 -cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf) +cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_itype, CV_LeafKind kind, String8 raw_leaf) { Temp scratch = scratch_begin(&arena, 1); U64 cursor = 0; @@ -1260,7 +3620,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, CV_LeafBitField lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Length: %u", lf.len); rd_printf("Position: %u", lf.pos); } break; @@ -1274,10 +3634,10 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); + rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); rd_printf("Unknown1: %x", lf.unknown1); rd_printf("Unknown2: %x", lf.unknown2); if (lf.props & CV_TypeProp_HasUniqueName) { @@ -1327,27 +3687,27 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, lf.owner_itype)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.owner_itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_VFUNCTAB: { CV_LeafVFuncTab lf = {0}; - cursor += syms_based_range_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_METHODLIST: { for (; cursor < raw_leaf.size; ) { CV_LeafMethodListMember ml = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &ml); - U32 mprop = CV_FieldAttribs_Extract_MPROP(ml.attribs); + U32 mprop = CV_FieldAttribs_Extract_MethodProp(ml.attribs); B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); U32 vbase = 0; if (has_vbase) { cursor += str8_deserial_read_struct(raw_leaf, cursor, &vbase); } rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, ml.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, ml.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, ml.itype)); if (has_vbase) { rd_printf("Virtual Base: %x", vbase); } @@ -1357,7 +3717,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, case CV_LeafKind_ONEMETHOD: { CV_LeafOneMethod lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - U32 mprop = CV_FieldAttribs_Extract_MPROP(lf.attribs); + U32 mprop = CV_FieldAttribs_Extract_MethodProp(lf.attribs); B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); U32 vbase = 0; if (has_vbase) { @@ -1367,7 +3727,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); rd_printf("Field Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); if (has_vbase) { rd_printf("Virtual Base: %#x", vbase); } @@ -1381,7 +3741,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Count: %u", lf.count); - rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, lf.list_itype)); + rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, min_itype, lf.list_itype)); } break; case CV_LeafKind_VBCLASS: case CV_LeafKind_IVBCLASS: { @@ -1393,8 +3753,8 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &vbtable_off); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); - rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, lf.vbptr_itype)); + rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vbptr_itype)); rd_printf("vbpoff: %S", cv_string_from_numeric(scratch.arena, vbptr_off)); rd_printf("vbind: %S", cv_string_from_numeric(scratch.arena, vbtable_off)); } break; @@ -1405,7 +3765,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &offset); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, offset)); } break; case CV_LeafKind_VTSHAPE: { @@ -1432,26 +3792,26 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MFUNCTION: { CV_LeafMFunction lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); - rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, lf.class_itype)); - rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, lf.this_itype)); + rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.class_itype)); + rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.this_itype)); rd_printf("Call Kind: %S", cv_string_from_call_kind(lf.call_kind)); rd_printf("Function Attribs: %S", cv_string_from_function_attribs(scratch.arena, lf.attribs)); rd_printf("Argument Count: %u", lf.arg_count); - rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; #if 0 case CV_LeafKind_SKIP_16t: { CV_LeafSkip_16t lf = {0}; cursor += str8_deserial_read_struct(base, range, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.type)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.type)); } break; #endif case CV_LeafKind_SKIP: { @@ -1459,7 +3819,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, // This is used by incremental compilers to reserve space for indices. CV_LeafSkip lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_ENUM_ST: case CV_LeafKind_ENUM: { @@ -1471,8 +3831,8 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Field Count: %u", lf.count); rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.base_itype)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.base_itype)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -1498,7 +3858,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Index: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Index: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_NOTTRAN: { // ms-symbol-pdf: @@ -1508,7 +3868,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, CV_LeafUDTSrcLine lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type = %S, Source File = %x, Line = %u", cv_string_from_itype(scratch.arena, lf.udt_itype), lf.src_string_id, lf.line); + rd_printf("Type = %S, Source File = %x, Line = %u", cv_string_from_itype(scratch.arena, min_itype, lf.udt_itype), lf.src_string_id, lf.line); } break; case CV_LeafKind_STRING_ID: { CV_LeafStringId lf = {0}; @@ -1517,19 +3877,17 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &string); rd_printf("string: %S", string); - rd_printf("Substrings: %x", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead + rd_printf("Substrings: %S", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead } break; case CV_LeafKind_POINTER: { CV_LeafPointer lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - CV_PointerKind kind = CV_PointerAttribs_Extract_KIND(lf.attribs); - CV_PointerMode mode = CV_PointerAttribs_Extract_MODE(lf.attribs); + CV_PointerKind kind = CV_PointerAttribs_Extract_Kind(lf.attribs); + CV_PointerMode mode = CV_PointerAttribs_Extract_Mode(lf.attribs); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Attribs: %S", cv_string_from_pointer_attribs(arena, lf.attribs)); - rd_printf("Kind: %S", cv_string_from_pointer_kind(kind)); - rd_printf("Mode: %S", cv_string_from_pointer_mode(mode)); rd_indent(); if (mode == CV_PointerMode_PtrMem) { CV_TypeIndex itype = 0; @@ -1537,7 +3895,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); cursor += str8_deserial_read_struct(raw_leaf, cursor, &pm); - rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, itype)); + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, itype)); rd_printf("Format: %S", cv_string_from_member_pointer_kind(pm)); } else { if (kind == CV_PointerKind_BaseSeg) { @@ -1551,7 +3909,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &base_itype); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, base_itype)); + rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, base_itype)); rd_printf("Name: %S", name); } } @@ -1566,11 +3924,16 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %s", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); - rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); + if (lf.props & CV_TypeProp_HasUniqueName) { + String8 unique_name = {0}; + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); + rd_printf("Unique Name: %S", unique_name); + } } break; case CV_LeafKind_CLASS_ST: case CV_LeafKind_STRUCTURE_ST: @@ -1583,13 +3946,13 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); - rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); - rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); + rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -1606,7 +3969,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, for (U32 i = 0; i < lf.count; ++i) { U32 itype = 0; cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); - rd_printf("%S", cv_string_from_itype(scratch.arena, itype)); + rd_printf("%S", cv_string_from_itype(scratch.arena, min_itype, itype)); } rd_unindent(); } break; @@ -1617,11 +3980,11 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 call_kind = cv_string_from_call_kind(lf.call_kind); String8 func_attribs = cv_string_from_function_attribs(scratch.arena, lf.attribs); - rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); + rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); rd_printf("Call Convention: %S", call_kind); rd_printf("Function Attribs: %S", func_attribs); rd_printf("Argumnet Count: %u", lf.arg_count); - rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; case CV_LeafKind_FUNC_ID: { CV_LeafFuncId lf = {0}; @@ -1630,29 +3993,26 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, lf.scope_string_id)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.scope_string_id)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MODIFIER: { CV_LeafModifier lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Flags: %S", cv_string_from_modifier_flags(scratch.arena, lf.flags)); } break; case CV_LeafKind_ARRAY_ST: case CV_LeafKind_ARRAY: { CV_LeafArray lf = {0}; CV_NumericParsed num = {0}; - String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += cv_read_numeric(raw_leaf, cursor, &num); - cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, lf.entry_itype)); - rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, lf.index_itype)); + rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.entry_itype)); + rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.index_itype)); rd_printf("Length: %S", cv_string_from_numeric(scratch.arena, num)); - rd_printf("Name: %S", name); } break; case CV_LeafKind_FIELDLIST: { for (U64 idx = 0; cursor < raw_leaf.size;) { @@ -1662,7 +4022,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("list[%u] = %S", idx++, cv_string_from_leaf_name(arena, member_type)); rd_indent(); - cursor += cv_format_leaf(arena, out, indent, member_type, raw_member); + cursor += cv_print_leaf(arena, out, indent, min_itype, member_type, raw_member); cursor = AlignPow2(cursor, 4); rd_unindent(); } @@ -1678,7 +4038,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, num)); } break; // 16bit @@ -1776,70 +4136,70 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, } internal void -cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t) +cv_print_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t) { Temp scratch = scratch_begin(&arena, 1); for (U64 lf_idx = 0; lf_idx < debug_t.count; ++lf_idx) { - CV_Leaf lf = cv_debug_t_get_leaf(debug_t, lf_idx); - U64 offset = (U64)(lf.data.str-debug_t.v[0]); - rd_printf("%S (%#x) [%04x-%04x)", cv_string_from_leaf_kind(lf.kind), offset, offset+lf.data.size); + CV_Leaf lf = cv_debug_t_get_leaf(debug_t, lf_idx); + U64 offset = (U64)(lf.data.str-debug_t.v[0]); + CV_TypeIndex itype = CV_MinComplexTypeIndex + lf_idx; + rd_printf("LF_%S (%x) [%04llx-%04llx)", cv_string_from_leaf_kind(lf.kind), itype, offset, offset+lf.data.size); rd_indent(); - coff_format_leaf(arena, out, indent, lf.kind, lf.data); + cv_print_leaf(arena, out, indent, CV_MinComplexTypeIndex, lf.kind, lf.data); rd_unindent(); } scratch_end(scratch); } internal void -cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_symbols_c13(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) { - CV_Arch arch = ~0u; + Temp scratch = scratch_begin(&arena, 1); + + B32 scope_depth = 0; for (U64 cursor = 0; cursor < raw_data.size; ) { CV_SymbolHeader header = {0}; cursor += str8_deserial_read_struct(raw_data, cursor, &header); - if (header.kind == CV_SymKind_COMPILE) { - if (header.size >= sizeof(CV_SymCompile)) { - CV_SymCompile *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE"); - } - } else if (header.kind == CV_SymKind_COMPILE2) { - if (header.size >= sizeof(CV_SymCompile2)) { - CV_SymCompile2 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE2"); - } - } else if (header.kind == CV_SymKind_COMPILE3) { - if (header.size >= sizeof(CV_SymCompile3)) { - CV_SymCompile3 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE3"); - } - } - if (header.size >= sizeof(header.kind)) { + Temp temp = temp_begin(scratch.arena); + U64 symbol_end = cursor + (header.size - sizeof(header.kind)); String8 raw_symbol = str8_substr(raw_data, rng_1u64(cursor, symbol_end)); - rd_printf("%S [%04x-%04x)", cv_string_from_sym_kinds(header.kind), cursor, header.size-sizeof(header.size)); + if (header.kind == CV_SymKind_END || header.kind == CV_SymKind_INLINESITE_END) { + if (scope_depth > 0) { + rd_unindent(); + --scope_depth; + } else { + rd_errorf("unbalanced scopes"); + } + } + + rd_printf("%S [%04llx-%04llx)", cv_string_from_symbol_type(temp.arena, header.kind), cursor, header.size-sizeof(header.size)); rd_indent(); - cv_format_symbol(arena, out, indent, arch, header.kind, raw_symbol); + cv_print_symbol(arena, out, indent, arch, CV_MinComplexTypeIndex, header.kind, raw_symbol); rd_unindent(); + if (header.kind == CV_SymKind_BLOCK32 || header.kind == CV_SymKind_INLINESITE) { + rd_indent(); + ++scope_depth; + } + cursor = symbol_end; + + temp_end(temp); } else { rd_errorf("symbol must be at least two bytes long"); } } + + scratch_end(scratch); } internal void -cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines) +cv_print_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines) { Temp scratch = scratch_begin(&arena, 1); @@ -1870,9 +4230,9 @@ cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_ B32 always_step_in_line_number = line.off == 0xFEEFEE; B32 never_step_in_line_number = line.off == 0xF00F00; - U32 ln = CV_C13LineFlags_ExtractLineNumber(line.flags); - //U32 delta = CV_C13LineFlags_ExtractDeltaToEnd(line.flags); - //B32 is_stmt = CV_C13LineFlags_ExtractStatement(line.flags); + U32 ln = CV_C13LineFlags_Extract_LineNumber(line.flags); + //U32 delta = CV_C13LineFlags_Extract_DeltaToEnd(line.flags); + //B32 is_stmt = CV_C13LineFlags_Extract_Statement(line.flags); if (always_step_in_line_number || never_step_in_line_number) { str8_list_pushf(temp.arena, &columns, "%x %08X", ln, line.off); @@ -1900,15 +4260,14 @@ cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_ } internal void -cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums) +cv_print_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums) { Temp scratch = scratch_begin(&arena, 1); - rd_printf("%8s %8s %8s %16s", "File", "Size", "Type", "Chksum"); + rd_printf("%-8s %-8s %-8s %-16s", "File", "Size", "Type", "Checksum"); for (U64 cursor = 0; cursor < raw_chksums.size; ) { CV_C13Checksum chksum = {0}; cursor += str8_deserial_read_struct(raw_chksums, cursor, &chksum); - cursor = AlignPow2(cursor, CV_FileCheckSumsAlign); Temp temp = temp_begin(scratch.arena); String8 chksum_str = str8_lit("???"); @@ -1917,20 +4276,23 @@ cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 chksum_str = rd_format_hex_array(temp.arena, chksum_ptr, chksum.len); } - rd_printf("%08x %08x %8S %S", + rd_printf("%08x %08x %-8S %S", chksum.name_off, chksum.len, cv_string_from_c13_checksum_kind(chksum.kind), chksum_str); temp_end(temp); + + cursor += chksum.len; + cursor = AlignPow2(cursor, CV_FileCheckSumsAlign); } scratch_end(scratch); } internal void -cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab) +cv_print_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab) { for (U64 cursor = 0; cursor < raw_strtab.size; ) { String8 str = {0}; @@ -1940,7 +4302,7 @@ cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 r } internal void -cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data) { Temp scratch = scratch_begin(&arena, 1); @@ -1988,7 +4350,11 @@ cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 } internal void -cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss) +cv_print_symbols_section(Arena *arena, + String8List *out, + String8 indent, + CV_Arch arch, + String8 raw_ss) { Temp scratch = scratch_begin(&arena, 1); @@ -1999,28 +4365,23 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String for (; cursor < raw_ss.size; ) { U64 sst_offset = 0; CV_C13SubSectionHeader ss_header = {0}; + char *ss_ver = "???"; switch (cv_sig) { case CV_Signature_C6: { rd_printf("TODO: C6"); } break; - case CV_Signature_C7: { rd_printf("TODO: C7"); } break; - case CV_Signature_C11: { ss_header.kind = CV_C13SubSectionKind_Symbols; ss_header.size = raw_ss.size - sizeof(cv_sig); - - rd_printf("# CodeView C11"); - rd_newline(); + ss_ver = "C11"; } break; case CV_Signature_C13: { sst_offset = cursor; cursor += str8_deserial_read_struct(raw_ss, cursor, &ss_header); - - coff_pritnf("# CodeView C13"); - rd_newline(); + ss_ver = "C13"; } break; } @@ -2028,23 +4389,28 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String String8 raw_sst = str8_substr(raw_ss, rng_1u64(cursor, sst_end)); cursor = AlignPow2(sst_end, CV_C13SubSectionAlign); - rd_printf("# %S [%llx-%llx)", cv_string_from_c13_subsection_kind(ss_header.kind), sst_offset, sst_end); + rd_printf("# %S %s [%llx-%llx)", cv_string_from_c13_subsection_kind(ss_header.kind), ss_ver, sst_offset, sst_end); rd_indent(); switch (ss_header.kind) { case CV_C13SubSectionKind_Symbols: { - cv_format_symbols_c13(arena, out, indent, raw_sst); + cv_print_symbols_c13(arena, out, indent, arch, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_Lines: { - cv_format_lines_c13(arena, out, indent, raw_sst); + cv_print_lines_c13(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_FileChksms: { - cv_format_file_checksums(arena, out, indent, raw_sst); + cv_print_file_checksums(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_StringTable: { - cv_format_string_table(arena, out, indent, raw_sst); + cv_print_string_table(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_InlineeLines: { - cv_format_inlinee_lines(arena, out, indent, raw_sst); + cv_print_inlinee_lines(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_FrameData: case CV_C13SubSectionKind_CrossScopeImports: @@ -2066,10 +4432,96 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String scratch_end(scratch); } -//- COFF +internal void +cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections) +{ + CV_Arch arch = ~0; + { + B32 keep_parsing = 1; + for (U64 i = 0; i < section_count && keep_parsing; ++i) { + COFF_SectionHeader *header = §ions[i]; + String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); + String8 raw_sect = str8_substr(raw_image, sect_frange); + if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + Temp scratch = scratch_begin(&arena, 1); + CV_DebugS debug_s = cv_parse_debug_s(scratch.arena, raw_sect); + for (String8Node *string_n = debug_s.data_list[CV_C13SubSectionIdxKind_Symbols].first; + string_n != 0 && keep_parsing; string_n = string_n->next) { + Temp temp = temp_begin(scratch.arena); + CV_SymbolList symbol_list = {0}; + cv_parse_symbol_sub_section(temp.arena, &symbol_list, 0, string_n->string, CV_SymbolAlign); + for (CV_SymbolNode *symbol_n = symbol_list.first; symbol_n != 0 && keep_parsing; symbol_n = symbol_n->next) { + CV_Symbol symbol = symbol_n->data; + if (symbol.kind == CV_SymKind_COMPILE) { + if (symbol.data.size >= sizeof(CV_SymCompile)) { + CV_SymCompile *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE"); + } + keep_parsing = 0; + } else if (symbol.kind == CV_SymKind_COMPILE2) { + if (symbol.data.size >= sizeof(CV_SymCompile2)) { + CV_SymCompile2 *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE2"); + } + keep_parsing = 0; + } else if (symbol.kind == CV_SymKind_COMPILE3) { + if (symbol.data.size >= sizeof(CV_SymCompile3)) { + CV_SymCompile3 *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE3"); + } + keep_parsing = 0; + } + } + temp_end(temp); + } + scratch_end(scratch); + } + } + } + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ions[i]; + String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); + String8 raw_sect = str8_substr(raw_image, sect_frange); + if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + rd_printf("# .debug$S No. %llx", i+1); + rd_indent(); + cv_print_symbols_section(arena, out, indent, arch, raw_sect); + rd_unindent(); + } else if (str8_match(sect_name, str8_lit(".debug$T"), 0)) { + Temp scratch = scratch_begin(&arena, 1); + CV_Signature sig = 0; + str8_deserial_read_struct(raw_sect, 0, &sig); + + String8 raw_types = str8_skip(raw_sect, sizeof(sig)); + CV_DebugT debug_t = {0}; + if (sig == CV_Signature_C13) { + debug_t = cv_debug_t_from_data(scratch.arena, raw_types, CV_LeafAlign); + } else { + NotImplemented; + } + + rd_printf("# .debug$T No. %llx", i+1); + rd_indent(); + cv_print_debug_t(arena, out, indent, debug_t); + rd_unindent(); + scratch_end(scratch); + } + } +} + +// COFF internal void -coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) +coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) { Temp scratch = scratch_begin(&arena, 1); String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp); @@ -2085,7 +4537,7 @@ coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent } internal void -coff_format_section_table(Arena *arena, +coff_print_seciton_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2287,7 +4739,7 @@ coff_disasm_sections(Arena *arena, COFF_MachineType machine, U64 image_base, B32 is_obj, - RD_MarkerArray *section_markers, + RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections) { @@ -2302,7 +4754,7 @@ coff_disasm_sections(Arena *arena, rd_printf("# Disassembly [Section No. %#llx]", (sect_idx+1)); rd_indent(); - rd_format_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); + rd_print_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); rd_unindent(); } } @@ -2329,7 +4781,7 @@ coff_raw_data_sections(Arena *arena, rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1)); rd_indent(); - rd_format_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); + rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); rd_unindent(); rd_newline(); } @@ -2338,7 +4790,7 @@ coff_raw_data_sections(Arena *arena, } internal void -coff_format_relocs(Arena *arena, +coff_print_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2416,7 +4868,7 @@ coff_format_relocs(Arena *arena, } internal void -coff_format_symbol_table(Arena *arena, +coff_print_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2516,7 +4968,7 @@ coff_format_symbol_table(Arena *arena, } internal void -coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) +coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2538,7 +4990,7 @@ coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_ } internal void -coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) +coff_print_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2561,7 +5013,7 @@ coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header * } internal void -coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) +coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2585,7 +5037,7 @@ coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHe } internal void -coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2595,7 +5047,7 @@ coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_ COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); if (opts & RD_Option_Headers) { - coff_format_big_obj_header(arena, out, indent, big_obj); + coff_print_big_obj_header(arena, out, indent, big_obj); rd_newline(); } @@ -2619,17 +5071,17 @@ coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_ } } - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); rd_newline(); } @@ -2638,7 +5090,7 @@ exit:; } internal void -coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2646,9 +5098,10 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); + Arch arch = arch_from_coff_machine(header->machine); if (opts & RD_Option_Headers) { - coff_format_header(arena, out, indent, header); + coff_print_header(arena, out, indent, header); rd_newline(); } @@ -2672,17 +5125,17 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data } } - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); rd_newline(); } @@ -2700,12 +5153,21 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data rd_newline(); } + if (opts & RD_Option_Codeview) { + cv_format_debug_sections(arena, out, indent, raw_data, string_table_off, header->section_count, sections); + } + + if (opts & RD_Option_Dwarf) { + DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, header->section_count, sections); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + } + exit:; scratch_end(scratch); } internal void -coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts) +coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2829,23 +5291,23 @@ coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_ rd_indent(); if (opts & RD_Option_Headers) { - coff_format_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); + coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); rd_newline(); } switch (member_type) { case COFF_DataType_BIG_OBJ: { - coff_format_big_obj(arena, out, indent, member.data, opts); + coff_print_big_obj(arena, out, indent, member.data, opts); } break; case COFF_DataType_OBJ: { - coff_format_obj(arena, out, indent, member.data, opts); + coff_print_obj(arena, out, indent, member.data, opts); } break; case COFF_DataType_IMPORT: { if (opts & RD_Option_Headers) { COFF_ImportHeader header = {0}; U64 parse_size = coff_parse_archive_import(member.data, 0, &header); if (parse_size) { - coff_format_import(arena, out, indent, &header); + coff_print_import(arena, out, indent, &header); } else { rd_errorf("not enough bytes to parse import header"); } @@ -2865,25 +5327,27 @@ coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_ scratch_end(scratch); } -//- MSVC CRT +// MSVC CRT internal void -mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler) +mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, MSCRT_EhHandlerType32 *handler) { - String8 catch_line = str8_zero(); // TODO: syms_line_for_voff(scratch.arena, group, handler->catch_handler_voff); - String8 adjectives_str = mscrt_string_from_eh_adjectives(arena, handler->adjectives); - rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); - rd_printf("Descriptor: %#x", handler->descriptor_voff); - rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); - rd_printf("Catch Handler: %#x %S", handler->catch_handler_voff, catch_line); - rd_printf("Delta to FP Handler: %#x", handler->fp_distance); + Temp scratch = scratch_begin(&arena, 1); + String8 catch_line = rd_format_line_from_voff(scratch.arena, rdi, handler->catch_handler_voff, PathStyle_WindowsAbsolute); + String8 adjectives_str = mscrt_string_from_eh_adjectives(scratch.arena, handler->adjectives); + rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); + rd_printf("Descriptor: %#x", handler->descriptor_voff); + rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); + rd_printf("Catch Handler: %#x%s%S", handler->catch_handler_voff, catch_line.size ? " " : "", catch_line); + rd_printf("Delta to FP Handler: %#x", handler->fp_distance); + scratch_end(scratch); } //////////////////////////////// //~ PE internal void -pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) +pe_print_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); rd_printf("# Data Directories"); @@ -2895,14 +5359,14 @@ pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, } else { dir_name = push_str8f(scratch.arena, "%#x", i); } - rd_printf("%-16S [%08x-%08x)", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size); + rd_printf("%-16S [%08x-%08x) %m", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size, dirs[i].virt_size); } rd_unindent(); scratch_end(scratch); } internal void -pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) +pe_print_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); @@ -2938,7 +5402,7 @@ pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_O rd_printf("RVA and offset count: %u", opt_header->data_dir_count); rd_newline(); - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); rd_newline(); rd_unindent(); @@ -2946,7 +5410,7 @@ pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_O } internal void -pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) +pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); @@ -2981,7 +5445,7 @@ pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, rd_printf("RVA and offset count: %u", opt_header->data_dir_count); rd_newline(); - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); rd_newline(); rd_unindent(); @@ -2989,7 +5453,7 @@ pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, } internal void -pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) +pe_print_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) { Temp scratch = scratch_begin(&arena, 1); @@ -3073,7 +5537,7 @@ exit:; } internal void -pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) +pe_print_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) { Temp scratch = scratch_begin(&arena, 1); @@ -3157,7 +5621,7 @@ exit:; } internal void -pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) +pe_print_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) { Temp scratch = scratch_begin(&arena, 1); @@ -3189,7 +5653,7 @@ pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) } internal void -pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) +pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) { Temp scratch = scratch_begin(&arena, 1); @@ -3364,7 +5828,7 @@ pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String } internal void -pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) +pe_print_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) { Temp scratch = scratch_begin(&arena, 1); @@ -3395,7 +5859,7 @@ pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_Parsed } internal void -pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) +pe_print_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) { Temp scratch = scratch_begin(&arena, 1); @@ -3432,7 +5896,7 @@ pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U6 } internal void -pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) +pe_print_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) { if (imptab.count) { Temp scratch = scratch_begin(&arena, 1); @@ -3485,7 +5949,7 @@ pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 } internal void -pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) +pe_print_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) { Temp scratch = scratch_begin(&arena, 1); @@ -3618,13 +6082,14 @@ pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceD } internal void -pe_format_exceptions_x8664(Arena *arena, +pe_print_exceptions_x8664(Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 except_frange) + Rng1U64 except_frange, + RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -3635,9 +6100,11 @@ pe_format_exceptions_x8664(Arena *arena, U64 pdata_offset = i * sizeof(PE_IntelPdata); PE_IntelPdata *pdata = str8_deserial_get_raw_ptr(raw_except, pdata_offset, sizeof(*pdata)); + String8 pdata_name = rd_proc_name_from_voff(rdi, pdata->voff_first); - String8 pdata_name = str8_zero(); // TODO: syms_name_for_voff(arena, group, thunk_accel, thunk_table_set, pdata.voff_first); - + if (pdata->voff_first == 0x0020cf44) { + int x = 0; + } U64 unwind_info_offset = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info); PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, unwind_info_offset, sizeof(*uwinfo)); @@ -3801,8 +6268,7 @@ pe_format_exceptions_x8664(Arena *arena, U32 handler = 0; read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler); - String8 handler_name = str8_zero(); // TODO: syms_name_for_voff(scratch.arena, group, thunk_accel, thunk_table_set, handler); - + String8 handler_name = rd_proc_name_from_voff(rdi, handler); rd_printf("Handler: %#llx%s%S", handler, handler_name.size ? " " : "", handler_name); U32 handler_data_flags = 0; @@ -3842,7 +6308,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_printf("%8s %8s", "State", "IP"); for (U32 i = 0; i < func_info.ip_map_count; ++i) { MSCRT_IPState32 state = func_info.ip_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, state.ip); + String8 line = rd_format_line_from_voff(scratch.arena, rdi, state.ip, PathStyle_WindowsAbsolute); rd_printf("%8d %08x %S", state.state, state.ip, line); } rd_unindent(); @@ -3854,7 +6320,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_printf("%13s %10s %8s", "Current State", "Next State", "Action @"); for (U32 i = 0; i < func_info.max_state; ++i) { MSCRT_UnwindMap32 map = func_info.unwind_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, map.action_virt_off); + String8 line = rd_format_line_from_voff(scratch.arena, rdi, map.action_virt_off, PathStyle_WindowsAbsolute); rd_printf("%13u %10d %8x %S", i, map.next_state, map.action_virt_off, line); } rd_unindent(); @@ -3873,7 +6339,7 @@ pe_format_exceptions_x8664(Arena *arena, for (U32 ihandler = 0; ihandler < try_block.catch_handlers_count; ++ihandler) { rd_printf("Catch #%u", ihandler); rd_indent(); - mscrt_format_eh_handler_type32(arena, out, indent, &try_block.catch_handlers[ihandler]); + mscrt_print_eh_handler_type32(arena, out, indent, rdi, &try_block.catch_handlers[ihandler]); rd_unindent(); } rd_unindent(); @@ -3887,19 +6353,17 @@ pe_format_exceptions_x8664(Arena *arena, if (i > 0) { rd_newline(); } - mscrt_format_eh_handler_type32(arena, out, indent, &func_info.es_type_list.handlers[i]); + mscrt_print_eh_handler_type32(arena, out, indent, rdi, &func_info.es_type_list.handlers[i]); } rd_unindent(); } } if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo4) { - U32 handler_data_voff = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler_data_voff); - - U32 unknown = 0; + U32 func_info_voff = 0, unknown = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &func_info_voff); read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &unknown); - U64 func_info_foff = coff_foff_from_voff(sections, section_count, handler_data_voff); + U64 func_info_foff = coff_foff_from_voff(sections, section_count, func_info_voff); MSCRT_ParsedFuncInfoV4 func_info = {0}; mscrt_parse_func_info_v4(arena, raw_data, section_count, sections, func_info_foff, pdata->voff_first, &func_info); @@ -3907,27 +6371,27 @@ pe_format_exceptions_x8664(Arena *arena, { String8List header_list = {0}; if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { - str8_list_pushf(arena, &header_list, "IsCatch"); + str8_list_pushf(scratch.arena, &header_list, "IsCatch"); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { - str8_list_pushf(arena, &header_list, "IsSeparted"); + str8_list_pushf(scratch.arena, &header_list, "IsSeparted"); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { - str8_list_pushf(arena, &header_list, "IsBBT"); + str8_list_pushf(scratch.arena, &header_list, "IsBBT"); } if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - str8_list_pushf(arena, &header_list, "UnwindMap"); + str8_list_pushf(scratch.arena, &header_list, "UnwindMap"); } if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - str8_list_pushf(arena, &header_list, "TryBlockMap"); + str8_list_pushf(scratch.arena, &header_list, "TryBlockMap"); } if (func_info.header & MSCRT_FuncInfoV4Flag_EHs) { - str8_list_pushf(arena, &header_list, "EHs"); + str8_list_pushf(scratch.arena, &header_list, "EHs"); } if (func_info.header & MSCRT_FuncInfoV4Flag_NoExcept) { - str8_list_pushf(arena, &header_list, "NoExcept"); + str8_list_pushf(scratch.arena, &header_list, "NoExcept"); } - header_str = str8_list_join(arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); + header_str = str8_list_join(scratch.arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); } rd_printf("Function Info V4:"); @@ -3940,7 +6404,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_indent(); rd_printf("%8s %8s", "State", "IP"); for (U32 i = 0; i < ip2state_map.count; ++i) { - String8 line_str = str8_zero(); // TODO: syms_line_for_voff(arena, group, ip2state_map.voffs[i]); + String8 line_str = rd_format_line_from_voff(scratch.arena, rdi, ip2state_map.voffs[i], PathStyle_WindowsAbsolute); rd_printf("%8d %08X %S", ip2state_map.states[i], ip2state_map.voffs[i], line_str); } rd_unindent(); @@ -4074,25 +6538,25 @@ pe_format_exceptions_x8664(Arena *arena, } internal void -pe_format_exceptions(Arena *arena, +pe_print_exceptions(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 except_frange) + Rng1U64 except_frange, + RDI_Parsed *rdi) { if (dim_1u64(except_frange)) { rd_printf("# Exceptions"); rd_indent(); rd_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); - switch (machine) { case COFF_MachineType_UNKNOWN: break; case COFF_MachineType_X64: case COFF_MachineType_X86: { - pe_format_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange); + pe_print_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange, rdi); } break; default: NotImplemented; break; } @@ -4102,7 +6566,7 @@ pe_format_exceptions(Arena *arena, } internal void -pe_format_base_relocs(Arena *arena, +pe_print_base_relocs(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, @@ -4110,7 +6574,8 @@ pe_format_base_relocs(Arena *arena, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 base_reloc_franges) + Rng1U64 base_reloc_franges, + RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -4172,21 +6637,9 @@ pe_format_base_relocs(Arena *arena, if (type == PE_BaseRelocKind_ABSOLUTE) { rd_printf("%-4x %-12s", offset, type_str); } else { - rd_printf("%-4x %-12s %016llx", offset, type_str, apply_to); - - // TODO - #if 0 - U64 reloc_voff = apply_to - image_base; - SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, reloc_voff); - SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, reloc_voff); - if (sid) { - SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); - String8 name = syms_group_symbol_name_from_sid(arena, group, unit, sid); - str8_list_pushf(arena, list, " %-4X %-12s %016llX %.*s", offset, type_str, apply_to, syms_expand_string(name)); - } else { - str8_list_pushf(arena, list, " %-4X %-12s %016llX", offset, type_str, apply_to); - } - #endif + U64 reloc_voff = apply_to - image_base; + String8 name = rd_format_proc_line(scratch.arena, rdi, reloc_voff); + rd_printf("%-4x %-12s %016llx%s%S", offset, type_str, apply_to, name.size ? " " : "", name); } } rd_unindent(); @@ -4200,7 +6653,7 @@ pe_format_base_relocs(Arena *arena, } internal void -pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts, RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -4258,10 +6711,11 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, coff_header->optional_header_size); if (opts & RD_Option_Headers) { - coff_format_header(arena, out, indent, coff_header); + coff_print_header(arena, out, indent, coff_header); rd_newline(); } + Arch arch = arch_from_coff_machine(coff_header->machine); U64 image_base = 0; U64 dir_count = 0; PE_DataDirectory *dirs = 0; @@ -4277,7 +6731,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Headers) { - pe_format_optional_header32(arena, out, indent, opt_header, dirs); + pe_print_optional_header32(arena, out, indent, opt_header, dirs); } } else if (opt_header_magic == PE_PE32PLUS_MAGIC) { PE_OptionalHeader32Plus *opt_header = (PE_OptionalHeader32Plus *)raw_opt_header; @@ -4290,7 +6744,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Headers) { - pe_format_optional_header32plus(arena, out, indent, opt_header, dirs); + pe_print_optional_header32plus(arena, out, indent, opt_header, dirs); } } @@ -4305,15 +6759,15 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Sections) { - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); } if (opts & RD_Option_Exports) { @@ -4323,41 +6777,42 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXPORT], dirs_virt_ranges[PE_DataDirectoryIndex_EXPORT]); + pe_print_export_table(arena, out, indent, exptab); } if (opts & RD_Option_Imports) { B32 is_pe32 = opt_header_magic == PE_PE32_MAGIC; PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); - pe_format_static_import_table(arena, out, indent, image_base, static_imptab); - pe_format_delay_import_table(arena, out, indent, image_base, delay_imptab); + pe_print_static_import_table(arena, out, indent, image_base, static_imptab); + pe_print_delay_import_table(arena, out, indent, image_base, delay_imptab); } if (opts & RD_Option_Resources) { String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_RESOURCES]); PE_ResourceDir *dir_root = pe_resource_table_from_directory_data(scratch.arena, raw_dir); - pe_format_resources(arena, out, indent, dir_root); + pe_print_resources(arena, out, indent, dir_root); } if (opts & RD_Option_Exceptions) { - pe_format_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS]); + pe_print_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS], rdi); } if (opts & RD_Option_Relocs) { - pe_format_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC]); + pe_print_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC], rdi); } if (opts & RD_Option_Debug) { if (PE_DataDirectoryIndex_DEBUG < dir_count) { String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DEBUG]); - pe_format_debug_directory(arena, out, indent, raw_data, raw_dir); + pe_print_debug_diretory(arena, out, indent, raw_data, raw_dir); } } if (opts & RD_Option_Tls) { if (dim_1u64(dirs_file_ranges[PE_DataDirectoryIndex_TLS])) { PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); - pe_format_tls(arena, out, indent, tls); + pe_print_tls(arena, out, indent, tls); } } @@ -4369,7 +6824,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O case COFF_MachineType_X86: { PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { - pe_format_load_config32(arena, out, indent, lc); + pe_print_load_config32(arena, out, indent, lc); } else { rd_errorf("not enough bytes to parse 32bit load config"); } @@ -4377,7 +6832,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O case COFF_MachineType_X64: { PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { - pe_format_load_config64(arena, out, indent, lc); + pe_print_load_config64(arena, out, indent, lc); } else { rd_errorf("not enough bytes to parse 64bit load config"); } @@ -4400,49 +6855,12 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O coff_disasm_sections(arena, out, indent, raw_data, coff_header->machine, 0, 1, section_markers, coff_header->section_count, sections); } + if (opts & RD_Option_Dwarf) { + DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, sections); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + } + exit:; scratch_end(scratch); } -internal B32 -is_pe(String8 raw_data) -{ - PE_DosHeader header = {0}; - str8_deserial_read_struct(raw_data, 0, &header); - return header.magic == PE_DOS_MAGIC; -} - -internal void -format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) -{ - Temp scratch = scratch_begin(&arena, 1); - - char *input_type_string = "???"; - - if (coff_is_archive(raw_data)) { - input_type_string = "Archive"; - } else if (coff_is_thin_archive(raw_data)) { - input_type_string = "Thin Archive"; - } else if (coff_is_big_obj(raw_data)) { - input_type_string = "Big Obj"; - } else if (coff_is_obj(raw_data)) { - input_type_string = "Obj"; - } else if (is_pe(raw_data)) { - input_type_string = "COFF/PE"; - } - - DateTime universal_dt = os_now_universal_time(); - DateTime local_dt = os_local_time_from_universal(&universal_dt); - String8 time = push_date_time_string(scratch.arena, &local_dt); - - rd_printf("# Input"); - rd_indent(); - rd_printf("Path: %S", input_path); - rd_printf("Type: %s", input_type_string); - rd_printf("Time: %S", time); - rd_unindent(); - rd_newline(); - - scratch_end(scratch); -} - diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index c835f576..90738f38 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -9,31 +9,63 @@ #define rd_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__) #define rd_newline() str8_list_pushf(arena, out, ""); -#define rd_errorf(f, ...) rd_printf("ERROR: "f, __VA_ARGS__) +#define rd_errorf(f, ...) rd_stderr("ERROR: "f, __VA_ARGS__) +#define rd_warningf(f, ...) rd_stderr("WARNING: "f, __VA_ARGS__) #define rd_indent() do { if (indent.size + RD_INDENT_WIDTH <= RD_INDENT_MAX) { indent.size += RD_INDENT_WIDTH; } else { Assert(!"indent overflow"); } } while (0) -#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) +#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) typedef U64 RD_Option; -enum RD_OptionEnum -{ - RD_Option_Help = (1 << 0), - RD_Option_Version = (1 << 1), - RD_Option_Headers = (1 << 2), - RD_Option_Sections = (1 << 3), - RD_Option_Debug = (1 << 4), - RD_Option_Imports = (1 << 5), - RD_Option_Exports = (1 << 6), - RD_Option_Disasm = (1 << 7), - RD_Option_Rawdata = (1 << 8), - RD_Option_Tls = (1 << 9), - RD_Option_Codeview = (1 << 10), - RD_Option_Symbols = (1 << 11), - RD_Option_Relocs = (1 << 12), - RD_Option_Exceptions = (1 << 13), - RD_Option_LoadConfig = (1 << 14), - RD_Option_Resources = (1 << 15), - RD_Option_LongNames = (1 << 16), -}; + +#define RD_Option_Help (1ull << 0) +#define RD_Option_Version (1ull << 1) +#define RD_Option_Headers (1ull << 2) +#define RD_Option_Sections (1ull << 3) +#define RD_Option_Debug (1ull << 4) +#define RD_Option_Imports (1ull << 5) +#define RD_Option_Exports (1ull << 6) +#define RD_Option_Disasm (1ull << 7) +#define RD_Option_Rawdata (1ull << 8) +#define RD_Option_Tls (1ull << 9) +#define RD_Option_Codeview (1ull << 10) +#define RD_Option_Symbols (1ull << 11) +#define RD_Option_Relocs (1ull << 12) +#define RD_Option_Exceptions (1ull << 13) +#define RD_Option_LoadConfig (1ull << 14) +#define RD_Option_Resources (1ull << 15) +#define RD_Option_LongNames (1ull << 16) +// DWARF +#define RD_Option_DebugInfo (1ull << 17) +#define RD_Option_DebugAbbrev (1ull << 18) +#define RD_Option_DebugLine (1ull << 19) +#define RD_Option_DebugStr (1ull << 20) +#define RD_Option_DebugLoc (1ull << 21) +#define RD_Option_DebugRanges (1ull << 22) +#define RD_Option_DebugARanges (1ull << 23) +#define RD_Option_DebugAddr (1ull << 24) +#define RD_Option_DebugLocLists (1ull << 25) +#define RD_Option_DebugRngLists (1ull << 26) +#define RD_Option_DebugPubNames (1ull << 27) +#define RD_Option_DebugPubTypes (1ull << 28) +#define RD_Option_DebugLineStr (1ull << 29) +#define RD_Option_DebugStrOffsets (1ull << 30) +#define RD_Option_Dwarf \ + (RD_Option_DebugInfo | \ + RD_Option_DebugAbbrev | \ + RD_Option_DebugLine | \ + RD_Option_DebugStr | \ + RD_Option_DebugLoc | \ + RD_Option_DebugRanges | \ + RD_Option_DebugARanges | \ + RD_Option_DebugAddr | \ + RD_Option_DebugLocLists | \ + RD_Option_DebugRngLists | \ + RD_Option_DebugPubNames | \ + RD_Option_DebugPubTypes | \ + RD_Option_DebugLineStr | \ + RD_Option_DebugStrOffsets) +#define RD_Option_RelaxDwarfParser (1ull << 31ull) +// RDI +#define RD_Option_NoRdi (1ull << 32ull) typedef struct RD_Marker { @@ -66,77 +98,124 @@ typedef struct RD_DisasmResult U64 size; } RD_DisasmResult; +typedef struct RD_Section +{ + String8 name; + String8 raw_data; +} RD_Section; + +typedef struct RD_SectionArray +{ + U64 count; + RD_Section *v; +} RD_SectionArray; + +typedef struct RD_Line +{ + String8 file_path; + U32 line_num; +} RD_Line; + //////////////////////////////// -//- Markers +// raddump + +internal B32 rd_is_pe(String8 raw_data); +internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); + +// Markers internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols); -//- Disasm +// Sections + +internal RD_SectionArray rd_sections_from_coff_section_table(Arena *arnea, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections); + +// Disasm internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code); -internal void rd_format_disasm(Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); +internal void rd_print_disasm (Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); -//- Raw Data +// Raw Data internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); -internal void rd_format_raw_data(Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); +internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); -//- CodeView +// DWARF -internal void cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); -internal void cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range); -internal void cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr); -internal void cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol); -internal U64 cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf); -internal void cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t); -internal void cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines); -internal void cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums); -internal void cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab); -internal void cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss); +internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal String8 dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal String8 dw_format_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc); +internal void dw_print_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); -//- COFF +internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx); +internal void dw_print_debug_info (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_abbrev (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_line (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed); +internal void dw_print_debug_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges, Arch arch); +internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges); +internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); -internal void coff_format_section_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); -internal void coff_disasm_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_raw_data_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_format_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); -internal void coff_format_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); -internal void coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); -internal void coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header); -internal void coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); -internal void coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); -internal void coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); -internal void coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); +// CodeView -//- MSVC CRT +internal void cv_print_binary_annots (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); +internal void cv_print_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range); +internal void cv_print_lvar_addr_gap (Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_print_lvar_attr (Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr); +internal void cv_print_symbol (Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV_TypeIndex min_itype, CV_SymKind type, String8 raw_symbol); +internal U64 cv_print_leaf (Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_itype, CV_LeafKind kind, String8 raw_leaf); +internal void cv_print_debug_t (Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t); +internal void cv_print_symbols_c13 (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); +internal void cv_print_lines_c13 (Arena *arena, String8List *out, String8 indent, String8 raw_lines); +internal void cv_print_file_checksums (Arena *arena, String8List *out, String8 indent, String8 raw_chksums); +internal void cv_print_string_table (Arena *arena, String8List *out, String8 indent, String8 raw_strtab); +internal void cv_print_inlinee_lines (Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_print_symbols_section(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_ss); -internal void mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler); +// COFF -//- PE +internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); +internal void coff_print_seciton_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); +internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); +internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); +internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); +internal void coff_print_header (Arena *arena, String8List *out, String8 indent, COFF_Header *header); +internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); +internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); -internal void pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs); -internal void pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs); -internal void pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs); -internal void pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); -internal void pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); -internal void pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); -internal void pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); -internal void pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); -internal void pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); -internal void pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); -internal void pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root); -internal void pe_format_exceptions_x8664(Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); -internal void pe_format_exceptions(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); -internal void pe_format_base_relocs(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges); -internal void pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +// MSVC CRT -//////////////////////////////// +internal void mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, MSCRT_EhHandlerType32 *handler); -internal void format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); +// PE + +internal void pe_print_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs); +internal void pe_print_optional_header32 (Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs); +internal void pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs); +internal void pe_print_load_config32 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); +internal void pe_print_load_config64 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); +internal void pe_print_tls (Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); +internal void pe_print_debug_diretory (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); +internal void pe_print_export_table (Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); +internal void pe_print_static_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); +internal void pe_print_delay_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); +internal void pe_print_resources (Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root); +internal void pe_print_exceptions_x8664 (Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi); +internal void pe_print_exceptions (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi); +internal void pe_print_base_relocs (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges, RDI_Parsed *rdi); +internal void pe_print (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts, RDI_Parsed *rdi); #endif // RADDUMP_H + diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index 432651fe..3277ba54 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -6,16 +6,25 @@ //////////////////////////////// +#include "linker/base_ext/base_blake3.h" +#include "linker/base_ext/base_blake3.c" #include "third_party/xxHash/xxhash.c" #include "third_party/xxHash/xxhash.h" #include "third_party/radsort/radsort.h" +#include "third_party/md5/md5.c" +#include "third_party/md5/md5.h" #include "third_party/zydis/zydis.h" #include "third_party/zydis/zydis.c" +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" //////////////////////////////// #include "base/base_inc.h" #include "os/os_inc.h" +#include "async/async.h" +#include "rdi_format/rdi_format_local.h" +#include "rdi_make/rdi_make_local.h" #include "path/path.h" #include "coff/coff.h" #include "coff/coff_enum.h" @@ -28,9 +37,19 @@ #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" +#include "pdb/pdb_parse.h" +#include "rdi_from_pdb/rdi_from_pdb.h" +#include "dwarf/dwarf.h" +#include "dwarf/dwarf_parse.h" +#include "dwarf/dwarf_expr.h" +#include "dwarf/dwarf_unwind.h" +#include "dwarf/dwarf_enum.h" #include "base/base_inc.c" #include "os/os_inc.c" +#include "async/async.c" +#include "rdi_format/rdi_format_local.c" +#include "rdi_make/rdi_make_local.c" #include "path/path.c" #include "coff/coff.c" #include "coff/coff_enum.c" @@ -43,9 +62,16 @@ #include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" +#include "pdb/pdb_parse.c" +#include "rdi_from_pdb/rdi_from_pdb.c" +#include "dwarf/dwarf.c" +#include "dwarf/dwarf_parse.c" +#include "dwarf/dwarf_expr.c" +#include "dwarf/dwarf_unwind.c" +#include "dwarf/dwarf_enum.c" -#include "linker/base_ext/base_core.h" -#include "linker/base_ext/base_core.c" +#include "linker/base_ext/base_inc.h" +#include "linker/base_ext/base_inc.c" #include "linker/path_ext/path.h" #include "linker/path_ext/path.c" #include "linker/thread_pool/thread_pool.h" @@ -66,29 +92,66 @@ global read_only struct char *name; char *help; } g_rd_dump_option_map[] = { - { RD_Option_Help, "help", "Print help and exit" }, - { RD_Option_Version, "v", "Print version and exit" }, - { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, - { RD_Option_Sections, "sections", "Dump section headers as table" }, - { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, - { RD_Option_Codeview, "cv", "Dump CodeView" }, - { RD_Option_Disasm, "disasm", "Disassemble code sections" }, - { RD_Option_Symbols, "symbols", "Dump COFF symbol table" }, - { RD_Option_Relocs, "relocs", "Dump relocations" }, - { RD_Option_Exceptions, "exceptions", "Dump exceptions" }, - { RD_Option_Tls, "tls", "Dump Thread Local Storage directory" }, - { RD_Option_Debug, "debug", "Dump debug directory" }, - { RD_Option_Imports, "imports", "Dump import table" }, - { RD_Option_Exports, "exports", "Dump export table" }, - { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, - { RD_Option_Resources, "resources", "Dump resource directory" }, - { RD_Option_LongNames, "longnames", "Dump archive long names" }, + { RD_Option_Help, "help", "Print help and exit" }, + { RD_Option_Version, "version", "Print version and exit" }, + { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, + { RD_Option_Sections, "sections", "Dump section headers as table" }, + { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, + { RD_Option_Codeview, "cv", "Dump CodeView" }, + { RD_Option_Disasm, "disasm", "Disassemble code sections" }, + { RD_Option_Symbols, "symtab", "Dump COFF symbol table" }, + { RD_Option_Relocs, "relocs", "Dump relocations" }, + { RD_Option_Exceptions, "exceptions", "Dump exceptions" }, + { RD_Option_Tls, "tls", "Dump Thread Local Storage directory" }, + { RD_Option_Debug, "debug", "Dump debug directory" }, + { RD_Option_Imports, "imports", "Dump import table" }, + { RD_Option_Exports, "exports", "Dump export table" }, + { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, + { RD_Option_Resources, "resources", "Dump resource directory" }, + { RD_Option_LongNames, "longnames", "Dump archive long names" }, + { RD_Option_DebugInfo, "debug_info", "Dump .debug_info" }, + { RD_Option_DebugAbbrev, "debug_abbrev", "Dump .debug_abbrev" }, + { RD_Option_DebugLine, "debug_line", "Dump .debug_line" }, + { RD_Option_DebugStr, "debug_str", "Dump .debug_str" }, + { RD_Option_DebugLoc, "debug_loc", "Dump .debug_loc" }, + { RD_Option_DebugRanges, "debug_ranges", "Dump .debug_ranges" }, + { RD_Option_DebugARanges, "debug_aranges", "Dump .debug_aranges" }, + { RD_Option_DebugAddr, "debug_addr", "Dump .debug_addr" }, + { RD_Option_DebugLocLists, "debug_loclists", "Dump .debug_loclists" }, + { RD_Option_DebugRngLists, "debug_rnglists", "Dump .debug_rnglists" }, + { RD_Option_DebugPubNames, "debug_pubnames", "Dump .debug_pubnames" }, + { RD_Option_DebugPubTypes, "debug_pubtypes", "Dump .debug_putypes" }, + { RD_Option_DebugLineStr, "debug_linestr", "Dump .debug_linestr" }, + { RD_Option_DebugStrOffsets, "debug_stroffsets", "Dump .debug_stroffsets" }, + { RD_Option_Dwarf, "dwarf", "Dump all DWARF sections" }, + { RD_Option_RelaxDwarfParser, "relax_dwarf_parser", "Relaxes version requirement on attribute and form encodings" }, + { RD_Option_NoRdi, "nordi", "Don't load RAD Debug Info" }, + + { RD_Option_Help, "h", "Alias for -help" }, + { RD_Option_Version, "v", "Alias for -version" }, + { RD_Option_Sections, "s", "Alias for -sections" }, + { RD_Option_Exceptions, "e", "Alias for -exceptions" }, + { RD_Option_Imports, "i", "Alias for -imports" }, + { RD_Option_Exports, "x", "Alias for -exports" }, + { RD_Option_LoadConfig, "l", "Alias for -loadconifg" }, + { RD_Option_Resources, "c", "Alias for -resources" }, + { RD_Option_Relocs, "r", "Alias for -relocs" }, }; internal void entry_point(CmdLine *cmdline) { - Temp scratch = scratch_begin(0,0); + Arena *arena = arena_alloc(); + + // make indent + String8List *out = push_array(arena, String8List, 1); + String8 indent; + { + U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX; + U8 *indent_buffer = push_array(arena, U8, indent_buffer_size); + MemorySet(indent_buffer, ' ', indent_buffer_size); + indent = str8(indent_buffer, 0); + } // parse options RD_Option opts = 0; @@ -107,8 +170,8 @@ entry_point(CmdLine *cmdline) } if (opt == 0) { - fprintf(stderr, "Unknown argument: \"%.*s\"\n", str8_varg(cmd->string)); - os_abort(1); + rd_errorf("Unknown argument: \"%S\"", cmd->string); + goto exit; } opts |= opt; @@ -117,66 +180,73 @@ entry_point(CmdLine *cmdline) // print help if (opts & RD_Option_Help) { + int longest_cmd_switch = 0; for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { - fprintf(stdout, "-%s %s\n", g_rd_dump_option_map[opt_idx].name, g_rd_dump_option_map[opt_idx].help); + longest_cmd_switch = Max(longest_cmd_switch, strlen(g_rd_dump_option_map[opt_idx].name)); } - os_abort(0); + rd_printf(BUILD_TITLE_STRING_LITERAL); + rd_newline(); + rd_printf("# Help"); + rd_indent(); + for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { + char *name = g_rd_dump_option_map[opt_idx].name; + char *help = g_rd_dump_option_map[opt_idx].help; + int indent_size = longest_cmd_switch - strlen(name) + 1; + rd_printf("-%s%.*s%s", g_rd_dump_option_map[opt_idx].name, indent_size, indent.str, g_rd_dump_option_map[opt_idx].help); + } + rd_unindent(); + goto exit; } // print version if (opts & RD_Option_Version) { - fprintf(stdout, BUILD_TITLE_STRING_LITERAL "\n"); - fprintf(stdout, "\traddump \n"); - os_abort(0); + rd_printf(BUILD_TITLE_STRING_LITERAL); + rd_printf("\traddump "); + goto exit; } // input check if (cmdline->inputs.node_count == 0) { - fprintf(stderr, "No input file specified\n"); - os_abort(1); + rd_errorf("No input file specified"); + goto exit; } else if (cmdline->inputs.node_count > 1) { - fprintf(stderr, "Too many inputs specified, expected one\n"); - os_abort(1); + rd_errorf("Too many inputs specified, expected one"); + goto exit; } // read input String8 file_path = str8_list_first(&cmdline->inputs); - String8 raw_data = os_data_from_file_path(scratch.arena, file_path); + String8 raw_data = os_data_from_file_path(arena, file_path); // is read ok? if (raw_data.size == 0) { - fprintf(stderr, "Unable to read input file \"%.*s\"\n", str8_varg(file_path)); - os_abort(1); - } - - // make indent - String8 indent; - { - U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX; - U8 *indent_buffer = push_array(scratch.arena, U8, indent_buffer_size); - MemorySet(indent_buffer, ' ', indent_buffer_size); - indent = str8(indent_buffer, 0); + rd_errorf("Unable to read input file \"%S\"", file_path); + goto exit; } // format input - String8List out = {0}; - format_preamble(scratch.arena, &out, indent, file_path, raw_data); + rd_format_preamble(arena, out, indent, file_path, raw_data); if (coff_is_archive(raw_data) || coff_is_thin_archive(raw_data)) { - coff_format_archive(scratch.arena, &out, indent, raw_data, opts); + coff_print_archive(arena, out, indent, raw_data, opts); } else if (coff_is_big_obj(raw_data)) { - coff_format_big_obj(scratch.arena, &out, indent, raw_data, opts); + coff_print_big_obj(arena, out, indent, raw_data, opts); } else if (coff_is_obj(raw_data)) { - coff_format_obj(scratch.arena, &out, indent, raw_data, opts); - } else if (is_pe(raw_data)) { - pe_format(scratch.arena, &out, indent, raw_data, opts); + coff_print_obj(arena, out, indent, raw_data, opts); + } else if (rd_is_pe(raw_data)) { + RDI_Parsed *rdi = 0; + if (!(opts & RD_Option_NoRdi)) { + rdi = rd_rdi_from_pe(arena, file_path, raw_data); + } + pe_print(arena, out, indent, raw_data, opts, rdi); } else if (pe_is_res(raw_data)) { //tool_out_coff_res(stdout, file_data); } +exit:; // print formatted string - String8 out_string = str8_list_join(scratch.arena, &out, &(StringJoin){ .sep = str8_lit("\n"),}); + String8 out_string = str8_list_join(arena, out, &(StringJoin){ .sep = str8_lit("\n"),}); fprintf(stdout, "%.*s", str8_varg(out_string)); - scratch_end(scratch); + arena_release(arena); } From 0d0a6d3980addfc72c4fda2a7ba90964ee46a691 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:14:41 -0800 Subject: [PATCH 10/53] fixed compile error in Linux entry point --- src/os/core/linux/os_core_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 604786b4..3b2c73b1 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1326,5 +1326,5 @@ main(int argc, char **argv) } //- rjf: call into "real" entry point - main_thread_base_entry_point(arguments_count, arguments); + main_thread_base_entry_point(argc, argv); } From d0d1786cec870254e94dea1771b3dea725e6026a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:17:37 -0800 Subject: [PATCH 11/53] define enum for image type --- src/base/base_core.h | 9 +++++++++ src/dwarf/dwarf_parse.c | 6 +++--- src/raddump/raddump.c | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index b8058de9..191e1e7f 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -454,6 +454,15 @@ typedef enum OperatingSystem } OperatingSystem; +typedef enum ImageType +{ + Image_Null, + Image_CoffPe, + Image_Elf32, + Image_Elf64, + Image_Macho +} ImageType; + typedef enum Arch { Arch_Null, diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index ee0df7ef..31c52af7 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -1473,15 +1473,15 @@ dw_ext_from_params(String8 producer, Arch arch, ImageType image_type) DW_Ext ext = DW_Ext_Null; switch (image_type) { case Image_Null: break; - case Image_COFF_PE: { + case Image_CoffPe: { if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU | DW_Ext_LLVM; } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU; } } break; - case Image_ELF32: - case Image_ELF64: { + case Image_Elf32: + case Image_Elf64: { if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU | DW_Ext_LLVM; } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 35d3e47d..189fcc48 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -5159,7 +5159,7 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, if (opts & RD_Option_Dwarf) { DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, header->section_count, sections); - dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_CoffPe); } exit:; @@ -6857,7 +6857,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (opts & RD_Option_Dwarf) { DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, sections); - dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_CoffPe); } exit:; From 42e441541dfb59480cc1689952ffa832f581afcf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:18:18 -0800 Subject: [PATCH 12/53] fixes for LEB decode --- src/base/base_strings.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 1e47ac37..9e42e0cd 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -2377,16 +2377,22 @@ str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) U64 value = 0; U64 shift = 0; U64 cursor = off; - for( ;; ++cursor, shift += 7u) + for(;;) { U8 byte = 0; U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + if(bytes_read != sizeof(byte)) { break; } + U8 val = byte & 0x7fu; value |= ((U64)val) << shift; + + cursor += bytes_read; + shift += 7u; + if((byte & 0x80u) == 0) { break; @@ -2406,7 +2412,7 @@ str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) U64 value = 0; U64 shift = 0; U64 cursor = off; - for( ;; ++cursor) + for(;;) { U8 byte; U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); @@ -2414,9 +2420,13 @@ str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) { break; } + U8 val = byte & 0x7fu; value |= ((U64)val) << shift; + + cursor += bytes_read; shift += 7u; + if((byte & 0x80u) == 0) { if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) From 2b33978037d047bbea35497843a76124a861f560 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:23:13 -0800 Subject: [PATCH 13/53] updated name convention for flag extract macro in CodeView layer --- src/codeview/codeview.c | 4 +- src/codeview/codeview.h | 86 +++++------ src/codeview/codeview_enum.c | 264 +++++++++++++++++++++++++++----- src/codeview/codeview_enum.h | 6 +- src/codeview/codeview_parse.c | 16 +- src/rdi_from_pdb/rdi_from_pdb.c | 10 +- 6 files changed, 283 insertions(+), 103 deletions(-) diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index ac8de886..84ec882e 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -96,11 +96,11 @@ cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B32 is_local_param) CV_EncodedFramePtrReg fp_reg = 0; if(is_local_param) { - fp_reg = CV_FrameprocFlags_ExtractParamBasePointer(frameproc->flags); + fp_reg = CV_FrameprocFlags_Extract_ParamBasePointer(frameproc->flags); } else { - fp_reg = CV_FrameprocFlags_ExtractLocalBasePointer(frameproc->flags); + fp_reg = CV_FrameprocFlags_Extract_LocalBasePointer(frameproc->flags); } return fp_reg; } diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index d3796d4f..2ac3aece 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -1123,12 +1123,12 @@ struct CV_LocalVarAttr //- (SymKind: COMPILE) typedef U32 CV_CompileFlags; -#define CV_CompileFlags_ExtractLanguage(f) (((f) )&0xFF) -#define CV_CompileFlags_ExtractFloatPrec(f) (((f)>> 8)&0x03) -#define CV_CompileFlags_ExtractFloatPkg(f) (((f)>>10)&0x03) -#define CV_CompileFlags_ExtractAmbientData(f) (((f)>>12)&0x07) -#define CV_CompileFlags_ExtractAmbientCode(f) (((f)>>15)&0x07) -#define CV_CompileFlags_ExtractMode(f) (((f)>>18)&0x01) +#define CV_CompileFlags_Extract_Language(f) (((f) )&0xFF) +#define CV_CompileFlags_Extract_FloatPrec(f) (((f)>> 8)&0x03) +#define CV_CompileFlags_Extract_FloatPkg(f) (((f)>>10)&0x03) +#define CV_CompileFlags_Extract_AmbientData(f) (((f)>>12)&0x07) +#define CV_CompileFlags_Extract_AmbientCode(f) (((f)>>15)&0x07) +#define CV_CompileFlags_Extract_Mode(f) (((f)>>18)&0x01) typedef struct CV_SymCompile CV_SymCompile; struct CV_SymCompile @@ -1246,8 +1246,8 @@ enum CV_FrameprocFlag_HasCFG = (1 << 21), CV_FrameprocFlag_HasCFW = (1 << 22), }; -#define CV_FrameprocFlags_ExtractLocalBasePointer(f) (((f) >> 14)&3) -#define CV_FrameprocFlags_ExtractParamBasePointer(f) (((f) >> 16)&3) +#define CV_FrameprocFlags_Extract_LocalBasePointer(f) (((f) >> 14)&3) +#define CV_FrameprocFlags_Extract_ParamBasePointer(f) (((f) >> 16)&3) typedef struct CV_SymFrameproc CV_SymFrameproc; struct CV_SymFrameproc @@ -1457,16 +1457,16 @@ struct CV_SymThread32 //- (SymKind: COMPILE2) typedef U32 CV_Compile2Flags; -#define CV_Compile2Flags_ExtractLanguage(f) (((f) )&0xFF) -#define CV_Compile2Flags_ExtractEditAndContinue(f) (((f)>> 8)&0x01) -#define CV_Compile2Flags_ExtractNoDbgInfo(f) (((f)>> 9)&0x01) -#define CV_Compile2Flags_ExtractLTCG(f) (((f)>>10)&0x01) -#define CV_Compile2Flags_ExtractNoDataAlign(f) (((f)>>11)&0x01) -#define CV_Compile2Flags_ExtractManagedPresent(f) (((f)>>12)&0x01) -#define CV_Compile2Flags_ExtractSecurityChecks(f) (((f)>>13)&0x01) -#define CV_Compile2Flags_ExtractHotPatch(f) (((f)>>14)&0x01) -#define CV_Compile2Flags_ExtractCVTCIL(f) (((f)>>15)&0x01) -#define CV_Compile2Flags_ExtractMSILModule(f) (((f)>>16)&0x01) +#define CV_Compile2Flags_Extract_Language(f) (((f) )&0xFF) +#define CV_Compile2Flags_Extract_EditAndContinue(f) (((f)>> 8)&0x01) +#define CV_Compile2Flags_Extract_NoDbgInfo(f) (((f)>> 9)&0x01) +#define CV_Compile2Flags_Extract_LTCG(f) (((f)>>10)&0x01) +#define CV_Compile2Flags_Extract_NoDataAlign(f) (((f)>>11)&0x01) +#define CV_Compile2Flags_Extract_ManagedPresent(f) (((f)>>12)&0x01) +#define CV_Compile2Flags_Extract_SecurityChecks(f) (((f)>>13)&0x01) +#define CV_Compile2Flags_Extract_HotPatch(f) (((f)>>14)&0x01) +#define CV_Compile2Flags_Extract_CVTCIL(f) (((f)>>15)&0x01) +#define CV_Compile2Flags_Extract_MSILModule(f) (((f)>>16)&0x01) typedef struct CV_SymCompile2 CV_SymCompile2; struct CV_SymCompile2 @@ -1737,19 +1737,19 @@ enum }; typedef U32 CV_Compile3Flags; -#define CV_Compile3Flags_ExtractLanguage(f) (((f) )&0xFF) -#define CV_Compile3Flags_ExtractEditAndContinue(f) (((f)>> 9)&0x01) -#define CV_Compile3Flags_ExtractNoDbgInfo(f) (((f)>>10)&0x01) -#define CV_Compile3Flags_ExtractLTCG(f) (((f)>>11)&0x01) -#define CV_Compile3Flags_ExtractNoDataAlign(f) (((f)>>12)&0x01) -#define CV_Compile3Flags_ExtractManagedPresent(f) (((f)>>13)&0x01) -#define CV_Compile3Flags_ExtractSecurityChecks(f) (((f)>>14)&0x01) -#define CV_Compile3Flags_ExtractHotPatch(f) (((f)>>15)&0x01) -#define CV_Compile3Flags_ExtractCVTCIL(f) (((f)>>16)&0x01) -#define CV_Compile3Flags_ExtractMSILModule(f) (((f)>>17)&0x01) -#define CV_Compile3Flags_ExtractSDL(f) (((f)>>18)&0x01) -#define CV_Compile3Flags_ExtractPGO(f) (((f)>>19)&0x01) -#define CV_Compile3Flags_ExtractEXP(f) (((f)>>20)&0x01) +#define CV_Compile3Flags_Extract_Language(f) (((f) )&0xFF) +#define CV_Compile3Flags_Extract_EditAndContinue(f) (((f)>> 9)&0x01) +#define CV_Compile3Flags_Extract_NoDbgInfo(f) (((f)>>10)&0x01) +#define CV_Compile3Flags_Extract_LTCG(f) (((f)>>11)&0x01) +#define CV_Compile3Flags_Extract_NoDataAlign(f) (((f)>>12)&0x01) +#define CV_Compile3Flags_Extract_ManagedPresent(f) (((f)>>13)&0x01) +#define CV_Compile3Flags_Extract_SecurityChecks(f) (((f)>>14)&0x01) +#define CV_Compile3Flags_Extract_HotPatch(f) (((f)>>15)&0x01) +#define CV_Compile3Flags_Extract_CVTCIL(f) (((f)>>16)&0x01) +#define CV_Compile3Flags_Extract_MSILModule(f) (((f)>>17)&0x01) +#define CV_Compile3Flags_Extract_SDL(f) (((f)>>18)&0x01) +#define CV_Compile3Flags_Extract_PGO(f) (((f)>>19)&0x01) +#define CV_Compile3Flags_Extract_EXP(f) (((f)>>20)&0x01) typedef struct CV_SymCompile3 CV_SymCompile3; struct CV_SymCompile3 @@ -1853,7 +1853,7 @@ struct CV_SymDefrangeFramepointerRel //- (SymKind: DEFRANGE_SUBFIELD_REGISTER) -#define CV_DefrangeSubfieldRegister_ExtractParentOffset(x) ((x) & 0x1FFF) +#define CV_DefrangeSubfieldRegister_Extract_ParentOffset(x) ((x) & 0x1FFF) typedef struct CV_SymDefrangeSubfieldRegister CV_SymDefrangeSubfieldRegister; struct CV_SymDefrangeSubfieldRegister @@ -1880,7 +1880,7 @@ enum { CV_DefrangeRegisterRelFlag_SpilledOutUDTMember = (1 << 0), }; -#define CV_DefrangeRegisterRelFlag_ExtractOffsetParent(f) (((f)>>4)&0xFFF) +#define CV_DefrangeRegisterRelFlag_Extract_OffsetParent(f) (((f)>>4)&0xFFF) typedef struct CV_SymDefrangeRegisterRel CV_SymDefrangeRegisterRel; struct CV_SymDefrangeRegisterRel @@ -2166,8 +2166,8 @@ enum CV_TypeProp_Intrinsic = (1 << 13), // MOCOM: 14,15 }; -#define CV_TypeProps_ExtractHFA(f) (((f)>>11)&0x3) -#define CV_TypeProps_ExtractMOCOM(f) (((f)>>14)&0x3) +#define CV_TypeProps_Extract_HFA(f) (((f)>>11)&0x3) +#define CV_TypeProps_Extract_MOCOM(f) (((f)>>14)&0x3) typedef U8 CV_PointerKind; typedef enum CV_PointerKindEnum @@ -2259,8 +2259,8 @@ enum CV_FieldAttrib_CompilerGenated = (1<<8), CV_FieldAttrib_Sealed = (1<<9), }; -#define CV_FieldAttribs_ExtractAccess(f) ((f)&0x3) -#define CV_FieldAttribs_ExtractMethodProp(f) (((f)>>2)&0x7) +#define CV_FieldAttribs_Extract_Access(f) ((f)&0x3) +#define CV_FieldAttribs_Extract_MethodProp(f) (((f)>>2)&0x7) typedef U16 CV_LabelKind; typedef enum CV_LabelKindEnum @@ -2408,9 +2408,9 @@ enum CV_PointerAttrib_RRef = (1 << 22) }; -#define CV_PointerAttribs_ExtractKind(a) ((a)&0x1F) -#define CV_PointerAttribs_ExtractMode(a) (((a)>>5)&0x7) -#define CV_PointerAttribs_ExtractSize(a) (((a)>>13)&0x3F) +#define CV_PointerAttribs_Extract_Kind(a) ((a)&0x1F) +#define CV_PointerAttribs_Extract_Mode(a) (((a)>>5)&0x7) +#define CV_PointerAttribs_Extract_Size(a) (((a)>>13)&0x3F) typedef struct CV_LeafPointer CV_LeafPointer; struct CV_LeafPointer @@ -2861,9 +2861,9 @@ struct CV_C13File }; typedef U32 CV_C13LineFlags; -#define CV_C13LineFlags_ExtractLineNumber(f) ((f)&0xFFFFFF) -#define CV_C13LineFlags_ExtractDeltaToEnd(f) (((f)>>24)&0x7F) -#define CV_C13LineFlags_ExtractStatement(f) (((f)>>31)&0x1) +#define CV_C13LineFlags_Extract_LineNumber(f) ((f)&0xFFFFFF) +#define CV_C13LineFlags_Extract_DeltaToEnd(f) (((f)>>24)&0x7F) +#define CV_C13LineFlags_Extract_Statement(f) (((f)>>31)&0x1) typedef struct CV_C13Line CV_C13Line; struct CV_C13Line diff --git a/src/codeview/codeview_enum.c b/src/codeview/codeview_enum.c index ada3d2c5..8442ace9 100644 --- a/src/codeview/codeview_enum.c +++ b/src/codeview/codeview_enum.c @@ -29,12 +29,12 @@ cv_string_from_numeric(Arena *arena, CV_NumericParsed num) { String8 result = str8_zero(); switch (num.kind) { - case CV_NumericKind_FLOAT16: break; // TODO: format float16 + case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16 case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break; - case CV_NumericKind_FLOAT48: break; // TODO: format float48 + case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48 case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break; - case CV_NumericKind_FLOAT80: break; // TODO: format float80 - case CV_NumericKind_FLOAT128: break; // TODO: format float128 + case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80 + case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128 case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break; case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break; case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break; @@ -47,25 +47,28 @@ cv_string_from_numeric(Arena *arena, CV_NumericParsed num) } internal String8 -cv_string_from_reg_id(CV_Arch arch, U32 id) +cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id) { String8 result = str8_zero(); switch (arch) { case CV_Arch_8086: { switch (id) { - #define X(_name, _id,...) case _id: str8_lit(Stringify(_name)); break; + #define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break; CV_Reg_X86_XList(X) #undef X } } break; case CV_Arch_X64: { switch (id) { - #define X(_name, _id,...) case _id: str8_lit(Stringify(_name)); break; + #define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break; CV_Reg_X64_XList(X) #undef X } } break; - default: NotImplemented; + default: NotImplemented; break; + } + if (result.size == 0) { + result = push_str8f(arena, "%x", id); } return result; } @@ -274,7 +277,7 @@ cv_string_from_pointer_kind(CV_PointerKind x) case CV_PointerKind_BaseSelf: return str8_lit("BaseSelf"); case CV_PointerKind_Near32: return str8_lit("Near32"); case CV_PointerKind_Far32: return str8_lit("Far32"); - case CV_PointerKind_64: return str8_lit("64"); + case CV_PointerKind_64: return str8_lit("64Bit"); } return str8_zero(); } @@ -308,7 +311,7 @@ internal String8 cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x) { switch (x) { - #define X(_id, _name) case CV_C13SubSectionKind_##_id: return str8_lit(Stringify(_name)); + #define X(_N, _ID) case CV_C13SubSectionKind_##_N: return str8_lit(Stringify(_N)); CV_C13SubSectionKindXList(X) #undef X } @@ -331,37 +334,70 @@ cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x) } String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); + return result; } internal String8 cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x) { Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; if (x & CV_PointerAttrib_IsFlat) { + x &= ~CV_PointerAttrib_IsFlat; str8_list_pushf(scratch.arena, &list, "IsFlat"); } if (x & CV_PointerAttrib_Volatile) { + x &= ~CV_PointerAttrib_Volatile; str8_list_pushf(scratch.arena, &list, "Volatile"); } if (x & CV_PointerAttrib_Const) { + x &= ~CV_PointerAttrib_Const; str8_list_pushf(scratch.arena, &list, "Const"); } if (x & CV_PointerAttrib_Unaligned) { + x &= ~CV_PointerAttrib_Unaligned; str8_list_pushf(scratch.arena, &list, "Unaligned"); } if (x & CV_PointerAttrib_Restricted) { + x &= ~CV_PointerAttrib_Restricted; str8_list_pushf(scratch.arena, &list, "Restricted"); } if (x & CV_PointerAttrib_MOCOM) { + x &= ~CV_PointerAttrib_MOCOM; str8_list_pushf(scratch.arena, &list, "MOCOM"); } if (x & CV_PointerAttrib_LRef) { + x &= ~CV_PointerAttrib_LRef; str8_list_pushf(scratch.arena, &list, "LRef"); } if (x & CV_PointerAttrib_RRef) { + x &= ~CV_PointerAttrib_RRef; str8_list_pushf(scratch.arena, &list, "RRef"); } + + CV_PointerKind kind = CV_PointerAttribs_Extract_Kind(x); + CV_PointerMode mode = CV_PointerAttribs_Extract_Mode(x); + U64 size = CV_PointerAttribs_Extract_Size(x); + + x &= ~(0x1f|(0x7<<5)|(0x3f<<13)); + + if (kind) { + String8 kind_str = cv_string_from_pointer_kind(kind); + str8_list_pushf(scratch.arena, &list, "Kind=%S", kind_str); + } + if (mode) { + String8 mode_str = cv_string_from_pointer_mode(mode); + str8_list_pushf(scratch.arena, &list, "Mode=%S", mode_str); + } + if (size) { + str8_list_pushf(scratch.arena, &list, "Size=%llu", size); + } + + if (x != 0) { + str8_list_pushf(scratch.arena, &list, "Unknown=%x", x); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); return result; @@ -453,7 +489,7 @@ cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x) } internal String8 -cv_string_generic_flags(Arena *arena, CV_GenericFlags x) +cv_string_from_generic_flags(Arena *arena, CV_GenericFlags x) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; @@ -539,51 +575,78 @@ internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps x) { Temp scratch = scratch_begin(&arena, 1); + U32 hfa = CV_TypeProps_Extract_HFA(x); U32 mcom = CV_TypeProps_Extract_MOCOM(x); + String8 hfa_str = cv_string_from_hfa(hfa); + String8 mcom_str = cv_string_from_mcom(mcom); + String8 flags_str; { String8List list = {0}; if (x & CV_TypeProp_Packed) { + x &= ~CV_TypeProp_Packed; str8_list_pushf(scratch.arena, &list, "Packed"); } if (x & CV_TypeProp_HasConstructorsDestructors) { + x &= ~CV_TypeProp_HasConstructorsDestructors; str8_list_pushf(scratch.arena, &list, "HasConstructorsDestructors"); } if (x & CV_TypeProp_OverloadedOperators) { + x &= ~CV_TypeProp_OverloadedOperators; str8_list_pushf(scratch.arena, &list, "OverloadedOperators"); } if (x & CV_TypeProp_IsNested) { + x &= ~CV_TypeProp_IsNested; str8_list_pushf(scratch.arena, &list, "IsNested"); } if (x & CV_TypeProp_ContainsNested) { + x &= ~CV_TypeProp_ContainsNested; str8_list_pushf(scratch.arena, &list, "ContainsNested"); } if (x & CV_TypeProp_OverloadedAssignment) { + x &= ~CV_TypeProp_OverloadedAssignment; str8_list_pushf(scratch.arena, &list, "OverloadedAssignment"); } if (x & CV_TypeProp_OverloadedCasting) { + x &= ~CV_TypeProp_OverloadedCasting; str8_list_pushf(scratch.arena, &list, "OverloadedCasting"); } if (x & CV_TypeProp_FwdRef) { + x &= ~CV_TypeProp_FwdRef; str8_list_pushf(scratch.arena, &list, "FwdRef"); } if (x & CV_TypeProp_Scoped) { + x &= ~CV_TypeProp_Scoped; str8_list_pushf(scratch.arena, &list, "Scoped"); } if (x & CV_TypeProp_HasUniqueName) { + x &= ~CV_TypeProp_HasUniqueName; str8_list_pushf(scratch.arena, &list, "HasUniqueName"); } if (x & CV_TypeProp_Sealed) { + x &= ~CV_TypeProp_Sealed; str8_list_pushf(scratch.arena, &list, "Sealed"); } + if (x & CV_TypeProp_Intrinsic) { + x &= ~CV_TypeProp_Intrinsic; + str8_list_pushf(scratch.arena, &list, "Intrinsic"); + } + if (x != 0) { + str8_list_pushf(scratch.arena, &list, "%x", x); + } flags_str = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ") }); + + if (hfa) { + str8_list_pushf(scratch.arena, &list, "HFA = %S", hfa_str); + } + if (mcom) { + str8_list_pushf(scratch.arena, &list, "MCOM = %S", mcom_str); + } } - String8 hfa_str = cv_string_from_hfa(hfa); - String8 mcom_str = cv_string_from_mcom(mcom); - String8 result = push_str8f(arena, "flags = %S, HFA = %S, MCOM = %S", flags_str, hfa_str, mcom_str); + String8 result = push_str8f(arena, "%S", flags_str); scratch_end(scratch); return result; @@ -638,30 +701,46 @@ cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x) Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; if (x & CV_ProcFlag_NoFPO) { + x &= ~CV_ProcFlag_NoFPO; str8_list_pushf(scratch.arena, &list, "NoFPO"); } if (x & CV_ProcFlag_IntReturn) { + x &= ~CV_ProcFlag_IntReturn; str8_list_pushf(scratch.arena, &list, "IntReturn"); } if (x & CV_ProcFlag_FarReturn) { + x &= ~CV_ProcFlag_FarReturn; str8_list_pushf(scratch.arena, &list, "FarReturn"); } if (x & CV_ProcFlag_NeverReturn) { + x &= ~CV_ProcFlag_NeverReturn; str8_list_pushf(scratch.arena, &list, "NeverReturn"); } if (x & CV_ProcFlag_NotReached) { + x &= ~CV_ProcFlag_NotReached; str8_list_pushf(scratch.arena, &list, "NotReached"); } if (x & CV_ProcFlag_CustomCall) { + x &= ~CV_ProcFlag_CustomCall; str8_list_pushf(scratch.arena, &list, "CustomCall"); } if (x & CV_ProcFlag_NoInline) { + x &= ~CV_ProcFlag_NoInline; str8_list_pushf(scratch.arena, &list, "NoInline"); } if (x & CV_ProcFlag_OptDbgInfo) { + x &= ~CV_ProcFlag_OptDbgInfo; str8_list_pushf(scratch.arena, &list, "OptDbgInfo"); } - String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + if (x != 0) { + str8_list_pushf(scratch.arena, &list, "%#x", x); + } + String8 result; + if (list.node_count == 0) { + result = str8_lit("None"); + } else { + result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + } temp_end(scratch); return result; } @@ -691,42 +770,140 @@ cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs) { Temp scratch = scratch_begin(&arena, 1); - U32 access = CV_FieldAttribs_Extract_ACCESS(attribs); - U32 mprop = CV_FieldAttribs_Extract_MPROP(attribs); - - String8 attribs_str; - { - String8List list = {0}; - if (attribs & CV_FieldAttrib_Pseudo) { - str8_list_pushf(scratch.arena, &list, "Pseudo"); - } - if (attribs & CV_FieldAttrib_NoInherit) { - str8_list_pushf(scratch.arena, &list, "NoInherit"); - } - if (attribs & CV_FieldAttrib_NoConstruct) { - str8_list_pushf(scratch.arena, &list, "NoConstruct"); - } - if (attribs & CV_FieldAttrib_CompilerGenated) { - str8_list_pushf(scratch.arena, &list, "CompilerGenerated"); - } - if (attribs & CV_FieldAttrib_Sealed) { - str8_list_pushf(scratch.arena, &list, "Sealed"); - } - attribs_str = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=", " }); - } + U32 access = CV_FieldAttribs_Extract_Access(attribs); + U32 mprop = CV_FieldAttribs_Extract_MethodProp(attribs); + attribs &= ~(0x3 | 0x7); String8 access_str = cv_string_from_member_access(access); String8 mprop_str = cv_string_from_method_prop(mprop); - String8 result = push_str8f(arena, "flags = %S, access = %S, method prop = %S", attribs_str, access_str, mprop_str); + + String8List list = {0}; + { + if (attribs & CV_FieldAttrib_Pseudo) { + attribs &= ~CV_FieldAttrib_Pseudo; + str8_list_pushf(scratch.arena, &list, "Pseudo"); + } + if (attribs & CV_FieldAttrib_NoInherit) { + attribs &= ~CV_FieldAttrib_NoInherit; + str8_list_pushf(scratch.arena, &list, "NoInherit"); + } + if (attribs & CV_FieldAttrib_NoConstruct) { + attribs &= ~CV_FieldAttrib_NoConstruct; + str8_list_pushf(scratch.arena, &list, "NoConstruct"); + } + if (attribs & CV_FieldAttrib_CompilerGenated) { + attribs &= ~CV_FieldAttrib_CompilerGenated; + str8_list_pushf(scratch.arena, &list, "CompilerGenerated"); + } + if (attribs & CV_FieldAttrib_Sealed) { + attribs &= ~CV_FieldAttrib_Sealed; + str8_list_pushf(scratch.arena, &list, "Sealed"); + } + if (attribs) { + str8_list_pushf(scratch.arena, &list, "Unknown: %x", attribs); + } + } + + if (access) { + str8_list_pushf(scratch.arena, &list, "%S", access_str); + } + if (mprop) { + str8_list_pushf(scratch.arena, &list, "%S", mprop_str); + } + + String8 result = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); return result; } internal String8 -cv_string_from_itype(Arena *arena, CV_TypeIndex itype) +cv_string_from_itype(Arena *arena, CV_TypeIndex min_itype, CV_TypeIndex itype) { - String8 result = push_str8f(arena, "%x", itype); + String8 result = str8_zero(); + if (itype < min_itype) { + String8 n = cv_type_name_from_basic_type((CV_BasicType)itype); + if (n.size) { + Temp scratch = scratch_begin(&arena, 1); + + U64 type = CV_BasicTypeFromTypeId(itype); + char *type_str = "???"; + switch (type) { + case CV_BasicType_NOTYPE: type_str = "NOTYPE"; break; + case CV_BasicType_ABS: type_str = "ABS"; break; + case CV_BasicType_SEGMENT: type_str = "SEGMENT"; break; + case CV_BasicType_VOID: type_str = "VOID"; break; + case CV_BasicType_CURRENCY: type_str = "CURRENCY"; break; + case CV_BasicType_NBASICSTR: type_str = "NBASICSTR"; break; + case CV_BasicType_FBASICSTR: type_str = "FBASICSTR"; break; + case CV_BasicType_NOTTRANS: type_str = "NOTTRANS"; break; + case CV_BasicType_HRESULT: type_str = "HRESULT"; break; + case CV_BasicType_CHAR: type_str = "CHAR"; break; + case CV_BasicType_SHORT: type_str = "SHORT"; break; + case CV_BasicType_LONG: type_str = "LONG"; break; + case CV_BasicType_QUAD: type_str = "QUAD"; break; + case CV_BasicType_OCT: type_str = "OCT"; break; + case CV_BasicType_UCHAR: type_str = "UCHAR"; break; + case CV_BasicType_USHORT: type_str = "USHORT"; break; + case CV_BasicType_ULONG: type_str = "ULONG"; break; + case CV_BasicType_UQUAD: type_str = "UQUAD"; break; + case CV_BasicType_UOCT: type_str = "UOCT"; break; + case CV_BasicType_BOOL8: type_str = "BOOL8"; break; + case CV_BasicType_BOOL16: type_str = "BOOL16"; break; + case CV_BasicType_BOOL32: type_str = "BOOL32"; break; + case CV_BasicType_BOOL64: type_str = "BOOL64"; break; + case CV_BasicType_FLOAT32: type_str = "FLOAT32"; break; + case CV_BasicType_FLOAT64: type_str = "FLOAT64"; break; + case CV_BasicType_FLOAT80: type_str = "FLOAT80"; break; + case CV_BasicType_FLOAT128: type_str = "FLOAT128"; break; + case CV_BasicType_FLOAT48: type_str = "FLOAT48"; break; + case CV_BasicType_FLOAT32PP: type_str = "FLOAT32PP"; break; + case CV_BasicType_FLOAT16: type_str = "FLOAT16"; break; + case CV_BasicType_COMPLEX32: type_str = "COMPLEX32"; break; + case CV_BasicType_COMPLEX64: type_str = "COMPLEX64"; break; + case CV_BasicType_COMPLEX80: type_str = "COMPLEX80"; break; + case CV_BasicType_COMPLEX128: type_str = "COMPLEX128"; break; + case CV_BasicType_BIT: type_str = "BIT"; break; + case CV_BasicType_PASCHAR: type_str = "PASCHAR"; break; + case CV_BasicType_BOOL32FF: type_str = "BOOL32FF"; break; + case CV_BasicType_INT8: type_str = "INT8"; break; + case CV_BasicType_UINT8: type_str = "UINT8"; break; + case CV_BasicType_RCHAR: type_str = "RCHAR"; break; + case CV_BasicType_WCHAR: type_str = "WCHAR"; break; + case CV_BasicType_INT16: type_str = "INT16"; break; + case CV_BasicType_UINT16: type_str = "UINT16"; break; + case CV_BasicType_INT32: type_str = "INT32"; break; + case CV_BasicType_UINT32: type_str = "UINT32"; break; + case CV_BasicType_INT64: type_str = "INT64"; break; + case CV_BasicType_UINT64: type_str = "UINT64"; break; + case CV_BasicType_INT128: type_str = "INT128"; break; + case CV_BasicType_UINT128: type_str = "UINT128"; break; + case CV_BasicType_CHAR16: type_str = "CHAR16"; break; + case CV_BasicType_CHAR32: type_str = "CHAR32"; break; + case CV_BasicType_CHAR8: type_str = "CHAR8"; break; + case CV_BasicType_PTR: type_str = "PTR"; break; + } + + U64 ptr = CV_BasicPointerKindFromTypeId(itype); + char *ptr_str = ""; + switch (ptr) { + case 0x1: ptr_str = "P"; break; + case 0x2: ptr_str = "PF"; break; + case 0x3: ptr_str = "PH"; break; + case 0x4: ptr_str = "32P"; break; + case 0x5: ptr_str = "32PF"; break; + case 0x6: ptr_str = "64P"; break; + } + + n = upper_from_str8(scratch.arena, n); + result = push_str8f(arena, "T_%s%s(%x)", ptr_str, type_str, itype); + scratch_end(scratch); + } else { + result = push_str8f(arena, "%x", itype); + } + } else { + result = push_str8f(arena, "%x", itype); + } return result; } @@ -740,7 +917,10 @@ cv_string_from_itemid(Arena *arena, CV_ItemId itemid) internal String8 cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off) { - return push_str8f(arena, "%S+%x", cv_string_from_reg_id(arch, reg), off); + Temp scratch = scratch_begin(&arena, 1); + String8 result = push_str8f(arena, "%S+%x", cv_string_from_reg_id(scratch.arena, arch, reg), off); + scratch_end(scratch); + return result; } internal String8 diff --git a/src/codeview/codeview_enum.h b/src/codeview/codeview_enum.h index c15392a9..3216f867 100644 --- a/src/codeview/codeview_enum.h +++ b/src/codeview/codeview_enum.h @@ -7,7 +7,7 @@ internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source); internal String8 cv_string_from_language(CV_Language x); internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num); -internal String8 cv_string_from_reg_id(CV_Arch arch, U32 id); +internal String8 cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id); internal String8 cv_string_from_member_access(CV_MemberAccess x); internal String8 cv_string_from_method_prop(CV_MethodProp x); internal String8 cv_string_from_hfa(CV_HFAKind x); @@ -30,7 +30,7 @@ internal String8 cv_string_from_function_attribs(Arena *arena, CV_FunctionAttrib internal String8 cv_string_from_export_flags(Arena *arena, CV_ExportFlags x); internal String8 cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x); internal String8 cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x); -internal String8 cv_string_generic_flags(Arena *arena, CV_GenericFlags x); +internal String8 cv_string_from_generic_flags(Arena *arena, CV_GenericFlags x); internal String8 cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x); internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps x); internal String8 cv_string_from_local_flags(Arena *arena, CV_LocalFlags x); @@ -38,7 +38,7 @@ internal String8 cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x); internal String8 cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x); internal String8 cv_string_from_defrange_register_rel_flags(Arena *arena, CV_DefrangeRegisterRelFlags x); internal String8 cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs); -internal String8 cv_string_from_itype(Arena *arena, CV_TypeIndex itype); +internal String8 cv_string_from_itype(Arena *arena, CV_TypeIndex min_itype, CV_TypeIndex itype); internal String8 cv_string_from_itemid(Arena *arena, CV_ItemId itemid); internal String8 cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off); internal String8 cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type); diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c index da09881b..c1b0e30c 100644 --- a/src/codeview/codeview_parse.c +++ b/src/codeview/codeview_parse.c @@ -475,12 +475,12 @@ cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data case CV_LeafKind_POINTER: { cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafPointer, itype)); CV_LeafPointer *ptr = (CV_LeafPointer *)data.str; - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs); if (ptr_kind == CV_PointerKind_BaseType) { // TODO: add CV_LeafPointerBaseType cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); } else { - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs); if (ptr_mode == CV_PointerMode_PtrMem || ptr_mode == CV_PointerMode_PtrMethod) { // TODO: add type for the CvLeafPointerMember to syms_cv.mc cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); @@ -631,7 +631,7 @@ cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data CV_LeafOneMethod onemethod; cursor += str8_deserial_read_struct(data, cursor, &onemethod); - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(onemethod.attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(onemethod.attribs); if(prop == CV_MethodProp_PureIntro || prop == CV_MethodProp_Intro) { cursor += sizeof(U32); // virtoff @@ -711,7 +711,7 @@ cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethodListMember, itype)); // take into account intro virtual offset - CV_MethodProp mprop = CV_FieldAttribs_ExtractMethodProp(method.attribs); + CV_MethodProp mprop = CV_FieldAttribs_Extract_MethodProp(method.attribs); if (mprop == CV_MethodProp_Intro || mprop == CV_MethodProp_PureIntro) { read_size += sizeof(U32); } @@ -1100,7 +1100,7 @@ cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align) CV_SymCompile *compile = (CV_SymCompile*)first; String8 ver_str = str8_cstring_capped((char*)(compile + 1), (char *)(first + cap)); result->info.arch = compile->machine; - result->info.language = CV_CompileFlags_ExtractLanguage(compile->flags);; + result->info.language = CV_CompileFlags_Extract_Language(compile->flags);; result->info.compiler_name = ver_str; }break; case CV_SymKind_COMPILE2: @@ -1114,7 +1114,7 @@ cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align) compile2->ver_minor, compile2->ver_build); result->info.arch = compile2->machine; - result->info.language = CV_Compile2Flags_ExtractLanguage(compile2->flags);; + result->info.language = CV_Compile2Flags_Extract_Language(compile2->flags);; result->info.compiler_name = compiler_name; }break; case CV_SymKind_COMPILE3: @@ -1128,7 +1128,7 @@ cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align) compile3->ver_minor, compile3->ver_build); result->info.arch = compile3->machine; - result->info.language = CV_Compile3Flags_ExtractLanguage(compile3->flags);; + result->info.language = CV_Compile3Flags_Extract_Language(compile3->flags);; result->info.compiler_name = compiler_name; }break; } @@ -1295,7 +1295,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec U32 i = 0; for (; line_ptr < line_opl; line_ptr += 1, i += 1){ voffs[i] = line_ptr->off + secrel_off + sec_base_off; - line_nums[i] = CV_C13LineFlags_ExtractLineNumber(line_ptr->flags); + line_nums[i] = CV_C13LineFlags_Extract_LineNumber(line_ptr->flags); } voffs[i] = secrel_opl + sec_base_off; } diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 26a35bf6..268e50ab 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1792,7 +1792,7 @@ ASYNC_WORK_DEF(p2r_udt_convert_work) method_read_ptr = next_method_read_ptr) { CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); next_method_read_ptr = (U8 *)(method+1); @@ -1867,7 +1867,7 @@ ASYNC_WORK_DEF(p2r_udt_convert_work) // rjf: unpack leaf CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(lf->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); U8 *vbaseoff_ptr = (U8 *)(lf+1); U8 *vbaseoff_opl_ptr = vbaseoff_ptr; U32 vbaseoff = 0; @@ -3694,9 +3694,9 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // rjf: unpack leaf CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(lf->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(lf->attribs); - U32 ptr_size = CV_PointerAttribs_ExtractSize(lf->attribs); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); // rjf: cv -> rdi modifier flags RDI_TypeModifierFlags modifier_flags = 0; From 30dc0340a4df4bedfb313f00fd2a7a7021d3ad8f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 8 Jan 2025 03:24:09 -0800 Subject: [PATCH 14/53] print sizes in telemetry mark up in GSI build step --- src/linker/pdb_ext/pdb_builder.c | 71 ++++++++++++++++---------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 0c28c267..19a87ca2 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -2131,55 +2131,57 @@ gsi_release(PDB_GsiContext **gsi_ptr) } internal void -gsi_write_build_result(TP_Context *tp, PDB_GsiBuildResult build, MSF_Context *msf, MSF_StreamNumber gsi_sn, MSF_StreamNumber symbols_sn) +gsi_write_build_result(TP_Context *tp, + PDB_GsiBuildResult build, + MSF_Context *msf, + MSF_StreamNumber gsi_sn, + MSF_StreamNumber symbols_sn) { ProfBeginFunction(); - - // reserve stream memory - U64 hash_record_arr_size = sizeof(build.hash_record_arr[0]) * build.hash_record_count; - U64 bitmap_size = sizeof(build.bitmap[0]) * build.bitmap_count; + + U64 hash_record_arr_size = sizeof(build.hash_record_arr[0]) * build.hash_record_count; + U64 bitmap_size = sizeof(build.bitmap[0]) * build.bitmap_count; U64 compressed_bucket_arr_size = sizeof(build.compressed_bucket_arr[0]) * build.compressed_bucket_count; U64 gsi_size = sizeof(build.header) + hash_record_arr_size + bitmap_size + compressed_bucket_arr_size; - - ProfBegin("GSI Reserve"); + + ProfBeginV("Reserve %M for GSI hash table", gsi_size); msf_stream_reserve(msf, gsi_sn, gsi_size); ProfEnd(); - ProfBegin("Symbol Data Reserve"); + ProfBeginV("Reserve %M for symbols", build.symbol_data.size); msf_stream_reserve(msf, symbols_sn, build.symbol_data.size); ProfEnd(); - // write gsi stream + ProfBegin("Write GSI header"); msf_stream_write_struct(msf, gsi_sn, &build.header); + ProfEnd(); - ProfBegin("Hash Record Write"); + ProfBegin("Write hash records [%M]", hash_record_arr_size); msf_stream_write_parallel(tp, msf, gsi_sn, &build.hash_record_arr[0], hash_record_arr_size); ProfEnd(); - ProfBegin("Bitmap Write"); + ProfBeginV("Write bucket bitmap [%M]", bitmap_size); msf_stream_write(msf, gsi_sn, &build.bitmap[0], bitmap_size); ProfEnd(); - ProfBegin("Compressed Bucket Write"); + ProfBegin("Write buckets [%M]", compressed_bucket_arr-size); msf_stream_write(msf, gsi_sn, &build.compressed_bucket_arr[0], compressed_bucket_arr_size); ProfEnd(); - // write symbol stream - ProfBegin("Symbol Data Write"); + ProfBegin("Write symbols [%M]", build.symbol_data.size); msf_stream_write_string_parallel(tp, msf, symbols_sn, build.symbol_data); ProfEnd(); ProfEnd(); } -int -gsi_hash_record_compar_is_before(void *a_, void *b_) +internal int +gsi_hash_record_compar_is_before(void *raw_a, void *raw_b) { - PDB_GsiSortRecord *a = (PDB_GsiSortRecord*)a_; - PDB_GsiSortRecord *b = (PDB_GsiSortRecord*)b_; + PDB_GsiSortRecord *a = raw_a; + PDB_GsiSortRecord *b = raw_b; int is_before; - if (a->name.size != b->name.size) { is_before = a->name.size < b->name.size; } else { @@ -2193,20 +2195,19 @@ gsi_hash_record_compar_is_before(void *a_, void *b_) return is_before; } -int -psi_addr_map_compar_is_before(void *a_, void *b_) +internal int +psi_addr_map_compar_is_before(void *raw_a, void *raw_b) { - PDB_GsiSortRecord *a = (PDB_GsiSortRecord*)a_; - PDB_GsiSortRecord *b = (PDB_GsiSortRecord*)b_; + PDB_GsiSortRecord *a = raw_a; + PDB_GsiSortRecord *b = raw_b; int is_before; - if (a->isect_off.isect != b->isect_off.isect) { is_before = a->isect_off.isect < b->isect_off.isect; } else if (a->isect_off.off != b->isect_off.off) { is_before = a->isect_off.off < b->isect_off.off; } else { - is_before = a->name.size < b->name.size; + is_before = str8_compar_case_sensitive(&a->name, &b->name); } return is_before; @@ -2231,9 +2232,9 @@ gsi_record_sort_by_sc(PDB_GsiSortRecord *arr, U64 count) internal THREAD_POOL_TASK_FUNC(gsi_size_buckets_task) { - U64 bucket_idx = task_id; - PDB_GsiSerializeSymbolsTask *task = raw_task; - CV_SymbolList *bucket_list = &task->bucket_arr[bucket_idx]; + U64 bucket_idx = task_id; + PDB_GsiSerializeSymbolsTask *task = raw_task; + CV_SymbolList *bucket_list = &task->bucket_arr[bucket_idx]; for (CV_SymbolNode *node = bucket_list->first; node != 0; node = node->next) { task->bucket_size_arr[bucket_idx] += cv_compute_symbol_record_size(&node->data, task->symbol_align); } @@ -2258,16 +2259,16 @@ THREAD_POOL_TASK_FUNC(gsi_serialize_pub32) CV_Symbol *symbol = &node->data; Assert(symbol->kind == CV_SymKind_PUB32); - CV_SymPub32 *pub32 = (CV_SymPub32 *)symbol->data.str; - U8 *str_ptr = (U8 *)(pub32 + 1); - U64 str_size = symbol->data.size - sizeof(*pub32); - String8 name = str8(str_ptr, str_size); + CV_SymPub32 *pub32 = (CV_SymPub32 *)symbol->data.str; + U8 *str_ptr = (U8 *)(pub32 + 1); + U64 str_size = symbol->data.size - sizeof(*pub32); + String8 name = str8(str_ptr, str_size); // init sort record PDB_GsiSortRecord *sr = &sort_record_arr[sort_idx]; - sr->isect_off = isect_off(pub32->sec, pub32->off); - sr->name = name; - sr->offset = buffer_cursor; + sr->isect_off = isect_off(pub32->sec, pub32->off); + sr->name = name; + sr->offset = buffer_cursor; // serialize symbol U64 serial_size = cv_serialize_symbol_to_buffer(buffer, buffer_cursor, buffer_size, symbol, task->symbol_align); From 5b7c366234967d61f705e5d6dbb2327b25b2e110 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 8 Jan 2025 14:54:11 -0800 Subject: [PATCH 15/53] cfg data structure first pass, serialization/deserialization, & building, to prep for all rd_entity code deletion --- src/raddbg/raddbg_core.c | 526 +++++++++++++++++++++++++++++++++++++++ src/raddbg/raddbg_core.h | 71 +++++- src/raddbg/raddbg_main.c | 57 +++++ 3 files changed, 653 insertions(+), 1 deletion(-) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 5eb5ee6e..31fdd38e 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1031,6 +1031,327 @@ rd_name_release(String8 string) SLLStackPush(rd_state->free_name_chunks[bucket_idx], node); } +//////////////////////////////// +//~ rjf: New Config/Entity Data Structure Functions + +internal RD_Cfg * +rd_cfg_alloc(void) +{ + RD_Cfg *result = rd_state->free_cfg; + if(result) + { + SLLStackPop(rd_state->free_cfg); + } + else + { + result = push_array_no_zero(rd_state->arena, RD_Cfg, 1); + } + U64 old_gen = result->gen; + MemoryZeroStruct(result); + result->first = result->last = result->next = result->prev = result->parent = &rd_nil_cfg; + result->gen = old_gen + 1; + return result; +} + +internal void +rd_cfg_release(RD_Cfg *cfg) +{ + Temp scratch = scratch_begin(0, 0); + rd_cfg_unhook(cfg->parent, cfg); + RD_CfgList nodes = {0}; + for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rd_cfg_rec__depth_first(cfg, c).next) + { + rd_cfg_list_push(scratch.arena, &nodes, c); + } + for(RD_CfgNode *n = nodes.first; n != 0; n = n->next) + { + RD_Cfg *c = n->v; + c->gen += 1; + rd_name_release(c->string); + SLLStackPush(rd_state->free_cfg, c); + } + scratch_end(scratch); +} + +internal RD_Cfg * +rd_cfg_new(RD_Cfg *parent, String8 string) +{ + RD_Cfg *cfg = rd_cfg_alloc(); + rd_cfg_insert_child(parent, parent->last, cfg); + rd_cfg_equip_string(cfg, string); + return cfg; +} + +internal RD_Cfg * +rd_cfg_newf(RD_Cfg *parent, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + RD_Cfg *result = rd_cfg_new(parent, string); + va_end(args); + scratch_end(scratch); + return result; +} + +internal void +rd_cfg_equip_string(RD_Cfg *cfg, String8 string) +{ + if(cfg->string.size != 0) + { + rd_name_release(cfg->string); + } + cfg->string = rd_name_alloc(string); +} + +internal void +rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child) +{ + DLLInsert_NPZ(&rd_nil_cfg, parent->first, parent->last, prev_child, new_child, next, prev); + new_child->parent = parent; +} + +internal void +rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child) +{ + if(parent == child->parent && parent != &rd_nil_cfg) + { + DLLRemove_NPZ(&rd_nil_cfg, parent->first, parent->last, child, next, prev); + child->parent = &rd_nil_cfg; + } +} + +internal RD_Cfg * +rd_cfg_child_from_string(RD_Cfg *parent, String8 string) +{ + RD_Cfg *child = &rd_nil_cfg; + for(RD_Cfg *c = parent->first; c != &rd_nil_cfg; c = c->next) + { + if(str8_match(c->string, string, 0)) + { + child = c; + break; + } + } + return child; +} + +internal RD_CfgList +rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string) +{ + RD_CfgList result = {0}; + for(RD_Cfg *child = parent->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, string, 0)) + { + rd_cfg_list_push(arena, &result, child); + } + } + return result; +} + +internal RD_CfgList +rd_cfg_top_level_list_from_string(Arena *arena, String8 string) +{ + RD_CfgList result = {0}; + for(RD_Cfg *bucket = rd_state->root_cfg->first; bucket != &rd_nil_cfg; bucket = bucket->next) + { + for(RD_Cfg *tln = bucket->first; tln != &rd_nil_cfg; tln = tln->next) + { + if(str8_match(tln->string, string, 0)) + { + rd_cfg_list_push(arena, &result, tln); + } + } + } + return result; +} + +internal RD_CfgList +rd_cfg_tree_list_from_string(Arena *arena, String8 string) +{ + RD_CfgList result = {0}; + Temp scratch = scratch_begin(&arena, 1); + MD_Node *root = md_tree_from_string(scratch.arena, string); + for MD_EachNode(tln, root->first) + { + RD_Cfg *dst_root_n = &rd_nil_cfg; + RD_Cfg *dst_active_parent_n = &rd_nil_cfg; + MD_NodeRec rec = {0}; + for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next) + { + RD_Cfg *dst_n = rd_cfg_alloc(); + rd_cfg_equip_string(dst_n, src_n->string); + if(dst_active_parent_n != &rd_nil_cfg) + { + rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n); + } + rec = md_node_rec_depth_first_pre(src_n, tln); + if(rec.push_count > 0) + { + if(dst_active_parent_n == &rd_nil_cfg) + { + dst_root_n = dst_n; + } + dst_active_parent_n = dst_n; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_active_parent_n = dst_active_parent_n->parent; + } + } + rd_cfg_list_push(arena, &result, dst_root_n); + } + scratch_end(scratch); + return result; +} + +internal String8 +rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strings = {0}; + { + typedef struct NestTask NestTask; + struct NestTask + { + NestTask *next; + RD_Cfg *cfg; + B32 is_simple; + }; + NestTask *top_nest_task = 0; + RD_CfgRec rec = {0}; + for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rec.next) + { + // rjf: push name of this node + if(c->string.size != 0 || c->first == &rd_nil_cfg) + { + String8List c_name_strings = {0}; + B32 name_can_be_pushed_standalone = 0; + { + Temp temp = temp_begin(scratch.arena); + MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c->string); + name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| + MD_TokenFlag_Numeric| + MD_TokenFlag_StringLiteral| + MD_TokenFlag_Symbol)); + temp_end(temp); + } + if(name_can_be_pushed_standalone) + { + str8_list_push(scratch.arena, &c_name_strings, c->string); + } + else + { + String8 c_name_escaped = escaped_from_raw_str8(scratch.arena, c->string); + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + str8_list_push(scratch.arena, &c_name_strings, c_name_escaped); + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + } + if(top_nest_task != 0 && top_nest_task->is_simple) + { + str8_list_push(scratch.arena, &strings, str8_lit(" ")); + } + str8_list_concat_in_place(&strings, &c_name_strings); + } + + // rjf: grab next recursion + rec = rd_cfg_rec__depth_first(cfg, c); + + // rjf: determine if this node is simple, and can be encoded on a single line - + // if so, push a new nesting task onto the stack + if(c->first != &rd_nil_cfg) + { + B32 is_simple_children_list = 1; + for(RD_Cfg *child = c->first; child != &rd_nil_cfg; child = child->next) + { + if(child->first != &rd_nil_cfg && child != c->last) + { + is_simple_children_list = 0; + break; + } + } + NestTask *task = push_array(scratch.arena, NestTask, 1); + task->cfg = c; + task->is_simple = is_simple_children_list; + SLLStackPush(top_nest_task, task); + } + + // rjf: tree navigations -> encode hierarchy + if(rec.push_count > 0) + { + if(top_nest_task->is_simple && c->string.size != 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(":")); + } + else + { + if(c->string.size != 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(":\n")); + } + str8_list_push(scratch.arena, &strings, str8_lit("{")); + } + } + else + { + for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task)) + { + if(top_nest_task->is_simple) + { + if(top_nest_task->cfg->string.size == 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(" }")); + } + } + else + { + str8_list_push(scratch.arena, &strings, str8_lit("\n}")); + } + } + } + if(!top_nest_task || top_nest_task->is_simple == 0) + { + str8_list_push(scratch.arena, &strings, str8_lit("\n")); + } + } + } + String8 result_unindented = str8_list_join(scratch.arena, &strings, 0); + String8 result = indented_from_string(arena, result_unindented); + scratch_end(scratch); + return result; +} + +internal RD_CfgRec +rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg) +{ + RD_CfgRec rec = {&rd_nil_cfg}; + if(cfg->first != &rd_nil_cfg) + { + rec.next = cfg->first; + rec.push_count = 1; + } + else for(RD_Cfg *p = cfg; p != root; p = p->parent, rec.pop_count += 1) + { + if(p->next != &rd_nil_cfg) + { + rec.next = p->next; + break; + } + } + return rec; +} + +internal void +rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg) +{ + RD_CfgNode *n = push_array(arena, RD_CfgNode, 1); + n->v = cfg; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + //////////////////////////////// //~ rjf: Entity State Functions @@ -11169,6 +11490,15 @@ rd_init(CmdLine *cmdln) rd_state->top_regs = &rd_state->base_regs; rd_clear_bindings(); + // rjf: set up top-level config entity trees + { + rd_state->root_cfg = rd_cfg_alloc(); + RD_Cfg *user_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *project_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *command_line_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("command_line")); + RD_Cfg *transient = rd_cfg_new(rd_state->root_cfg, str8_lit("transient")); + } + // rjf: set up user / project paths { Temp scratch = scratch_begin(0, 0); @@ -11332,6 +11662,12 @@ rd_frame(void) local_persist S32 depth = 0; log_scope_begin(); + //- TODO(rjf): @cfg debugging: stringify the current cfg tree + { + String8 string = rd_string_from_cfg_tree(scratch.arena, rd_state->root_cfg); + int x = 0; + } + ////////////////////////////// //- rjf: do per-frame resets // @@ -12147,6 +12483,32 @@ rd_frame(void) case RD_CmdKind_OpenUser: case RD_CmdKind_OpenProject: { + //- TODO(rjf): @cfg load & apply user/project data to the cfg data structure + { + String8 file_root_key = (kind == RD_CmdKind_OpenUser ? str8_lit("user") : str8_lit("project")); + RD_Cfg *file_root = rd_cfg_child_from_string(rd_state->root_cfg, file_root_key); + + //- rjf: eliminate all old state under this file tree + for(RD_Cfg *tln = file_root->first, *next = &rd_nil_cfg; + tln != &rd_nil_cfg; + tln = next) + { + next = tln->next; + rd_cfg_release(tln); + } + + //- rjf: load & parse the new file, generate cfg entities for it + String8 file_path = rd_regs()->file_path; + String8 file_data = os_data_from_file_path(scratch.arena, file_path); + RD_CfgList file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, file_data); + + //- rjf: insert the new cfg entities into this file tree + for(RD_CfgNode *n = file_cfg_list.first; n != 0; n = n->next) + { + rd_cfg_insert_child(file_root, file_root->last, n->v); + } + } + // TODO(rjf): dear lord this is so overcomplicated, this needs to be collapsed down & simplified ASAP B32 load_cfg[RD_CfgSrc_COUNT] = {0}; @@ -12320,6 +12682,32 @@ rd_frame(void) //- rjf: keep track of recent projects if(src == RD_CfgSrc_Project) { + //- TODO(rjf): @cfg keep track of recent projects + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_CfgList recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + RD_Cfg *recent_project = &rd_nil_cfg; + for(RD_CfgNode *n = recent_projects.first; n != 0; n = n->next) + { + if(path_match_normalized(n->v->string, cfg_path)) + { + recent_project = n->v; + break; + } + } + if(recent_project == &rd_nil_cfg) + { + recent_project = rd_cfg_new(user, str8_lit("recent_project")); + rd_cfg_new(recent_project, path_normalized_from_string(scratch.arena, cfg_path)); + } + rd_cfg_unhook(user, recent_project); + rd_cfg_insert_child(user, &rd_nil_cfg, recent_project); + recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + if(recent_projects.count > 32) + { + rd_cfg_release(recent_projects.last->v); + } + } RD_EntityList recent_projects = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentProject); RD_Entity *recent_project = &rd_nil_entity; for(RD_EntityNode *n = recent_projects.first; n != 0; n = n->next) @@ -13548,6 +13936,15 @@ rd_frame(void) String8 map_dst = str8_list_join(scratch.arena, &map_dst_parts, &map_join); //- rjf: store as file path map entity + //- TODO(rjf): @cfg store as file path map entity + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *map = rd_cfg_new(user, str8_lit("file_path_map")); + RD_Cfg *src = rd_cfg_new(map, str8_lit("source")); + RD_Cfg *dst = rd_cfg_new(map, str8_lit("dest")); + rd_cfg_new(src, map_src); + rd_cfg_new(dst, map_dst); + } RD_Entity *map = rd_entity_alloc(rd_entity_root(), RD_EntityKind_FilePathMap); RD_Entity *src = rd_entity_alloc(map, RD_EntityKind_Source); RD_Entity *dst = rd_entity_alloc(map, RD_EntityKind_Dest); @@ -13880,6 +14277,34 @@ rd_frame(void) if(rd_regs()->file_path.size != 0) { String8 path = path_normalized_from_string(scratch.arena, rd_regs()->file_path); + + //- TODO(rjf): @cfg record file in project + { + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_CfgList recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files")); + RD_Cfg *recent_file = &rd_nil_cfg; + for(RD_CfgNode *n = recent_files.first; n != 0; n = n->next) + { + if(path_match_normalized(n->v->string, path)) + { + recent_file = n->v; + break; + } + } + if(recent_file == &rd_nil_cfg) + { + recent_file = rd_cfg_new(project, str8_lit("recent_file")); + rd_cfg_new(recent_file, path); + } + rd_cfg_unhook(project, recent_file); + rd_cfg_insert_child(project, &rd_nil_cfg, recent_file); + recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files")); + if(recent_files.count > 256) + { + rd_cfg_release(recent_files.last->v); + } + } + RD_EntityList recent_files = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentFile); if(recent_files.count >= 256) { @@ -15075,6 +15500,49 @@ rd_frame(void) U64 vaddr = rd_regs()->vaddr; if(file_path.size != 0 || string.size != 0 || vaddr != 0) { + //- TODO(rjf): @cfg add/toggle breakpoint + { + B32 removed_already_existing = 0; + if(kind == RD_CmdKind_ToggleBreakpoint) + { + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + { + RD_Cfg *bp = n->v; + RD_Cfg *loc = rd_cfg_child_from_string(bp, str8_lit("location")); + S64 loc_line = 0; + U64 loc_vaddr = 0; + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); + B32 loc_matches_string = (string.size != 0 && str8_match(loc->first->string, string, 0)); + B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); + if(loc_matches_file_pt || loc_matches_string || loc_matches_vaddr) + { + rd_cfg_release(bp); + removed_already_existing = 1; + break; + } + } + } + if(!removed_already_existing) + { + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint")); + RD_Cfg *loc = rd_cfg_new(bp, str8_lit("location")); + if(vaddr != 0) + { + rd_cfg_newf(loc, "0x%I64x", vaddr); + } + else if(string.size != 0) + { + rd_cfg_new(loc, string); + } + else if(file_path.size != 0) + { + RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); + rd_cfg_newf(file_path_cfg, "%I64d", pt.line); + } + } + } B32 removed_already_existing = 0; if(kind == RD_CmdKind_ToggleBreakpoint) { @@ -15131,6 +15599,48 @@ rd_frame(void) TxtPt pt = rd_regs()->cursor; String8 string = rd_regs()->string; U64 vaddr = rd_regs()->vaddr; + //- TODO(rjf): @cfg add/toggle watch pin + { + B32 removed_already_existing = 0; + if(kind == RD_CmdKind_ToggleWatchPin) + { + RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(RD_CfgNode *n = wps.first; n != 0; n = n->next) + { + RD_Cfg *wp = n->v; + RD_Cfg *name = rd_cfg_child_from_string(wp, str8_lit("name")); + RD_Cfg *loc = rd_cfg_child_from_string(wp, str8_lit("location")); + S64 loc_line = 0; + U64 loc_vaddr = 0; + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); + B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); + B32 loc_matches_expr = (string.size != 0 && str8_match(name->first->string, string, 0)); + if(loc_matches_expr && (loc_matches_file_pt || loc_matches_vaddr)) + { + rd_cfg_release(wp); + removed_already_existing = 1; + break; + } + } + } + if(!removed_already_existing) + { + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin")); + RD_Cfg *name = rd_cfg_new(wp, str8_lit("name")); + RD_Cfg *loc = rd_cfg_new(wp, str8_lit("location")); + rd_cfg_new(name, string); + if(vaddr != 0) + { + rd_cfg_newf(loc, "0x%I64x", vaddr); + } + else if(file_path.size != 0) + { + RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); + rd_cfg_newf(file_path_cfg, "%I64d", pt.line); + } + } + } B32 removed_already_existing = 0; if(kind == RD_CmdKind_ToggleWatchPin) { @@ -15251,6 +15761,22 @@ rd_frame(void) //- rjf: targets case RD_CmdKind_AddTarget: { + //- TODO(rjf): @cfg add new target + { + String8 file_path = rd_regs()->file_path; + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *target = rd_cfg_new(project, str8_lit("target")); + RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); + rd_cfg_new(exe, file_path); + String8 working_directory = str8_chop_last_slash(file_path); + if(working_directory.size != 0) + { + RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); + rd_cfg_newf(wdir, "%S/", working_directory); + } + // TODO(rjf): (select target here) + } + // rjf: build target RD_Entity *entity = &rd_nil_entity; entity = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index d625c3c7..196a6328 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -376,6 +376,44 @@ struct RD_CfgTable RD_CfgVal *last_val; }; +//////////////////////////////// +//~ rjf: New Config/Entity Data Structure + +typedef struct RD_Cfg RD_Cfg; +struct RD_Cfg +{ + RD_Cfg *first; + RD_Cfg *last; + RD_Cfg *next; + RD_Cfg *prev; + RD_Cfg *parent; + U64 gen; + String8 string; +}; + +typedef struct RD_CfgNode RD_CfgNode; +struct RD_CfgNode +{ + RD_CfgNode *next; + RD_Cfg *v; +}; + +typedef struct RD_CfgList RD_CfgList; +struct RD_CfgList +{ + RD_CfgNode *first; + RD_CfgNode *last; + U64 count; +}; + +typedef struct RD_CfgRec RD_CfgRec; +struct RD_CfgRec +{ + RD_Cfg *next; + S32 push_count; + S32 pop_count; +}; + //////////////////////////////// //~ rjf: Entity Types @@ -836,12 +874,16 @@ struct RD_State RD_RegSlot drag_drop_regs_slot; RD_DragDropState drag_drop_state; + // rjf: cfg state + RD_NameChunkNode *free_name_chunks[8]; + RD_Cfg *free_cfg; + RD_Cfg *root_cfg; + //- // TODO(rjf): TO BE ELIMINATED OR REPLACED VVVVVVVVVVVVVVVV //- // rjf: entity state - RD_NameChunkNode *free_name_chunks[8]; Arena *entities_arena; RD_Entity *entities_base; U64 entities_count; @@ -914,6 +956,15 @@ struct RD_State read_only global RD_CfgTree d_nil_cfg_tree = {&d_nil_cfg_tree, RD_CfgSrc_User, &md_nil_node}; read_only global RD_CfgVal d_nil_cfg_val = {&d_nil_cfg_val, &d_nil_cfg_val, &d_nil_cfg_tree, &d_nil_cfg_tree}; +read_only global RD_Cfg rd_nil_cfg = +{ + &rd_nil_cfg, + &rd_nil_cfg, + &rd_nil_cfg, + &rd_nil_cfg, + &rd_nil_cfg, +}; + read_only global RD_Entity rd_nil_entity = { &rd_nil_entity, @@ -1097,6 +1148,24 @@ internal U64 rd_name_bucket_idx_from_string_size(U64 size); internal String8 rd_name_alloc(String8 string); internal void rd_name_release(String8 string); +//////////////////////////////// +//~ rjf: New Config/Entity Data Structure Functions + +internal RD_Cfg *rd_cfg_alloc(void); +internal void rd_cfg_release(RD_Cfg *cfg); +internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string); +internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...); +internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string); +internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child); +internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child); +internal RD_Cfg *rd_cfg_child_from_string(RD_Cfg *parent, String8 string); +internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string); +internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string); +internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 string); +internal String8 rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg); +internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg); +internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); + //////////////////////////////// //~ rjf: Entity Stateful Functions diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 985af73f..f0f97e8a 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -599,6 +599,63 @@ entry_point(CmdLine *cmd_line) String8List args = cmd_line->inputs; if(args.node_count > 0 && args.first->string.size != 0) { + //- TODO(rjf): @cfg setup initial target from command line arguments + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack command line inputs + String8 executable_name_string = {0}; + String8 arguments_string = {0}; + String8 working_directory_string = {0}; + { + // rjf: unpack full executable path + if(args.first->string.size != 0) + { + String8 current_path = os_get_current_path(scratch.arena); + String8 exe_name = args.first->string; + PathStyle style = path_style_from_str8(exe_name); + if(style == PathStyle_Relative) + { + exe_name = push_str8f(scratch.arena, "%S/%S", current_path, exe_name); + exe_name = path_normalized_from_string(scratch.arena, exe_name); + } + executable_name_string = exe_name; + } + + // rjf: unpack working directory + if(args.first->string.size != 0) + { + String8 path_part_of_arg = str8_chop_last_slash(args.first->string); + if(path_part_of_arg.size != 0) + { + String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); + working_directory_string = path; + } + } + + // rjf: unpack arguments + String8List passthrough_args_list = {0}; + for(String8Node *n = args.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &passthrough_args_list, n->string); + } + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + arguments_string = str8_list_join(scratch.arena, &passthrough_args_list, &join); + } + + //- rjf: build config tree + RD_Cfg *command_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); + RD_Cfg *target = rd_cfg_new(command_line_root, str8_lit("target")); + RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); + RD_Cfg *args = rd_cfg_new(target, str8_lit("arguments")); + RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); + rd_cfg_new(exe, executable_name_string); + rd_cfg_new(args, arguments_string); + rd_cfg_new(wdir, working_directory_string); + + scratch_end(scratch); + } + Temp scratch = scratch_begin(0, 0); RD_Entity *target = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target); rd_entity_equip_cfg_src(target, RD_CfgSrc_CommandLine); From a1e7ec5a0e9c8674f5b0271ce528f6b651d43564 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Jan 2025 10:06:47 -0800 Subject: [PATCH 16/53] rdi_from_pdb: fix line emitting rules in inline site symbol parsing; also fix non-application of code lengths to code offsets in inline lines --- src/rdi_from_pdb/rdi_from_pdb.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 268e50ab..d1e19ae1 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -794,11 +794,9 @@ ASYNC_WORK_DEF(p2r_units_convert_work) CV_InlineRangeKind range_kind = 0; U32 code_length = 0; U32 code_offset = 0; - U32 last_code_offset = code_offset; String8 file_name = inlinee_lines_parsed->file_name; - String8 last_file_name = file_name; + String8 last_file_name = {0}; S32 line = (S32)inlinee_lines_parsed->first_source_ln; - S32 last_line = line; S32 column = 1; S32 last_column = column; @@ -821,6 +819,9 @@ ASYNC_WORK_DEF(p2r_units_convert_work) CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; // rjf: decode loop + B32 line_num_emitted = 0; + B32 code_off_emitted = 0; + B32 code_len_emitted = 0; U64 read_off = 0; U64 read_off_opl = binary_annots.size; for(B32 good = 1; read_off < read_off_opl && good;) @@ -840,6 +841,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) case CV_InlineBinaryAnnotation_CodeOffset: { read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset); + code_off_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: { @@ -857,11 +859,13 @@ ASYNC_WORK_DEF(p2r_units_convert_work) U32 delta = 0; read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta); code_offset += delta; + code_off_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeCodeLength: { code_length = 0; read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); + code_len_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeFile: { @@ -881,6 +885,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) S32 delta = 0; read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &delta); line += delta; + line_num_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeLineEndDelta: { @@ -923,6 +928,8 @@ ASYNC_WORK_DEF(p2r_units_convert_work) S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); code_offset += code_delta; line += line_delta; + code_off_emitted = 1; + line_num_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: { @@ -930,6 +937,8 @@ ASYNC_WORK_DEF(p2r_units_convert_work) read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &offset_delta); code_offset += offset_delta; + code_len_emitted = 1; + code_off_emitted = 1; }break; case CV_InlineBinaryAnnotation_ChangeColumnEnd: { @@ -941,7 +950,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } // rjf: gather new lines - if(!good || line != last_line || code_offset != last_code_offset) + if(!good || (line_num_emitted && code_off_emitted && code_len_emitted)) { LineChunk *chunk = last_line_chunk; if(chunk == 0 || chunk->count+1 >= chunk->cap) @@ -957,6 +966,15 @@ ASYNC_WORK_DEF(p2r_units_convert_work) chunk->line_nums[chunk->count] = (U32)line; chunk->count += 1; total_line_chunk_line_count += 1; + line_num_emitted = 0; + code_off_emitted = 0; + code_len_emitted = 0; + } + + // rjf: advance code offset by the code length + { + code_offset += code_length; + code_length = 0; } // rjf: push line sequence to line table & source file @@ -1029,12 +1047,6 @@ ASYNC_WORK_DEF(p2r_units_convert_work) first_line_chunk = last_line_chunk = 0; total_line_chunk_line_count = 0; } - - // rjf: update prev/current states - last_file_name = file_name; - last_line = line; - last_column = column; - last_code_offset = code_offset; } } }break; From 076aa0a8cb95aa44f8db0cf9bb9d8634fbcfbf6e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 13 Jan 2025 10:09:09 -0800 Subject: [PATCH 17/53] build fixes for parse_inline_sites --- src/codeview/codeview.c | 11 +++++++++++ src/codeview/codeview.h | 2 ++ src/scratch/parse_inline_sites.c | 17 ++++++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index 84ec882e..9ff233a3 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -165,3 +165,14 @@ cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg) return r; } + +internal String8 +cv_string_from_inline_range_kind(CV_InlineRangeKind kind) +{ + switch (kind) { + case CV_InlineRangeKind_Expr: return str8_lit("Expr"); + case CV_InlineRangeKind_Stmt: return str8_lit("Stmt"); + } + return str8_zero(); +} + diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index 2ac3aece..524b59c6 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -2971,5 +2971,7 @@ internal CV_EncodedFramePtrReg cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B internal CV_Reg cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg); internal U32 cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg); +internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind); + #endif // CODEVIEW_H diff --git a/src/scratch/parse_inline_sites.c b/src/scratch/parse_inline_sites.c index 87e54a68..45fc8138 100644 --- a/src/scratch/parse_inline_sites.c +++ b/src/scratch/parse_inline_sites.c @@ -4,17 +4,18 @@ #include "os/os_inc.h" #include "coff/coff.h" #include "codeview/codeview.h" -#include "codeview/codeview_stringize.h" +#include "codeview/codeview_parse.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" #include "pdb/pdb_parse.h" +#include "pdb/pdb_stringize.h" #include "base/base_inc.c" #include "os/os_inc.c" #include "coff/coff.c" #include "codeview/codeview.c" -#include "codeview/codeview_stringize.c" +#include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" @@ -25,23 +26,21 @@ #include "linker/base_ext/base_blake3.h" #include "linker/base_ext/base_blake3.c" -#include "linker/third_party_ext/md5/md5.c" -#include "linker/third_party_ext/md5/md5.h" -#include "linker/third_party_ext/xxHash/xxhash.c" -#include "linker/third_party_ext/xxHash/xxhash.h" +#include "third_party/md5/md5.c" +#include "third_party/md5/md5.h" +#include "third_party/xxHash/xxhash.c" +#include "third_party/xxHash/xxhash.h" #include "linker/base_ext/base_inc.h" #include "linker/path_ext/path.h" #include "linker/hash_table.h" #include "linker/thread_pool/thread_pool.h" -#include "linker/os_ext/os_inc.h" #include "linker/codeview_ext/codeview.h" #include "linker/base_ext/base_inc.c" #include "linker/path_ext/path.c" #include "linker/hash_table.c" #include "linker/thread_pool/thread_pool.c" -#include "linker/os_ext/os_inc.c" #include "linker/codeview_ext/codeview.c" internal void @@ -116,7 +115,7 @@ print_inline_binary_annotations(String8 binary_annots) case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: { U32 code_offset_and_line_offset = 0; cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset_and_line_offset); - S32 line_delta = cv_inline_annot_convert_to_signed_operand(code_offset_and_line_offset >> 4); + S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); U32 code_delta = code_offset_and_line_offset & 0xF; line_offset += line_delta; code_offset += code_delta; From 3cec629a8c7ca48f2032c3c5975116a93df6a2b4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 13 Jan 2025 15:22:18 -0800 Subject: [PATCH 18/53] pipe obj directives through config path --- src/linker/lnk.c | 19 +- src/linker/lnk_config.c | 1709 ++++++++++++++++++------------------ src/linker/lnk_config.h | 41 +- src/linker/lnk_directive.c | 94 +- src/linker/lnk_directive.h | 20 +- src/linker/lnk_error.c | 25 + src/linker/lnk_error.h | 2 + src/linker/lnk_obj.c | 24 +- 8 files changed, 993 insertions(+), 941 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index adab3ac3..1f80d3a2 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2895,7 +2895,7 @@ lnk_init_merge_directive_list(Arena *arena, LNK_ObjList obj_list) // collect merge directives from objs for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) { LNK_Obj *obj = &obj_node->data; - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Merge].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Merge].first; dir != 0; dir = dir->next) { for (String8Node *value_node = dir->value_list.first; value_node != 0; value_node = value_node->next) { LNK_MergeDirective merge_dir; if (lnk_parse_merge_directive(value_node->string, &merge_dir)) { lnk_merge_directive_list_push(arena, &result, merge_dir); @@ -3569,11 +3569,26 @@ lnk_run(int argc, char **argv) ProfBegin("Collect Directives"); for (U64 i = 0; i < obj_node_arr.count; ++i) { LNK_Obj *obj = &obj_node_arr.v[i].data; + str8_list_concat_in_place(&include_symbol_list, &obj->include_symbol_list); + lnk_alt_name_list_concat_in_place(&alt_name_list, &obj->alt_name_list); - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_DisallowLib].first; dir != 0; dir = dir->next) { + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_DisallowLib].first; dir != 0; dir = dir->next) { str8_list_concat_in_place(&input_disallow_lib_list, &dir->value_list); } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Entry].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_SubSystem].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Stack].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } } ProfEnd(); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index b7610398..eb754b40 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -38,6 +38,7 @@ read_only struct { LNK_CmdSwitch_Dll, "DLL", "", "" }, { LNK_CmdSwitch_NotImplemented, "DRIVER", "", "" }, { LNK_CmdSwitch_DisallowLib, "DISALLOWLIB", ":LIBRARY", "", }, + { LNK_CmdSwitch_EditAndContinue, "EDITANDCONTINUE", "[:NO]", "" }, { LNK_CmdSwitch_DynamicBase, "DYNAMICBASE", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, "EMITVOLATILEMETADATA", "", "" }, { LNK_CmdSwitch_Entry, "ENTRY", ":FUNCTION", "" }, @@ -46,11 +47,13 @@ read_only struct { LNK_CmdSwitch_NotImplemented, "EXPORTADMIN", "", "" }, { LNK_CmdSwitch_FastFail, "FASTFAIL", "", "Not used." }, { LNK_CmdSwitch_NotImplemented, "FASTGENPROFILE", "", "" }, + { LNK_CmdSwitch_FailIfMismatch, "FAILIFMISMATCH", "", "" }, { LNK_CmdSwitch_FileAlign, "FILEALIGN", ":#", "" }, { LNK_CmdSwitch_Fixed, "FIXED", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, "FORCE", "", "" }, { LNK_CmdSwitch_FunctionPadMin, "FUNCTIONPADMIN", ":#", "Not Implemented" }, { LNK_CmdSwitch_NotImplemented, "GUARD", "", "" }, + { LNK_CmdSwitch_GuardSym, "GUARDSYM", "", "", }, { LNK_CmdSwitch_NotImplemented, "GENPROFILE", "", "" }, { LNK_CmdSwitch_Heap, "HEAP", "RESERVE[,COMMIT]", "" }, { LNK_CmdSwitch_HighEntropyVa, "HIGHENTROPYVA", "[:NO]", "" }, @@ -62,6 +65,8 @@ read_only struct { LNK_CmdSwitch_Include, "INCLUDE", "", "" }, { LNK_CmdSwitch_Incremental, "INCREMENTAL", "[:NO]", "Incremental linking is not supported." }, { LNK_CmdSwitch_NotImplemented, "INTEGRITYCHECK", "", "" }, + { LNK_CmdSwitch_InferAsanLibs, "INFERASANLIBS", "[:NO]", "" }, + { LNK_CmdSwitch_InferAsanLibsNo, "INFERASANLIBSNO", "", "", }, { LNK_CmdSwitch_NotImplemented, "KERNEL", "", "" }, { LNK_CmdSwitch_NotImplemented, "KEYCONTAINER", "", "" }, { LNK_CmdSwitch_NotImplemented, "KEYFILE", "", "" }, @@ -79,7 +84,7 @@ read_only struct { LNK_CmdSwitch_ManifestUac, "MANIFESTUAC", ":{NO|{'level'={'asInvoker'|'highestAvailable'|'requireAdministrator'} ['uiAccess'={'true'|'false'}]}}", "" }, { LNK_CmdSwitch_NotImplemented, "MAP", "", "" }, { LNK_CmdSwitch_NotImplemented, "MAPINFO", "", "" }, - { LNK_CmdSwitch_NotImplemented, "MERGE", "", "" }, + { LNK_CmdSwitch_Merge, "MERGE", ":from=to", "" }, { LNK_CmdSwitch_NotImplemented, "MIDL", "", "" }, { LNK_CmdSwitch_Natvis, "NATVIS", ":FILENAME", "" }, { LNK_CmdSwitch_NotImplemented, "NOASSEMBLY", "", "" }, @@ -110,6 +115,7 @@ read_only struct { LNK_CmdSwitch_NotImplemented, "TLBOUT", "", "" }, { LNK_CmdSwitch_NotImplemented, "TIME", "", "" }, { LNK_CmdSwitch_TsAware, "TSAWARE", "[:NO]", "" }, + { LNK_CmdSwitch_ThrowingNew, "THROWINGNEW", "", "" }, { LNK_CmdSwitch_NotImplemented, "USERPROFILE", "", "" }, { LNK_CmdSwitch_NotImplemented, "VERBOSE", "", "" }, { LNK_CmdSwitch_Version, "VERSION", "", "" }, @@ -158,6 +164,18 @@ read_only struct { LNK_CmdSwitch_Help, "?", "", "" }, }; +internal LNK_CmdSwitchType +lnk_cmd_switch_type_from_string(String8 name) +{ + for (U64 i = 0; i < ArrayCount(g_cmd_switch_map); ++i) { + String8 curr_name = str8_cstring(g_cmd_switch_map[i].name); + if (str8_match(curr_name, name, StringMatchFlag_CaseInsensitive)) { + return g_cmd_switch_map[i].type; + } + } + return LNK_CmdSwitch_Null; +} + internal String8 lnk_string_from_cmd_switch_type(LNK_CmdSwitchType type) { @@ -169,21 +187,6 @@ lnk_string_from_cmd_switch_type(LNK_CmdSwitchType type) return str8(0,0); } -internal LNK_CmdSwitchType -lnk_cmd_switch_type_from_string(String8 string) -{ - LNK_CmdSwitchType type = LNK_CmdSwitch_Null; - for (U64 icmd = 0; icmd < ArrayCount(g_cmd_switch_map); icmd += 1) { - String8 cmd_name = str8_cstring(g_cmd_switch_map[icmd].name); - if (str8_match(cmd_name, string, StringMatchFlag_CaseInsensitive)) { - type = g_cmd_switch_map[icmd].type; - break; - } - } - - return type; -} - read_only struct { char *name; LNK_InputType type; @@ -290,17 +293,16 @@ lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch) //////////////////////////////// internal void -lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt, ...) +lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...) { Temp scratch = scratch_begin(0,0); - va_list args; - va_start(args, fmt); + va_list args; va_start(args, fmt); String8 switch_name = lnk_string_from_cmd_switch_type(cmd_switch); - String8 message = push_str8fv(scratch.arena, fmt, args); - String8 output = push_str8f(scratch.arena, "/%S: %S", switch_name, message); - lnk_error(code, "%S", output); + String8 message = push_str8fv(scratch.arena, fmt, args); + String8 output = push_str8f(scratch.arena, "/%S: %S", switch_name, message); + lnk_error_with_loc(code, obj_path, lib_path, "%S", output); va_end(args); @@ -308,19 +310,19 @@ lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt } internal void -lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch) +lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch) { - lnk_error_cmd_switch(code, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(code, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } internal void -lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, String8 param) +lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param) { - lnk_error_cmd_switch(code, cmd_switch, "invalid parameter \"%S\"", param); + lnk_error_cmd_switch(code, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", param); } internal String8 -lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 string) +lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 string) { String8 result = string; B32 starts_with_quote = str8_match(str8_lit("\""), string, StringMatchFlag_RightSideSloppy); @@ -329,22 +331,22 @@ lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd result = str8_skip(result, 1); result = str8_chop(result, 1); } else { - lnk_error_cmd_switch(error_code, cmd_switch, "detected unmatched \" in \"%S\"", string); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "detected unmatched \" in \"%S\"", string); } } return result; } internal void -lnk_error_invalid_uac_level_param(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 input) +lnk_error_invalid_uac_level_param(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 input) { - lnk_error_cmd_switch(error_code, cmd_switch, "invalid param format, expected \"level={'asInvoker'|'highestAvailable'|'requireAdministrator'}\" but got \"%S\"", input); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "invalid param format, expected \"level={'asInvoker'|'highestAvailable'|'requireAdministrator'}\" but got \"%S\"", input); } internal void -lnk_error_invalid_uac_ui_access_param(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 input) +lnk_error_invalid_uac_ui_access_param(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 input) { - lnk_error_cmd_switch(error_code, cmd_switch, "invalid param format, expected \"uiAccess={'true'|'false'}\" but got \"%S\"", input); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "invalid param format, expected \"uiAccess={'true'|'false'}\" but got \"%S\"", input); } //////////////////////////////// @@ -363,6 +365,8 @@ lnk_get_default_function_pad_min(COFF_MachineType machine) } break; default: { lnk_error_cmd_switch(LNK_Error_Cmdl, + str8_zero(), + str8_zero(), LNK_CmdSwitch_FunctionPadMin, "default paramter is not defined for: %S", coff_string_from_machine_type(machine)); @@ -524,7 +528,7 @@ lnk_do_debug_info(LNK_Config *config) //////////////////////////////// internal B32 -lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_switch, Version *ver_out) +lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out) { Temp scratch = scratch_begin(0,0); B32 is_parsed = 0; @@ -540,7 +544,7 @@ lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_sw maj_str = split_list.first->string; min_str = split_list.last->string; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid version format, too many dots, expected format: {N[.N]}"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid version format, too many dots, expected format: {N[.N]}"); goto exit; } @@ -550,13 +554,13 @@ lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_sw *ver_out = make_version(maj, min); is_parsed = 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse minor version"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse minor version"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse major version"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse major version"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } exit:; @@ -565,7 +569,7 @@ exit:; } internal B32 -lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_switch, Rng1U64 *tuple_out) +lnk_cmd_switch_parse_tuple(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out) { if (value_strings.node_count == 1) { U64 value; @@ -573,7 +577,7 @@ lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_swit tuple_out->v[0] = value; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse the parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse the parameter \"%S\"", value_strings.first->string); } } else if (value_strings.node_count == 2) { U64 a,b; @@ -583,13 +587,13 @@ lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_swit tuple_out->v[1] = b; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable ot parse second parameter \"%S\"", value_strings.last->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable ot parse second parameter \"%S\"", value_strings.last->string); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } return 0; } @@ -615,24 +619,24 @@ lnk_try_parse_u64(String8 string, LNK_ParseU64Flags flags, U64 *value_out) } internal B32 -lnk_cmd_switch_parse_u64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *value_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags) { if (value_strings.node_count != 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, exepcted integer number as input"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, exepcted integer number as input"); return 0; } if (!lnk_try_parse_u64(value_strings.first->string, flags, value_out)) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse string \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse string \"%S\"", value_strings.first->string); return 0; } return 1; } internal B32 -lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *value_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags) { U64 value; - if (lnk_cmd_switch_parse_u64(value_strings, cmd_switch, &value, flags | LNK_ParseU64Flag_CheckUnder32bit)) { + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &value, flags | LNK_ParseU64Flag_CheckUnder32bit)) { *value_out = (U32)value; return 1; } @@ -640,7 +644,7 @@ lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch } internal B32 -lnk_cmd_switch_parse_u64_list(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, U64List *list_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u64_list(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64List *list_out, LNK_ParseU64Flags flags) { for (String8Node *string_n = value_strings.first; string_n != 0; string_n = string_n->next) { U64 value; @@ -653,11 +657,11 @@ lnk_cmd_switch_parse_u64_list(Arena *arena, String8List value_strings, LNK_CmdSw } internal B32 -lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switch, LNK_SwitchState *value_out) +lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out) { B32 is_parsed = 0; if (value_strings.node_count > 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters"); } else if (value_strings.node_count == 1) { if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { *value_out = LNK_SwitchState_No; @@ -669,7 +673,7 @@ lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switc *value_out = 1; is_parsed = 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); } } else { *value_out = LNK_SwitchState_Yes; @@ -679,10 +683,10 @@ lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switc } internal void -lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits) +lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -692,10 +696,10 @@ lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_ } internal void -lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits) +lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -705,10 +709,10 @@ lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_ } internal void -lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits) +lnk_cmd_switch_set_flag_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -718,10 +722,10 @@ lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal void -lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *flags, U32 bits) +lnk_cmd_switch_set_flag_32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -731,10 +735,10 @@ lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal void -lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits) +lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -744,25 +748,25 @@ lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal B32 -lnk_cmd_switch_parse_string(String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out) +lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out) { if (value_strings.node_count == 1) { if (value_strings.first->string.size > 0) { *string_out = value_strings.first->string; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "empty string is not permitted"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "empty string is not permitted"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } return 0; } internal void -lnk_cmd_switch_parse_string_copy(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out) +lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out) { - if (lnk_cmd_switch_parse_string(value_strings, cmd_switch, string_out)) { + if (lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, string_out)) { *string_out = push_str8_copy(arena, *string_out); } } @@ -883,6 +887,798 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) return result; } +internal void +lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path) +{ + Temp scratch = scratch_begin(&arena,1); + + LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); + + switch (cmd_switch) { + case LNK_CmdSwitch_Null: { + String8 value = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); + lnk_error_with_loc(LNK_Warning_UnknownSwitch, obj_path, lib_path, "unknown switch: \"/%S%s%S\"", cmd_name, value.size ? ":" : "", value); + } break; + + default: { InvalidPath; } break; + + case LNK_CmdSwitch_NotImplemented: { + String8 value = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); + lnk_not_implemented("switch \"%S\" is not implemented \"%S\"", cmd_name, value); + } break; + + case LNK_CmdSwitch_Align: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->sect_align, LNK_ParseU64Flag_CheckPow2); + } break; + + case LNK_CmdSwitch_AllowBind: { + lnk_cmd_switch_set_flag_inv_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NO_BIND); + } break; + + case LNK_CmdSwitch_AllowIsolation: { + lnk_cmd_switch_set_flag_inv_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NO_ISOLATION); + } break; + + case LNK_CmdSwitch_AlternateName: { + String8 *error_string = lnk_parse_alt_name_directive_list(arena, value_strings, &config->alt_name_list); + if (error_string != 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string); + } + } break; + + case LNK_CmdSwitch_AppContainer: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_APPCONTAINER); + } break; + + case LNK_CmdSwitch_Base: { + if (value_strings.node_count == 2) { + String8Node *first_node = value_strings.first; + //String8Node *second_node = first_node->next; + B32 is_response_file = str8_match(str8_lit("@"), first_node->string, StringMatchFlag_RightSideSloppy); + if (is_response_file) { + //String8 file_path = first_node->string; + //String8 tag = second_node->string; + lnk_not_implemented("Response files are not implemented for /BASE"); + } else { + Rng1U64 addr_size = {0}; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &addr_size)) { + config->user_base_addr = addr_size.v[0]; + config->max_image_size = addr_size.v[1]; + } + } + } else if (value_strings.node_count == 1) { + U64 addr; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &addr, 0)) { + config->user_base_addr = addr; + } + } else if (value_strings.node_count == 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "expected at least 1 parameter"); + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters"); + } + } break; + + case LNK_CmdSwitch_Debug: { + if (value_strings.node_count == 0) { + config->debug_mode = LNK_DebugMode_Full; + } else if (value_strings.node_count == 1) { + LNK_DebugMode debug_mode = lnk_debug_mode_from_string(value_strings.first->string); + if (debug_mode == LNK_DebugMode_GHash) { + config->debug_mode = LNK_DebugMode_Full; + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "GHASH is not supported, switching to FULL"); + } else if (debug_mode == LNK_DebugMode_FastLink) { + config->debug_mode = LNK_DebugMode_Full; + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "FASTLINK is not supported, switching to FULL"); + } else if (debug_mode != LNK_DebugMode_Null) { + config->debug_mode = debug_mode; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_DefaultLib: { + String8List default_lib_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->input_default_lib_list, &default_lib_list); + } break; + + case LNK_CmdSwitch_Delay: { + if (value_strings.node_count == 0 || value_strings.node_count > 1) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } else { + String8 value = value_strings.first->string; + if (str8_match(value, str8_lit("unload"), StringMatchFlag_CaseInsensitive)) { + config->flags |= LNK_ConfigFlag_DelayUnload; + } else if (str8_match(value, str8_lit("nobind"), StringMatchFlag_CaseInsensitive)) { + config->flags &= ~LNK_ConfigFlag_DelayBind; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value); + } + } + } break; + + case LNK_CmdSwitch_DelayLoad: { + String8List delay_load_dll_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->delay_load_dll_list, &delay_load_dll_list); + } break; + + case LNK_CmdSwitch_Dll: { + config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL; + } break; + + case LNK_CmdSwitch_DisallowLib: { + lnk_not_implemented("TODO: how is this switch different from /nodefaultlib?"); + } break; + + case LNK_CmdSwitch_DynamicBase: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_DYNAMIC_BASE); + } break; + + case LNK_CmdSwitch_Entry: { + String8 new_entry_point_name = {0}; + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &new_entry_point_name); + + if (config->entry_point_name.size) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "unable to redefine entry point \"%S\" to \"%S\"", config->entry_point_name, new_entry_point_name); + break; + } + + config->entry_point_name = new_entry_point_name; + } break; + + case LNK_CmdSwitch_FastFail: { + // do nothing + } break; + + case LNK_CmdSwitch_FileAlign: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->file_align, LNK_ParseU64Flag_CheckPow2); + } break; + + case LNK_CmdSwitch_Fixed: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_Fixed); + } break; + + case LNK_CmdSwitch_FunctionPadMin: { + if (value_strings.node_count == 0) { + config->function_pad_min = 0; // :function_pad_min + } else { + local_persist U64 function_pad_min; + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); + config->function_pad_min = &function_pad_min; + } + } break; + + case LNK_CmdSwitch_Heap: { + Rng1U64 reserve_commit; + reserve_commit.v[0] = config->heap_reserve; + reserve_commit.v[1] = config->heap_commit; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &reserve_commit)) { + if (reserve_commit.v[0] >= reserve_commit.v[1]) { + U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); + U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); +#if 0 + if (reserve_aligned != reserve_commit.v[0]) { + lnk_error_cmd_switch(LNK_WARNING_CMDL, obj_path, lib_path, cmd_switch, "reserve is not power of two, aligned to %u bytes", reserve_aligned); + } + if (commit_aligned != reserve_commit.v[1]) { + lnk_error_cmd_switch(LNK_WARNING_CMDL, obj_path, lib_path, cmd_switch, "commit is not power of two, aligned to %u bytes", commit_aligned); + } +#endif + config->heap_reserve = reserve_aligned; + config->heap_commit = commit_aligned; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); + } + } + } break; + + case LNK_CmdSwitch_HighEntropyVa: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_HIGH_ENTROPY_VA); + } break; + + case LNK_CmdSwitch_Ignore: { + U64 error_code; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &error_code, 0)) { + switch (error_code) { + case LNK_MsWarningCode_UnsuedDelayLoadDll: { + lnk_suppress_error(LNK_Warning_UnusedDelayLoadDll); + } break; + case LNK_MsWarningCode_MissingExternalTypeServer: { + lnk_suppress_error(LNK_Warning_MissingExternalTypeServer); + } break; + case LNK_MsWarningCode_SectionFlagsConflict: { + lnk_suppress_error(LNK_Warning_SectionFlagsConflict); + } break; + default: { + lnk_not_implemented("TODO: /IGNORE:%llu", error_code); + } break; + } + } + } break; + + case LNK_CmdSwitch_ImpLib: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->imp_lib_name); + } break; + + case LNK_CmdSwitch_Include: { + String8List include_symbol_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->include_symbol_list, &include_symbol_list); + } break; + + case LNK_CmdSwitch_Incremental: { + LNK_SwitchState state; + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { + if (state == LNK_SwitchState_Yes) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "incremental linkage is not supported"); + } + } + } break; + + case LNK_CmdSwitch_LargeAddressAware: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); + } break; + + case LNK_CmdSwitch_LibPath: { + String8List lib_dir_list = str8_list_copy(arena, &value_strings); + for (String8Node *dir_n = lib_dir_list.first; dir_n != 0; dir_n = dir_n->next) { + if (!os_folder_path_exists(dir_n->string)) { + String8 full_path = os_full_path_from_path(scratch.arena, dir_n->string); + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "path doesn't exist %S", full_path); + } + } + str8_list_concat_in_place(&config->lib_dir_list, &lib_dir_list); + } break; + + case LNK_CmdSwitch_Machine: { + if (value_strings.node_count == 1) { + COFF_MachineType machine = coff_machine_from_string(value_strings.first->string); + if (machine != COFF_MachineType_UNKNOWN) { + config->machine = machine; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Manifest: { + if (value_strings.node_count == 1) { + String8List param_list = str8_split_by_string_chars(scratch.arena, value_strings.first->string, str8_lit(","), 0); + String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); + if (param_arr.count > 0) { + if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { + config->manifest_opt = LNK_ManifestOpt_Embed; + + if (param_arr.count == 1) { + config->manifest_resource_id = 0; + } else if (param_arr.count > 1) { + // parse resource id + if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); + String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); + if (res_id_arr.count == 2) { + U64 resource_id; + if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) { + config->manifest_resource_id = push_u64(arena, resource_id); + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]); + } + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } else if (str8_match(param_arr.v[0], str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + config->manifest_opt = LNK_ManifestOpt_No; + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } else if (value_strings.node_count == 0) { + config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } break; + + case LNK_CmdSwitch_ManifestDependency: { + String8List manifest_dependency_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); + + if (config->manifest_opt == LNK_ManifestOpt_Null) { + config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } + } break; + + case LNK_CmdSwitch_ManifestFile: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->manifest_name); + } break; + + case LNK_CmdSwitch_ManifestInput: { + // see :manifest_input + } break; + + case LNK_CmdSwitch_ManifestUac: { + if (value_strings.node_count == 1) { + String8 uac = lnk_error_check_and_strip_quotes(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, value_strings.first->string); + String8List param_list = str8_split_by_string_chars(scratch.arena, uac, str8_lit(" "), 0); + String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); + if (param_arr.count > 0) { + if (str8_match(str8_lit("level="), param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + String8 level_param = param_arr.v[0]; + String8List level_list = str8_split_by_string_chars(scratch.arena, level_param, str8_lit("="), 0); + if (level_list.node_count == 2) { + if (str8_match(level_list.first->string, str8_lit("level"), StringMatchFlag_CaseInsensitive)) { + String8 level = level_list.last->string; + if (str8_match(level, str8_lit("'asInvoker'"), 0) || + str8_match(level, str8_lit("'highestAvailable'"), 0) || + str8_match(level, str8_lit("'requireAdministrator'"), 0)) { + // manifest level was parsed! + config->manifest_uac = 1; + config->manifest_level = push_str8_copy(arena, level); + if (param_arr.count > 1) { + String8 ui_access_param = param_arr.v[1]; + String8List ui_access_list = str8_split_by_string_chars(scratch.arena, ui_access_param, str8_lit("="), 0); + if (ui_access_list.node_count == 2) { + String8 ui_access = ui_access_list.last->string; + if (str8_match(ui_access, str8_lit("'true'"), 0) || + str8_match(ui_access, str8_lit("'false'"), 0)) { + // ui access was parsed! + config->manifest_ui_access = push_str8_copy(arena, ui_access); + } else { + lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, ui_access_param); + } + } else { + lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, ui_access_param); + } + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else if (str8_match(str8_lit("no"), param_arr.v[0], StringMatchFlag_CaseInsensitive)) { + config->manifest_uac = 0; + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "empty param string"); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } break; + + case LNK_CmdSwitch_Natvis: { + // warn about invalid natvis extension + for (String8Node *node = value_strings.first; node != 0; node = node->next) { + String8 ext = str8_skip_last_dot(node->string); + if (!str8_match(ext, str8_lit("natvis"), StringMatchFlag_CaseInsensitive)) { + lnk_error_cmd_switch(LNK_Warning_InvalidNatvisFileExt, obj_path, lib_path, cmd_switch, "Visual Studio expects .natvis extension: \"%S\"", node->string); + } + } + + String8List natvis_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->natvis_list, &natvis_list); + } break; + + case LNK_CmdSwitch_NoDefaultLib: { + if (value_strings.node_count == 0) { + config->no_default_libs = 1; + } else { + String8List no_default_lib_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list); + } + } break; + + case LNK_CmdSwitch_NoExp: { + config->build_exp = 0; + } break; + + case LNK_CmdSwitch_NoImpLib: { + config->build_imp_lib = 0; + } break; + + case LNK_CmdSwitch_NoLogo: { + // we don't print logo + } break; + + case LNK_CmdSwitch_NxCompat: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NX_COMPAT); + } break; + + case LNK_CmdSwitch_Opt: { + for (String8Node *n = value_strings.first; n != 0; n = n->next) { + String8 param = n->string; + if (str8_match(param, str8_lit("ref"), StringMatchFlag_CaseInsensitive)) { + config->opt_ref = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("noref"), StringMatchFlag_CaseInsensitive)) { + config->opt_ref = LNK_SwitchState_No; + } else if (str8_match(param, str8_lit("icf"), StringMatchFlag_CaseInsensitive) || + str8_match(param, str8_lit("icf="), StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { + String8List vals = str8_split_by_string_chars(scratch.arena, param, str8_lit("="), 0); + if (vals.node_count > 2) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters for iteration"); + continue; + } + if (vals.node_count == 2) { + B32 is_parsed = try_u64_from_str8_c_rules(vals.last->string, &config->opt_iter_count); + if (!is_parsed) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse iterations \"%S\"", vals.last->string); + continue; + } + } + config->opt_icf = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("noicf"), StringMatchFlag_CaseInsensitive)) { + config->opt_icf = LNK_SwitchState_No; + } else if (str8_match(param, str8_lit("lbr"), StringMatchFlag_CaseInsensitive)) { + config->opt_lbr = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("nolibr"), StringMatchFlag_CaseInsensitive)) { + config->opt_lbr = LNK_SwitchState_No; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown option \"%S\"", param); + } + } + } break; + + case LNK_CmdSwitch_Out: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->image_name); + } break; + + case LNK_CmdSwitch_Pdb: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_name); + } break; + + case LNK_CmdSwitch_PdbAltPath: { + // see :PdbAltPath + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_alt_path); + } break; + + case LNK_CmdSwitch_PdbPageSize: { + U64 page_size; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &page_size, LNK_ParseU64Flag_CheckPow2)) { + if (page_size >= MSF_MIN_PAGE_SIZE) { + if (page_size < MSF_MAX_PAGE_SIZE) { + config->pdb_page_size = page_size; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "page size must be <= %u bytes", MSF_MAX_PAGE_SIZE); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "page size must be >= %u bytes", MSF_MIN_PAGE_SIZE); + } + } + } break; + + case LNK_CmdSwitch_Release: { + if (value_strings.node_count == 0) { + config->flags |= LNK_ConfigFlag_WriteImageChecksum; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Stack: { + Rng1U64 reserve_commit; + reserve_commit.v[0] = config->stack_reserve; + reserve_commit.v[1] = config->stack_commit; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &reserve_commit)) { + if (reserve_commit.v[0] >= reserve_commit.v[1]) { + U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); + U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); +#if 0 + if (reserve_aligned != reserve_commit.v[0]) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "reserve is not power of two, aligned to %u", reserve_aligned); + } + if (commit_aligned != reserve_commit.v[1]) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "commit is not power of two, aligned to %u", commit_aligned); + } +#endif + config->stack_reserve = reserve_aligned; + config->stack_commit = commit_aligned; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); + } + } + } break; + + case LNK_CmdSwitch_SubSystem: { + if (value_strings.node_count <= 2 && value_strings.node_count > 0) { + // set subsystem type + PE_WindowsSubsystem subsystem = pe_subsystem_from_string(value_strings.first->string); + if (subsystem != PE_WindowsSubsystem_UNKNOWN) { + if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "overriding subystem \"%S\" with \"%S\"", + pe_string_from_subsystem(config->subsystem), + pe_string_from_subsystem(subsystem)); + } + config->subsystem = subsystem; + + // parse version (optional) + if (value_strings.node_count == 2) { + str8_list_pop_front(&value_strings); // pop subsystem parameter + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->subsystem_ver); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid subsystem \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Time: { + } break; + + case LNK_CmdSwitch_TsAware: { + lnk_cmd_switch_set_flag_inv_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_NoTsAware); + } break; + + case LNK_CmdSwitch_Version: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->image_ver); + } break; + + case LNK_CmdSwitch_Rad_Age: { + lnk_cmd_switch_parse_u32(obj_path, lib_path, cmd_switch, value_strings, &config->age, 0); + } break; + + case LNK_CmdSwitch_Rad_BuildInfo: { + lnk_print_build_info(); + os_abort(0); + } break; + + case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); + } break; + + case LNK_CmdSwitch_Rad_Debug: { + lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug); + } break; + case LNK_CmdSwitch_Rad_DebugName: { + // :Rad_DebugAltPath + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug_name); + } break; + + case LNK_CmdSwitch_Rad_DebugAltPath: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug_alt_path); + } break; + + case LNK_CmdSwitch_Rad_DelayBind: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_DelayBind); + } break; + + case LNK_CmdSwitch_Rad_DoMerge: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_Merge); + } break; + + case LNK_CmdSwitch_Rad_EnvLib: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_EnvLib); + } break; + + case LNK_CmdSwitch_Rad_Exe: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_EXE); + } break; + + case LNK_CmdSwitch_Rad_Guid: { + if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("imageblake3"), StringMatchFlag_CaseInsensitive)) { + config->guid_type = Lnk_DebugInfoGuid_ImageBlake3; + } else if (str8_match(value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { + config->guid = os_make_guid(); + } else { + Guid guid; + if (try_guid_from_string(value_strings.first->string, &guid)) { + config->guid = guid; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse \"%S\"", value_strings.first->string); + } + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, expected GUID formatted as following: \"0000000-0000-0000-0000-000000000000\""); + } + } break; + + case LNK_CmdSwitch_Rad_IdleWorkers: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->idle_worker_count, 0); + } break; + + case LNK_CmdSwitch_Rad_LargePages: { + if (value_strings.node_count == 0) { + OS_ProcessInfo *process_info = os_get_process_info(); + if (process_info->large_pages_allowed) { + arena_default_flags |= ArenaFlag_LargePages; + } else { + lnk_error_cmd_switch(LNK_Warning_LargePages, obj_path, lib_path, cmd_switch, "Large pages aren't enabled on this system."); +#if OS_WINDOWS + lnk_supplement_error("To enable large pages:"); + lnk_supplement_error("\t- Press Win+R and open \"gpedit.msc\""); + lnk_supplement_error("\t- Navigate to Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > User Rights And Assignments"); + lnk_supplement_error("\t- Double-click on \"Lock pages in memory\""); + lnk_supplement_error("\t- Click \"Add User or Group...\""); + lnk_supplement_error("\t- Type in your user name"); + lnk_supplement_error("\t- Click Oks and reboot the machine"); +#endif + } + } else if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("quiet"), StringMatchFlag_CaseInsensitive)) { + OS_ProcessInfo *process_info = os_get_process_info(); + if (process_info->large_pages_allowed) { + arena_default_flags |= ArenaFlag_LargePages; + } + } else if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + arena_default_flags &= ~ArenaFlag_LargePages; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter: \"%S\", expected NO or QUIET", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Rad_LinkVer: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->link_ver); + } break; + + case LNK_CmdSwitch_Rad_Log: { + if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { + for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { + lnk_set_log_status((LNK_LogType)ilog, 1); + } + } else if (str8_match(value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) { + lnk_set_log_status(LNK_Log_IO_Read, 1); + lnk_set_log_status(LNK_Log_IO_Write, 1); + } else { + LNK_LogType log_type = lnk_log_type_from_string(value_strings.first->string); + if (log_type == LNK_Log_Null) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); + } else { + lnk_set_log_status(log_type, 1); + } + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, expected 1"); + } + } break; + + case LNK_CmdSwitch_Rad_MtPath: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->mt_path); + } break; + + case LNK_CmdSwitch_Rad_OsVer: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->os_ver); + } break; + + case LNK_CmdSwitch_Rad_PageSize: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->page_size, 0); + } break; + + case LNK_CmdSwitch_Rad_PathStyle: { + if (value_strings.node_count == 1) { + PathStyle path_style = path_style_from_string(str8_list_first(&value_strings)); + if (path_style != PathStyle_Null) { + config->path_style = path_style; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNames: { + String8 mode_string = str8_list_first(&value_strings); + + LNK_TypeNameHashMode mode; + if (mode_string.size == 0) { + config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient; + } else { + mode = lnk_type_name_hash_mode_from_string(mode_string); + if (mode == LNK_TypeNameHashMode_Null) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter: \"%S\"", mode_string); + } else { + config->pdb_hash_type_names = mode; + } + } + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_hash_type_name_map); + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->pdb_hash_type_name_length, 0); + } break; + + case LNK_CmdSwitch_Rad_SectVirtOff: { + U64 sect_virt_off; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, §_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) { + if (sect_virt_off >= 0x1000) { + config->section_virt_off = sect_virt_off; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "section virtual offset must be >= 0x1000"); + } + } + } break; + + case LNK_CmdSwitch_Rad_SuppressError: { + U64List error_code_list = {0}; + if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) { + for (U64Node *error_code_n = error_code_list.first; error_code_n != 0; error_code_n = error_code_n->next) { + if (error_code_n->data < LNK_Error_Count) { + lnk_suppress_error(error_code_n->data); + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "unknown error code %llu", error_code_n->data); + } + } + } + } break; + + case LNK_CmdSwitch_Rad_SymbolTableCapDefined: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_defined, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapInternal: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_internal, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapWeak: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_weak, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapLib: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_lib, 0); + } break; + + case LNK_CmdSwitch_Rad_TargetOs: { + if (value_strings.node_count == 1) { + String8 os_string = str8_list_first(&value_strings); + OperatingSystem target_os = operating_system_from_string(os_string); + if (target_os != OperatingSystem_Null) { + config->target_os = target_os; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown operating system type %S", os_string); + } + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "expected 1 parameter"); + } + } break; + + case LNK_CmdSwitch_Rad_TimeStamp: { + lnk_cmd_switch_parse_u32(obj_path, lib_path, cmd_switch, value_strings, &config->time_stamp, 0); + } break; + + case LNK_CmdSwitch_Rad_Version: { + fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL); + os_abort(0); + } break; + + case LNK_CmdSwitch_Rad_Workers: { + U64 worker_count; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &worker_count, 0)) { + config->worker_count = worker_count; + } + } break; + + case LNK_CmdSwitch_Help: { + lnk_print_help(); + os_abort(0); + } break; + } + + scratch_end(scratch); +} + internal LNK_Config * lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) { @@ -894,8 +1690,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); // setup default flags - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512); if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); @@ -928,7 +1724,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); - #if BUILD_DEBUG lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); @@ -954,777 +1749,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // process command line switches for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { - LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string); - switch (cmd_switch) { - case LNK_CmdSwitch_Null: { - String8 value = str8_list_join(scratch.arena, &cmd->value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); - lnk_error(LNK_Warning_UnknownSwitch, "unknown switch: \"/%S%s%S\"", cmd->string, value.size ? ":" : "", value); - } break; - - default: { InvalidPath; } break; - - case LNK_CmdSwitch_NotImplemented: { - String8 value = str8_list_join(scratch.arena, &cmd->value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); - lnk_not_implemented("switch \"%S\" is not implemented \"%S\"", cmd->string, value); - } break; - - case LNK_CmdSwitch_Align: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->sect_align, LNK_ParseU64Flag_CheckPow2); - } break; - - case LNK_CmdSwitch_AllowBind: { - lnk_cmd_switch_set_flag_inv_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NO_BIND); - } break; - - case LNK_CmdSwitch_AllowIsolation: { - lnk_cmd_switch_set_flag_inv_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NO_ISOLATION); - } break; - - case LNK_CmdSwitch_AlternateName: { - String8 *error_string = lnk_parse_alt_name_directive_list(arena, cmd->value_strings, &config->alt_name_list); - if (error_string != 0) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string); - } - } break; - - case LNK_CmdSwitch_AppContainer: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_APPCONTAINER); - } break; - - case LNK_CmdSwitch_Base: { - if (cmd->value_strings.node_count == 2) { - String8Node *first_node = cmd->value_strings.first; - //String8Node *second_node = first_node->next; - B32 is_response_file = str8_match(str8_lit("@"), first_node->string, StringMatchFlag_RightSideSloppy); - if (is_response_file) { - //String8 file_path = first_node->string; - //String8 tag = second_node->string; - lnk_not_implemented("Response files are not implemented for /BASE"); - } else { - Rng1U64 addr_size = {0}; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &addr_size)) { - config->user_base_addr = addr_size.v[0]; - config->max_image_size = addr_size.v[1]; - } - } - } else if (cmd->value_strings.node_count == 1) { - U64 addr; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &addr, 0)) { - config->user_base_addr = addr; - } - } else if (cmd->value_strings.node_count == 0) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "expected at least 1 parameter"); - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters"); - } - } break; - - case LNK_CmdSwitch_Debug: { - if (cmd->value_strings.node_count == 0) { - config->debug_mode = LNK_DebugMode_Full; - } else if (cmd->value_strings.node_count == 1) { - LNK_DebugMode debug_mode = lnk_debug_mode_from_string(cmd->value_strings.first->string); - if (debug_mode == LNK_DebugMode_GHash) { - config->debug_mode = LNK_DebugMode_Full; - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "GHASH is not supported, switching to FULL"); - } else if (debug_mode == LNK_DebugMode_FastLink) { - config->debug_mode = LNK_DebugMode_Full; - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "FASTLINK is not supported, switching to FULL"); - } else if (debug_mode != LNK_DebugMode_Null) { - config->debug_mode = debug_mode; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_DefaultLib: { - String8List default_lib_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->input_default_lib_list, &default_lib_list); - } break; - - case LNK_CmdSwitch_Delay: { - if (cmd->value_strings.node_count == 0 || cmd->value_strings.node_count > 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } else { - String8 value = cmd->value_strings.first->string; - if (str8_match(value, str8_lit("unload"), StringMatchFlag_CaseInsensitive)) { - config->flags |= LNK_ConfigFlag_DelayUnload; - } else if (str8_match(value, str8_lit("nobind"), StringMatchFlag_CaseInsensitive)) { - config->flags &= ~LNK_ConfigFlag_DelayBind; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", value); - } - } - } break; - - case LNK_CmdSwitch_DelayLoad: { - String8List delay_load_dll_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->delay_load_dll_list, &delay_load_dll_list); - } break; - - case LNK_CmdSwitch_Dll: { - config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL; - } break; - - case LNK_CmdSwitch_DisallowLib: { - lnk_not_implemented("TODO: how is this switch different from /nodefaultlib?"); - } break; - - case LNK_CmdSwitch_DynamicBase: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_DYNAMIC_BASE); - } break; - - case LNK_CmdSwitch_Entry: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->user_entry_point_name); - config->entry_point_name = config->user_entry_point_name; - } break; - - case LNK_CmdSwitch_FastFail: { - // do nothing - } break; - - case LNK_CmdSwitch_FileAlign: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->file_align, LNK_ParseU64Flag_CheckPow2); - } break; - - case LNK_CmdSwitch_Fixed: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Fixed); - } break; - - case LNK_CmdSwitch_FunctionPadMin: { - if (cmd->value_strings.node_count == 0) { - config->function_pad_min = 0; // :function_pad_min - } else { - local_persist U64 function_pad_min; - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); - config->function_pad_min = &function_pad_min; - } - } break; - - case LNK_CmdSwitch_Heap: { - Rng1U64 reserve_commit; - reserve_commit.v[0] = config->heap_reserve; - reserve_commit.v[1] = config->heap_commit; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &reserve_commit)) { - if (reserve_commit.v[0] >= reserve_commit.v[1]) { - U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); - U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); -#if 0 - if (reserve_aligned != reserve_commit.v[0]) { - lnk_error_cmd_switch(LNK_WARNING_CMDL, cmd_switch, "reserve is not power of two, aligned to %u bytes", reserve_aligned); - } - if (commit_aligned != reserve_commit.v[1]) { - lnk_error_cmd_switch(LNK_WARNING_CMDL, cmd_switch, "commit is not power of two, aligned to %u bytes", commit_aligned); - } -#endif - config->heap_reserve = reserve_aligned; - config->heap_commit = commit_aligned; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); - } - } - } break; - - case LNK_CmdSwitch_HighEntropyVa: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_HIGH_ENTROPY_VA); - } break; - - case LNK_CmdSwitch_Ignore: { - U64 error_code; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &error_code, 0)) { - switch (error_code) { - case LNK_MsWarningCode_UnsuedDelayLoadDll: { - lnk_suppress_error(LNK_Warning_UnusedDelayLoadDll); - } break; - case LNK_MsWarningCode_MissingExternalTypeServer: { - lnk_suppress_error(LNK_Warning_MissingExternalTypeServer); - } break; - case LNK_MsWarningCode_SectionFlagsConflict: { - lnk_suppress_error(LNK_Warning_SectionFlagsConflict); - } break; - default: { - lnk_not_implemented("TODO: /IGNORE:%llu", error_code); - } break; - } - } - } break; - - case LNK_CmdSwitch_ImpLib: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->imp_lib_name); - } break; - - case LNK_CmdSwitch_Include: { - String8List include_symbol_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->include_symbol_list, &include_symbol_list); - } break; - - case LNK_CmdSwitch_Incremental: { - LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &state)) { - if (state == LNK_SwitchState_Yes) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "incremental linkage is not supported"); - } - } - } break; - - case LNK_CmdSwitch_LargeAddressAware: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); - } break; - - case LNK_CmdSwitch_LibPath: { - String8List lib_dir_list = str8_list_copy(arena, &cmd->value_strings); - for (String8Node *dir_n = lib_dir_list.first; dir_n != 0; dir_n = dir_n->next) { - if (!os_folder_path_exists(dir_n->string)) { - String8 full_path = os_full_path_from_path(scratch.arena, dir_n->string); - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "path doesn't exist %S", full_path); - } - } - str8_list_concat_in_place(&config->lib_dir_list, &lib_dir_list); - } break; - - case LNK_CmdSwitch_Machine: { - if (cmd->value_strings.node_count == 1) { - COFF_MachineType machine = coff_machine_from_string(cmd->value_strings.first->string); - if (machine != COFF_MachineType_UNKNOWN) { - config->machine = machine; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Manifest: { - if (cmd->value_strings.node_count == 1) { - String8List param_list = str8_split_by_string_chars(scratch.arena, cmd->value_strings.first->string, str8_lit(","), 0); - String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); - if (param_arr.count > 0) { - if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { - config->manifest_opt = LNK_ManifestOpt_Embed; - - if (param_arr.count == 1) { - config->manifest_resource_id = 0; - } else if (param_arr.count > 1) { - // parse resource id - if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); - String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); - if (res_id_arr.count == 2) { - U64 resource_id; - if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) { - config->manifest_resource_id = push_u64(arena, resource_id); - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]); - } - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } else if (str8_match(param_arr.v[0], str8_lit("no"), StringMatchFlag_CaseInsensitive)) { - config->manifest_opt = LNK_ManifestOpt_No; - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } else if (cmd->value_strings.node_count == 0) { - config->manifest_opt = LNK_ManifestOpt_WriteToFile; - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } break; - - case LNK_CmdSwitch_ManifestDependency: { - String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); - - if (config->manifest_opt == LNK_ManifestOpt_Null) { - config->manifest_opt = LNK_ManifestOpt_WriteToFile; - } - } break; - - case LNK_CmdSwitch_ManifestFile: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->manifest_name); - } break; - - case LNK_CmdSwitch_ManifestInput: { - // see :manifest_input - } break; - - case LNK_CmdSwitch_ManifestUac: { - if (cmd->value_strings.node_count == 1) { - String8 uac = lnk_error_check_and_strip_quotes(LNK_Error_Cmdl, cmd_switch, cmd->value_strings.first->string); - String8List param_list = str8_split_by_string_chars(scratch.arena, uac, str8_lit(" "), 0); - String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); - if (param_arr.count > 0) { - if (str8_match(str8_lit("level="), param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - String8 level_param = param_arr.v[0]; - String8List level_list = str8_split_by_string_chars(scratch.arena, level_param, str8_lit("="), 0); - if (level_list.node_count == 2) { - if (str8_match(level_list.first->string, str8_lit("level"), StringMatchFlag_CaseInsensitive)) { - String8 level = level_list.last->string; - if (str8_match(level, str8_lit("'asInvoker'"), 0) || - str8_match(level, str8_lit("'highestAvailable'"), 0) || - str8_match(level, str8_lit("'requireAdministrator'"), 0)) { - // manifest level was parsed! - config->manifest_uac = 1; - config->manifest_level = push_str8_copy(arena, level); - if (param_arr.count > 1) { - String8 ui_access_param = param_arr.v[1]; - String8List ui_access_list = str8_split_by_string_chars(scratch.arena, ui_access_param, str8_lit("="), 0); - if (ui_access_list.node_count == 2) { - String8 ui_access = ui_access_list.last->string; - if (str8_match(ui_access, str8_lit("'true'"), 0) || - str8_match(ui_access, str8_lit("'false'"), 0)) { - // ui access was parsed! - config->manifest_ui_access = push_str8_copy(arena, ui_access); - } else { - lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, cmd_switch, ui_access_param); - } - } else { - lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, cmd_switch, ui_access_param); - } - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else if (str8_match(str8_lit("no"), param_arr.v[0], StringMatchFlag_CaseInsensitive)) { - config->manifest_uac = 0; - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "empty param string"); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } break; - - case LNK_CmdSwitch_Natvis: { - // warn about invalid natvis extension - for (String8Node *node = cmd->value_strings.first; node != 0; node = node->next) { - String8 ext = str8_skip_last_dot(node->string); - if (!str8_match(ext, str8_lit("natvis"), StringMatchFlag_CaseInsensitive)) { - lnk_error_cmd_switch(LNK_Warning_InvalidNatvisFileExt, cmd_switch, "Visual Studio expects .natvis extension: \"%S\"", node->string); - } - } - - String8List natvis_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->natvis_list, &natvis_list); - } break; - - case LNK_CmdSwitch_NoDefaultLib: { - if (cmd->value_strings.node_count == 0) { - config->no_default_libs = 1; - } else { - String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list); - } - } break; - - case LNK_CmdSwitch_NoExp: { - config->build_exp = 0; - } break; - - case LNK_CmdSwitch_NoImpLib: { - config->build_imp_lib = 0; - } break; - - case LNK_CmdSwitch_NoLogo: { - // we don't print logo - } break; - - case LNK_CmdSwitch_NxCompat: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NX_COMPAT); - } break; - - case LNK_CmdSwitch_Opt: { - for (String8Node *n = cmd->value_strings.first; n != 0; n = n->next) { - String8 param = n->string; - if (str8_match(param, str8_lit("ref"), StringMatchFlag_CaseInsensitive)) { - config->opt_ref = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noref"), StringMatchFlag_CaseInsensitive)) { - config->opt_ref = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("icf"), StringMatchFlag_CaseInsensitive) || - str8_match(param, str8_lit("icf="), StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { - String8List vals = str8_split_by_string_chars(scratch.arena, param, str8_lit("="), 0); - if (vals.node_count > 2) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters for iteration"); - continue; - } - if (vals.node_count == 2) { - B32 is_parsed = try_u64_from_str8_c_rules(vals.last->string, &config->opt_iter_count); - if (!is_parsed) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse iterations \"%S\"", vals.last->string); - continue; - } - } - config->opt_icf = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noicf"), StringMatchFlag_CaseInsensitive)) { - config->opt_icf = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("lbr"), StringMatchFlag_CaseInsensitive)) { - config->opt_lbr = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("nolibr"), StringMatchFlag_CaseInsensitive)) { - config->opt_lbr = LNK_SwitchState_No; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown option \"%S\"", param); - } - } - } break; - - case LNK_CmdSwitch_Out: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->image_name); - } break; - - case LNK_CmdSwitch_Pdb: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_name); - } break; - - case LNK_CmdSwitch_PdbAltPath: { - // see :PdbAltPath - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_alt_path); - } break; - - case LNK_CmdSwitch_PdbPageSize: { - U64 page_size; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &page_size, LNK_ParseU64Flag_CheckPow2)) { - if (page_size >= MSF_MIN_PAGE_SIZE) { - if (page_size < MSF_MAX_PAGE_SIZE) { - config->pdb_page_size = page_size; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "page size must be <= %u bytes", MSF_MAX_PAGE_SIZE); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "page size must be >= %u bytes", MSF_MIN_PAGE_SIZE); - } - } - } break; - - case LNK_CmdSwitch_Release: { - if (cmd->value_strings.node_count == 0) { - config->flags |= LNK_ConfigFlag_WriteImageChecksum; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Stack: { - Rng1U64 reserve_commit; - reserve_commit.v[0] = config->stack_reserve; - reserve_commit.v[1] = config->stack_commit; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &reserve_commit)) { - if (reserve_commit.v[0] >= reserve_commit.v[1]) { - U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); - U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); -#if 0 - if (reserve_aligned != reserve_commit.v[0]) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "reserve is not power of two, aligned to %u", reserve_aligned); - } - if (commit_aligned != reserve_commit.v[1]) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "commit is not power of two, aligned to %u", commit_aligned); - } -#endif - config->stack_reserve = reserve_aligned; - config->stack_commit = commit_aligned; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); - } - } - } break; - - case LNK_CmdSwitch_SubSystem: { - if (cmd->value_strings.node_count <= 2 && cmd->value_strings.node_count > 0) { - // set subsystem type - PE_WindowsSubsystem subsystem = pe_subsystem_from_string(cmd->value_strings.first->string); - if (subsystem != PE_WindowsSubsystem_UNKNOWN) { - config->subsystem = subsystem; - - // parse version (optional) - if (cmd->value_strings.node_count == 2) { - String8List value_strings = cmd->value_strings; - str8_list_pop_front(&value_strings); // pop subsystem parameter - lnk_cmd_switch_parse_version(value_strings, cmd_switch, &config->subsystem_ver); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid subsystem \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Time: { - } break; - - case LNK_CmdSwitch_TsAware: { - lnk_cmd_switch_set_flag_inv_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_NoTsAware); - } break; - - case LNK_CmdSwitch_Version: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->image_ver); - } break; - - case LNK_CmdSwitch_Rad_Age: { - lnk_cmd_switch_parse_u32(cmd->value_strings, cmd_switch, &config->age, 0); - } break; - - case LNK_CmdSwitch_Rad_BuildInfo: { - lnk_print_build_info(); - os_abort(0); - } break; - - case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); - } break; - - case LNK_CmdSwitch_Rad_Debug: { - lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->rad_debug); - } break; - case LNK_CmdSwitch_Rad_DebugName: { - // :Rad_DebugAltPath - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_name); - } break; - - case LNK_CmdSwitch_Rad_DebugAltPath: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_alt_path); - } break; - - case LNK_CmdSwitch_Rad_DelayBind: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind); - } break; - - case LNK_CmdSwitch_Rad_DoMerge: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge); - } break; - - case LNK_CmdSwitch_Rad_EnvLib: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_EnvLib); - } break; - - case LNK_CmdSwitch_Rad_Exe: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->file_characteristics, PE_ImageFileCharacteristic_EXE); - } break; - - case LNK_CmdSwitch_Rad_Guid: { - if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("imageblake3"), StringMatchFlag_CaseInsensitive)) { - config->guid_type = Lnk_DebugInfoGuid_ImageBlake3; - } else if (str8_match(cmd->value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { - config->guid = os_make_guid(); - } else { - Guid guid; - if (try_guid_from_string(cmd->value_strings.first->string, &guid)) { - config->guid = guid; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse \"%S\"", cmd->value_strings.first->string); - } - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, expected GUID formatted as following: \"0000000-0000-0000-0000-000000000000\""); - } - } break; - - case LNK_CmdSwitch_Rad_IdleWorkers: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->idle_worker_count, 0); - } break; - - case LNK_CmdSwitch_Rad_LargePages: { - if (cmd->value_strings.node_count == 0) { - OS_ProcessInfo *process_info = os_get_process_info(); - if (process_info->large_pages_allowed) { - arena_default_flags |= ArenaFlag_LargePages; - } else { - lnk_error_cmd_switch(LNK_Warning_LargePages, cmd_switch, "Large pages aren't enabled on this system."); -#if OS_WINDOWS - lnk_supplement_error("To enable large pages:"); - lnk_supplement_error("\t- Press Win+R and open \"gpedit.msc\""); - lnk_supplement_error("\t- Navigate to Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > User Rights And Assignments"); - lnk_supplement_error("\t- Double-click on \"Lock pages in memory\""); - lnk_supplement_error("\t- Click \"Add User or Group...\""); - lnk_supplement_error("\t- Type in your user name"); - lnk_supplement_error("\t- Click Oks and reboot the machine"); -#endif - } - } else if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("quiet"), StringMatchFlag_CaseInsensitive)) { - OS_ProcessInfo *process_info = os_get_process_info(); - if (process_info->large_pages_allowed) { - arena_default_flags |= ArenaFlag_LargePages; - } - } else if (str8_match(cmd->value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { - arena_default_flags &= ~ArenaFlag_LargePages; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter: \"%S\", expected NO or QUIET", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Rad_LinkVer: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->link_ver); - } break; - - case LNK_CmdSwitch_Rad_Log: { - if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { - for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { - lnk_set_log_status((LNK_LogType)ilog, 1); - } - } else if (str8_match(cmd->value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) { - lnk_set_log_status(LNK_Log_IO_Read, 1); - lnk_set_log_status(LNK_Log_IO_Write, 1); - } else { - LNK_LogType log_type = lnk_log_type_from_string(cmd->value_strings.first->string); - if (log_type == LNK_Log_Null) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", cmd->value_strings.first->string); - } else { - lnk_set_log_status(log_type, 1); - } - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, expected 1"); - } - } break; - - case LNK_CmdSwitch_Rad_MtPath: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->mt_path); - } break; - - case LNK_CmdSwitch_Rad_OsVer: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->os_ver); - } break; - - case LNK_CmdSwitch_Rad_PageSize: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->page_size, 0); - } break; - - case LNK_CmdSwitch_Rad_PathStyle: { - if (cmd->value_strings.node_count == 1) { - PathStyle path_style = path_style_from_string(str8_list_first(&cmd->value_strings)); - if (path_style != PathStyle_Null) { - config->path_style = path_style; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNames: { - String8 mode_string = str8_list_first(&cmd->value_strings); - - LNK_TypeNameHashMode mode; - if (mode_string.size == 0) { - config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient; - } else { - mode = lnk_type_name_hash_mode_from_string(mode_string); - if (mode == LNK_TypeNameHashMode_Null) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter: \"%S\"", mode_string); - } else { - config->pdb_hash_type_names = mode; - } - } - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_map); - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_length, 0); - } break; - - case LNK_CmdSwitch_Rad_SectVirtOff: { - U64 sect_virt_off; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, §_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) { - if (sect_virt_off >= 0x1000) { - config->section_virt_off = sect_virt_off; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "section virtual offset must be >= 0x1000"); - } - } - } break; - - case LNK_CmdSwitch_Rad_SuppressError: { - U64List error_code_list = {0}; - if (lnk_cmd_switch_parse_u64_list(scratch.arena, cmd->value_strings, cmd_switch, &error_code_list, 0)) { - for (U64Node *error_code_n = error_code_list.first; error_code_n != 0; error_code_n = error_code_n->next) { - if (error_code_n->data < LNK_Error_Count) { - lnk_suppress_error(error_code_n->data); - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "unknown error code %llu", error_code_n->data); - } - } - } - } break; - - case LNK_CmdSwitch_Rad_SymbolTableCapDefined: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_defined, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapInternal: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_internal, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapWeak: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_weak, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapLib: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_lib, 0); - } break; - - case LNK_CmdSwitch_Rad_TargetOs: { - if (cmd->value_strings.node_count == 1) { - String8 os_string = str8_list_first(&cmd->value_strings); - OperatingSystem target_os = operating_system_from_string(os_string); - if (target_os != OperatingSystem_Null) { - config->target_os = target_os; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown operating system type %S", os_string); - } - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "expected 1 parameter"); - } - } break; - - case LNK_CmdSwitch_Rad_TimeStamp: { - lnk_cmd_switch_parse_u32(cmd->value_strings, cmd_switch, &config->time_stamp, 0); - } break; - - case LNK_CmdSwitch_Rad_Version: { - fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL); - os_abort(0); - } break; - - case LNK_CmdSwitch_Rad_Workers: { - U64 worker_count; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &worker_count, 0)) { - config->worker_count = worker_count; - } - } break; - - case LNK_CmdSwitch_Help: { - lnk_print_help(); - os_abort(0); - } break; - } + lnk_apply_cmd_option_to_config(arena, config, cmd->string, cmd->value_strings, str8_zero(), str8_zero()); } // apply idle workers switch @@ -1733,7 +1758,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) U64 final_worker_count = config->worker_count - config->idle_worker_count; config->worker_count = final_worker_count; } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count); + lnk_error_cmd_switch(LNK_Warning_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count); } } @@ -1748,7 +1773,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) } } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); + lnk_error_cmd_switch(LNK_Error_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); } } diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 01518cbe..54783f7b 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -40,6 +40,7 @@ typedef enum LNK_CmdSwitch_ManifestFile, LNK_CmdSwitch_ManifestInput, LNK_CmdSwitch_ManifestUac, + LNK_CmdSwitch_Merge, LNK_CmdSwitch_Natvis, LNK_CmdSwitch_NoDefaultLib, LNK_CmdSwitch_NoExp, @@ -73,18 +74,23 @@ typedef enum LNK_CmdSwitch_DependentLoadFlag, LNK_CmdSwitch_Driver, LNK_CmdSwitch_DisallowLib, + LNK_CmdSwitch_EditAndContinue, LNK_CmdSwitch_EmitVolatileMetadata, LNK_CmdSwitch_ErrorReport, LNK_CmdSwitch_Export, LNK_CmdSwitch_ExportAdmin, LNK_CmdSwitch_FastGenProfile, + LNK_CmdSwitch_FailIfMismatch, LNK_CmdSwitch_Force, LNK_CmdSwitch_Guard, + LNK_CmdSwitch_GuardSym, LNK_CmdSwitch_GenProfile, LNK_CmdSwitch_IdlOut, LNK_CmdSwitch_IgnoreIdl, LNK_CmdSwitch_Ilk, LNK_CmdSwitch_IntegrityCheck, + LNK_CmdSwitch_InferAsanLibs, + LNK_CmdSwitch_InferAsanLibsNo, LNK_CmdSwitch_Kernel, LNK_CmdSwitch_KeyContainer, LNK_CmdSwitch_KeyFile, @@ -94,7 +100,6 @@ typedef enum LNK_CmdSwitch_LtcgOut, LNK_CmdSwitch_Map, LNK_CmdSwitch_MapInfo, - LNK_CmdSwitch_Merge, LNK_CmdSwitch_Midl, LNK_CmdSwitch_NoAssembly, LNK_CmdSwitch_NoEntry, @@ -108,6 +113,7 @@ typedef enum LNK_CmdSwitch_Stub, LNK_CmdSwitch_SwapRun, LNK_CmdSwitch_TlbId, + LNK_CmdSwitch_ThrowingNew, LNK_CmdSwitch_UserProfile, LNK_CmdSwitch_Verbose, LNK_CmdSwitch_Version, @@ -281,7 +287,6 @@ typedef struct LNK_Config Version subsystem_ver; PE_ImageFileCharacteristics file_characteristics; PE_DllCharacteristics dll_characteristics; - String8 user_entry_point_name; String8 entry_point_name; String8List lib_dir_list; PathStyle path_style; @@ -471,9 +476,9 @@ internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSw //////////////////////////////// // Errors -internal void lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt, ...); -internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch); -internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, String8 param); +internal void lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...); +internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch); +internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param); //////////////////////////////// // Getters @@ -488,24 +493,26 @@ internal B32 lnk_do_debug_info(LNK_Config *config); //////////////////////////////// // Specialized Parsers -internal B32 lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_switch, Version *ver_out); -internal B32 lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_switch, Rng1U64 *tuple_out); -internal B32 lnk_cmd_switch_parse_u64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switch, LNK_SwitchState *value_out); -internal void lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits); -internal void lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits); -internal void lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits); -internal void lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *flags, U32 bits); -internal void lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits); -internal B32 lnk_cmd_switch_parse_string(String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out); -internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out); +internal B32 lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out); +internal B32 lnk_cmd_switch_parse_tuple(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out); +internal B32 lnk_cmd_switch_parse_u64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_u32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out); +internal void lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); +internal void lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); +internal void lnk_cmd_switch_set_flag_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); +internal void lnk_cmd_switch_set_flag_32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits); +internal void lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); +internal B32 lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); +internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out); internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out); //////////////////////////////// +internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, String8 obj_path, String8 lib_path); + internal LNK_Config * lnk_config_from_raw_cmd_line(Arena *arena, String8List raw_cmd_line); internal LNK_Config * lnk_build_config(Arena *arena, int argc, char **argv); diff --git a/src/linker/lnk_directive.c b/src/linker/lnk_directive.c index c0d7e408..c3107942 100644 --- a/src/linker/lnk_directive.c +++ b/src/linker/lnk_directive.c @@ -23,69 +23,76 @@ lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_Me //////////////////////////////// +internal B32 +lnk_is_directive_legal(LNK_CmdSwitchType type) +{ + static B32 init_table = 1; + static B8 is_legal[LNK_CmdSwitch_Count]; + if (init_table) { + init_table = 0; + is_legal[LNK_CmdSwitch_AlternateName] = 1; + is_legal[LNK_CmdSwitch_DefaultLib] = 1; + is_legal[LNK_CmdSwitch_DisallowLib] = 1; + is_legal[LNK_CmdSwitch_EditAndContinue] = 1; + is_legal[LNK_CmdSwitch_Entry] = 1; + is_legal[LNK_CmdSwitch_Export] = 1; + is_legal[LNK_CmdSwitch_FailIfMismatch] = 1; + is_legal[LNK_CmdSwitch_GuardSym] = 1; + is_legal[LNK_CmdSwitch_Include] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibs] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibsNo] = 1; + is_legal[LNK_CmdSwitch_ManifestDependency] = 1; + is_legal[LNK_CmdSwitch_Merge] = 1; + is_legal[LNK_CmdSwitch_NoDefaultLib] = 1; + is_legal[LNK_CmdSwitch_Release] = 1; + is_legal[LNK_CmdSwitch_Section] = 1; + is_legal[LNK_CmdSwitch_Stack] = 1; + is_legal[LNK_CmdSwitch_SubSystem] = 1; + is_legal[LNK_CmdSwitch_ThrowingNew] = 1; + } + return is_legal[type]; +} + internal void lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path) { Temp scratch = scratch_begin(&arena, 1); - String8 unparsed_directives = buffer; + String8 to_parse; { - static const U8 BOM_SIG[] = { 0xEF, 0xBB, 0xBF }; - B32 is_bom = MemoryMatch(buffer.str, &BOM_SIG[0], sizeof(BOM_SIG)); - if (is_bom) { - unparsed_directives = str8_zero(); + local_persist const U8 bom_sig[] = { 0xEF, 0xBB, 0xBF }; + local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; + if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { + to_parse = str8_zero(); lnk_not_implemented("TODO: support for BOM encoding"); - } - static const U8 ASCII_SIG[] = { 0x20, 0x20, 0x20 }; - B32 is_ascii = MemoryMatch(buffer.str, &ASCII_SIG[0], sizeof(ASCII_SIG)); - if (is_ascii) { - unparsed_directives = str8_skip(buffer, sizeof(ASCII_SIG)); + } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { + to_parse = str8_skip(buffer, sizeof(ascii_sig)); + } else { + to_parse = buffer; } } - String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, unparsed_directives); + String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, to_parse); LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list); for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) { - static struct { - LNK_DirectiveKind kind; - String8 name; - } directive_table[LNK_Directive_Count] = { - { LNK_Directive_Null, str8_lit_comp("") }, - { LNK_Directive_DefaultLib, str8_lit_comp("defaultlib") }, - { LNK_Directive_Export, str8_lit_comp("export" ) }, - { LNK_Directive_Include, str8_lit_comp("include") }, - { LNK_Directive_ManifestDependency, str8_lit_comp("manifestdependency") }, - { LNK_Directive_Merge, str8_lit_comp("merge") }, - { LNK_Directive_Section, str8_lit_comp("section") }, - { LNK_Directive_AlternateName, str8_lit_comp("alternatename") }, - { LNK_Directive_GuardSym, str8_lit_comp("guardsym") }, - { LNK_Directive_DisallowLib, str8_lit_comp("disallowlib") }, - { LNK_Directive_FailIfMismatch, str8_lit_comp("failifmismatch") }, - { LNK_Directive_EditAndContinue, str8_lit_comp("editandcontinue") }, - { LNK_Directive_ThrowingNew, str8_lit_comp("throwingnew") }, - }; + LNK_CmdSwitchType type = lnk_cmd_switch_type_from_string(opt->string); - LNK_DirectiveKind kind = LNK_Directive_Null; - for (U64 i = 0; i < ArrayCount(directive_table); ++i) { - if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) { - kind = directive_table[i].kind; - if (kind == LNK_Directive_Merge) { - String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")}); - } - break; - } - } - if (kind == LNK_Directive_Null) { + if (type == LNK_CmdSwitch_Null) { lnk_error(LNK_Warning_UnknownDirective, "%S: unknown directive \"%S\"", obj_path, opt->string); + continue; } - + if (!lnk_is_directive_legal(type)) { + lnk_error(LNK_Warning_IllegalDirective, "%S: illegal directive \"%S\"", obj_path, opt->string); + continue; + } + LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1); directive->next = 0; directive->id = push_str8_copy(arena, opt->string); directive->value_list = str8_list_copy(arena, &opt->value_strings); - - LNK_DirectiveList *directive_list = &directive_info->v[kind]; + + LNK_DirectiveList *directive_list = &directive_info->v[type]; SLLQueuePush(directive_list->first, directive_list->last, directive); ++directive_list->count; } @@ -110,7 +117,6 @@ lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list) } else { lib_path = push_str8_copy(arena, lib_path); } - str8_list_push(arena, &default_libs, lib_path); } diff --git a/src/linker/lnk_directive.h b/src/linker/lnk_directive.h index c6228738..64f9e0d2 100644 --- a/src/linker/lnk_directive.h +++ b/src/linker/lnk_directive.h @@ -51,27 +51,9 @@ typedef struct LNK_MergeDirectiveList LNK_MergeDirectiveNode *last; } LNK_MergeDirectiveList; -typedef enum -{ - LNK_Directive_Null, - LNK_Directive_DefaultLib, - LNK_Directive_Export, - LNK_Directive_Include, - LNK_Directive_ManifestDependency, - LNK_Directive_Merge, - LNK_Directive_Section, - LNK_Directive_AlternateName, - LNK_Directive_GuardSym, - LNK_Directive_DisallowLib, - LNK_Directive_FailIfMismatch, - LNK_Directive_EditAndContinue, - LNK_Directive_ThrowingNew, - LNK_Directive_Count -} LNK_DirectiveKind; - typedef struct LNK_DirectiveInfo { - LNK_DirectiveList v[LNK_Directive_Count]; + LNK_DirectiveList v[LNK_CmdSwitch_Count]; } LNK_DirectiveInfo; //////////////////////////////// diff --git a/src/linker/lnk_error.c b/src/linker/lnk_error.c index 1aeb04f0..b907de88 100644 --- a/src/linker/lnk_error.c +++ b/src/linker/lnk_error.c @@ -67,6 +67,31 @@ lnk_error(LNK_ErrorCode code, char *fmt, ...) va_end(args); } +internal void +lnk_error_with_loc_fv(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, va_list args) +{ + Temp scratch = scratch_begin(0, 0); + String8 text = push_str8fv(scratch.arena, fmt, args); + if (obj_path.size) { + if (lib_path.size) { + lnk_error(code, "%S(%S): %S", lib_path, obj_path, text); + } else { + lnk_error(code, "%S: %S", obj_path, text); + } + } else { + lnk_error(code, "%S", text); + } + scratch_end(scratch); +} + +internal void +lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...) +{ + va_list args; va_start(args, fmt); + lnk_error_with_loc_fv(code, obj_path, lib_path, fmt, args); + va_end(args); +} + internal void lnk_supplement_error(char *fmt, ...) { diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 555a23ce..65cdf96b 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -74,6 +74,7 @@ typedef enum LNK_Warning_SectionFlagsConflict, LNK_Warning_Subsystem, LNK_Warning_UnknownDirective, + LNK_Warning_IllegalDirective, LNK_Warning_UnresolvedComdat, LNK_Warning_UnusedDelayLoadDll, LNK_Warning_LongSectionName, @@ -110,6 +111,7 @@ typedef enum internal void lnk_init_error_handler(void); internal void lnk_errorfv(LNK_ErrorCode code, char *fmt, va_list args); internal void lnk_error(LNK_ErrorCode code, char *fmt, ...); +internal void lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...); internal void lnk_supplement_error(char *fmt, ...); internal void lnk_supplement_error_list(String8List list); internal void lnk_suppress_error(LNK_ErrorCode code); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index b6c9c487..2fb22216 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -6,19 +6,9 @@ internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...) { - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 text = push_str8fv(scratch.arena, fmt, args); - - if (obj->lib_path.size) { - lnk_error(code, "%S(%S): %S", obj->lib_path, obj->path, text); - } else { - lnk_error(code, "%S: %S", obj->path, text); - } - + va_list args; va_start(args, fmt); + lnk_error_with_loc_fv(code, obj->path, obj->lib_path, fmt, args); va_end(args); - scratch_end(scratch); } //////////////////////////////// @@ -230,7 +220,7 @@ THREAD_POOL_TASK_FUNC(lnk_default_lib_collector) String8List *result = &task->out_arr[task_id]; for (U64 obj_idx = range.min; obj_idx < range.max; obj_idx += 1) { LNK_Obj *obj = &task->in_arr.v[obj_idx].data; - String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_Directive_DefaultLib]); + String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_CmdSwitch_DefaultLib]); str8_list_concat_in_place(result, &list); } } @@ -264,7 +254,7 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector) for (; obj_ptr < obj_opl; obj_ptr += 1) { LNK_Obj *obj = &obj_ptr->data; - LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency]; + LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_CmdSwitch_ManifestDependency]; for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) { String8List dep = str8_list_copy(arena, &dir->value_list); str8_list_concat_in_place(list, &dep); @@ -450,7 +440,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // parse exports LNK_ExportParseList export_parse = {0}; - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Export].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) { lnk_parse_export_direcive(arena, &obj->export_parse, dir->value_list, obj); } @@ -461,12 +451,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // push /include symbols - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Include].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Include].first; dir != 0; dir = dir->next) { str8_list_concat_in_place(&obj->include_symbol_list, &dir->value_list); } // parse /alternatename - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_AlternateName].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) { String8 *invalid_string = lnk_parse_alt_name_directive_list(arena, dir->value_list, &obj->alt_name_list); if (invalid_string != 0) { lnk_error_obj(LNK_Error_Cmdl, obj, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string); From 24efb574f13287f3fd96b1741f806eb55f84dbde Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 13 Jan 2025 18:00:18 -0800 Subject: [PATCH 19/53] factored out inline site decoder into stand alone helper so it can be reused in the converter --- src/codeview/codeview_parse.c | 195 ++++++++++++++++ src/codeview/codeview_parse.h | 48 ++++ src/linker/codeview_ext/codeview.c | 213 ++--------------- src/rdi_from_pdb/rdi_from_pdb.c | 361 +++++++---------------------- 4 files changed, 352 insertions(+), 465 deletions(-) diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c index c1b0e30c..96732f61 100644 --- a/src/codeview/codeview_parse.c +++ b/src/codeview/codeview_parse.c @@ -257,6 +257,201 @@ cv_inline_annot_signed_from_unsigned_operand(U32 value) return result; } +internal CV_C13InlineSiteDecoder +cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff) +{ + CV_C13InlineSiteDecoder decoder = {0}; + decoder.parent_voff = parent_voff; + decoder.file_off = file_off; + decoder.ln = (S32)first_source_ln; + decoder.cn = 1; + decoder.ln_changed = 1; + return decoder; +} + +internal CV_C13InlineSiteDecoderStep +cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots) +{ + CV_C13InlineSiteDecoderStep result = {0}; + + for (; decoder->cursor < binary_annots.size && result.flags == 0; ) { + U32 op = CV_InlineBinaryAnnotation_Null; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &op); + + switch (op) { + case CV_InlineBinaryAnnotation_Null: { + decoder->cursor = binary_annots.size; + // this is last run, append range with left over code bytes + decoder->code_length = decoder->code_offset - decoder->code_offset_lo; + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_CodeOffset: { + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_offset); + decoder->code_offset_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: { + AssertAlways(!"TODO: test case"); + // U32 delta = 0; + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); + // decoder->code_offset_base = decoder->code_offset; + // decoder->code_offset_end = decoder->code_offset + delta; + // decoder->code_offset += delta; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffset: { + U32 delta = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); + + decoder->code_offset += delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + decoder->code_offset_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeLength: { + decoder->code_length = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeFile: { + U32 old_file_off = decoder->file_off; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->file_off); + decoder->file_off_changed = old_file_off != decoder->file_off; + // Compiler isn't obligated to terminate code sequence before chaning files, + // so we have to always force emit code range on file change. + decoder->code_length_changed = decoder->file_off_changed; + } break; + case CV_InlineBinaryAnnotation_ChangeLineOffset: { + S32 delta = 0; + decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); + + decoder->ln += delta; + decoder->ln_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeLineEndDelta: { + AssertAlways(!"TODO: test case"); + // S32 end_delta = 1; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); + // decoder->ln += end_delta; + } break; + case CV_InlineBinaryAnnotation_ChangeRangeKind: { + AssertAlways(!"TODO: test case"); + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &range_kind); + } break; + case CV_InlineBinaryAnnotation_ChangeColumnStart: { + AssertAlways(!"TODO: test case"); + // S32 delta; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); + // decoder->cn += delta; + } break; + case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: { + AssertAlways(!"TODO: test case"); + // S32 end_delta; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); + // decoder->cn += end_delta; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: { + U32 code_offset_and_line_offset = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &code_offset_and_line_offset); + + S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); + U32 code_delta = (code_offset_and_line_offset & 0xf); + + decoder->code_offset += code_delta; + decoder->ln += line_delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + + decoder->code_offset_changed = 1; + decoder->ln_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: { + U32 offset_delta = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &offset_delta); + + decoder->code_offset += offset_delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + + decoder->code_offset_changed = 1; + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeColumnEnd: { + AssertAlways(!"TODO: test case"); + // U32 column_end = 0; + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &column_end); + } break; + } + + U64 line_code_offset = decoder->code_offset; + + if (decoder->code_length_changed) { + // compute upper bound of the range + U64 code_offset_hi = decoder->code_offset + decoder->code_length; + + // can last code range be extended to cover current sequence too? + if (decoder->last_range.max == decoder->parent_voff + decoder->code_offset_lo) { + decoder->last_range.max = decoder->parent_voff + code_offset_hi; + + result.flags |= CV_C13InlineSiteDecoderStepFlag_ExtendLastRange; + result.range = decoder->last_range; + } else { + decoder->last_range = rng_1u64(decoder->parent_voff + decoder->code_offset_lo, decoder->parent_voff + code_offset_hi); + decoder->file_last_range = decoder->last_range; + + result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitRange; + result.range = decoder->last_range; + } + + // update state + decoder->code_offset_lo = code_offset_hi; + decoder->code_offset += decoder->code_length; + decoder->code_offset_lo_changed = 0; + decoder->code_length_changed = 0; + decoder->code_length = 0; + } + + if (decoder->file_off_changed || (decoder->file_count == 0)) { + result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitFile; + result.file_off = decoder->file_off; + + // update state + decoder->file_last_range = decoder->last_range; + decoder->file_off_changed = 0; + decoder->file_count += 1; + decoder->file_line_count = 0; + } + + if (decoder->code_offset_changed && decoder->ln_changed) { + if (decoder->file_line_count == 0 || decoder->file_last_ln != decoder->ln) { + result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitLine; + result.ln = decoder->ln; + result.cn = decoder->cn; + result.line_voff = decoder->parent_voff + line_code_offset; + result.line_voff_end = decoder->last_range.max; + + // update state + decoder->file_line_count += 1; + decoder->file_last_ln = decoder->ln; + } + + // update state + decoder->code_offset_changed = 0; + decoder->ln_changed = 0; + } + } + + return result; +} + //- Symbol/Leaf Helpers internal B32 diff --git a/src/codeview/codeview_parse.h b/src/codeview/codeview_parse.h index 5e558d60..e2b0fb01 100644 --- a/src/codeview/codeview_parse.h +++ b/src/codeview/codeview_parse.h @@ -95,6 +95,51 @@ struct CV_LeafParsed //////////////////////////////// //~ CodeView C13 Info Parser Types +typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder; +struct CV_C13InlineSiteDecoder +{ + U64 cursor; + U64 parent_voff; + CV_InlineRangeKind range_kind; + U32 code_length; + U32 code_offset; + U32 file_off; + S32 ln; + S32 cn; + U64 code_offset_lo; + B32 code_offset_changed; + B32 code_offset_lo_changed; + B32 code_length_changed; + B32 ln_changed; + B32 file_off_changed; + Rng1U64 last_range; + U32 file_count; + Rng1U64 file_last_range; + U64 file_line_count; + U64 file_last_ln; +}; + +typedef U32 CV_C13InlineSiteDecoderStepFlags; +enum +{ + CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0), + CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1), + CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2), + CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3), +}; + +typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep; +struct CV_C13InlineSiteDecoderStep +{ + CV_C13InlineSiteDecoderStepFlags flags; + Rng1U64 range; + U64 line_voff; + U64 line_voff_end; + U64 ln; + U64 cn; + U32 file_off; +}; + typedef struct CV_C13LinesParsed CV_C13LinesParsed; struct CV_C13LinesParsed { @@ -213,6 +258,9 @@ internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value); internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value); +internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff); +internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots); + //- Symbol/Leaf Helpers internal B32 cv_is_udt_name_anon(String8 name); diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index fa555c62..a2c4df0a 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1985,198 +1985,33 @@ cv_c13_parse_inline_binary_annots(Arena *arena, struct SourceFile *file_last = 0; U64 file_count = 0; - CV_InlineRangeKind range_kind = 0; (void)range_kind; - U32 code_length = 0; - U32 code_offset = 0; - U32 file_off = inlinee_parsed->file_off; - S32 ln = (S32)inlinee_parsed->first_source_ln; - S32 cn = 1; - U64 code_offset_lo = 0; - B32 code_offset_changed = 0; - B32 code_offset_lo_changed = 0; - B32 code_length_changed = 0; - B32 ln_changed = 1; - B32 file_off_changed = 0; - - for (U64 cursor = 0, keep_running = 1; cursor < binary_annots.size && keep_running; ) { - U32 op = CV_InlineBinaryAnnotation_Null; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &op); - - switch (op) { - case CV_InlineBinaryAnnotation_Null: { - keep_running = 0; - - // this is last run, append range with left over code bytes - code_length = code_offset - code_offset_lo; - code_length_changed = 1; - }break; - case CV_InlineBinaryAnnotation_CodeOffset: { - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset); - code_offset_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: { - AssertAlways(!"TODO: test case"); - // U32 delta = 0; - // cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &delta); - // code_offset_base = code_offset; - // code_offset_end = code_offset + delta; - // code_offset += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffset: { - U32 delta = 0; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &delta); - - code_offset += delta; - - if (!code_offset_lo_changed) { - code_offset_lo = code_offset; - code_offset_lo_changed = 1; - } - code_offset_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLength: { - code_length = 0; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_length); - code_length_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeFile: { - U32 old_file_off = file_off; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &file_off); - file_off_changed = old_file_off != file_off; - // Compiler isn't obligated to terminate code sequence before chaning files, - // so we have to always force emit code range on file change. - code_length_changed = file_off_changed; - }break; - case CV_InlineBinaryAnnotation_ChangeLineOffset: { - S32 delta = 0; - cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &delta); - - ln += delta; - ln_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeLineEndDelta: { - AssertAlways(!"TODO: test case"); - // S32 end_delta = 1; - // cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &end_delta); - // ln += end_delta; - }break; - case CV_InlineBinaryAnnotation_ChangeRangeKind: { - AssertAlways(!"TODO: test case"); - // cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &range_kind); - }break; - case CV_InlineBinaryAnnotation_ChangeColumnStart: { - AssertAlways(!"TODO: test case"); - // S32 delta; - // cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &delta); - // cn += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: { - AssertAlways(!"TODO: test case"); - // S32 end_delta; - // cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &end_delta); - // cn += end_delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: { - U32 code_offset_and_line_offset = 0; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset_and_line_offset); - - S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); - U32 code_delta = (code_offset_and_line_offset & 0xf); - - code_offset += code_delta; - ln += line_delta; - - if (!code_offset_lo_changed) { - code_offset_lo = code_offset; - code_offset_lo_changed = 1; - } - - code_offset_changed = 1; - ln_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: { - U32 offset_delta = 0; - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_length); - cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &offset_delta); - - code_offset += offset_delta; - - if (!code_offset_lo_changed) { - code_offset_lo = code_offset; - code_offset_lo_changed = 1; - } - - code_offset_changed = 1; - code_length_changed = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeColumnEnd: { - AssertAlways(!"TODO: test case"); - // U32 column_end = 0; - // cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &column_end); - }break; + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_parsed->file_off, inlinee_parsed->first_source_ln, parent_voff); + for (;;) { + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if (step.flags == 0) { + break; } - - U64 line_code_offset = code_offset; - - if (code_length_changed) { - // compute upper bound of the range - U64 code_offset_hi = code_offset + code_length; - - // can last code range be extended to cover current sequence too? - if (code_ranges.last != 0 && code_ranges.last->v.max == parent_voff + code_offset_lo) { - code_ranges.last->v.max = parent_voff + code_offset_hi; - } else { - // append range - rng1u64_list_push(arena, &code_ranges, rng_1u64(parent_voff + code_offset_lo, parent_voff + code_offset_hi)); - - // update last code range in file - if (file_last) { - file_last->last_code_range = code_ranges.last->v; - } - } - - // update low offset for next range - code_offset_lo = code_offset_hi; - - // advance code offset - code_offset += code_length; - - // reset state - code_offset_lo_changed = 0; - code_length_changed = 0; - code_length = 0; + if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) { + rng1u64_list_push(scratch.arena, &code_ranges, step.range); } - - if (file_off_changed || (file_first == 0)) { - // append file + if (step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) { + if (code_ranges.last) { + code_ranges.last->v = step.range; + } + } + if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) { struct SourceFile *file = push_array(scratch.arena, struct SourceFile, 1); - file->checksum_off = file_off; + file->checksum_off = step.file_off; SLLQueuePush(file_first, file_last, file); ++file_count; - - // update last code range in file - if (code_ranges.last) { - file->last_code_range = code_ranges.last->v; - } - - // reset state - file_off_changed = 0; } - - if (code_offset_changed && ln_changed) { - if (file_last->line_last == 0 || file_last->line_last->ln != (U64)ln) { - // append line - struct SourceLine *line = push_array(scratch.arena, struct SourceLine, 1); - line->voff = parent_voff + line_code_offset; - line->ln = (U64)ln; - line->cn = (U64)cn; - SLLQueuePush(file_last->line_first, file_last->line_last, line); - ++file_last->line_count; - } - - // reset state - code_offset_changed = 0; - ln_changed = 0; + if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) { + struct SourceLine *line = push_array(scratch.arena, struct SourceLine, 1); + line->voff = step.line_voff; + line->ln = step.ln; + line->cn = step.cn; + SLLQueuePush(file_last->line_first, file_last->line_last, line); + ++file_last->line_count; } } @@ -2209,9 +2044,9 @@ cv_c13_parse_inline_binary_annots(Arena *arena, // fill out result CV_InlineBinaryAnnotsParsed result = {0}; - result.lines_count = file_count; - result.lines = lines; - result.code_ranges = code_ranges; + result.lines_count = file_count; + result.lines = lines; + result.code_ranges = code_ranges; scratch_end(scratch); return result; diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index d1e19ae1..efdd582f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -787,203 +787,58 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } // rjf: build line table, fill with parsed binary annotations - RDIM_LineTable *line_table = 0; + if(inlinee_lines_parsed != 0) { - // rjf: state machine registers - CV_InlineRangeKind range_kind = 0; - U32 code_length = 0; - U32 code_offset = 0; - String8 file_name = inlinee_lines_parsed->file_name; - String8 last_file_name = {0}; - S32 line = (S32)inlinee_lines_parsed->first_source_ln; - S32 column = 1; - S32 last_column = column; - + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; + // rjf: gathered lines typedef struct LineChunk LineChunk; struct LineChunk { LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; - - // rjf: decode loop - B32 line_num_emitted = 0; - B32 code_off_emitted = 0; - B32 code_len_emitted = 0; - U64 read_off = 0; - U64 read_off_opl = binary_annots.size; - for(B32 good = 1; read_off < read_off_opl && good;) + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) { - // rjf: decode next annotation op - U32 op = CV_InlineBinaryAnnotation_Null; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &op); - - // rjf: apply op - switch(op) + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) { - default:{good = 0;}break; - case CV_InlineBinaryAnnotation_Null: - { - good = 0; - }break; - case CV_InlineBinaryAnnotation_CodeOffset: - { - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset); - code_off_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: - { - good = 0; - // TODO(rjf): currently untested/unknown - first guess below: - // - // U32 delta = 0; - // read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta); - // code_offset_base = code_offset; - // code_offset_end = code_offset + delta; - // code_offset += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffset: - { - U32 delta = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta); - code_offset += delta; - code_off_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLength: - { - code_length = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); - code_len_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeFile: - { - U32 new_file_off = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &new_file_off); - String8 new_file_name = {0}; - if(new_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + new_file_off); - U32 name_off = checksum->name_off; - new_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); - } - file_name = new_file_name; - }break; - case CV_InlineBinaryAnnotation_ChangeLineOffset: - { - S32 delta = 0; - read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &delta); - line += delta; - line_num_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeLineEndDelta: - { - good = 0; - // TODO(rjf): currently untested/unknown - first guess below: - // - // S32 end_delta = 1; - // read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &end_delta); - // line += end_delta; - }break; - case CV_InlineBinaryAnnotation_ChangeRangeKind: - { - good = 0; - // TODO(rjf): currently untested/unknown - first guess below: - // - // read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &range_kind); - }break; - case CV_InlineBinaryAnnotation_ChangeColumnStart: - { - good = 0; - // TODO(rjf): currently untested/unknown - first guess below: - // - // S32 delta = 0; - // read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &delta); - // column += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: - { - // TODO(rjf): currently untested/unknown - first guess below: - // - // S32 end_delta = 0; - // read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &end_delta); - // column += end_delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: - { - U32 code_offset_and_line_offset = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset_and_line_offset); - U32 code_delta = (code_offset_and_line_offset & 0xf); - S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); - code_offset += code_delta; - line += line_delta; - code_off_emitted = 1; - line_num_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: - { - U32 offset_delta = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &offset_delta); - code_offset += offset_delta; - code_len_emitted = 1; - code_off_emitted = 1; - }break; - case CV_InlineBinaryAnnotation_ChangeColumnEnd: - { - // TODO(rjf): currently untested/unknown - first guess below: - // - // U32 column_end = 0; - // read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &column_end); - }break; + last_file_off = curr_file_off; + curr_file_off = step.file_off; } - - // rjf: gather new lines - if(!good || (line_num_emitted && code_off_emitted && code_len_emitted)) + if(step.flags == 0 && total_line_chunk_line_count > 0) { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + if((last_file_off != max_U32 && last_file_off != curr_file_off)) + { + String8 seq_file_name = {0}; + + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 256; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); } - chunk->voffs[chunk->count] = base_voff + code_offset; - chunk->voffs[chunk->count+1] = base_voff + code_offset + code_length; - chunk->line_nums[chunk->count] = (U32)line; - chunk->count += 1; - total_line_chunk_line_count += 1; - line_num_emitted = 0; - code_off_emitted = 0; - code_len_emitted = 0; - } - - // rjf: advance code offset by the code length - { - code_offset += code_length; - code_length = 0; - } - - // rjf: push line sequence to line table & source file - if(!good || (op == CV_InlineBinaryAnnotation_ChangeFile && !str8_match(last_file_name, file_name, 0))) - { - String8 seq_file_name = last_file_name; // NOTE(rjf): `file_name` is possibly changed to the next sequence, so use previous // rjf: file name -> normalized file path - String8 file_path = seq_file_name; + String8 file_path = seq_file_name; String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); for(U64 idx = 0; idx < file_path_normalized.size; idx += 1) { @@ -994,9 +849,9 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } // rjf: normalized file path -> source file node - U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); - U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) { if(str8_match(n->src_file->normal_full_path, file_path_normalized, 0)) @@ -1009,23 +864,22 @@ ASYNC_WORK_DEF(p2r_units_convert_work) { src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096); src_file_node->src_file->normal_full_path = push_str8_copy(arena, file_path_normalized); } // rjf: gather all lines - RDI_U64 *voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - RDI_U32 *line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - RDI_U64 line_count = total_line_chunk_line_count; + RDI_U64 *voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + RDI_U32 *line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + RDI_U64 line_count = total_line_chunk_line_count; { U64 dst_idx = 0; for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*chunk->count); + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); dst_idx += chunk->count; } - voffs[dst_idx] = 0xffffffffffffffffull; } // rjf: push @@ -1044,9 +898,32 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; + first_line_chunk = last_line_chunk = 0; total_line_chunk_line_count = 0; } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 256; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + if(step.flags == 0) + { + break; + } } } }break; @@ -2988,98 +2865,30 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) // rjf: parse offset ranges of this inline site - attach to scope { - U32 code_length = 0; - U32 code_offset = 0; - U32 last_code_offset = code_offset; - U32 last_code_length = code_length; - U64 read_off = 0; - U64 read_off_opl = binary_annots.size; - for(B32 good = 1; read_off < read_off_opl && good;) + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); + for(;;) { - // rjf: decode next annotation op - U32 op = CV_InlineBinaryAnnotation_Null; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &op); - - // rjf: apply op - switch(op) + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) { - default:{good = 1;}break; - case CV_InlineBinaryAnnotation_Null: - { - good = 0; - }break; - case CV_InlineBinaryAnnotation_CodeOffset: - { - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset); - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: - { - good = 0; - // TODO(rjf): currently untested/unknown - first guess below: - // - // U32 delta = 0; - // read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta); - // code_offset_base = code_offset; - // code_offset_end = code_offset + delta; - // code_offset += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffset: - { - U32 delta = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta); - code_offset += delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLength: - { - code_length = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); - }break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: - { - U32 code_offset_and_line_offset = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset_and_line_offset); - U32 code_delta = (code_offset_and_line_offset & 0xf); - code_offset += code_delta; - }break; - case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: - { - U32 offset_delta = 0; - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length); - read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &offset_delta); - code_offset += offset_delta; - }break; + // rjf: build new range & add to scope + RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; + rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); } - - // rjf: gather new ranges - if(last_code_length != code_length) + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) { - // rjf: convert current state machine state to [first_voff, opl_voff) range - RDIM_Rng1U64 voff_range = + if(scope->voff_ranges.last != 0) { - procedure_base_voff + code_offset, - procedure_base_voff + code_offset + code_length, - }; - - // rjf: attempt to extend last-added range to cover this range, if possible - if(scope->voff_ranges.last != 0 && scope->voff_ranges.last->v.max == voff_range.min) - { - scope->voff_ranges.last->v.max = voff_range.max; + scope->voff_ranges.last->v.max = step.range.max; } - - // rjf: cannot add to previous range? -> build new range & add to scope - else - { - rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); - } - - // rjf: advance - code_offset += code_length; - code_length = 0; } - - // rjf: update prev/current states - last_code_offset = code_offset; - last_code_length = code_length; + + if(step.flags == 0) + { + break; + } } } }break; From b1c5b308c0a9b37852116da3d54c7efadcc432f0 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 14 Jan 2025 10:42:14 -0800 Subject: [PATCH 20/53] collect inline site name string --- src/lib_rdi_make/rdi_make.c | 9 +++++++ src/lib_rdi_make/rdi_make.h | 2 ++ src/rdi_from_pdb/rdi_from_pdb.c | 48 +++++++++++++++++++++++++++++++++ src/rdi_from_pdb/rdi_from_pdb.h | 17 ++++++++++++ 4 files changed, 76 insertions(+) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index ddfd77e6..3f37b9f5 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1968,6 +1968,15 @@ rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringM } } +RDI_PROC void +rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); + } +} + RDI_PROC void rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count) { diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 0a8e7d9b..47ff5ade 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1471,6 +1471,8 @@ RDI_PROC void rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM RDI_PROC void rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count); + RDI_PROC void rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count); //- rjf: list-granularity bake string gathering passes diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index efdd582f..078740da 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -4052,6 +4052,23 @@ ASYNC_WORK_DEF(p2r_bake_symbols_strings_work) return 0; } +ASYNC_WORK_DEF(p2r_bake_inline_site_strings_work) +{ + ProfBeginFunction(); + Arena *arena = p2r_state->work_thread_arenas[thread_idx]; + P2R_BakeInlineSiteStringsIn *in = input; + p2r_make_string_map_if_needed(); + ProfScope("bake inline site strings"); + { + for(P2R_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + ASYNC_WORK_DEF(p2r_bake_scopes_strings_work) { ProfBeginFunction(); @@ -4518,6 +4535,37 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) } } } + + ProfScope("kick off inline site string map build task") + { + U64 items_per_task = 4096; + U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task); + RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + P2R_BakeInlineSiteStringsIn *in = push_array(scratch.arena, P2R_BakeInlineSiteStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + P2R_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, P2R_BakeInlineSiteStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_inline_site_strings_work, .input = in)); + } + } // rjf: scope chunks ProfScope("kick off scope chunks string map build tasks") diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 7535d450..ced21a66 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -353,6 +353,23 @@ struct P2R_BakeSymbolsStringsIn P2R_BakeSymbolsStringsInNode *last; }; +typedef struct P2R_BakeInlineSiteStringsInNode P2R_BakeInlineSiteStringsInNode; +struct P2R_BakeInlineSiteStringsInNode +{ + P2R_BakeInlineSiteStringsInNode *next; + RDIM_InlineSite *v; + RDI_U64 count; +}; + +typedef struct P2R_BakeInlineSiteStringsIn P2R_BakeInlineSiteStringsIn; +struct P2R_BakeInlineSiteStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + P2R_BakeInlineSiteStringsInNode *first; + P2R_BakeInlineSiteStringsInNode *last; +}; + typedef struct P2R_BakeScopesStringsInNode P2R_BakeScopesStringsInNode; struct P2R_BakeScopesStringsInNode { From b889765c1597d002cfe3c686ce732badfff5923d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 14 Jan 2025 16:49:05 -0800 Subject: [PATCH 21/53] updated PE bin info to handle RDI entry, changed raddump to convert and load RDI from memory, added helper for parsing debug directory --- src/pe/pe.c | 285 +++++++++++++++++++++++++----------------- src/pe/pe.h | 47 ++++++- src/raddump/raddump.c | 264 ++++++++++++++++---------------------- 3 files changed, 321 insertions(+), 275 deletions(-) diff --git a/src/pe/pe.c b/src/pe/pe.c index 630ce5f7..352e775e 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -438,18 +438,18 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read coff header - U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); - COFF_Header coff_header = {0}; + U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_Header coff_header = {0}; if(valid) { str8_deserial_read_struct(data, coff_header_off, &coff_header); } // rjf: range of optional extension header ("optional" for short) - U32 optional_size = coff_header.optional_header_size; - U64 after_coff_header_off = coff_header_off + sizeof(coff_header); - U64 after_optional_header_off = after_coff_header_off + optional_size; - Rng1U64 optional_range = {0}; + U32 optional_size = coff_header.optional_header_size; + U64 after_coff_header_off = coff_header_off + sizeof(coff_header); + U64 after_optional_header_off = after_coff_header_off + optional_size; + Rng1U64 optional_range = {0}; if(valid) { optional_range.min = ClampTop(after_coff_header_off, data.size); @@ -457,11 +457,11 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: get sections - U64 sec_array_off = optional_range.max; - U64 sec_array_raw_opl = sec_array_off + coff_header.section_count*sizeof(COFF_SectionHeader); - U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size); - U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader); - COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off); + U64 sec_array_off = optional_range.max; + U64 sec_array_raw_opl = sec_array_off + coff_header.section_count*sizeof(COFF_SectionHeader); + U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size); + U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader); + COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off); // rjf: get symbols U64 symbol_array_off = coff_header.symbol_table_foff; @@ -471,13 +471,13 @@ pe_bin_info_from_data(Arena *arena, String8 data) U64 string_table_off = symbol_array_off + sizeof(COFF_Symbol16) * symbol_count; // rjf: read optional header - U16 optional_magic = 0; - U64 image_base = 0; - U64 entry_point = 0; - U32 data_dir_count = 0; - U64 virt_section_align = 0; - U64 file_section_align = 0; - Rng1U64 *data_dir_franges = 0; + U16 optional_magic = 0; + U64 image_base = 0; + U64 entry_point = 0; + U32 data_dir_count = 0; + U64 virt_section_align = 0; + U64 file_section_align = 0; + Rng1U64 *data_dir_franges = 0; if(valid && optional_size > 0) { // rjf: read magic number @@ -491,24 +491,36 @@ pe_bin_info_from_data(Arena *arena, String8 data) case PE_PE32_MAGIC: { PE_OptionalHeader32 pe_optional = {0}; - str8_deserial_read_struct(data, optional_range.min, &pe_optional); - image_base = pe_optional.image_base; - entry_point = pe_optional.entry_point_va; - virt_section_align = pe_optional.section_alignment; - file_section_align = pe_optional.file_alignment; - reported_data_dir_offset = sizeof(pe_optional); - reported_data_dir_count = pe_optional.data_dir_count; + if(str8_deserial_read_struct(data, optional_range.min, &pe_optional) == sizeof(pe_optional)) + { + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + } + else + { + Assert(!"unable to read PE Optional Header"); + } }break; case PE_PE32PLUS_MAGIC: { PE_OptionalHeader32Plus pe_optional = {0}; - str8_deserial_read_struct(data, optional_range.min, &pe_optional); - image_base = pe_optional.image_base; - entry_point = pe_optional.entry_point_va; - virt_section_align = pe_optional.section_alignment; - file_section_align = pe_optional.file_alignment; - reported_data_dir_offset = sizeof(pe_optional); - reported_data_dir_count = pe_optional.data_dir_count; + if(str8_deserial_read_struct(data, optional_range.min, &pe_optional) == sizeof(pe_optional)) + { + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + } + else + { + Assert(!"unable to read PE Optional Plus Header"); + } }break; } @@ -520,56 +532,16 @@ pe_bin_info_from_data(Arena *arena, String8 data) data_dir_franges = push_array(arena, Rng1U64, data_dir_count); for(U32 dir_idx = 0; dir_idx < data_dir_count; dir_idx += 1) { - U64 dir_offset = optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*dir_idx; - PE_DataDirectory dir = {0}; - str8_deserial_read_struct(data, dir_offset, &dir); - U64 file_off = coff_foff_from_voff(sections, clamped_sec_count, dir.virt_off); - data_dir_franges[dir_idx] = r1u64(file_off, file_off+dir.virt_size); - } - } - - // rjf: read info about debug file - U32 dbg_time = 0; - U32 dbg_age = 0; - Guid dbg_guid = {0}; - U64 dbg_path_off = 0; - U64 dbg_path_size = 0; - if(valid && PE_DataDirectoryIndex_DEBUG < data_dir_count) - { - // rjf: read debug directory - PE_DebugDirectory dbg_data = {0}; - str8_deserial_read_struct(data, data_dir_franges[PE_DataDirectoryIndex_DEBUG].min, &dbg_data); - - // rjf: extract external file info from codeview header - if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW) - { - U64 cv_offset = dbg_data.foff; - U32 cv_magic = 0; - str8_deserial_read_struct(data, cv_offset, &cv_magic); - switch(cv_magic) + U64 dir_offset = optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*dir_idx; + PE_DataDirectory dir = {0}; + if(str8_deserial_read_struct(data, dir_offset, &dir) == sizeof(dir)) { - default:break; - case PE_CODEVIEW_PDB20_MAGIC: - { - PE_CvHeaderPDB20 cv = {0}; - str8_deserial_read_struct(data, cv_offset, &cv); - dbg_time = cv.time_stamp; - dbg_age = cv.age; - dbg_path_off = cv_offset + sizeof(cv); - }break; - case PE_CODEVIEW_PDB70_MAGIC: - { - PE_CvHeaderPDB70 cv = {0}; - str8_deserial_read_struct(data, cv_offset, &cv); - dbg_guid = cv.guid; - dbg_age = cv.age; - dbg_path_off = cv_offset + sizeof(cv); - }break; + U64 file_off = coff_foff_from_voff(sections, clamped_sec_count, dir.virt_off); + data_dir_franges[dir_idx] = r1u64(file_off, file_off+dir.virt_size); } - if(dbg_path_off > 0) + else { - U8 *dbg_path_cstring_base = data.str+dbg_path_off; - dbg_path_size = cstring8_length(dbg_path_cstring_base); + Assert(!"unable to read data directory"); } } } @@ -581,21 +553,32 @@ pe_bin_info_from_data(Arena *arena, String8 data) Rng1U64 tls_header_frng = data_dir_franges[PE_DataDirectoryIndex_TLS]; switch(coff_header.machine) { - default:{}break; + default:{ NotImplemented; }break; + case COFF_MachineType_UNKNOWN: break; case COFF_MachineType_X86: { PE_TLSHeader32 tls_header32 = {0}; - str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32); - tls_header.raw_data_start = (U64)tls_header32.raw_data_start; - tls_header.raw_data_end = (U64)tls_header32.raw_data_end; - tls_header.index_address = (U64)tls_header32.index_address; - tls_header.callbacks_address = (U64)tls_header32.callbacks_address; - tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; - tls_header.characteristics = (U64)tls_header32.characteristics; + if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32) == sizeof(tls_header32)) + { + tls_header.raw_data_start = (U64)tls_header32.raw_data_start; + tls_header.raw_data_end = (U64)tls_header32.raw_data_end; + tls_header.index_address = (U64)tls_header32.index_address; + tls_header.callbacks_address = (U64)tls_header32.callbacks_address; + tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; + tls_header.characteristics = (U64)tls_header32.characteristics; + } + else + { + Assert(!"unable to read TLS Header 32"); + } }break; case COFF_MachineType_X64: { - str8_deserial_read_struct(data, tls_header_frng.min, &tls_header); + if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header) != sizeof(tls_header)) + { + MemoryZeroStruct(&tls_header); + Assert(!"unable to read TLS Header 64"); + } }break; } } @@ -603,36 +586,110 @@ pe_bin_info_from_data(Arena *arena, String8 data) // rjf: fill info if(valid) { - info.image_base = image_base; - info.entry_point = entry_point; - info.is_pe32 = (optional_magic == PE_PE32_MAGIC); - info.virt_section_align = virt_section_align; - info.file_section_align = file_section_align; - info.section_array_off = sec_array_off; - info.section_count = clamped_sec_count; - info.symbol_array_off = symbol_array_off; - info.symbol_count = symbol_count; - info.string_table_off = string_table_off; - info.dbg_path_off = dbg_path_off; - info.dbg_path_size = dbg_path_size; - info.dbg_guid = dbg_guid; - info.dbg_age = dbg_age; - info.dbg_time = dbg_time; - info.data_dir_franges = data_dir_franges; - info.data_dir_count = data_dir_count; - switch(coff_header.machine) - { - default:{}break; - case COFF_MachineType_X86: {info.arch = Arch_x86;}break; - case COFF_MachineType_X64: {info.arch = Arch_x64;}break; - case COFF_MachineType_ARM: {info.arch = Arch_arm32;}break; - case COFF_MachineType_ARM64: {info.arch = Arch_arm64;}break; - } - MemoryCopyStruct(&info.tls_header, &tls_header); + info.image_base = image_base; + info.entry_point = entry_point; + info.is_pe32 = (optional_magic == PE_PE32_MAGIC); + info.virt_section_align = virt_section_align; + info.file_section_align = file_section_align; + info.section_array_off = sec_array_off; + info.section_count = clamped_sec_count; + info.symbol_array_off = symbol_array_off; + info.symbol_count = symbol_count; + info.string_table_off = string_table_off; + info.data_dir_franges = data_dir_franges; + info.data_dir_count = data_dir_count; + info.arch = arch_from_coff_machine(coff_header.machine); + info.tls_header = tls_header; } + return info; } +internal PE_DebugInfoList +pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir) +{ + PE_DebugInfoList result = {0}; + + PE_DebugDirectory *debug_entry = str8_deserial_get_raw_ptr(raw_debug_dir, 0, sizeof(*debug_entry)); + PE_DebugDirectory *debug_entry_opl = debug_entry + raw_debug_dir.size/sizeof(*debug_entry_opl); + for (PE_DebugDirectory *entry = debug_entry; entry < debug_entry_opl; ++entry) { + switch (entry->type) { + default: { + PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1); + n->v.header = *entry; + n->v.u.raw_data = str8_substr(raw_image, rng_1u64(entry->foff, entry->foff + entry->size)); + + SLLQueuePush(result.first, result.last, n); + ++result.count; + } break; + case PE_DebugDirectoryType_CODEVIEW: { + U32 cv_magic = 0; + str8_deserial_read_struct(raw_image, entry->foff, &cv_magic); + + switch (cv_magic) { + case PE_CODEVIEW_PDB20_MAGIC: { + PE_CvHeaderPDB20 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv); + if (cv_read_size == sizeof(cv)) { + String8 path = {0}; + str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path); + + PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1); + n->v.header = *entry; + n->v.u.codeview.pdb20.header = cv; + n->v.u.codeview.pdb20.path = path; + + SLLQueuePush(result.first, result.last, n); + ++result.count; + } else { + Assert(!"unable to read PE_CvHeaderPDB20"); + } + } break; + case PE_CODEVIEW_PDB70_MAGIC: { + PE_CvHeaderPDB70 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv); + if (cv_read_size == sizeof(cv)) { + String8 path = {0}; + str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path); + + PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1); + n->v.header = *entry; + n->v.u.codeview.pdb70.header = cv; + n->v.u.codeview.pdb70.path = path; + + SLLQueuePush(result.first, result.last, n); + ++result.count; + } else { + Assert(!"unable to read PE_CvHeaderPDB70"); + } + } break; + case PE_CODEVIEW_RDI_MAGIC: { + PE_CvHeaderRDI cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv); + if (cv_read_size == sizeof(cv)) { + String8 path = {0}; + str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path); + + PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1); + n->v.header = *entry; + n->v.u.codeview.rdi.header = cv; + n->v.u.codeview.rdi.path = path; + + SLLQueuePush(result.first, result.last, n); + ++result.count; + } else { + Assert(!"unable to read PE_CvHeaderRDI"); + } + } break; + default: break; + } + } break; + } + } + + return result; +} + //////////////////////////////// //~ rjf: Helpers diff --git a/src/pe/pe.h b/src/pe/pe.h index 5df0890b..c6e40254 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -1003,17 +1003,53 @@ struct PE_BinInfo U64 symbol_array_off; U64 symbol_count; U64 string_table_off; - U64 dbg_path_off; - U64 dbg_path_size; - Guid dbg_guid; - U32 dbg_age; - U32 dbg_time; Arch arch; Rng1U64 *data_dir_franges; U32 data_dir_count; PE_TLSHeader64 tls_header; }; +typedef struct PE_DebugInfo +{ + PE_DebugDirectory header; + union + { + union + { + U32 magic; + struct + { + PE_CvHeaderPDB20 header; + String8 path; + } pdb20; + struct + { + PE_CvHeaderPDB70 header; + String8 path; + } pdb70; + struct + { + PE_CvHeaderRDI header; + String8 path; + } rdi; + } codeview; + String8 raw_data; + } u; +} PE_DebugInfo; + +typedef struct PE_DebugInfoNode +{ + struct PE_DebugInfoNode *next; + PE_DebugInfo v; +} PE_DebugInfoNode; + +typedef struct PE_DebugInfoList +{ + PE_DebugInfoNode *first; + PE_DebugInfoNode *last; + U64 count; +} PE_DebugInfoList; + //////////////////////////////// //~ rjf: Basic Enum Functions @@ -1038,6 +1074,7 @@ internal String8 pe_string_from_dll_characteristics(Arena *arena, PE_DllCharacte internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data); +internal PE_DebugInfoList pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir); internal PE_ParsedStaticImportTable pe_static_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range); internal PE_ParsedDelayImportTable pe_delay_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range); internal PE_ParsedExportTable pe_exports_from_data(Arena *arena, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range, Rng1U64 dir_virt_range); diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 189fcc48..9da15187 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -42,8 +42,8 @@ rd_stderr(char *fmt, ...) scratch_end(scratch); } -internal B32 -rd_invoke_rdi_converter(String8 exe_name, String8 exe_data, String8 pdb_path, String8 out_path) +internal String8 +rd_invoke_rdi_converter(Arena *arena, String8 exe_name, String8 exe_data, String8 pdb_path) { Temp scratch = scratch_begin(0,0); @@ -52,17 +52,17 @@ rd_invoke_rdi_converter(String8 exe_name, String8 exe_data, String8 pdb_path, St user2convert.input_pdb_data = os_data_from_file_path(scratch.arena, pdb_path); user2convert.input_exe_name = exe_name; user2convert.input_exe_data = exe_data; - user2convert.output_name = out_path; + user2convert.output_name = str8_zero(); user2convert.flags = P2R_ConvertFlag_All; - P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert); - P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake); - RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); - String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle); - B32 is_rdi_write_ok = os_write_data_list_to_file_path(user2convert.output_name, rdi_blobs); + P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert); + P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake); + RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); + String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle); + String8 raw_rdi = str8_list_join(arena, &rdi_blobs, 0); scratch_end(scratch); - return is_rdi_write_ok; + return raw_rdi; } internal RDI_Parsed * @@ -71,110 +71,72 @@ rd_rdi_from_pe(Arena *arena, String8 data_path, String8 raw_data) Temp scratch = scratch_begin(&arena, 1); RDI_Parsed *rdi = 0; - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data); - // PDB 2.0 - COFF_TimeStamp pdb20_time_stamp = 0; - U32 pdb20_age = 0; - String8 pdb20_path = str8_zero(); - // PDB 7.0 - U32 pdb70_age = 0; - Guid pdb70_guid = {0}; - String8 pdb70_path = str8_zero(); - // RDI - String8 rdi_path = str8_zero(); - Guid rdi_guid = {0}; - if (PE_DataDirectoryIndex_DEBUG < pe.data_dir_count) { - String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); - PE_DebugDirectory *debug_entry = str8_deserial_get_raw_ptr(raw_debug_dir, 0, sizeof(*debug_entry)); - PE_DebugDirectory *debug_entry_opl = debug_entry + raw_debug_dir.size/sizeof(*debug_entry_opl); - for (PE_DebugDirectory *debug_entry_ptr = debug_entry; debug_entry_ptr < debug_entry_opl; ++debug_entry_ptr) { - if (debug_entry_ptr->type == PE_DebugDirectoryType_CODEVIEW) { - U32 cv_magic = 0; - str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv_magic); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data); + String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); + PE_DebugInfoList dbg_list = pe_parse_debug_directory(scratch.arena, raw_data, raw_debug_dir); - switch (cv_magic) { - case PE_CODEVIEW_PDB20_MAGIC: { - PE_CvHeaderPDB20 cv = {0}; - U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); - if (cv_read_size == sizeof(cv)) { - pdb20_time_stamp = cv.time_stamp; - pdb20_age = cv.age; - str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb20_path); - } else { - rd_errorf("unable to read PE_CvHeaderPDB20"); - } - } break; - case PE_CODEVIEW_PDB70_MAGIC: { - PE_CvHeaderPDB70 cv = {0}; - U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); - if (cv_read_size == sizeof(cv)) { - pdb70_age = cv.age; - pdb70_guid = cv.guid; - str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb70_path); - } else { - rd_errorf("unable to read PE_CvHeaderPDB70"); - } - } break; - case PE_CODEVIEW_RDI_MAGIC: { - PE_CvHeaderRDI cv = {0}; - U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); - if (cv_read_size == sizeof(cv)) { - rdi_guid = cv.guid; - str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &rdi_path); - } else { - rd_errorf("unable to read PE_CvHeaderRDI"); - } - } break; - default: break; + String8 raw_rdi = {0}; + Guid rdi_guid = {0}; + for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) { + PE_DebugInfo *v = &n->v; + if (v->header.type == PE_DebugDirectoryType_CODEVIEW) { + if (v->u.codeview.magic == PE_CODEVIEW_RDI_MAGIC) { + if (raw_rdi.size) { + rd_warningf("multiple RDI paths defined in %S"); + } else { + raw_rdi = os_data_from_file_path(arena, v->u.codeview.rdi.path); + rdi_guid = v->u.codeview.rdi.header.guid; + if (raw_rdi.size == 0) { + rd_errorf("unable to open RDI: %S", v->u.codeview.rdi.path); + } } } } } - // convert debug info to RDI - if (!rdi_path.size && (pdb20_path.size || pdb70_path.size)) { - if (pdb20_path.size && pdb70_path.size) { - rd_warningf("multiple PDB paths defined %S, %S (picking first)", pdb70_path, pdb20_path); + if (!raw_rdi.size) { + String8 pdb_path = str8_zero(); + Guid pdb_guid = {0}; + B32 convert_pdb = 0; + for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) { + PE_DebugInfo *v = &n->v; + if (v->header.type == PE_DebugDirectoryType_CODEVIEW) { + pdb_path = v->u.codeview.pdb70.path; + pdb_guid = v->u.codeview.pdb70.header.guid; + convert_pdb = 1; + break; + } } - String8 pdb_path = pdb70_path.size ? pdb70_path : pdb20_path; - String8 out_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(pdb_path)); - B32 is_rdi_ok = rd_invoke_rdi_converter(data_path, raw_data, pdb_path, out_path); - if (is_rdi_ok) { - rdi_path = out_path; - } else { - rd_errorf("unable write RDI to %S", out_path); + + if (convert_pdb) { + raw_rdi = rd_invoke_rdi_converter(scratch.arena, data_path, raw_data, pdb_path); } } - if (rdi_path.size) { - String8 raw_rdi = os_data_from_file_path(arena, rdi_path); - if (raw_rdi.size > 0) { - rdi = push_array(arena, RDI_Parsed, 1); + if (raw_rdi.size) { + rdi = push_array(arena, RDI_Parsed, 1); - // TODO: check guid - RDI_ParseStatus parse_status = rdi_parse(raw_rdi.str, raw_rdi.size, rdi); + // TODO: check guid + RDI_ParseStatus parse_status = rdi_parse(raw_rdi.str, raw_rdi.size, rdi); - String8 parse_status_string = str8_zero(); - if (parse_status == RDI_ParseStatus_Good) { - } else if (parse_status == RDI_ParseStatus_HeaderDoesNotMatch) { - parse_status_string = str8_lit("Header does not match"); - } else if (parse_status == RDI_ParseStatus_UnsupportedVersionNumber) { - parse_status_string = str8_lit("Unsupported version number"); - } else if (parse_status == RDI_ParseStatus_InvalidDataSecionLayout) { - parse_status_string = str8_lit("Invalid data section layout"); - } else if (parse_status == RDI_ParseStatus_MissingRequiredSection) { - parse_status_string = str8_lit("Missing required section"); - } else { - parse_status_string = push_str8f(scratch.arena, "unknown parse status code: %u", parse_status); - } - - if (parse_status_string.size) { - rdi = 0; - rd_errorf("RDI parse status(%u): %S", parse_status, parse_status_string); - } + String8 parse_status_string = str8_zero(); + if (parse_status == RDI_ParseStatus_Good) { + } else if (parse_status == RDI_ParseStatus_HeaderDoesNotMatch) { + parse_status_string = str8_lit("Header does not match"); + } else if (parse_status == RDI_ParseStatus_UnsupportedVersionNumber) { + parse_status_string = str8_lit("Unsupported version number"); + } else if (parse_status == RDI_ParseStatus_InvalidDataSecionLayout) { + parse_status_string = str8_lit("Invalid data section layout"); + } else if (parse_status == RDI_ParseStatus_MissingRequiredSection) { + parse_status_string = str8_lit("Missing required section"); } else { - rd_errorf("unable to open RDI: %S", rdi_path); + parse_status_string = push_str8f(scratch.arena, "unknown parse status code: %u", parse_status); + } + + if (parse_status_string.size) { + rdi = 0; + rd_errorf("RDI parse status(%u): %S", parse_status, parse_status_string); } } @@ -5657,41 +5619,34 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 { Temp scratch = scratch_begin(&arena, 1); - rd_printf("# Debug"); + rd_printf("# Debug Directory"); rd_indent(); - U64 entry_count = raw_dir.size / sizeof(PE_DebugDirectory); - PE_DebugDirectory *entries = str8_deserial_get_raw_ptr(raw_dir, 0, sizeof(*entries)*entry_count); - for (U64 i = 0; i < entry_count; ++i) { - PE_DebugDirectory *de = entries+i; - if (i > 0) { - rd_newline(); - } - rd_printf("Entry[%u]", i); - rd_indent(); + PE_DebugInfoList debug_info_list = pe_parse_debug_directory(scratch.arena, raw_data, raw_dir); + U64 i = 0; + for (PE_DebugInfoNode *entry = debug_info_list.first; entry != 0; entry = entry->next, ++i) { + PE_DebugInfo *de = &entry->v; - { - String8 time_stamp = coff_string_from_time_stamp(scratch.arena, de->time_stamp); - String8 type = pe_string_from_debug_directory_type(de->type); - - rd_printf("Characteristics: %#x", de->characteristics); - rd_printf("Time Stamp: %S", time_stamp); - rd_printf("Version: %u.%u", de->major_ver, de->minor_ver); - rd_printf("Type: %S", type); - rd_printf("Size: %u", de->size); - rd_printf("Data virt off: %#x", de->voff); - rd_printf("Data file off: %#x", de->foff); + if (entry != debug_info_list.first) { rd_newline(); } - String8 raw_entry = str8_substr(raw_data, rng_1u64(de->foff, de->foff+de->size)); - if (raw_entry.size != de->size) { - rd_errorf("unable to read debug entry @ %#x", de->foff); - break; - } - + rd_printf("Entry[%llu]", i); rd_indent(); - switch (de->type) { + + // print header + rd_printf("Characteristics: %#x", de->header.characteristics); + rd_printf("Time Stamp: %S", coff_string_from_time_stamp(scratch.arena, de->header.time_stamp)); + rd_printf("Version: %u.%u", de->header.major_ver, de->header.minor_ver); + rd_printf("Type: %S", pe_string_from_debug_directory_type(de->header.type)); + rd_printf("Size: %u", de->header.size); + rd_printf("Data virt off: %#x", de->header.voff); + rd_printf("Data file off: %#x", de->header.foff); + rd_newline(); + + // print directory contents + rd_indent(); + switch (de->header.type) { case PE_DebugDirectoryType_ILTCG: case PE_DebugDirectoryType_MPX: case PE_DebugDirectoryType_EXCEPTION: @@ -5709,30 +5664,30 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 // TODO: is this version? U32 unknown = 0; - off += str8_deserial_read_struct(raw_entry, off, &unknown); + off += str8_deserial_read_struct(de->u.raw_data, off, &unknown); if (unknown != 0) { rd_printf("TODO: unknown: %u", unknown); } rd_printf("%-8s %-8s %-8s", "VOFF", "Size", "Name"); - for (; off < raw_entry.size; ) { + for (; off < de->u.raw_data.size; ) { U32 voff = 0; U32 size = 0; String8 name = str8_zero(); - off += str8_deserial_read_struct(raw_entry, off, &voff); - off += str8_deserial_read_struct(raw_entry, off, &size); + off += str8_deserial_read_struct(de->u.raw_data, off, &voff); + off += str8_deserial_read_struct(de->u.raw_data, off, &size); if (voff == 0 && size == 0) { break; } - off += str8_deserial_read_cstr(raw_entry, off, &name); + off += str8_deserial_read_cstr(de->u.raw_data, off, &name); off = AlignPow2(off, 4); rd_printf("%08x %08x %S", voff, size, name); } } break; case PE_DebugDirectoryType_VC_FEATURE: { - MSCRT_VCFeatures *feat = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*feat)); + MSCRT_VCFeatures *feat = str8_deserial_get_raw_ptr(de->u.raw_data, 0, sizeof(*feat)); if (feat) { rd_printf("Pre-VC++ 11.0: %u", feat->pre_vcpp); rd_printf("C/C++: %u", feat->c_cpp); @@ -5744,7 +5699,7 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 } } break; case PE_DebugDirectoryType_FPO: { - PE_DebugFPO *fpo = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*fpo)); + PE_DebugFPO *fpo = str8_deserial_get_raw_ptr(de->u.raw_data, 0, sizeof(*fpo)); if (fpo) { U8 prolog_size = PE_FPOEncoded_Extract_PROLOG_SIZE(fpo->flags); U8 saved_regs_size = PE_FPOEncoded_Extract_SAVED_REGS_SIZE(fpo->flags); @@ -5766,38 +5721,35 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 rd_errorf("not enough bytes to read FPO"); } } break; - case PE_DebugDirectoryType_CODEVIEW: { - U32 magic = 0; - str8_deserial_read_struct(raw_entry, 0, &magic); - switch (magic) { + switch (de->u.codeview.magic) { case PE_CODEVIEW_PDB20_MAGIC: { - PE_CvHeaderPDB20 *cv20 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv20)); - String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv20), &name); + PE_CvHeaderPDB20 *header = &de->u.codeview.pdb20.header; - String8 time_stamp = coff_string_from_time_stamp(scratch.arena, cv20->time_stamp); - - rd_printf("Time stamp: %S", time_stamp); - rd_printf("Age: %u", cv20->age); - rd_printf("Name: %S", name); + rd_printf("Time stamp: %S", coff_string_from_time_stamp(scratch.arena, header->time_stamp)); + rd_printf("Age: %u", header->age); + rd_printf("Name: %S", de->u.codeview.pdb20.path); } break; case PE_CODEVIEW_PDB70_MAGIC: { - PE_CvHeaderPDB70 *cv70 = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*cv70)); - String8 name; str8_deserial_read_cstr(raw_entry, sizeof(*cv70), &name); - - String8 guid = string_from_guid(scratch.arena, cv70->guid); + PE_CvHeaderPDB70 *header = &de->u.codeview.pdb70.header; - rd_printf("GUID: %S", guid); - rd_printf("Age: %u", cv70->age); - rd_printf("Name: %S", name); + rd_printf("GUID: %S", string_from_guid(scratch.arena, header->guid)); + rd_printf("Age: %u", header->age); + rd_printf("Name: %S", de->u.codeview.pdb70.path); + } break; + case PE_CODEVIEW_RDI_MAGIC: { + PE_CvHeaderRDI *header = &de->u.codeview.rdi.header; + + rd_printf("GUID: %S", string_from_guid(scratch.arena, header->guid)); + rd_printf("Name: %S", de->u.codeview.rdi.path); } break; default: { - rd_errorf("unknown CodeView magic %#x", magic); + rd_errorf("unknown CodeView magic %#x", de->u.codeview.magic); } break; } } break; case PE_DebugDirectoryType_MISC: { - PE_DebugMisc *misc = str8_deserial_get_raw_ptr(raw_entry, 0, sizeof(*misc)); + PE_DebugMisc *misc = str8_deserial_get_raw_ptr(de->u.raw_data, 0, sizeof(*misc)); String8 type_string = pe_string_from_misc_type(misc->data_type); @@ -5808,7 +5760,7 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 switch (misc->data_type) { case PE_DebugMiscType_EXE_NAME: { String8 name; - str8_deserial_read_cstr(raw_entry, sizeof(*misc), &name); + str8_deserial_read_cstr(de->u.raw_data, sizeof(*misc), &name); rd_printf("Name: %S", name); } break; default: { @@ -5818,12 +5770,12 @@ pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 } break; } rd_unindent(); - rd_unindent(); } rd_unindent(); rd_newline(); + scratch_end(scratch); } From 25f924b075bf3750ae929303ca1cc10bb61daf56 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 14 Jan 2025 16:49:23 -0800 Subject: [PATCH 22/53] generate markers from RDI --- src/raddump/raddump.c | 117 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 9da15187..943a3881 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -255,13 +255,107 @@ rd_marker_is_before(void *a, void *b) return u64_is_before(&((RD_Marker*)a)->off, &((RD_Marker*)b)->off); } +internal int +rd_range_min_is_before(void *raw_a, void *raw_b) +{ + Rng1U64 *a = raw_a; + Rng1U64 *b = raw_b; + return a->min < b->min; +} + +internal U64 +rd_range_bsearch(Rng1U64 *ranges, U64 count, U64 x) +{ + if (count > 0 && ranges[0].min <= x && x < ranges[count - 1].min) { + U64 first = 0; + U64 opl = count; + for (;;) { + U64 mid = (first + opl)/2; + if (ranges[mid].min < x) { + first = mid; + } else if (ranges[mid].min > x) { + opl = mid; + } else { + first = mid; + break; + } + if (opl - first <= 1) { + break; + } + } + return first; + } + return max_U64; +} + +internal RD_MarkerArray * +rd_section_markers_from_rdi(Arena *arena, RDI_Parsed *rdi) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 sect_count = 0; + RDI_BinarySection *sect_lo = rdi_table_from_name(rdi, BinarySections, §_count); + + Rng1U64 *sect_vranges = push_array(scratch.arena, Rng1U64, sect_count); + for (U64 i = 0; i < sect_count; ++i) { + sect_vranges[i].min = sect_lo[i].voff_first; + sect_vranges[i].max = i; + } + radsort(sect_vranges, sect_count, rd_range_min_is_before); + + U64 proc_count = 0; + RDI_Procedure *proc_lo = rdi_table_from_name(rdi, Procedures, &proc_count); + + RD_MarkerList *markers = push_array(scratch.arena, RD_MarkerList, sect_count); + for (U64 i = 0; i < proc_count; ++i) { + RDI_Procedure *proc = proc_lo + i; + U64 proc_voff_lo = rdi_first_voff_from_procedure(rdi, proc); + U64 proc_voff_hi = rdi_opl_voff_from_procedure(rdi, proc); + + U64 sect_range_idx = rd_range_bsearch(sect_vranges, sect_count, proc_voff_lo); + if (sect_range_idx < sect_count) { + Rng1U64 sect_range = sect_vranges[sect_range_idx]; + U64 sect_idx = sect_range.max; + + String8 name = str8_zero(); + name.str = rdi_name_from_procedure(rdi, proc, &name.size); + + RD_MarkerNode *n = push_array(scratch.arena, RD_MarkerNode, 1); + n->v.off = proc_voff_lo - sect_range.min; + n->v.string = name; + + RD_MarkerList *list = &markers[sect_idx]; + SLLQueuePush(list->first, list->last, n); + ++list->count; + } + } + + // lists -> arrays + RD_MarkerArray *result = push_array(arena, RD_MarkerArray, sect_count); + for (U64 i = 0; i < sect_count; ++i) { + result[i].count = 0; + result[i].v = push_array(arena, RD_Marker, markers[i].count); + for (RD_MarkerNode *n = markers[i].first; n != 0; n = n->next) { + result[i].v[result[i].count++] = n->v; + } + } + + // sort arrays + for (U64 i = 0; i < sect_count; ++i) { + radsort(result[i].v, result[i].count, rd_marker_is_before); + } + + scratch_end(scratch); + return result; +} + internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols) { Temp scratch = scratch_begin(&arena, 1); // extract markers from symbol table - RD_MarkerList *markers = push_array(scratch.arena, RD_MarkerList, section_count); + RD_MarkerList *markers = push_array(scratch.arena, RD_MarkerList, section_count+1); for (U64 symbol_idx = 0; symbol_idx < symbols.count; ++symbol_idx) { COFF_Symbol32 *symbol = &symbols.v[symbol_idx]; @@ -277,7 +371,7 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st n->v.off = symbol->value; n->v.string = name; - RD_MarkerList *list = &markers[symbol->section_number-1]; + RD_MarkerList *list = &markers[symbol->section_number]; SLLQueuePush(list->first, list->last, n); ++list->count; } @@ -4709,14 +4803,15 @@ coff_disasm_sections(Arena *arena, for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { COFF_SectionHeader *sect = sections+sect_idx; if (sect->flags & COFF_SectionFlag_CNT_CODE) { - U64 sect_off = is_obj ? sect->foff : sect->voff; - U64 sect_size = is_obj ? sect->fsize : sect->vsize; - String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); - RD_MarkerArray markers = section_markers[sect_idx]; + U64 sect_off = is_obj ? sect->foff : sect->voff; + U64 sect_size = is_obj ? sect->fsize : sect->vsize; + String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); + U64 sect_number = sect_idx+1; + RD_MarkerArray markers = section_markers[sect_number]; - rd_printf("# Disassembly [Section No. %#llx]", (sect_idx+1)); + rd_printf("# Disassembly [Section No. %#llx]", sect_number); rd_indent(); - rd_print_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); + rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code); rd_unindent(); } } @@ -6796,7 +6891,11 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op RD_MarkerArray *section_markers = 0; if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) { - section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, symbols); + if (rdi) { + section_markers = rd_section_markers_from_rdi(scratch.arena, rdi); + } else { + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, symbols); + } } if (opts & RD_Option_Rawdata) { From 1f8433096a3171024de763efa4db0d9d482c288a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 15 Jan 2025 10:25:16 -0800 Subject: [PATCH 23/53] COFF parser fixes --- src/coff/coff.c | 75 +++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/coff/coff.c b/src/coff/coff.c index 0e29f25b..6257e3fc 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -953,9 +953,9 @@ coff_parse_archive_member_header(String8 data, U64 offset, B32 is_regular_archiv size = str8_skip_chop_whitespace(size); header_out->name = name; - header_out->time_stamp = s32_from_str8(date, 10); - header_out->user_id = s32_from_str8(user_id, 10); - header_out->group_id = s32_from_str8(group_id, 10); + header_out->time_stamp = u32_from_str8(date, 10); + header_out->user_id = u32_from_str8(user_id, 10); + header_out->group_id = u32_from_str8(group_id, 10); header_out->mode = mode; header_out->is_end_correct = str8_match(end, end_magic, 0); header_out->data_range = rng_1u64(cursor, cursor + u32_from_str8(size, 10)); @@ -1028,41 +1028,42 @@ coff_parse_first_archive_member(COFF_ArchiveMember *member) internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member) { - Assert(str8_match(member->header.name, str8_lit("/"), 0)); - - U64 cursor = 0; - - U32 member_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &member_count); - - Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); - cursor += dim_1u64(member_offsets_range); - - U32 symbol_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); - - Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); - cursor += dim_1u64(symbol_indices_range); - - Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - - String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); - String8 raw_indices = str8_substr(member->data, symbol_indices_range); - - U32 *member_offsets = (U32 *)raw_member_offsets.str; - U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); - - U16 *symbol_indices = (U16 *)raw_indices.str; - U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); - COFF_ArchiveSecondMember result = {0}; - result.member_count = member_count; - result.symbol_count = symbol_count; - result.member_offsets = member_offsets; - result.member_offset_count = member_offset_count; - result.symbol_indices = symbol_indices; - result.symbol_index_count = symbol_index_count; - result.string_table = str8_substr(member->data, string_table_range); + + if (str8_match(member->header.name, str8_lit("/"), 0)) { + U64 cursor = 0; + + U32 member_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &member_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); + cursor += dim_1u64(symbol_indices_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); + String8 raw_indices = str8_substr(member->data, symbol_indices_range); + + U32 *member_offsets = (U32 *)raw_member_offsets.str; + U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); + + U16 *symbol_indices = (U16 *)raw_indices.str; + U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); + + result.member_count = member_count; + result.symbol_count = symbol_count; + result.member_offsets = member_offsets; + result.member_offset_count = member_offset_count; + result.symbol_indices = symbol_indices; + result.symbol_index_count = symbol_index_count; + result.string_table = str8_substr(member->data, string_table_range); + } return result; } From 1d6ee734091d764fe0857132e25a45e95616348b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 15 Jan 2025 10:37:47 -0800 Subject: [PATCH 24/53] handle zero sized array --- src/raddump/raddump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 943a3881..4600b54f 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -532,7 +532,7 @@ rd_print_disasm(Arena *arena, internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size) { - U64 buf_max = size * 8; + U64 buf_max = 32 + size * 8; char *buf = push_array(arena, char, buf_max); U64 buf_size = 0; From 190eb03ff3271a60d522888fef690905ce0cfbfd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 15 Jan 2025 14:03:40 -0800 Subject: [PATCH 25/53] removed default lib directive parser, moved directive code to obj file, getting ready to deprecate LNK_Directive struct --- src/coff/coff.c | 2 + src/coff/coff.h | 3 +- src/linker/lnk.c | 14 ++- src/linker/lnk_config.c | 94 ++++++++++++++++- src/linker/lnk_config.h | 48 ++++++++- src/linker/lnk_directive.c | 194 ---------------------------------- src/linker/lnk_directive.h | 71 ------------- src/linker/lnk_error.h | 1 + src/linker/lnk_obj.c | 211 +++++++++++++++++++++++++++---------- src/linker/lnk_obj.h | 25 ++++- 10 files changed, 332 insertions(+), 331 deletions(-) delete mode 100644 src/linker/lnk_directive.c delete mode 100644 src/linker/lnk_directive.h diff --git a/src/coff/coff.c b/src/coff/coff.c index 6257e3fc..34c97aab 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -99,6 +99,7 @@ coff_header_info_from_data(String8 data) COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str; info.type = COFF_DataType_BIG_OBJ; info.machine = big_header->machine; + info.header_size = sizeof(COFF_HeaderBigObj); info.section_array_off = sizeof(COFF_HeaderBigObj); info.section_count_no_null = big_header->section_count; info.string_table_off = big_header->symbol_table_foff + sizeof(COFF_Symbol32) * big_header->symbol_count; @@ -109,6 +110,7 @@ coff_header_info_from_data(String8 data) COFF_Header *header = (COFF_Header*)data.str; info.type = COFF_DataType_OBJ; info.machine = header->machine; + info.header_size = sizeof(COFF_Header); info.section_array_off = sizeof(COFF_Header); info.section_count_no_null = header->section_count; info.string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16) * header->symbol_count; diff --git a/src/coff/coff.h b/src/coff/coff.h index ccf905bb..b1251b9c 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -634,8 +634,9 @@ typedef U32 COFF_DataType; typedef struct COFF_HeaderInfo { - COFF_MachineType machine; COFF_DataType type; + COFF_MachineType machine; + U64 header_size; U64 section_array_off; U64 section_count_no_null; U64 string_table_off; diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1f80d3a2..e6a3d845 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -115,7 +115,6 @@ #include "lnk_config.h" #include "lnk_chunk.h" #include "lnk_reloc.h" -#include "lnk_directive.h" #include "lnk_symbol_table.h" #include "lnk_section_table.h" #include "lnk_obj.h" @@ -133,7 +132,6 @@ #include "lnk_config.c" #include "lnk_chunk.c" #include "lnk_reloc.c" -#include "lnk_directive.c" #include "lnk_symbol_table.c" #include "lnk_section_table.c" #include "lnk_obj.c" @@ -3553,6 +3551,8 @@ lnk_run(int argc, char **argv) // derive machine from obj if (config->machine == COFF_MachineType_UNKNOWN) { config->machine = obj->machine; + } else if (config->machine != COFF_MachineType_X64) { + lnk_error_with_loc(LNK_Error_UnsupportedMachine, obj->path, obj->lib_path, "%S machine is supported", coff_string_from_machine_type(obj->machine)); } else { // is obj machine compatible? if (config->machine != obj->machine && @@ -3901,8 +3901,16 @@ lnk_run(int argc, char **argv) } break; case State_BuildExportTable: { ProfBegin("Build Export Table"); - + + // push exports from command line + for (LNK_ExportParse *exp_parse = config->export_symbol_list.first; exp_parse != 0; exp_parse = exp_parse->next) { + lnk_export_table_push_export(exptab, symtab, exp_parse); + } + + // push exports from obj directives lnk_collect_exports_from_obj_directives(exptab, obj_list, symtab); + + // build export table section lnk_build_edata(exptab, st, symtab, config->image_name, config->machine); ProfEnd(); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index eb754b40..72c7ed4c 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -43,7 +43,7 @@ read_only struct { LNK_CmdSwitch_NotImplemented, "EMITVOLATILEMETADATA", "", "" }, { LNK_CmdSwitch_Entry, "ENTRY", ":FUNCTION", "" }, { LNK_CmdSwitch_Null, "ERRORREPORT", "", "Deprecated starting Windows Vista." }, - { LNK_CmdSwitch_NotImplemented, "EXPORT", ":SYMBOL", "" }, + { LNK_CmdSwitch_Export, "EXPORT", ":SYMBOL", "" }, { LNK_CmdSwitch_NotImplemented, "EXPORTADMIN", "", "" }, { LNK_CmdSwitch_FastFail, "FASTFAIL", "", "Not used." }, { LNK_CmdSwitch_NotImplemented, "FASTGENPROFILE", "", "" }, @@ -773,6 +773,13 @@ lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_pat //////////////////////////////// +internal void +lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat) +{ + str8_list_concat_in_place(&list->from_list, &to_concat->from_list); + str8_list_concat_in_place(&list->to_list, &to_concat->to_list); +} + internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out) { @@ -800,6 +807,86 @@ lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameLis return 0; } +internal LNK_ExportParse * +lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + LNK_ExportParse *parse = 0; + + // parse directive + String8 name = str8_zero(); + String8 alias = str8_zero(); + String8 type = coff_string_from_import_header_type(COFF_ImportHeaderType_CODE); + if (value_list.node_count > 0) { + String8List dir_split = str8_split_by_string_chars(scratch.arena, value_list.first->string, str8_lit("="), 0); + B32 is_export_valid = value_list.node_count <= 2 && value_list.node_count > 0; + if (is_export_valid) { + if (dir_split.node_count > 0) { + name = dir_split.last->string; + } + if (dir_split.node_count == 2) { + alias = dir_split.first->string; + } + if (value_list.node_count == 2) { + type = value_list.last->string; + } + } + } + + // prase error check + if (name.size == 0) { + String8 dir = str8_list_join(scratch.arena, &value_list, 0); + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "invalid export directive \"%S\"", dir); + goto exit; + } + + parse = push_array_no_zero(arena, LNK_ExportParse, 1); + parse->next = 0; + parse->name = name; + parse->alias = alias; + parse->type = type; + + SLLQueuePush(list->first, list->last, parse); + ++list->count; + +exit:; + + scratch_end(scratch); + ProfEnd(); + return parse; +} + +internal LNK_MergeDirectiveNode * +lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data) +{ + LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1); + node->data = data; + node->next = 0; + + SLLQueuePush(list->first, list->last, node); + ++list->count; + + return node; +} + +internal B32 +lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out) +{ + Temp scratch = scratch_begin(0, 0); + B32 is_parse_ok = 0; + + String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("="), 0); + if (list.node_count == 2) { + out->src = list.first->string; + out->dst = list.last->string; + is_parse_ok = 1; + } + + scratch_end(scratch); + return is_parse_ok; +} + //////////////////////////////// internal void @@ -1028,6 +1115,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam config->entry_point_name = new_entry_point_name; } break; + case LNK_CmdSwitch_Export: { + String8List value_strings_copy = str8_list_copy(arena, &value_strings); + lnk_parse_export_directive(arena, &config->export_symbol_list, value_strings_copy, obj_path, lib_path); + } break; + case LNK_CmdSwitch_FastFail: { // do nothing } break; diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 54783f7b..595eca07 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -7,7 +7,6 @@ typedef enum { LNK_CmdSwitch_Null, LNK_CmdSwitch_NotImplemented, - LNK_CmdSwitch_Deprecated, LNK_CmdSwitch_Align, LNK_CmdSwitch_AllowBind, @@ -22,6 +21,7 @@ typedef enum LNK_CmdSwitch_Dll, LNK_CmdSwitch_DynamicBase, LNK_CmdSwitch_Entry, + LNK_CmdSwitch_Export, LNK_CmdSwitch_FastFail, LNK_CmdSwitch_FileAlign, LNK_CmdSwitch_Fixed, @@ -77,7 +77,6 @@ typedef enum LNK_CmdSwitch_EditAndContinue, LNK_CmdSwitch_EmitVolatileMetadata, LNK_CmdSwitch_ErrorReport, - LNK_CmdSwitch_Export, LNK_CmdSwitch_ExportAdmin, LNK_CmdSwitch_FastGenProfile, LNK_CmdSwitch_FailIfMismatch, @@ -227,6 +226,42 @@ typedef struct LNK_AltNameList String8List to_list; } LNK_AltNameList; +typedef struct LNK_ExportParse +{ + struct LNK_ExportParse *next; + String8 name; + String8 alias; + String8 type; +} LNK_ExportParse; + +typedef struct LNK_ExportParseList +{ + U64 count; + LNK_ExportParse *first; + LNK_ExportParse *last; +} LNK_ExportParseList; + +typedef struct LNK_MergeDirective +{ + String8 src; + String8 dst; +} LNK_MergeDirective; + +typedef struct LNK_MergeDirectiveNode +{ + struct LNK_MergeDirectiveNode *next; + LNK_MergeDirective data; +} LNK_MergeDirectiveNode; + +typedef struct LNK_MergeDirectiveList +{ + U64 count; + LNK_MergeDirectiveNode *first; + LNK_MergeDirectiveNode *last; +} LNK_MergeDirectiveList; + + + typedef enum { LNK_DebugInfoGuid_Null, @@ -301,6 +336,7 @@ typedef struct LNK_Config LNK_TypeNameHashMode pdb_hash_type_names; String8 pdb_hash_type_name_map; U64 pdb_hash_type_name_length; + LNK_ExportParseList export_symbol_list; String8List input_list[LNK_Input_Count]; String8List input_default_lib_list; String8List disallow_lib_list; @@ -506,9 +542,17 @@ internal void lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK internal B32 lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); +//////////////////////////////// + +internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat); internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out); internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out); +internal LNK_ExportParse * lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path); + +internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data); +internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out); + //////////////////////////////// internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, String8 obj_path, String8 lib_path); diff --git a/src/linker/lnk_directive.c b/src/linker/lnk_directive.c deleted file mode 100644 index c3107942..00000000 --- a/src/linker/lnk_directive.c +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal void -lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat) -{ - str8_list_concat_in_place(&list->from_list, &to_concat->from_list); - str8_list_concat_in_place(&list->to_list, &to_concat->to_list); -} - -internal LNK_MergeDirectiveNode * -lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data) -{ - LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1); - node->data = data; - node->next = 0; - - SLLQueuePush(list->first, list->last, node); - ++list->count; - - return node; -} - -//////////////////////////////// - -internal B32 -lnk_is_directive_legal(LNK_CmdSwitchType type) -{ - static B32 init_table = 1; - static B8 is_legal[LNK_CmdSwitch_Count]; - if (init_table) { - init_table = 0; - is_legal[LNK_CmdSwitch_AlternateName] = 1; - is_legal[LNK_CmdSwitch_DefaultLib] = 1; - is_legal[LNK_CmdSwitch_DisallowLib] = 1; - is_legal[LNK_CmdSwitch_EditAndContinue] = 1; - is_legal[LNK_CmdSwitch_Entry] = 1; - is_legal[LNK_CmdSwitch_Export] = 1; - is_legal[LNK_CmdSwitch_FailIfMismatch] = 1; - is_legal[LNK_CmdSwitch_GuardSym] = 1; - is_legal[LNK_CmdSwitch_Include] = 1; - is_legal[LNK_CmdSwitch_InferAsanLibs] = 1; - is_legal[LNK_CmdSwitch_InferAsanLibsNo] = 1; - is_legal[LNK_CmdSwitch_ManifestDependency] = 1; - is_legal[LNK_CmdSwitch_Merge] = 1; - is_legal[LNK_CmdSwitch_NoDefaultLib] = 1; - is_legal[LNK_CmdSwitch_Release] = 1; - is_legal[LNK_CmdSwitch_Section] = 1; - is_legal[LNK_CmdSwitch_Stack] = 1; - is_legal[LNK_CmdSwitch_SubSystem] = 1; - is_legal[LNK_CmdSwitch_ThrowingNew] = 1; - } - return is_legal[type]; -} - -internal void -lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 to_parse; - { - local_persist const U8 bom_sig[] = { 0xEF, 0xBB, 0xBF }; - local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; - if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { - to_parse = str8_zero(); - lnk_not_implemented("TODO: support for BOM encoding"); - } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { - to_parse = str8_skip(buffer, sizeof(ascii_sig)); - } else { - to_parse = buffer; - } - } - - String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, to_parse); - LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list); - - for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) { - LNK_CmdSwitchType type = lnk_cmd_switch_type_from_string(opt->string); - - if (type == LNK_CmdSwitch_Null) { - lnk_error(LNK_Warning_UnknownDirective, "%S: unknown directive \"%S\"", obj_path, opt->string); - continue; - } - if (!lnk_is_directive_legal(type)) { - lnk_error(LNK_Warning_IllegalDirective, "%S: illegal directive \"%S\"", obj_path, opt->string); - continue; - } - - LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1); - directive->next = 0; - directive->id = push_str8_copy(arena, opt->string); - directive->value_list = str8_list_copy(arena, &opt->value_strings); - - LNK_DirectiveList *directive_list = &directive_info->v[type]; - SLLQueuePush(directive_list->first, directive_list->last, directive); - ++directive_list->count; - } - - scratch_end(scratch); -} - -internal String8List -lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list) -{ - ProfBeginFunction(); - String8List default_libs = {0}; - - for (LNK_Directive *dir = dir_list->first; dir != 0; dir = dir->next) { - for (String8Node *i = dir->value_list.first; i != 0; i = i->next) { - String8 lib_path = i->string; - - // is there lib extension? - String8 ext = str8_skip_last_dot(lib_path); - if (ext.size == lib_path.size) { // TODO: fix string_extension_from_path, if there is no extension it should return zero - lib_path = push_str8f(arena, "%S.lib", lib_path); - } else { - lib_path = push_str8_copy(arena, lib_path); - } - - str8_list_push(arena, &default_libs, lib_path); - } - } - - ProfEnd(); - return default_libs; -} - -internal LNK_ExportParse * -lnk_parse_export_direcive(Arena *arena, LNK_ExportParseList *list, String8List value_list, LNK_Obj *obj) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - LNK_ExportParse *parse = 0; - - // parse directive - String8 name = str8(0,0); - String8 alias = str8(0,0); - String8 type = coff_string_from_import_header_type(COFF_ImportHeaderType_CODE); - if (value_list.node_count > 0) { - String8List dir_split = str8_split_by_string_chars(scratch.arena, value_list.first->string, str8_lit("="), 0); - B32 is_export_valid = value_list.node_count <= 2 && value_list.node_count > 0; - if (is_export_valid) { - if (dir_split.node_count > 0) { - name = dir_split.last->string; - } - if (dir_split.node_count == 2) { - alias = dir_split.first->string; - } - if (value_list.node_count == 2) { - type = value_list.last->string; - } - } - } - - // prase error check - if (name.size == 0) { - String8 dir = str8_list_join(scratch.arena, &value_list, 0); - lnk_error_obj(LNK_Error_IllData, obj, "invalid export directive \"%S\"", dir); - goto exit; - } - - parse = push_array_no_zero(arena, LNK_ExportParse, 1); - parse->next = 0; - parse->name = name; - parse->alias = alias; - parse->type = type; - - SLLQueuePush(list->first, list->last, parse); - ++list->count; - -exit:; - scratch_end(scratch); - ProfEnd(); - return parse; -} - -internal B32 -lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out) -{ - Temp scratch = scratch_begin(0, 0); - B32 is_parse_ok = 0; - - String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("="), 0); - if (list.node_count == 2) { - out->src = list.first->string; - out->dst = list.last->string; - is_parse_ok = 1; - } - - scratch_end(scratch); - return is_parse_ok; -} - diff --git a/src/linker/lnk_directive.h b/src/linker/lnk_directive.h deleted file mode 100644 index 64f9e0d2..00000000 --- a/src/linker/lnk_directive.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#pragma once - -typedef struct LNK_Directive -{ - struct LNK_Directive *next; - String8 id; - String8List value_list; -} LNK_Directive; - -typedef struct LNK_DirectiveList -{ - U64 count; - LNK_Directive *first; - LNK_Directive *last; -} LNK_DirectiveList; - -typedef struct LNK_ExportParse -{ - struct LNK_ExportParse *next; - String8 name; - String8 alias; - String8 type; -} LNK_ExportParse; - -typedef struct LNK_ExportParseList -{ - U64 count; - LNK_ExportParse *first; - LNK_ExportParse *last; -} LNK_ExportParseList; - -typedef struct LNK_MergeDirective -{ - String8 src; - String8 dst; -} LNK_MergeDirective; - -typedef struct LNK_MergeDirectiveNode -{ - struct LNK_MergeDirectiveNode *next; - LNK_MergeDirective data; -} LNK_MergeDirectiveNode; - -typedef struct LNK_MergeDirectiveList -{ - U64 count; - LNK_MergeDirectiveNode *first; - LNK_MergeDirectiveNode *last; -} LNK_MergeDirectiveList; - -typedef struct LNK_DirectiveInfo -{ - LNK_DirectiveList v[LNK_CmdSwitch_Count]; -} LNK_DirectiveInfo; - -//////////////////////////////// - -internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat); - -internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data); - -//////////////////////////////// - -internal void lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path); -internal String8List lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list); -internal B32 lnk_parse_merge_directive(String8 directive, LNK_MergeDirective *out); - - diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 65cdf96b..2f3cd415 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -80,6 +80,7 @@ typedef enum LNK_Warning_LongSectionName, LNK_Warning_UnknownSwitch, LNK_Warning_TLSAlign, + LNK_Warning_DirectiveSectionWithRelocs, LNK_Warning_Last, LNK_Error_Count diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 2fb22216..03265995 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -219,9 +219,10 @@ THREAD_POOL_TASK_FUNC(lnk_default_lib_collector) Rng1U64 range = task->range_arr[task_id]; String8List *result = &task->out_arr[task_id]; for (U64 obj_idx = range.min; obj_idx < range.max; obj_idx += 1) { - LNK_Obj *obj = &task->in_arr.v[obj_idx].data; - String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_CmdSwitch_DefaultLib]); - str8_list_concat_in_place(result, &list); + LNK_Obj *obj = &task->in_arr.v[obj_idx].data; + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_DefaultLib].first; dir != 0; dir = dir->next) { + str8_list_concat_in_place(result, &dir->value_list); + } } } @@ -322,19 +323,26 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) LNK_ObjNode *obj_node = task->obj_node_arr + task_id; LNK_Obj *obj = &obj_node->data; - // cache path, we need it for error reports and debug stuff String8 cached_path = push_str8_copy(arena, input->path); String8 cached_lib_path = push_str8_copy(arena, input->lib_path); // parse coff obj - COFF_HeaderInfo coff_info = coff_header_info_from_data(input->data); - COFF_SectionHeader *coff_sect_arr = (COFF_SectionHeader *)(input->data.str + coff_info.section_array_off); - void *coff_symbols = input->data.str + coff_info.symbol_off; + COFF_HeaderInfo coff_info = coff_header_info_from_data(input->data); + Rng1U64 coff_file_header_range = rng_1u64(0, coff_info.header_size); + Rng1U64 coff_sect_arr_range = rng_1u64(coff_info.section_array_off, coff_info.section_array_off + coff_info.section_count_no_null * sizeof(COFF_SectionHeader)); + Rng1U64 coff_symbols_range = rng_1u64(coff_info.symbol_off, coff_info.symbol_off + coff_info.symbol_count * coff_info.symbol_size); + String8 raw_coff_sect_arr = str8_substr(input->data, coff_sect_arr_range); + String8 raw_coff_symbols = str8_substr(input->data, coff_symbols_range); - // handle machines we dont support - if (coff_info.machine != COFF_MachineType_UNKNOWN && coff_info.machine != COFF_MachineType_X64) { - lnk_error(LNK_Error_UnsupportedMachine, "%S: %S machine is supported", input->path, coff_string_from_machine_type(coff_info.machine)); + if (raw_coff_sect_arr.size != dim_1u64(coff_sect_arr_range)) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read section header table"); } + if (raw_coff_symbols.size != dim_1u64(coff_symbols_range)) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read symbol table"); + } + + COFF_SectionHeader *coff_sect_arr = (COFF_SectionHeader *)raw_coff_sect_arr.str; + void *coff_symbols = raw_coff_symbols.str; // :function_pad_min U64 function_pad_min; @@ -344,30 +352,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) function_pad_min = lnk_get_default_function_pad_min(coff_info.machine); } - U64 chunk_count = 0; - chunk_count += coff_info.section_count_no_null; - chunk_count += 1; // :common_block + U64 chunk_count = 1; // :common_block + chunk_count += coff_info.section_count_no_null; - String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); - String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); + String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); + String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); LNK_Chunk *chunk_arr = push_array_no_zero(arena, LNK_Chunk, chunk_count); - // init section name and postfix array - for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { - COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx]; - - // read name - String8 sect_name = coff_name_from_section_header(coff_sect, input->data, coff_info.string_table_off); - - // parse section name - String8 name, postfix; - coff_parse_section_name(sect_name, &name, &postfix); - - // fill out - sect_name_arr[sect_idx] = name; - sect_sort_arr[sect_idx] = postfix; - } - // :common_block U64 common_block_idx = chunk_count - 1; sect_name_arr[common_block_idx] = str8_lit(".bss"); @@ -376,11 +367,38 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx]; + // read name + String8 sect_name = coff_name_from_section_header(coff_sect, input->data, coff_info.string_table_off); + + // parse section name + coff_parse_section_name(sect_name, §_name_arr[sect_idx], §_sort_arr[sect_idx]); + String8 data; if (coff_sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { data = str8(0, coff_sect->fsize); } else { - data = str8(input->data.str + coff_sect->foff, coff_sect->fsize); + if (coff_sect->fsize > 0) { + Rng1U64 range = rng_1u64(coff_sect->foff, coff_sect->foff + coff_sect->fsize); + data = str8_substr(input->data, range); + + if (contains_1u64(coff_file_header_range, coff_sect->foff) || + (coff_sect->fsize > 0 && contains_1u64(coff_file_header_range, coff_sect->foff + coff_sect->fsize-1))) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1); + } + if (contains_1u64(coff_sect_arr_range, coff_sect->foff) || + (coff_sect->fsize > 0 && contains_1u64(coff_sect_arr_range, coff_sect->foff + coff_sect->fsize-1))) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into section header table)", sect_name, sect_idx+1); + } + if (contains_1u64(coff_symbols_range, coff_sect->foff) || + (coff_sect->fsize > 0 && contains_1u64(coff_symbols_range, coff_sect->foff + coff_sect->fsize-1))) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into symbol table)", sect_name, sect_idx+1); + } + if (dim_1u64(range) != coff_sect->fsize) { + lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data", sect_name, sect_idx+1); + } + } else { + data = str8_zero(); + } } LNK_Chunk *chunk = &chunk_arr[sect_idx]; @@ -418,10 +436,11 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // convert from coff - B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); - LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); - LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); + B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); + LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); + LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); + LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); // fill out obj obj->data = input->data; @@ -436,12 +455,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) obj->chunk_arr = chunk_ptr_arr; obj->symbol_list = symbol_list; obj->sect_reloc_list_arr = reloc_list_arr; - obj->directive_info = lnk_init_directives(arena, cached_path, coff_info.section_count_no_null, sect_name_arr, chunk_arr); + obj->directive_info = directive_info; // parse exports LNK_ExportParseList export_parse = {0}; for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) { - lnk_parse_export_direcive(arena, &obj->export_parse, dir->value_list, obj); + lnk_parse_export_directive(arena, &obj->export_parse, dir->value_list, obj->path, obj->lib_path); } // push /export symbols @@ -1029,30 +1048,108 @@ lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 c return reloc_list_arr; } +internal void +lnk_parse_msvc_linker_directive(Arena *arena, String8 obj_path, String8 lib_path, LNK_DirectiveInfo *directive_info, String8 buffer) +{ + Temp scratch = scratch_begin(&arena, 1); + + local_persist B32 init_table = 1; + local_persist B8 is_legal[LNK_CmdSwitch_Count]; + if (init_table) { + init_table = 0; + is_legal[LNK_CmdSwitch_AlternateName] = 1; + is_legal[LNK_CmdSwitch_DefaultLib] = 1; + is_legal[LNK_CmdSwitch_DisallowLib] = 1; + is_legal[LNK_CmdSwitch_EditAndContinue] = 1; + is_legal[LNK_CmdSwitch_Entry] = 1; + is_legal[LNK_CmdSwitch_Export] = 1; + is_legal[LNK_CmdSwitch_FailIfMismatch] = 1; + is_legal[LNK_CmdSwitch_GuardSym] = 1; + is_legal[LNK_CmdSwitch_Include] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibs] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibsNo] = 1; + is_legal[LNK_CmdSwitch_ManifestDependency] = 1; + is_legal[LNK_CmdSwitch_Merge] = 1; + is_legal[LNK_CmdSwitch_NoDefaultLib] = 1; + is_legal[LNK_CmdSwitch_Release] = 1; + is_legal[LNK_CmdSwitch_Section] = 1; + is_legal[LNK_CmdSwitch_Stack] = 1; + is_legal[LNK_CmdSwitch_SubSystem] = 1; + is_legal[LNK_CmdSwitch_ThrowingNew] = 1; + } + + String8 to_parse; + { + local_persist const U8 bom_sig[] = { 0xEF, 0xBB, 0xBF }; + local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; + if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { + to_parse = str8_zero(); + lnk_error_with_loc(LNK_InternalError_NotImplemented, obj_path, lib_path, "TODO: support for BOM encoding"); + } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { + to_parse = str8_skip(buffer, sizeof(ascii_sig)); + } else { + to_parse = buffer; + } + } + + String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, to_parse); + LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list); + + for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) { + LNK_CmdSwitchType type = lnk_cmd_switch_type_from_string(opt->string); + + if (type == LNK_CmdSwitch_Null) { + lnk_error_with_loc(LNK_Warning_UnknownDirective, obj_path, lib_path, "unknown directive \"%S\"", opt->string); + continue; + } + if (!is_legal[type]) { + lnk_error_with_loc(LNK_Warning_IllegalDirective, obj_path, lib_path, "illegal directive \"%S\"", opt->string); + continue; + } + + LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1); + directive->next = 0; + directive->id = push_str8_copy(arena, opt->string); + directive->value_list = str8_list_copy(arena, &opt->value_strings); + + LNK_DirectiveList *directive_list = &directive_info->v[type]; + SLLQueuePush(directive_list->first, directive_list->last, directive); + ++directive_list->count; + } + + scratch_end(scratch); +} + internal LNK_DirectiveInfo -lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr) +lnk_directive_info_from_sections(Arena *arena, + String8 obj_path, + String8 lib_path, + U64 chunk_count, + LNK_RelocList *reloc_list_arr, + String8 *sect_name_arr, + LNK_Chunk *chunk_arr) { LNK_DirectiveInfo directive_info = {0}; - for (U64 chunk_idx = 0; chunk_idx < chunk_count; chunk_idx += 1) { + for (U64 chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { String8 sect_name = sect_name_arr[chunk_idx]; - LNK_Chunk *sect_chunk = &chunk_arr[chunk_idx]; - Assert(sect_chunk->type == LNK_Chunk_Leaf); - - if (!str8_match(sect_name, str8_lit(".drectve"), 0)) { - continue; + LNK_Chunk *sect_chunk = chunk_arr + chunk_idx; + if (str8_match(sect_name, str8_lit(".drectve"), 0)) { + if (sect_chunk->type == LNK_Chunk_Leaf) { + if (sect_chunk->u.leaf.size >= 3) { + if (~sect_chunk->flags & COFF_SectionFlag_LNK_INFO) { + lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "%S missing COFF_SectionFlag_LNK_INFO", sect_name); + } + if (reloc_list_arr[chunk_idx].count > 0) { + lnk_error_with_loc(LNK_Warning_DirectiveSectionWithRelocs, obj_path, lib_path, "directive section %S(%#x) has relocations", sect_name, (chunk_idx+1)); + } + lnk_parse_msvc_linker_directive(arena, obj_path, lib_path, &directive_info, sect_chunk->u.leaf); + } else { + lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "unable to parse %S", sect_name); + } + } else { + Assert(!"linker directive section chunk must be of leaf type"); + } } - if (sect_chunk->u.leaf.size < 3) { - lnk_error(LNK_Warning_IllData, "%S: can't parse %S", obj_path, sect_name); - continue; - } - if (~sect_chunk->flags & COFF_SectionFlag_LNK_INFO) { - lnk_error(LNK_Warning_IllData, "%S: %S missing COFF_SectionFlag_LNK_INFO.", obj_path, sect_name); - } - - // TODO: warn if section has relocations - - lnk_parse_directives(arena, &directive_info, sect_chunk->u.leaf, obj_path); - int bad_vs = 0; (void)bad_vs; } return directive_info; } diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index ce316b0e..fa821460 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -25,6 +25,27 @@ typedef struct LNK_InputObjList //////////////////////////////// +typedef struct LNK_Directive +{ + struct LNK_Directive *next; + String8 id; + String8List value_list; +} LNK_Directive; + +typedef struct LNK_DirectiveList +{ + U64 count; + LNK_Directive *first; + LNK_Directive *last; +} LNK_DirectiveList; + +typedef struct LNK_DirectiveInfo +{ + LNK_DirectiveList v[LNK_CmdSwitch_Count]; +} LNK_DirectiveInfo; + +//////////////////////////////// + #define LNK_MakeChunkInputIdx(obj_idx, sect_idx) (((U64)(obj_idx) << 32) | (U64)((sect_idx) & max_U32)) typedef struct LNK_Obj @@ -181,10 +202,10 @@ internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs); internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr); -internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block); +internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block); internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count); internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array); -internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr); +internal LNK_DirectiveInfo lnk_directive_info_from_sections(Arena *arena, String8 obj_path, String8 lib_path, U64 chunk_count, LNK_RelocList *reloc_list_arr, String8 *sect_name_arr, LNK_Chunk *chunk_arr); internal U32 lnk_obj_get_features(LNK_Obj *obj); internal U32 lnk_obj_get_comp_id(LNK_Obj *obj); From c000817b9a50ed611e1a394eb67f758513511fee Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 16 Jan 2025 13:43:19 -0800 Subject: [PATCH 26/53] pass over COFF symbol parser --- src/coff/coff.c | 64 ++++++++++++++++++++++++++++++++++++------------- src/coff/coff.h | 14 +++++++++++ 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/coff/coff.c b/src/coff/coff.c index 34c97aab..140dfea8 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -310,6 +310,38 @@ coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolNam return name_str; } +internal COFF_ParsedSymbol +coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32) +{ + COFF_ParsedSymbol result = {0}; + result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name); + result.value = sym32->value; + result.section_number = sym32->section_number; + result.type = sym32->type; + result.storage_class = sym32->storage_class; + result.aux_symbol_count = sym32->aux_symbol_count; + return result; +} + +internal COFF_ParsedSymbol +coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16) +{ + COFF_ParsedSymbol result = {0}; + result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name); + result.value = sym16->value; + if (sym16->section_number == COFF_SYMBOL_DEBUG_SECTION_16) { + result.section_number = COFF_SYMBOL_DEBUG_SECTION; + } else if (sym16->section_number == COFF_SYMBOL_ABS_SECTION_16) { + result.section_number = COFF_SYMBOL_ABS_SECTION; + } else { + result.section_number = (U32)sym16->section_number; + } + result.type = sym16->type; + result.storage_class = sym16->storage_class; + result.aux_symbol_count = sym16->aux_symbol_count; + return result; +} + internal void coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16) { @@ -328,30 +360,30 @@ coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16) } internal COFF_Symbol32Array -coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count) +coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count) { - COFF_Symbol32Array result; - result.count = symbol_count; - result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8); + COFF_Symbol32Array result = {0}; + result.count = symbol_count; + result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8); - COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)(data.str + symbol_array_off); - for (U64 isymbol = 0; isymbol < symbol_count; isymbol += 1) { - // read header symbol + Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count); + String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range); + COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str; + + for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) { COFF_Symbol16 *sym16 = &sym16_arr[isymbol]; - - // convert to 32bit COFF_Symbol32 *sym32 = &result.v[isymbol]; + coff_symbol32_from_coff_symbol16(sym32, sym16); - if (isymbol + 1 + sym16->aux_symbol_count > symbol_count) { - Assert(!"aux symbols out of bounds"); - } - // copy aux symbols - for (U64 iaux = 0; iaux < sym16->aux_symbol_count; iaux += 1) { - COFF_Symbol16 *aux16 = sym16 + iaux + 1; - COFF_Symbol32 *aux32 = sym32 + iaux + 1; // 32bit COFF uses 16bit aux symbols + for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) { + COFF_Symbol16 *aux16 = sym16_arr + iaux; + COFF_Symbol32 *aux32 = result.v + iaux; + + // 32bit COFF uses 16bit aux symbols MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16)); + MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16)); } // take into account aux symbols diff --git a/src/coff/coff.h b/src/coff/coff.h index b1251b9c..6ec8c8f6 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -779,6 +779,18 @@ typedef struct COFF_SectionHeaderArray COFF_SectionHeader *v; } COFF_SectionHeaderArray; +//////////////////////////////// + +typedef struct COFF_ParsedSymbol +{ + String8 name; + U32 value; + U32 section_number; + COFF_SymbolType type; + COFF_SymStorageClass storage_class; + U8 aux_symbol_count; +} COFF_ParsedSymbol; + //////////////////////////////// //~ rjf: Globals @@ -815,6 +827,8 @@ internal String8 coff_name_from_section_header(COFF_SectionHeader *h internal void coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out); internal String8 coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name); +internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32); +internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16); internal void coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16); internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); From b405ed4873ac59023e244f819bec7cc3e42796db Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 16 Jan 2025 13:46:47 -0800 Subject: [PATCH 27/53] factored out logic for splitting function chunks into separate pass over symbol table; associations are now assigned to sub chunks too; inherit function chunk align from parent chunk --- src/linker/lnk.c | 18 +- src/linker/lnk_chunk.c | 13 +- src/linker/lnk_chunk.h | 2 +- src/linker/lnk_obj.c | 468 +++++++++++++++---------------- src/linker/lnk_reloc.c | 4 +- src/linker/lnk_section_table.c | 2 +- src/linker/pdb_ext/pdb_builder.c | 2 +- 7 files changed, 258 insertions(+), 251 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e6a3d845..f094c978 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -39,6 +39,7 @@ #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" +#include "codeview/codeview_enum.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -51,6 +52,7 @@ #include "coff/coff_enum.c" #include "pe/pe.c" #include "codeview/codeview.c" +#include "codeview/codeview_enum.c" #include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" @@ -1824,11 +1826,20 @@ lnk_base_reloc_page_is_before(void *raw_a, void *raw_b) return a->voff < b->voff; } +int +lnk_base_reloc_page_compar(const void *raw_a, const void *raw_b) +{ + const LNK_BaseRelocPage *a = raw_a; + const LNK_BaseRelocPage *b = raw_b; + return u64_compar(&a->voff, &b->voff); +} + internal void lnk_base_reloc_page_array_sort(LNK_BaseRelocPageArray arr) { ProfBeginFunction(); - radsort(arr.v, arr.count, lnk_base_reloc_page_is_before); + //radsort(arr.v, arr.count, lnk_base_reloc_page_is_before); + qsort(arr.v, arr.count, sizeof(arr.v[0]), lnk_base_reloc_page_compar); ProfEnd(); } @@ -1927,7 +1938,7 @@ lnk_build_base_relocs(TP_Context *tp, ProfBegin("Page List -> Array"); LNK_BaseRelocPageArray page_arr = lnk_base_reloc_page_array_from_list(base_reloc_sect->arena, *main_page_list); ProfEnd(); - + ProfBegin("Sort Pages on VOFF"); lnk_base_reloc_page_array_sort(page_arr); ProfEnd(); @@ -3634,7 +3645,7 @@ lnk_run(int argc, char **argv) } for (U64 input_source = 0; input_source < ArrayCount(input_libs); ++input_source) { - ProfBeginV("Source %S", lnk_string_from_input_source(input_source)); + ProfBeginV("Input Source %S", lnk_string_from_input_source(input_source)); Temp temp = temp_begin(scratch.arena); LNK_InputLibList input_lib_list = input_libs[input_source]; @@ -3716,6 +3727,7 @@ lnk_run(int argc, char **argv) } temp_end(temp); + ProfEnd(); } // reset input libs diff --git a/src/linker/lnk_chunk.c b/src/linker/lnk_chunk.c index b1f99fb3..c35e4b73 100644 --- a/src/linker/lnk_chunk.c +++ b/src/linker/lnk_chunk.c @@ -302,13 +302,20 @@ lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_C return src_node; } +internal +LNK_CHUNK_VISITOR_SIG(lnk_set_associate_on_chunks) +{ + chunk->associate = (LNK_Chunk *)ud; + return 0; +} + internal void -lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *chunk) +lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *chunk) { // for simplicity we don't support multiple associations, // but it's possible to craft symbol table with multiple associations - Assert(!chunk->associate); - chunk->associate = head; + AssertAlways(!chunk->associate); + lnk_visit_chunks(0, chunk, lnk_set_associate_on_chunks, head); } internal B32 diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index e8313b98..0b64d968 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -175,7 +175,7 @@ internal LNK_Chunk * lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager * internal LNK_Chunk * lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index); internal LNK_ChunkNode * lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk); internal LNK_ChunkNode * lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max); -internal void lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *associate); +internal void lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *associate); internal B32 lnk_chunk_is_discarded(LNK_Chunk *chunk); internal U64 lnk_chunk_get_size(LNK_Chunk *chunk); internal U64 lnk_chunk_list_get_node_count(LNK_Chunk *chunk); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 03265995..c018b5ab 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -357,7 +357,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); - LNK_Chunk *chunk_arr = push_array_no_zero(arena, LNK_Chunk, chunk_count); + LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, chunk_count); // :common_block U64 common_block_idx = chunk_count - 1; @@ -402,16 +402,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } LNK_Chunk *chunk = &chunk_arr[sect_idx]; - chunk->ref = lnk_chunk_ref(0,0); // :chunk_ref_assign chunk->align = coff_align_size_from_section_flags(coff_sect->flags); - chunk->min_size = 0; chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LNK_REMOVE); chunk->sort_chunk = 1; chunk->type = LNK_Chunk_Leaf; chunk->sort_idx = sect_sort_arr[sect_idx]; chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx); chunk->flags = coff_sect->flags; - chunk->associate = 0; chunk->u.leaf = data; lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx); } @@ -437,7 +434,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // convert from coff B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); @@ -740,9 +737,10 @@ lnk_obj_list_push_parallel(TP_Context *tp, internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, - String8 coff_data, + String8 raw_coff, LNK_Obj *obj, String8 obj_path, + String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, @@ -753,282 +751,270 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block) { - LNK_SymbolArray symbol_array; - symbol_array.count = coff_symbol_count; - symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); - - for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; ++symbol_idx) { - String8 name; - U32 section_number; - U32 value; - COFF_SymStorageClass storage_class; - COFF_SymbolType type; - U64 aux_symbol_count; - void *aux_symbols; + if (function_pad_min) { + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + // read symbol + if (is_big_obj) { + symbol = coff_parse_symbol32(raw_coff, string_table_off, &((COFF_Symbol32 *)coff_symbols)[symbol_idx]); + } else { + symbol = coff_parse_symbol16(raw_coff, string_table_off, &((COFF_Symbol16 *)coff_symbols)[symbol_idx]); + } + + // is this a function symbol? + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_REGULAR && COFF_SymbolType_IsFunc(symbol.type)) { + if (symbol.section_number == 0 || symbol.section_number > sect_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number); + } + if (symbol.value > coff_sect_arr[symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value); + } + + LNK_Chunk *chunk = chunk_ptr_arr[symbol.section_number-1]; + if (symbol.value > 0) { + // convert leaf to list + // + // there is no way to know up front how many splits we have, + // so lazily convert chunks when see two or more functions + // in a section + if (chunk->type == LNK_Chunk_Leaf) { + // make a list chunk + LNK_Chunk *chunk_list = push_array(arena, LNK_Chunk, 1); + chunk_list->type = LNK_Chunk_List; + chunk_list->align = chunk->align; + chunk_list->is_discarded = chunk->is_discarded; + chunk_list->sort_idx = chunk->sort_idx; + chunk_list->input_idx = chunk->input_idx; + chunk_list->flags = chunk->flags; + chunk_list->u.list = push_array(arena, LNK_ChunkList, 1); + lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, symbol.name); + + // update properties on first chunk + chunk->min_size = function_pad_min; + chunk->sort_chunk = 0; + chunk->sort_idx = str8_zero(); + chunk->input_idx = 0; + + // push leaf to list + lnk_chunk_list_push(arena, chunk_list->u.list, chunk); + + // set list as target chunk + chunk = chunk_list; + + // set list chunk to be head of this section + chunk_ptr_arr[symbol.section_number-1] = chunk_list; + } + + // find chunk that is near symbol + U64 offset_cursor = 0; + LNK_ChunkNode *current = chunk->u.list->last; + for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { + Assert(c->data->type == LNK_Chunk_Leaf); + if (offset_cursor + c->data->u.leaf.size >= symbol.value) { + current = c; + break; + } + offset_cursor += c->data->u.leaf.size; + } + Assert(current->data->type == LNK_Chunk_Leaf); + + if (offset_cursor < symbol.value) { + // bifurcate chunk at symbol offset + U64 split_pos = symbol.value - offset_cursor; + Rng1U64 left_data_range = rng_1u64(0, split_pos); + Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size); + String8 left_data = str8_substr(current->data->u.leaf, left_data_range); + String8 right_data = str8_substr(current->data->u.leaf, right_data_range); + + // create new chunk + LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1); + split_chunk->type = LNK_Chunk_Leaf; + split_chunk->align = current->data->align; + split_chunk->min_size = function_pad_min; + split_chunk->is_discarded = current->data->is_discarded; + split_chunk->flags = current->data->flags; + split_chunk->u.leaf = right_data; + lnk_chunk_set_debugf(arena, split_chunk, "%S: chunk split on function %S SECT%x SPLIT_POS %#llx", obj_path, symbol.name, symbol.section_number, split_pos); + + LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1); + split_node->data = split_chunk; + + // update split chunk data + current->data->u.leaf = left_data; + + // insert split chunk after current chunk + if (split_node->next == 0) { + chunk->u.list->last = split_node; + } + split_node->next = current->next; + current->next = split_node; + chunk->u.list->count += 1; + } + } + } + } + } + + LNK_SymbolArray symbol_array = {0}; + symbol_array.count = coff_symbol_count; + symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); + + COFF_ParsedSymbol parsed_symbol; + for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + parsed_symbol.aux_symbol_count)) { + void *aux_symbols; if (is_big_obj) { - COFF_Symbol32 *coff_symbol32 = (COFF_Symbol32 *)coff_symbols + symbol_idx; - name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol32->name); - section_number = coff_symbol32->section_number; - value = coff_symbol32->value; - storage_class = coff_symbol32->storage_class; - type = coff_symbol32->type; - aux_symbol_count = coff_symbol32->aux_symbol_count; - aux_symbols = coff_symbol32 + 1; + COFF_Symbol32 *ptr = &((COFF_Symbol32 *)coff_symbols)[symbol_idx]; + parsed_symbol = coff_parse_symbol32(raw_coff, string_table_off, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } else { - COFF_Symbol16 *coff_symbol16 = (COFF_Symbol16 *)coff_symbols + symbol_idx; - name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol16->name); - section_number = coff_symbol16->section_number; - value = coff_symbol16->value; - storage_class = coff_symbol16->storage_class; - type = coff_symbol16->type; - aux_symbol_count = coff_symbol16->aux_symbol_count; - aux_symbols = coff_symbol16 + 1; - - // promote special section numbers to 32 bit - if (section_number == COFF_SYMBOL_DEBUG_SECTION_16) { - section_number = COFF_SYMBOL_DEBUG_SECTION; - } else if (section_number == COFF_SYMBOL_ABS_SECTION_16) { - section_number = COFF_SYMBOL_ABS_SECTION; - } + COFF_Symbol16 *ptr = (COFF_Symbol16 *)coff_symbols + symbol_idx; + parsed_symbol = coff_parse_symbol16(raw_coff, string_table_off, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } - if (symbol_idx + aux_symbol_count + 1 > coff_symbol_count) { - lnk_error(LNK_Error_IllData, "%S: symbol %S has out of bounds aux symbol count %u", obj_path, name, aux_symbol_count); + if (symbol_idx + parsed_symbol.aux_symbol_count + 1 > coff_symbol_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds aux symbol count %llu", parsed_symbol.name, symbol_idx, parsed_symbol.aux_symbol_count); } - COFF_SymbolValueInterpType interp = coff_interp_symbol(section_number, value, storage_class); + COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); switch (interp) { - case COFF_SymbolValueInterp_REGULAR: { - if (section_number == 0 || section_number > sect_count) { - lnk_error(LNK_Error_IllData, "%S: out ouf bounds section index in symbol \"%S (%u)\"", obj_path, name, section_number); - break; - } + case COFF_SymbolValueInterp_REGULAR: { + if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); + } + if (parsed_symbol.value > coff_sect_arr[parsed_symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number); + } - COFF_SectionHeader *coff_sect_header = &coff_sect_arr[section_number-1]; - if (value > coff_sect_header->fsize) { - lnk_error(LNK_Error_IllData, "%S: out of bounds section offset in symbol \"%S (%u)\"", obj_path, name, value); - break; - } + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (storage_class == COFF_SymStorageClass_EXTERNAL) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + LNK_Chunk *chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + U64 offset = parsed_symbol.value; + COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; + U64 check_sum = 0; - LNK_Chunk *chunk = chunk_ptr_arr[section_number-1]; - U64 offset = value; - COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; - U64 check_sum = 0; - if (coff_sect_header->flags & COFF_SectionFlag_LNK_COMDAT) { - B32 has_static_def = value == 0 && - type.u.lsb == COFF_SymType_NULL && - storage_class == COFF_SymStorageClass_STATIC && - aux_symbol_count == 1; - if (has_static_def) { + B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LNK_COMDAT) && + parsed_symbol.value == 0 && + parsed_symbol.aux_symbol_count > 0 && + parsed_symbol.type.u.lsb == COFF_SymType_NULL && + parsed_symbol.storage_class == COFF_SymStorageClass_STATIC; + if (is_comdat) { COFF_SymbolSecDef *secdef = aux_symbols; selection = secdef->selection; check_sum = secdef->check_sum; - + + // create association link between chunks if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) { U32 secdef_number = secdef->number_lo; + + // promote secdef number to 32 bits if (is_big_obj) { secdef_number |= (U32)secdef->number_hi << 16; } - if (secdef_number == 0 || secdef_number > sect_count) { - lnk_error(LNK_Error_IllData, "%S: symbol %u has out of bounds section definition number %u", name, symbol_idx, secdef_number); - } - - LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; - LNK_Chunk *associate_chunk = chunk_ptr_arr[section_number-1]; - lnk_chunk_associate(arena, head_chunk, associate_chunk); - } - } - } - - if (function_pad_min) { - if ((flags & LNK_DefinedSymbolFlag_IsFunc)) { - if (offset > 0) { - // convert leaf to list - // - // there is no way to know up front how many splits we have, - // so lazily convert chunks when see two or more functions - // in a section - if (chunk->type == LNK_Chunk_Leaf) { - // make a list chunk - LNK_Chunk *chunk_list = push_array(arena, LNK_Chunk, 1); - chunk_list->type = LNK_Chunk_List; - chunk_list->align = chunk->align; - chunk_list->is_discarded = chunk->is_discarded; - chunk_list->sort_idx = chunk->sort_idx; - chunk_list->input_idx = chunk->input_idx; - chunk_list->flags = chunk->flags; - chunk_list->associate = chunk->associate; - chunk_list->u.list = push_array(arena, LNK_ChunkList, 1); - lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, name); - - // reset chunk properties - chunk->align = 1; - chunk->min_size = function_pad_min; - chunk->sort_chunk = 0; - chunk->sort_idx = str8_zero(); - chunk->input_idx = 0; - chunk->associate = 0; - - // push leaf to list - lnk_chunk_list_push(arena, chunk_list->u.list, chunk); - - // set list as target chunk - chunk = chunk_list; - - // set list chunk to be head of this section - chunk_ptr_arr[section_number-1] = chunk_list; - } - - // find chunk that is near symbol - U64 cursor = 0; - LNK_ChunkNode *current = chunk->u.list->last; - for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { - Assert(c->data->type == LNK_Chunk_Leaf); - if (cursor + c->data->u.leaf.size > value) { - current = c; - break; - } - cursor += c->data->u.leaf.size; - } - - if (cursor < value) { - // bifurcate chunk at symbol offset - U64 split_pos = value - cursor; - Rng1U64 left_data_range = rng_1u64(0, split_pos); - Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size); - String8 left_data = str8_substr(current->data->u.leaf, left_data_range); - String8 right_data = str8_substr(current->data->u.leaf, right_data_range); - - // create new chunk for new part - LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1); - split_chunk->align = 1; - split_chunk->is_discarded = current->data->is_discarded; - split_chunk->type = LNK_Chunk_Leaf; - split_chunk->flags = current->data->flags; - split_chunk->u.leaf = right_data; - lnk_chunk_set_debugf(arena, chunk, "%S: chunk split on function %S", obj_path, name); - - LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1); - split_node->data = split_chunk; - - // update split chunk data - current->data->u.leaf = left_data; - - // insert split chunk after current chunk - split_node->next = current->next; - current->next = split_node; - chunk->u.list->count += 1; - - // point symbol to new split chunk - chunk = split_chunk; - offset = 0; + // associate chunks + if (secdef_number > 0 && secdef_number <= sect_count) { + LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; + LNK_Chunk *associate_chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + lnk_chunk_associate(head_chunk, associate_chunk); } else { - // chunk was already split at the offset - chunk = current->data; - offset = value - cursor; + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number); } } - - chunk->min_size = function_pad_min; } - // if symbol points to bifurcated section then we have an alias symbol (e.g. memmove is an alias to memcpy) - // and we need to find chunk that is near symbol + if (chunk->type == LNK_Chunk_List) { - U64 cursor = 0; + LNK_Chunk *closest_chunk = chunk->u.list->last->data; + U64 offset_cursor = 0; for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { - if (cursor + c->data->u.leaf.size > value) { - chunk = c->data; - offset = offset - cursor; + if (offset_cursor + c->data->u.leaf.size > offset) { + closest_chunk = c->data; break; } - cursor += c->data->u.leaf.size; + offset_cursor += c->data->u.leaf.size; } + Assert(offset >= offset_cursor); + offset -= offset_cursor; + chunk = closest_chunk; } - } + Assert(chunk->type == LNK_Chunk_Leaf); - Assert(chunk->type == LNK_Chunk_Leaf); - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, name, visibility, flags, chunk, offset, selection, check_sum); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_WEAK: { - if (aux_symbol_count == 0) { - lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" must at least one aux symbol", obj_path, name, symbol_idx); - } - - COFF_SymbolWeakExt *weak_ext = aux_symbols; - if (weak_ext->tag_index >= coff_symbol_count) { - lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" points to out of bounds symbol", obj_path, name, symbol_idx); - break; - } + lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum); + symbol_array.v[symbol_idx].obj = obj; + } break; + case COFF_SymbolValueInterp_WEAK: { + if (parsed_symbol.aux_symbol_count == 0) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx); + } + + COFF_SymbolWeakExt *weak_ext = aux_symbols; + if (weak_ext->tag_index >= coff_symbol_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx); + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; - lnk_init_weak_symbol(symbol, name, weak_ext->characteristics, fallback_symbol); + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; + lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol); - symbol->obj = obj; - fallback_symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_UNDEFINED: { - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_undefined_symbol(symbol, name, LNK_SymbolScopeFlag_Main); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_COMMON: { - // :common_block - // - // TODO: sort chunks on size to reduce bss usage - LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); - chunk->align = Min(32, u64_up_to_pow2(value)); // link.exe caps align at 32 bytes - chunk->type = LNK_Chunk_Leaf; - chunk->flags = master_common_block->flags; - chunk->u.leaf = str8(0, value); - lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, name); - lnk_chunk_list_push(arena, master_common_block->u.list, chunk); + symbol->obj = obj; + fallback_symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_UNDEFINED: { + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_COMMON: { + // :common_block + // + // TODO: sort chunks on size to reduce bss usage + LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); + chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes + chunk->type = LNK_Chunk_Leaf; + chunk->flags = master_common_block->flags; + chunk->u.leaf = str8(0, parsed_symbol.value); + lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, parsed_symbol.name); + lnk_chunk_list_push(arena, master_common_block->u.list, chunk); - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_ABS: { - // Never code or data, synthetic symbol. COFF spec says bits in value are used - // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. - // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_ABS: { + // Never code or data, synthetic symbol. COFF spec says bits in value are used + // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. + // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (storage_class == COFF_SymStorageClass_EXTERNAL) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_va(symbol, name, visibility, 0, value); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_DEBUG: break; + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_DEBUG: { + } break; } - - // skip aux symbols - symbol_idx += aux_symbol_count; } return symbol_array; @@ -1084,7 +1070,7 @@ lnk_parse_msvc_linker_directive(Arena *arena, String8 obj_path, String8 lib_path local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { to_parse = str8_zero(); - lnk_error_with_loc(LNK_InternalError_NotImplemented, obj_path, lib_path, "TODO: support for BOM encoding"); + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "TODO: support for BOM encoding"); } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { to_parse = str8_skip(buffer, sizeof(ascii_sig)); } else { diff --git a/src/linker/lnk_reloc.c b/src/linker/lnk_reloc.c index 779234ab..0c52820d 100644 --- a/src/linker/lnk_reloc.c +++ b/src/linker/lnk_reloc.c @@ -77,18 +77,20 @@ lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK LNK_Symbol *symbol = symbol_array.v + coff_reloc_ptr->isymbol; if (chunk->type == LNK_Chunk_List) { + reloc_chunk = chunk->u.list->last->data; U64 cursor = 0; for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { Assert(c->data->type == LNK_Chunk_Leaf); if (coff_reloc_ptr->apply_off < cursor + c->data->u.leaf.size) { reloc_chunk = c->data; - apply_off = coff_reloc_ptr->apply_off - cursor; break; } cursor += c->data->u.leaf.size; } + apply_off = coff_reloc_ptr->apply_off - cursor; } + Assert(reloc_chunk->type == LNK_Chunk_Leaf); Assert(coff_reloc_ptr->isymbol < symbol_array.count); reloc_ptr->chunk = reloc_chunk; reloc_ptr->type = type; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 422008cf..e2412459 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -145,7 +145,7 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, internal void lnk_section_associate_chunks(LNK_Section *sect, LNK_Chunk *head, LNK_Chunk *associate) { - lnk_chunk_associate(sect->arena, head, associate); + lnk_chunk_associate(head, associate); } internal LNK_Chunk * diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 19a87ca2..2fbf706b 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -2164,7 +2164,7 @@ gsi_write_build_result(TP_Context *tp, msf_stream_write(msf, gsi_sn, &build.bitmap[0], bitmap_size); ProfEnd(); - ProfBegin("Write buckets [%M]", compressed_bucket_arr-size); + ProfBegin("Write buckets [%M]", compressed_bucket_arr_size); msf_stream_write(msf, gsi_sn, &build.compressed_bucket_arr[0], compressed_bucket_arr_size); ProfEnd(); From de2ea38f50963050bbb4cb893ba8f9a2f1e4be03 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 16 Jan 2025 14:03:14 -0800 Subject: [PATCH 28/53] build file paths relative to image path --- src/linker/lnk_config.c | 25 ++++++++++++++----------- src/linker/path_ext/path.c | 17 ----------------- src/linker/path_ext/path.h | 1 - 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 72c7ed4c..8662b4aa 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1960,35 +1960,38 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // handle empty /OUT if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) { - String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]); - String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); - config->image_name = make_file_path_with_ext(scratch.arena, name, ext); + String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]); + String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); + config->image_name = make_file_name_with_ext(scratch.arena, name, ext); } - config->image_name = os_full_path_from_path(arena, config->image_name); // handle empty /PDB if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) { - config->pdb_name = make_file_path_with_ext(arena, config->image_name, str8_lit("pdb")); + config->pdb_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("pdb")); } - config->pdb_name = os_full_path_from_path(arena, config->pdb_name); // handle empty /RAD_DEBUG_NAME if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) { - config->rad_debug_name = make_file_name_with_ext(arena, config->image_name, str8_lit("rdi")); + config->rad_debug_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("rdi")); } - config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name); // handle empty /IMPLIB if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) { - config->imp_lib_name = make_file_name_with_ext(arena, config->image_name, str8_lit("lib")); + config->imp_lib_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("lib")); } - config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name); // handle empty /MANIFESTFILE if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) { - config->manifest_name = push_str8f(arena, "%S.manifest", config->image_name); + config->manifest_name = push_str8f(scratch.arena, "%S.manifest", config->image_name); } + // convert to full paths + config->image_name = os_full_path_from_path(arena, config->image_name); + config->pdb_name = os_full_path_from_path(arena, config->pdb_name); + config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name); + config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name); + config->manifest_name = os_full_path_from_path(arena, config->manifest_name); + // collect env vars HashTable *env_vars = hash_table_init(scratch.arena, 512); { diff --git a/src/linker/path_ext/path.c b/src/linker/path_ext/path.c index ac41560d..8b50bfb4 100644 --- a/src/linker/path_ext/path.c +++ b/src/linker/path_ext/path.c @@ -9,23 +9,6 @@ make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext) return result; } -internal String8 -make_file_path_with_ext(Arena *arena, String8 file_name, String8 ext) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 curr = os_get_current_path(scratch.arena); - String8 name = make_file_name_with_ext(scratch.arena, str8_skip_last_slash(file_name), ext); - - String8List list = {0}; - str8_list_push(scratch.arena, &list, curr); - str8_list_push(scratch.arena, &list, name); - String8 result = str8_path_list_join_by_style(arena, &list, PathStyle_SystemAbsolute); - - scratch_end(scratch); - return result; -} - internal String8 path_char_from_style(PathStyle style) { diff --git a/src/linker/path_ext/path.h b/src/linker/path_ext/path.h index 383d1011..ae3e4bb9 100644 --- a/src/linker/path_ext/path.h +++ b/src/linker/path_ext/path.h @@ -4,7 +4,6 @@ #pragma once internal String8 make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext); -internal String8 make_file_path_with_ext(Arena *arena, String8 file_name, String8 ext); internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style); internal String8 path_canon_from_regular_path(Arena *arena, String8 path); internal PathStyle path_style_from_string(String8 string); From 89ff4d0de2a89f7fbb92a138294603cabbaf31ca Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 17 Jan 2025 15:28:10 -0800 Subject: [PATCH 29/53] on lambda types we have to replace unique name with hash, otherwise visual studio wont show local variables in lambdas --- src/linker/lnk_debug_info.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 03e4e2bc..055ac556 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2505,7 +2505,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) map = &task->maps[task_id]; } - U64 hash_max_chars = hash_length; + U64 hash_max_chars = hash_length*2; U8 temp[128]; for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) { @@ -2513,7 +2513,9 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); - if (udt_info.props & CV_TypeProp_HasUniqueName && udt_info.unique_name.size > hash_max_chars) { + if ((udt_info.props & CV_TypeProp_HasUniqueName) && + udt_info.unique_name.size > hash_max_chars && + udt_info.name.size > hash_max_chars) { // hash unique name U128 name_hash; blake3_hasher hasher; blake3_hasher_init(&hasher); @@ -2523,27 +2525,33 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) // emit hash -> unique name map if (make_map) { lnk_format_u128(temp, sizeof(temp), hash_length, name_hash); - str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(udt_info.unique_name)); + str8_list_pushf(map_arena, map, "%s %S\n", temp, str8_varg(udt_info.unique_name)); } // parse leaf size CV_NumericParsed dummy; U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy); - U64 colon_pos = str8_find_needle_reverse(udt_info.name, 0, str8_lit("size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1; - - // discard unique name - CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1); - lf->props &= ~CV_TypeProp_HasUniqueName; + header->size = sizeof(CV_LeafKind) + + sizeof(CV_LeafStruct) + + numeric_size + + udt_info.name.size + 1 + + udt_info.unique_name.size + 1; } else { // replace uniuqe type name with hash udt_info.unique_name.str = udt_info.name.str + udt_info.name.size + 1; From a1d5837ff332d9b55bebf78e17f3bf420ac66947 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 18 Jan 2025 17:01:32 -0800 Subject: [PATCH 30/53] helpers for matching string literals --- src/base/base_strings.h | 3 + src/codeview/codeview_parse.c | 8 +- src/coff/coff.c | 14 +- src/dwarf/dwarf_parse.c | 14 +- src/linker/lnk.c | 12 +- src/linker/lnk_cmd_line.c | 6 +- src/linker/lnk_config.c | 248 ++++++++++++++------------------- src/linker/lnk_lib.c | 4 +- src/linker/lnk_obj.c | 2 +- src/linker/lnk_section_table.c | 14 +- src/msvc_crt/msvc_crt.c | 8 +- src/raddump/raddump.c | 26 ++-- src/raddump/raddump_main.c | 2 +- 13 files changed, 165 insertions(+), 196 deletions(-) diff --git a/src/base/base_strings.h b/src/base/base_strings.h index fc946dd8..67e90349 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -206,10 +206,13 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string); //////////////////////////////// //~ rjf: String Matching +#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags)) +#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags)) internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags); +#define str8_ends_with_lit(string, end_lit, flags) str8_ends_with((string), str8_lit(end_lit), (flags)) //////////////////////////////// //~ rjf: String Slicing diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c index 96732f61..94c72e43 100644 --- a/src/codeview/codeview_parse.c +++ b/src/codeview/codeview_parse.c @@ -458,10 +458,10 @@ internal B32 cv_is_udt_name_anon(String8 name) { // corresponds to fUDTAnon from dbi/tm.cpp:817 - B32 is_anon = str8_match(str8_lit(""), name, 0) || - str8_match(str8_lit("__unnamed"), name, 0) || - str8_match(str8_lit("::"), name, StringMatchFlag_RightSideSloppy) || - str8_match(str8_lit("::__unnamed"), name, StringMatchFlag_RightSideSloppy); + B32 is_anon = str8_match_lit("", name, 0) || + str8_match_lit("__unnamed", name, 0) || + str8_match_lit("::", name, StringMatchFlag_RightSideSloppy) || + str8_match_lit("::__unnamed", name, StringMatchFlag_RightSideSloppy); return is_anon; } diff --git a/src/coff/coff.c b/src/coff/coff.c index 140dfea8..1e9c2487 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -270,7 +270,7 @@ coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_o // TLS sections don't have a postfix but we still have to sort them based // on dollar sign so they are sloted between CRT's _tls_start and _tls_end sections. - if (str8_match(*name_out, str8_lit(".tls"), 0) && postfix_out->size == 0) { + if (str8_match_lit(".tls", *name_out, 0) && postfix_out->size == 0) { *postfix_out = str8_lit("$"); } @@ -1031,7 +1031,7 @@ coff_parse_archive_member_data(String8 data, U64 cursor, COFF_ArchiveMember *mem internal COFF_ArchiveFirstMember coff_parse_first_archive_member(COFF_ArchiveMember *member) { - Assert(str8_match(member->header.name, str8_lit("/"), 0)); + Assert(str8_match_lit("/", member->header.name, 0)); U64 cursor = 0; @@ -1064,7 +1064,7 @@ coff_parse_second_archive_member(COFF_ArchiveMember *member) { COFF_ArchiveSecondMember result = {0}; - if (str8_match(member->header.name, str8_lit("/"), 0)) { + if (str8_match_lit("/", member->header.name, 0)) { U64 cursor = 0; U32 member_count = 0; @@ -1232,7 +1232,7 @@ coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember if (member_out->header.is_end_correct) { member_out->offset = *offset; - if (str8_match(member_out->header.name, str8_lit("/"), 0) || str8_match(member_out->header.name, str8_lit("//"), 0)) { + if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) { member_out->data = str8_substr(data, member_out->header.data_range); } else { // size field in non-header members means size of stand-alone obj @@ -1265,7 +1265,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) COFF_ArchiveMemberNode *ptr = member_list.first; if (ptr) { - if (str8_match(ptr->data.header.name, str8_lit("/"), 0)) { + if (str8_match_lit("/", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { first_header = ptr->data; ptr = ptr->next; @@ -1278,7 +1278,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) } if (!error.size && ptr) { - if (str8_match(ptr->data.header.name, str8_lit("/"), 0)) { + if (str8_match_lit("/", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { second_header = ptr->data; ptr = ptr->next; @@ -1290,7 +1290,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) } if (!error.size && ptr) { - if (str8_match(ptr->data.header.name, str8_lit("//"), 0)) { + if (str8_match_lit("//", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { long_names_member = ptr->data; ptr = ptr->next; diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 31c52af7..aa2c7d3e 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -1474,24 +1474,24 @@ dw_ext_from_params(String8 producer, Arch arch, ImageType image_type) switch (image_type) { case Image_Null: break; case Image_CoffPe: { - if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU | DW_Ext_LLVM; - } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU; } } break; case Image_Elf32: case Image_Elf64: { - if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU | DW_Ext_LLVM; - } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU; } } break; case Image_Macho: { - if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_LLVM | DW_Ext_APPLE; - } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { ext = DW_Ext_GNU | DW_Ext_APPLE; } } break; @@ -2046,7 +2046,7 @@ dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) String8List path_list = {0}; - if (str8_match(str8_lit(".."), dir, StringMatchFlag_RightSideSloppy)) { + if (str8_match_lit("..", dir, StringMatchFlag_RightSideSloppy)) { String8List comp_dir_list = str8_split_path(scratch.arena, vm->dir_table.v[0]); str8_list_concat_in_place(&path_list, &comp_dir_list); } diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f094c978..b29c6744 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -770,7 +770,7 @@ lnk_make_res_obj(TP_Context *tp, LNK_RelocList reloc_list = {0}; LNK_RelocList res_data_reloc_list = {0}; for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) { - B32 is_reloc_symbol = str8_match(str8_lit("$R"), reloc->symbol->name, StringMatchFlag_RightSideSloppy); + B32 is_reloc_symbol = str8_match_lit("$R", reloc->symbol->name, StringMatchFlag_RightSideSloppy); LNK_Reloc *dst; if (is_reloc_symbol) { dst = lnk_reloc_list_push(sect->arena, &res_data_reloc_list); @@ -2464,7 +2464,7 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) case COFF_WeakExtType_SEARCH_ALIAS: { lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); if (!lazy) { - if (str8_match(str8_lit(".weak."), symbol->name, StringMatchFlag_RightSideSloppy)) { + if (str8_match_lit(".weak.", symbol->name, StringMatchFlag_RightSideSloppy)) { // TODO: Clang and MingGW encode extra info in alias // // __attribute__((weak,alias("foo"))) void bar(void); @@ -3349,13 +3349,13 @@ lnk_run(int argc, char **argv) // redirect user entry to appropriate CRT entry if (entry_point_symbol) { config->entry_point_name = entry_point_symbol->name; - if (str8_match(config->entry_point_name, str8_lit("wmain"), 0)) { + if (str8_match_lit("wmain", config->entry_point_name, 0)) { config->entry_point_name = str8_lit("wmainCRTStartup"); - } else if (str8_match(config->entry_point_name, str8_lit("main"), 0)) { + } else if (str8_match_lit("main", config->entry_point_name, 0)) { config->entry_point_name = str8_lit("mainCRTStartup"); - } else if (str8_match(config->entry_point_name, str8_lit("WinMain"), 0)) { + } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { config->entry_point_name = str8_lit("WinMainCRTStartup"); - } else if (str8_match(config->entry_point_name, str8_lit("wWinMain"), 0)) { + } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { config->entry_point_name = str8_lit("wWinMainCRTStartup"); } } diff --git a/src/linker/lnk_cmd_line.c b/src/linker/lnk_cmd_line.c index d7f9b89d..5d1f6d5f 100644 --- a/src/linker/lnk_cmd_line.c +++ b/src/linker/lnk_cmd_line.c @@ -135,8 +135,8 @@ lnk_cmd_line_parse_windows_rules(Arena *arena, String8List arg_list) for (String8Node *arg_node = arg_list.first; arg_node != 0; arg_node = arg_node->next) { String8 arg = arg_node->string; - B32 is_option = str8_match(str8_lit("/"), arg, StringMatchFlag_RightSideSloppy) || - str8_match(str8_lit("-"), arg, StringMatchFlag_RightSideSloppy); + B32 is_option = str8_match_lit("/", arg, StringMatchFlag_RightSideSloppy) || + str8_match_lit("-", arg, StringMatchFlag_RightSideSloppy); if (is_option) { U64 param_start_pos = str8_find_needle(arg, 0, str8_lit(":"), 0); String8 option_name = str8_chop(arg, arg.size - param_start_pos); @@ -195,7 +195,7 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list) String8List result = {0}; for (String8Node *curr = arg_list.first; curr != 0; curr = curr->next) { - B32 is_rsp = str8_match(str8_lit("@"), curr->string, StringMatchFlag_RightSideSloppy); + B32 is_rsp = str8_match_lit("@", curr->string, StringMatchFlag_RightSideSloppy); if (is_rsp) { // remove "@" String8 name = str8_skip(curr->string, 1); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 8662b4aa..353068dd 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -4,7 +4,7 @@ //////////////////////////////// // Enum <-> String -read_only struct +global read_only struct { LNK_CmdSwitchType type; char *name; @@ -164,12 +164,45 @@ read_only struct { LNK_CmdSwitch_Help, "?", "", "" }, }; +global read_only struct +{ + char *name; + LNK_InputType type; +} g_input_type_map[] = { + { "o", LNK_Input_Obj }, + { "obj", LNK_Input_Obj }, + { "lib", LNK_Input_Lib }, + { "rlib", LNK_Input_Lib }, // rust libs + { "res", LNK_Input_Res }, +}; + +global read_only struct +{ + char *name; + LNK_DebugMode mode; +} g_debug_mode_map[] = { + { "null", LNK_DebugMode_Null }, + { "none", LNK_DebugMode_None }, + { "fastlink", LNK_DebugMode_FastLink }, + { "ghash", LNK_DebugMode_GHash }, + { "full", LNK_DebugMode_Full }, +}; + +global read_only struct +{ + char *name; + LNK_TypeNameHashMode mode; +} g_type_name_hash_mode_map[] = { + { "none", LNK_TypeNameHashMode_None }, + { "lenient", LNK_TypeNameHashMode_Lenient }, + { "full", LNK_TypeNameHashMode_Full } +}; + internal LNK_CmdSwitchType lnk_cmd_switch_type_from_string(String8 name) { - for (U64 i = 0; i < ArrayCount(g_cmd_switch_map); ++i) { - String8 curr_name = str8_cstring(g_cmd_switch_map[i].name); - if (str8_match(curr_name, name, StringMatchFlag_CaseInsensitive)) { + for (U64 i = 0; i < ArrayCount(g_cmd_switch_map); i += 1) { + if (str8_match_cstr(g_cmd_switch_map[i].name, name, StringMatchFlag_CaseInsensitive)) { return g_cmd_switch_map[i].type; } } @@ -184,69 +217,36 @@ lnk_string_from_cmd_switch_type(LNK_CmdSwitchType type) return str8_cstring(g_cmd_switch_map[cmd_idx].name); } } - return str8(0,0); + return str8_zero(); } -read_only struct { - char *name; - LNK_InputType type; -} g_input_type_map[] = { - { "o", LNK_Input_Obj }, - { "obj", LNK_Input_Obj }, - { "lib", LNK_Input_Lib }, - { "rlib", LNK_Input_Lib }, // rust libs - { "res", LNK_Input_Res }, -}; - internal LNK_InputType -lnk_input_type_from_string(String8 string) +lnk_input_type_from_string(String8 name) { for (U64 i = 0; i < ArrayCount(g_input_type_map); i += 1) { - if (str8_match(str8_cstring(g_input_type_map[i].name), string, StringMatchFlag_CaseInsensitive)) { + if (str8_match_cstr(g_input_type_map[i].name, name, StringMatchFlag_CaseInsensitive)) { return g_input_type_map[i].type; } } return LNK_Input_Null; } -read_only struct -{ - char *name; - LNK_DebugMode mode; -} g_debug_mode_map[] = { - { "null", LNK_DebugMode_Null }, - { "none", LNK_DebugMode_None }, - { "fastlink", LNK_DebugMode_FastLink }, - { "ghash", LNK_DebugMode_GHash }, - { "full", LNK_DebugMode_Full }, -}; - internal LNK_DebugMode -lnk_debug_mode_from_string(String8 string) +lnk_debug_mode_from_string(String8 name) { for (U64 i = 0; i < ArrayCount(g_debug_mode_map); i += 1) { - if (str8_match(str8_cstring(g_debug_mode_map[i].name), string, StringMatchFlag_CaseInsensitive)) { + if (str8_match_cstr(g_debug_mode_map[i].name, name, StringMatchFlag_CaseInsensitive)) { return g_debug_mode_map[i].mode; } } return LNK_DebugMode_Null; } -read_only struct -{ - char *name; - LNK_TypeNameHashMode mode; -} g_type_name_hash_mode_map[] = { - { "none", LNK_TypeNameHashMode_None }, - { "lenient", LNK_TypeNameHashMode_Lenient }, - { "full", LNK_TypeNameHashMode_Full } -}; - internal LNK_TypeNameHashMode -lnk_type_name_hash_mode_from_string(String8 string) +lnk_type_name_hash_mode_from_string(String8 name) { - for (U64 i = 0; i < ArrayCount(g_type_name_hash_mode_map); ++i) { - if (str8_match(str8_cstring(g_type_name_hash_mode_map[i].name), string, StringMatchFlag_CaseInsensitive)) { + for (U64 i = 0; i < ArrayCount(g_type_name_hash_mode_map); i += 1) { + if (str8_match_cstr(g_type_name_hash_mode_map[i].name, name, StringMatchFlag_CaseInsensitive)) { return g_type_name_hash_mode_map[i].mode; } } @@ -296,16 +296,12 @@ internal void lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...) { Temp scratch = scratch_begin(0,0); - va_list args; va_start(args, fmt); - String8 switch_name = lnk_string_from_cmd_switch_type(cmd_switch); String8 message = push_str8fv(scratch.arena, fmt, args); String8 output = push_str8f(scratch.arena, "/%S: %S", switch_name, message); lnk_error_with_loc(code, obj_path, lib_path, "%S", output); - va_end(args); - scratch_end(scratch); } @@ -325,9 +321,9 @@ internal String8 lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 string) { String8 result = string; - B32 starts_with_quote = str8_match(str8_lit("\""), string, StringMatchFlag_RightSideSloppy); + B32 starts_with_quote = str8_match_lit("\"", string, StringMatchFlag_RightSideSloppy); if (starts_with_quote) { - if (str8_ends_with(string, str8_lit("\""), 0)) { + if (str8_ends_with_lit(string, "\"", 0)) { result = str8_skip(result, 1); result = str8_chop(result, 1); } else { @@ -396,55 +392,45 @@ lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineTyp { Version ver = make_version(0,0); switch (subsystem) { - case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: { - ver = make_version(1,0); - } break; + case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break; case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { case COFF_MachineType_X64: - case COFF_MachineType_X86: { - ver = make_version(6,0); - } break; + case COFF_MachineType_X86: ver = make_version(6,0); break; + case COFF_MachineType_ARMNT: case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { - ver = make_version(6,2); - } break; - default: { InvalidPath; } break; + case COFF_MachineType_ARM: ver = make_version(6,2); break; + + default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } } break; case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { case COFF_MachineType_X64: - case COFF_MachineType_X86: { - ver = make_version(6,0); - } break; + case COFF_MachineType_X86: ver = make_version(6,0); break; + case COFF_MachineType_ARMNT: case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { - ver = make_version(6,2); - } break; - default: { InvalidPath; } break; + case COFF_MachineType_ARM: ver = make_version(6,2); break; + + default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } } break; - case PE_WindowsSubsystem_POSIX_CUI: { - ver = make_version(19,90); - } break; + case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(19,90); break; case PE_WindowsSubsystem_EFI_APPLICATION: case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: case PE_WindowsSubsystem_EFI_ROM: - case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: { - ver = make_version(1,0); - } break; + case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break; case PE_WindowsSubsystem_NATIVE_WINDOWS: - case PE_WindowsSubsystem_NATIVE: { - Assert(!"TODO: detect -drive=WDM switch"); - } break; + case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break; + + default: lnk_not_implemented("unknown subsystem kind %u", subsystem); break; } return ver; } @@ -454,65 +440,47 @@ lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType ma { Version ver = make_version(0,0); switch (subsystem) { - case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: { - ver = make_version(1,0); - } break; + case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break; case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { - case COFF_MachineType_X86: { - ver = make_version(5,1); - } break; + case COFF_MachineType_X86: ver = make_version(5,1); break; - case COFF_MachineType_X64: { - ver = make_version(5,2); - } break; + case COFF_MachineType_X64: ver = make_version(5,2); break; case COFF_MachineType_ARMNT: case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { - ver = make_version(6,2); - } break; + case COFF_MachineType_ARM: ver = make_version(6,2); break; - default: InvalidPath; break; + default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } } break; case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { - case COFF_MachineType_X86: { - ver = make_version(5,1); - } break; + case COFF_MachineType_X86: ver = make_version(5,1); break; - case COFF_MachineType_X64: { - ver = make_version(5,2); - } break; + case COFF_MachineType_X64: ver = make_version(5,2); break; case COFF_MachineType_ARMNT: case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { - ver = make_version(6,2); - } break; + case COFF_MachineType_ARM: ver = make_version(6,2); break; - default: InvalidPath; break; + default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } } break; - case PE_WindowsSubsystem_POSIX_CUI: { - ver = make_version(1,0); - } break; + case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(1,0); break; case PE_WindowsSubsystem_EFI_APPLICATION: case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: case PE_WindowsSubsystem_EFI_ROM: - case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: { - ver = make_version(1,0); - } break; + case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break; case PE_WindowsSubsystem_NATIVE_WINDOWS: - case PE_WindowsSubsystem_NATIVE: { - Assert(!"TODO: detect -drive=WDM switch"); - } break; + case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break; + + default: lnk_not_implemented("unknown subsystem kind %u", subsystem); } return ver; } @@ -607,7 +575,6 @@ lnk_try_parse_u64(String8 string, LNK_ParseU64Flags flags, U64 *value_out) return 0; } } - if (flags & LNK_ParseU64Flag_CheckPow2) { if (!IsPow2(*value_out)) { return 0; @@ -663,10 +630,10 @@ lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType if (value_strings.node_count > 1) { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters"); } else if (value_strings.node_count == 1) { - if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("no", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { *value_out = LNK_SwitchState_No; is_parsed = 1; - } else if (str8_match(value_strings.first->string, str8_lit("yes"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("yes", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { *value_out = LNK_SwitchState_Yes; is_parsed = 1; } else if (value_strings.first->string.size == 0) { @@ -1021,7 +988,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (value_strings.node_count == 2) { String8Node *first_node = value_strings.first; //String8Node *second_node = first_node->next; - B32 is_response_file = str8_match(str8_lit("@"), first_node->string, StringMatchFlag_RightSideSloppy); + B32 is_response_file = str8_match_lit("@", first_node->string, StringMatchFlag_RightSideSloppy); if (is_response_file) { //String8 file_path = first_node->string; //String8 tag = second_node->string; @@ -1076,9 +1043,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } else { String8 value = value_strings.first->string; - if (str8_match(value, str8_lit("unload"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("unload", value, StringMatchFlag_CaseInsensitive)) { config->flags |= LNK_ConfigFlag_DelayUnload; - } else if (str8_match(value, str8_lit("nobind"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("nobind", value, StringMatchFlag_CaseInsensitive)) { config->flags &= ~LNK_ConfigFlag_DelayBind; } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value); @@ -1241,14 +1208,13 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam String8List param_list = str8_split_by_string_chars(scratch.arena, value_strings.first->string, str8_lit(","), 0); String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); if (param_arr.count > 0) { - if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("embed", param_arr.v[0], StringMatchFlag_CaseInsensitive)) { config->manifest_opt = LNK_ManifestOpt_Embed; - if (param_arr.count == 1) { config->manifest_resource_id = 0; } else if (param_arr.count > 1) { // parse resource id - if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("id=", param_arr.v[1], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); if (res_id_arr.count == 2) { @@ -1267,7 +1233,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } else { lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); } - } else if (str8_match(param_arr.v[0], str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("no", param_arr.v[0], StringMatchFlag_CaseInsensitive)) { config->manifest_opt = LNK_ManifestOpt_No; } else { lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); @@ -1305,15 +1271,15 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam String8List param_list = str8_split_by_string_chars(scratch.arena, uac, str8_lit(" "), 0); String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); if (param_arr.count > 0) { - if (str8_match(str8_lit("level="), param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("level=", param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { String8 level_param = param_arr.v[0]; String8List level_list = str8_split_by_string_chars(scratch.arena, level_param, str8_lit("="), 0); if (level_list.node_count == 2) { - if (str8_match(level_list.first->string, str8_lit("level"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("level", level_list.first->string, StringMatchFlag_CaseInsensitive)) { String8 level = level_list.last->string; - if (str8_match(level, str8_lit("'asInvoker'"), 0) || - str8_match(level, str8_lit("'highestAvailable'"), 0) || - str8_match(level, str8_lit("'requireAdministrator'"), 0)) { + if (str8_match_lit("'asInvoker'", level, 0) || + str8_match_lit("'highestAvailable'", level, 0) || + str8_match_lit("'requireAdministrator'", level, 0)) { // manifest level was parsed! config->manifest_uac = 1; config->manifest_level = push_str8_copy(arena, level); @@ -1322,8 +1288,8 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam String8List ui_access_list = str8_split_by_string_chars(scratch.arena, ui_access_param, str8_lit("="), 0); if (ui_access_list.node_count == 2) { String8 ui_access = ui_access_list.last->string; - if (str8_match(ui_access, str8_lit("'true'"), 0) || - str8_match(ui_access, str8_lit("'false'"), 0)) { + if (str8_match_lit("'true'", ui_access, 0) || + str8_match_lit("'false'", ui_access, 0)) { // ui access was parsed! config->manifest_ui_access = push_str8_copy(arena, ui_access); } else { @@ -1342,7 +1308,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } else { lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); } - } else if (str8_match(str8_lit("no"), param_arr.v[0], StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("no", param_arr.v[0], StringMatchFlag_CaseInsensitive)) { config->manifest_uac = 0; } else { lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); @@ -1359,7 +1325,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam // warn about invalid natvis extension for (String8Node *node = value_strings.first; node != 0; node = node->next) { String8 ext = str8_skip_last_dot(node->string); - if (!str8_match(ext, str8_lit("natvis"), StringMatchFlag_CaseInsensitive)) { + if (!str8_match_lit("natvis", ext, StringMatchFlag_CaseInsensitive)) { lnk_error_cmd_switch(LNK_Warning_InvalidNatvisFileExt, obj_path, lib_path, cmd_switch, "Visual Studio expects .natvis extension: \"%S\"", node->string); } } @@ -1396,12 +1362,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Opt: { for (String8Node *n = value_strings.first; n != 0; n = n->next) { String8 param = n->string; - if (str8_match(param, str8_lit("ref"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("ref", param, StringMatchFlag_CaseInsensitive)) { config->opt_ref = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noref"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("noref", param, StringMatchFlag_CaseInsensitive)) { config->opt_ref = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("icf"), StringMatchFlag_CaseInsensitive) || - str8_match(param, str8_lit("icf="), StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { + } else if (str8_match_lit("icf", param, StringMatchFlag_CaseInsensitive) || + str8_match_lit("icf=", param, StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { String8List vals = str8_split_by_string_chars(scratch.arena, param, str8_lit("="), 0); if (vals.node_count > 2) { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters for iteration"); @@ -1415,11 +1381,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } config->opt_icf = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noicf"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("noicf", param, StringMatchFlag_CaseInsensitive)) { config->opt_icf = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("lbr"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("lbr", param, StringMatchFlag_CaseInsensitive)) { config->opt_lbr = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("nolibr"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("nolibr", param, StringMatchFlag_CaseInsensitive)) { config->opt_lbr = LNK_SwitchState_No; } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown option \"%S\"", param); @@ -1566,9 +1532,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Rad_Guid: { if (value_strings.node_count == 1) { - if (str8_match(value_strings.first->string, str8_lit("imageblake3"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("imageblake3", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { config->guid_type = Lnk_DebugInfoGuid_ImageBlake3; - } else if (str8_match(value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("random", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { config->guid = os_make_guid(); } else { Guid guid; @@ -1605,12 +1571,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam #endif } } else if (value_strings.node_count == 1) { - if (str8_match(value_strings.first->string, str8_lit("quiet"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("quiet", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { OS_ProcessInfo *process_info = os_get_process_info(); if (process_info->large_pages_allowed) { arena_default_flags |= ArenaFlag_LargePages; } - } else if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("no", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { arena_default_flags &= ~ArenaFlag_LargePages; } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter: \"%S\", expected NO or QUIET", value_strings.first->string); @@ -1626,11 +1592,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Rad_Log: { if (value_strings.node_count == 1) { - if (str8_match(value_strings.first->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { + if (str8_match_lit("all", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { lnk_set_log_status((LNK_LogType)ilog, 1); } - } else if (str8_match(value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("io", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { lnk_set_log_status(LNK_Log_IO_Read, 1); lnk_set_log_status(LNK_Log_IO_Write, 1); } else { diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 0d018704..22225e42 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -542,7 +542,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach ProfBeginFunction(); Assert(machine == COFF_MachineType_X64); - Assert(str8_match(str8_lit("dll"), str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); + Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); String8List list = {0}; @@ -802,7 +802,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m { ProfBeginFunction(); - Assert(str8_match(str8_lit("dll"), str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); + Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); String8List list = {0}; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index c018b5ab..d971b459 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -1119,7 +1119,7 @@ lnk_directive_info_from_sections(Arena *arena, for (U64 chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { String8 sect_name = sect_name_arr[chunk_idx]; LNK_Chunk *sect_chunk = chunk_arr + chunk_idx; - if (str8_match(sect_name, str8_lit(".drectve"), 0)) { + if (str8_match_lit(".drectve", sect_name, 0)) { if (sect_chunk->type == LNK_Chunk_Leaf) { if (sect_chunk->u.leaf.size >= 3) { if (~sect_chunk->flags & COFF_SectionFlag_LNK_INFO) { diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index e2412459..b3d135ac 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -91,10 +91,10 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, str8_list_pushf(scratch.arena, &sort_index_list, "a"); } - if (str8_match(name, str8_lit(".null"), 0)) { + if (str8_match_lit(".null", name, 0)) { // null section always first str8_list_pushf(scratch.arena, &sort_index_list, "a"); - } else if (str8_match(name, str8_lit(".rsrc"), 0)) { + } else if (str8_match_lit(".rsrc", name, 0)) { // section with resource data must be last because during runtime windows might append pages str8_list_pushf(scratch.arena, &sort_index_list, "c"); } else { @@ -104,18 +104,18 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, // sort sections based on the contents if (flags & COFF_SectionFlag_CNT_CODE) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); - if (str8_match(name, str8_lit(".text"), 0)) { + if (str8_match_lit(".text", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "b"); } } else if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { str8_list_pushf(scratch.arena, &sort_index_list, "b"); - if (str8_match(name, str8_lit(".data"), 0)) { + if (str8_match_lit(".data", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); - } else if (str8_match(name, str8_lit(".rdata"), 0)) { + } else if (str8_match_lit(".rdata", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "b"); - } else if (str8_match(name, str8_lit(".tls"), 0)) { + } else if (str8_match_lit(".tls", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "c"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "d"); @@ -888,7 +888,7 @@ lnk_dump_chunks(LNK_SectionTable *st) LNK_Section *sect = sect_id_map[sect_id]; if (!sect) continue; if (sect->is_merged) continue; - if (str8_match(sect->name, str8_lit(".text"), 0)) { + if (str8_match_lit(".text", sect->name, 0)) { for (U64 chunk_id = 0; chunk_id < sect->cman->total_chunk_count; ++chunk_id) { LNK_ChunkRef chunk_ref = { sect_id, chunk_id }; LNK_Chunk *chunk = lnk_chunk_from_chunk_ref(sect_id_map, chunk_id_map, chunk_ref); diff --git a/src/msvc_crt/msvc_crt.c b/src/msvc_crt/msvc_crt.c index a735341d..fda085a4 100644 --- a/src/msvc_crt/msvc_crt.c +++ b/src/msvc_crt/msvc_crt.c @@ -438,8 +438,8 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena, } */ - B32 is_handler_v3_or_below = str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0) || - str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0); + B32 is_handler_v3_or_below = str8_match_lit("__CxxFrameHandler3", handler_name, 0) || + str8_match_lit("__GSHandlerCheck_EH", handler_name, 0); if (is_handler_v3_or_below) { U64 func_info_foff = handler_data_foff + sizeof(handler_voff); MSCRT_FuncInfo func_info = {0}; @@ -457,8 +457,8 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena, goto next; } - B32 is_handler_v4 = str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0) || - str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0); + B32 is_handler_v4 = str8_match_lit("__CxxFrameHandler4", handler_name, 0) || + str8_match_lit("__GSHandlerCheck_EH4", handler_name, 0); if (is_handler_v4) { U32 func_info_voff = *(U32 *)str8_deserial_get_raw_ptr(raw_data, handler_data_foff + sizeof(handler_voff), sizeof(func_info_voff)); U64 func_info_foff = coff_foff_from_voff(sections, section_count, func_info_voff); diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 4600b54f..f1cea0ee 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -416,9 +416,9 @@ rd_dw_sections_from_coff_section_table(Arena *arena, DW_SectionKind s = DW_Section_Null; B32 is_dwo = 0; #define X(_K,_L,_M,_W) \ - if (str8_match(name, str8_lit(_L), 0)) { s = DW_Section_##_K; } \ - if (str8_match(name, str8_lit(_M), 0)) { s = DW_Section_##_K; } \ - if (str8_match(name, str8_lit(_W), 0)) { s = DW_Section_##_K; is_dwo = 1; } + if (str8_match_lit(_L, name, 0)) { s = DW_Section_##_K; } \ + if (str8_match_lit(_M, name, 0)) { s = DW_Section_##_K; } \ + if (str8_match_lit(_W, name, 0)) { s = DW_Section_##_K; is_dwo = 1; } DW_SectionKind_XList(X) #undef X @@ -4499,7 +4499,7 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); - if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + if (str8_match_lit(".debug$S", sect_name, 0)) { Temp scratch = scratch_begin(&arena, 1); CV_DebugS debug_s = cv_parse_debug_s(scratch.arena, raw_sect); for (String8Node *string_n = debug_s.data_list[CV_C13SubSectionIdxKind_Symbols].first; @@ -4547,12 +4547,12 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); - if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + if (str8_match_lit(".debug$S", sect_name, 0)) { rd_printf("# .debug$S No. %llx", i+1); rd_indent(); cv_print_symbols_section(arena, out, indent, arch, raw_sect); rd_unindent(); - } else if (str8_match(sect_name, str8_lit(".debug$T"), 0)) { + } else if (str8_match_lit(".debug$T", sect_name, 0)) { Temp scratch = scratch_begin(&arena, 1); CV_Signature sig = 0; str8_deserial_read_struct(raw_sect, 0, &sig); @@ -6319,19 +6319,19 @@ pe_print_exceptions_x8664(Arena *arena, rd_printf("Handler: %#llx%s%S", handler, handler_name.size ? " " : "", handler_name); U32 handler_data_flags = 0; - if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0)) { + if (str8_match_lit("__GSHandlerCheck_EH4", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; - } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0)) { + } else if (str8_match_lit("__CxxFrameHandler4", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_FuncInfo4; - } else if (str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0)) { + } else if (str8_match_lit("__CxxFrameHandler3", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_FuncInfo; - } else if (str8_match(handler_name, str8_lit("__C_specific_handler"), 0)) { + } else if (str8_match_lit("__C_specific_handler", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_ScopeTable; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck"), 0)) { + } else if (str8_match_lit("__GSHandlerCheck", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_GS; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_SEH"), 0)) { + } else if (str8_match_lit("__GSHandlerCheck_SEH", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_ScopeTable|ExceptionHandlerDataFlag_GS; - } else if (str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0)) { + } else if (str8_match_lit("__GSHandlerCheck_EH", handler_name, 0)) { handler_data_flags = ExceptionHandlerDataFlag_FuncInfo|ExceptionHandlerDataFlag_GS; } diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index 3277ba54..0534911a 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -163,7 +163,7 @@ entry_point(CmdLine *cmdline) if (str8_match(cmd->string, opt_name, StringMatchFlag_CaseInsensitive)) { opt = g_rd_dump_option_map[opt_idx].opt; break; - } else if (str8_match(cmd->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { + } else if (str8_match_lit("all", cmd->string, StringMatchFlag_CaseInsensitive)) { opt = ~0ull & ~(RD_Option_Help|RD_Option_Version); break; } From 269dc339856c3d4025947421417ca668a49f1b29 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 18 Jan 2025 23:21:06 -0800 Subject: [PATCH 31/53] set COMDAT selection on chunks created by import table --- src/linker/lnk_import_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk_import_table.c b/src/linker/lnk_import_table.c index 1cf40ff3..616de6fe 100644 --- a/src/linker/lnk_import_table.c +++ b/src/linker/lnk_import_table.c @@ -736,7 +736,7 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu ProfBeginFunction(); // emit load thunk symbol String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name); - LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); + LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_NODUPLICATES, 0); ProfEnd(); return load_thunk_symbol; } @@ -746,7 +746,7 @@ lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fun { ProfBeginFunction(); String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name); - LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); + LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_ANY, 0); ProfEnd(); return jmp_thunk_symbol; } @@ -756,7 +756,7 @@ lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu { ProfBeginFunction(); String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name); - LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); + LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_NODUPLICATES, 0); ProfEnd(); return tail_merge_symbol; } From 153bbc7b1db454487fa67e0327e9d1359088249f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 20 Jan 2025 19:31:52 -0800 Subject: [PATCH 32/53] pass over COFF layer - updated naming convention on structs, enums, and macros to conform with code base style - moved related structs closer to each other - moved parser code to separate file --- src/codeview/codeview.c | 48 +- src/coff/coff.c | 1449 ++++---------------------- src/coff/coff.h | 1111 +++++++------------- src/coff/coff_enum.c | 467 ++++----- src/coff/coff_enum.h | 19 +- src/coff/coff_parse.c | 904 ++++++++++++++++ src/coff/coff_parse.h | 315 ++++++ src/ctrl/ctrl_core.c | 18 +- src/demon/win32/demon_core_win32.c | 22 +- src/linker/lnk.c | 224 ++-- src/linker/lnk.h | 16 +- src/linker/lnk_config.c | 50 +- src/linker/lnk_debug_info.c | 2 +- src/linker/lnk_export_table.c | 10 +- src/linker/lnk_export_table.h | 14 +- src/linker/lnk_import_table.c | 68 +- src/linker/lnk_import_table.h | 4 +- src/linker/lnk_lib.c | 98 +- src/linker/lnk_obj.c | 53 +- src/linker/lnk_reloc.c | 64 +- src/linker/lnk_section_table.c | 20 +- src/linker/lnk_symbol_table.c | 24 +- src/linker/pdb_ext/pdb_builder.c | 14 +- src/linker/rdi/rdi_coff.c | 54 +- src/pe/pe.c | 80 +- src/raddbg/raddbg_main.c | 2 + src/raddump/raddump.c | 248 +++-- src/raddump/raddump.h | 21 +- src/raddump/raddump_main.c | 4 +- src/rdi_from_pdb/rdi_from_pdb.c | 6 +- src/rdi_from_pdb/rdi_from_pdb_main.c | 2 + 31 files changed, 2659 insertions(+), 2772 deletions(-) create mode 100644 src/coff/coff_parse.c create mode 100644 src/coff/coff_parse.h diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index 9ff233a3..4836c249 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -14,30 +14,30 @@ cv_arch_from_coff_machine(COFF_MachineType machine) CV_Arch arch = 0; switch(machine) { - case COFF_MachineType_X64: arch = CV_Arch_X64; break; - case COFF_MachineType_X86: arch = CV_Arch_8086; break; - case COFF_MachineType_AM33: arch = CV_Arch_AM33; break; - case COFF_MachineType_ARM: NotImplemented; break; - case COFF_MachineType_ARM64: arch = CV_Arch_ARM64; break; - case COFF_MachineType_ARMNT: arch = CV_Arch_ARMNT; break; - case COFF_MachineType_EBC: arch = CV_Arch_EBC; break; - case COFF_MachineType_IA64: arch = CV_Arch_IA64; break; - case COFF_MachineType_M32R: arch = CV_Arch_M32R; break; - case COFF_MachineType_MIPS16: arch = CV_Arch_MIPS16; break; - case COFF_MachineType_MIPSFPU: NotImplemented; break; - case COFF_MachineType_MIPSFPU16: NotImplemented; break; - case COFF_MachineType_POWERPC: NotImplemented; break; - case COFF_MachineType_POWERPCFP: arch = CV_Arch_PPCFP; break; - case COFF_MachineType_R4000: NotImplemented; break; - case COFF_MachineType_RISCV32: NotImplemented; break; - case COFF_MachineType_RISCV64: NotImplemented; break; - case COFF_MachineType_RISCV128: NotImplemented; break; - case COFF_MachineType_SH3: arch = CV_Arch_SH3; break; - case COFF_MachineType_SH3DSP: arch = CV_Arch_SH3DSP; break; - case COFF_MachineType_SH4: arch = CV_Arch_SH4; break; - case COFF_MachineType_SH5: NotImplemented; break; - case COFF_MachineType_THUMB: arch = CV_Arch_THUMB; break; - case COFF_MachineType_WCEMIPSV2: NotImplemented; break; + case COFF_Machine_X64: arch = CV_Arch_X64; break; + case COFF_Machine_X86: arch = CV_Arch_8086; break; + case COFF_Machine_Am33: arch = CV_Arch_AM33; break; + case COFF_Machine_Arm: NotImplemented; break; + case COFF_Machine_Arm64: arch = CV_Arch_ARM64; break; + case COFF_Machine_ArmNt: arch = CV_Arch_ARMNT; break; + case COFF_Machine_Ebc: arch = CV_Arch_EBC; break; + case COFF_Machine_Ia64: arch = CV_Arch_IA64; break; + case COFF_Machine_M32R: arch = CV_Arch_M32R; break; + case COFF_Machine_Mips16: arch = CV_Arch_MIPS16; break; + case COFF_Machine_MipsFpu: NotImplemented; break; + case COFF_Machine_MipsFpu16: NotImplemented; break; + case COFF_Machine_PowerPc: NotImplemented; break; + case COFF_Machine_PowerPcFp: arch = CV_Arch_PPCFP; break; + case COFF_Machine_R4000: NotImplemented; break; + case COFF_Machine_RiscV32: NotImplemented; break; + case COFF_Machine_RiscV64: NotImplemented; break; + case COFF_Machine_RiscV128: NotImplemented; break; + case COFF_Machine_Sh3: arch = CV_Arch_SH3; break; + case COFF_Machine_Sh3Dsp: arch = CV_Arch_SH3DSP; break; + case COFF_Machine_Sh4: arch = CV_Arch_SH4; break; + case COFF_Machine_Sh5: NotImplemented; break; + case COFF_Machine_Thumb: arch = CV_Arch_THUMB; break; + case COFF_Machine_WceMipsV2: NotImplemented; break; } return arch; } diff --git a/src/coff/coff.c b/src/coff/coff.c index 1e9c2487..0f2ba099 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -1,148 +1,28 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal B32 -coff_is_big_obj(String8 data) -{ - B32 is_big_obj = 0; - if (data.size >= sizeof(COFF_HeaderBigObj)) { - COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)(data.str); - is_big_obj = big_header->sig1 == COFF_MachineType_UNKNOWN && - big_header->sig2 == max_U16 && - big_header->version >= COFF_MIN_BIG_OBJ_VERSION && - MemoryCompare(big_header->magic, coff_big_obj_magic, sizeof(big_header->magic)) == 0; - } - return is_big_obj; -} - -internal B32 -coff_is_obj(String8 data) -{ - B32 is_obj = 0; - - if (data.size >= sizeof(COFF_Header)) { - COFF_Header *header = (COFF_Header*)(data.str); - - // validate machine - B32 is_machine_type_valid = 0; - switch (header->machine) { - case COFF_MachineType_UNKNOWN: - case COFF_MachineType_X86: case COFF_MachineType_X64: - case COFF_MachineType_AM33: case COFF_MachineType_ARM: - case COFF_MachineType_ARM64: case COFF_MachineType_ARMNT: - case COFF_MachineType_EBC: case COFF_MachineType_IA64: - case COFF_MachineType_M32R: case COFF_MachineType_MIPS16: - case COFF_MachineType_MIPSFPU:case COFF_MachineType_MIPSFPU16: - case COFF_MachineType_POWERPC:case COFF_MachineType_POWERPCFP: - case COFF_MachineType_R4000: case COFF_MachineType_RISCV32: - case COFF_MachineType_RISCV64:case COFF_MachineType_RISCV128: - case COFF_MachineType_SH3: case COFF_MachineType_SH3DSP: - case COFF_MachineType_SH4: case COFF_MachineType_SH5: - case COFF_MachineType_THUMB: case COFF_MachineType_WCEMIPSV2: - { - is_machine_type_valid = 1; - }break; - } - - if (is_machine_type_valid) { - // validate section count - U64 section_count = header->section_count; - U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader); - if (data.size >= section_hdr_opl_off) { - - COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(data.str + sizeof(*header)); - COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count; - - // validate section ranges - B32 is_sect_range_valid = 1; - for (COFF_SectionHeader *sec_hdr = section_hdrs; - sec_hdr < section_hdr_opl; - sec_hdr += 1) { - if (!(sec_hdr->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) { - U64 min = sec_hdr->foff; - U64 max = min + sec_hdr->fsize; - if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= data.size)) { - is_sect_range_valid = 0; - break; - } - } - } - - if (is_sect_range_valid) { - // validate symbol table - U64 symbol_table_off = header->symbol_table_foff; - U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count; - U64 symbol_table_opl_off = symbol_table_off + symbol_table_size; - - // don't validate symbol table when there is none - if (symbol_table_off == 0 && symbol_table_size == 0) { - symbol_table_off = section_hdr_opl_off; - symbol_table_opl_off = section_hdr_opl_off; - } - - is_obj = (section_hdr_opl_off <= symbol_table_off && - symbol_table_off <= symbol_table_opl_off && - symbol_table_opl_off <= data.size); - } - } - } - } - - return is_obj; -} - -internal COFF_HeaderInfo -coff_header_info_from_data(String8 data) -{ - COFF_HeaderInfo info = {0}; - if (coff_is_big_obj(data)) { - COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str; - info.type = COFF_DataType_BIG_OBJ; - info.machine = big_header->machine; - info.header_size = sizeof(COFF_HeaderBigObj); - info.section_array_off = sizeof(COFF_HeaderBigObj); - info.section_count_no_null = big_header->section_count; - info.string_table_off = big_header->symbol_table_foff + sizeof(COFF_Symbol32) * big_header->symbol_count; - info.symbol_size = sizeof(COFF_Symbol32); - info.symbol_off = big_header->symbol_table_foff; - info.symbol_count = big_header->symbol_count; - } else if (coff_is_obj(data)) { - COFF_Header *header = (COFF_Header*)data.str; - info.type = COFF_DataType_OBJ; - info.machine = header->machine; - info.header_size = sizeof(COFF_Header); - info.section_array_off = sizeof(COFF_Header); - info.section_count_no_null = header->section_count; - info.string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16) * header->symbol_count; - info.symbol_size = sizeof(COFF_Symbol16); - info.symbol_off = header->symbol_table_foff; - info.symbol_count = header->symbol_count; - } - return info; -} - internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags) { U32 align = 0; - U32 align_index = COFF_SectionFlags_Extract_ALIGN(flags); + U32 align_index = COFF_SectionFlags_ExtractAlign(flags); switch (align_index) { default: break; case 0: align = 1; break; // alignment isn't specified, default to 1 - case COFF_SectionAlign_1BYTES: align = 1; break; - case COFF_SectionAlign_2BYTES: align = 2; break; - case COFF_SectionAlign_4BYTES: align = 4; break; - case COFF_SectionAlign_8BYTES: align = 8; break; - case COFF_SectionAlign_16BYTES: align = 16; break; - case COFF_SectionAlign_32BYTES: align = 32; break; - case COFF_SectionAlign_64BYTES: align = 64; break; - case COFF_SectionAlign_128BYTES: align = 128; break; - case COFF_SectionAlign_256BYTES: align = 256; break; - case COFF_SectionAlign_512BYTES: align = 512; break; - case COFF_SectionAlign_1024BYTES: align = 1024; break; - case COFF_SectionAlign_2048BYTES: align = 2048; break; - case COFF_SectionAlign_4096BYTES: align = 4096; break; - case COFF_SectionAlign_8192BYTES: align = 8192; break; + case COFF_SectionAlign_1Bytes: align = 1; break; + case COFF_SectionAlign_2Bytes: align = 2; break; + case COFF_SectionAlign_4Bytes: align = 4; break; + case COFF_SectionAlign_8Bytes: align = 8; break; + case COFF_SectionAlign_16Bytes: align = 16; break; + case COFF_SectionAlign_32Bytes: align = 32; break; + case COFF_SectionAlign_64Bytes: align = 64; break; + case COFF_SectionAlign_128Bytes: align = 128; break; + case COFF_SectionAlign_256Bytes: align = 256; break; + case COFF_SectionAlign_512Bytes: align = 512; break; + case COFF_SectionAlign_1024Bytes: align = 1024; break; + case COFF_SectionAlign_2048Bytes: align = 2048; break; + case COFF_SectionAlign_4096Bytes: align = 4096; break; + case COFF_SectionAlign_8192Bytes: align = 8192; break; } return align; } @@ -152,101 +32,35 @@ coff_section_flag_from_align_size(U64 align) { COFF_SectionFlags flags = 0; switch (align) { - case 1: flags = COFF_SectionAlign_1BYTES; break; - case 2: flags = COFF_SectionAlign_2BYTES; break; - case 4: flags = COFF_SectionAlign_4BYTES; break; - case 8: flags = COFF_SectionAlign_8BYTES; break; - case 16: flags = COFF_SectionAlign_16BYTES; break; - case 32: flags = COFF_SectionAlign_32BYTES; break; - case 64: flags = COFF_SectionAlign_64BYTES; break; - case 128: flags = COFF_SectionAlign_128BYTES; break; - case 256: flags = COFF_SectionAlign_256BYTES; break; - case 512: flags = COFF_SectionAlign_512BYTES; break; - case 1024: flags = COFF_SectionAlign_1024BYTES; break; - case 2048: flags = COFF_SectionAlign_2048BYTES; break; - case 4096: flags = COFF_SectionAlign_4096BYTES; break; - case 8192: flags = COFF_SectionAlign_8192BYTES; break; + case 1: flags = COFF_SectionAlign_1Bytes; break; + case 2: flags = COFF_SectionAlign_2Bytes; break; + case 4: flags = COFF_SectionAlign_4Bytes; break; + case 8: flags = COFF_SectionAlign_8Bytes; break; + case 16: flags = COFF_SectionAlign_16Bytes; break; + case 32: flags = COFF_SectionAlign_32Bytes; break; + case 64: flags = COFF_SectionAlign_64Bytes; break; + case 128: flags = COFF_SectionAlign_128Bytes; break; + case 256: flags = COFF_SectionAlign_256Bytes; break; + case 512: flags = COFF_SectionAlign_512Bytes; break; + case 1024: flags = COFF_SectionAlign_1024Bytes; break; + case 2048: flags = COFF_SectionAlign_2048Bytes; break; + case 4096: flags = COFF_SectionAlign_4096Bytes; break; + case 8192: flags = COFF_SectionAlign_8192Bytes; break; } - flags <<= COFF_SectionFlag_ALIGN_SHIFT; + flags <<= COFF_SectionFlag_AlignShift; return flags; } -internal COFF_SymbolValueInterpType -coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class) -{ - if (storage_class == COFF_SymStorageClass_SECTION && section_number == COFF_SYMBOL_UNDEFINED_SECTION) { - return COFF_SymbolValueInterp_UNDEFINED; - } - if (storage_class == COFF_SymStorageClass_EXTERNAL && value == 0 && section_number == COFF_SYMBOL_UNDEFINED_SECTION) { - return COFF_SymbolValueInterp_UNDEFINED; - } - if (storage_class == COFF_SymStorageClass_EXTERNAL && value != 0 && section_number == COFF_SYMBOL_UNDEFINED_SECTION) { - return COFF_SymbolValueInterp_COMMON; - } - if (section_number == COFF_SYMBOL_ABS_SECTION) { - return COFF_SymbolValueInterp_ABS; - } - if (section_number == COFF_SYMBOL_DEBUG_SECTION) { - return COFF_SymbolValueInterp_DEBUG; - } - if (storage_class == COFF_SymStorageClass_WEAK_EXTERNAL) { - return COFF_SymbolValueInterp_WEAK; - } - return COFF_SymbolValueInterp_REGULAR; -} - -internal U64 -coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff) -{ - U64 foff = 0; - for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) - { - COFF_SectionHeader *sect = §ions[sect_idx]; - if(sect->voff <= voff && voff < sect->voff+sect->vsize) - { - if(!(sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) - { - foff = sect->foff + (voff - sect->voff); - } - break; - } - } - return foff; -} - -internal COFF_SectionHeader * -coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n) -{ - COFF_SectionHeader *result = &coff_section_header_nil; - if(1 <= n && section_headers_off + n*sizeof(COFF_SectionHeader) <= data.size) - { - result = (COFF_SectionHeader*)(data.str + section_headers_off + (n-1)*sizeof(COFF_SectionHeader)); - } - return result; -} - internal String8 -coff_name_from_section_header(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base) +coff_name_from_section_header(String8 raw_coff, COFF_SectionHeader *header, U64 string_table_off) { - U64 size = 0; - for (; size < sizeof(header->name); size += 1) { - if (header->name[size] == '\0') { - break; - } - } - String8 name = str8(header->name, size); - + String8 name = str8_cstring_capped(header->name, header->name + sizeof(header->name)); if (name.str[0] == '/') { - String8 ascii_name_offset = str8_skip(name, 1); - U64 name_offset = u64_from_str8(ascii_name_offset, 10); - - name_offset += string_table_base; - if (name_offset < coff_data.size) { - char *ptr = (char *)coff_data.str + name_offset; - name = str8_cstring(ptr); - } + String8 ascii_off = str8_skip(name, 1); + U64 name_rel_off = u64_from_str8(ascii_off, 10); + U64 name_off = name_rel_off + string_table_off; + name = str8_cstring_capped(raw_coff.str + name_off, raw_coff.str + raw_coff.size); } - return name; } @@ -261,11 +75,11 @@ coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_o // P: Precompiled types // F: FPO data // H: Clang extension produced with /debug:ghash, array of type hashes - *name_out = full_name; + *name_out = full_name; *postfix_out = str8_lit(""); for (U64 i = 0; i < full_name.size; ++i) { if (full_name.str[i] == '$') { - *name_out = str8(full_name.str, i); + *name_out = str8(full_name.str, i); *postfix_out = str8(full_name.str + i + 1, full_name.size - i - 1); // TLS sections don't have a postfix but we still have to sort them based @@ -279,25 +93,13 @@ coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_o } } -internal COFF_RelocNode * -coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc) -{ - COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1); - node->data = reloc; - SLLQueuePush(list->first, list->last, node); - ++list->count; - return node; -} - -//////////////////////////////// - internal String8 -coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name) +coff_read_symbol_name(String8 raw_coff, U64 string_table_off, COFF_SymbolName *name) { String8 name_str = str8_lit(""); if (name->long_name.zeroes == 0) { - U64 string_table_offset = string_table_base_offset + name->long_name.string_table_offset; - str8_deserial_read_cstr(data, string_table_offset, &name_str); + U64 name_string_off = string_table_off + name->long_name.string_table_offset; + str8_deserial_read_cstr(raw_coff, name_string_off, &name_str); } else { U32 i; for (i = 0; i < sizeof(name->short_name); ++i) { @@ -310,160 +112,28 @@ coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolNam return name_str; } -internal COFF_ParsedSymbol -coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32) -{ - COFF_ParsedSymbol result = {0}; - result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name); - result.value = sym32->value; - result.section_number = sym32->section_number; - result.type = sym32->type; - result.storage_class = sym32->storage_class; - result.aux_symbol_count = sym32->aux_symbol_count; - return result; -} - -internal COFF_ParsedSymbol -coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16) -{ - COFF_ParsedSymbol result = {0}; - result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name); - result.value = sym16->value; - if (sym16->section_number == COFF_SYMBOL_DEBUG_SECTION_16) { - result.section_number = COFF_SYMBOL_DEBUG_SECTION; - } else if (sym16->section_number == COFF_SYMBOL_ABS_SECTION_16) { - result.section_number = COFF_SYMBOL_ABS_SECTION; - } else { - result.section_number = (U32)sym16->section_number; - } - result.type = sym16->type; - result.storage_class = sym16->storage_class; - result.aux_symbol_count = sym16->aux_symbol_count; - return result; -} - -internal void -coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16) -{ - sym32->name = sym16->name; - sym32->value = sym16->value; - if (sym16->section_number == COFF_SYMBOL_DEBUG_SECTION_16) { - sym32->section_number = COFF_SYMBOL_DEBUG_SECTION; - } else if (sym16->section_number == COFF_SYMBOL_ABS_SECTION_16) { - sym32->section_number = COFF_SYMBOL_ABS_SECTION; - } else { - sym32->section_number = (U32)sym16->section_number; - } - sym32->type.v = sym16->type.v; - sym32->storage_class = sym16->storage_class; - sym32->aux_symbol_count = sym16->aux_symbol_count; -} - -internal COFF_Symbol32Array -coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count) -{ - COFF_Symbol32Array result = {0}; - result.count = symbol_count; - result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8); - - Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count); - String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range); - COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str; - - for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) { - COFF_Symbol16 *sym16 = &sym16_arr[isymbol]; - COFF_Symbol32 *sym32 = &result.v[isymbol]; - - coff_symbol32_from_coff_symbol16(sym32, sym16); - - // copy aux symbols - for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) { - COFF_Symbol16 *aux16 = sym16_arr + iaux; - COFF_Symbol32 *aux32 = result.v + iaux; - - // 32bit COFF uses 16bit aux symbols - MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16)); - MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16)); - } - - // take into account aux symbols - isymbol += sym32->aux_symbol_count; - } - - return result; -} - -internal COFF_Symbol32Array -coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count) -{ - COFF_Symbol32Array result; - result.count = symbol_count; - result.v = (COFF_Symbol32 *)(data.str + symbol_array_off); - return result; -} - -internal COFF_Symbol32Array -coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_off, U64 symbol_count, U64 symbol_size) -{ - COFF_Symbol32Array result = {0}; - switch (symbol_size) { - case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_off, symbol_count); break; - case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_off, symbol_count); break; - } - return result; -} - -internal COFF_Symbol16Node * -coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol) -{ - COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1); - node->next = 0; - node->data = symbol; - SLLQueuePush(list->first, list->last, node); - list->count += 1; - return node; -} - -internal COFF_RelocInfo -coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header) -{ - COFF_RelocInfo result = {0}; - if (header->flags & COFF_SectionFlag_LNK_NRELOC_OVFL && header->reloc_count == max_U16) { - COFF_Reloc counter; - U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter); - if (read_size == sizeof(counter) && counter.apply_off > 0) { - result.array_off = header->relocs_foff + sizeof(COFF_Reloc); - result.count = counter.apply_off - 1; // exclude counter entry - } - } else { - result.array_off = header->relocs_foff; - result.count = header->reloc_count; - } - return result; -} - internal U64 -coff_apply_size_from_reloc_x64(COFF_RelocTypeX64 x) +coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x) { switch (x) { - case COFF_RelocTypeX64_ABS: return 4; - case COFF_RelocTypeX64_ADDR64: return 8; - case COFF_RelocTypeX64_ADDR32: return 4; - case COFF_RelocTypeX64_ADDR32NB: return 4; - case COFF_RelocTypeX64_REL32: return 4; - case COFF_RelocTypeX64_REL32_1: return 4; - case COFF_RelocTypeX64_REL32_2: return 4; - case COFF_RelocTypeX64_REL32_3: return 4; - case COFF_RelocTypeX64_REL32_4: return 4; - case COFF_RelocTypeX64_REL32_5: return 4; - case COFF_RelocTypeX64_SECTION: return 2; - case COFF_RelocTypeX64_SECREL: return 4; - case COFF_RelocTypeX64_SREL32: return 4; + case COFF_Reloc_X64_Abs: return 4; + case COFF_Reloc_X64_Addr64: return 8; + case COFF_Reloc_X64_Addr32: return 4; + case COFF_Reloc_X64_Addr32Nb: return 4; + case COFF_Reloc_X64_Rel32: return 4; + case COFF_Reloc_X64_Rel32_1: return 4; + case COFF_Reloc_X64_Rel32_2: return 4; + case COFF_Reloc_X64_Rel32_3: return 4; + case COFF_Reloc_X64_Rel32_4: return 4; + case COFF_Reloc_X64_Rel32_5: return 4; + case COFF_Reloc_X64_Section: return 2; + case COFF_Reloc_X64_SecRel: return 4; + case COFF_Reloc_X64_SRel32: return 4; - case COFF_RelocTypeX64_SECREL7: - case COFF_RelocTypeX64_TOKEN: - case COFF_RelocTypeX64_PAIR: - case COFF_RelocTypeX64_SSPAN32: + case COFF_Reloc_X64_SecRel7: + case COFF_Reloc_X64_Token: + case COFF_Reloc_X64_Pair: + case COFF_Reloc_X64_SSpan32: NotImplemented; break; } @@ -471,29 +141,29 @@ coff_apply_size_from_reloc_x64(COFF_RelocTypeX64 x) } internal U64 -coff_apply_size_from_reloc_x86(COFF_RelocTypeX86 x) +coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x) { switch (x) { - case COFF_RelocTypeX86_ABS: return 4; - case COFF_RelocTypeX86_DIR16: return 2; - case COFF_RelocTypeX86_REL16: return 2; - case COFF_RelocTypeX86_DIR32: return 4; - case COFF_RelocTypeX86_DIR32NB: return 4; - case COFF_RelocTypeX86_SEG12: return 0; - case COFF_RelocTypeX86_SECTION: return 2; - case COFF_RelocTypeX86_SECREL: return 4; - case COFF_RelocTypeX86_TOKEN: return 4; - case COFF_RelocTypeX86_SECREL7: return 1; - case COFF_RelocTypeX86_REL32: return 4; + case COFF_Reloc_X86_Abs: return 4; + case COFF_Reloc_X86_Dir16: return 2; + case COFF_Reloc_X86_Rel16: return 2; + case COFF_Reloc_X86_Dir32: return 4; + case COFF_Reloc_X86_Dir32Nb: return 4; + case COFF_Reloc_X86_Seg12: return 0; + case COFF_Reloc_X86_Section: return 2; + case COFF_Reloc_X86_SecRel: return 4; + case COFF_Reloc_X86_Token: return 4; + case COFF_Reloc_X86_SecRel7: return 1; + case COFF_Reloc_X86_Rel32: return 4; - case COFF_RelocTypeX86_UNKNOWN0: - case COFF_RelocTypeX86_UNKNOWN2: - case COFF_RelocTypeX86_UNKNOWN3: - case COFF_RelocTypeX86_UNKNOWN4: - case COFF_RelocTypeX86_UNKNOWN6: - case COFF_RelocTypeX86_UNKNOWN7: - case COFF_RelocTypeX86_UNKNOWN8: - case COFF_RelocTypeX86_UNKNOWN9: + case COFF_Reloc_X86_Unknown0: + case COFF_Reloc_X86_Unknown2: + case COFF_Reloc_X86_Unknown3: + case COFF_Reloc_X86_Unknown4: + case COFF_Reloc_X86_Unknown6: + case COFF_Reloc_X86_Unknown7: + case COFF_Reloc_X86_Unknown8: + case COFF_Reloc_X86_Unknown9: NotImplemented; break; } @@ -504,20 +174,132 @@ internal U64 coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x) { switch (machine) { - case COFF_MachineType_X64: return coff_apply_size_from_reloc_x64(x); - case COFF_MachineType_X86: return coff_apply_size_from_reloc_x86(x); + case COFF_Machine_X64: return coff_apply_size_from_reloc_x64(x); + case COFF_Machine_X86: return coff_apply_size_from_reloc_x86(x); default: NotImplemented; } return 0; } +internal String8 +coff_make_import_lookup(Arena *arena, U16 hint, String8 name) +{ + U64 buffer_size = sizeof(hint) + (name.size + 1); + U8 *buffer = push_array(arena, U8, buffer_size); + *(U16*)buffer = hint; + MemoryCopy(buffer + sizeof(hint), name.str, name.size); + buffer[buffer_size - 1] = 0; + String8 result = str8(buffer, buffer_size); + return result; +} + +internal U32 +coff_make_ordinal32(U16 hint) +{ + U32 ordinal = (1 << 31) | hint; + return ordinal; +} + +internal U64 +coff_make_ordinal64(U16 hint) +{ + U64 ordinal = (1ULL << 63) | hint; + return ordinal; +} + +internal String8 +coff_make_import_header_by_name(Arena *arena, + String8 dll_name, + COFF_MachineType machine, + COFF_TimeStamp time_stamp, + String8 name, + U16 hint, + COFF_ImportType type) +{ + COFF_ImportHeaderFlags flags = 0; + flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift; + flags |= COFF_ImportBy_Name << COFF_ImportHeader_ImportByShift; + + COFF_ImportHeader header = {0}; + header.sig1 = COFF_Machine_Unknown; + header.sig2 = max_U16; + header.version = 0; + header.machine = machine; + header.time_stamp = time_stamp; + header.data_size = safe_cast_u32(name.size + dll_name.size + 2); + header.hint_or_ordinal = hint; + header.flags = flags; + + // alloc memory + U64 buffer_size = sizeof(header) + header.data_size; + U8 *buffer = push_array_no_zero(arena, U8, buffer_size); + + // copy header + MemoryCopy(buffer, &header, sizeof(header)); + + // copy function name + U8 *func_name = buffer + sizeof(header); + MemoryCopy(func_name, name.str, name.size); + func_name[name.size] = 0; + + // copy dll name + U8 *dll_name_buffer = buffer + sizeof(header) + name.size + 1; + MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size); + dll_name_buffer[dll_name.size] = 0; + + String8 import_data = str8(buffer, buffer_size); + return import_data; +} + +internal String8 +coff_make_import_header_by_ordinal(Arena *arena, + String8 dll_name, + COFF_MachineType machine, + COFF_TimeStamp time_stamp, + U16 ordinal, + COFF_ImportType type) +{ + COFF_ImportHeaderFlags flags = 0; + flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift; + flags |= COFF_ImportBy_Ordinal << COFF_ImportHeader_ImportByShift; + + COFF_ImportHeader header = {0}; + header.sig1 = COFF_Machine_Unknown; + header.sig2 = max_U16; + header.version = 0; + header.machine = machine; + header.time_stamp = time_stamp; + header.data_size = safe_cast_u32(dll_name.size + 2); + header.hint_or_ordinal = ordinal; + header.flags = flags; + + // alloc memory + U64 buffer_size = sizeof(header) + header.data_size; + U8 *buffer = push_array_no_zero(arena, U8, buffer_size); + + // copy header + MemoryCopyStruct(buffer, &header); + + // no function name write zero + U8 *func_name = buffer + sizeof(header); + func_name[0] = 0; + + // copy dll name + U8 *dll_name_buffer = buffer + sizeof(header) + /* name.size */ + 1; + MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size); + dll_name_buffer[dll_name.size] = 0; + + String8 import_data = str8(buffer, buffer_size); + return import_data; +} + internal U64 coff_word_size_from_machine(COFF_MachineType machine) { U64 result = 0; switch (machine) { - case COFF_MachineType_X64: result = 8; break; - case COFF_MachineType_X86: result = 4; break; + case COFF_Machine_X64: result = 8; break; + case COFF_Machine_X86: result = 4; break; } return result; } @@ -544,830 +326,37 @@ coff_default_dll_base_from_machine(COFF_MachineType machine) return dll_base; } -internal String8 -coff_make_import_lookup(Arena *arena, U16 hint, String8 name) -{ - U64 buffer_size = sizeof(hint) + (name.size + 1); - U8 *buffer = push_array(arena, U8, buffer_size); - *(U16*)buffer = hint; - MemoryCopy(buffer + sizeof(hint), name.str, name.size); - buffer[buffer_size - 1] = 0; - String8 result = str8(buffer, buffer_size); - return result; -} - -internal U32 -coff_make_ordinal_32(U16 hint) -{ - U32 ordinal = (1 << 31) | hint; - return ordinal; -} - -internal U64 -coff_make_ordinal_64(U16 hint) -{ - U64 ordinal = (1ULL << 63) | hint; - return ordinal; -} - -//////////////////////////////// - -internal String8 -coff_make_import_header_by_name(Arena *arena, - String8 dll_name, - COFF_MachineType machine, - COFF_TimeStamp time_stamp, - String8 name, - U16 hint, - COFF_ImportHeaderType type) -{ - struct { - U16 sig1; - U16 sig2; - U16 version; - COFF_MachineType machine; - COFF_TimeStamp time_stamp; - U32 sizeof_data; - U16 hint_ordinal; - U16 flags; - } import_header = { - COFF_MachineType_UNKNOWN, // sig1 - max_U16, // sig2 - 0, // version - machine, - time_stamp, - safe_cast_u32(name.size + dll_name.size + 2), // sizeof_data - 0, // hint_ordinal - 0, // flags - }; - - import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT; - import_header.flags |= COFF_ImportHeaderNameType_NAME << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT; - import_header.hint_ordinal = hint; - - // alloc memory - U64 buffer_size = sizeof(import_header) + import_header.sizeof_data; - U8 *buffer = push_array_no_zero(arena, U8, buffer_size); - - // copy header - MemoryCopy(buffer, &import_header, sizeof(import_header)); - - // copy function name - U8 *func_name = buffer + sizeof(import_header); - MemoryCopy(func_name, name.str, name.size); - func_name[name.size] = 0; - - // copy dll name - U8 *dll_name_buffer = buffer + sizeof(import_header) + name.size + 1; - MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size); - dll_name_buffer[dll_name.size] = 0; - - String8 import_data = str8(buffer, buffer_size); - return import_data; -} - -internal String8 -coff_make_import_header_by_ordinal(Arena *arena, - String8 dll_name, - COFF_MachineType machine, - COFF_TimeStamp time_stamp, - U16 ordinal, - COFF_ImportHeaderType type) -{ - struct { - U16 sig1; - U16 sig2; - U16 version; - COFF_MachineType machine; - COFF_TimeStamp time_stamp; - U32 sizeof_data; - U16 hint_ordinal; - U16 flags; - } import_header = { - COFF_MachineType_UNKNOWN, // sig1 - max_U16, // sig2 - 0, // version - machine, - time_stamp, - safe_cast_u32(/* name.size + */ dll_name.size + 2), // sizeof_data - 0, // hint_ordinal - 0, // flags - }; - - import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT; - import_header.flags |= COFF_ImportHeaderNameType_ORDINAL << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT; - import_header.hint_ordinal = ordinal; - - // alloc memory - U64 buffer_size = sizeof(import_header) + import_header.sizeof_data; - U8 *buffer = push_array_no_zero(arena, U8, buffer_size); - - // copy header - MemoryCopyStruct(buffer, &import_header); - - // no function name write zero - U8 *func_name = buffer + sizeof(import_header); - func_name[0] = 0; - - // copy dll name - U8 *dll_name_buffer = buffer + sizeof(import_header) + /* name.size */ + 1; - MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size); - dll_name_buffer[dll_name.size] = 0; - - String8 import_data = str8(buffer, buffer_size); - return import_data; -} - -//////////////////////////////// -//~ Resources - -internal String8 -coff_resource_string_from_str16(Arena *arena, String16 string) -{ - AssertAlways(string.size <= max_U16); - U16 size16 = (U16)string.size; - - U16 *buffer = push_array_no_zero(arena, U16, size16 + 1); - MemoryCopy(buffer + 0, &size16, sizeof(size16)); - MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0])); - - return str8_array(buffer, size16 + 1); -} - -internal String8 -coff_resource_string_from_str8(Arena *arena, String8 string) -{ - Temp scratch = scratch_begin(&arena, 1); - String16 string16 = str16_from_8(scratch.arena, string); - String8 result = coff_resource_string_from_str16(arena, string16); - scratch_end(scratch); - return result; -} - -internal String8 -coff_resource_number_from_u16(Arena *arena, U16 number) -{ - U16 *buffer = push_array_no_zero(arena, U16, 2); - buffer[0] = max_U16; - buffer[1] = number; - return str8_array(buffer, 2); -} - -internal B32 -coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b) -{ - B32 is_equal = 0; - if (a.type == b.type) { - switch (a.type) { - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_NUMBER: is_equal = (a.u.number == b.u.number); break; - case COFF_ResourceIDType_STRING: is_equal = str8_match(a.u.string, b.u.string, 0); break; - default: Assert(!"invalid resource id type"); - } - } - return is_equal; -} - -internal COFF_ResourceID -coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16) -{ - COFF_ResourceID id = {0}; - id.type = id_16->type; - switch (id_16->type) { - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_NUMBER: { - id.u.number = id_16->u.number; - } break; - case COFF_ResourceIDType_STRING: { - id.u.string = str8_from_16(arena, id_16->u.string); - } break; - default: InvalidPath; - } - return id; -} - -internal U64 -coff_read_resource_id_utf16(String8 data, U64 off, COFF_ResourceID_16 *id_out) -{ - U64 cursor = off; - - U16 flag = 0; - str8_deserial_read_struct(data, cursor, &flag); - - if (flag == max_U16) { - id_out->type = COFF_ResourceIDType_NUMBER; - cursor += sizeof(flag); - cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number); - } else { - id_out->type = COFF_ResourceIDType_STRING; - cursor += str8_deserial_read_windows_utf16_string16(data, cursor, &id_out->u.string); - } - - U64 read_size = cursor - off; - read_size = AlignPow2(read_size, COFF_RES_ALIGN); - return read_size; -} - -internal U64 -coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out) -{ - String8 raw_header = str8_skip(raw_res, off); - U64 header_cursor = 0; - - // prefix - COFF_ResourceHeaderPrefix prefix = {0}; - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix); - - Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix)); - raw_header = str8_prefix(raw_header, prefix.header_size); - - // header - COFF_ResourceID_16 type_16 = {0}; - COFF_ResourceID_16 name_16 = {0}; - header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16); - header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16); - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version); - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags); - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id); - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version); - header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics); - Assert(prefix.header_size == header_cursor); - - // convert utf-16 resource ids to utf-8 - res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16); - res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16); - - // read data - U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data); - Assert(prefix.data_size == data_read_size); - - // compute read size - U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_RES_ALIGN); - return read_size; -} - -internal COFF_ResourceList -coff_resource_list_from_data(Arena *arena, String8 data) -{ - COFF_ResourceList list = {0}; - U64 cursor; - for (cursor = 0 ; cursor < data.size; ) { - COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1); - cursor += coff_read_resource(data, cursor, arena, &node->data); - SLLQueuePush(list.first, list.last, node); - ++list.count; - } - Assert(cursor == data.size); - return list; -} - -internal String8 -coff_write_resource_id(Arena *arena, COFF_ResourceID id) -{ - String8 result = str8_zero(); - switch (id.type) { - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_NUMBER: { - result = coff_resource_number_from_u16(arena, id.u.number); - } break; - case COFF_ResourceIDType_STRING: { - result = coff_resource_string_from_str8(arena, id.u.string); - } break; - default: InvalidPath; - } - return result; -} - -internal String8 -coff_write_resource(Arena *arena, - COFF_ResourceID type, - COFF_ResourceID name, - U32 data_version, - COFF_ResourceMemoryFlags memory_flags, - U16 language_id, - U32 version, - U32 characteristics, - String8 data) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8List list = {0}; - - COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1); - String8 packed_type = coff_write_resource_id(scratch.arena, type); - String8 packed_name = coff_write_resource_id(scratch.arena, name); - - // prefix + header - str8_list_push(scratch.arena, &list, str8_struct(prefix)); - str8_list_push(scratch.arena, &list, packed_type); - str8_list_push(scratch.arena, &list, packed_name); - str8_list_push(scratch.arena, &list, str8_struct(&data_version)); - str8_list_push(scratch.arena, &list, str8_struct(&memory_flags)); - str8_list_push(scratch.arena, &list, str8_struct(&language_id)); - str8_list_push(scratch.arena, &list, str8_struct(&version)); - str8_list_push(scratch.arena, &list, str8_struct(&characteristics)); - - prefix->data_size = safe_cast_u32(data.size); - prefix->header_size = safe_cast_u32(list.total_size); - - // data - str8_list_push(scratch.arena, &list, data); - - // magic - str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic)); - - // align - U64 align_size = AlignPow2(list.total_size, COFF_RES_ALIGN) - list.total_size; - U8 *align = push_array(scratch.arena, U8, align_size); - str8_list_push(scratch.arena, &list, str8(align, align_size)); - - // join - String8 res = str8_list_join(arena, &list, 0); - - scratch_end(scratch); - return res; -} - -//////////////////////////////// - -internal COFF_DataType -coff_data_type_from_data(String8 data) -{ - B32 is_big_obj = coff_is_big_obj(data); - if (is_big_obj) { - return COFF_DataType_BIG_OBJ; - } - B32 is_import = coff_is_import(data); - if (is_import) { - return COFF_DataType_IMPORT; - } - return COFF_DataType_OBJ; -} - -internal B32 -coff_is_import(String8 data) -{ - B32 is_import = 0; - if (data.size >= sizeof(U16)*2) { - U16 *sig1 = (U16*)data.str; - U16 *sig2 = sig1 + 1; - is_import = *sig1 == COFF_MachineType_UNKNOWN && *sig2 == 0xffff; - } - return is_import; -} - -internal B32 -coff_is_archive(String8 data) -{ - B32 is_archive = 0; - U8 sig[sizeof(g_coff_archive_sig)]; - if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) { - is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0; - } - return is_archive; -} - -internal B32 -coff_is_thin_archive(String8 data) -{ - B32 is_archive = 0; - U8 sig[sizeof(g_coff_thin_archive_sig)]; - if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) { - is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0; - } - return is_archive; -} - -internal COFF_ArchiveType -coff_archive_type_from_data(String8 data) -{ - if (coff_is_archive(data)) { - return COFF_Archive_Regular; - } else if (coff_is_thin_archive(data)) { - return COFF_Archive_Thin; - } - return COFF_Archive_Null; -} - -internal U64 -coff_parse_archive_member_header(String8 data, U64 offset, B32 is_regular_archive, COFF_ArchiveMemberHeader *header_out) -{ - static const U64 name_size = 16; - static const U64 date_size = 12; - static const U64 user_id_size = 6; - static const U64 group_id_size = 6; - static const U64 mode_size = 8; - static const U64 size_size = 10; - static const String8 end_magic = str8_lit_comp("`\n"); - U64 total_header_size = name_size + date_size + user_id_size + group_id_size + mode_size + size_size + end_magic.size; - - U64 cursor = offset; - if (cursor + total_header_size <= data.size) { - String8 name = str8_zero(); - String8 date = str8_zero(); - String8 user_id = str8_zero(); - String8 group_id = str8_zero(); - String8 mode = str8_zero(); - String8 size = str8_zero(); - String8 end = str8_zero(); - - cursor += str8_deserial_read_block(data, cursor, name_size, &name ); - cursor += str8_deserial_read_block(data, cursor, date_size, &date ); - cursor += str8_deserial_read_block(data, cursor, user_id_size, &user_id ); - cursor += str8_deserial_read_block(data, cursor, group_id_size, &group_id); - cursor += str8_deserial_read_block(data, cursor, mode_size, &mode ); - cursor += str8_deserial_read_block(data, cursor, size_size, &size ); - cursor += str8_deserial_read_block(data, cursor, 2, &end ); - - name = str8_skip_chop_whitespace(name); - date = str8_skip_chop_whitespace(date); - user_id = str8_skip_chop_whitespace(user_id); - group_id = str8_skip_chop_whitespace(group_id); - mode = str8_skip_chop_whitespace(mode); - size = str8_skip_chop_whitespace(size); - - header_out->name = name; - header_out->time_stamp = u32_from_str8(date, 10); - header_out->user_id = u32_from_str8(user_id, 10); - header_out->group_id = u32_from_str8(group_id, 10); - header_out->mode = mode; - header_out->is_end_correct = str8_match(end, end_magic, 0); - header_out->data_range = rng_1u64(cursor, cursor + u32_from_str8(size, 10)); - - if (is_regular_archive) { - cursor = header_out->data_range.max; - } - } - - U64 result = AlignPow2((cursor - offset), COFF_ARCHIVE_ALIGN); - return result; -} - -internal B32 -coff_parse_archive_member_data(String8 data, U64 cursor, COFF_ArchiveMember *member_out) -{ - B32 is_parsed = 0; - - COFF_ArchiveMemberHeader header; header.is_end_correct = 0; - coff_parse_archive_member_header(data, cursor, 1, &header); - - if (header.is_end_correct) { - member_out->header = header; - member_out->offset = cursor; - member_out->data = str8_substr(data, header.data_range); - - cursor = AlignPow2(header.data_range.max, COFF_ARCHIVE_ALIGN); - - is_parsed = 1; - } else { - MemoryZeroStruct(&member_out->header); - member_out->offset = max_U64; - member_out->data = str8_zero(); - } - - return is_parsed; -} - -internal COFF_ArchiveFirstMember -coff_parse_first_archive_member(COFF_ArchiveMember *member) -{ - Assert(str8_match_lit("/", member->header.name, 0)); - - U64 cursor = 0; - - U32 symbol_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); - - symbol_count = from_be_u32(symbol_count); - - Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32)); - cursor += dim_1u64(member_offsets_range); - - Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - cursor += dim_1u64(string_table_range); - - String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); - U32 *member_offsets = (U32 *)raw_member_offsets.str; - U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); - - COFF_ArchiveFirstMember result = {0}; - result.symbol_count = symbol_count; - result.member_offset_count = member_offset_count; - result.member_offsets = member_offsets; - result.string_table = str8_substr(member->data, string_table_range); - - return result; -} - -internal COFF_ArchiveSecondMember -coff_parse_second_archive_member(COFF_ArchiveMember *member) -{ - COFF_ArchiveSecondMember result = {0}; - - if (str8_match_lit("/", member->header.name, 0)) { - U64 cursor = 0; - - U32 member_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &member_count); - - Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); - cursor += dim_1u64(member_offsets_range); - - U32 symbol_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); - - Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); - cursor += dim_1u64(symbol_indices_range); - - Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - - String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); - String8 raw_indices = str8_substr(member->data, symbol_indices_range); - - U32 *member_offsets = (U32 *)raw_member_offsets.str; - U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); - - U16 *symbol_indices = (U16 *)raw_indices.str; - U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); - - result.member_count = member_count; - result.symbol_count = symbol_count; - result.member_offsets = member_offsets; - result.member_offset_count = member_offset_count; - result.symbol_indices = symbol_indices; - result.symbol_index_count = symbol_index_count; - result.string_table = str8_substr(member->data, string_table_range); - } - - return result; -} - -internal String8 -coff_parse_long_name(String8 long_names, String8 name) -{ - String8 result = name; - if (name.size > 0 && name.str[0] == '/') { - String8 offset_str = str8(name.str + 1, name.size - 1); - U64 offset = u64_from_str8(offset_str, 10); - if (offset < long_names.size) { - U8 *ptr = long_names.str + offset; - U8 *opl = long_names.str + long_names.size; - for (; ptr < opl; ++ptr) { - if (*ptr == '\0' || *ptr == '\n') { - break; - } - } - result = str8_range(long_names.str + offset, ptr); - } - } - return result; -} - -internal U64 -coff_parse_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out) -{ - U64 cursor = offset; - - cursor += str8_deserial_read_struct(data, cursor, &header_out->sig1); - cursor += str8_deserial_read_struct(data, cursor, &header_out->sig2); - cursor += str8_deserial_read_struct(data, cursor, &header_out->version); - cursor += str8_deserial_read_struct(data, cursor, &header_out->machine); - cursor += str8_deserial_read_struct(data, cursor, &header_out->time_stamp); - cursor += str8_deserial_read_struct(data, cursor, &header_out->data_size); - cursor += str8_deserial_read_struct(data, cursor, &header_out->hint); - - U16 flags = 0; - cursor += str8_deserial_read_struct(data, cursor, &flags); - header_out->type = COFF_IMPORT_HEADER_GET_TYPE(flags); - header_out->name_type = COFF_IMPORT_HEADER_GET_NAME_TYPE(flags); - - header_out->func_name = str8_zero(); - cursor += str8_deserial_read_cstr(data, cursor, &header_out->func_name); - - header_out->dll_name = str8_zero(); - cursor += str8_deserial_read_cstr(data, cursor, &header_out->dll_name); - - Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size); - - U64 read_size = cursor - offset; - return read_size; -} - -internal COFF_ArchiveMember -coff_archive_member_from_offset(String8 data, U64 offset) -{ - COFF_ArchiveMember member = {0}; - coff_archive_member_iter_next(data, &offset, &member); - return member; -} - -internal COFF_ArchiveMember -coff_archive_member_from_data(String8 data) -{ - return coff_archive_member_from_offset(data, 0); -} - -internal COFF_ImportHeader -coff_archive_import_from_data(String8 data) -{ - COFF_ImportHeader header = {0}; - coff_parse_archive_import(data, 0, &header); - return header; -} - -internal U64 -coff_archive_member_iter_init(String8 data) -{ - U64 cursor = data.size; - if (coff_is_archive(data)) { - cursor = sizeof(g_coff_archive_sig); - } - return cursor; -} - -internal B32 -coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out) -{ - B32 is_parsed; - - COFF_ArchiveMemberHeader header; header.is_end_correct = 0; - U64 read_size = coff_parse_archive_member_header(data, *offset, 1, &header); - - if (header.is_end_correct) { - member_out->header = header; - member_out->offset = *offset; - member_out->data = str8_substr(data, header.data_range); - - *offset += read_size; - - is_parsed = 1; - } else { - MemoryZeroStruct(&member_out->header); - member_out->offset = max_U64; - member_out->data = str8(0,0); - - is_parsed = 0; - } - - return is_parsed; -} - -internal U64 -coff_thin_archive_member_iter_init(String8 data) -{ - U64 cursor = data.size; - if (coff_is_thin_archive(data)) { - cursor = sizeof(g_coff_thin_archive_sig); - } - return cursor; -} - -internal B32 -coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out) -{ - B32 is_parsed = 0; - - member_out->header.is_end_correct = 0; - U64 header_size = coff_parse_archive_member_header(data, *offset, 0, &member_out->header); - - if (member_out->header.is_end_correct) { - member_out->offset = *offset; - if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) { - member_out->data = str8_substr(data, member_out->header.data_range); - } else { - // size field in non-header members means size of stand-alone obj - member_out->data = str8_zero(); - } - *offset += header_size; - is_parsed = 1; - } - - return is_parsed; -} - -internal void -coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node) -{ - SLLQueuePush(list->first, list->last, node); - list->count += 1; -} - -internal COFF_ArchiveParse -coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) -{ - String8 error = str8_zero(); - B32 has_second_header = 0; - B32 has_long_names = 0; - COFF_ArchiveMember first_header = {0}; - COFF_ArchiveMember second_header = {0}; - COFF_ArchiveMember long_names_member = {0}; - - COFF_ArchiveMemberNode *ptr = member_list.first; - - if (ptr) { - if (str8_match_lit("/", ptr->data.header.name, 0)) { - if (ptr->data.header.is_end_correct) { - first_header = ptr->data; - ptr = ptr->next; - } else { - error = str8_lit("first header doesn't have correct end"); - } - } - } else { - error = str8_lit("missing first header"); - } - - if (!error.size && ptr) { - if (str8_match_lit("/", ptr->data.header.name, 0)) { - if (ptr->data.header.is_end_correct) { - second_header = ptr->data; - ptr = ptr->next; - has_second_header = 1; - } else { - error = str8_lit("second header doesn't have correct end"); - } - } - } - - if (!error.size && ptr) { - if (str8_match_lit("//", ptr->data.header.name, 0)) { - if (ptr->data.header.is_end_correct) { - long_names_member = ptr->data; - ptr = ptr->next; - has_long_names; - } else { - error = str8_lit("long names header doesn't have correct end"); - } - } - } - - COFF_ArchiveParse parse = {0}; - parse.has_second_header = has_second_header; - parse.has_long_names = has_long_names; - parse.first_member = coff_parse_first_archive_member(&first_header); - parse.second_member = coff_parse_second_archive_member(&second_header); - parse.long_names = long_names_member.data; - parse.error = error; - - return parse; -} - -internal COFF_ArchiveParse -coff_archive_from_data(String8 data) -{ - COFF_ArchiveMemberList list = {0}; - COFF_ArchiveMemberNode node_arr[3] = {0}; - U64 cursor = coff_archive_member_iter_init(data); - for (U64 i = 0; i < ArrayCount(node_arr); ++i) { - COFF_ArchiveMemberNode *node = &node_arr[i]; - if (!coff_archive_member_iter_next(data, &cursor, &node->data)) { - break; - } - coff_archive_member_list_push_node(&list, node); - } - return coff_archive_parse_from_member_list(list); -} - -internal COFF_ArchiveParse -coff_thin_archive_from_data(String8 data) -{ - COFF_ArchiveMemberList list = {0}; - COFF_ArchiveMemberNode node_arr[3] = {0}; - U64 cursor = coff_thin_archive_member_iter_init(data); - for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { - COFF_ArchiveMemberNode *node = &node_arr[i]; - if (!coff_thin_archive_member_iter_next(data, &cursor, &node->data)) { - break; - } - coff_archive_member_list_push_node(&list, node); - } - return coff_archive_parse_from_member_list(list); -} - -internal COFF_ArchiveParse -coff_archive_parse_from_data(String8 data) -{ - COFF_ArchiveType type = coff_archive_type_from_data(data); - switch (type) { - case COFF_Archive_Null: break; - case COFF_Archive_Regular: return coff_archive_from_data(data); - case COFF_Archive_Thin: return coff_thin_archive_from_data(data); - } - COFF_ArchiveParse null_parse = {0}; - return null_parse; -} internal Arch arch_from_coff_machine(COFF_MachineType machine) { Arch result = Arch_Null; switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: result = Arch_x86; break; - case COFF_MachineType_X64: result = Arch_x64; break; - case COFF_MachineType_ARM: result = Arch_arm32; break; - case COFF_MachineType_ARM64: result = Arch_arm64; break; + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: result = Arch_x86; break; + case COFF_Machine_X64: result = Arch_x64; break; + case COFF_Machine_Arm: result = Arch_arm32; break; + case COFF_Machine_Arm64: result = Arch_arm64; break; } return result; } +internal U64 +coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff) +{ + U64 foff = 0; + for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) + { + COFF_SectionHeader *sect = §ions[sect_idx]; + if(sect->voff <= voff && voff < sect->voff+sect->vsize) + { + if(!(sect->flags & COFF_SectionFlag_CntUninitializedData)) + { + foff = sect->foff + (voff - sect->voff); + } + break; + } + } + return foff; +} + diff --git a/src/coff/coff.h b/src/coff/coff.h index 6ec8c8f6..97727aef 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -4,434 +4,258 @@ #ifndef COFF_H #define COFF_H +//////////////////////////////// +//~ rjf: COFF Format Types + +read_only global U8 g_coff_big_header_magic[] = +{ + 0xc7, 0xa1, 0xba, 0xd1, 0xee, 0xba, 0xa9, 0x4b, 0xaf, 0x20, 0xfa, 0xf6, 0x6a, 0xa4, 0xdc, 0xb8 +}; +read_only global U8 g_coff_res_magic[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +read_only global U8 g_coff_archive_sig[8] = "!\n"; +read_only global U8 g_coff_thin_archive_sig[8] = "!\n"; + +#pragma pack(push, 1) + typedef U32 COFF_TimeStamp; -//////////////////////////////// -//~ rjf: Coff Format Types - -#pragma pack(push,1) - -typedef U16 COFF_Flags; +typedef U16 COFF_FileHeaderFlags; enum { - COFF_Flag_RELOC_STRIPPED = (1 << 0), - COFF_Flag_EXECUTABLE_IMAGE = (1 << 1), - COFF_Flag_LINE_NUMS_STRIPPED = (1 << 2), - COFF_Flag_SYM_STRIPPED = (1 << 3), - COFF_Flag_RESERVED_0 = (1 << 4), - COFF_Flag_LARGE_ADDRESS_AWARE = (1 << 5), - COFF_Flag_RESERVED_1 = (1 << 6), - COFF_Flag_RESERVED_2 = (1 << 7), - COFF_Flag_32BIT_MACHINE = (1 << 8), - COFF_Flag_DEBUG_STRIPPED = (1 << 9), - COFF_Flag_REMOVABLE_RUN_FROM_SWAP = (1 << 10), - COFF_Flag_NET_RUN_FROM_SWAP = (1 << 11), - COFF_Flag_SYSTEM = (1 << 12), - COFF_Flag_DLL = (1 << 13), - COFF_Flag_UP_SYSTEM_ONLY = (1 << 14), - COFF_Flag_BYTES_RESERVED_HI = (1 << 15), + COFF_FileHeaderFlag_RelocStripped = (1 << 0), + COFF_FileHeaderFlag_ExecutableImage = (1 << 1), + COFF_FileHeaderFlag_LineNumbersStripped = (1 << 2), + COFF_FileHeaderFlag_SymbolsStripped = (1 << 3), + COFF_FileHeaderFlag_Reserved0 = (1 << 4), + COFF_FileHeaderFlag_LargeAddressAware = (1 << 5), + COFF_FileHeaderFlag_Reserved1 = (1 << 6), + COFF_FileHeaderFlag_Reserved2 = (1 << 7), + COFF_FileHeaderFlag_32BitMachine = (1 << 8), + COFF_FileHeaderFlag_DebugStripped = (1 << 9), + COFF_FileHeaderFlag_RemovableRunFromSwap = (1 << 10), + COFF_FileHeaderFlag_NetRunFromSwap = (1 << 11), + COFF_FileHeaderFlag_System = (1 << 12), + COFF_FileHeaderFlag_Dll = (1 << 13), + COFF_FileHeaderFlag_UpSystemOnly = (1 << 14), + COFF_FileHeaderFlag_BytesReservedHi = (1 << 15) }; typedef U16 COFF_MachineType; enum { - COFF_MachineType_UNKNOWN = 0x0, - COFF_MachineType_X86 = 0x14c, - COFF_MachineType_X64 = 0x8664, - COFF_MachineType_AM33 = 0x1d3, - COFF_MachineType_ARM = 0x1c0, - COFF_MachineType_ARM64 = 0xaa64, - COFF_MachineType_ARMNT = 0x1c4, - COFF_MachineType_EBC = 0xebc, - COFF_MachineType_IA64 = 0x200, - COFF_MachineType_M32R = 0x9041, - COFF_MachineType_MIPS16 = 0x266, - COFF_MachineType_MIPSFPU = 0x366, - COFF_MachineType_MIPSFPU16 = 0x466, - COFF_MachineType_POWERPC = 0x1f0, - COFF_MachineType_POWERPCFP = 0x1f1, - COFF_MachineType_R4000 = 0x166, - COFF_MachineType_RISCV32 = 0x5032, - COFF_MachineType_RISCV64 = 0x5064, - COFF_MachineType_RISCV128 = 0x5128, - COFF_MachineType_SH3 = 0x1a2, - COFF_MachineType_SH3DSP = 0x1a3, - COFF_MachineType_SH4 = 0x1a6, - COFF_MachineType_SH5 = 0x1a8, - COFF_MachineType_THUMB = 0x1c2, - COFF_MachineType_WCEMIPSV2 = 0x169, - COFF_MachineType_COUNT = 25 + COFF_Machine_Unknown = 0x0, + COFF_Machine_X86 = 0x14c, + COFF_Machine_X64 = 0x8664, + COFF_Machine_Am33 = 0x1d3, + COFF_Machine_Arm = 0x1c0, + COFF_Machine_Arm64 = 0xaa64, + COFF_Machine_ArmNt = 0x1c4, + COFF_Machine_Ebc = 0xebc, + COFF_Machine_Ia64 = 0x200, + COFF_Machine_M32R = 0x9041, + COFF_Machine_Mips16 = 0x266, + COFF_Machine_MipsFpu = 0x366, + COFF_Machine_MipsFpu16 = 0x466, + COFF_Machine_PowerPc = 0x1f0, + COFF_Machine_PowerPcFp = 0x1f1, + COFF_Machine_R4000 = 0x166, + COFF_Machine_RiscV32 = 0x5032, + COFF_Machine_RiscV64 = 0x5064, + COFF_Machine_RiscV128 = 0x5128, + COFF_Machine_Sh3 = 0x1a2, + COFF_Machine_Sh3Dsp = 0x1a3, + COFF_Machine_Sh4 = 0x1a6, + COFF_Machine_Sh5 = 0x1a8, + COFF_Machine_Thumb = 0x1c2, + COFF_Machine_WceMipsV2 = 0x169 }; -typedef struct COFF_Header COFF_Header; -struct COFF_Header +typedef struct COFF_FileHeader { + COFF_MachineType machine; + U16 section_count; + COFF_TimeStamp time_stamp; + U32 symbol_table_foff; + U32 symbol_count; + U16 optional_header_size; + COFF_FileHeaderFlags flags; +} COFF_FileHeader; + +typedef struct COFF_BigObjHeader +{ + U16 sig1; // COFF_Machine_Unknown + U16 sig2; // max_U16 + U16 version; // 2 COFF_MachineType machine; - U16 section_count; COFF_TimeStamp time_stamp; + U8 magic[16]; // g_coff_big_header_magic + U8 unused[16]; + U32 section_count; U32 symbol_table_foff; U32 symbol_count; - U16 optional_header_size; - COFF_Flags flags; -}; +} COFF_BigObjHeader; typedef U32 COFF_SectionAlign; enum { - COFF_SectionAlign_1BYTES = 0x1, - COFF_SectionAlign_2BYTES = 0x2, - COFF_SectionAlign_4BYTES = 0x3, - COFF_SectionAlign_8BYTES = 0x4, - COFF_SectionAlign_16BYTES = 0x5, - COFF_SectionAlign_32BYTES = 0x6, - COFF_SectionAlign_64BYTES = 0x7, - COFF_SectionAlign_128BYTES = 0x8, - COFF_SectionAlign_256BYTES = 0x9, - COFF_SectionAlign_512BYTES = 0xA, - COFF_SectionAlign_1024BYTES = 0xB, - COFF_SectionAlign_2048BYTES = 0xC, - COFF_SectionAlign_4096BYTES = 0xD, - COFF_SectionAlign_8192BYTES = 0xE, - COFF_SectionAlign_COUNT = 14 + COFF_SectionAlign_1Bytes = 0x1, + COFF_SectionAlign_2Bytes = 0x2, + COFF_SectionAlign_4Bytes = 0x3, + COFF_SectionAlign_8Bytes = 0x4, + COFF_SectionAlign_16Bytes = 0x5, + COFF_SectionAlign_32Bytes = 0x6, + COFF_SectionAlign_64Bytes = 0x7, + COFF_SectionAlign_128Bytes = 0x8, + COFF_SectionAlign_256Bytes = 0x9, + COFF_SectionAlign_512Bytes = 0xa, + COFF_SectionAlign_1024Bytes = 0xb, + COFF_SectionAlign_2048Bytes = 0xc, + COFF_SectionAlign_4096Bytes = 0xd, + COFF_SectionAlign_8192Bytes = 0xe }; typedef U32 COFF_SectionFlags; enum { - COFF_SectionFlag_TYPE_NO_PAD = (1 << 3), - COFF_SectionFlag_CNT_CODE = (1 << 5), - COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6), - COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7), - COFF_SectionFlag_LNK_OTHER = (1 << 8), - COFF_SectionFlag_LNK_INFO = (1 << 9), - COFF_SectionFlag_LNK_REMOVE = (1 << 11), - COFF_SectionFlag_LNK_COMDAT = (1 << 12), - COFF_SectionFlag_GPREL = (1 << 15), - COFF_SectionFlag_MEM_16BIT = (1 << 17), - COFF_SectionFlag_MEM_LOCKED = (1 << 18), - COFF_SectionFlag_MEM_PRELOAD = (1 << 19), - COFF_SectionFlag_ALIGN_SHIFT = 20, - COFF_SectionFlag_ALIGN_MASK = 0xf, - COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24), - COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25), - COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26), - COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27), - COFF_SectionFlag_MEM_SHARED = (1 << 28), - COFF_SectionFlag_MEM_EXECUTE = (1 << 29), - COFF_SectionFlag_MEM_READ = (1 << 30), - COFF_SectionFlag_MEM_WRITE = (1 << 31), + COFF_SectionFlag_TypeNoPad = (1 << 3), + COFF_SectionFlag_CntCode = (1 << 5), + COFF_SectionFlag_CntInitializedData = (1 << 6), + COFF_SectionFlag_CntUninitializedData = (1 << 7), + COFF_SectionFlag_LnkOther = (1 << 8), + COFF_SectionFlag_LnkInfo = (1 << 9), + COFF_SectionFlag_LnkRemove = (1 << 11), + COFF_SectionFlag_LnkCOMDAT = (1 << 12), + COFF_SectionFlag_GpRel = (1 << 15), + COFF_SectionFlag_Mem16Bit = (1 << 17), + COFF_SectionFlag_MemLocked = (1 << 18), + COFF_SectionFlag_MemPreload = (1 << 19), + COFF_SectionFlag_AlignShift = 20, + COFF_SectionFlag_AlignMask = 0xf, + COFF_SectionFlag_LnkNRelocOvfl = (1 << 24), + COFF_SectionFlag_MemDiscardable = (1 << 25), + COFF_SectionFlag_MemNotCached = (1 << 26), + COFF_SectionFlag_MemNotPaged = (1 << 27), + COFF_SectionFlag_MemShared = (1 << 28), + COFF_SectionFlag_MemExecute = (1 << 29), + COFF_SectionFlag_MemRead = (1 << 30), + COFF_SectionFlag_MemWrite = (1 << 31) }; -#define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK) -#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL) +#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask) +#define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl) -typedef struct COFF_SectionHeader COFF_SectionHeader; -struct COFF_SectionHeader +typedef struct COFF_SectionHeader { - U8 name[8]; - U32 vsize; - U32 voff; - U32 fsize; - U32 foff; - U32 relocs_foff; - U32 lines_foff; - U16 reloc_count; - U16 line_count; + U8 name[8]; + U32 vsize; + U32 voff; + U32 fsize; + U32 foff; + U32 relocs_foff; + U32 lines_foff; + U16 reloc_count; + U16 line_count; COFF_SectionFlags flags; -}; +} COFF_SectionHeader; -typedef U16 COFF_RelocType; - -typedef COFF_RelocType COFF_RelocTypeX64; -enum -{ - COFF_RelocTypeX64_ABS = 0x0, - COFF_RelocTypeX64_ADDR64 = 0x1, - COFF_RelocTypeX64_ADDR32 = 0x2, - COFF_RelocTypeX64_ADDR32NB = 0x3, // NB => No Base - COFF_RelocTypeX64_REL32 = 0x4, - COFF_RelocTypeX64_REL32_1 = 0x5, - COFF_RelocTypeX64_REL32_2 = 0x6, - COFF_RelocTypeX64_REL32_3 = 0x7, - COFF_RelocTypeX64_REL32_4 = 0x8, - COFF_RelocTypeX64_REL32_5 = 0x9, - COFF_RelocTypeX64_SECTION = 0xA, - COFF_RelocTypeX64_SECREL = 0xB, - COFF_RelocTypeX64_SECREL7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token - COFF_RelocTypeX64_TOKEN = 0xD, - COFF_RelocTypeX64_SREL32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR - COFF_RelocTypeX64_PAIR = 0xF, - COFF_RelocTypeX64_SSPAN32 = 0x10, - COFF_RelocTypeX64_COUNT = 17 -}; - -typedef COFF_RelocType COFF_RelocTypeX86; -enum -{ - COFF_RelocTypeX86_ABS = 0x0, // relocation is ignored - COFF_RelocTypeX86_DIR16 = 0x1, // no support - COFF_RelocTypeX86_REL16 = 0x2, // no support - COFF_RelocTypeX86_UNKNOWN0 = 0x3, - COFF_RelocTypeX86_UNKNOWN2 = 0x4, - COFF_RelocTypeX86_UNKNOWN3 = 0x5, - COFF_RelocTypeX86_DIR32 = 0x6, // 32-bit virtual address - COFF_RelocTypeX86_DIR32NB = 0x7, // 32-bit virtual offset - COFF_RelocTypeX86_SEG12 = 0x9, // no support - COFF_RelocTypeX86_SECTION = 0xA, // 16-bit section index, used for debug info purposes - COFF_RelocTypeX86_SECREL = 0xB, // 32-bit offset from start of a section - COFF_RelocTypeX86_TOKEN = 0xC, // CLR token? (for managed languages) - COFF_RelocTypeX86_SECREL7 = 0xD, // 7-bit offset from the base of the section that contains the target. - COFF_RelocTypeX86_UNKNOWN4 = 0xE, - COFF_RelocTypeX86_UNKNOWN5 = 0xF, - COFF_RelocTypeX86_UNKNOWN6 = 0x10, - COFF_RelocTypeX86_UNKNOWN7 = 0x11, - COFF_RelocTypeX86_UNKNOWN8 = 0x12, - COFF_RelocTypeX86_UNKNOWN9 = 0x13, - COFF_RelocTypeX86_REL32 = 0x14, - COFF_RelocTypeX86_COUNT = 20 -}; - -typedef COFF_RelocType COFF_RelocTypeARM; -enum -{ - COFF_RelocTypeARM_ABS = 0x0, - COFF_RelocTypeARM_ADDR32 = 0x1, - COFF_RelocTypeARM_ADDR32NB = 0x2, - COFF_RelocTypeARM_BRANCH24 = 0x3, - COFF_RelocTypeARM_BRANCH11 = 0x4, - COFF_RelocTypeARM_UNKNOWN1 = 0x5, - COFF_RelocTypeARM_UNKNOWN2 = 0x6, - COFF_RelocTypeARM_UNKNOWN3 = 0x7, - COFF_RelocTypeARM_UNKNOWN4 = 0x8, - COFF_RelocTypeARM_UNKNOWN5 = 0x9, - COFF_RelocTypeARM_REL32 = 0xA, - COFF_RelocTypeARM_SECTION = 0xE, - COFF_RelocTypeARM_SECREL = 0xF, - COFF_RelocTypeARM_MOV32 = 0x10, - COFF_RelocTypeARM_THUMB_MOV32 = 0x11, - COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12, - COFF_RelocTypeARM_UNUSED = 0x13, - COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14, - COFF_RelocTypeARM_THUMB_BLX23 = 0x15, - COFF_RelocTypeARM_PAIR = 0x16, - COFF_RelocTypeARM_COUNT = 20 -}; - -typedef COFF_RelocType COFF_RelocTypeARM64; -enum -{ - COFF_RelocTypeARM64_ABS = 0x0, - COFF_RelocTypeARM64_ADDR32 = 0x1, - COFF_RelocTypeARM64_ADDR32NB = 0x2, - COFF_RelocTypeARM64_BRANCH26 = 0x3, - COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4, - COFF_RelocTypeARM64_REL21 = 0x5, - COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6, - COFF_RelocTypeARM64_SECREL = 0x8, - COFF_RelocTypeARM64_SECREL_LOW12A = 0x9, - COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA, - COFF_RelocTypeARM64_SECREL_LOW12L = 0xB, - COFF_RelocTypeARM64_TOKEN = 0xC, - COFF_RelocTypeARM64_SECTION = 0xD, - COFF_RelocTypeARM64_ADDR64 = 0xE, - COFF_RelocTypeARM64_BRANCH19 = 0xF, - COFF_RelocTypeARM64_BRANCH14 = 0x10, - COFF_RelocTypeARM64_REL32 = 0x11, - COFF_RelocTypeARM64_COUNT = 17 -}; +//////////////////////////////// typedef U8 COFF_SymType; enum { - COFF_SymType_NULL, - COFF_SymType_VOID, - COFF_SymType_CHAR, - COFF_SymType_SHORT, - COFF_SymType_INT, - COFF_SymType_LONG, - COFF_SymType_FLOAT, - COFF_SymType_DOUBLE, - COFF_SymType_STRUCT, - COFF_SymType_UNION, - COFF_SymType_ENUM, - COFF_SymType_MOE, // member of enumeration - COFF_SymType_BYTE, - COFF_SymType_WORD, - COFF_SymType_UINT, - COFF_SymType_DWORD, - COFF_SymType_COUNT = 16 + COFF_SymType_Null, + COFF_SymType_Void, + COFF_SymType_Char, + COFF_SymType_Short, + COFF_SymType_Int, + COFF_SymType_Long, + COFF_SymType_Float, + COFF_SymType_Double, + COFF_SymType_Struct, + COFF_SymType_Union, + COFF_SymType_Enum, + COFF_SymType_MemberOfEnumeration, + COFF_SymType_Byte, + COFF_SymType_Word, + COFF_SymType_UInt, + COFF_SymType_DWord }; typedef U8 COFF_SymStorageClass; enum { - COFF_SymStorageClass_END_OF_FUNCTION = 0xff, - COFF_SymStorageClass_NULL = 0, - COFF_SymStorageClass_AUTOMATIC = 1, - COFF_SymStorageClass_EXTERNAL = 2, - COFF_SymStorageClass_STATIC = 3, - COFF_SymStorageClass_REGISTER = 4, - COFF_SymStorageClass_EXTERNAL_DEF = 5, - COFF_SymStorageClass_LABEL = 6, - COFF_SymStorageClass_UNDEFINED_LABEL = 7, - COFF_SymStorageClass_MEMBER_OF_STRUCT = 8, - COFF_SymStorageClass_ARGUMENT = 9, - COFF_SymStorageClass_STRUCT_TAG = 10, - COFF_SymStorageClass_MEMBER_OF_UNION = 11, - COFF_SymStorageClass_UNION_TAG = 12, - COFF_SymStorageClass_TYPE_DEFINITION = 13, - COFF_SymStorageClass_UNDEFINED_STATIC = 14, - COFF_SymStorageClass_ENUM_TAG = 15, - COFF_SymStorageClass_MEMBER_OF_ENUM = 16, - COFF_SymStorageClass_REGISTER_PARAM = 17, - COFF_SymStorageClass_BIT_FIELD = 18, - COFF_SymStorageClass_BLOCK = 100, - COFF_SymStorageClass_FUNCTION = 101, - COFF_SymStorageClass_END_OF_STRUCT = 102, - COFF_SymStorageClass_FILE = 103, - COFF_SymStorageClass_SECTION = 104, - COFF_SymStorageClass_WEAK_EXTERNAL = 105, - COFF_SymStorageClass_CLR_TOKEN = 107, - COFF_SymStorageClass_COUNT = 27 -}; - -typedef U16 COFF_SymSecNumber; -enum -{ - COFF_SymSecNumber_NUMBER_UNDEFINED = 0, - COFF_SymSecNumber_ABSOLUTE = 0xffff, - COFF_SymSecNumber_DEBUG = 0xfffe, - COFF_SymSecNumber_COUNT = 3 + COFF_SymStorageClass_Null = 0x00, + COFF_SymStorageClass_Automatic = 0x01, + COFF_SymStorageClass_External = 0x02, + COFF_SymStorageClass_Static = 0x03, + COFF_SymStorageClass_Register = 0x04, + COFF_SymStorageClass_ExternalDef = 0x05, + COFF_SymStorageClass_Label = 0x06, + COFF_SymStorageClass_UndefinedLabel = 0x07, + COFF_SymStorageClass_MemberOfStruct = 0x08, + COFF_SymStorageClass_Argument = 0x09, + COFF_SymStorageClass_StructTag = 0x0a, + COFF_SymStorageClass_MemberOfUnion = 0x0b, + COFF_SymStorageClass_UnionTag = 0x0c, + COFF_SymStorageClass_TypeDefinition = 0x0d, + COFF_SymStorageClass_UndefinedStatic = 0x0e, + COFF_SymStorageClass_EnumTag = 0x0f, + COFF_SymStorageClass_MemberOfEnum = 0x10, + COFF_SymStorageClass_RegisterParam = 0x11, + COFF_SymStorageClass_BitField = 0x12, + COFF_SymStorageClass_Block = 0x64, + COFF_SymStorageClass_Function = 0x65, + COFF_SymStorageClass_EndOfStruct = 0x66, + COFF_SymStorageClass_File = 0x67, + COFF_SymStorageClass_Section = 0x68, + COFF_SymStorageClass_WeakExternal = 0x69, + COFF_SymStorageClass_CLRToken = 0x6b, + COFF_SymStorageClass_EndOfFunction = 0xff }; typedef U8 COFF_SymDType; enum { - COFF_SymDType_NULL = 0, - COFF_SymDType_PTR = 16, - COFF_SymDType_FUNC = 32, - COFF_SymDType_ARRAY = 48, - COFF_SymDType_COUNT = 4 -}; - -typedef U32 COFF_WeakExtType; -enum -{ - COFF_WeakExtType_NOLIBRARY = 1, - COFF_WeakExtType_SEARCH_LIBRARY = 2, - COFF_WeakExtType_SEARCH_ALIAS = 3, - COFF_WeakExtType_COUNT = 3 -}; - -typedef U32 COFF_ImportHeaderType; -enum -{ - COFF_ImportHeaderType_CODE = 0, - COFF_ImportHeaderType_DATA = 1, - COFF_ImportHeaderType_CONST = 2, - COFF_ImportHeaderType_COUNT = 3 -}; - -typedef U32 COFF_ImportHeaderNameType; -enum -{ - COFF_ImportHeaderNameType_ORDINAL = 0, - COFF_ImportHeaderNameType_NAME = 1, - COFF_ImportHeaderNameType_NAME_NOPREFIX = 2, - COFF_ImportHeaderNameType_UNDECORATE = 3, - COFF_ImportHeaderNameType_COUNT = 4 -}; - -#define COFF_IMPORT_HEADER_TYPE_MASK 0x03 -#define COFF_IMPORT_HEADER_TYPE_SHIFT 0 -#define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c -#define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2 -#define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT) -#define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT) -typedef struct COFF_ImportHeader -{ - U16 sig1; - U16 sig2; - U16 version; - U16 machine; - COFF_TimeStamp time_stamp; - U32 data_size; - U16 hint; - U16 type; - U16 name_type; - // type : 2 - // name type : 3 - // reserved : 11 - //U16 flags; - String8 func_name; - String8 dll_name; -} COFF_ImportHeader; - -typedef U8 COFF_ComdatSelectType; -enum -{ - COFF_ComdatSelectType_NULL = 0, // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown. - COFF_ComdatSelectType_NODUPLICATES = 1, // Select any symbol, even if there are multiple definitions. (we default to first declaration) - COFF_ComdatSelectType_ANY = 2, // Sections that symbols reference must match in size, otherwise multiply definition error is thrown. - COFF_ComdatSelectType_SAME_SIZE = 3, // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown. - COFF_ComdatSelectType_EXACT_MATCH = 4, // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number') - COFF_ComdatSelectType_ASSOCIATIVE = 5, // Linker selects section with largest size. - COFF_ComdatSelectType_LARGEST = 6, - COFF_ComdatSelectType_COUNT = 7 -}; - -#define COFF_MIN_BIG_OBJ_VERSION 2 - -typedef struct COFF_HeaderBigObj COFF_HeaderBigObj; -struct COFF_HeaderBigObj -{ - U16 sig1; // COFF_MachineType_UNKNOWN - U16 sig2; // U16_MAX - U16 version; // COFF_MIN_BIG_OBJ_VERSION - COFF_MachineType machine; - COFF_TimeStamp time_stamp; - U8 magic[16]; - U32 unused[4]; - U32 section_count; - U32 symbol_table_foff; - U32 symbol_count; + COFF_SymDType_Null = 0x00, + COFF_SymDType_Ptr = 0x10, + COFF_SymDType_Func = 0x20, + COFF_SymDType_Array = 0x30 }; // Special values for section number field in coff symbol -#define COFF_SYMBOL_UNDEFINED_SECTION 0 -#define COFF_SYMBOL_ABS_SECTION ((U32)-1) -#define COFF_SYMBOL_DEBUG_SECTION ((U32)-2) -#define COFF_SYMBOL_ABS_SECTION_16 ((U16)-1) -#define COFF_SYMBOL_DEBUG_SECTION_16 ((U16)-2) +#define COFF_Symbol_UndefinedSection 0 +#define COFF_Symbol_AbsSection32 ((U32)-1) +#define COFF_Symbol_DebugSection32 ((U32)-2) +#define COFF_Symbol_AbsSection16 ((U16)-1) +#define COFF_Symbol_DebugSection16 ((U16)-2) -typedef union COFF_SymbolName COFF_SymbolName; -union COFF_SymbolName +typedef union COFF_SymbolName { U8 short_name[8]; - struct - { + struct { // if this field is filled with zeroes we have a long name, - // which means name is stored in the string table + // which means name is stored in the string table // and we need to use the offset to look it up... U32 zeroes; U32 string_table_offset; } long_name; -}; +} COFF_SymbolName; -#define COFF_SymbolType_IsFunc(x) ((x).u.lsb == COFF_SymType_NULL && (x).u.msb == COFF_SymDType_FUNC) +#define COFF_SymbolType_IsFunc(x) ((x).u.lsb == COFF_SymType_Null && (x).u.msb == COFF_SymDType_Func) -typedef union COFF_SymbolType COFF_SymbolType; -union COFF_SymbolType +typedef union COFF_SymbolType { - struct - { + struct { COFF_SymDType msb; - COFF_SymType lsb; + COFF_SymType lsb; } u; U16 v; -}; +} COFF_SymbolType; -typedef struct COFF_Symbol16 COFF_Symbol16; -struct COFF_Symbol16 +typedef struct COFF_Symbol16 { COFF_SymbolName name; U32 value; @@ -439,10 +263,9 @@ struct COFF_Symbol16 COFF_SymbolType type; COFF_SymStorageClass storage_class; U8 aux_symbol_count; -}; +} COFF_Symbol16; -typedef struct COFF_Symbol32 COFF_Symbol32; -struct COFF_Symbol32 +typedef struct COFF_Symbol32 { COFF_SymbolName name; U32 value; @@ -450,12 +273,20 @@ struct COFF_Symbol32 COFF_SymbolType type; COFF_SymStorageClass storage_class; U8 aux_symbol_count; -}; +} COFF_Symbol32; // Auxilary symbols are allocated with fixed size so that symbol table could be maintaned as array of regular size. -#define COFF_AUX_SYMBOL_SIZE 18 +#define COFF_AuxSymbolSize 18 -// storage class: EXTERNAL +typedef U32 COFF_WeakExtType; +enum +{ + COFF_WeakExt_NoLibrary = 1, + COFF_WeakExt_SearchLibrary = 2, + COFF_WeakExt_SearchAlias = 3 +}; + +// storage class: External typedef struct COFF_SymbolFuncDef { U32 tag_index; @@ -465,7 +296,7 @@ typedef struct COFF_SymbolFuncDef U8 unused[2]; } COFF_SymbolFuncDef; -// storage class: FUNCTION +// storage class: Function typedef struct COFF_SymbolFunc { U8 unused[4]; @@ -475,7 +306,7 @@ typedef struct COFF_SymbolFunc U8 unused3[2]; } COFF_SymbolFunc; -// storage class: WEAK_EXTERNAL +// storage class: WeakExternal typedef struct COFF_SymbolWeakExt { U32 tag_index; @@ -483,39 +314,145 @@ typedef struct COFF_SymbolWeakExt U8 unused[10]; } COFF_SymbolWeakExt; -typedef struct COFF_SymbolFile +typedef struct COFF_SymbolFile { - char name[18]; + U8 name[18]; } COFF_SymbolFile; +typedef U8 COFF_ComdatSelectType; +enum +{ + COFF_ComdatSelect_Null = 0, + COFF_ComdatSelect_NoDuplicates = 1, // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown. + COFF_ComdatSelect_Any = 2, // Select any symbol, even if there are multiple definitions. (we default to first declaration) + COFF_ComdatSelect_SameSize = 3, // Sections that symbols reference must match in size, otherwise multiply definition error is thrown. + COFF_ComdatSelect_ExactMatch = 4, // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown. + COFF_ComdatSelect_Associative = 5, // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number') + COFF_ComdatSelect_Largest = 6 // Linker selects section with largest size. +}; + // provides information about section to which symbol refers to. -// storage class: STATIC +// storage class: Static typedef struct COFF_SymbolSecDef { U32 length; U16 number_of_relocations; U16 number_of_ln; U32 check_sum; - U16 number_lo; // low 16 bits of one-based section index + U16 number_lo; // low 16 bits of one-based section index COFF_ComdatSelectType selection; U8 unused; U16 number_hi; } COFF_SymbolSecDef; -// specifies how section data should be modified when placed in the image file. -typedef struct COFF_Reloc COFF_Reloc; -struct COFF_Reloc +//////////////////////////////// + +typedef U16 COFF_RelocType; + +typedef COFF_RelocType COFF_Reloc_X64; +enum { - U32 apply_off; // section relative offset where relocation is placed - U32 isymbol; // zero based index into coff symbol table - U16 type; // relocation type that depends on the arch + COFF_Reloc_X64_Abs = 0x0, + COFF_Reloc_X64_Addr64 = 0x1, + COFF_Reloc_X64_Addr32 = 0x2, + COFF_Reloc_X64_Addr32Nb = 0x3, // NB => No Base + COFF_Reloc_X64_Rel32 = 0x4, + COFF_Reloc_X64_Rel32_1 = 0x5, + COFF_Reloc_X64_Rel32_2 = 0x6, + COFF_Reloc_X64_Rel32_3 = 0x7, + COFF_Reloc_X64_Rel32_4 = 0x8, + COFF_Reloc_X64_Rel32_5 = 0x9, + COFF_Reloc_X64_Section = 0xA, + COFF_Reloc_X64_SecRel = 0xB, + COFF_Reloc_X64_SecRel7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token + COFF_Reloc_X64_Token = 0xD, + COFF_Reloc_X64_SRel32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR + COFF_Reloc_X64_Pair = 0xF, + COFF_Reloc_X64_SSpan32 = 0x10 }; -#pragma pack(pop) +typedef COFF_RelocType COFF_Reloc_X86; +enum +{ + COFF_Reloc_X86_Abs = 0x0, // relocation is ignored + COFF_Reloc_X86_Dir16 = 0x1, // no support + COFF_Reloc_X86_Rel16 = 0x2, // no support + COFF_Reloc_X86_Unknown0 = 0x3, + COFF_Reloc_X86_Unknown2 = 0x4, + COFF_Reloc_X86_Unknown3 = 0x5, + COFF_Reloc_X86_Dir32 = 0x6, // 32-bit virtual address + COFF_Reloc_X86_Dir32Nb = 0x7, // 32-bit virtual offset + COFF_Reloc_X86_Seg12 = 0x9, // no support + COFF_Reloc_X86_Section = 0xa, // 16-bit section index, used for debug info purposes + COFF_Reloc_X86_SecRel = 0xb, // 32-bit offset from start of a section + COFF_Reloc_X86_Token = 0xc, // CLR token? (for managed languages) + COFF_Reloc_X86_SecRel7 = 0xd, // 7-bit offset from the base of the section that contains the target. + COFF_Reloc_X86_Unknown4 = 0xe, + COFF_Reloc_X86_Unknown5 = 0xf, + COFF_Reloc_X86_Unknown6 = 0x10, + COFF_Reloc_X86_Unknown7 = 0x11, + COFF_Reloc_X86_Unknown8 = 0x12, + COFF_Reloc_X86_Unknown9 = 0x13, + COFF_Reloc_X86_Rel32 = 0x14 +}; + +typedef COFF_RelocType COFF_Reloc_Arm; +enum +{ + COFF_Reloc_Arm_Abs = 0x0, + COFF_Reloc_Arm_Addr32 = 0x1, + COFF_Reloc_Arm_Addr32Nb = 0x2, + COFF_Reloc_Arm_Branch24 = 0x3, + COFF_Reloc_Arm_Branch11 = 0x4, + COFF_Reloc_Arm_Unknown1 = 0x5, + COFF_Reloc_Arm_Unknown2 = 0x6, + COFF_Reloc_Arm_Unknown3 = 0x7, + COFF_Reloc_Arm_Unknown4 = 0x8, + COFF_Reloc_Arm_Unknown5 = 0x9, + COFF_Reloc_Arm_Rel32 = 0xa, + COFF_Reloc_Arm_Section = 0xe, + COFF_Reloc_Arm_SecRel = 0xf, + COFF_Reloc_Arm_Mov32 = 0x10, + COFF_Reloc_Arm_ThumbMov32 = 0x11, + COFF_Reloc_Arm_ThumbBranch20 = 0x12, + COFF_Reloc_Arm_Unused = 0x13, + COFF_Reloc_Arm_ThumbBranch24 = 0x14, + COFF_Reloc_Arm_ThumbBlx23 = 0x15, + COFF_Reloc_Arm_Pair = 0x16 +}; + +typedef COFF_RelocType COFF_Reloc_Arm64; +enum +{ + COFF_Reloc_Arm64_Abs = 0x0, + COFF_Reloc_Arm64_Addr32 = 0x1, + COFF_Reloc_Arm64_Addr32Nb = 0x2, + COFF_Reloc_Arm64_Branch26 = 0x3, + COFF_Reloc_Arm64_PageBaseRel21 = 0x4, + COFF_Reloc_Arm64_Rel21 = 0x5, + COFF_Reloc_Arm64_PageOffset12a = 0x6, + COFF_Reloc_Arm64_SecRel = 0x8, + COFF_Reloc_Arm64_SecRelLow12a = 0x9, + COFF_Reloc_Arm64_SecRelHigh12a = 0xa, + COFF_Reloc_Arm64_SecRelLow12l = 0xb, + COFF_Reloc_Arm64_Token = 0xc, + COFF_Reloc_Arm64_Section = 0xd, + COFF_Reloc_Arm64_Addr64 = 0xe, + COFF_Reloc_Arm64_Branch19 = 0xf, + COFF_Reloc_Arm64_Branch14 = 0x10, + COFF_Reloc_Arm64_Rel32 = 0x11 +}; + +typedef struct COFF_Reloc +{ + U32 apply_off; // section relative offset where relocation is placed + U32 isymbol; // zero based index into coff symbol table + COFF_RelocType type; // relocation type that depends on the arch +} COFF_Reloc; //////////////////////////////// -#define COFF_RES_ALIGN 4u +#define COFF_ResourceAlign 4u typedef struct COFF_ResourceHeaderPrefix { @@ -526,52 +463,12 @@ typedef struct COFF_ResourceHeaderPrefix typedef U16 COFF_ResourceMemoryFlags; enum { - COFF_ResourceMemoryFlag_MOVEABLE = 0x10, - COFF_ResourceMemoryFlag_PURE = 0x20, - COFF_ResourceMemoryFlag_PRELOAD = 0x40, - COFF_ResourceMemoryFlag_DISCARDABLE = 0x1000, + COFF_ResourceMemoryFlag_Moveable = 0x10, + COFF_ResourceMemoryFlag_Pure = 0x20, + COFF_ResourceMemoryFlag_PreLoad = 0x40, + COFF_ResourceMemoryFlag_Discardable = 0x1000 }; -typedef enum -{ - COFF_ResourceIDType_NULL, - COFF_ResourceIDType_NUMBER, - COFF_ResourceIDType_STRING, - COFF_ResourceIDType_COUNT -} COFF_ResourceIDType; - -typedef struct COFF_ResourceID_16 -{ - COFF_ResourceIDType type; - union - { - U16 number; - String16 string; - } u; -} COFF_ResourceID_16; - -typedef struct COFF_ResourceID -{ - COFF_ResourceIDType type; - union - { - U16 number; - String8 string; - } u; -} COFF_ResourceID; - -typedef struct COFF_Resource -{ - COFF_ResourceID type; - COFF_ResourceID name; - U32 data_version; - COFF_ResourceMemoryFlags memory_flags; - U16 language_id; - U32 version; - U32 characteristics; - String8 data; -} COFF_Resource; - typedef struct COFF_ResourceDataEntry { U32 data_voff; @@ -590,7 +487,7 @@ typedef struct COFF_ResourceDirTable U16 id_entry_count; } COFF_ResourceDirTable; -#define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u) +#define COFF_Resource_SubDirFlag (1u << 31u) typedef struct COFF_ResourceDirEntry { union { @@ -605,311 +502,103 @@ typedef struct COFF_ResourceDirEntry //////////////////////////////// -#define COFF_ARCHIVE_ALIGN 2 -#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15 -#define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60 +#define COFF_Archive_MemberAlign 2 +#define COFF_Archive_MaxShortNameSize 15 typedef struct COFF_ArchiveMemberHeader { - String8 name; // padded to 16 bytes with spaces - COFF_TimeStamp time_stamp; - U32 user_id; // unix artifact that does not have meaning on windows - U32 group_id; // unix artifact that does not have meaning on windows - String8 mode; // octal representation the members file mode - B32 is_end_correct; // set to true if found correct signature after header - Rng1U64 data_range; + U8 name[16]; + U8 date[12]; + U8 user_id[6]; + U8 group_id[6]; + U8 mode[8]; + U8 size[10]; + U8 end[2]; } COFF_ArchiveMemberHeader; -//////////////////////////////// -// Helpers - +#define COFF_ImportType_Invalid max_U16 +typedef U16 COFF_ImportType; enum { - COFF_DataType_NULL, - COFF_DataType_BIG_OBJ, - COFF_DataType_OBJ, - COFF_DataType_IMPORT, + COFF_ImportHeader_Code = 0, + COFF_ImportHeader_Data = 1, + COFF_ImportHeader_Const = 2 }; -typedef U32 COFF_DataType; - -typedef struct COFF_HeaderInfo -{ - COFF_DataType type; - COFF_MachineType machine; - U64 header_size; - U64 section_array_off; - U64 section_count_no_null; - U64 string_table_off; - U64 symbol_size; - U64 symbol_off; - U64 symbol_count; -} COFF_HeaderInfo; +typedef U32 COFF_ImportByType; enum { - COFF_SymbolValueInterp_REGULAR, // symbol has section and offset. - COFF_SymbolValueInterp_WEAK, // symbol is overridable - COFF_SymbolValueInterp_UNDEFINED, // symbol doesn't have a reference section. - COFF_SymbolValueInterp_COMMON, // symbol has no section but still has size. - COFF_SymbolValueInterp_ABS, // symbol has an absolute (non-relocatable) value and is not an address. - COFF_SymbolValueInterp_DEBUG // symbol is used to provide general type of debugging information. -}; -typedef U32 COFF_SymbolValueInterpType; - -typedef struct COFF_Symbol16Node -{ - struct COFF_Symbol16Node *next; - COFF_Symbol16 data; -} COFF_Symbol16Node; - -typedef struct COFF_Symbol16List -{ - U64 count; - COFF_Symbol16Node *first; - COFF_Symbol16Node *last; -} COFF_Symbol16List; - -typedef struct COFF_Symbol32Array -{ - U64 count; - COFF_Symbol32 *v; -} COFF_Symbol32Array; - -typedef struct COFF_RelocNode -{ - struct COFF_RelocNode *next; - COFF_Reloc data; -} COFF_RelocNode; - -typedef struct COFF_RelocList -{ - U64 count; - COFF_RelocNode *first; - COFF_RelocNode *last; -} COFF_RelocList; - -typedef struct COFF_RelocArray -{ - U64 count; - COFF_Reloc *v; -} COFF_RelocArray; - -typedef struct COFF_RelocInfo -{ - U64 array_off; - U64 count; -} COFF_RelocInfo; - -typedef struct COFF_ResourceNode -{ - struct COFF_ResourceNode *next; - COFF_Resource data; -} COFF_ResourceNode; - -typedef struct COFF_ResourceList -{ - U64 count; - COFF_ResourceNode *first; - COFF_ResourceNode *last; -} COFF_ResourceList; - -//////////////////////////////// - -typedef struct COFF_ArchiveMember -{ - COFF_ArchiveMemberHeader header; - U64 offset; - String8 data; -} COFF_ArchiveMember; - -typedef struct COFF_ArchiveFirstMember -{ - U32 symbol_count; - U64 member_offset_count; - U32 *member_offsets; - String8 string_table; -} COFF_ArchiveFirstMember; - -typedef struct COFF_ArchiveSecondMember -{ - U32 member_count; - U32 symbol_count; - U64 member_offset_count; - U32 *member_offsets; - U64 symbol_index_count; - U16 *symbol_indices; - String8 string_table; -} COFF_ArchiveSecondMember; - -typedef struct COFF_ArchiveMemberNode -{ - struct COFF_ArchiveMemberNode *next; - COFF_ArchiveMember data; -} COFF_ArchiveMemberNode; - -typedef struct COFF_ArchiveMemberList -{ - U64 count; - COFF_ArchiveMemberNode *first; - COFF_ArchiveMemberNode *last; -} COFF_ArchiveMemberList; - -typedef enum -{ - COFF_Archive_Null, - COFF_Archive_Regular, - COFF_Archive_Thin -} COFF_ArchiveType; - -typedef struct COFF_ArchiveParse -{ - B32 has_second_header; - B32 has_long_names; - COFF_ArchiveFirstMember first_member; - COFF_ArchiveSecondMember second_member; - String8 long_names; - String8 error; -} COFF_ArchiveParse; - -//////////////////////////////// - -typedef struct COFF_SectionHeaderArray -{ - U64 count; - COFF_SectionHeader *v; -} COFF_SectionHeaderArray; - -//////////////////////////////// - -typedef struct COFF_ParsedSymbol -{ - String8 name; - U32 value; - U32 section_number; - COFF_SymbolType type; - COFF_SymStorageClass storage_class; - U8 aux_symbol_count; -} COFF_ParsedSymbol; - -//////////////////////////////// -//~ rjf: Globals - -read_only global U8 coff_big_obj_magic[] = -{ - 0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B, - 0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8, + COFF_ImportBy_Ordinal = 0, + COFF_ImportBy_Name = 1, + COFF_ImportBy_NameNoPrefix = 2, + COFF_ImportBy_Undecorate = 3 }; -read_only global U8 g_coff_archive_sig[8] = "!\n"; -read_only global U8 g_coff_thin_archive_sig[8] = "!\n"; - -read_only global U8 g_coff_res_magic[] = +typedef U16 COFF_ImportHeaderFlags; +enum { - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + COFF_ImportHeader_TypeShift = 0, + COFF_ImportHeader_TypeMask = 3, + COFF_ImportHeader_ImportByShift = 2, + COFF_ImportHeader_ImportByMask = 3, }; +#define COFF_ImportHeader_ExtractType(x) (((x) >> COFF_ImportHeader_TypeShift ) & COFF_ImportHeader_TypeMask ) +#define COFF_ImportHeader_ExtractImportBy(x) (((x) >> COFF_ImportHeader_ImportByShift) & COFF_ImportHeader_ImportByMask) -read_only global COFF_SectionHeader coff_section_header_nil = {0}; +typedef struct COFF_ImportHeader +{ + U16 sig1; // COFF_Machine_Unknown + U16 sig2; // max_U16 + U16 version; // 0 + COFF_MachineType machine; + COFF_TimeStamp time_stamp; + U32 data_size; + U16 hint_or_ordinal; + COFF_ImportHeaderFlags flags; + // char *func_name; + // char *dll_name; +} COFF_ImportHeader; + +#pragma pack(pop) //////////////////////////////// -//~ rjf: Helper Functions +// Section -internal B32 coff_is_big_obj(String8 data); -internal B32 coff_is_obj(String8 data); -internal COFF_HeaderInfo coff_header_info_from_data(String8 data); -internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags); -internal COFF_SectionFlags coff_section_flag_from_align_size(U64 align); -internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class); +internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags); +internal COFF_SectionFlags coff_section_flag_from_align_size (U64 align); -internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff); -internal COFF_SectionHeader *coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n); -internal String8 coff_name_from_section_header(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base); -internal void coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out); +internal String8 coff_name_from_section_header(String8 raw_coff, COFF_SectionHeader *header, U64 string_table_off); +internal void coff_parse_section_name (String8 full_name, String8 *name_out, String8 *postfix_out); -internal String8 coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name); -internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32); -internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16); -internal void coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16); -internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); -internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); -internal COFF_Symbol32Array coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_off, U64 symbol_count, U64 symbol_size); -internal COFF_Symbol16Node * coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol); -internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header); +//////////////////////////////// +// Symbol -internal U64 coff_apply_size_from_reloc_x64(COFF_RelocTypeX64 x); -internal U64 coff_apply_size_from_reloc_x86(COFF_RelocTypeX86 x); -internal U64 coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x); +internal String8 coff_read_symbol_name(String8 raw_coff, U64 string_table_off, COFF_SymbolName *name); -internal U64 coff_word_size_from_machine(COFF_MachineType machine); +//////////////////////////////// +// Reloc + +internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x); +internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x); + +//////////////////////////////// +// Import + +internal U32 coff_make_ordinal32(U16 hint); +internal U64 coff_make_ordinal64(U16 hint); + +internal String8 coff_make_import_lookup (Arena *arena, U16 hint, String8 name); +internal String8 coff_make_import_header_by_name (Arena *arena, String8 dll_name, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 name, U16 hint, COFF_ImportType type); +internal String8 coff_make_import_header_by_ordinal(Arena *arena, String8 dll_name, COFF_MachineType machine, COFF_TimeStamp time_stamp, U16 ordinal, COFF_ImportType type); + +//////////////////////////////// +// Misc + +internal U64 coff_word_size_from_machine (COFF_MachineType machine); internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine); internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine); -internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name); -internal U32 coff_make_ordinal_32(U16 hint); -internal U64 coff_make_ordinal_64(U16 hint); - -internal String8 coff_make_import_header_by_name(Arena *arena, - String8 dll_name, - COFF_MachineType machine, - COFF_TimeStamp time_stamp, - String8 name, - U16 hint, - COFF_ImportHeaderType type); -internal String8 coff_make_import_header_by_ordinal(Arena *arena, - String8 dll_name, - COFF_MachineType machine, - COFF_TimeStamp time_stamp, - U16 ordinal, - COFF_ImportHeaderType type); - -//////////////////////////////// -//~ Resources - -internal String8 coff_resource_string_from_str16(Arena *arena, String16 string); -internal String8 coff_resource_string_from_str8(Arena *arena, String8 string); -internal String8 coff_resource_number_from_u16(Arena *arena, U16 number); - -internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b); -internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16); - -internal U64 coff_read_resource_id_utf16(String8 res, U64 off, COFF_ResourceID_16 *id_out); -internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out); -internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data); - -internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id); -internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data); - -//////////////////////////////// -//~ Archive - -internal COFF_DataType coff_data_type_from_data(String8 data); -internal B32 coff_is_import(String8 data); -internal B32 coff_is_archive(String8 data); -internal B32 coff_is_thin_archive(String8 data); -internal COFF_ArchiveType coff_archive_type_from_data(String8 data); - -internal U64 coff_parse_archive_member_header(String8 data, U64 offset, B32 is_regular_archive, COFF_ArchiveMemberHeader *header_out); -internal B32 coff_parse_archive_member_data(String8 data, U64 cursor, COFF_ArchiveMember *member_out); -internal COFF_ArchiveFirstMember coff_parse_first_archive_member(COFF_ArchiveMember *member); -internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member); -internal String8 coff_parse_long_name(String8 long_names, String8 name); -internal U64 coff_parse_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out); - -internal COFF_ArchiveMember coff_archive_member_from_offset(String8 data, U64 offset); -internal COFF_ArchiveMember coff_archive_member_from_data(String8 data); -internal COFF_ImportHeader coff_archive_import_from_data(String8 data); - -internal U64 coff_archive_member_iter_init(String8 data); -internal B32 coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); - -internal U64 coff_thin_archive_member_iter_init(String8 data); -internal B32 coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); - -internal COFF_ArchiveParse coff_archive_parse_from_member_list(COFF_ArchiveMemberList list); -internal COFF_ArchiveParse coff_archive_from_data(String8 data); -internal COFF_ArchiveParse coff_thin_archive_from_data(String8 data); -internal COFF_ArchiveParse coff_archive_parse_from_data(String8 data); - internal Arch arch_from_coff_machine(COFF_MachineType machine); +internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff); -#endif //COFF_H +#endif // COFF_H diff --git a/src/coff/coff_enum.c b/src/coff/coff_enum.c index 0830f2aa..9a8c2874 100644 --- a/src/coff/coff_enum.c +++ b/src/coff/coff_enum.c @@ -21,54 +21,54 @@ read_only struct String8 string; COFF_MachineType machine; } g_coff_machine_map[] = { - { str8_lit_comp(""), COFF_MachineType_UNKNOWN }, - { str8_lit_comp("X86"), COFF_MachineType_X86 }, - { str8_lit_comp("AMD64"), COFF_MachineType_X64 }, - { str8_lit_comp("X64"), COFF_MachineType_X64 }, - { str8_lit_comp("AM33"), COFF_MachineType_AM33 }, - { str8_lit_comp("ARM"), COFF_MachineType_ARM }, - { str8_lit_comp("ARM64"), COFF_MachineType_ARM64 }, - { str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT }, - { str8_lit_comp("EBC"), COFF_MachineType_EBC }, - { str8_lit_comp("IA64"), COFF_MachineType_IA64 }, - { str8_lit_comp("M32R"), COFF_MachineType_M32R }, - { str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 }, - { str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU }, - { str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 }, - { str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC }, - { str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP }, - { str8_lit_comp("R4000"), COFF_MachineType_R4000 }, - { str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 }, - { str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 }, - { str8_lit_comp("SH3"), COFF_MachineType_SH3 }, - { str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP }, - { str8_lit_comp("SH4"), COFF_MachineType_SH4 }, - { str8_lit_comp("SH5"), COFF_MachineType_SH5 }, - { str8_lit_comp("THUMB"), COFF_MachineType_THUMB }, - { str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 }, + { str8_lit_comp(""), COFF_Machine_Unknown }, + { str8_lit_comp("X86"), COFF_Machine_X86 }, + { str8_lit_comp("Amd64"), COFF_Machine_X64 }, + { str8_lit_comp("X64"), COFF_Machine_X64 }, + { str8_lit_comp("Am33"), COFF_Machine_Am33 }, + { str8_lit_comp("Arm"), COFF_Machine_Arm }, + { str8_lit_comp("Arm64"), COFF_Machine_Arm64 }, + { str8_lit_comp("ArmNt"), COFF_Machine_ArmNt }, + { str8_lit_comp("Ebc"), COFF_Machine_Ebc }, + { str8_lit_comp("Ia64"), COFF_Machine_Ia64 }, + { str8_lit_comp("M32r"), COFF_Machine_M32R }, + { str8_lit_comp("Mips16"), COFF_Machine_Mips16 }, + { str8_lit_comp("MipsFpu"), COFF_Machine_MipsFpu }, + { str8_lit_comp("MipsFpu16"), COFF_Machine_MipsFpu16 }, + { str8_lit_comp("PowerPc"), COFF_Machine_PowerPc }, + { str8_lit_comp("PowerPcFp"), COFF_Machine_PowerPcFp }, + { str8_lit_comp("R4000"), COFF_Machine_R4000 }, + { str8_lit_comp("RiscV32"), COFF_Machine_RiscV32 }, + { str8_lit_comp("RiscV64"), COFF_Machine_RiscV64 }, + { str8_lit_comp("Sh3"), COFF_Machine_Sh3 }, + { str8_lit_comp("Sh3Dsp"), COFF_Machine_Sh3Dsp }, + { str8_lit_comp("Sh4"), COFF_Machine_Sh4 }, + { str8_lit_comp("Sh5"), COFF_Machine_Sh5 }, + { str8_lit_comp("Thumb"), COFF_Machine_Thumb }, + { str8_lit_comp("WceMipsV2"), COFF_Machine_WceMipsV2 }, }; read_only static struct { char * name; - COFF_ImportHeaderType type; + COFF_ImportType type; } g_coff_import_header_type_map[] = { - { "CODE", COFF_ImportHeaderType_CODE }, - { "DATA", COFF_ImportHeaderType_DATA }, - { "CONST", COFF_ImportHeaderType_CONST }, + { "Code", COFF_ImportHeader_Code }, + { "Data", COFF_ImportHeader_Data }, + { "Const", COFF_ImportHeader_Const }, }; internal String8 -coff_string_from_comdat_select_type(COFF_ComdatSelectType select) +coff_string_from_comdat_select_type(COFF_ComdatSelectType type) { - String8 result = str8(0,0); - switch (select) { - case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break; - case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break; - case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break; - case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break; - case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break; - case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break; - case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break; + String8 result = str8_zero(); + switch (type) { + case COFF_ComdatSelect_Null: result = str8_lit("Null"); break; + case COFF_ComdatSelect_NoDuplicates: result = str8_lit("NoDuplicates"); break; + case COFF_ComdatSelect_Any: result = str8_lit("Any"); break; + case COFF_ComdatSelect_SameSize: result = str8_lit("SameSize"); break; + case COFF_ComdatSelect_ExactMatch: result = str8_lit("ExactMatch"); break; + case COFF_ComdatSelect_Associative: result = str8_lit("Associative"); break; + case COFF_ComdatSelect_Largest: result = str8_lit("Largest"); break; } return result; } @@ -85,45 +85,45 @@ coff_string_from_machine_type(COFF_MachineType machine) } internal String8 -coff_string_from_flags(Arena *arena, COFF_Flags flags) +coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; - if (flags & COFF_Flag_RELOC_STRIPPED) { + if (flags & COFF_FileHeaderFlag_RelocStripped) { str8_list_pushf(scratch.arena, &list, "Relocs Stripped"); } - if (flags & COFF_Flag_EXECUTABLE_IMAGE) { + if (flags & COFF_FileHeaderFlag_ExecutableImage) { str8_list_pushf(scratch.arena, &list, "Executable"); } - if (flags & COFF_Flag_LINE_NUMS_STRIPPED) { + if (flags & COFF_FileHeaderFlag_LineNumbersStripped) { str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped"); } - if (flags & COFF_Flag_SYM_STRIPPED) { + if (flags & COFF_FileHeaderFlag_SymbolsStripped) { str8_list_pushf(scratch.arena, &list, "Symbols Stripped"); } - if (flags & COFF_Flag_LARGE_ADDRESS_AWARE) { + if (flags & COFF_FileHeaderFlag_LargeAddressAware) { str8_list_pushf(scratch.arena, &list, "Large Address Aware"); } - if (flags & COFF_Flag_32BIT_MACHINE) { + if (flags & COFF_FileHeaderFlag_32BitMachine) { str8_list_pushf(scratch.arena, &list, "32-Bit Machine"); } - if (flags & COFF_Flag_DEBUG_STRIPPED) { + if (flags & COFF_FileHeaderFlag_DebugStripped) { str8_list_pushf(scratch.arena, &list, "Debug Stripped"); } - if (flags & COFF_Flag_REMOVABLE_RUN_FROM_SWAP) { + if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) { str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap"); } - if (flags & COFF_Flag_NET_RUN_FROM_SWAP) { + if (flags & COFF_FileHeaderFlag_NetRunFromSwap) { str8_list_pushf(scratch.arena, &list, "Net Run From Swap"); } - if (flags & COFF_Flag_SYSTEM) { + if (flags & COFF_FileHeaderFlag_System) { str8_list_pushf(scratch.arena, &list, "System"); } - if (flags & COFF_Flag_DLL) { + if (flags & COFF_FileHeaderFlag_Dll) { str8_list_pushf(scratch.arena, &list, "DLL"); } - if (flags & COFF_Flag_UP_SYSTEM_ONLY) { + if (flags & COFF_FileHeaderFlag_UpSystemOnly) { str8_list_pushf(scratch.arena, &list, "Up System Only"); } @@ -139,62 +139,62 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; - if (flags & COFF_SectionFlag_TYPE_NO_PAD) { - str8_list_pushf(scratch.arena, &list, "TYPE_NO_PAD"); + if (flags & COFF_SectionFlag_TypeNoPad) { + str8_list_pushf(scratch.arena, &list, "TypeNoPad"); } - if (flags & COFF_SectionFlag_CNT_CODE) { - str8_list_pushf(scratch.arena, &list, "CNT_CODE"); + if (flags & COFF_SectionFlag_CntCode) { + str8_list_pushf(scratch.arena, &list, "CntCode"); } - if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &list, "CNT_INITIALIZED_DATA"); + if (flags & COFF_SectionFlag_CntInitializedData) { + str8_list_pushf(scratch.arena, &list, "CntInitializedData"); } - if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { - str8_list_pushf(scratch.arena, &list, "CNT_UNINITIALIZED_DATA"); + if (flags & COFF_SectionFlag_CntUninitializedData) { + str8_list_pushf(scratch.arena, &list, "CntUninitializedData"); } - if (flags & COFF_SectionFlag_LNK_OTHER) { - str8_list_pushf(scratch.arena, &list, "LNK_OTHER"); + if (flags & COFF_SectionFlag_LnkOther) { + str8_list_pushf(scratch.arena, &list, "LnkOther"); } - if (flags & COFF_SectionFlag_LNK_INFO) { - str8_list_pushf(scratch.arena, &list, "LNK_INFO"); + if (flags & COFF_SectionFlag_LnkInfo) { + str8_list_pushf(scratch.arena, &list, "LnkInfo"); } - if (flags & COFF_SectionFlag_LNK_COMDAT) { - str8_list_pushf(scratch.arena, &list, "LNK_COMDAT"); + if (flags & COFF_SectionFlag_LnkCOMDAT) { + str8_list_pushf(scratch.arena, &list, "LnkCOMDAT"); } - if (flags & COFF_SectionFlag_GPREL) { - str8_list_pushf(scratch.arena, &list, "GPREL"); + if (flags & COFF_SectionFlag_GpRel) { + str8_list_pushf(scratch.arena, &list, "GpRel"); } - if (flags & COFF_SectionFlag_MEM_16BIT) { - str8_list_pushf(scratch.arena, &list, "MEM_16BIT"); + if (flags & COFF_SectionFlag_Mem16Bit) { + str8_list_pushf(scratch.arena, &list, "Mem16Bit"); } - if (flags & COFF_SectionFlag_MEM_LOCKED) { - str8_list_pushf(scratch.arena, &list, "MEM_LOCKED"); + if (flags & COFF_SectionFlag_MemLocked) { + str8_list_pushf(scratch.arena, &list, "MemLocked"); } - if (flags & COFF_SectionFlag_MEM_PRELOAD) { - str8_list_pushf(scratch.arena, &list, "MEM_PRELOAD"); + if (flags & COFF_SectionFlag_MemPreload) { + str8_list_pushf(scratch.arena, &list, "MemPreload"); } - if (flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { - str8_list_pushf(scratch.arena, &list, "LNK_NRELOC_OVFL"); + if (flags & COFF_SectionFlag_LnkNRelocOvfl) { + str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl"); } - if (flags & COFF_SectionFlag_MEM_DISCARDABLE) { - str8_list_pushf(scratch.arena, &list, "MEM_DISCARDABLE"); + if (flags & COFF_SectionFlag_MemDiscardable) { + str8_list_pushf(scratch.arena, &list, "MemDiscardable"); } - if (flags & COFF_SectionFlag_MEM_NOT_CACHED) { - str8_list_pushf(scratch.arena, &list, "MEM_NOT_CACHED"); + if (flags & COFF_SectionFlag_MemNotCached) { + str8_list_pushf(scratch.arena, &list, "MemNotCached"); } - if (flags & COFF_SectionFlag_MEM_NOT_PAGED) { - str8_list_pushf(scratch.arena, &list, "MEM_NOT_PAGED"); + if (flags & COFF_SectionFlag_MemNotPaged) { + str8_list_pushf(scratch.arena, &list, "MemNotPaged"); } - if (flags & COFF_SectionFlag_MEM_SHARED) { - str8_list_pushf(scratch.arena, &list, "MEM_SHARED"); + if (flags & COFF_SectionFlag_MemShared) { + str8_list_pushf(scratch.arena, &list, "MemShared"); } - if (flags & COFF_SectionFlag_MEM_EXECUTE) { - str8_list_pushf(scratch.arena, &list, "MEM_EXECUTE"); + if (flags & COFF_SectionFlag_MemExecute) { + str8_list_pushf(scratch.arena, &list, "MemExecute"); } - if (flags & COFF_SectionFlag_MEM_READ) { - str8_list_pushf(scratch.arena, &list, "MEM_READ"); + if (flags & COFF_SectionFlag_MemRead) { + str8_list_pushf(scratch.arena, &list, "MemRead"); } - if (flags & COFF_SectionFlag_MEM_WRITE) { - str8_list_pushf(scratch.arena, &list, "MEM_WRITE"); + if (flags & COFF_SectionFlag_MemWrite) { + str8_list_pushf(scratch.arena, &list, "MemWrite"); } U64 align = coff_align_size_from_section_flags(flags); @@ -215,7 +215,7 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) } internal String8 -coff_string_from_import_header_type(COFF_ImportHeaderType type) +coff_string_from_import_header_type(COFF_ImportType type) { for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { if (g_coff_import_header_type_map[i].type == type) { @@ -229,10 +229,10 @@ internal String8 coff_string_from_sym_dtype(COFF_SymDType x) { switch (x) { - case COFF_SymDType_NULL: return str8_lit("NULL"); - case COFF_SymDType_PTR : return str8_lit("PTR"); - case COFF_SymDType_FUNC: return str8_lit("FUNC"); - case COFF_SymDType_ARRAY: return str8_lit("ARRAY"); + case COFF_SymDType_Null: return str8_lit("Null"); + case COFF_SymDType_Ptr : return str8_lit("Ptr"); + case COFF_SymDType_Func: return str8_lit("Func"); + case COFF_SymDType_Array: return str8_lit("Array"); } return str8_zero(); } @@ -241,22 +241,22 @@ internal String8 coff_string_from_sym_type(COFF_SymType x) { switch (x) { - case COFF_SymType_NULL: return str8_lit("NULL"); - case COFF_SymType_VOID: return str8_lit("VOID"); - case COFF_SymType_CHAR: return str8_lit("CHAR"); - case COFF_SymType_SHORT: return str8_lit("SHORT"); - case COFF_SymType_INT: return str8_lit("INT"); - case COFF_SymType_LONG: return str8_lit("LONG"); - case COFF_SymType_FLOAT: return str8_lit("FLOAT"); - case COFF_SymType_DOUBLE: return str8_lit("DOUBLE"); - case COFF_SymType_STRUCT: return str8_lit("STRUCT"); - case COFF_SymType_UNION: return str8_lit("UNION"); - case COFF_SymType_ENUM: return str8_lit("ENUM"); - case COFF_SymType_MOE: return str8_lit("MOE"); - case COFF_SymType_BYTE: return str8_lit("BYTE"); - case COFF_SymType_WORD: return str8_lit("WORD"); - case COFF_SymType_UINT: return str8_lit("UINT"); - case COFF_SymType_DWORD: return str8_lit("DWORD"); + case COFF_SymType_Null: return str8_lit("Null"); + case COFF_SymType_Void: return str8_lit("Void"); + case COFF_SymType_Char: return str8_lit("Char"); + case COFF_SymType_Short: return str8_lit("Short"); + case COFF_SymType_Int: return str8_lit("Int"); + case COFF_SymType_Long: return str8_lit("Long"); + case COFF_SymType_Float: return str8_lit("Float"); + case COFF_SymType_Double: return str8_lit("Double"); + case COFF_SymType_Struct: return str8_lit("Struct"); + case COFF_SymType_Union: return str8_lit("Union"); + case COFF_SymType_Enum: return str8_lit("Enum"); + case COFF_SymType_MemberOfEnumeration: return str8_lit("MOE"); + case COFF_SymType_Byte: return str8_lit("Byte"); + case COFF_SymType_Word: return str8_lit("Word"); + case COFF_SymType_UInt: return str8_lit("UInt"); + case COFF_SymType_DWord: return str8_lit("DWord"); } return str8_zero(); } @@ -265,33 +265,33 @@ internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x) { switch (x) { - case COFF_SymStorageClass_NULL: break; - case COFF_SymStorageClass_END_OF_FUNCTION: return str8_lit("EOF"); - case COFF_SymStorageClass_AUTOMATIC: return str8_lit("AUTOMATIC"); - case COFF_SymStorageClass_EXTERNAL: return str8_lit("EXTERNAL"); - case COFF_SymStorageClass_STATIC: return str8_lit("STATIC"); - case COFF_SymStorageClass_REGISTER: return str8_lit("REGISTER"); - case COFF_SymStorageClass_EXTERNAL_DEF: return str8_lit("DEF"); - case COFF_SymStorageClass_LABEL: return str8_lit("LABEL"); - case COFF_SymStorageClass_UNDEFINED_LABEL: return str8_lit("LABEL"); - case COFF_SymStorageClass_MEMBER_OF_STRUCT: return str8_lit("STRUCT"); - case COFF_SymStorageClass_ARGUMENT: return str8_lit("ARGUMENT"); - case COFF_SymStorageClass_STRUCT_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_MEMBER_OF_UNION: return str8_lit("UNION"); - case COFF_SymStorageClass_UNION_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_TYPE_DEFINITION: return str8_lit("DEFINITION"); - case COFF_SymStorageClass_UNDEFINED_STATIC: return str8_lit("STATIC"); - case COFF_SymStorageClass_ENUM_TAG: return str8_lit("TAG"); - case COFF_SymStorageClass_MEMBER_OF_ENUM: return str8_lit("ENUM"); - case COFF_SymStorageClass_REGISTER_PARAM: return str8_lit("PARAM"); - case COFF_SymStorageClass_BIT_FIELD: return str8_lit("FIELD"); - case COFF_SymStorageClass_BLOCK: return str8_lit("BLOCK"); - case COFF_SymStorageClass_FUNCTION: return str8_lit("FUNCTION"); - case COFF_SymStorageClass_END_OF_STRUCT: return str8_lit("STRUCT"); - case COFF_SymStorageClass_FILE: return str8_lit("FILE"); - case COFF_SymStorageClass_SECTION: return str8_lit("SECTION"); - case COFF_SymStorageClass_WEAK_EXTERNAL: return str8_lit("EXTERNAL"); - case COFF_SymStorageClass_CLR_TOKEN: return str8_lit("TOKEN"); + case COFF_SymStorageClass_Null: break; + case COFF_SymStorageClass_EndOfFunction: return str8_lit("EndOfFunction"); + case COFF_SymStorageClass_Automatic: return str8_lit("Automatic"); + case COFF_SymStorageClass_External: return str8_lit("External"); + case COFF_SymStorageClass_Static: return str8_lit("Static"); + case COFF_SymStorageClass_Register: return str8_lit("Register"); + case COFF_SymStorageClass_ExternalDef: return str8_lit("Def"); + case COFF_SymStorageClass_Label: return str8_lit("Label"); + case COFF_SymStorageClass_UndefinedLabel: return str8_lit("UndefinedLabel"); + case COFF_SymStorageClass_MemberOfStruct: return str8_lit("Struct"); + case COFF_SymStorageClass_Argument: return str8_lit("Argument"); + case COFF_SymStorageClass_StructTag: return str8_lit("Tag"); + case COFF_SymStorageClass_MemberOfUnion: return str8_lit("Union"); + case COFF_SymStorageClass_UnionTag: return str8_lit("Tag"); + case COFF_SymStorageClass_TypeDefinition: return str8_lit("Definition"); + case COFF_SymStorageClass_UndefinedStatic: return str8_lit("Static"); + case COFF_SymStorageClass_EnumTag: return str8_lit("Tag"); + case COFF_SymStorageClass_MemberOfEnum: return str8_lit("Enum"); + case COFF_SymStorageClass_RegisterParam: return str8_lit("Param"); + case COFF_SymStorageClass_BitField: return str8_lit("Field"); + case COFF_SymStorageClass_Block: return str8_lit("Block"); + case COFF_SymStorageClass_Function: return str8_lit("Function"); + case COFF_SymStorageClass_EndOfStruct: return str8_lit("Struct"); + case COFF_SymStorageClass_File: return str8_lit("File"); + case COFF_SymStorageClass_Section: return str8_lit("Section"); + case COFF_SymStorageClass_WeakExternal: return str8_lit("External"); + case COFF_SymStorageClass_CLRToken: return str8_lit("Token"); } return str8_zero(); } @@ -300,130 +300,115 @@ internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x) { switch (x) { - case COFF_WeakExtType_NOLIBRARY: return str8_lit("NOLIBRARY"); - case COFF_WeakExtType_SEARCH_LIBRARY: return str8_lit("SEARCH_LIBRARY"); - case COFF_WeakExtType_SEARCH_ALIAS: return str8_lit("SEARCH_ALIAS"); + case COFF_WeakExt_NoLibrary: return str8_lit("NoLibrary"); + case COFF_WeakExt_SearchLibrary: return str8_lit("SearchLibrary"); + case COFF_WeakExt_SearchAlias: return str8_lit("SearchAlias"); } return str8_zero(); } internal String8 -coff_string_from_selection(COFF_ComdatSelectType x) +coff_string_from_reloc_x86(COFF_Reloc_X86 x) { switch (x) { - case COFF_ComdatSelectType_NULL: break; - case COFF_ComdatSelectType_NODUPLICATES: return str8_lit("NODUPLICATES"); - case COFF_ComdatSelectType_ANY: return str8_lit("ANY"); - case COFF_ComdatSelectType_SAME_SIZE: return str8_lit("SIZE"); - case COFF_ComdatSelectType_EXACT_MATCH: return str8_lit("MATCH"); - case COFF_ComdatSelectType_ASSOCIATIVE: return str8_lit("ASSOCIATIVE"); - case COFF_ComdatSelectType_LARGEST: return str8_lit("LARGEST"); + case COFF_Reloc_X86_Abs: return str8_lit("Abs"); + case COFF_Reloc_X86_Dir16: return str8_lit("Dir16"); + case COFF_Reloc_X86_Rel16: return str8_lit("Rel16"); + case COFF_Reloc_X86_Unknown0: return str8_lit("Unknown0"); + case COFF_Reloc_X86_Unknown2: return str8_lit("Unknown2"); + case COFF_Reloc_X86_Unknown3: return str8_lit("Unknown3"); + case COFF_Reloc_X86_Dir32: return str8_lit("Dir32"); + case COFF_Reloc_X86_Dir32Nb: return str8_lit("Dir32Nb"); + case COFF_Reloc_X86_Seg12: return str8_lit("Seg12"); + case COFF_Reloc_X86_Section: return str8_lit("Section"); + case COFF_Reloc_X86_SecRel: return str8_lit("SecRel"); + case COFF_Reloc_X86_Token: return str8_lit("Token"); + case COFF_Reloc_X86_SecRel7: return str8_lit("SecRel7"); + case COFF_Reloc_X86_Unknown4: return str8_lit("Unknown4"); + case COFF_Reloc_X86_Unknown5: return str8_lit("Unknown5"); + case COFF_Reloc_X86_Unknown6: return str8_lit("Unknown6"); + case COFF_Reloc_X86_Unknown7: return str8_lit("Unknown7"); + case COFF_Reloc_X86_Unknown8: return str8_lit("Unknown8"); + case COFF_Reloc_X86_Unknown9: return str8_lit("Unknown9"); + case COFF_Reloc_X86_Rel32: return str8_lit("Rel32"); } return str8_zero(); } internal String8 -coff_string_from_reloc_x86(COFF_RelocTypeX86 x) +coff_string_from_reloc_x64(COFF_Reloc_X64 x) { switch (x) { - case COFF_RelocTypeX86_ABS: return str8_lit("ABS"); - case COFF_RelocTypeX86_DIR16: return str8_lit("DIR16"); - case COFF_RelocTypeX86_REL16: return str8_lit("REL16"); - case COFF_RelocTypeX86_UNKNOWN0: return str8_lit("UNKNOWN0"); - case COFF_RelocTypeX86_UNKNOWN2: return str8_lit("UNKNOWN2"); - case COFF_RelocTypeX86_UNKNOWN3: return str8_lit("UNKNOWN3"); - case COFF_RelocTypeX86_DIR32: return str8_lit("DIR32"); - case COFF_RelocTypeX86_DIR32NB: return str8_lit("DIR32NB"); - case COFF_RelocTypeX86_SEG12: return str8_lit("SEG12"); - case COFF_RelocTypeX86_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeX86_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeX86_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeX86_SECREL7: return str8_lit("SECREL7"); - case COFF_RelocTypeX86_UNKNOWN4: return str8_lit("UNKNOWN4"); - case COFF_RelocTypeX86_UNKNOWN5: return str8_lit("UNKNOWN5"); - case COFF_RelocTypeX86_UNKNOWN6: return str8_lit("UNKNOWN6"); - case COFF_RelocTypeX86_UNKNOWN7: return str8_lit("UNKNOWN7"); - case COFF_RelocTypeX86_UNKNOWN8: return str8_lit("UNKNOWN8"); - case COFF_RelocTypeX86_UNKNOWN9: return str8_lit("UNKNOWN9"); - case COFF_RelocTypeX86_REL32: return str8_lit("REL32"); + case COFF_Reloc_X64_Abs: return str8_lit("Abs"); + case COFF_Reloc_X64_Addr64: return str8_lit("Addr64"); + case COFF_Reloc_X64_Addr32: return str8_lit("Addr32"); + case COFF_Reloc_X64_Addr32Nb: return str8_lit("Addr32Nb"); + case COFF_Reloc_X64_Rel32: return str8_lit("Rel32"); + case COFF_Reloc_X64_Rel32_1: return str8_lit("Rel32_1"); + case COFF_Reloc_X64_Rel32_2: return str8_lit("Rel32_2"); + case COFF_Reloc_X64_Rel32_3: return str8_lit("Rel32_3"); + case COFF_Reloc_X64_Rel32_4: return str8_lit("Rel32_4"); + case COFF_Reloc_X64_Rel32_5: return str8_lit("Rel32_5"); + case COFF_Reloc_X64_Section: return str8_lit("Section"); + case COFF_Reloc_X64_SecRel: return str8_lit("SecRel"); + case COFF_Reloc_X64_SecRel7: return str8_lit("SecRel7"); + case COFF_Reloc_X64_Token: return str8_lit("Token"); + case COFF_Reloc_X64_SRel32: return str8_lit("SRel32"); + case COFF_Reloc_X64_Pair: return str8_lit("Pair"); + case COFF_Reloc_X64_SSpan32: return str8_lit("SSpan32"); } return str8_zero(); } internal String8 -coff_string_from_reloc_x64(COFF_RelocTypeX64 x) +coff_string_from_reloc_arm(COFF_Reloc_Arm x) { switch (x) { - case COFF_RelocTypeX64_ABS: return str8_lit("ABS"); - case COFF_RelocTypeX64_ADDR64: return str8_lit("ADDR64"); - case COFF_RelocTypeX64_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeX64_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeX64_REL32: return str8_lit("REL32"); - case COFF_RelocTypeX64_REL32_1: return str8_lit("REL32_1"); - case COFF_RelocTypeX64_REL32_2: return str8_lit("REL32_2"); - case COFF_RelocTypeX64_REL32_3: return str8_lit("REL32_3"); - case COFF_RelocTypeX64_REL32_4: return str8_lit("REL32_4"); - case COFF_RelocTypeX64_REL32_5: return str8_lit("REL32_5"); - case COFF_RelocTypeX64_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeX64_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeX64_SECREL7: return str8_lit("SECREL7"); - case COFF_RelocTypeX64_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeX64_SREL32: return str8_lit("SREL32"); - case COFF_RelocTypeX64_PAIR: return str8_lit("PAIR"); - case COFF_RelocTypeX64_SSPAN32: return str8_lit("SSPAN32"); + case COFF_Reloc_Arm_Abs: return str8_lit("Abs"); + case COFF_Reloc_Arm_Addr32: return str8_lit("Addr32"); + case COFF_Reloc_Arm_Addr32Nb: return str8_lit("Addr32Nb"); + case COFF_Reloc_Arm_Branch24: return str8_lit("Branch24"); + case COFF_Reloc_Arm_Branch11: return str8_lit("Branch11"); + case COFF_Reloc_Arm_Unknown1: return str8_lit("Unknown1"); + case COFF_Reloc_Arm_Unknown2: return str8_lit("Unknown2"); + case COFF_Reloc_Arm_Unknown3: return str8_lit("Unknown3"); + case COFF_Reloc_Arm_Unknown4: return str8_lit("Unknown4"); + case COFF_Reloc_Arm_Unknown5: return str8_lit("Unknown5"); + case COFF_Reloc_Arm_Rel32: return str8_lit("Rel32"); + case COFF_Reloc_Arm_Section: return str8_lit("Section"); + case COFF_Reloc_Arm_SecRel: return str8_lit("SecRel"); + case COFF_Reloc_Arm_Mov32: return str8_lit("Mov32"); + case COFF_Reloc_Arm_ThumbMov32: return str8_lit("ThumbMov32"); + case COFF_Reloc_Arm_ThumbBranch20: return str8_lit("ThumbBranch20"); + case COFF_Reloc_Arm_Unused: return str8_lit("Unused"); + case COFF_Reloc_Arm_ThumbBranch24: return str8_lit("ThumbBranch24"); + case COFF_Reloc_Arm_ThumbBlx23: return str8_lit("ThumbBlx23"); + case COFF_Reloc_Arm_Pair: return str8_lit("Pair"); } return str8_zero(); } internal String8 -coff_string_from_reloc_arm(COFF_RelocTypeARM x) +coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x) { switch (x) { - case COFF_RelocTypeARM_ABS: return str8_lit("ABS"); - case COFF_RelocTypeARM_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeARM_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeARM_BRANCH24: return str8_lit("BRANCH24"); - case COFF_RelocTypeARM_BRANCH11: return str8_lit("BRANCH11"); - case COFF_RelocTypeARM_UNKNOWN1: return str8_lit("UNKNOWN1"); - case COFF_RelocTypeARM_UNKNOWN2: return str8_lit("UNKNOWN2"); - case COFF_RelocTypeARM_UNKNOWN3: return str8_lit("UNKNOWN3"); - case COFF_RelocTypeARM_UNKNOWN4: return str8_lit("UNKNOWN4"); - case COFF_RelocTypeARM_UNKNOWN5: return str8_lit("UNKNOWN5"); - case COFF_RelocTypeARM_REL32: return str8_lit("REL32"); - case COFF_RelocTypeARM_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeARM_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeARM_MOV32: return str8_lit("MOV32"); - case COFF_RelocTypeARM_THUMB_MOV32: return str8_lit("THUMB_MOV32"); - case COFF_RelocTypeARM_THUMB_BRANCH20: return str8_lit("THUMB_BRANCH20"); - case COFF_RelocTypeARM_UNUSED: return str8_lit("UNUSED"); - case COFF_RelocTypeARM_THUMB_BRANCH24: return str8_lit("THUMB_BRANCH24"); - case COFF_RelocTypeARM_THUMB_BLX23: return str8_lit("THUMB_BLX23"); - case COFF_RelocTypeARM_PAIR: return str8_lit("PAIR"); - } - return str8_zero(); -} - -internal String8 -coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x) -{ - switch (x) { - case COFF_RelocTypeARM64_ABS: return str8_lit("ABS"); - case COFF_RelocTypeARM64_ADDR32: return str8_lit("ADDR32"); - case COFF_RelocTypeARM64_ADDR32NB: return str8_lit("ADDR32NB"); - case COFF_RelocTypeARM64_BRANCH26: return str8_lit("BRANCH26"); - case COFF_RelocTypeARM64_PAGEBASE_REL21: return str8_lit("PAGEBASE_REL21"); - case COFF_RelocTypeARM64_REL21: return str8_lit("REL21"); - case COFF_RelocTypeARM64_PAGEOFFSET_12A: return str8_lit("PAGEOFFSET_12A"); - case COFF_RelocTypeARM64_SECREL: return str8_lit("SECREL"); - case COFF_RelocTypeARM64_SECREL_LOW12A: return str8_lit("SECREL_LOW12A"); - case COFF_RelocTypeARM64_SECREL_HIGH12A: return str8_lit("SECREL_HIGH12A"); - case COFF_RelocTypeARM64_SECREL_LOW12L: return str8_lit("SECREL_LOW12L"); - case COFF_RelocTypeARM64_TOKEN: return str8_lit("TOKEN"); - case COFF_RelocTypeARM64_SECTION: return str8_lit("SECTION"); - case COFF_RelocTypeARM64_ADDR64: return str8_lit("ADDR64"); - case COFF_RelocTypeARM64_BRANCH19: return str8_lit("BRANCH19"); - case COFF_RelocTypeARM64_BRANCH14: return str8_lit("BRANCH14"); - case COFF_RelocTypeARM64_REL32: return str8_lit("REL32"); + case COFF_Reloc_Arm64_Abs: return str8_lit("Abs"); + case COFF_Reloc_Arm64_Addr32: return str8_lit("Addr32"); + case COFF_Reloc_Arm64_Addr32Nb: return str8_lit("Addr32Nb"); + case COFF_Reloc_Arm64_Branch26: return str8_lit("Branch26"); + case COFF_Reloc_Arm64_PageBaseRel21: return str8_lit("PageBaseRel21"); + case COFF_Reloc_Arm64_Rel21: return str8_lit("Rel21"); + case COFF_Reloc_Arm64_PageOffset12a: return str8_lit("PageOffset12a"); + case COFF_Reloc_Arm64_SecRel: return str8_lit("SecRel"); + case COFF_Reloc_Arm64_SecRelLow12a: return str8_lit("SecRelLow12a"); + case COFF_Reloc_Arm64_SecRelHigh12a: return str8_lit("SecRelHigh12a"); + case COFF_Reloc_Arm64_SecRelLow12l: return str8_lit("SecRelLow12l"); + case COFF_Reloc_Arm64_Token: return str8_lit("Token"); + case COFF_Reloc_Arm64_Section: return str8_lit("Section"); + case COFF_Reloc_Arm64_Addr64: return str8_lit("Addr64"); + case COFF_Reloc_Arm64_Branch19: return str8_lit("Branch19"); + case COFF_Reloc_Arm64_Branch14: return str8_lit("Branch14"); + case COFF_Reloc_Arm64_Rel32: return str8_lit("Rel32"); } return str8_zero(); } @@ -432,10 +417,10 @@ internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x) { switch (machine) { - case COFF_MachineType_X86: return coff_string_from_reloc_x86(x); - case COFF_MachineType_X64: return coff_string_from_reloc_x64(x); - case COFF_MachineType_ARM: return coff_string_from_reloc_arm(x); - case COFF_MachineType_ARM64: return coff_string_from_reloc_arm64(x); + case COFF_Machine_X86: return coff_string_from_reloc_x86(x); + case COFF_Machine_X64: return coff_string_from_reloc_x64(x); + case COFF_Machine_Arm: return coff_string_from_reloc_arm(x); + case COFF_Machine_Arm64: return coff_string_from_reloc_arm64(x); } return str8_zero(); } @@ -448,10 +433,10 @@ coff_machine_from_string(String8 string) return g_coff_machine_map[i].machine; } } - return COFF_MachineType_UNKNOWN; + return COFF_Machine_Unknown; } -internal COFF_ImportHeaderType +internal COFF_ImportType coff_import_header_type_from_string(String8 name) { for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { @@ -459,7 +444,7 @@ coff_import_header_type_from_string(String8 name) return g_coff_import_header_type_map[i].type; } } - return COFF_ImportHeaderType_COUNT; + return COFF_ImportType_Invalid; } diff --git a/src/coff/coff_enum.h b/src/coff/coff_enum.h index 7eb174e7..a294b5a2 100644 --- a/src/coff/coff_enum.h +++ b/src/coff/coff_enum.h @@ -5,23 +5,22 @@ #define COFF_ENUM_H internal String8 coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp); -internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select); +internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType type); internal String8 coff_string_from_machine_type(COFF_MachineType machine); -internal String8 coff_string_from_flags(Arena *arena, COFF_Flags flags); +internal String8 coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags); internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags); -internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type); +internal String8 coff_string_from_import_header_type(COFF_ImportType type); internal String8 coff_string_from_sym_dtype(COFF_SymDType x); internal String8 coff_string_from_sym_type(COFF_SymType x); internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x); internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x); -internal String8 coff_string_from_selection(COFF_ComdatSelectType x); -internal String8 coff_string_from_reloc_x86(COFF_RelocTypeX86 x); -internal String8 coff_string_from_reloc_x64(COFF_RelocTypeX64 x); -internal String8 coff_string_from_reloc_arm(COFF_RelocTypeARM x); -internal String8 coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x); +internal String8 coff_string_from_reloc_x86(COFF_Reloc_X86 x); +internal String8 coff_string_from_reloc_x64(COFF_Reloc_X64 x); +internal String8 coff_string_from_reloc_arm(COFF_Reloc_Arm x); +internal String8 coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x); internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x); -internal COFF_MachineType coff_machine_from_string(String8 string); -internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name); +internal COFF_MachineType coff_machine_from_string(String8 string); +internal COFF_ImportType coff_import_header_type_from_string(String8 name); #endif // COFF_ENUM_H diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c new file mode 100644 index 00000000..aa33fb07 --- /dev/null +++ b/src/coff/coff_parse.c @@ -0,0 +1,904 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +coff_is_big_obj(String8 raw_coff) +{ + B32 is_big_obj = 0; + if (raw_coff.size >= sizeof(COFF_BigObjHeader)) { + COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str); + is_big_obj = file_header32->sig1 == COFF_Machine_Unknown && + file_header32->sig2 == max_U16 && + file_header32->version >= 2 && + MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0; + } + return is_big_obj; +} + +internal B32 +coff_is_obj(String8 raw_coff) +{ + B32 is_obj = 0; + + if (raw_coff.size >= sizeof(COFF_FileHeader)) { + COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str); + + // validate machine + B32 is_machine_type_valid = 0; + switch (header->machine) { + case COFF_Machine_Unknown: + case COFF_Machine_X86: case COFF_Machine_X64: + case COFF_Machine_Am33: case COFF_Machine_Arm: + case COFF_Machine_Arm64: case COFF_Machine_ArmNt: + case COFF_Machine_Ebc: case COFF_Machine_Ia64: + case COFF_Machine_M32R: case COFF_Machine_Mips16: + case COFF_Machine_MipsFpu:case COFF_Machine_MipsFpu16: + case COFF_Machine_PowerPc:case COFF_Machine_PowerPcFp: + case COFF_Machine_R4000: case COFF_Machine_RiscV32: + case COFF_Machine_RiscV64:case COFF_Machine_RiscV128: + case COFF_Machine_Sh3: case COFF_Machine_Sh3Dsp: + case COFF_Machine_Sh4: case COFF_Machine_Sh5: + case COFF_Machine_Thumb: case COFF_Machine_WceMipsV2: + { + is_machine_type_valid = 1; + }break; + } + + if (is_machine_type_valid) { + // validate section count + U64 section_count = header->section_count; + U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader); + if (raw_coff.size >= section_hdr_opl_off) { + + COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header)); + COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count; + + // validate section ranges + B32 is_sect_range_valid = 1; + for (COFF_SectionHeader *sec_hdr = section_hdrs; + sec_hdr < section_hdr_opl; + sec_hdr += 1) { + if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) { + U64 min = sec_hdr->foff; + U64 max = min + sec_hdr->fsize; + if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) { + is_sect_range_valid = 0; + break; + } + } + } + + if (is_sect_range_valid) { + // validate symbol table + U64 symbol_table_off = header->symbol_table_foff; + U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count; + U64 symbol_table_opl_off = symbol_table_off + symbol_table_size; + + // don't validate symbol table when there is none + if (symbol_table_off == 0 && symbol_table_size == 0) { + symbol_table_off = section_hdr_opl_off; + symbol_table_opl_off = section_hdr_opl_off; + } + + is_obj = (section_hdr_opl_off <= symbol_table_off && + symbol_table_off <= symbol_table_opl_off && + symbol_table_opl_off <= raw_coff.size); + } + } + } + } + + return is_obj; +} + +internal COFF_FileHeaderInfo +coff_file_header_info_from_data(String8 raw_coff) +{ + COFF_FileHeaderInfo info = {0}; + if (coff_is_big_obj(raw_coff)) { + COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str; + info.is_big_obj = 1; + info.machine = header32->machine; + info.header_size = sizeof(COFF_BigObjHeader); + info.section_array_off = sizeof(COFF_BigObjHeader); + info.section_count_no_null = header32->section_count; + info.string_table_off = header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count; + info.symbol_size = sizeof(COFF_Symbol32); + info.symbol_off = header32->symbol_table_foff; + info.symbol_count = header32->symbol_count; + } else if (coff_is_obj(raw_coff)) { + COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str; + info.is_big_obj = 0; + info.machine = header16->machine; + info.header_size = sizeof(COFF_FileHeader); + info.section_array_off = sizeof(COFF_FileHeader); + info.section_count_no_null = header16->section_count; + info.string_table_off = header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count; + info.symbol_size = sizeof(COFF_Symbol16); + info.symbol_off = header16->symbol_table_foff; + info.symbol_count = header16->symbol_count; + } + return info; +} + +internal COFF_ParsedSymbol +coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32) +{ + COFF_ParsedSymbol result = {0}; + result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name); + result.value = sym32->value; + result.section_number = sym32->section_number; + result.type = sym32->type; + result.storage_class = sym32->storage_class; + result.aux_symbol_count = sym32->aux_symbol_count; + return result; +} + +internal COFF_ParsedSymbol +coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16) +{ + COFF_ParsedSymbol result = {0}; + result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name); + result.value = sym16->value; + if (sym16->section_number == COFF_Symbol_DebugSection16) { + result.section_number = COFF_Symbol_DebugSection32; + } else if (sym16->section_number == COFF_Symbol_AbsSection16) { + result.section_number = COFF_Symbol_AbsSection32; + } else { + result.section_number = (U32)sym16->section_number; + } + result.type = sym16->type; + result.storage_class = sym16->storage_class; + result.aux_symbol_count = sym16->aux_symbol_count; + return result; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count) +{ + COFF_Symbol32Array result = {0}; + result.count = symbol_count; + result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8); + + Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count); + String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range); + COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str; + + for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) { + COFF_Symbol16 *sym16 = &sym16_arr[isymbol]; + COFF_Symbol32 *sym32 = &result.v[isymbol]; + + sym32->name = sym16->name; + sym32->value = sym16->value; + if (sym16->section_number == COFF_Symbol_DebugSection16) { + sym32->section_number = COFF_Symbol_DebugSection32; + } else if (sym16->section_number == COFF_Symbol_AbsSection16) { + sym32->section_number = COFF_Symbol_AbsSection32; + } else { + sym32->section_number = (U32)sym16->section_number; + } + sym32->type.v = sym16->type.v; + sym32->storage_class = sym16->storage_class; + sym32->aux_symbol_count = sym16->aux_symbol_count; + + // copy aux symbols + for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) { + COFF_Symbol16 *aux16 = sym16_arr + iaux; + COFF_Symbol32 *aux32 = result.v + iaux; + + // 32bit COFF uses 16bit aux symbols + MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16)); + MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16)); + } + + // take into account aux symbols + isymbol += sym32->aux_symbol_count; + } + + return result; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count) +{ + COFF_Symbol32Array result; + result.count = symbol_count; + result.v = (COFF_Symbol32 *)(data.str + symbol_array_off); + return result; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size) +{ + COFF_Symbol32Array result = {0}; + switch (symbol_size) { + case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break; + case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break; + } + return result; +} + +internal COFF_Symbol16Node * +coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol) +{ + COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1); + node->next = 0; + node->data = symbol; + SLLQueuePush(list->first, list->last, node); + list->count += 1; + return node; +} + +internal COFF_SymbolValueInterpType +coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class) +{ + if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) { + return COFF_SymbolValueInterp_Undefined; + } + if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) { + return COFF_SymbolValueInterp_Undefined; + } + if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) { + return COFF_SymbolValueInterp_Common; + } + if (section_number == COFF_Symbol_AbsSection32) { + return COFF_SymbolValueInterp_Abs; + } + if (section_number == COFF_Symbol_DebugSection32) { + return COFF_SymbolValueInterp_Debug; + } + if (storage_class == COFF_SymStorageClass_WeakExternal) { + return COFF_SymbolValueInterp_Weak; + } + return COFF_SymbolValueInterp_Regular; +} + +internal COFF_RelocNode * +coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc) +{ + COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1); + node->data = reloc; + SLLQueuePush(list->first, list->last, node); + ++list->count; + return node; +} + +internal COFF_RelocInfo +coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header) +{ + COFF_RelocInfo result = {0}; + if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) { + COFF_Reloc counter; + U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter); + if (read_size == sizeof(counter) && counter.apply_off > 0) { + result.array_off = header->relocs_foff + sizeof(COFF_Reloc); + result.count = counter.apply_off - 1; // exclude counter entry + } + } else { + result.array_off = header->relocs_foff; + result.count = header->reloc_count; + } + return result; +} + +internal String8 +coff_resource_string_from_str16(Arena *arena, String16 string) +{ + AssertAlways(string.size <= max_U16); + U16 size16 = (U16)string.size; + + U16 *buffer = push_array_no_zero(arena, U16, size16 + 1); + MemoryCopy(buffer + 0, &size16, sizeof(size16)); + MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0])); + + return str8_array(buffer, size16 + 1); +} + +internal String8 +coff_resource_string_from_str8(Arena *arena, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + String16 string16 = str16_from_8(scratch.arena, string); + String8 result = coff_resource_string_from_str16(arena, string16); + scratch_end(scratch); + return result; +} + +internal String8 +coff_resource_number_from_u16(Arena *arena, U16 number) +{ + U16 *buffer = push_array_no_zero(arena, U16, 2); + buffer[0] = max_U16; + buffer[1] = number; + return str8_array(buffer, 2); +} + +internal COFF_ResourceID +coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16) +{ + COFF_ResourceID id = {0}; + id.type = id_16->type; + switch (id_16->type) { + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_Number: { + id.u.number = id_16->u.number; + } break; + case COFF_ResourceIDType_String: { + id.u.string = str8_from_16(arena, id_16->u.string); + } break; + default: InvalidPath; + } + return id; +} + +internal U64 +coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out) +{ + U64 cursor = off; + + U16 flag = 0; + str8_deserial_read_struct(raw_res, cursor, &flag); + + if (flag == max_U16) { + id_out->type = COFF_ResourceIDType_Number; + cursor += sizeof(flag); + cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number); + } else { + id_out->type = COFF_ResourceIDType_String; + cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string); + } + + U64 read_size = cursor - off; + read_size = AlignPow2(read_size, COFF_ResourceAlign); + return read_size; +} + +internal U64 +coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out) +{ + String8 raw_header = str8_skip(raw_res, off); + U64 header_cursor = 0; + + // prefix + COFF_ResourceHeaderPrefix prefix = {0}; + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix); + + Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix)); + raw_header = str8_prefix(raw_header, prefix.header_size); + + // header + COFF_ResourceID16 type_16 = {0}; + COFF_ResourceID16 name_16 = {0}; + header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16); + header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics); + Assert(prefix.header_size == header_cursor); + + // convert utf-16 resource ids to utf-8 + res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16); + res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16); + + // read data + U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data); + Assert(prefix.data_size == data_read_size); + + // compute read size + U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign); + return read_size; +} + +internal COFF_ParsedResourceList +coff_resource_list_from_data(Arena *arena, String8 data) +{ + COFF_ParsedResourceList list = {0}; + U64 cursor; + for (cursor = 0 ; cursor < data.size; ) { + COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1); + cursor += coff_read_resource(arena, data, cursor, &node->data); + SLLQueuePush(list.first, list.last, node); + ++list.count; + } + Assert(cursor == data.size); + return list; +} + +internal String8 +coff_write_resource_id(Arena *arena, COFF_ResourceID id) +{ + String8 result = str8_zero(); + switch (id.type) { + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_Number: { + result = coff_resource_number_from_u16(arena, id.u.number); + } break; + case COFF_ResourceIDType_String: { + result = coff_resource_string_from_str8(arena, id.u.string); + } break; + default: InvalidPath; + } + return result; +} + +internal String8 +coff_write_resource(Arena *arena, + COFF_ResourceID type, + COFF_ResourceID name, + U32 data_version, + COFF_ResourceMemoryFlags memory_flags, + U16 language_id, + U32 version, + U32 characteristics, + String8 data) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List list = {0}; + + COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1); + String8 packed_type = coff_write_resource_id(scratch.arena, type); + String8 packed_name = coff_write_resource_id(scratch.arena, name); + + // prefix + header + str8_list_push(scratch.arena, &list, str8_struct(prefix)); + str8_list_push(scratch.arena, &list, packed_type); + str8_list_push(scratch.arena, &list, packed_name); + str8_list_push(scratch.arena, &list, str8_struct(&data_version)); + str8_list_push(scratch.arena, &list, str8_struct(&memory_flags)); + str8_list_push(scratch.arena, &list, str8_struct(&language_id)); + str8_list_push(scratch.arena, &list, str8_struct(&version)); + str8_list_push(scratch.arena, &list, str8_struct(&characteristics)); + + prefix->data_size = safe_cast_u32(data.size); + prefix->header_size = safe_cast_u32(list.total_size); + + // data + str8_list_push(scratch.arena, &list, data); + + // magic + str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic)); + + // align + U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size; + U8 *align = push_array(scratch.arena, U8, align_size); + str8_list_push(scratch.arena, &list, str8(align, align_size)); + + // join + String8 res = str8_list_join(arena, &list, 0); + + scratch_end(scratch); + return res; +} + +internal int +coff_resource_id_compar(void *raw_a, void *raw_b) +{ + int cmp; + COFF_ResourceID *a = raw_b; + COFF_ResourceID *b = raw_b; + if (a->type == b->type) { + switch (a->type) { + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_Number: cmp = u16_compar(&a->u.number, &b->u.number); break; + case COFF_ResourceIDType_String: cmp = str8_compar_case_sensitive(&a->u.string, &b->u.string); break; + default: InvalidPath; break; + } + } else { + cmp = u32_compar(&a->type, &b->type); + } + return cmp; +} + +internal B32 +coff_is_import(String8 raw_archive_member) +{ + B32 is_import = 0; + if (raw_archive_member.size >= sizeof(U16)*2) { + U16 *sig1 = (U16*)raw_archive_member.str; + U16 *sig2 = sig1 + 1; + is_import = *sig1 == COFF_Machine_Unknown && *sig2 == 0xffff; + } + return is_import; +} + +internal COFF_DataType +coff_data_type_from_data(String8 raw_archive_member) +{ + B32 is_big_obj = coff_is_big_obj(raw_archive_member); + if (is_big_obj) { + return COFF_DataType_BigObj; + } + B32 is_import = coff_is_import(raw_archive_member); + if (is_import) { + return COFF_DataType_Import; + } + return COFF_DataType_Obj; +} + +internal B32 +coff_is_regular_archive(String8 raw_archive) +{ + B32 is_archive = 0; + U8 sig[sizeof(g_coff_archive_sig)]; + if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) { + is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0; + } + return is_archive; +} + +internal B32 +coff_is_thin_archive(String8 raw_archive) +{ + B32 is_archive = 0; + U8 sig[sizeof(g_coff_thin_archive_sig)]; + if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) { + is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0; + } + return is_archive; +} + +internal COFF_ArchiveType +coff_archive_type_from_data(String8 raw_archive) +{ + if (coff_is_regular_archive(raw_archive)) { + return COFF_Archive_Regular; + } else if (coff_is_thin_archive(raw_archive)) { + return COFF_Archive_Thin; + } + return COFF_Archive_Null; +} + +internal U64 +coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out) +{ + COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header)); + if (header) { + String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) )); + String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) )); + String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) )); + String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id))); + String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) )); + String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) )); + String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end)); + + U32 data_size = u32_from_str8(size, 10); + U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader); + + header_out->name = name; + header_out->time_stamp = u32_from_str8(date, 10); + header_out->user_id = u32_from_str8(user_id, 10); + header_out->group_id = u32_from_str8(group_id, 10); + header_out->mode = mode; + header_out->is_end_correct = str8_match_lit("`\n", end, 0); + header_out->data_range = rng_1u64(data_off, data_off + data_size); + + return sizeof(*header); + } + return 0; +} + +internal COFF_ArchiveFirstMember +coff_parse_first_archive_member(COFF_ArchiveMember *member) +{ + Assert(str8_match_lit("/", member->header.name, 0)); + + U64 cursor = 0; + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + symbol_count = from_be_u32(symbol_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + cursor += dim_1u64(string_table_range); + + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); + U32 *member_offsets = (U32 *)raw_member_offsets.str; + U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); + + COFF_ArchiveFirstMember result = {0}; + result.symbol_count = symbol_count; + result.member_offset_count = member_offset_count; + result.member_offsets = member_offsets; + result.string_table = str8_substr(member->data, string_table_range); + + return result; +} + +internal COFF_ArchiveSecondMember +coff_parse_second_archive_member(COFF_ArchiveMember *member) +{ + COFF_ArchiveSecondMember result = {0}; + + if (str8_match_lit("/", member->header.name, 0)) { + U64 cursor = 0; + + U32 member_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &member_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); + cursor += dim_1u64(symbol_indices_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); + String8 raw_indices = str8_substr(member->data, symbol_indices_range); + + U32 *member_offsets = (U32 *)raw_member_offsets.str; + U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); + + U16 *symbol_indices = (U16 *)raw_indices.str; + U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); + + result.member_count = member_count; + result.symbol_count = symbol_count; + result.member_offsets = member_offsets; + result.member_offset_count = member_offset_count; + result.symbol_indices = symbol_indices; + result.symbol_index_count = symbol_index_count; + result.string_table = str8_substr(member->data, string_table_range); + } + + return result; +} + +internal String8 +coff_parse_long_name(String8 long_names, String8 name) +{ + String8 result = name; + if (name.size > 0 && name.str[0] == '/') { + String8 offset_str = str8(name.str + 1, name.size - 1); + U64 offset = u64_from_str8(offset_str, 10); + if (offset < long_names.size) { + U8 *ptr = long_names.str + offset; + U8 *opl = long_names.str + long_names.size; + for (; ptr < opl; ++ptr) { + if (*ptr == '\0' || *ptr == '\n') { + break; + } + } + result = str8_range(long_names.str + offset, ptr); + } + } + return result; +} + +internal U64 +coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out) +{ + COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header)); + if (header) { + Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size); + String8 raw_data = str8_substr(raw_archive_member, data_range); + U64 data_cursor = 0; + + header_out->version = header->version; + header_out->machine = header->machine; + header_out->time_stamp = header->time_stamp; + header_out->data_size = header->data_size; + header_out->hint_or_ordinal = header->hint_or_ordinal; + header_out->type = COFF_ImportHeader_ExtractType(header->flags); + header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags); + data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name); + data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name); + + Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size); + U64 read_size = sizeof(*header) + header->data_size; + return read_size; + } + return 0; +} + +internal COFF_ArchiveMember +coff_archive_member_from_offset(String8 raw_archive, U64 offset) +{ + COFF_ArchiveMember member = {0}; + coff_regular_archive_member_iter_next(raw_archive, &offset, &member); + return member; +} + +internal COFF_ArchiveMember +coff_archive_member_from_data(String8 raw_archive_member) +{ + return coff_archive_member_from_offset(raw_archive_member, 0); +} + +internal COFF_ParsedArchiveImportHeader +coff_archive_import_from_data(String8 raw_archive_member) +{ + COFF_ParsedArchiveImportHeader header = {0}; + coff_parse_import(raw_archive_member, 0, &header); + return header; +} + +internal U64 +coff_regular_archive_member_iter_init(String8 raw_archive) +{ + U64 cursor = raw_archive.size; + if (coff_is_regular_archive(raw_archive)) { + cursor = sizeof(g_coff_archive_sig); + } + return cursor; +} + +internal B32 +coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out) +{ + B32 is_parsed = 0; + + member_out->header.is_end_correct = 0; + U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header); + + if (member_out->header.is_end_correct) { + member_out->offset = *offset; + member_out->data = str8_substr(raw_archive, member_out->header.data_range); + + U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign); + *offset += read_size; + + is_parsed = 1; + } + + return is_parsed; +} + +internal U64 +coff_thin_archive_member_iter_init(String8 raw_archive) +{ + U64 cursor = raw_archive.size; + if (coff_is_thin_archive(raw_archive)) { + cursor = sizeof(g_coff_thin_archive_sig); + } + return cursor; +} + +internal B32 +coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out) +{ + B32 is_parsed = 0; + + member_out->header.is_end_correct = 0; + U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header); + + if (member_out->header.is_end_correct) { + Rng1U64 data_in_archive_range = {0}; + if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) { + data_in_archive_range = member_out->header.data_range; + } + + member_out->offset = *offset; + member_out->data = str8_substr(raw_archive, data_in_archive_range); + + U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign); + *offset += read_size; + + is_parsed = 1; + } + + return is_parsed; +} + +internal void +coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node) +{ + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal COFF_ArchiveParse +coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) +{ + String8 error = str8_zero(); + B32 has_second_header = 0; + B32 has_long_names = 0; + COFF_ArchiveMember first_header = {0}; + COFF_ArchiveMember second_header = {0}; + COFF_ArchiveMember long_names_member = {0}; + + COFF_ArchiveMemberNode *ptr = member_list.first; + + if (ptr) { + if (str8_match_lit("/", ptr->data.header.name, 0)) { + if (ptr->data.header.is_end_correct) { + first_header = ptr->data; + ptr = ptr->next; + } else { + error = str8_lit("first header doesn't have correct end"); + } + } + } else { + error = str8_lit("missing first header"); + } + + if (!error.size && ptr) { + if (str8_match_lit("/", ptr->data.header.name, 0)) { + if (ptr->data.header.is_end_correct) { + second_header = ptr->data; + ptr = ptr->next; + has_second_header = 1; + } else { + error = str8_lit("second header doesn't have correct end"); + } + } + } + + if (!error.size && ptr) { + if (str8_match_lit("//", ptr->data.header.name, 0)) { + if (ptr->data.header.is_end_correct) { + long_names_member = ptr->data; + ptr = ptr->next; + has_long_names; + } else { + error = str8_lit("long names header doesn't have correct end"); + } + } + } + + COFF_ArchiveParse parse = {0}; + parse.has_second_header = has_second_header; + parse.has_long_names = has_long_names; + parse.first_member = coff_parse_first_archive_member(&first_header); + parse.second_member = coff_parse_second_archive_member(&second_header); + parse.long_names = long_names_member.data; + parse.error = error; + + return parse; +} + +internal COFF_ArchiveParse +coff_regular_archive_parse_from_data(String8 raw_archive) +{ + COFF_ArchiveMemberList list = {0}; + COFF_ArchiveMemberNode node_arr[3] = {0}; + U64 cursor = coff_regular_archive_member_iter_init(raw_archive); + for (U64 i = 0; i < ArrayCount(node_arr); ++i) { + COFF_ArchiveMemberNode *node = &node_arr[i]; + if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) { + break; + } + coff_archive_member_list_push_node(&list, node); + } + return coff_archive_parse_from_member_list(list); +} + +internal COFF_ArchiveParse +coff_thin_archive_parse_from_data(String8 raw_archive) +{ + COFF_ArchiveMemberList list = {0}; + COFF_ArchiveMemberNode node_arr[3] = {0}; + U64 cursor = coff_thin_archive_member_iter_init(raw_archive); + for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { + COFF_ArchiveMemberNode *node = &node_arr[i]; + if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) { + break; + } + coff_archive_member_list_push_node(&list, node); + } + return coff_archive_parse_from_member_list(list); +} + +internal COFF_ArchiveParse +coff_archive_parse_from_data(String8 raw_archive) +{ + COFF_ArchiveType type = coff_archive_type_from_data(raw_archive); + switch (type) { + case COFF_Archive_Null: break; + case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive); + case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive); + } + COFF_ArchiveParse null_parse = {0}; + return null_parse; +} + diff --git a/src/coff/coff_parse.h b/src/coff/coff_parse.h new file mode 100644 index 00000000..2ed92e92 --- /dev/null +++ b/src/coff/coff_parse.h @@ -0,0 +1,315 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef COFF_PARSE_H +#define COFF_PARSE_H + +typedef struct COFF_FileHeaderInfo +{ + B32 is_big_obj; + COFF_MachineType machine; + U64 header_size; + U64 section_array_off; + U64 section_count_no_null; + U64 string_table_off; + U64 symbol_size; + U64 symbol_off; + U64 symbol_count; +} COFF_FileHeaderInfo; + +//////////////////////////////// + +typedef struct COFF_SectionHeaderArray +{ + U64 count; + COFF_SectionHeader *v; +} COFF_SectionHeaderArray; + +//////////////////////////////// + +typedef struct COFF_Symbol16Node +{ + struct COFF_Symbol16Node *next; + COFF_Symbol16 data; +} COFF_Symbol16Node; + +typedef struct COFF_Symbol16List +{ + U64 count; + COFF_Symbol16Node *first; + COFF_Symbol16Node *last; +} COFF_Symbol16List; + +typedef struct COFF_Symbol32Array +{ + U64 count; + COFF_Symbol32 *v; +} COFF_Symbol32Array; + +typedef struct COFF_ParsedSymbol +{ + String8 name; + U32 value; + U32 section_number; + COFF_SymbolType type; + COFF_SymStorageClass storage_class; + U8 aux_symbol_count; +} COFF_ParsedSymbol; + +typedef U32 COFF_SymbolValueInterpType; +enum +{ + COFF_SymbolValueInterp_Regular, // symbol has section and offset. + COFF_SymbolValueInterp_Weak, // symbol is overridable. + COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section. + COFF_SymbolValueInterp_Common, // symbol has no section but still has size. + COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address. + COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information. +}; + +//////////////////////////////// + +typedef struct COFF_RelocNode +{ + struct COFF_RelocNode *next; + COFF_Reloc data; +} COFF_RelocNode; + +typedef struct COFF_RelocList +{ + U64 count; + COFF_RelocNode *first; + COFF_RelocNode *last; +} COFF_RelocList; + +typedef struct COFF_RelocArray +{ + U64 count; + COFF_Reloc *v; +} COFF_RelocArray; + +typedef struct COFF_RelocInfo +{ + U64 array_off; + U64 count; +} COFF_RelocInfo; + +//////////////////////////////// + +typedef U32 COFF_ResourceIDType; +enum COFF_ResourceIDTypeEnum +{ + COFF_ResourceIDType_Null, + COFF_ResourceIDType_Number, + COFF_ResourceIDType_String, + COFF_ResourceIDType_Count +}; + +typedef struct COFF_ResourceID16 +{ + COFF_ResourceIDType type; + union { + U16 number; + String16 string; + } u; +} COFF_ResourceID16; + +typedef struct COFF_ResourceID +{ + COFF_ResourceIDType type; + union { + U16 number; + String8 string; + } u; +} COFF_ResourceID; + +typedef struct COFF_ParsedResource +{ + COFF_ResourceID type; + COFF_ResourceID name; + U32 data_version; + COFF_ResourceMemoryFlags memory_flags; + U16 language_id; + U32 version; + U32 characteristics; + String8 data; +} COFF_ParsedResource; + +typedef struct COFF_ParsedResourceNode +{ + struct COFF_ParsedResourceNode *next; + COFF_ParsedResource data; +} COFF_ParsedResourceNode; + +typedef struct COFF_ParsedResourceList +{ + U64 count; + COFF_ParsedResourceNode *first; + COFF_ParsedResourceNode *last; +} COFF_ParsedResourceList; + +//////////////////////////////// + +typedef enum +{ + COFF_DataType_Null, + COFF_DataType_Obj, + COFF_DataType_BigObj, + COFF_DataType_Import +} COFF_DataType; + +typedef enum +{ + COFF_Archive_Null, + COFF_Archive_Regular, + COFF_Archive_Thin +} COFF_ArchiveType; + +typedef struct COFF_ParsedArchiveMemberHeader +{ + String8 name; // padded to 16 bytes with spaces + COFF_TimeStamp time_stamp; + U32 user_id; // unix artifact that does not have meaning on windows + U32 group_id; // unix artifact that does not have meaning on windows + String8 mode; // octal representation the members file mode + B32 is_end_correct; // set to true if found correct signature after header + Rng1U64 data_range; +} COFF_ParsedArchiveMemberHeader; + +typedef struct COFF_ParsedArchiveImportHeader +{ + B32 is_sig_correct; + U16 version; + COFF_MachineType machine; + COFF_TimeStamp time_stamp; + U32 data_size; + U16 hint_or_ordinal; + COFF_ImportType type; + COFF_ImportByType import_by; + String8 func_name; + String8 dll_name; +} COFF_ParsedArchiveImportHeader; + +typedef struct COFF_ArchiveMember +{ + COFF_ParsedArchiveMemberHeader header; + U64 offset; + String8 data; +} COFF_ArchiveMember; + +typedef struct COFF_ArchiveFirstMember +{ + U32 symbol_count; + U64 member_offset_count; + U32 *member_offsets; + String8 string_table; +} COFF_ArchiveFirstMember; + +typedef struct COFF_ArchiveSecondMember +{ + U32 member_count; + U32 symbol_count; + U64 member_offset_count; + U32 *member_offsets; + U64 symbol_index_count; + U16 *symbol_indices; + String8 string_table; +} COFF_ArchiveSecondMember; + +typedef struct COFF_ArchiveMemberNode +{ + struct COFF_ArchiveMemberNode *next; + COFF_ArchiveMember data; +} COFF_ArchiveMemberNode; + +typedef struct COFF_ArchiveMemberList +{ + U64 count; + COFF_ArchiveMemberNode *first; + COFF_ArchiveMemberNode *last; +} COFF_ArchiveMemberList; + +typedef struct COFF_ArchiveParse +{ + B32 has_second_header; + B32 has_long_names; + COFF_ArchiveFirstMember first_member; + COFF_ArchiveSecondMember second_member; + String8 long_names; + String8 error; +} COFF_ArchiveParse; + +//////////////////////////////// +// Obj Header + +internal B32 coff_is_big_obj(String8 raw_coff); +internal B32 coff_is_obj (String8 raw_coff); +internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff); + +//////////////////////////////// +// Symbol + +internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32); +internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16); + +internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); +internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); +internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size); + +internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol); + +internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class); + +//////////////////////////////// +// Reloc + +internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header); + +//////////////////////////////// +// Resource + +internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string); +internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string); +internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number); +internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16); + +internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out); +internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out); +internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data); + +internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id); +internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data); + +internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID + +//////////////////////////////// +// Archive + +internal B32 coff_is_import (String8 raw_archive_member); +internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member); +internal B32 coff_is_regular_archive (String8 raw_archive); +internal B32 coff_is_thin_archive (String8 raw_archive); +internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive); + +internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out); +internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member); +internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member); +internal String8 coff_parse_long_name (String8 long_names, String8 name); +internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out); + +internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset); +internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member); +internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member); + +internal U64 coff_regular_archive_member_iter_init(String8 raw_archive); +internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out); + +internal U64 coff_thin_archive_member_iter_init(String8 raw_archive); +internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out); + +internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list); +internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive); +internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive); +internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive); + +#endif // COFF_PARSE_H diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 41012033..3be0a2fb 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3489,20 +3489,20 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } //- rjf: read COFF header - U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); - COFF_Header coff_header = {0}; + U64 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_FileHeader file_header = {0}; if(is_valid) { - if(!dmn_process_read_struct(process.dmn_handle, vaddr_range.min + coff_header_off, &coff_header)) + if(!dmn_process_read_struct(process.dmn_handle, vaddr_range.min + file_header_off, &file_header)) { is_valid = 0; } } //- rjf: unpack range of optional extension header - U32 opt_ext_size = coff_header.optional_header_size; - Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), - coff_header_off + sizeof(coff_header) + opt_ext_size); + U32 opt_ext_size = file_header.optional_header_size; + Rng1U64 opt_ext_off_range = r1u64(file_header_off + sizeof(COFF_FileHeader), + file_header_off + sizeof(COFF_FileHeader) + opt_ext_size); //- rjf: read optional header U16 optional_magic = 0; @@ -3569,10 +3569,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ PE_DataDirectory dir = {0}; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir); Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); - switch(coff_header.machine) + switch(file_header.machine) { default:{}break; - case COFF_MachineType_X86: + case COFF_Machine_X86: { PE_TLSHeader32 tls_header32 = {0}; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header32); @@ -3583,7 +3583,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; tls_header.characteristics = (U64)tls_header32.characteristics; }break; - case COFF_MachineType_X64: + case COFF_Machine_X64: { dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header); }break; diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index d31d029e..1ac146b0 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -469,9 +469,9 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) } // rjf: get COFF header - B32 got_coff_header = 0; - U64 coff_header_off = 0; - COFF_Header coff_header = {0}; + B32 got_file_header = 0; + U64 file_header_off = 0; + COFF_FileHeader file_header = {0}; if(pe_offset > 0) { U64 pe_magic_off = base_vaddr + pe_offset; @@ -479,28 +479,28 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); if(pe_magic == PE_MAGIC) { - coff_header_off = pe_magic_off + sizeof(pe_magic); - if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header)) + file_header_off = pe_magic_off + sizeof(pe_magic); + if(dmn_w32_process_read_struct(process, file_header_off, &file_header)) { - got_coff_header = 1; + got_file_header = 1; } } } // rjf: get arch and size DMN_W32_ImageInfo result = zero_struct; - if(got_coff_header) + if(got_file_header) { U64 optional_size_off = 0; Arch arch = Arch_Null; - switch(coff_header.machine) + switch(file_header.machine) { - case COFF_MachineType_X86: + case COFF_Machine_X86: { arch = Arch_x86; optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image); }break; - case COFF_MachineType_X64: + case COFF_Machine_X64: { arch = Arch_x64; optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); @@ -510,7 +510,7 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) } if(arch != Arch_Null) { - U64 optional_off = coff_header_off + sizeof(coff_header); + U64 optional_off = file_header_off + sizeof(COFF_FileHeader); U32 size = 0; if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size)) { diff --git a/src/linker/lnk.c b/src/linker/lnk.c index b29c6744..5f74851d 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -36,6 +36,7 @@ #include "path/path.h" #include "coff/coff.h" #include "coff/coff_enum.h" +#include "coff/coff_parse.h" #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" @@ -50,6 +51,7 @@ #include "path/path.c" #include "coff/coff.c" #include "coff/coff_enum.c" +#include "coff/coff_parse.c" #include "pe/pe.c" #include "codeview/codeview.c" #include "codeview/codeview_enum.c" @@ -391,8 +393,8 @@ lnk_res_string_id_is_before(void *raw_a, void *raw_b) { PE_Resource *a = raw_a; PE_Resource *b = raw_b; - Assert(a->id.type == COFF_ResourceIDType_STRING); - Assert(b->id.type == COFF_ResourceIDType_STRING); + Assert(a->id.type == COFF_ResourceIDType_String); + Assert(b->id.type == COFF_ResourceIDType_String); int is_before = str8_is_before_case_sensitive(&a->id.u.string, &b->id.u.string); return is_before; } @@ -402,8 +404,8 @@ lnk_res_number_id_is_before(void *raw_a, void *raw_b) { PE_Resource *a = raw_a; PE_Resource *b = raw_b; - Assert(a->id.type == COFF_ResourceIDType_NUMBER); - Assert(b->id.type == COFF_ResourceIDType_NUMBER); + Assert(a->id.type == COFF_ResourceIDType_Number); + Assert(b->id.type == COFF_ResourceIDType_Number); int is_before = u16_is_before(&a->id.u.number, &b->id.u.number); return is_before; } @@ -426,7 +428,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE dir_data_chunk->sort_idx = str8_lit("c"); PE_Resource root_wrapper = {0}; - root_wrapper.id.type = COFF_ResourceIDType_NUMBER; + root_wrapper.id.type = COFF_ResourceIDType_Number; root_wrapper.id.u.number = 0; root_wrapper.kind = PE_ResDataKind_DIR; root_wrapper.u.dir = root_dir; @@ -460,11 +462,11 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE stack->coff_entry_chunk = lnk_section_push_chunk_data(dir_sect, stack->coff_entry_array_chunk, str8_struct(entry), str8_zero()); switch (res->id.type) { - case COFF_ResourceIDType_NUMBER: { + case COFF_ResourceIDType_Number: { entry->name.id = res->id.u.number; } break; - case COFF_ResourceIDType_STRING: { + case COFF_ResourceIDType_String: { // TODO: we can make string table smaller by reusing offsets for same strings // not sure why high bit has to be turned on here since number id and string id entries are @@ -480,7 +482,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol); } break; - case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_Null: break; default: InvalidPath; } @@ -499,14 +501,14 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE // push sub directory chunk layout LNK_Chunk *dir_node_chunk = lnk_section_push_chunk_list(dir_sect, dir_tree_chunk, str8_zero()); - dir_node_chunk->align = COFF_RES_ALIGN; + dir_node_chunk->align = COFF_ResourceAlign; LNK_Chunk *dir_header_chunk = lnk_section_push_chunk_data(dir_sect, dir_node_chunk, str8_struct(dir_header), str8_zero()); LNK_Chunk *entry_array_chunk = lnk_section_push_chunk_list(dir_sect, dir_node_chunk, str8_zero()); lnk_chunk_set_debugf(dir_sect->arena, dir_header_chunk, "DIR_HEADER_CHUNK"); lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK"); // push symbols to patch coff entry - LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG); + LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_Resource_SubDirFlag); LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory @@ -542,8 +544,8 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE LNK_Chunk *resource_data_chunk = lnk_section_push_chunk_data(data_sect, data_sect->root, res->u.coff_res.data, str8_zero()); // windows errors out on unaligned data - coff_resource_data_entry_chunk->align = COFF_RES_ALIGN; - resource_data_chunk->align = COFF_RES_ALIGN; + coff_resource_data_entry_chunk->align = COFF_ResourceAlign; + resource_data_chunk->align = COFF_ResourceAlign; // relocate data String8 resource_data_symbol_name = push_str8f(symtab->arena->v[0], "$R%06X", total_res_count); @@ -725,8 +727,8 @@ lnk_make_res_obj(TP_Context *tp, COFF_Symbol16 coff_feat00 = {0}; MemoryCopyStr8(&coff_feat00.name, str8_lit("@feat.00")); coff_feat00.value = MSCRT_FeatFlag_HAS_SAFE_SEH|MSCRT_FeatFlag_UNKNOWN_4; - coff_feat00.section_number = COFF_SYMBOL_ABS_SECTION_16; - coff_feat00.storage_class = COFF_SymStorageClass_STATIC; + coff_feat00.section_number = COFF_Symbol_AbsSection16; + coff_feat00.storage_class = COFF_SymStorageClass_Static; coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_feat00); // emit coff symbols for section definitions @@ -749,7 +751,7 @@ lnk_make_res_obj(TP_Context *tp, coff_sect_symbol.value = 0; coff_sect_symbol.section_number = sect->isect; coff_sect_symbol.aux_symbol_count = 1; - coff_sect_symbol.storage_class = COFF_SymStorageClass_STATIC; + coff_sect_symbol.storage_class = COFF_SymStorageClass_Static; Assert(sect->isect <= max_U16); COFF_SymbolSecDef secdef = {0}; @@ -805,7 +807,7 @@ lnk_make_res_obj(TP_Context *tp, MemoryCopyStr8(&coff_symbol.name, symbol_name); coff_symbol.value = symbol_offset; coff_symbol.section_number = symbol_sect->isect; - coff_symbol.storage_class = COFF_SymStorageClass_STATIC; + coff_symbol.storage_class = COFF_SymStorageClass_Static; coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_symbol); // push coff reloc @@ -843,7 +845,7 @@ lnk_make_res_obj(TP_Context *tp, } } - LNK_Section *misc_sect = lnk_section_table_push(st, str8_lit(".misc"), COFF_SectionFlag_LNK_INFO|COFF_SectionFlag_LNK_REMOVE); + LNK_Section *misc_sect = lnk_section_table_push(st, str8_lit(".misc"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove); misc_sect->emit_header = 0; // serialize coff symbol list @@ -863,27 +865,27 @@ lnk_make_res_obj(TP_Context *tp, // build obj header { // init header - COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1); - coff_header->machine = machine; - coff_header->section_count = 0; // relocated - coff_header->time_stamp = time_stamp; - coff_header->symbol_table_foff = 0; // relocated - coff_header->symbol_count = 0; // relocated - coff_header->optional_header_size = 0; // no PE header in obj - coff_header->flags = COFF_Flag_32BIT_MACHINE; + COFF_FileHeader *file_header = push_array(header_sect->arena, COFF_FileHeader, 1); + file_header->machine = machine; + file_header->section_count = 0; // relocated + file_header->time_stamp = time_stamp; + file_header->symbol_table_foff = 0; // relocated + file_header->symbol_count = 0; // relocated + file_header->optional_header_size = 0; // no PE header in obj + file_header->flags = COFF_FileHeaderFlag_32BitMachine; // push coff header chunk - String8 coff_header_data = str8_struct(coff_header); - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, coff_header_data, str8_zero()); + String8 file_header_data = str8_struct(file_header); + LNK_Chunk *file_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, file_header_data, str8_zero()); // relocate coff header fields - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); - lnk_section_push_reloc(header_sect, coff_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_Header, symbol_table_foff), coff_symbol_table_symbol); - lnk_section_push_reloc(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, symbol_count), coff_symbol_count_symbol); + lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_FileHeader, symbol_table_foff), coff_symbol_table_symbol); + lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, symbol_count), coff_symbol_count_symbol); // push coff header symbol - LNK_Symbol *coff_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, coff_header_symbol); + LNK_Symbol *file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); + lnk_symbol_table_push(symtab, file_header_symbol); } // build section headers @@ -923,7 +925,7 @@ lnk_make_res_obj(TP_Context *tp, } // patch file fields - if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { LNK_Symbol *sect_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, sect->name); lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect_symbol); lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect_symbol); @@ -1034,13 +1036,13 @@ lnk_make_linker_coff_obj(TP_Context *tp, header_sect->emit_header = 0; { - COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1); - coff_header->machine = machine; - coff_header->section_count = 0; - coff_header->time_stamp = time_stamp; + COFF_FileHeader *file_header = push_array(header_sect->arena, COFF_FileHeader, 1); + file_header->machine = machine; + file_header->section_count = 0; + file_header->time_stamp = time_stamp; - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, coff_header, sizeof(*coff_header), str8_zero()); - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); + LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, file_header, sizeof(*file_header), str8_zero()); + lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); } { @@ -1139,7 +1141,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, } // emit relocs for file fields - if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { LNK_Symbol *sect_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, sect->name); lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect_symbol); lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect_symbol); @@ -1232,12 +1234,12 @@ lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *laz COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { - case COFF_DataType_IMPORT: { + case COFF_DataType_Import: { LNK_InputImport *input = lnk_input_import_list_push(arena, input_import_list); input->import_header = coff_archive_import_from_data(member_info.data); } break; - case COFF_DataType_BIG_OBJ: - case COFF_DataType_OBJ: { + case COFF_DataType_BigObj: + case COFF_DataType_Obj: { String8 obj_path = coff_parse_long_name(lazy->lib->long_names, member_info.header.name); // obj path in thin archive has slash appended which screws up @@ -1279,12 +1281,12 @@ lnk_push_linker_symbols(LNK_SymbolTable *symtab, COFF_MachineType machine) // passing it around as a function argument. // // 100h: lea rax, [rip + ffffff00h] ; -100h - LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_ANY, 0); + LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_Any, 0); { // load config symbols - if (machine == COFF_MachineType_X86) { - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); + if (machine == COFF_Machine_X86) { + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0); } // TODO: investigate IMAGE_ENCLAVE_CONFIG 32/64 @@ -1409,7 +1411,7 @@ lnk_build_debug_rdi(LNK_SectionTable *st, { ProfBeginFunction(); - LNK_Section *rdi_sect = lnk_section_table_push(st, str8_lit(".raddbg"), COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ); + LNK_Section *rdi_sect = lnk_section_table_push(st, str8_lit(".raddbg"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead); // push chunks String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path); @@ -1488,7 +1490,7 @@ lnk_build_guard_tables(TP_Context *tp, if (lnk_chunk_is_discarded(chunk)) { continue; } - if (~chunk->flags & COFF_SectionFlag_CNT_CODE) { + if (~chunk->flags & COFF_SectionFlag_CntCode) { continue; } Assert(chunk->type == LNK_Chunk_Leaf); @@ -1508,7 +1510,7 @@ lnk_build_guard_tables(TP_Context *tp, if (symbol_chunk->type != LNK_Chunk_Leaf) { continue; } - if (~symbol_chunk->flags & COFF_SectionFlag_CNT_CODE) { + if (~symbol_chunk->flags & COFF_SectionFlag_CntCode) { continue; } lnk_symbol_list_push(scratch.arena, &guard_symbol_list_table[GUARD_FIDS], symbol); @@ -1603,7 +1605,7 @@ lnk_build_guard_tables(TP_Context *tp, } // TODO: emit table for SEH on X86 - if (machine == COFF_MachineType_X86) { + if (machine == COFF_Machine_X86) { lnk_not_implemented("__safe_se_handler_table"); lnk_not_implemented("__safe_se_handler_count"); } @@ -2078,7 +2080,7 @@ internal LNK_Chunk * lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics) { - COFF_Header *file_header = push_array_no_zero(header_sect->arena, COFF_Header, 1); + COFF_FileHeader *file_header = push_array_no_zero(header_sect->arena, COFF_FileHeader, 1); file_header->machine = machine; file_header->time_stamp = time_stamp; file_header->symbol_table_foff = 0; @@ -2088,16 +2090,16 @@ lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LN file_header->flags = file_characteristics; LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, file_header, sizeof(*file_header), str8_zero()); - lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_HEADER_SYMBOL_NAME); + lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_FILE_HEADER_SYMBOL_NAME); - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); // :section_count - lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_16, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_16, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); // :optional_header_size - lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_Header, optional_header_size), str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); - lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_Header, optional_header_size), str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_FileHeader, optional_header_size), str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_FileHeader, optional_header_size), str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); return file_header_chunk; } @@ -2173,17 +2175,17 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, continue; } // :sizeof_uninited_data - if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (sect->flags & COFF_SectionFlag_CntUninitializedData) { lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_uninited_data), sect->name, LNK_SymbolScopeFlag_Internal); } // :sizeof_inited_data - if (sect->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + if (sect->flags & COFF_SectionFlag_CntInitializedData) { lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_inited_data), sect->name, LNK_SymbolScopeFlag_Internal); } // :sizeof_code - if (sect->flags & COFF_SectionFlag_CNT_CODE) { + if (sect->flags & COFF_SectionFlag_CntCode) { lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_code), sect->name, LNK_SymbolScopeFlag_Internal); } @@ -2202,7 +2204,7 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, lnk_section_push_reloc(header_sect, opt_header_chunk, LNK_Reloc_FILE_ALIGN_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_headers), &g_null_symbol); // :check_sum - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelectType_NODUPLICATES, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelect_NoDuplicates, 0); // :data_dir_count lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(PE_OptionalHeader32Plus, data_dir_count), str8_lit(LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -2272,11 +2274,11 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, } // push COFF header array chunk - LNK_Chunk *coff_header_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); - lnk_chunk_set_debugf(header_sect->arena, coff_header_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); + LNK_Chunk *COFF_FileHeader_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); + lnk_chunk_set_debugf(header_sect->arena, COFF_FileHeader_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); // define symbol for COFF header array - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_array_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, COFF_FileHeader_array_chunk, 0, 0, 0); // push headers for (LNK_Section *sect = §_arr.v[0], *sect_opl = sect + sect_arr.count; sect < sect_opl; sect += 1) { @@ -2286,38 +2288,38 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, if (!sect->has_layout) { continue; } - COFF_SectionHeader *coff_header = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1); + COFF_SectionHeader *COFF_FileHeader = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1); // TODO: for objs we can store long name in string table and write here /offset - if (sect->name.size > sizeof(coff_header->name)) { + if (sect->name.size > sizeof(COFF_FileHeader->name)) { lnk_error(LNK_Warning_LongSectionName, "not enough space in COFF section header to store entire name \"%S\"", sect->name); } - MemorySet(&coff_header->name[0], 0, sizeof(coff_header->name)); - MemoryCopy(&coff_header->name[0], sect->name.str, Min(sect->name.size, sizeof(coff_header->name))); - coff_header->vsize = 0; // :vsize - coff_header->voff = 0; // :voff - coff_header->fsize = 0; // :fsize - coff_header->foff = 0; // :foff - coff_header->relocs_foff = 0; // :relocs_foff - coff_header->lines_foff = 0; // obsolete - coff_header->reloc_count = 0; // :reloc_count - coff_header->line_count = 0; // obsolete - coff_header->flags = sect->flags; + MemorySet(&COFF_FileHeader->name[0], 0, sizeof(COFF_FileHeader->name)); + MemoryCopy(&COFF_FileHeader->name[0], sect->name.str, Min(sect->name.size, sizeof(COFF_FileHeader->name))); + COFF_FileHeader->vsize = 0; // :vsize + COFF_FileHeader->voff = 0; // :voff + COFF_FileHeader->fsize = 0; // :fsize + COFF_FileHeader->foff = 0; // :foff + COFF_FileHeader->relocs_foff = 0; // :relocs_foff + COFF_FileHeader->lines_foff = 0; // obsolete + COFF_FileHeader->reloc_count = 0; // :reloc_count + COFF_FileHeader->line_count = 0; // obsolete + COFF_FileHeader->flags = sect->flags; // push chunk - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, coff_header_array_chunk, coff_header, sizeof(*coff_header), str8_zero()); + LNK_Chunk *COFF_FileHeader_chunk = lnk_section_push_chunk_raw(header_sect, COFF_FileHeader_array_chunk, COFF_FileHeader, sizeof(*COFF_FileHeader), str8_zero()); // :vsize - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal); // :voff - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal); - if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { // :fsize - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal); // :foff - lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal); } // TODO: :reloc_off @@ -2325,10 +2327,10 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, } // push symbol for section header count - U64 header_count = coff_header_array_chunk->u.list->count; + U64 header_count = COFF_FileHeader_array_chunk->u.list->count; lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, header_count); - return coff_header_array_chunk; + return COFF_FileHeader_array_chunk; } internal LNK_Chunk * @@ -2371,7 +2373,7 @@ lnk_build_win32_image_header(LNK_SymbolTable *symtab, lnk_build_pe_magic(symtab, header_sect, pe_magic_chunk); lnk_build_coff_file_header(symtab, header_sect, coff_file_header_chunk, config->machine, config->time_stamp, config->file_characteristics); switch (config->machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { lnk_build_pe_optional_header_x64(symtab, header_sect, pe_optional_chunk, @@ -2455,13 +2457,13 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) LNK_Symbol *lazy = 0; switch (weak->lookup_type) { - case COFF_WeakExtType_NOLIBRARY: { + case COFF_WeakExt_NoLibrary: { // NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member. } break; - case COFF_WeakExtType_SEARCH_LIBRARY: { + case COFF_WeakExt_SearchLibrary: { lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); } break; - case COFF_WeakExtType_SEARCH_ALIAS: { + case COFF_WeakExt_SearchAlias: { lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); if (!lazy) { if (str8_match_lit(".weak.", symbol->name, StringMatchFlag_RightSideSloppy)) { @@ -2964,9 +2966,9 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) LNK_Section *sect = §_node->data; if (sect->has_layout) { U64 sect_size = lnk_file_size_from_chunk_ref(sect_id_map, sect->root->ref); - if (sect->flags & COFF_SectionFlag_CNT_CODE) { + if (sect->flags & COFF_SectionFlag_CntCode) { code_size += sect_size; - } else if (sect->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + } else if (sect->flags & COFF_SectionFlag_CntInitializedData) { data_size += sect_size; } } @@ -2974,21 +2976,21 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) LNK_Symbol *dos_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_HEADER_SYMBOL_NAME)); LNK_Symbol *dos_program_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_PROGRAM_SYMBOL_NAME)); - LNK_Symbol *coff_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME)); + LNK_Symbol *COFF_FileHeader_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME)); LNK_Symbol *coff_section_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME)); LNK_Symbol *pe_opt_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME)); LNK_Symbol *pe_directories_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME)); LNK_Chunk *dos_header_chunk = dos_header_symbol->u.defined.u.chunk; LNK_Chunk *dos_program_chunk = dos_program_symbol->u.defined.u.chunk; - LNK_Chunk *coff_header_chunk = coff_header_symbol->u.defined.u.chunk; + LNK_Chunk *COFF_FileHeader_chunk = COFF_FileHeader_symbol->u.defined.u.chunk; LNK_Chunk *coff_section_header_chunk = coff_section_header_symbol->u.defined.u.chunk; LNK_Chunk *pe_opt_header_chunk = pe_opt_header_symbol->u.defined.u.chunk; LNK_Chunk *pe_directories_chunk = pe_directories_symbol->u.defined.u.chunk; U64 dos_header_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_header_chunk->ref); U64 dos_program_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_program_chunk->ref); - U64 coff_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_header_chunk->ref); + U64 COFF_FileHeader_size = lnk_file_size_from_chunk_ref(sect_id_map, COFF_FileHeader_chunk->ref); U64 coff_section_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_section_header_chunk->ref); U64 pe_opt_header_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_opt_header_chunk->ref); U64 pe_directories_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_directories_chunk->ref); @@ -2997,7 +2999,7 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) str8_list_pushf(scratch.arena, &output_list, "--- Image Size Breakdown -------------------------------------------------------"); str8_list_pushf(scratch.arena, &output_list, " DOS Header: %M", dos_header_size); str8_list_pushf(scratch.arena, &output_list, " DOS Program Stub: %M", dos_program_size); - str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", coff_header_size); + str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", COFF_FileHeader_size); str8_list_pushf(scratch.arena, &output_list, " COFF Section Headers: %M", coff_section_header_size); str8_list_pushf(scratch.arena, &output_list, " PE Header: %M", pe_opt_header_size); str8_list_pushf(scratch.arena, &output_list, " Directories: %M", pe_directories_size); @@ -3403,8 +3405,8 @@ lnk_run(int argc, char **argv) String8 delay_helper_name = str8_zero(); switch (config->machine) { - case COFF_MachineType_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break; - case COFF_MachineType_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break; + case COFF_Machine_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break; + case COFF_Machine_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break; default: NotImplemented; } @@ -3438,7 +3440,7 @@ lnk_run(int argc, char **argv) for (String8Node *from_node = alt_name_list.from_list.first, *to_node = alt_name_list.to_list.first; from_node != 0; from_node = from_node->next, to_node = to_node->next) { - LNK_Symbol *weak = lnk_symbol_table_push_weak(symtab, from_node->string, COFF_WeakExtType_SEARCH_ALIAS, to_node->string); + LNK_Symbol *weak = lnk_symbol_table_push_weak(symtab, from_node->string, COFF_WeakExt_SearchAlias, to_node->string); lnk_symbol_list_push(scratch.arena, &input_weak_list, weak); } ProfEnd(); @@ -3458,12 +3460,12 @@ lnk_run(int argc, char **argv) case State_InputImports: { ProfBegin("Input Imports"); for (LNK_InputImport *input = input_import_list.first; input != 0; input = input->next) { - COFF_ImportHeader *import_header = &input->import_header; + COFF_ParsedArchiveImportHeader *import_header = &input->import_header; KeyValuePair *is_delayed = hash_table_search_path(delay_load_dll_ht, import_header->dll_name); if (is_delayed) { if (!imptab_delayed) { - Assert(config->machine != COFF_MachineType_UNKNOWN); + Assert(config->machine != COFF_Machine_Unknown); B32 is_unloadable = !!(config->flags & LNK_ConfigFlag_DelayUnload); B32 is_bindable = !!(config->flags & LNK_ConfigFlag_DelayBind); imptab_delayed = lnk_import_table_alloc_delayed(st, symtab, config->machine, is_unloadable, is_bindable); @@ -3478,7 +3480,7 @@ lnk_run(int argc, char **argv) } } else { if (!imptab_static) { - Assert(config->machine != COFF_MachineType_UNKNOWN); + Assert(config->machine != COFF_Machine_Unknown); imptab_static = lnk_import_table_alloc_static(st, symtab, config->machine); } LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_static, import_header->dll_name); @@ -3560,14 +3562,14 @@ lnk_run(int argc, char **argv) LNK_Obj *obj = &obj_node_arr.v[obj_idx].data; // derive machine from obj - if (config->machine == COFF_MachineType_UNKNOWN) { + if (config->machine == COFF_Machine_Unknown) { config->machine = obj->machine; - } else if (config->machine != COFF_MachineType_X64) { + } else if (config->machine != COFF_Machine_X64) { lnk_error_with_loc(LNK_Error_UnsupportedMachine, obj->path, obj->lib_path, "%S machine is supported", coff_string_from_machine_type(obj->machine)); } else { // is obj machine compatible? if (config->machine != obj->machine && - obj->machine != COFF_MachineType_UNKNOWN) { // obj with unknown machine type is compatible with any other machine type + obj->machine != COFF_Machine_Unknown) { // obj with unknown machine type is compatible with any other machine type lnk_error_obj(LNK_Error_IncompatibleObj, obj, "conflicting machine types expected %S but got %S", coff_string_from_machine_type(config->machine), @@ -3989,18 +3991,18 @@ lnk_run(int argc, char **argv) if (pdata_symbol) { String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, image_data, pdata_symbol->u.defined.u.chunk->ref); switch (config->machine) { - case COFF_MachineType_X86: - case COFF_MachineType_X64: { + case COFF_Machine_X86: + case COFF_Machine_X64: { U64 count = pdata.size / sizeof(PE_IntelPdata); radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664); } break; - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { + case COFF_Machine_Arm64: + case COFF_Machine_Arm: { AssertAlways(!"TOOD: ARM"); } break; - case COFF_MachineType_MIPSFPU: - case COFF_MachineType_MIPS16: - case COFF_MachineType_MIPSFPU16: { + case COFF_Machine_MipsFpu: + case COFF_Machine_Mips16: + case COFF_Machine_MipsFpu16: { AssertAlways(!"TODO: MIPS"); } break; } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index a1999a32..9f2b1b35 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -49,7 +49,7 @@ #define LNK_DOS_HEADER_SYMBOL_NAME "DOS_HEADER" #define LNK_DOS_PROGRAM_SYMBOL_NAME "DOS_PROGRAM" #define LNK_PE_MAGIC_SYMBOL_NAME "PE_MAGIC" -#define LNK_COFF_HEADER_SYMBOL_NAME "COFF_HEADER" +#define LNK_COFF_FILE_HEADER_SYMBOL_NAME "COFF_FILE_HEADER" #define LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME "PE_DIRECTORY_ARRAY" #define LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME "PE_DIRECTORY_COUNT" #define LNK_PE_OPT_HEADER_SYMBOL_NAME "PE_OPTIONAL_HEADER" @@ -82,10 +82,10 @@ #define LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME "__delayLoadHelper2" #define LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME "___delayLoadHelper2@8" -#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CNT_CODE|COFF_SectionFlag_MEM_EXECUTE|COFF_SectionFlag_MEM_READ) -#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE) -#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ) -#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CNT_UNINITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE) +#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead) +#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite) +#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead) +#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CntUninitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite) #define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS @@ -96,8 +96,8 @@ #define LNK_GIATS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_GLJMP_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_GEHCONT_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS -#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE) -#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE) +#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable) +#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable) //////////////////////////////// @@ -114,7 +114,7 @@ typedef String8List LNK_InputLibList; typedef struct LNK_InputImport { - COFF_ImportHeader import_header; + COFF_ParsedArchiveImportHeader import_header; struct LNK_InputImport *next; } LNK_InputImport; diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 353068dd..d05e8804 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -352,11 +352,11 @@ lnk_get_default_function_pad_min(COFF_MachineType machine) { U64 function_pad_min = 0; switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: { + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: { function_pad_min = 5; } break; - case COFF_MachineType_X64: { + case COFF_Machine_X64: { function_pad_min = 6; } break; default: { @@ -396,12 +396,12 @@ lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineTyp case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { - case COFF_MachineType_X64: - case COFF_MachineType_X86: ver = make_version(6,0); break; + case COFF_Machine_X64: + case COFF_Machine_X86: ver = make_version(6,0); break; - case COFF_MachineType_ARMNT: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: ver = make_version(6,2); break; + case COFF_Machine_ArmNt: + case COFF_Machine_Arm64: + case COFF_Machine_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -409,12 +409,12 @@ lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineTyp case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { - case COFF_MachineType_X64: - case COFF_MachineType_X86: ver = make_version(6,0); break; + case COFF_Machine_X64: + case COFF_Machine_X86: ver = make_version(6,0); break; - case COFF_MachineType_ARMNT: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: ver = make_version(6,2); break; + case COFF_Machine_ArmNt: + case COFF_Machine_Arm64: + case COFF_Machine_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -444,13 +444,13 @@ lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType ma case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { - case COFF_MachineType_X86: ver = make_version(5,1); break; + case COFF_Machine_X86: ver = make_version(5,1); break; - case COFF_MachineType_X64: ver = make_version(5,2); break; + case COFF_Machine_X64: ver = make_version(5,2); break; - case COFF_MachineType_ARMNT: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: ver = make_version(6,2); break; + case COFF_Machine_ArmNt: + case COFF_Machine_Arm64: + case COFF_Machine_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -458,13 +458,13 @@ lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType ma case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { - case COFF_MachineType_X86: ver = make_version(5,1); break; + case COFF_Machine_X86: ver = make_version(5,1); break; - case COFF_MachineType_X64: ver = make_version(5,2); break; + case COFF_Machine_X64: ver = make_version(5,2); break; - case COFF_MachineType_ARMNT: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: ver = make_version(6,2); break; + case COFF_Machine_ArmNt: + case COFF_Machine_Arm64: + case COFF_Machine_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -784,7 +784,7 @@ lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List // parse directive String8 name = str8_zero(); String8 alias = str8_zero(); - String8 type = coff_string_from_import_header_type(COFF_ImportHeaderType_CODE); + String8 type = coff_string_from_import_header_type(COFF_ImportHeader_Code); if (value_list.node_count > 0) { String8List dir_split = str8_split_by_string_chars(scratch.arena, value_list.first->string, str8_lit("="), 0); B32 is_export_valid = value_list.node_count <= 2 && value_list.node_count > 0; @@ -1193,7 +1193,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Machine: { if (value_strings.node_count == 1) { COFF_MachineType machine = coff_machine_from_string(value_strings.first->string); - if (machine != COFF_MachineType_UNKNOWN) { + if (machine != COFF_Machine_Unknown) { config->machine = machine; } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 055ac556..1c175386 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3025,7 +3025,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) // Mod1::fUpdateSecContrib if (sc_count > 0) { for (U64 sc_idx = 0; sc_idx < sc_count; ++sc_idx) { - if (sc_arr[sc_idx].data.base.flags & COFF_SectionFlag_CNT_CODE) { + if (sc_arr[sc_idx].data.base.flags & COFF_SectionFlag_CntCode) { mod->first_sc = sc_arr[sc_idx].data; break; } diff --git a/src/linker/lnk_export_table.c b/src/linker/lnk_export_table.c index 02bdba68..ff36c649 100644 --- a/src/linker/lnk_export_table.c +++ b/src/linker/lnk_export_table.c @@ -82,22 +82,22 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L // to CODE instead of DATA. But if you try export global variable with: // #pragma comment(linker, "/export:global_bar,CODE") // MSVC and LLD issue an error. For compatibility sake we do the same thing too. - COFF_ImportHeaderType type = coff_import_header_type_from_string(exp_parse->type); + COFF_ImportType type = coff_import_header_type_from_string(exp_parse->type); switch (type) { - case COFF_ImportHeaderType_CODE: { + case COFF_ImportHeader_Code: { B32 is_export_data = !(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk)); if (is_export_data) { lnk_error(LNK_Error_IllExport, "export \"%S\" is DATA but has specifier CODE", exp_parse->name); } } break; - case COFF_ImportHeaderType_DATA: { + case COFF_ImportHeader_Data: { B32 is_export_code = !!(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk)); if (is_export_code) { lnk_error(LNK_Error_IllExport, "export \"%S\" is CODE but has specifier DATA", exp_parse->name); } } break; - case COFF_ImportHeaderType_CONST: { - lnk_not_implemented("TODO: COFF_ImportHeaderType_CONST"); + case COFF_ImportHeader_Const: { + lnk_not_implemented("TODO: COFF_ImportHeader_Const"); } break; default: { if (exp_parse->type.size) { diff --git a/src/linker/lnk_export_table.h b/src/linker/lnk_export_table.h index 15c1205e..25cc31ca 100644 --- a/src/linker/lnk_export_table.h +++ b/src/linker/lnk_export_table.h @@ -5,13 +5,13 @@ typedef struct LNK_Export { - struct LNK_Export *next; - String8 name; - LNK_Symbol *symbol; - U32 id; - U16 ordinal; - COFF_ImportHeaderType type; - B32 is_private; + struct LNK_Export *next; + String8 name; + LNK_Symbol *symbol; + U32 id; + U16 ordinal; + COFF_ImportType type; + B32 is_private; } LNK_Export; typedef struct LNK_ExportList diff --git a/src/linker/lnk_import_table.c b/src/linker/lnk_import_table.c index 616de6fe..34f44e52 100644 --- a/src/linker/lnk_import_table.c +++ b/src/linker/lnk_import_table.c @@ -345,7 +345,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt // emit tail merge LNK_Chunk *tail_merge_chunk = 0; switch (machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol); } break; @@ -375,7 +375,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt } internal LNK_ImportFunc * -lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header) +lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) { ProfBeginFunction(); @@ -395,20 +395,20 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt U64 import_size = coff_word_size_from_machine(dll->machine); // generate sort index (optional) - String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint); + String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal); - switch (header->name_type) { - case COFF_ImportHeaderNameType_ORDINAL: { - String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint); + switch (header->import_by) { + case COFF_ImportBy_Ordinal: { + String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal); ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index); iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, ordinal_data, sort_index); // associate chunks lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk); } break; - case COFF_ImportHeaderNameType_NAME: { + case COFF_ImportBy_Name: { // put together name look up entry - String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name); + String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name); LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); // create symbol for lookup chunk @@ -429,11 +429,11 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol); lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol); } break; - case COFF_ImportHeaderNameType_UNDECORATE: { - lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE"); + case COFF_ImportBy_Undecorate: { + lnk_not_implemented("TODO: COFF_ImportBy_Undecorate"); } break; - case COFF_ImportHeaderNameType_NAME_NOPREFIX: { - lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX"); + case COFF_ImportBy_NameNoPrefix: { + lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix"); } break; } @@ -444,9 +444,9 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt // generate thunks LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; - if (header->type == COFF_ImportHeaderType_CODE) { + if (header->type == COFF_ImportHeader_Code) { switch (dll->machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { // generate jump thunk LNK_Chunk *jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol); lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk); @@ -472,7 +472,7 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt } internal LNK_ImportFunc * -lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header) +lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) { ProfBeginFunction(); @@ -498,16 +498,16 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym LNK_Symbol *int_symbol = 0; // generate sort index (optional) - String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint); + String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal); // generate thunks LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; LNK_Symbol *load_thunk_symbol = g_null_symbol_ptr; LNK_Chunk *jmp_thunk_chunk = 0; LNK_Chunk *load_thunk_chunk = 0; - if (header->type == COFF_ImportHeaderType_CODE) { + if (header->type == COFF_ImportHeader_Code) { switch (dll->machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name); LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main); @@ -523,9 +523,9 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym } } - switch (header->name_type) { - case COFF_ImportHeaderNameType_ORDINAL: { - String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint); + switch (header->import_by) { + case COFF_ImportBy_Ordinal: { + String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal); Assert(ordinal_data.size == import_size); ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index); iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index); @@ -543,9 +543,9 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym lnk_section_associate_chunks(data_sect, iat_chunk, uiat_chunk); } } break; - case COFF_ImportHeaderNameType_NAME: { + case COFF_ImportBy_Name: { // put together name look up entry - String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name); + String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name); LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); // create symbol for lookup chunk @@ -586,11 +586,11 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol); } } break; - case COFF_ImportHeaderNameType_UNDECORATE: { - lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE"); + case COFF_ImportBy_Undecorate: { + lnk_not_implemented("TODO: COFF_ImportBy_Undecorate"); } break; - case COFF_ImportHeaderNameType_NAME_NOPREFIX: { - lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX"); + case COFF_ImportBy_NameNoPrefix: { + lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix"); } break; } @@ -624,14 +624,14 @@ lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) { String8 ordinal_data = str8_zero(); switch (machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { U64 *ordinal = push_array(arena, U64, 1); - *ordinal = coff_make_ordinal_64(hint); + *ordinal = coff_make_ordinal64(hint); ordinal_data = str8_struct(ordinal); } break; - case COFF_MachineType_X86: { + case COFF_Machine_X86: { U32 *ordinal = push_array(arena, U32, 1); - *ordinal = coff_make_ordinal_32(hint); + *ordinal = coff_make_ordinal32(hint); ordinal_data = str8_struct(ordinal); } break; default: lnk_not_implemented("TODO: support for machine 0x%x", machine); @@ -736,7 +736,7 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu ProfBeginFunction(); // emit load thunk symbol String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name); - LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_NODUPLICATES, 0); + LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0); ProfEnd(); return load_thunk_symbol; } @@ -746,7 +746,7 @@ lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fun { ProfBeginFunction(); String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name); - LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_ANY, 0); + LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_Any, 0); ProfEnd(); return jmp_thunk_symbol; } @@ -756,7 +756,7 @@ lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu { ProfBeginFunction(); String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name); - LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelectType_NODUPLICATES, 0); + LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0); ProfEnd(); return tail_merge_symbol; } diff --git a/src/linker/lnk_import_table.h b/src/linker/lnk_import_table.h index 0299c911..6005b622 100644 --- a/src/linker/lnk_import_table.h +++ b/src/linker/lnk_import_table.h @@ -64,8 +64,8 @@ internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *st, internal void lnk_import_table_release(LNK_ImportTable **imptab); internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); -internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header); -internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header); +internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); +internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name); internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 22225e42..b200b1db 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -303,19 +303,19 @@ lnk_lib_writer_push_export(LNK_LibWriter *writer, COFF_MachineType machine, U64 lnk_lib_member_list_push(writer->arena, &writer->member_list, member); switch (exp->type) { - case COFF_ImportHeaderType_CODE: { + case COFF_ImportHeader_Code: { LNK_LibSymbol def_symbol = {0}; def_symbol.name = push_str8_copy(writer->arena, exp->name); def_symbol.member_idx = member_idx; lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, def_symbol); } - case COFF_ImportHeaderType_DATA: { + case COFF_ImportHeader_Data: { LNK_LibSymbol imp_symbol = {0}; imp_symbol.name = push_str8f(writer->arena, "__imp_%S", exp->name); imp_symbol.member_idx = member_idx; lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, imp_symbol); } break; - case COFF_ImportHeaderType_CONST: { + case COFF_ImportHeader_Const: { NotImplemented; } break; default: InvalidPath; @@ -361,7 +361,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second // make member name String8 name; U64 name_with_slash_size = member->name.size + 1; - if (name_with_slash_size > COFF_ARCHIVE_MAX_SHORT_NAME_SIZE) { + if (name_with_slash_size > COFF_Archive_MaxShortNameSize) { // have we seen this member name before? KeyValuePair *is_present = hash_table_search_string(name_ht, member->name); if (is_present) { @@ -382,7 +382,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second str8_list_push(arena, &member_data_list, member_header); str8_list_push(arena, &member_data_list, member_data); - str8_list_push_pad(arena, &member_data_list, member_data_list.total_size, COFF_ARCHIVE_ALIGN); + str8_list_push_pad(arena, &member_data_list, member_data_list.total_size, COFF_Archive_MemberAlign); } // long names member @@ -390,7 +390,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second String8 header = lnk_build_lib_member_header(arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size); String8 data = str8_list_join(arena, &long_names_list, 0); U64 member_offset = member_data_list.total_size + data.size + header.size; - str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN); + str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign); str8_list_push_front(arena, &member_data_list, data); str8_list_push_front(arena, &member_data_list, header); } @@ -415,13 +415,13 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second U64 member_base_off; { - U64 sizeof_first_header = COFF_ARCHIVE_MEMBER_HEADER_SIZE + sizeof(U32) + sizeof(U32) * symbol_count + name_buffer_size; - U64 sizeof_second_header = COFF_ARCHIVE_MEMBER_HEADER_SIZE + sizeof(U32) + sizeof(U32) * lib->member_count + sizeof(U32) + sizeof(U16) * symbol_count + name_buffer_size; - U64 sizeof_long_names = COFF_ARCHIVE_MEMBER_HEADER_SIZE + long_names_list.total_size; + U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * symbol_count + name_buffer_size; + U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib->member_count + sizeof(U32) + sizeof(U16) * symbol_count + name_buffer_size; + U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size; - sizeof_first_header = AlignPow2(sizeof_first_header, COFF_ARCHIVE_ALIGN); - sizeof_second_header = AlignPow2(sizeof_second_header, COFF_ARCHIVE_ALIGN); - sizeof_long_names = AlignPow2(sizeof_long_names, COFF_ARCHIVE_ALIGN); + sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign); + sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign); + sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign); member_base_off = sizeof(g_coff_archive_sig); member_base_off += sizeof_first_header; @@ -468,7 +468,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second String8 member_header = lnk_build_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); U64 member_offset = member_data_list.total_size + member_data.size + member_header.size; - str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN); + str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign); str8_list_push_front(arena, &member_data_list, member_data); str8_list_push_front(arena, &member_data_list, member_header); } @@ -497,7 +497,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second String8 member_header = lnk_build_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size; - str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN); + str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign); str8_list_push_front(arena, &member_data_list, member_data); str8_list_push_front(arena, &member_data_list, member_header); } @@ -541,18 +541,18 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach { ProfBeginFunction(); - Assert(machine == COFF_MachineType_X64); + Assert(machine == COFF_Machine_X64); Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); String8List list = {0}; - COFF_Header *coff_header = push_array(arena, COFF_Header, 1); - coff_header->machine = machine; - str8_list_push(arena, &list, str8_struct(coff_header)); + COFF_FileHeader *file_header = push_array(arena, COFF_FileHeader, 1); + file_header->machine = machine; + str8_list_push(arena, &list, str8_struct(file_header)); - coff_header->section_count = 2; - COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count); - str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count)); + file_header->section_count = 2; + COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, file_header->section_count); + str8_list_push(arena, &list, str8_array(coff_sect_header_array, file_header->section_count)); PE_ImportEntry *import_entry = push_array(arena, PE_ImportEntry, 1); U64 import_entry_off = list.total_size; @@ -567,10 +567,10 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach U64 import_entry_reloc_off = list.total_size; str8_list_push(arena, &list, str8_array(import_entry_reloc_array, import_entry_reloc_count)); - coff_header->symbol_count = 7; - COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count); - coff_header->symbol_table_foff = safe_cast_u32(list.total_size); - str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count)); + file_header->symbol_count = 7; + COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, file_header->symbol_count); + file_header->symbol_table_foff = safe_cast_u32(list.total_size); + str8_list_push(arena, &list, str8_array(symbol_array, file_header->symbol_count)); U64 string_table_base = list.total_size; U32 *string_table_size_ptr = push_array(arena, U32, 1); @@ -591,23 +591,23 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach sect->foff = import_entry_off; sect->reloc_count = import_entry_reloc_count; sect->relocs_foff = import_entry_reloc_off; - sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_4BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE; + sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; } { COFF_Reloc *lookup_table_voff_reloc = &import_entry_reloc_array[0]; lookup_table_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, lookup_table_voff); lookup_table_voff_reloc->isymbol = 3; - lookup_table_voff_reloc->type = COFF_RelocTypeX64_ADDR32NB; + lookup_table_voff_reloc->type = COFF_Reloc_X64_Addr32Nb; COFF_Reloc *name_voff_reloc = &import_entry_reloc_array[1]; name_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, name_voff); name_voff_reloc->isymbol = 2; - name_voff_reloc->type = COFF_RelocTypeX64_ADDR32NB; + name_voff_reloc->type = COFF_Reloc_X64_Addr32Nb; COFF_Reloc *import_addr_table_voff = &import_entry_reloc_array[2]; import_addr_table_voff->apply_off = OffsetOf(PE_ImportEntry, import_addr_table_voff); import_addr_table_voff->isymbol = 4; - import_addr_table_voff->type = COFF_RelocTypeX64_ADDR32NB; + import_addr_table_voff->type = COFF_Reloc_X64_Addr32Nb; } // dll name @@ -623,7 +623,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach sect->name[7] = '6'; sect->fsize = dll_name_cstr.size; sect->foff = dll_name_off; - sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_2BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE; + sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; } // import descriptor @@ -638,7 +638,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach symbol->name.long_name.zeroes = 0; symbol->name.long_name.string_table_offset = symbol_name_off; symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_EXTERNAL; + symbol->storage_class = COFF_SymStorageClass_External; } // .idata$2 @@ -653,7 +653,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach symbol->name.short_name[6] = '$'; symbol->name.short_name[7] = '2'; symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_SECTION; + symbol->storage_class = COFF_SymStorageClass_Section; } // .idata$6 @@ -668,7 +668,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach symbol->name.short_name[6] = '$'; symbol->name.short_name[7] = '6'; symbol->section_number = 2; - symbol->storage_class = COFF_SymStorageClass_STATIC; + symbol->storage_class = COFF_SymStorageClass_Static; } // .idata$4 @@ -682,8 +682,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach symbol->name.short_name[5] = 'a'; symbol->name.short_name[6] = '$'; symbol->name.short_name[7] = '4'; - symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION; - symbol->storage_class = COFF_SymStorageClass_SECTION; + symbol->section_number = COFF_Symbol_UndefinedSection; + symbol->storage_class = COFF_SymStorageClass_Section; } // .idata$5 @@ -697,8 +697,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach symbol->name.short_name[5] = 'a'; symbol->name.short_name[6] = '$'; symbol->name.short_name[7] = '5'; - symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION; - symbol->storage_class = COFF_SymStorageClass_SECTION; + symbol->section_number = COFF_Symbol_UndefinedSection; + symbol->storage_class = COFF_SymStorageClass_Section; } // __NULL_IMPORT_DESCRIPTOR @@ -709,8 +709,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach COFF_Symbol16 *symbol = &symbol_array[5]; symbol->name.long_name.zeroes = 0; symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION; - symbol->storage_class = COFF_SymStorageClass_EXTERNAL; + symbol->section_number = COFF_Symbol_UndefinedSection; + symbol->storage_class = COFF_SymStorageClass_External; } // NULL_THUNK_DATA @@ -724,8 +724,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach COFF_Symbol16 *symbol = &symbol_array[6]; symbol->name.long_name.zeroes = 0; symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION; - symbol->storage_class = COFF_SymStorageClass_EXTERNAL; + symbol->section_number = COFF_Symbol_UndefinedSection; + symbol->storage_class = COFF_SymStorageClass_External; } // update string table size @@ -742,7 +742,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine) String8List list = {0}; - COFF_Header *coff_header = push_array(arena, COFF_Header, 1); + COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1); coff_header->machine = machine; str8_list_push(arena, &list, str8_struct(coff_header)); @@ -776,7 +776,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine) sect->name[7] = '3'; sect->fsize = null_import_data_size; sect->foff = null_import_data_off; - sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_4BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE; + sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; } { @@ -787,7 +787,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine) symbol->name.long_name.zeroes = 0; symbol->name.long_name.string_table_offset = symbol_name_off; symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_EXTERNAL; + symbol->storage_class = COFF_SymStorageClass_External; } // update string table size @@ -806,7 +806,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m String8List list = {0}; - COFF_Header *coff_header = push_array(arena, COFF_Header, 1); + COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1); coff_header->machine = machine; str8_list_push(arena, &list, str8_struct(coff_header)); @@ -845,7 +845,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m sect->name[7] = '5'; sect->fsize = lookup_entry_data_size; sect->foff = lookup_entry_data_off; - sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_8BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE; + sect->flags = COFF_SectionFlag_CntInitializedData | (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|(COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite); } { @@ -860,7 +860,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m sect->name[7] = '4'; sect->fsize = null_thunk_data_size; sect->foff = null_thunk_data_off; - sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_8BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE; + sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; } { @@ -874,7 +874,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m symbol->name.long_name.zeroes = 0; symbol->name.long_name.string_table_offset = symbol_name_off; symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_EXTERNAL; + symbol->storage_class = COFF_SymStorageClass_External; } // update string table size @@ -908,7 +908,7 @@ lnk_build_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stam str8_list_pushf(scratch.arena, &list, "`\n"); String8 result = str8_list_join(arena, &list, 0); - Assert(result.size == COFF_ARCHIVE_MEMBER_HEADER_SIZE); + Assert(result.size == sizeof(COFF_ArchiveMemberHeader)); scratch_end(scratch); ProfEnd(); return result; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index d971b459..d53802d2 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -327,7 +327,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) String8 cached_lib_path = push_str8_copy(arena, input->lib_path); // parse coff obj - COFF_HeaderInfo coff_info = coff_header_info_from_data(input->data); + COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(input->data); Rng1U64 coff_file_header_range = rng_1u64(0, coff_info.header_size); Rng1U64 coff_sect_arr_range = rng_1u64(coff_info.section_array_off, coff_info.section_array_off + coff_info.section_count_no_null * sizeof(COFF_SectionHeader)); Rng1U64 coff_symbols_range = rng_1u64(coff_info.symbol_off, coff_info.symbol_off + coff_info.symbol_count * coff_info.symbol_size); @@ -368,13 +368,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx]; // read name - String8 sect_name = coff_name_from_section_header(coff_sect, input->data, coff_info.string_table_off); + String8 sect_name = coff_name_from_section_header(input->data, coff_sect, coff_info.string_table_off); // parse section name coff_parse_section_name(sect_name, §_name_arr[sect_idx], §_sort_arr[sect_idx]); String8 data; - if (coff_sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (coff_sect->flags & COFF_SectionFlag_CntUninitializedData) { data = str8(0, coff_sect->fsize); } else { if (coff_sect->fsize > 0) { @@ -403,7 +403,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) LNK_Chunk *chunk = &chunk_arr[sect_idx]; chunk->align = coff_align_size_from_section_flags(coff_sect->flags); - chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LNK_REMOVE); + chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LnkRemove); chunk->sort_chunk = 1; chunk->type = LNK_Chunk_Leaf; chunk->sort_idx = sect_sort_arr[sect_idx]; @@ -433,8 +433,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // convert from coff - B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, coff_info.is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); @@ -495,7 +494,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_new_sect_scanner) for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) { String8 sect_name = obj->sect_name_arr[chunk_idx]; - COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx]->flags & ~COFF_SectionFlags_LNK_FLAGS; + COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx]->flags & ~COFF_SectionFlags_LnkFlags; KeyValuePair *is_present = hash_table_search_string(ht, sect_name); if (is_present) { @@ -675,7 +674,7 @@ lnk_obj_list_push_parallel(TP_Context *tp, // push new sections for :find_chunk_section for (LNK_SectDefn *curr = new_list.first; curr != 0; curr = curr->next) { - lnk_section_table_push(st, curr->name, curr->flags & ~COFF_SectionFlags_LNK_FLAGS); + lnk_section_table_push(st, curr->name, curr->flags & ~COFF_SectionFlags_LnkFlags); } tp_temp_end(temp); @@ -763,7 +762,7 @@ lnk_symbol_array_from_coff(Arena *arena, // is this a function symbol? COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_REGULAR && COFF_SymbolType_IsFunc(symbol.type)) { + if (interp == COFF_SymbolValueInterp_Regular && COFF_SymbolType_IsFunc(symbol.type)) { if (symbol.section_number == 0 || symbol.section_number > sect_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number); } @@ -879,7 +878,7 @@ lnk_symbol_array_from_coff(Arena *arena, COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); switch (interp) { - case COFF_SymbolValueInterp_REGULAR: { + case COFF_SymbolValueInterp_Regular: { if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); } @@ -889,7 +888,7 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { visibility = LNK_DefinedSymbolVisibility_Extern; } LNK_DefinedSymbolFlags flags = 0; @@ -900,15 +899,15 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_Chunk *chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; U64 offset = parsed_symbol.value; - COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; + COFF_ComdatSelectType selection = COFF_ComdatSelect_Any; U64 check_sum = 0; - B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LNK_COMDAT) && + B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) && parsed_symbol.value == 0 && parsed_symbol.aux_symbol_count > 0 && - parsed_symbol.type.u.lsb == COFF_SymType_NULL && - parsed_symbol.storage_class == COFF_SymStorageClass_STATIC; + parsed_symbol.type.u.lsb == COFF_SymType_Null && + parsed_symbol.storage_class == COFF_SymStorageClass_Static; if (is_comdat) { COFF_SymbolSecDef *secdef = aux_symbols; @@ -916,7 +915,7 @@ lnk_symbol_array_from_coff(Arena *arena, check_sum = secdef->check_sum; // create association link between chunks - if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) { + if (secdef->selection == COFF_ComdatSelect_Associative) { U32 secdef_number = secdef->number_lo; // promote secdef number to 32 bits @@ -955,7 +954,7 @@ lnk_symbol_array_from_coff(Arena *arena, lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum); symbol_array.v[symbol_idx].obj = obj; } break; - case COFF_SymbolValueInterp_WEAK: { + case COFF_SymbolValueInterp_Weak: { if (parsed_symbol.aux_symbol_count == 0) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx); } @@ -972,12 +971,12 @@ lnk_symbol_array_from_coff(Arena *arena, symbol->obj = obj; fallback_symbol->obj = obj; } break; - case COFF_SymbolValueInterp_UNDEFINED: { + case COFF_SymbolValueInterp_Undefined: { LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main); symbol->obj = obj; } break; - case COFF_SymbolValueInterp_COMMON: { + case COFF_SymbolValueInterp_Common: { // :common_block // // TODO: sort chunks on size to reduce bss usage @@ -995,16 +994,16 @@ lnk_symbol_array_from_coff(Arena *arena, } LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0); + lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0); symbol->obj = obj; } break; - case COFF_SymbolValueInterp_ABS: { + case COFF_SymbolValueInterp_Abs: { // Never code or data, synthetic symbol. COFF spec says bits in value are used // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { visibility = LNK_DefinedSymbolVisibility_Extern; } @@ -1012,7 +1011,7 @@ lnk_symbol_array_from_coff(Arena *arena, lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value); symbol->obj = obj; } break; - case COFF_SymbolValueInterp_DEBUG: { + case COFF_SymbolValueInterp_Debug: { } break; } } @@ -1025,8 +1024,8 @@ lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 c { LNK_RelocList *reloc_list_arr = push_array_no_zero(arena, LNK_RelocList, sect_count); for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) { - COFF_SectionHeader *coff_header = &coff_sect_arr[sect_idx]; - COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, coff_header); + COFF_SectionHeader *COFF_FileHeader = &coff_sect_arr[sect_idx]; + COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, COFF_FileHeader); COFF_Reloc *coff_reloc_v = (COFF_Reloc *)(coff_data.str + coff_reloc_info.array_off); LNK_Chunk *sect_chunk = chunk_ptr_arr[sect_idx]; reloc_list_arr[sect_idx] = lnk_reloc_list_from_coff_reloc_array(arena, machine, sect_chunk, symbol_array, coff_reloc_v, coff_reloc_info.count); @@ -1122,8 +1121,8 @@ lnk_directive_info_from_sections(Arena *arena, if (str8_match_lit(".drectve", sect_name, 0)) { if (sect_chunk->type == LNK_Chunk_Leaf) { if (sect_chunk->u.leaf.size >= 3) { - if (~sect_chunk->flags & COFF_SectionFlag_LNK_INFO) { - lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "%S missing COFF_SectionFlag_LNK_INFO", sect_name); + if (~sect_chunk->flags & COFF_SectionFlag_LnkInfo) { + lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "%S missing COFF_SectionFlag_LnkInfo", sect_name); } if (reloc_list_arr[chunk_idx].count > 0) { lnk_error_with_loc(LNK_Warning_DirectiveSectionWithRelocs, obj_path, lib_path, "directive section %S(%#x) has relocations", sect_name, (chunk_idx+1)); diff --git a/src/linker/lnk_reloc.c b/src/linker/lnk_reloc.c index 0c52820d..b37120bd 100644 --- a/src/linker/lnk_reloc.c +++ b/src/linker/lnk_reloc.c @@ -117,26 +117,26 @@ lnk_ext_reloc_type_from_coff(COFF_MachineType machine, U32 type) { LNK_RelocType result = LNK_Reloc_NULL; switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X64: { + case COFF_Machine_Unknown: break; + case COFF_Machine_X64: { switch (type) { - case COFF_RelocTypeX64_ABS: result = LNK_Reloc_NULL; break; - case COFF_RelocTypeX64_ADDR64: result = LNK_Reloc_ADDR_64; break; - case COFF_RelocTypeX64_ADDR32: result = LNK_Reloc_ADDR_32; break; - case COFF_RelocTypeX64_ADDR32NB: result = LNK_Reloc_VIRT_OFF_32; break; - case COFF_RelocTypeX64_REL32: result = LNK_Reloc_REL32; break; - case COFF_RelocTypeX64_REL32_1: result = LNK_Reloc_REL32_1; break; - case COFF_RelocTypeX64_REL32_2: result = LNK_Reloc_REL32_2; break; - case COFF_RelocTypeX64_REL32_3: result = LNK_Reloc_REL32_3; break; - case COFF_RelocTypeX64_REL32_4: result = LNK_Reloc_REL32_4; break; - case COFF_RelocTypeX64_REL32_5: result = LNK_Reloc_REL32_5; break; - case COFF_RelocTypeX64_SECTION: result = LNK_Reloc_SECT_IDX; break; - case COFF_RelocTypeX64_SECREL: result = LNK_Reloc_SECT_REL; break; - case COFF_RelocTypeX64_SECREL7: lnk_not_implemented("TODO: COFF_RelocTypeX64_SECREL7"); break; - case COFF_RelocTypeX64_TOKEN: lnk_not_implemented("TODO: COFF_RelocTypeX64_TOKEN"); break; - case COFF_RelocTypeX64_SREL32: lnk_not_implemented("TODO: COFF_RelocTypeX64_SREL32"); break; - case COFF_RelocTypeX64_PAIR: lnk_not_implemented("TODO: COFF_RelocTypeX64_PAIR"); break; - case COFF_RelocTypeX64_SSPAN32: lnk_not_implemented("TODO: COFF_RelocTypeX64_SSPAN32"); break; + case COFF_Reloc_X64_Abs: result = LNK_Reloc_NULL; break; + case COFF_Reloc_X64_Addr64: result = LNK_Reloc_ADDR_64; break; + case COFF_Reloc_X64_Addr32: result = LNK_Reloc_ADDR_32; break; + case COFF_Reloc_X64_Addr32Nb: result = LNK_Reloc_VIRT_OFF_32; break; + case COFF_Reloc_X64_Rel32: result = LNK_Reloc_REL32; break; + case COFF_Reloc_X64_Rel32_1: result = LNK_Reloc_REL32_1; break; + case COFF_Reloc_X64_Rel32_2: result = LNK_Reloc_REL32_2; break; + case COFF_Reloc_X64_Rel32_3: result = LNK_Reloc_REL32_3; break; + case COFF_Reloc_X64_Rel32_4: result = LNK_Reloc_REL32_4; break; + case COFF_Reloc_X64_Rel32_5: result = LNK_Reloc_REL32_5; break; + case COFF_Reloc_X64_Section: result = LNK_Reloc_SECT_IDX; break; + case COFF_Reloc_X64_SecRel: result = LNK_Reloc_SECT_REL; break; + case COFF_Reloc_X64_SecRel7: lnk_not_implemented("TODO: COFF_Reloc_X64_SecRel7"); break; + case COFF_Reloc_X64_Token: lnk_not_implemented("TODO: COFF_Reloc_X64_Token"); break; + case COFF_Reloc_X64_SRel32: lnk_not_implemented("TODO: COFF_Reloc_X64_SRel32"); break; + case COFF_Reloc_X64_Pair: lnk_not_implemented("TODO: COFF_Reloc_X64_Pair"); break; + case COFF_Reloc_X64_SSpan32: lnk_not_implemented("TODO: COFF_Reloc_X64_SSpan32"); break; default: lnk_invalid_path("unknown relocation type 0x%X", type); } } break; @@ -150,20 +150,20 @@ lnk_ext_reloc_type_to_coff(COFF_MachineType machine, LNK_RelocType type) { U32 result = 0; switch (machine) { - case COFF_MachineType_X64: { + case COFF_Machine_X64: { switch (type) { - case LNK_Reloc_NULL: result = COFF_RelocTypeX64_ABS; break; - case LNK_Reloc_ADDR_64: result = COFF_RelocTypeX64_ADDR64; break; - case LNK_Reloc_ADDR_32: result = COFF_RelocTypeX64_ADDR32; break; - case LNK_Reloc_VIRT_OFF_32: result = COFF_RelocTypeX64_ADDR32NB; break; - case LNK_Reloc_REL32: result = COFF_RelocTypeX64_REL32; break; - case LNK_Reloc_REL32_1: result = COFF_RelocTypeX64_REL32_1; break; - case LNK_Reloc_REL32_2: result = COFF_RelocTypeX64_REL32_2; break; - case LNK_Reloc_REL32_3: result = COFF_RelocTypeX64_REL32_3; break; - case LNK_Reloc_REL32_4: result = COFF_RelocTypeX64_REL32_4; break; - case LNK_Reloc_REL32_5: result = COFF_RelocTypeX64_REL32_5; break; - case LNK_Reloc_SECT_IDX: result = COFF_RelocTypeX64_SECTION; break; - case LNK_Reloc_SECT_REL: result = COFF_RelocTypeX64_SECREL; break; + case LNK_Reloc_NULL: result = COFF_Reloc_X64_Abs; break; + case LNK_Reloc_ADDR_64: result = COFF_Reloc_X64_Addr64; break; + case LNK_Reloc_ADDR_32: result = COFF_Reloc_X64_Addr32; break; + case LNK_Reloc_VIRT_OFF_32: result = COFF_Reloc_X64_Addr32Nb; break; + case LNK_Reloc_REL32: result = COFF_Reloc_X64_Rel32; break; + case LNK_Reloc_REL32_1: result = COFF_Reloc_X64_Rel32_1; break; + case LNK_Reloc_REL32_2: result = COFF_Reloc_X64_Rel32_2; break; + case LNK_Reloc_REL32_3: result = COFF_Reloc_X64_Rel32_3; break; + case LNK_Reloc_REL32_4: result = COFF_Reloc_X64_Rel32_4; break; + case LNK_Reloc_REL32_5: result = COFF_Reloc_X64_Rel32_5; break; + case LNK_Reloc_SECT_IDX: result = COFF_Reloc_X64_Section; break; + case LNK_Reloc_SECT_REL: result = COFF_Reloc_X64_SecRel; break; default: InvalidPath; } } break; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index b3d135ac..4ac8cb25 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -85,7 +85,7 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, // pack sections with run-time data closer String8List sort_index_list = {0}; - if (flags & COFF_SectionFlag_MEM_DISCARDABLE) { + if (flags & COFF_SectionFlag_MemDiscardable) { str8_list_pushf(scratch.arena, &sort_index_list, "b"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "a"); @@ -102,14 +102,14 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, } // sort sections based on the contents - if (flags & COFF_SectionFlag_CNT_CODE) { + if (flags & COFF_SectionFlag_CntCode) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); if (str8_match_lit(".text", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "b"); } - } else if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + } else if (flags & COFF_SectionFlag_CntInitializedData) { str8_list_pushf(scratch.arena, &sort_index_list, "b"); if (str8_match_lit(".data", name, 0)) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); @@ -120,14 +120,14 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, } else { str8_list_pushf(scratch.arena, &sort_index_list, "d"); } - } else if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + } else if (flags & COFF_SectionFlag_CntUninitializedData) { str8_list_pushf(scratch.arena, &sort_index_list, "c"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "d"); } // sort sections based on read/write access so final section layout looks cleaner - if (flags & COFF_SectionFlag_MEM_READ && ~flags & COFF_SectionFlag_MEM_WRITE) { + if (flags & COFF_SectionFlag_MemRead && ~flags & COFF_SectionFlag_MemWrite) { str8_list_pushf(scratch.arena, &sort_index_list, "a"); } else { str8_list_pushf(scratch.arena, &sort_index_list, "b"); @@ -236,8 +236,8 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine) { U8 align_byte = 0; switch (machine) { - case COFF_MachineType_X64: - case COFF_MachineType_X86: { + case COFF_Machine_X64: + case COFF_Machine_X86: { align_byte = 0xCC; } break; default: { @@ -570,7 +570,7 @@ lnk_section_table_assign_file_offsets(LNK_SectionTable *st) U64 cursor = 0; for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; - if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (sect->flags & COFF_SectionFlag_CntUninitializedData) { continue; } if (!sect->has_layout) continue; @@ -617,7 +617,7 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) { LNK_Section *sect = §_n->data; if (sect->has_layout) { - if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (sect->flags & COFF_SectionFlag_CntUninitializedData) { continue; } @@ -625,7 +625,7 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, String8 sect_data = str8_substr(image, rng_1u64(image_cursor, image_cursor + sect_size)); U8 fill_byte = 0; - if (sect->flags & COFF_SectionFlag_CNT_CODE) { + if (sect->flags & COFF_SectionFlag_CntCode) { fill_byte = lnk_code_align_byte_from_machine(machine); } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 3332aa1b..127a6f1d 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -271,17 +271,17 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) COFF_ComdatSelectType src_select = src_defn->u.selection; // handle objs compiled with /GR- and /GR - if ((src_select == COFF_ComdatSelectType_ANY && dst_select == COFF_ComdatSelectType_LARGEST) || - (src_select == COFF_ComdatSelectType_LARGEST && dst_select == COFF_ComdatSelectType_ANY)) { - dst_select = COFF_ComdatSelectType_LARGEST; - src_select = COFF_ComdatSelectType_LARGEST; + if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) || + (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) { + dst_select = COFF_ComdatSelect_Largest; + src_select = COFF_ComdatSelect_Largest; } if (src_select == dst_select) { switch (src_select) { default: InvalidPath; - case COFF_ComdatSelectType_NULL: - case COFF_ComdatSelectType_ANY: { + case COFF_ComdatSelect_Null: + case COFF_ComdatSelect_Any: { LNK_Chunk *dst_chunk = dst_defn->u.chunk; LNK_Chunk *src_chunk = src_defn->u.chunk; U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); @@ -293,10 +293,10 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) can_replace = src_chunk_size < dst_chunk_size; } } break; - case COFF_ComdatSelectType_NODUPLICATES: { + case COFF_ComdatSelect_NoDuplicates: { lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); } break; - case COFF_ComdatSelectType_SAME_SIZE: { + case COFF_ComdatSelect_SameSize: { LNK_Chunk *dst_chunk = dst_defn->u.chunk; LNK_Chunk *src_chunk = src_defn->u.chunk; U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); @@ -306,13 +306,13 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); } } break; - case COFF_ComdatSelectType_EXACT_MATCH: { + case COFF_ComdatSelect_ExactMatch: { B32 is_exact_match = (dst_defn->u.check_sum == src_defn->u.check_sum); if (!is_exact_match) { lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); } } break; - case COFF_ComdatSelectType_LARGEST: { + case COFF_ComdatSelect_Largest: { LNK_Chunk *dst_chunk = dst_defn->u.chunk; LNK_Chunk *src_chunk = src_defn->u.chunk; U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); @@ -330,7 +330,7 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) can_replace = dst_chunk_size < src_chunk_size; } } break; - case COFF_ComdatSelectType_ASSOCIATIVE: { + case COFF_ComdatSelect_Associative: { // ignore } break; } @@ -630,7 +630,7 @@ lnk_symbol_table_push_weak(LNK_SymbolTable *symtab, String8 weak_name, COFF_Weak weak_name = push_str8_copy(symtab->arena->v[0], weak_name); strong_name = push_str8_copy(symtab->arena->v[0], strong_name); LNK_Symbol *strong_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], strong_name, LNK_SymbolScopeFlag_Main); - LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExtType_SEARCH_ALIAS, strong_symbol); + LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExt_SearchAlias, strong_symbol); lnk_symbol_table_push(symtab, weak_symbol); return weak_symbol; } diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 2fbf706b..ffabb1c6 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -3270,21 +3270,21 @@ dbi_build_sec_map(Arena *arena, PDB_DbiContext *dbi) U64 isect = 0; for (PDB_DbiSectionNode *sect = dbi->section_list.first; sect; sect = sect->next, ++isect) { PDB_DbiSecMapEntry *s = &entry_array[isect]; - COFF_SectionHeader *coff_header = §->data; - if (coff_header->flags & COFF_SectionFlag_MEM_READ) { + COFF_SectionHeader *section_header = §->data; + if (section_header->flags & COFF_SectionFlag_MemRead) { s->flags |= PDB_DbiOMF_READ; } - if (coff_header->flags & COFF_SectionFlag_MEM_WRITE) { + if (section_header->flags & COFF_SectionFlag_MemWrite) { s->flags |= PDB_DbiOMF_WRITE; } - if (coff_header->flags & COFF_SectionFlag_MEM_EXECUTE) { + if (section_header->flags & COFF_SectionFlag_MemExecute) { s->flags |= PDB_DbiOMF_EXEC; } - if (~coff_header->flags & COFF_SectionFlag_MEM_16BIT) { + if (~section_header->flags & COFF_SectionFlag_Mem16Bit) { s->flags |= PDB_DbiOMF_IS_32BIT_ADDR; } s->flags |= PDB_DbiOMF_IS_SELECTOR; // always set - s->sec_size = coff_header->vsize; + s->sec_size = section_header->vsize; s->frame = isect + 1; s->sec_name = max_U16; s->class_name = max_U16; @@ -3444,7 +3444,7 @@ dbi_module_push_section_contrib(PDB_DbiContext *dbi, // Mod1::fUpdateSecContrib if (mod->first_sc.base.mod == 0) { - if (flags & COFF_SectionFlag_CNT_CODE) { + if (flags & COFF_SectionFlag_CntCode) { mod->first_sc = sc; } } diff --git a/src/linker/rdi/rdi_coff.c b/src/linker/rdi/rdi_coff.c index 07a3892f..32b93862 100644 --- a/src/linker/rdi/rdi_coff.c +++ b/src/linker/rdi/rdi_coff.c @@ -5,31 +5,31 @@ internal RDI_Arch rdi_arch_from_coff_machine(COFF_MachineType machine) { switch (machine) { - case COFF_MachineType_X86: return RDI_Arch_X86; - case COFF_MachineType_X64: return RDI_Arch_X64; + case COFF_Machine_X86: return RDI_Arch_X86; + case COFF_Machine_X64: return RDI_Arch_X64; - case COFF_MachineType_UNKNOWN: - case COFF_MachineType_AM33: - case COFF_MachineType_ARM: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARMNT: - case COFF_MachineType_EBC: - case COFF_MachineType_IA64: - case COFF_MachineType_M32R: - case COFF_MachineType_MIPS16: - case COFF_MachineType_MIPSFPU: - case COFF_MachineType_MIPSFPU16: - case COFF_MachineType_POWERPC: - case COFF_MachineType_POWERPCFP: - case COFF_MachineType_R4000: - case COFF_MachineType_RISCV32: - case COFF_MachineType_RISCV64: - case COFF_MachineType_SH3: - case COFF_MachineType_SH3DSP: - case COFF_MachineType_SH4: - case COFF_MachineType_SH5: - case COFF_MachineType_THUMB: - case COFF_MachineType_WCEMIPSV2: + case COFF_Machine_Unknown: + case COFF_Machine_Am33: + case COFF_Machine_Arm: + case COFF_Machine_Arm64: + case COFF_Machine_ArmNt: + case COFF_Machine_Ebc: + case COFF_Machine_Ia64: + case COFF_Machine_M32R: + case COFF_Machine_Mips16: + case COFF_Machine_MipsFpu: + case COFF_Machine_MipsFpu16: + case COFF_Machine_PowerPc: + case COFF_Machine_PowerPcFp: + case COFF_Machine_R4000: + case COFF_Machine_RiscV32: + case COFF_Machine_RiscV64: + case COFF_Machine_Sh3: + case COFF_Machine_Sh3Dsp: + case COFF_Machine_Sh4: + case COFF_Machine_Sh5: + case COFF_Machine_Thumb: + case COFF_Machine_WceMipsV2: NotImplemented; default: return RDI_Arch_NULL; @@ -40,13 +40,13 @@ internal RDI_BinarySectionFlags rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) { RDI_BinarySectionFlags result = 0; - if (flags & COFF_SectionFlag_MEM_READ) { + if (flags & COFF_SectionFlag_MemRead) { result |= RDI_BinarySectionFlag_Read; } - if (flags & COFF_SectionFlag_MEM_WRITE) { + if (flags & COFF_SectionFlag_MemWrite) { result |= RDI_BinarySectionFlag_Write; } - if (flags & COFF_SectionFlag_MEM_EXECUTE) { + if (flags & COFF_SectionFlag_MemExecute) { result |= RDI_BinarySectionFlag_Execute; } return result; diff --git a/src/pe/pe.c b/src/pe/pe.c index 352e775e..a4bac235 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -438,34 +438,34 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read coff header - U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); - COFF_Header coff_header = {0}; + U32 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_FileHeader file_header = {0}; if(valid) { - str8_deserial_read_struct(data, coff_header_off, &coff_header); + str8_deserial_read_struct(data, file_header_off, &file_header); } // rjf: range of optional extension header ("optional" for short) - U32 optional_size = coff_header.optional_header_size; - U64 after_coff_header_off = coff_header_off + sizeof(coff_header); - U64 after_optional_header_off = after_coff_header_off + optional_size; + U32 optional_size = file_header.optional_header_size; + U64 after_file_header_off = file_header_off + sizeof(COFF_FileHeader); + U64 after_optional_header_off = after_file_header_off + optional_size; Rng1U64 optional_range = {0}; if(valid) { - optional_range.min = ClampTop(after_coff_header_off, data.size); + optional_range.min = ClampTop(after_file_header_off, data.size); optional_range.max = ClampTop(after_optional_header_off, data.size); } // rjf: get sections U64 sec_array_off = optional_range.max; - U64 sec_array_raw_opl = sec_array_off + coff_header.section_count*sizeof(COFF_SectionHeader); + U64 sec_array_raw_opl = sec_array_off + file_header.section_count*sizeof(COFF_SectionHeader); U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size); U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader); COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off); // rjf: get symbols - U64 symbol_array_off = coff_header.symbol_table_foff; - U64 symbol_count = coff_header.symbol_count; + U64 symbol_array_off = file_header.symbol_table_foff; + U64 symbol_count = file_header.symbol_count; // rjf: get string table U64 string_table_off = symbol_array_off + sizeof(COFF_Symbol16) * symbol_count; @@ -551,11 +551,11 @@ pe_bin_info_from_data(Arena *arena, String8 data) if(valid && PE_DataDirectoryIndex_TLS < data_dir_count) { Rng1U64 tls_header_frng = data_dir_franges[PE_DataDirectoryIndex_TLS]; - switch(coff_header.machine) + switch(file_header.machine) { default:{ NotImplemented; }break; - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: { PE_TLSHeader32 tls_header32 = {0}; if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32) == sizeof(tls_header32)) @@ -572,7 +572,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) Assert(!"unable to read TLS Header 32"); } }break; - case COFF_MachineType_X64: + case COFF_Machine_X64: { if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header) != sizeof(tls_header)) { @@ -598,7 +598,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) info.string_table_off = string_table_off; info.data_dir_franges = data_dir_franges; info.data_dir_count = data_dir_count; - info.arch = arch_from_coff_machine(coff_header.machine); + info.arch = arch_from_coff_machine(file_header.machine); info.tls_header = tls_header; } @@ -824,7 +824,7 @@ pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff) COFF_SectionHeader *sect = §ions[sect_idx]; if(sect->voff <= voff && voff < sect->voff + sect->vsize) { - if(!(sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) + if(!(sect->flags & COFF_SectionFlag_CntUninitializedData)) { foff = sect->foff + (voff - sect->voff); } @@ -967,7 +967,7 @@ pe_get_entry_point_names(COFF_MachineType machine, String8Array entry_point_names = {0}; if (file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { - if (machine == COFF_MachineType_X86) { + if (machine == COFF_Machine_X86) { read_only static String8 dll_entry_point_arr[] = { str8_lit_comp("__DllMainCRTStartup@12"), }; @@ -1418,8 +1418,8 @@ pe_tls_from_data(Arena *arena, U64 *callback_addrs = 0; switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: { + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: { PE_TLSHeader32 header32 = {0}; str8_deserial_read_struct(raw_tls, 0, &header32); @@ -1444,7 +1444,7 @@ pe_tls_from_data(Arena *arena, callback_addrs[i] = (U64)src[i]; } } break; - case COFF_MachineType_X64: { + case COFF_Machine_X64: { str8_deserial_read_struct(raw_tls, 0, &header64); U64 callbacks_voff = header64.callbacks_address - image_base; @@ -1487,9 +1487,9 @@ pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID PE_ResourceList *list = 0; switch (id.type) { default: - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_STRING: list = &dir->named_list; break; - case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break; + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_String: list = &dir->named_list; break; + case COFF_ResourceIDType_Number: list = &dir->id_list; break; } PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1); @@ -1516,9 +1516,9 @@ pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_Resource PE_ResourceList *list = NULL; switch (id.type) { default: - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_STRING: list = &dir->named_list; break; - case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break; + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_String: list = &dir->named_list; break; + case COFF_ResourceIDType_Number: list = &dir->id_list; break; } PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1); @@ -1555,7 +1555,7 @@ internal PE_ResourceNode * pe_resource_dir_search_node(PE_ResourceDir *dir, COFF_ResourceID id) { for (PE_ResourceNode *i = dir->id_list.first; i != NULL; i = i->next) { - if (coff_resource_id_is_equal(i->data.id, id)) { + if (coff_resource_id_compar(&i->data.id, &id)) { return i; } } @@ -1586,11 +1586,11 @@ pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 re { // parse file into resource list String8 res_data = str8_substr(res_file, rng_1u64(sizeof(PE_RES_MAGIC), res_file.size)); - COFF_ResourceList list = coff_resource_list_from_data(arena, res_data); + COFF_ParsedResourceList list = coff_resource_list_from_data(arena, res_data); // move resources to directories based on type - for (COFF_ResourceNode *res_node = list.first; res_node != NULL; res_node = res_node->next) { - COFF_Resource *res = &res_node->data; + for (COFF_ParsedResourceNode *res_node = list.first; res_node != NULL; res_node = res_node->next) { + COFF_ParsedResource *res = &res_node->data; // search existing directories PE_Resource *dir_res = pe_resource_dir_search(root_dir, res->type); @@ -1612,7 +1612,7 @@ pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 re // push entry PE_Resource *sub_dir_res = pe_resource_dir_push_dir(arena, dir, res->name, 0, 0, 0, 0); COFF_ResourceID id; - id.type = COFF_ResourceIDType_NUMBER; + id.type = COFF_ResourceIDType_Number; id.u.number = res->language_id; pe_resource_dir_push_entry(arena, sub_dir_res->u.dir, id, res->type, res->data_version, res->version, res->memory_flags, res->data); } @@ -1673,7 +1673,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) str8_deserial_read_struct(data, entry_offset, &coff_entry); // NOTE: this is not documented on MSDN but high bit here is set for some reason - U32 name_offset = coff_entry.name.offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + U32 name_offset = coff_entry.name.offset & ~COFF_Resource_SubDirFlag; U16 name_size = 0; str8_deserial_read_struct(data, name_offset, &name_size); @@ -1681,15 +1681,15 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) str8_deserial_read_block(data, name_offset + sizeof(name_size), name_size*sizeof(U16), &name_block); String16 name16 = str16((U16*)name_block.str, name_size); - B32 is_dir = !!(coff_entry.id.data_entry_offset & COFF_RESOURCE_SUB_DIR_FLAG); + B32 is_dir = !!(coff_entry.id.data_entry_offset & COFF_Resource_SubDirFlag); - entry->id.type = COFF_ResourceIDType_STRING; + entry->id.type = COFF_ResourceIDType_String; entry->id.u.string = str8_from_16(arena, name16); entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); - frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_Resource_SubDirFlag; frame->directory_ptr = &entry->u.dir; SLLStackPush(stack, frame); goto yeild; @@ -1710,15 +1710,15 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) COFF_ResourceDirEntry coff_entry = {0}; str8_deserial_read_struct(data, entry_offset, &coff_entry); - B32 is_dir = !!(coff_entry.id.sub_dir_offset & COFF_RESOURCE_SUB_DIR_FLAG); + B32 is_dir = !!(coff_entry.id.sub_dir_offset & COFF_Resource_SubDirFlag); - entry->id.type = COFF_ResourceIDType_NUMBER; + entry->id.type = COFF_ResourceIDType_Number; entry->id.u.number = coff_entry.name.id; entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); - frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_Resource_SubDirFlag; frame->directory_ptr = &entry->u.dir; SLLStackPush(stack, frame); goto yeild; @@ -1740,11 +1740,11 @@ internal String8 pe_make_manifest_resource(Arena *arena, U32 resource_id, String8 manifest_data) { COFF_ResourceID type = {0}; - type.type = COFF_ResourceIDType_NUMBER; + type.type = COFF_ResourceIDType_Number; type.u.number = PE_ResourceKind_MANIFEST; COFF_ResourceID id = {0}; - id.type = COFF_ResourceIDType_NUMBER; + id.type = COFF_ResourceIDType_Number; id.u.number = resource_id; String8 res = coff_write_resource(arena, type, id, 1, 0, 1033, 0, 0, manifest_data); diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index f0f97e8a..e47ebe6e 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -340,6 +340,7 @@ #include "mutable_text/mutable_text.h" #include "path/path.h" #include "coff/coff.h" +#include "coff/coff_parse.h" #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" @@ -381,6 +382,7 @@ #include "mutable_text/mutable_text.c" #include "path/path.c" #include "coff/coff.c" +#include "coff/coff_parse.c" #include "pe/pe.c" #include "codeview/codeview.c" #include "codeview/codeview_parse.c" diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index f1cea0ee..ec47f263 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -228,7 +228,7 @@ rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input Temp scratch = scratch_begin(&arena, 1); char *input_type_string = "???"; - if (coff_is_archive(raw_data)) { + if (coff_is_regular_archive(raw_data)) { input_type_string = "Archive"; } else if (coff_is_thin_archive(raw_data)) { input_type_string = "Thin Archive"; @@ -360,9 +360,9 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st COFF_Symbol32 *symbol = &symbols.v[symbol_idx]; COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); - B32 is_marker = interp == COFF_SymbolValueInterp_REGULAR && + B32 is_marker = interp == COFF_SymbolValueInterp_Regular && symbol->aux_symbol_count == 0 && - (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC); + (symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static); if (is_marker) { String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); @@ -411,7 +411,7 @@ rd_dw_sections_from_coff_section_table(Arena *arena, for (U64 i = 0; i < section_count; ++i) { COFF_SectionHeader *header = §ions[i]; Rng1U64 raw_data_range = rng_1u64(header->foff, header->foff + header->fsize); - String8 name = coff_name_from_section_header(header, raw_image, string_table_off); + String8 name = coff_name_from_section_header(raw_image, header, string_table_off); DW_SectionKind s = DW_Section_Null; B32 is_dwo = 0; @@ -4496,7 +4496,7 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 B32 keep_parsing = 1; for (U64 i = 0; i < section_count && keep_parsing; ++i) { COFF_SectionHeader *header = §ions[i]; - String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + String8 sect_name = coff_name_from_section_header(raw_image, header, string_table_off); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); if (str8_match_lit(".debug$S", sect_name, 0)) { @@ -4544,7 +4544,7 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 for (U64 i = 0; i < section_count; ++i) { COFF_SectionHeader *header = §ions[i]; - String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + String8 sect_name = coff_name_from_section_header(raw_image, header, string_table_off); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); if (str8_match_lit(".debug$S", sect_name, 0)) { @@ -4577,7 +4577,7 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 // COFF internal void -coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) +coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names) { Temp scratch = scratch_begin(&arena, 1); String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp); @@ -4608,12 +4608,12 @@ coff_print_seciton_table(Arena *arena, for (U64 i = 0; i < symbols.count; ++i) { COFF_Symbol32 *symbol = symbols.v+i; COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); - if (interp == COFF_SymbolValueInterp_REGULAR && + if (interp == COFF_SymbolValueInterp_Regular && symbol->aux_symbol_count == 0 && - (symbol->storage_class == COFF_SymStorageClass_EXTERNAL || symbol->storage_class == COFF_SymStorageClass_STATIC)) { + (symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) { if (symbol->section_number > 0 && symbol->section_number <= symbols.count) { COFF_SectionHeader *header = sect_headers+(symbol->section_number-1); - if (header->flags & COFF_SectionFlag_LNK_COMDAT) { + if (header->flags & COFF_SectionFlag_LnkCOMDAT) { symlinks[symbol->section_number-1] = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); } } @@ -4644,7 +4644,7 @@ coff_print_seciton_table(Arena *arena, COFF_SectionHeader *header = sect_headers+i; String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name)); - String8 full_name = coff_name_from_section_header(header, raw_data, string_table_off); + String8 full_name = coff_name_from_section_header(raw_data, header, string_table_off); String8 align; { @@ -4655,69 +4655,69 @@ coff_print_seciton_table(Arena *arena, String8 flags; { String8List mem_flags = {0}; - if (header->flags & COFF_SectionFlag_MEM_READ) { + if (header->flags & COFF_SectionFlag_MemRead) { str8_list_pushf(scratch.arena, &mem_flags, "r"); } - if (header->flags & COFF_SectionFlag_MEM_WRITE) { + if (header->flags & COFF_SectionFlag_MemWrite) { str8_list_pushf(scratch.arena, &mem_flags, "w"); } - if (header->flags & COFF_SectionFlag_MEM_EXECUTE) { + if (header->flags & COFF_SectionFlag_MemExecute) { str8_list_pushf(scratch.arena, &mem_flags, "x"); } String8List cnt_flags = {0}; - if (header->flags & COFF_SectionFlag_CNT_CODE) { + if (header->flags & COFF_SectionFlag_CntCode) { str8_list_pushf(scratch.arena, &cnt_flags, "c"); } - if (header->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + if (header->flags & COFF_SectionFlag_CntInitializedData) { str8_list_pushf(scratch.arena, &cnt_flags, "d"); } - if (header->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + if (header->flags & COFF_SectionFlag_CntUninitializedData) { str8_list_pushf(scratch.arena, &cnt_flags, "u"); } String8List mem_extra_flags = {0}; - if (header->flags & COFF_SectionFlag_MEM_SHARED) { + if (header->flags & COFF_SectionFlag_MemShared) { str8_list_pushf(scratch.arena, &mem_flags, "s"); } - if (header->flags & COFF_SectionFlag_MEM_16BIT) { + if (header->flags & COFF_SectionFlag_Mem16Bit) { str8_list_pushf(scratch.arena, &mem_extra_flags, "h"); } - if (header->flags & COFF_SectionFlag_MEM_LOCKED) { + if (header->flags & COFF_SectionFlag_MemLocked) { str8_list_pushf(scratch.arena, &mem_extra_flags, "l"); } - if (header->flags & COFF_SectionFlag_MEM_DISCARDABLE) { + if (header->flags & COFF_SectionFlag_MemDiscardable) { str8_list_pushf(scratch.arena, &mem_extra_flags, "d"); } - if (header->flags & COFF_SectionFlag_MEM_NOT_CACHED) { + if (header->flags & COFF_SectionFlag_MemNotCached) { str8_list_pushf(scratch.arena, &mem_extra_flags, "c"); } - if (header->flags & COFF_SectionFlag_MEM_NOT_PAGED) { + if (header->flags & COFF_SectionFlag_MemNotPaged) { str8_list_pushf(scratch.arena, &mem_extra_flags, "p"); } String8List lnk_flags = {0}; - if (header->flags & COFF_SectionFlag_LNK_REMOVE) { + if (header->flags & COFF_SectionFlag_LnkRemove) { str8_list_pushf(scratch.arena, &lnk_flags, "r"); } - if (header->flags & COFF_SectionFlag_LNK_COMDAT) { + if (header->flags & COFF_SectionFlag_LnkCOMDAT) { str8_list_pushf(scratch.arena, &lnk_flags, "c"); } - if (header->flags & COFF_SectionFlag_LNK_OTHER) { + if (header->flags & COFF_SectionFlag_LnkOther) { str8_list_pushf(scratch.arena, &lnk_flags, "o"); } - if (header->flags & COFF_SectionFlag_LNK_INFO) { + if (header->flags & COFF_SectionFlag_LnkInfo) { str8_list_pushf(scratch.arena, &lnk_flags, "i"); } - if (header->flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { + if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) { str8_list_pushf(scratch.arena, &lnk_flags, "f"); } String8List other_flags = {0}; - if (header->flags & COFF_SectionFlag_TYPE_NO_PAD) { + if (header->flags & COFF_SectionFlag_TypeNoPad) { str8_list_pushf(scratch.arena, &other_flags, "n"); } - if (header->flags & COFF_SectionFlag_GPREL) { + if (header->flags & COFF_SectionFlag_GpRel) { str8_list_pushf(scratch.arena, &other_flags, "g"); } @@ -4773,11 +4773,11 @@ coff_print_seciton_table(Arena *arena, rd_newline(); rd_printf("Flags:"); rd_indent(); - rd_printf("r = MEM_READ w = MEM_WRITE x = MEM_EXECUTE"); - rd_printf("c = CNT_CODE d = INITIALIZED_DATA u = UNINITIALIZED_DATA"); - rd_printf("s = MEM_SHARED h = MEM_16BIT l = MEM_LOCKED d = MEM_DISCARDABLE c = MEM_NOT_CACHED p = MEM_NOT_PAGED"); - rd_printf("r = LNK_REMOVE c = LNK_COMDAT o = LNK_OTHER i = LNK_INFO f = LNK_NRELOC_OVFL"); - rd_printf("g = GPREL n = TYPE_NO_PAD"); + rd_printf("r = MemRead w = MemWrite x = MemExecute"); + rd_printf("c = CntCode d = InitializedData u = UninitializedData"); + rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged"); + rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl"); + rd_printf("g = GpRel n = TypeNoPad"); rd_unindent(); rd_unindent(); @@ -4802,7 +4802,7 @@ coff_disasm_sections(Arena *arena, if (section_count) { for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { COFF_SectionHeader *sect = sections+sect_idx; - if (sect->flags & COFF_SectionFlag_CNT_CODE) { + if (sect->flags & COFF_SectionFlag_CntCode) { U64 sect_off = is_obj ? sect->foff : sect->voff; U64 sect_size = is_obj ? sect->fsize : sect->vsize; String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); @@ -4950,10 +4950,10 @@ coff_print_symbol_table(Arena *arena, String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class); String8 section_number; switch (symbol->section_number) { - case COFF_SYMBOL_UNDEFINED_SECTION: section_number = str8_lit("UNDEF"); break; - case COFF_SYMBOL_ABS_SECTION: section_number = str8_lit("ABS"); break; - case COFF_SYMBOL_DEBUG_SECTION: section_number = str8_lit("DEBUG"); break; - default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break; + case COFF_Symbol_UndefinedSection: section_number = str8_lit("UNDEF"); break; + case COFF_Symbol_AbsSection32: section_number = str8_lit("ABS"); break; + case COFF_Symbol_DebugSection32: section_number = str8_lit("DEBUG"); break; + default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break; } String8List line = {0}; @@ -4973,28 +4973,28 @@ coff_print_symbol_table(Arena *arena, for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) { void *raw_aux = &symbols.v[k]; switch (symbol->storage_class) { - case COFF_SymStorageClass_EXTERNAL: { + case COFF_SymStorageClass_External: { COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k]; rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x", func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func); } break; - case COFF_SymStorageClass_FUNCTION: { + case COFF_SymStorageClass_Function: { COFF_SymbolFunc *func = raw_aux; rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func); } break; - case COFF_SymStorageClass_WEAK_EXTERNAL: { + case COFF_SymStorageClass_WeakExternal: { COFF_SymbolWeakExt *weak = raw_aux; String8 type = coff_string_from_weak_ext_type(weak->characteristics); rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type); } break; - case COFF_SymStorageClass_FILE: { + case COFF_SymStorageClass_File: { COFF_SymbolFile *file = raw_aux; String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name)); rd_printf("Name %S", name); } break; - case COFF_SymStorageClass_STATIC: { + case COFF_SymStorageClass_Static: { COFF_SymbolSecDef *sd = raw_aux; - String8 selection = coff_string_from_selection(sd->selection); + String8 selection = coff_string_from_comdat_select_type(sd->selection); U32 number = sd->number_lo; if (is_big_obj) { number |= (U32)sd->number_hi << 16; @@ -5025,7 +5025,7 @@ coff_print_symbol_table(Arena *arena, } internal void -coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) +coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header) { Temp scratch = scratch_begin(&arena, 1); @@ -5034,20 +5034,18 @@ coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_H rd_printf("# Big Obj"); rd_indent(); - - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Machine: %S", machine ); - rd_printf("Section Count: %u", header->section_count ); + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Machine: %S", machine ); + rd_printf("Section Count: %u", header->section_count ); rd_printf("Symbol Table: %#x", header->symbol_table_foff); - rd_printf("Symbol Count: %u", header->symbol_count ); - + rd_printf("Symbol Count: %u", header->symbol_count ); rd_unindent(); scratch_end(scratch); } internal void -coff_print_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) +coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header) { Temp scratch = scratch_begin(&arena, 1); @@ -5055,22 +5053,22 @@ coff_print_header(Arena *arena, String8List *out, String8 indent, COFF_Header *h String8 machine = coff_string_from_machine_type(header->machine); String8 flags = coff_string_from_flags(scratch.arena, header->flags); - rd_printf("# COFF Header"); + rd_printf("# COFF File Header"); rd_indent(); - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Machine: %S", machine ); - rd_printf("Section Count: %u", header->section_count ); + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Machine: %S", machine ); + rd_printf("Section Count: %u", header->section_count ); rd_printf("Symbol Table: %#x", header->symbol_table_foff ); - rd_printf("Symbol Count: %u", header->symbol_count ); - rd_printf("Optional Header Size: %m", header->optional_header_size); - rd_printf("Flags: %S", flags ); + rd_printf("Symbol Count: %u", header->symbol_count ); + rd_printf("Optional Header Size: %m", header->optional_header_size); + rd_printf("Flags: %S", flags ); rd_unindent(); scratch_end(scratch); } internal void -coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) +coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header) { Temp scratch = scratch_begin(&arena, 1); @@ -5079,15 +5077,15 @@ coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHea rd_printf("# Import"); rd_indent(); - rd_printf("Version: %u", header->version ); - rd_printf("Machine: %S", machine ); - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Data Size: %m", header->data_size); - rd_printf("Hint: %u", header->hint ); - rd_printf("Type: %u", header->type ); - rd_printf("Name Type: %u", header->name_type); - rd_printf("Function: %S", header->func_name); - rd_printf("DLL: %S", header->dll_name ); + rd_printf("Version: %u", header->version ); + rd_printf("Machine: %S", machine ); + rd_printf("Time Stamp: %S", time_stamp ); + rd_printf("Data Size: %m", header->data_size ); + rd_printf("Hint: %u", header->hint_or_ordinal); + rd_printf("Type: %u", header->type ); + rd_printf("Import By: %u", header->import_by ); + rd_printf("Function: %S", header->func_name ); + rd_printf("DLL: %S", header->dll_name ); rd_unindent(); scratch_end(scratch); @@ -5098,8 +5096,8 @@ coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_d { Temp scratch = scratch_begin(&arena, 1); - COFF_HeaderBigObj *big_obj = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(COFF_HeaderBigObj)); - COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sizeof(COFF_HeaderBigObj), sizeof(COFF_SectionHeader)*big_obj->section_count); + COFF_BigObjHeader *big_obj = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(COFF_BigObjHeader)); + COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sizeof(COFF_BigObjHeader), sizeof(COFF_SectionHeader)*big_obj->section_count); U64 string_table_off = big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count; COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); @@ -5151,14 +5149,14 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, { Temp scratch = scratch_begin(&arena, 1); - COFF_Header *header = (COFF_Header *)raw_data.str; + COFF_FileHeader *header = (COFF_FileHeader *)raw_data.str; COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); Arch arch = arch_from_coff_machine(header->machine); if (opts & RD_Option_Headers) { - coff_print_header(arena, out, indent, header); + coff_print_file_header(arena, out, indent, header); rd_newline(); } @@ -5353,16 +5351,16 @@ coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_a } switch (member_type) { - case COFF_DataType_BIG_OBJ: { - coff_print_big_obj(arena, out, indent, member.data, opts); - } break; - case COFF_DataType_OBJ: { + case COFF_DataType_Obj: { coff_print_obj(arena, out, indent, member.data, opts); } break; - case COFF_DataType_IMPORT: { + case COFF_DataType_BigObj: { + coff_print_big_obj(arena, out, indent, member.data, opts); + } break; + case COFF_DataType_Import: { if (opts & RD_Option_Headers) { - COFF_ImportHeader header = {0}; - U64 parse_size = coff_parse_archive_import(member.data, 0, &header); + COFF_ParsedArchiveImportHeader header = {0}; + U64 parse_size = coff_parse_import(member.data, 0, &header); if (parse_size) { coff_print_import(arena, out, indent, &header); } else { @@ -5370,7 +5368,7 @@ coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_a } } } break; - case COFF_DataType_NULL: { + case COFF_DataType_Null: { rd_errorf("unknown member format", member_offset); } break; } @@ -6600,9 +6598,9 @@ pe_print_exceptions(Arena *arena, rd_indent(); rd_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X64: - case COFF_MachineType_X86: { + case COFF_Machine_Unknown: break; + case COFF_Machine_X64: + case COFF_Machine_X86: { pe_print_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange, rdi); } break; default: NotImplemented; break; @@ -6635,9 +6633,9 @@ pe_print_base_relocs(Arena *arena, U32 addr_size = 0; switch (machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: addr_size = 4; break; - case COFF_MachineType_X64: addr_size = 8; break; + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: addr_size = 4; break; + case COFF_Machine_X64: addr_size = 8; break; default: NotImplemented; } @@ -6667,9 +6665,9 @@ pe_print_base_relocs(Arena *arena, case PE_BaseRelocKind_DIR64: type_str = "DIR64"; break; default: { switch (machine) { - case COFF_MachineType_ARM: - case COFF_MachineType_ARM64: - case COFF_MachineType_ARMNT: { + case COFF_Machine_Arm: + case COFF_Machine_Arm64: + case COFF_Machine_ArmNt: { switch (type) { case PE_BaseRelocKind_ARM_MOV32: type_str = "ARM_MOV32"; break; case PE_BaseRelocKind_THUMB_MOV32: type_str = "THUMB_MOV32"; break; @@ -6718,14 +6716,14 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op goto exit; } - U64 coff_header_off = dos_header->coff_file_offset+sizeof(pe_magic); - COFF_Header *coff_header = str8_deserial_get_raw_ptr(raw_data, coff_header_off, sizeof(*coff_header)); - if (!coff_header) { + U64 file_header_off = dos_header->coff_file_offset+sizeof(pe_magic); + COFF_FileHeader *file_header = str8_deserial_get_raw_ptr(raw_data, file_header_off, sizeof(*file_header)); + if (!file_header) { rd_errorf("not enough bytes to read COFF header"); goto exit; } - U64 opt_header_off = coff_header_off + sizeof(*coff_header); + U64 opt_header_off = file_header_off + sizeof(*file_header); U16 opt_header_magic = 0; str8_deserial_read_struct(raw_data, opt_header_off, &opt_header_magic); if (opt_header_magic != PE_PE32_MAGIC && opt_header_magic != PE_PE32PLUS_MAGIC) { @@ -6733,36 +6731,36 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op goto exit; } - if (opt_header_magic == PE_PE32_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32)) { - rd_errorf("unexpected optional header size in COFF header %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32)); + if (opt_header_magic == PE_PE32_MAGIC && file_header->optional_header_size < sizeof(PE_OptionalHeader32)) { + rd_errorf("unexpected optional header size in COFF header %m, expected at least %m", file_header->optional_header_size, sizeof(PE_OptionalHeader32)); goto exit; } - if (opt_header_magic == PE_PE32PLUS_MAGIC && coff_header->optional_header_size < sizeof(PE_OptionalHeader32Plus)) { - rd_errorf("unexpected optional header size %m, expected at least %m", coff_header->optional_header_size, sizeof(PE_OptionalHeader32Plus)); + if (opt_header_magic == PE_PE32PLUS_MAGIC && file_header->optional_header_size < sizeof(PE_OptionalHeader32Plus)) { + rd_errorf("unexpected optional header size %m, expected at least %m", file_header->optional_header_size, sizeof(PE_OptionalHeader32Plus)); goto exit; } - U64 sections_off = coff_header_off + sizeof(*coff_header) + coff_header->optional_header_size; - COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sections_off, sizeof(*sections)*coff_header->section_count); + U64 sections_off = file_header_off + sizeof(*file_header) + file_header->optional_header_size; + COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sections_off, sizeof(*sections)*file_header->section_count); if (!sections) { rd_errorf("not enough bytes to read COFF section headers"); goto exit; } - U64 string_table_off = coff_header->symbol_table_foff + sizeof(COFF_Symbol16) * coff_header->symbol_count; + U64 string_table_off = file_header->symbol_table_foff + sizeof(COFF_Symbol16) * file_header->symbol_count; - COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, coff_header->symbol_table_foff, coff_header->symbol_count); + COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, file_header->symbol_table_foff, file_header->symbol_count); - U8 *raw_opt_header = push_array(scratch.arena, U8, coff_header->optional_header_size); - str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, coff_header->optional_header_size); + U8 *raw_opt_header = push_array(scratch.arena, U8, file_header->optional_header_size); + str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, file_header->optional_header_size); if (opts & RD_Option_Headers) { - coff_print_header(arena, out, indent, coff_header); + coff_print_file_header(arena, out, indent, file_header); rd_newline(); } - Arch arch = arch_from_coff_machine(coff_header->machine); + Arch arch = arch_from_coff_machine(file_header->machine); U64 image_base = 0; U64 dir_count = 0; PE_DataDirectory *dirs = 0; @@ -6800,17 +6798,17 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op Rng1U64 *dirs_virt_ranges = push_array(scratch.arena, Rng1U64, dir_count); for (U64 i = 0; i < dir_count; ++i) { PE_DataDirectory dir = dirs[i]; - U64 file_off = coff_foff_from_voff(sections, coff_header->section_count, dir.virt_off); + U64 file_off = coff_foff_from_voff(sections, file_header->section_count, dir.virt_off); dirs_file_ranges[i] = r1u64(file_off, file_off+dir.virt_size); dirs_virt_ranges[i] = r1u64(dir.virt_off, dir.virt_off+dir.virt_size); } if (opts & RD_Option_Sections) { - coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, file_header->section_count, sections); } if (opts & RD_Option_Relocs) { - coff_print_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, file_header->machine, file_header->section_count, sections, symbols); } if (opts & RD_Option_Symbols) { @@ -6819,7 +6817,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (opts & RD_Option_Exports) { PE_ParsedExportTable exptab = pe_exports_from_data(arena, - coff_header->section_count, + file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXPORT], @@ -6829,8 +6827,8 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (opts & RD_Option_Imports) { B32 is_pe32 = opt_header_magic == PE_PE32_MAGIC; - PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); - PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); + PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); + PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); pe_print_static_import_table(arena, out, indent, image_base, static_imptab); pe_print_delay_import_table(arena, out, indent, image_base, delay_imptab); } @@ -6842,11 +6840,11 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op } if (opts & RD_Option_Exceptions) { - pe_print_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS], rdi); + pe_print_exceptions(arena, out, indent, file_header->machine, file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS], rdi); } if (opts & RD_Option_Relocs) { - pe_print_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC], rdi); + pe_print_base_relocs(arena, out, indent, file_header->machine, image_base, file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC], rdi); } if (opts & RD_Option_Debug) { @@ -6858,7 +6856,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (opts & RD_Option_Tls) { if (dim_1u64(dirs_file_ranges[PE_DataDirectoryIndex_TLS])) { - PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); + PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, file_header->machine, image_base, file_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); pe_print_tls(arena, out, indent, tls); } } @@ -6866,9 +6864,9 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (opts & RD_Option_LoadConfig) { String8 raw_lc = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_LOAD_CONFIG]); if (raw_lc.size) { - switch (coff_header->machine) { - case COFF_MachineType_UNKNOWN: break; - case COFF_MachineType_X86: { + switch (file_header->machine) { + case COFF_Machine_Unknown: break; + case COFF_Machine_X86: { PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { pe_print_load_config32(arena, out, indent, lc); @@ -6876,7 +6874,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op rd_errorf("not enough bytes to parse 32bit load config"); } } break; - case COFF_MachineType_X64: { + case COFF_Machine_X64: { PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { pe_print_load_config64(arena, out, indent, lc); @@ -6894,20 +6892,20 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (rdi) { section_markers = rd_section_markers_from_rdi(scratch.arena, rdi); } else { - section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, symbols); + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, file_header->section_count, symbols); } } if (opts & RD_Option_Rawdata) { - coff_raw_data_sections(arena, out, indent, raw_data, 0, section_markers, coff_header->section_count, sections); + coff_raw_data_sections(arena, out, indent, raw_data, 0, section_markers, file_header->section_count, sections); } if (opts & RD_Option_Disasm) { - coff_disasm_sections(arena, out, indent, raw_data, coff_header->machine, 0, 1, section_markers, coff_header->section_count, sections); + coff_disasm_sections(arena, out, indent, raw_data, file_header->machine, 0, 1, section_markers, file_header->section_count, sections); } if (opts & RD_Option_Dwarf) { - DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, sections); + DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, file_header->section_count, sections); dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_CoffPe); } diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index 90738f38..29529060 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -120,7 +120,8 @@ typedef struct RD_Line // raddump -internal B32 rd_is_pe(String8 raw_data); +internal B32 rd_is_pe(String8 raw_data); + internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); // Markers @@ -134,12 +135,12 @@ internal RD_SectionArray rd_sections_from_coff_section_table(Arena *arnea, Strin // Disasm internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code); -internal void rd_print_disasm (Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); +internal void rd_print_disasm (Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); // Raw Data internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); -internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); +internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); // DWARF @@ -182,15 +183,15 @@ internal void cv_print_symbols_section(Arena *arena, String8List *out, String8 i // COFF -internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); +internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names); internal void coff_print_seciton_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); -internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); -internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); -internal void coff_print_header (Arena *arena, String8List *out, String8 indent, COFF_Header *header); -internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); +internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header); +internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header); +internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header); internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); @@ -207,7 +208,7 @@ internal void pe_print_optional_header32plus(Arena *arena, String8List *out, Str internal void pe_print_load_config32 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); internal void pe_print_load_config64 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); internal void pe_print_tls (Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); -internal void pe_print_debug_diretory (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); +internal void pe_print_debug_diretory (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); internal void pe_print_export_table (Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); internal void pe_print_static_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); internal void pe_print_delay_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index 0534911a..ea19187d 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -28,6 +28,7 @@ #include "path/path.h" #include "coff/coff.h" #include "coff/coff_enum.h" +#include "coff/coff_parse.h" #include "pe/pe.h" #include "msvc_crt/msvc_crt.h" #include "msvc_crt/msvc_crt_enum.h" @@ -53,6 +54,7 @@ #include "path/path.c" #include "coff/coff.c" #include "coff/coff_enum.c" +#include "coff/coff_parse.c" #include "pe/pe.c" #include "msvc_crt/msvc_crt.c" #include "msvc_crt/msvc_crt_enum.c" @@ -226,7 +228,7 @@ entry_point(CmdLine *cmdline) // format input rd_format_preamble(arena, out, indent, file_path, raw_data); - if (coff_is_archive(raw_data) || coff_is_thin_archive(raw_data)) { + if (coff_is_regular_archive(raw_data) || coff_is_thin_archive(raw_data)) { coff_print_archive(arena, out, indent, raw_data, opts); } else if (coff_is_big_obj(raw_data)) { coff_print_big_obj(arena, out, indent, raw_data, opts); diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 078740da..b396ab9b 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -161,15 +161,15 @@ internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) { RDI_BinarySectionFlags result = 0; - if(flags & COFF_SectionFlag_MEM_READ) + if(flags & COFF_SectionFlag_MemRead) { result |= RDI_BinarySectionFlag_Read; } - if(flags & COFF_SectionFlag_MEM_WRITE) + if(flags & COFF_SectionFlag_MemWrite) { result |= RDI_BinarySectionFlag_Write; } - if(flags & COFF_SectionFlag_MEM_EXECUTE) + if(flags & COFF_SectionFlag_MemExecute) { result |= RDI_BinarySectionFlag_Execute; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c index d5de3918..9b2e49b5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -22,6 +22,7 @@ #include "async/async.h" #include "rdi_make/rdi_make_local.h" #include "coff/coff.h" +#include "coff/coff_parse.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" #include "msf/msf.h" @@ -37,6 +38,7 @@ #include "async/async.c" #include "rdi_make/rdi_make_local.c" #include "coff/coff.c" +#include "coff/coff_parse.c" #include "codeview/codeview.c" #include "codeview/codeview_parse.c" #include "msf/msf.c" From e1e7fb745e500386c34eff223b45467db4bb78d2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 20 Jan 2025 21:36:34 -0800 Subject: [PATCH 33/53] win32 shared mutex impl and linux stubs --- src/os/core/linux/os_core_linux.c | 26 +++++++++++++++++++++++ src/os/core/os_core.h | 6 ++++++ src/os/core/win32/os_core_win32.c | 34 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 3b2c73b1..31d2b252 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -861,6 +861,32 @@ os_mutex_drop(OS_Handle mutex) pthread_mutex_unlock(&entity->mutex_handle); } +internal OS_Handle +os_shared_mutex_alloc(String8 name) +{ + NotImplemented; + OS_Handle handle = {0}; + return handle; +} + +internal void +os_shared_mutex_release(OS_Handle mutex) +{ + NotImplemented; +} + +internal B32 +os_shared_mutex_take(OS_Handle mutex, U64 endt_us) +{ + NotImplemented; +} + +internal void +os_shared_mutex_drop(OS_Handle mutex) +{ + NotImplemented; +} + //- rjf: reader/writer mutexes internal OS_Handle diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 5f09ca8b..867120ef 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -277,6 +277,12 @@ internal void os_rw_mutex_drop_r(OS_Handle mutex); internal void os_rw_mutex_take_w(OS_Handle mutex); internal void os_rw_mutex_drop_w(OS_Handle mutex); +//- shared mutex +internal OS_Handle os_shared_mutex_alloc(String8 name); +internal void os_shared_mutex_release(OS_Handle mutex); +internal B32 os_shared_mutex_take(OS_Handle mutex, U64 endt_us); +internal void os_shared_mutex_drop(OS_Handle mutex); + //- rjf: condition variables internal OS_Handle os_condition_variable_alloc(void); internal void os_condition_variable_release(OS_Handle cv); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 6a0e0281..e97a203d 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1106,6 +1106,40 @@ os_mutex_drop(OS_Handle mutex) LeaveCriticalSection(&entity->mutex); } +internal OS_Handle +os_shared_mutex_alloc(String8 name) +{ + Assert(name.size); + Temp scratch = scratch_begin(0,0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = CreateMutexW(0, 0, (WCHAR*)name16.str); + Assert(handle != 0); + OS_Handle mutex = {(U64)handle}; + scratch_end(scratch); + return mutex; +} + +internal void +os_shared_mutex_release(OS_Handle mutex) +{ + CloseHandle((HANDLE)mutex.u64[0]); +} + +internal B32 +os_shared_mutex_take(OS_Handle mutex, U64 endt_us) +{ + U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + DWORD wait_result = WaitForSingleObject((HANDLE)mutex.u64[0], sleep_ms); + B32 result = (wait_result == WAIT_OBJECT_0); + return result; +} + +internal void +os_shared_mutex_drop(OS_Handle mutex) +{ + ReleaseMutex((HANDLE)mutex.u64[0]); +} + //- rjf: reader/writer mutexes internal OS_Handle From d3fbc858b8bb9a3e29b202ca36e769006fa71290 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 20 Jan 2025 21:41:24 -0800 Subject: [PATCH 34/53] impl shared thread pool mode --- src/linker/lnk.c | 9 +- src/linker/lnk_config.c | 137 +++++++++++++++------------ src/linker/lnk_config.h | 4 + src/linker/thread_pool/thread_pool.c | 33 ++++++- src/linker/thread_pool/thread_pool.h | 3 + 5 files changed, 118 insertions(+), 68 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 5f74851d..89a3b31c 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3189,8 +3189,13 @@ lnk_run(int argc, char **argv) LNK_Config *config = lnk_build_config(scratch.arena, argc, argv); - TP_Context *tp = tp_alloc(scratch.arena, config->worker_count); - TP_Arena *tp_arena = tp_arena_alloc(tp); + TP_Context *tp; + if (config->shared_thread_pool == LNK_SwitchState_Yes) { + tp = tp_alloc_shared(scratch.arena, config->worker_count, config->shared_thread_pool_mutex_name); + } else { + tp = tp_alloc(scratch.arena, config->worker_count); + } + TP_Arena *tp_arena = tp_arena_alloc(tp); #if PROFILE_TELEMETRY { diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index d05e8804..a3151585 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -127,41 +127,43 @@ global read_only struct { LNK_CmdSwitch_NotImplemented, "WX", "", "" }, //- internal switches - { LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, - { LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." }, - { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, - { LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" }, - { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, - { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, - { LNK_CmdSwitch_Rad_IdleWorkers, "RAD_IDLE_WORKERS", ":#", "Number of workers to leave idle." }, - { LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, - { LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, - { LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, - { LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, - { LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, - { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, - { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, - { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, - { LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, - { LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, - { LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." }, - { LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." }, + { LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, + { LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." }, + { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, + { LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" }, + { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, + { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, + { LNK_CmdSwitch_Rad_IdleWorkers, "RAD_IDLE_WORKERS", ":#", "Number of workers to leave idle." }, + { LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, + { LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, + { LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, + { LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, + { LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, + { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, + { LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RAD_SHARED_THREAD_POOL_MUTEX_NAME", ":STRING", "" }, + { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, + { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, + { LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, + { LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, + { LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." }, + { LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." }, - { LNK_CmdSwitch_Help, "HELP", "", "" }, - { LNK_CmdSwitch_Help, "?", "", "" }, + { LNK_CmdSwitch_Help, "HELP", "", "" }, + { LNK_CmdSwitch_Help, "?", "", "" }, }; global read_only struct @@ -944,6 +946,8 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path) { + Assert(cmd_name.size); // switch must have a defined name in the table + Temp scratch = scratch_begin(&arena,1); LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); @@ -1672,6 +1676,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } break; + case LNK_CmdSwitch_Rad_SharedThreadPool: { + lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool); + } break; + + case LNK_CmdSwitch_Rad_SharedThreadPoolMutexName: { + lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool_mutex_name); + } break; + case LNK_CmdSwitch_Rad_SuppressError: { U64List error_code_list = {0}; if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) { @@ -1754,34 +1766,35 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); } - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FunctionPadMin, "0"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DelayBind, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_EnvLib, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Exe, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Guid, "imageblake3"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LargePages, "no"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LinkVer, "14.0"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_OsVer, "6.0"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PageSize, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FunctionPadMin, "0"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DelayBind, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_EnvLib, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Exe, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Guid, "imageblake3"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LargePages, "no"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LinkVer, "14.0"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_OsVer, "6.0"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PageSize, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RADLINK_THREAD_POOL_MUTEX"); #if BUILD_DEBUG lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 595eca07..6db6f692 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -147,6 +147,8 @@ typedef enum LNK_CmdSwitch_Rad_PdbHashTypeNameMap, LNK_CmdSwitch_Rad_PdbHashTypeNameLength, LNK_CmdSwitch_Rad_SectVirtOff, + LNK_CmdSwitch_Rad_SharedThreadPool, + LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_SymbolTableCapDefined, LNK_CmdSwitch_Rad_SymbolTableCapInternal, @@ -310,6 +312,8 @@ typedef struct LNK_Config U64 pdb_page_size; U64 worker_count; U64 idle_worker_count; + LNK_SwitchState shared_thread_pool; + String8 shared_thread_pool_mutex_name; U64 *function_pad_min; U64 *manifest_resource_id; B32 no_default_libs; diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index afc9d4a9..29d45ee1 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -81,12 +81,25 @@ tp_alloc(Arena *arena, U32 worker_count) return pool; } +internal TP_Context * +tp_alloc_shared(Arena *arena, U32 worker_count, String8 name) +{ + TP_Context *tp = tp_alloc(arena, worker_count); + tp->shared_mutex_name = name; + tp->shared_mutex_handle = os_shared_mutex_alloc(name); + AssertAlways(!os_handle_match(tp->shared_mutex_handle, os_handle_zero())); + return tp; +} + internal void tp_release(TP_Context *pool) { pool->is_live = 0; os_semaphore_release(pool->task_semaphore); os_semaphore_release(pool->main_semaphore); + if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { + os_mutex_release(pool->shared_mutex_handle); + } for (U64 i = 1; i < pool->worker_count; i += 1) { os_thread_detach(pool->worker_arr[i].handle); } @@ -160,13 +173,20 @@ tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc * { Assert(!arena || arena->count == pool->worker_count); + // in shared mode take mutex + if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { + if (!os_shared_mutex_take(pool->shared_mutex_handle, max_U64)) { + AssertAlways(!"failed to take shared mutex"); + } + } + // setup pool state pool->worker_arena = arena; - pool->task_count = task_count; - pool->task_func = task_func; - pool->task_data = task_data; + pool->task_count = task_count; + pool->task_func = task_func; + pool->task_data = task_data; pool->next_task_id = 0; - pool->take_count = 0; + pool->take_count = 0; // do we have enough work for other workers? pool->take_count = Min(pool->task_count, pool->worker_count); @@ -183,6 +203,11 @@ tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc * // wait for workers to finish assigned tasks os_semaphore_take(pool->main_semaphore, max_U64); } + + // signal other thread pools that we have done our round of tasks + if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { + os_shared_mutex_drop(pool->shared_mutex_handle); + } } internal Rng1U64 * diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index 4ed6e5c2..dfc0bdcd 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -29,6 +29,8 @@ typedef struct TP_Context { OS_Handle task_semaphore; OS_Handle main_semaphore; + OS_Handle shared_mutex_handle; + String8 shared_mutex_name; B32 is_live; U32 worker_count; TP_Worker *worker_arr; @@ -41,6 +43,7 @@ typedef struct TP_Context } TP_Context; internal TP_Context * tp_alloc(Arena *arena, U32 worker_count); +internal TP_Context * tp_alloc_shared(Arena *arena, U32 worker_count, String8 name); internal void tp_release(TP_Context *pool); internal TP_Arena * tp_arena_alloc(TP_Context *pool); internal void tp_arena_release(TP_Arena **arena_ptr); From 85ea141b8376a4236e94d99246a375c90edcba69 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 20 Jan 2025 21:53:45 -0800 Subject: [PATCH 35/53] minor fixes --- src/coff/coff_parse.c | 8 ++++---- src/linker/lnk.c | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c index aa33fb07..dd501ec5 100644 --- a/src/coff/coff_parse.c +++ b/src/coff/coff_parse.c @@ -481,13 +481,13 @@ coff_resource_id_compar(void *raw_a, void *raw_b) COFF_ResourceID *b = raw_b; if (a->type == b->type) { switch (a->type) { - case COFF_ResourceIDType_Null: break; - case COFF_ResourceIDType_Number: cmp = u16_compar(&a->u.number, &b->u.number); break; - case COFF_ResourceIDType_String: cmp = str8_compar_case_sensitive(&a->u.string, &b->u.string); break; + case COFF_ResourceIDType_Null: cmp = 0; break; + case COFF_ResourceIDType_Number: cmp = a->u.number < b->u.number ? -1 : a->u.number > b->u.number ? +1 : 0; break; + case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break; default: InvalidPath; break; } } else { - cmp = u32_compar(&a->type, &b->type); + cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0; } return cmp; } diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 89a3b31c..764acaf1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1234,6 +1234,7 @@ lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *laz COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { + case COFF_DataType_Null: break; case COFF_DataType_Import: { LNK_InputImport *input = lnk_input_import_list_push(arena, input_import_list); input->import_header = coff_archive_import_from_data(member_info.data); From 61307aefbcae08d826f6d542ecf668d716748b2a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 21 Jan 2025 01:55:13 -0800 Subject: [PATCH 36/53] reworked thread pool to share workers via semaphore --- src/linker/lnk.c | 9 +-- src/linker/lnk_config.c | 17 ++--- src/linker/lnk_config.h | 6 +- src/linker/thread_pool/thread_pool.c | 104 ++++++++++----------------- src/linker/thread_pool/thread_pool.h | 9 +-- 5 files changed, 53 insertions(+), 92 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 764acaf1..ac8bb242 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3190,13 +3190,8 @@ lnk_run(int argc, char **argv) LNK_Config *config = lnk_build_config(scratch.arena, argc, argv); - TP_Context *tp; - if (config->shared_thread_pool == LNK_SwitchState_Yes) { - tp = tp_alloc_shared(scratch.arena, config->worker_count, config->shared_thread_pool_mutex_name); - } else { - tp = tp_alloc(scratch.arena, config->worker_count); - } - TP_Arena *tp_arena = tp_arena_alloc(tp); + TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->shared_thread_pool_name); + TP_Arena *tp_arena = tp_arena_alloc(tp); #if PROFILE_TELEMETRY { diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index a3151585..6b0a9ed6 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -150,8 +150,7 @@ global read_only struct { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, - { LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RAD_SHARED_THREAD_POOL_MUTEX_NAME", ":STRING", "" }, + { LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, @@ -1677,11 +1676,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_Rad_SharedThreadPool: { - lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool); - } break; - - case LNK_CmdSwitch_Rad_SharedThreadPoolMutexName: { - lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool_mutex_name); + if (value_strings.node_count == 0) { + config->shared_thread_pool_name = str8_lit(LNK_DEFAULT_THREAD_POOL_NAME); + } else { + lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool_name); + if (config->shared_thread_pool_name.size == 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid empty string for thread pool name"); + } + } } break; case LNK_CmdSwitch_Rad_SuppressError: { @@ -1794,7 +1796,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RADLINK_THREAD_POOL_MUTEX"); #if BUILD_DEBUG lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 6db6f692..130d879b 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -148,7 +148,6 @@ typedef enum LNK_CmdSwitch_Rad_PdbHashTypeNameLength, LNK_CmdSwitch_Rad_SectVirtOff, LNK_CmdSwitch_Rad_SharedThreadPool, - LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_SymbolTableCapDefined, LNK_CmdSwitch_Rad_SymbolTableCapInternal, @@ -286,6 +285,8 @@ typedef enum # error #endif +#define LNK_DEFAULT_THREAD_POOL_NAME "RADLINK_THREAD_POOL" + typedef struct LNK_Config { LNK_ConfigFlags flags; @@ -312,8 +313,7 @@ typedef struct LNK_Config U64 pdb_page_size; U64 worker_count; U64 idle_worker_count; - LNK_SwitchState shared_thread_pool; - String8 shared_thread_pool_mutex_name; + String8 shared_thread_pool_name; U64 *function_pad_min; U64 *manifest_resource_id; B32 no_default_libs; diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index 29d45ee1..6399cd78 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -6,42 +6,37 @@ tp_execute_tasks(TP_Worker *worker) { TP_Context *pool = worker->pool; - Arena *arena = NULL; - if (pool->worker_arena) { - arena = pool->worker_arena->v[worker->id]; - } - for (;;) { - // get task id - U64 next_task_id = ins_atomic_u64_inc_eval(&pool->next_task_id); - if (next_task_id > pool->task_count) { + // do we have tasks? + S64 task_left_count = ins_atomic_u64_dec_eval(&pool->task_left_count); + if (task_left_count < 0) { break; } - // invoke task func - U64 task_id = next_task_id - 1; + // invoke task + Arena *arena = pool->worker_arena ? pool->worker_arena->v[worker->id] : 0; + U64 task_id = pool->task_count - (task_left_count+1); pool->task_func(arena, worker->id, task_id, pool->task_data); + + // before last worker takes semaphore wake up main thread + U64 task_done_count = ins_atomic_u64_inc_eval(&pool->task_done_count); + if (task_done_count == pool->task_count) { + os_semaphore_drop(pool->main_semaphore); + } } } internal void tp_worker_main(void *raw_worker) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); + TCTX tctx_; tctx_init_and_equip(&tctx_); - TP_Worker *worker = (TP_Worker *)raw_worker; - TP_Context *pool = worker->pool; + TP_Worker *worker = raw_worker; + TP_Context *pool = worker->pool; while (pool->is_live) { if (os_semaphore_take(pool->task_semaphore, max_U64)) { tp_execute_tasks(worker); - - // before last worker takes semaphore wake up main worker - U64 take_count = ins_atomic_u64_dec_eval(&pool->take_count); - if (take_count == 1) { - os_semaphore_drop(pool->main_semaphore); - } } else { Assert(!"time out"); } @@ -49,7 +44,7 @@ tp_worker_main(void *raw_worker) } internal TP_Context * -tp_alloc(Arena *arena, U32 worker_count) +tp_alloc(Arena *arena, U32 worker_count, String8 name) { ProfBeginDynamic("Alloc Thread Pool [Worker Count: %u]", worker_count); Assert(worker_count > 0); @@ -57,7 +52,7 @@ tp_alloc(Arena *arena, U32 worker_count) // init pool TP_Context *pool = push_array(arena, TP_Context, 1); if (worker_count > 1) { - pool->task_semaphore = os_semaphore_alloc(0, worker_count - 1, str8(0,0)); + pool->task_semaphore = os_semaphore_alloc(0, worker_count - 1, name); pool->main_semaphore = os_semaphore_alloc(0, 1, str8(0,0)); } pool->is_live = 1; @@ -81,25 +76,12 @@ tp_alloc(Arena *arena, U32 worker_count) return pool; } -internal TP_Context * -tp_alloc_shared(Arena *arena, U32 worker_count, String8 name) -{ - TP_Context *tp = tp_alloc(arena, worker_count); - tp->shared_mutex_name = name; - tp->shared_mutex_handle = os_shared_mutex_alloc(name); - AssertAlways(!os_handle_match(tp->shared_mutex_handle, os_handle_zero())); - return tp; -} - internal void tp_release(TP_Context *pool) { pool->is_live = 0; os_semaphore_release(pool->task_semaphore); os_semaphore_release(pool->main_semaphore); - if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { - os_mutex_release(pool->shared_mutex_handle); - } for (U64 i = 1; i < pool->worker_count; i += 1) { os_thread_detach(pool->worker_arr[i].handle); } @@ -171,43 +153,29 @@ tp_temp_end(TP_Temp temp) internal void tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *task_func, void *task_data) { - Assert(!arena || arena->count == pool->worker_count); + if (task_count > 0) { + Assert(!arena || arena->count == pool->worker_count); - // in shared mode take mutex - if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { - if (!os_shared_mutex_take(pool->shared_mutex_handle, max_U64)) { - AssertAlways(!"failed to take shared mutex"); + // init context + pool->worker_arena = arena; + pool->task_count = task_count; + pool->task_func = task_func; + pool->task_data = task_data; + pool->task_done_count = 0; + pool->task_left_count = task_count; + + // wake up workers + for (U64 worker_idx = 1; worker_idx < pool->worker_count; worker_idx += 1) { + os_semaphore_drop(pool->task_semaphore); } - } - - // setup pool state - pool->worker_arena = arena; - pool->task_count = task_count; - pool->task_func = task_func; - pool->task_data = task_data; - pool->next_task_id = 0; - pool->take_count = 0; - - // do we have enough work for other workers? - pool->take_count = Min(pool->task_count, pool->worker_count); - U64 drop_count = pool->take_count; - for (U64 worker_idx = 1; worker_idx < drop_count; worker_idx += 1) { - os_semaphore_drop(pool->task_semaphore); - } - - // execute tasks on main worker too - TP_Worker *main_worker = &pool->worker_arr[0]; - tp_execute_tasks(main_worker); - - if (drop_count > 1) { - // wait for workers to finish assigned tasks + + // execute tasks on main worker + TP_Worker *main_worker = &pool->worker_arr[0]; + tp_execute_tasks(main_worker); + + // wait for workers to finish tasks os_semaphore_take(pool->main_semaphore, max_U64); } - - // signal other thread pools that we have done our round of tasks - if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) { - os_shared_mutex_drop(pool->shared_mutex_handle); - } } internal Rng1U64 * diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index dfc0bdcd..0c31913b 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -29,8 +29,6 @@ typedef struct TP_Context { OS_Handle task_semaphore; OS_Handle main_semaphore; - OS_Handle shared_mutex_handle; - String8 shared_mutex_name; B32 is_live; U32 worker_count; TP_Worker *worker_arr; @@ -38,12 +36,11 @@ typedef struct TP_Context U64 task_count; TP_TaskFunc *task_func; void *task_data; - volatile U64 next_task_id; - volatile U64 take_count; + volatile S64 task_left_count; + volatile U64 task_done_count; } TP_Context; -internal TP_Context * tp_alloc(Arena *arena, U32 worker_count); -internal TP_Context * tp_alloc_shared(Arena *arena, U32 worker_count, String8 name); +internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, String8 name); internal void tp_release(TP_Context *pool); internal TP_Arena * tp_arena_alloc(TP_Context *pool); internal void tp_arena_release(TP_Arena **arena_ptr); From c6d28b97b7e9229ec18b9610364e5ece2abbf99e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 21 Jan 2025 11:14:12 -0800 Subject: [PATCH 37/53] more details for LF_STRUCT2 --- src/codeview/codeview.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index 524b59c6..4caebc98 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -2149,6 +2149,7 @@ typedef enum CV_MoComUDTKindEnum } CV_MoComUDTKindEnum; typedef U16 CV_TypeProps; +typedef U32 CV_TypeProps32; enum { CV_TypeProp_Packed = (1 << 0), @@ -2686,12 +2687,11 @@ typedef struct CV_LeafStruct2 CV_LeafStruct2; struct CV_LeafStruct2 { // NOTE: still reverse engineering this - if you find docs please help! - CV_TypeProps props; - U16 unknown1; - CV_TypeId field_itype; - CV_TypeId derived_itype; - CV_TypeId vshape_itype; - U16 unknown2; + CV_TypeProps32 props; + CV_TypeId field_itype; + CV_TypeId derived_itype; + CV_TypeId vshape_itype; + U16 unknown; // count for something? (possibly CV_Numeric) // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) From aa4ec903a6a8f911e55e9023dc386b8478054379 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 21 Jan 2025 11:29:12 -0800 Subject: [PATCH 38/53] update LF_STRUCT2 printer --- src/codeview/codeview_enum.c | 2 +- src/codeview/codeview_enum.h | 2 +- src/raddump/raddump.c | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/codeview/codeview_enum.c b/src/codeview/codeview_enum.c index 8442ace9..6e0a1105 100644 --- a/src/codeview/codeview_enum.c +++ b/src/codeview/codeview_enum.c @@ -572,7 +572,7 @@ cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x) } internal String8 -cv_string_from_type_props(Arena *arena, CV_TypeProps x) +cv_string_from_type_props(Arena *arena, CV_TypeProps32 x) { Temp scratch = scratch_begin(&arena, 1); diff --git a/src/codeview/codeview_enum.h b/src/codeview/codeview_enum.h index 3216f867..86abb059 100644 --- a/src/codeview/codeview_enum.h +++ b/src/codeview/codeview_enum.h @@ -32,7 +32,7 @@ internal String8 cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x); internal String8 cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x); internal String8 cv_string_from_generic_flags(Arena *arena, CV_GenericFlags x); internal String8 cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x); -internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps x); +internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps32 x); internal String8 cv_string_from_local_flags(Arena *arena, CV_LocalFlags x); internal String8 cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x); internal String8 cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x); diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index ec47f263..2d41e462 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -3689,13 +3689,12 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += cv_read_numeric(raw_leaf, cursor, &size); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); - rd_printf("Unknown1: %x", lf.unknown1); - rd_printf("Unknown2: %x", lf.unknown2); + rd_printf("Name: %S", name); + rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); + rd_printf("Unknown: %x", lf.unknown); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = str8_zero(); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); From 53db7ee7121d4309c4358e5ee3019ebd599796c2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 21 Jan 2025 11:29:28 -0800 Subject: [PATCH 39/53] fix symbol table printer for big objs --- src/raddump/raddump.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 2d41e462..db727441 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -4949,9 +4949,9 @@ coff_print_symbol_table(Arena *arena, String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class); String8 section_number; switch (symbol->section_number) { - case COFF_Symbol_UndefinedSection: section_number = str8_lit("UNDEF"); break; - case COFF_Symbol_AbsSection32: section_number = str8_lit("ABS"); break; - case COFF_Symbol_DebugSection32: section_number = str8_lit("DEBUG"); break; + case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break; + case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break; + case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break; default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break; } @@ -5135,7 +5135,7 @@ coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_d } if (opts & RD_Option_Symbols) { - coff_print_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 1, string_table_off, symbols); rd_newline(); } From b007e4c0e59236e5bdfdb1fd7b846d50d18d8b22 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 23 Jan 2025 20:38:43 -0800 Subject: [PATCH 40/53] printer for S_LABEL --- src/codeview/codeview_enum.c | 16 ++++++++++++++++ src/codeview/codeview_enum.h | 1 + src/raddump/raddump.c | 15 ++++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/codeview/codeview_enum.c b/src/codeview/codeview_enum.c index 6e0a1105..3b03411b 100644 --- a/src/codeview/codeview_enum.c +++ b/src/codeview/codeview_enum.c @@ -1,6 +1,12 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal String8 +cv_string_from_unknown_value(Arena *arena, U32 x) +{ + return push_str8f(arena, "%#x", x); +} + internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source) { @@ -307,6 +313,16 @@ cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x) return str8_zero(); } +internal String8 +cv_string_from_label_kind(Arena *arena, CV_LabelKind x) +{ + switch (x) { + case CV_LabelKind_Near: return str8_lit("Near"); + case CV_LabelKind_Far: return str8_lit("Far"); + } + return cv_string_from_unknown_value(arena, x); +} + internal String8 cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x) { diff --git a/src/codeview/codeview_enum.h b/src/codeview/codeview_enum.h index 86abb059..02167351 100644 --- a/src/codeview/codeview_enum.h +++ b/src/codeview/codeview_enum.h @@ -23,6 +23,7 @@ internal String8 cv_string_from_member_pointer_kind(CV_MemberPointerKind x); internal String8 cv_string_from_pointer_kind(CV_PointerKind x); internal String8 cv_string_from_pointer_mode(CV_PointerMode x); internal String8 cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x); +internal String8 cv_string_from_label_kind(Arena *arena, CV_LabelKind x); internal String8 cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x); internal String8 cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x); internal String8 cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x); diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index db727441..212eb6ce 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -4084,7 +4084,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i } break; case CV_LeafKind_MEMBER_ST: case CV_LeafKind_MEMBER: { - CV_LeafMember lf = {0}; + CV_LeafMember lf = {0}; CV_NumericParsed num = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); @@ -4096,6 +4096,17 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, num)); } break; + case CV_LeafKind_LABEL: { + CV_LeafLabel lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + + rd_printf("Kind: %S", cv_string_from_label_kind(scratch.arena, lf.kind)); + } break; + case CV_LeafKind_ENDPRECOMP: { + CV_LeafEndPreComp lf = {0}; + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); + rd_printf("Sig: %#x", lf.sig); + } break; // 16bit case CV_LeafKind_OEM_16t: case CV_LeafKind_MODIFIER_16t: @@ -4145,8 +4156,6 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i // Manged case CV_LeafKind_MANAGED_ST: // undefined - case CV_LeafKind_LABEL: - case CV_LeafKind_ENDPRECOMP: case CV_LeafKind_LIST: case CV_LeafKind_REFSYM: case CV_LeafKind_BARRAY: From 71b0dfa150394aaac849b0fd6d980ece96a9a4a1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 23 Jan 2025 20:39:06 -0800 Subject: [PATCH 41/53] bugfix for uninited memory --- src/linker/lnk_debug_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 1c175386..b3418b83 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -305,8 +305,8 @@ THREAD_POOL_TASK_FUNC(lnk_get_external_leaves_task) LNK_GetExternalLeavesTask *task = raw_task; MSF_Parsed *msf_parse = task->msf_parse_arr[ts_idx]; - task->external_ti_ranges[ts_idx] = push_array_no_zero(arena, Rng1U64, CV_TypeIndexSource_COUNT); - task->external_leaves[ts_idx] = push_array_no_zero(arena, CV_DebugT, CV_TypeIndexSource_COUNT); + task->external_ti_ranges[ts_idx] = push_array(arena, Rng1U64, CV_TypeIndexSource_COUNT); + task->external_leaves[ts_idx] = push_array(arena, CV_DebugT, CV_TypeIndexSource_COUNT); task->is_corrupted[ts_idx] = 1; if (msf_parse) { From b463c8087d7e18735ba6fd6a6d951012073294df Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 23 Jan 2025 20:44:14 -0800 Subject: [PATCH 42/53] copy alternate name strings --- src/linker/lnk_config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 6b0a9ed6..d856cd68 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -977,7 +977,8 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_AlternateName: { - String8 *error_string = lnk_parse_alt_name_directive_list(arena, value_strings, &config->alt_name_list); + String8List value_strings_copy = str8_list_copy(arena, &value_strings); + String8 *error_string = lnk_parse_alt_name_directive_list(arena, value_strings_copy, &config->alt_name_list); if (error_string != 0) { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string); } From b18060ef0d64939eee6eee7dbfd8074c14b1d015 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 23 Jan 2025 20:45:25 -0800 Subject: [PATCH 43/53] on crash CRT randomly wont flush stdout --- src/linker/lnk_config.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index d856cd68..d0ef73a6 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -2027,10 +2027,10 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) if (lnk_get_log_status(LNK_Log_Debug)) { String8 full_cmd_line = str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") }); - lnk_log(LNK_Log_Debug, "--------------------------------------------------------------------------------"); - lnk_log(LNK_Log_Debug, "Command Line: %S", full_cmd_line); - lnk_log(LNK_Log_Debug, "Work Dir : %S", config->work_dir); - lnk_log(LNK_Log_Debug, "--------------------------------------------------------------------------------"); + fprintf(stderr, "--------------------------------------------------------------------------------\n"); + fprintf(stderr, "Command Line: %.*s\n", str8_varg(full_cmd_line)); + fprintf(stderr, "Work Dir : %.*s\n", str8_varg(config->work_dir)); + fprintf(stderr, "--------------------------------------------------------------------------------\n"); } scratch_end(scratch); From 8196ef0a6e155ed1e32395b85ef9cbcc1e0cc146 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 24 Jan 2025 10:33:42 -0800 Subject: [PATCH 44/53] tweaks and fixed in thread pool - created a separate entry point for shared workers - fixed race condition in tp_run_tasks where worker would read modified task count and cause unpredictable behavior --- src/linker/thread_pool/thread_pool.c | 141 ++++++++++++++++++--------- src/linker/thread_pool/thread_pool.h | 13 ++- 2 files changed, 104 insertions(+), 50 deletions(-) diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index 6399cd78..26637119 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -2,25 +2,27 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal void -tp_execute_tasks(TP_Worker *worker) +tp_run_tasks(TP_Context *pool, TP_Worker *worker) { - TP_Context *pool = worker->pool; - for (;;) { - // do we have tasks? - S64 task_left_count = ins_atomic_u64_dec_eval(&pool->task_left_count); - if (task_left_count < 0) { + S64 task_left = ins_atomic_u64_dec_eval(&pool->task_left); + + // are there any tasks left to run? + if (task_left < 0) { break; } - - // invoke task - Arena *arena = pool->worker_arena ? pool->worker_arena->v[worker->id] : 0; - U64 task_id = pool->task_count - (task_left_count+1); + + // run task + Arena *arena = pool->task_arena ? pool->task_arena->v[worker->id] : 0; + U64 task_id = pool->task_count - (task_left+1); pool->task_func(arena, worker->id, task_id, pool->task_data); - // before last worker takes semaphore wake up main thread - U64 task_done_count = ins_atomic_u64_inc_eval(&pool->task_done_count); - if (task_done_count == pool->task_count) { + // cache task count so we dont touch pool memory after atomic inc + U64 task_count = pool->task_count; + + // on last task ping main thread + U64 task_done = ins_atomic_u64_inc_eval(&pool->task_done); + if (task_done == task_count) { os_semaphore_drop(pool->main_semaphore); } } @@ -29,16 +31,27 @@ tp_execute_tasks(TP_Worker *worker) internal void tp_worker_main(void *raw_worker) { - TCTX tctx_; tctx_init_and_equip(&tctx_); - + TCTX tctx_; tctx_init_and_equip(&tctx_); TP_Worker *worker = raw_worker; TP_Context *pool = worker->pool; - - while (pool->is_live) { + for (; pool->is_live; ) { if (os_semaphore_take(pool->task_semaphore, max_U64)) { - tp_execute_tasks(worker); - } else { - Assert(!"time out"); + tp_run_tasks(pool, worker); + } + } +} + +internal void +tp_worker_main_shared(void *raw_worker) +{ + TCTX tctx_; tctx_init_and_equip(&tctx_); + TP_Worker *worker = raw_worker; + TP_Context *pool = worker->pool; + for (; pool->is_live; ) { + if (os_semaphore_take(pool->exec_semaphore, max_U64)) { + if (os_semaphore_take(pool->task_semaphore, max_U64)) { + tp_run_tasks(pool, worker); + } } } } @@ -47,14 +60,32 @@ internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, String8 name) { ProfBeginDynamic("Alloc Thread Pool [Worker Count: %u]", worker_count); - Assert(worker_count > 0); - - // init pool - TP_Context *pool = push_array(arena, TP_Context, 1); + AssertAlways(worker_count > 0); + + B32 is_shared = (name.size > 0); + + // alloc semaphores + OS_Handle main_semaphore = {0}; + OS_Handle task_semaphore = {0}; + OS_Handle exec_semaphore = {0}; if (worker_count > 1) { - pool->task_semaphore = os_semaphore_alloc(0, worker_count - 1, name); - pool->main_semaphore = os_semaphore_alloc(0, 1, str8(0,0)); + main_semaphore = os_semaphore_alloc(0, 1, str8_zero()); + if (is_shared) { + task_semaphore = os_semaphore_alloc(0, worker_count, name); + exec_semaphore = os_semaphore_alloc(0, worker_count, str8_zero()); + } else { + task_semaphore = os_semaphore_alloc(0, worker_count, str8_zero()); + } } + + // pick entry point for the workers + void *worker_entry = is_shared ? tp_worker_main_shared : tp_worker_main; + + // init pool + TP_Context *pool = push_array(arena, TP_Context, 1); + pool->exec_semaphore = exec_semaphore; + pool->task_semaphore = task_semaphore; + pool->main_semaphore = main_semaphore; pool->is_live = 1; pool->worker_count = worker_count; pool->worker_arr = push_array(arena, TP_Worker, worker_count); @@ -62,14 +93,14 @@ tp_alloc(Arena *arena, U32 worker_count, String8 name) // init worker data for (U64 i = 0; i < worker_count; i += 1) { TP_Worker *worker = &pool->worker_arr[i]; - worker->id = i; - worker->pool = pool; + worker->id = i; + worker->pool = pool; } // launch worker threads for (U64 i = 1; i < worker_count; i += 1) { TP_Worker *worker = &pool->worker_arr[i]; - worker->handle = os_thread_launch(tp_worker_main, worker, 0); + worker->handle = os_thread_launch(worker_entry, worker, 0); } ProfEnd(); @@ -80,11 +111,25 @@ internal void tp_release(TP_Context *pool) { pool->is_live = 0; - os_semaphore_release(pool->task_semaphore); - os_semaphore_release(pool->main_semaphore); + + B32 is_shared = !os_handle_match(pool->exec_semaphore, os_handle_zero()); + if (is_shared) { + for (U64 i = 0; i < pool->worker_count; ++i) { + os_semaphore_drop(pool->exec_semaphore); + } + } + for (U64 i = 0; i < pool->worker_count; ++i) { + os_semaphore_drop(pool->task_semaphore); + } for (U64 i = 1; i < pool->worker_count; i += 1) { os_thread_detach(pool->worker_arr[i].handle); } + if (is_shared) { + os_semaphore_release(pool->exec_semaphore); + } + os_semaphore_release(pool->task_semaphore); + os_semaphore_release(pool->main_semaphore); + MemoryZeroStruct(pool); } @@ -151,27 +196,33 @@ tp_temp_end(TP_Temp temp) } internal void -tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *task_func, void *task_data) +tp_for_parallel(TP_Context *pool, TP_Arena *task_arena, U64 task_count, TP_TaskFunc *task_func, void *task_data) { if (task_count > 0) { - Assert(!arena || arena->count == pool->worker_count); + // init run + pool->task_arena = task_arena; + pool->task_func = task_func; + pool->task_data = task_data; + pool->task_count = task_count; + pool->task_done = 0; + ins_atomic_u64_eval_assign(&pool->task_left, task_count); - // init context - pool->worker_arena = arena; - pool->task_count = task_count; - pool->task_func = task_func; - pool->task_data = task_data; - pool->task_done_count = 0; - pool->task_left_count = task_count; + U64 drop_count = Min(task_count, pool->worker_count); + + // if we are in shared mode ping local semaphore + if (!os_handle_match(pool->exec_semaphore, os_handle_zero())) { + for (U64 worker_idx = 0; worker_idx < drop_count; worker_idx +=1) { + os_semaphore_drop(pool->exec_semaphore); + } + } - // wake up workers - for (U64 worker_idx = 1; worker_idx < pool->worker_count; worker_idx += 1) { + // ping shared semaphore + for (U64 worker_idx = 0; worker_idx < drop_count; worker_idx += 1) { os_semaphore_drop(pool->task_semaphore); } - // execute tasks on main worker - TP_Worker *main_worker = &pool->worker_arr[0]; - tp_execute_tasks(main_worker); + // run tasks on main worker + tp_run_tasks(pool, &pool->worker_arr[0]); // wait for workers to finish tasks os_semaphore_take(pool->main_semaphore, max_U64); diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index 0c31913b..78aef33b 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -27,17 +27,20 @@ typedef struct TP_Worker typedef struct TP_Context { + B32 is_live; + OS_Handle exec_semaphore; OS_Handle task_semaphore; OS_Handle main_semaphore; - B32 is_live; + U32 worker_count; TP_Worker *worker_arr; - TP_Arena *worker_arena; - U64 task_count; + + TP_Arena *task_arena; TP_TaskFunc *task_func; void *task_data; - volatile S64 task_left_count; - volatile U64 task_done_count; + U64 task_count; + U64 task_done; + S64 task_left; } TP_Context; internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, String8 name); From f2f18b979844ba17341e4a20ed62efc4a6fc7a82 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 24 Jan 2025 12:49:30 -0800 Subject: [PATCH 45/53] replaced /RAD_IDLE_WORKERS with /RAD_SHARED_THREAD_POOL_MAX_WORKERS --- src/linker/lnk.c | 2 +- src/linker/lnk_config.c | 115 ++++++++++++++++----------- src/linker/lnk_config.h | 35 ++++---- src/linker/thread_pool/thread_pool.c | 5 +- src/linker/thread_pool/thread_pool.h | 2 +- 5 files changed, 90 insertions(+), 69 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index ac8bb242..4960fb17 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3190,7 +3190,7 @@ lnk_run(int argc, char **argv) LNK_Config *config = lnk_build_config(scratch.arena, argc, argv); - TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->shared_thread_pool_name); + TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name); TP_Arena *tp_arena = tp_arena_alloc(tp); #if PROFILE_TELEMETRY diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index d0ef73a6..28d2d329 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -127,39 +127,39 @@ global read_only struct { LNK_CmdSwitch_NotImplemented, "WX", "", "" }, //- internal switches - { LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, - { LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." }, - { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, - { LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" }, - { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, - { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, - { LNK_CmdSwitch_Rad_IdleWorkers, "RAD_IDLE_WORKERS", ":#", "Number of workers to leave idle." }, - { LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, - { LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, - { LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, - { LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, - { LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, - { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, - { LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, - { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, - { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, - { LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, - { LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, - { LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." }, - { LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." }, + { LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, + { LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." }, + { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, + { LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" }, + { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, + { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, + { LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, + { LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, + { LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, + { LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, + { LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, + { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, + { LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, + { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, + { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, + { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, + { LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, + { LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, + { LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, + { LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." }, + { LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." }, { LNK_CmdSwitch_Help, "HELP", "", "" }, { LNK_CmdSwitch_Help, "?", "", "" }, @@ -494,6 +494,12 @@ lnk_do_debug_info(LNK_Config *config) return do_debug_info; } +internal B32 +lnk_is_thread_pool_shared(LNK_Config *config) +{ + return config->shared_thread_pool_name.size > 0; +} + //////////////////////////////// internal B32 @@ -1553,10 +1559,6 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } break; - case LNK_CmdSwitch_Rad_IdleWorkers: { - lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->idle_worker_count, 0); - } break; - case LNK_CmdSwitch_Rad_LargePages: { if (value_strings.node_count == 0) { OS_ProcessInfo *process_info = os_get_process_info(); @@ -1687,6 +1689,21 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } break; + case LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers: { + OS_SystemInfo *sysinfo = os_get_system_info(); + if (value_strings.node_count == 0) { + config->max_worker_count = sysinfo->logical_processor_count; + } else { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->max_worker_count, 0); + if (config->max_worker_count == 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "number of workers must be greater than zero"); + } else if (config->max_worker_count > sysinfo->logical_processor_count) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "number of workers %llu exceeds processor count %llu", config->max_worker_count, sysinfo->logical_processor_count); + config->max_worker_count = sysinfo->logical_processor_count; + } + } + } break; + case LNK_CmdSwitch_Rad_SuppressError: { U64List error_code_list = {0}; if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) { @@ -1761,7 +1778,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // parse command line String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line); LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); - + // setup default flags lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); @@ -1804,6 +1821,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "%u", LNK_Error_InvalidTypeIndex); #endif + // set default max worker count + if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool)) { + lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, ""); + } + if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_MtPath)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MtPath, "%s", LNK_MANIFEST_MERGE_TOOL_NAME); } @@ -1825,16 +1847,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_apply_cmd_option_to_config(arena, config, cmd->string, cmd->value_strings, str8_zero(), str8_zero()); } - // apply idle workers switch - if (config->idle_worker_count > 0) { - if (config->idle_worker_count < config->worker_count) { - U64 final_worker_count = config->worker_count - config->idle_worker_count; - config->worker_count = final_worker_count; - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count); - } - } - // :manifest_input if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) { if (config->manifest_opt == LNK_ManifestOpt_Embed) { @@ -1922,6 +1934,13 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) } } } + + if (lnk_is_thread_pool_shared(config)) { + if (config->worker_count > config->max_worker_count) { + config->worker_count = config->max_worker_count; + lnk_error_cmd_switch(LNK_Warning_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_Rad_Workers, "worker count %llu exceeds thread pool max worker count %llu; claping count to max", config->worker_count, config->max_worker_count); + } + } // set flags for /FIXED if (config->flags & LNK_ConfigFlag_Fixed) { diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 130d879b..8f0b0511 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -134,7 +134,6 @@ typedef enum LNK_CmdSwitch_Rad_EnvLib, LNK_CmdSwitch_Rad_Exe, LNK_CmdSwitch_Rad_Guid, - LNK_CmdSwitch_Rad_IdleWorkers, LNK_CmdSwitch_Rad_LargePages, LNK_CmdSwitch_Rad_LinkVer, LNK_CmdSwitch_Rad_Log, @@ -148,6 +147,7 @@ typedef enum LNK_CmdSwitch_Rad_PdbHashTypeNameLength, LNK_CmdSwitch_Rad_SectVirtOff, LNK_CmdSwitch_Rad_SharedThreadPool, + LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_SymbolTableCapDefined, LNK_CmdSwitch_Rad_SymbolTableCapInternal, @@ -312,7 +312,7 @@ typedef struct LNK_Config U64 page_size; U64 pdb_page_size; U64 worker_count; - U64 idle_worker_count; + U64 max_worker_count; String8 shared_thread_pool_name; U64 *function_pad_min; U64 *manifest_resource_id; @@ -510,15 +510,15 @@ internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string // Command Line Helpers internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...); -internal LNK_CmdOption * lnk_cmd_line_push_optionf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...); +internal LNK_CmdOption * lnk_cmd_line_push_optionf (Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...); internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type); //////////////////////////////// // Errors -internal void lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...); +internal void lnk_error_cmd_switch (LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...); internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch); -internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param); +internal void lnk_error_cmd_switch_invalid_param (LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param); //////////////////////////////// // Getters @@ -528,28 +528,29 @@ internal U64 lnk_get_base_addr(LNK_Config *config); internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine); internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine); -internal B32 lnk_do_debug_info(LNK_Config *config); +internal B32 lnk_do_debug_info (LNK_Config *config); +internal B32 lnk_is_thread_pool_shared(LNK_Config *config); //////////////////////////////// // Specialized Parsers -internal B32 lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out); -internal B32 lnk_cmd_switch_parse_tuple(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out); -internal B32 lnk_cmd_switch_parse_u64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_u32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out); +internal B32 lnk_cmd_switch_parse_version (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out); +internal B32 lnk_cmd_switch_parse_tuple (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out); +internal B32 lnk_cmd_switch_parse_u64 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_u32 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_flag (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out); internal void lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); internal void lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); -internal void lnk_cmd_switch_set_flag_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); -internal void lnk_cmd_switch_set_flag_32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits); -internal void lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); -internal B32 lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); +internal void lnk_cmd_switch_set_flag_16 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); +internal void lnk_cmd_switch_set_flag_32 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits); +internal void lnk_cmd_switch_set_flag_64 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); +internal B32 lnk_cmd_switch_parse_string (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); //////////////////////////////// internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat); -internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out); +internal B32 lnk_parse_alt_name_directive (Arena *arena, String8 input, LNK_AltNameList *list_out); internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out); internal LNK_ExportParse * lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path); @@ -562,5 +563,5 @@ internal B32 lnk_parse_merge_directive(String8 string, LNK_ internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, String8 obj_path, String8 lib_path); internal LNK_Config * lnk_config_from_raw_cmd_line(Arena *arena, String8List raw_cmd_line); -internal LNK_Config * lnk_build_config(Arena *arena, int argc, char **argv); +internal LNK_Config * lnk_build_config (Arena *arena, int argc, char **argv); diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index 26637119..434729d8 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -57,7 +57,7 @@ tp_worker_main_shared(void *raw_worker) } internal TP_Context * -tp_alloc(Arena *arena, U32 worker_count, String8 name) +tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name) { ProfBeginDynamic("Alloc Thread Pool [Worker Count: %u]", worker_count); AssertAlways(worker_count > 0); @@ -71,7 +71,8 @@ tp_alloc(Arena *arena, U32 worker_count, String8 name) if (worker_count > 1) { main_semaphore = os_semaphore_alloc(0, 1, str8_zero()); if (is_shared) { - task_semaphore = os_semaphore_alloc(0, worker_count, name); + AssertAlways(worker_count <= max_worker_count); + task_semaphore = os_semaphore_alloc(0, max_worker_count, name); exec_semaphore = os_semaphore_alloc(0, worker_count, str8_zero()); } else { task_semaphore = os_semaphore_alloc(0, worker_count, str8_zero()); diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index 78aef33b..e37f903c 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -43,7 +43,7 @@ typedef struct TP_Context S64 task_left; } TP_Context; -internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, String8 name); +internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name); internal void tp_release(TP_Context *pool); internal TP_Arena * tp_arena_alloc(TP_Context *pool); internal void tp_arena_release(TP_Arena **arena_ptr); From 0ca9d9775090cd5583478940e7b3c12e9a199a65 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 24 Jan 2025 14:40:16 -0800 Subject: [PATCH 46/53] error out on /LIB and /DUMP switches --- src/linker/lnk_config.c | 10 ++++++++++ src/linker/lnk_config.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 28d2d329..7d123f23 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -29,6 +29,7 @@ global read_only struct { LNK_CmdSwitch_NotImplemented, "CLRTHREADATTRIBUTE", "", "" }, // .NET { LNK_CmdSwitch_NotImplemented, "CLRUNMANAGEDCODECHECK","", "" }, // .NET { LNK_CmdSwitch_Debug, "DEBUG", "[:{FULL|NONE}]", "" }, + { LNK_CmdSwitch_Dump, "DUMP", "", "" }, { LNK_CmdSwitch_NotImplemented, "DEF", ":FILENAME", "" }, { LNK_CmdSwitch_DefaultLib, "DEFAULTLIB", ":LIBNAME", "" }, { LNK_CmdSwitch_Delay, "DELAY", ":{NOBIND|UNLOAD}", "" }, @@ -71,6 +72,7 @@ global read_only struct { LNK_CmdSwitch_NotImplemented, "KEYCONTAINER", "", "" }, { LNK_CmdSwitch_NotImplemented, "KEYFILE", "", "" }, { LNK_CmdSwitch_LargeAddressAware, "LARGEADDRESSAWARE", "[:NO]", "" }, + { LNK_CmdSwitch_Lib, "LIB", "" }, { LNK_CmdSwitch_LibPath, "LIBPATH", ":DIR", "" }, { LNK_CmdSwitch_NotImplemented, "LINKERREPO", "", "" }, { LNK_CmdSwitch_NotImplemented, "LINKERREPOTARGET", "", "" }, @@ -1080,6 +1082,10 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_DYNAMIC_BASE); } break; + case LNK_CmdSwitch_Dump: { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unsupported switch; binary dump is done by passing /DUMP to link.exe"); + } break; + case LNK_CmdSwitch_Entry: { String8 new_entry_point_name = {0}; lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &new_entry_point_name); @@ -1189,6 +1195,10 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); } break; + case LNK_CmdSwitch_Lib: { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unsupported switch; static library is created by passing /LIB to link.exe"); + } break; + case LNK_CmdSwitch_LibPath: { String8List lib_dir_list = str8_list_copy(arena, &value_strings); for (String8Node *dir_n = lib_dir_list.first; dir_n != 0; dir_n = dir_n->next) { diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 8f0b0511..871e9662 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -20,6 +20,7 @@ typedef enum LNK_CmdSwitch_DelayLoad, LNK_CmdSwitch_Dll, LNK_CmdSwitch_DynamicBase, + LNK_CmdSwitch_Dump, LNK_CmdSwitch_Entry, LNK_CmdSwitch_Export, LNK_CmdSwitch_FastFail, @@ -33,6 +34,7 @@ typedef enum LNK_CmdSwitch_Include, LNK_CmdSwitch_Incremental, LNK_CmdSwitch_LargeAddressAware, + LNK_CmdSwitch_Lib, LNK_CmdSwitch_LibPath, LNK_CmdSwitch_Machine, LNK_CmdSwitch_Manifest, From 409905c983106e874b94651ce1b15a2e45c96d1a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 25 Jan 2025 11:33:44 -0800 Subject: [PATCH 47/53] yank out shared mutex impl Initially shared mutex was needed to lock cores so thread pool executes one parallel for at a time but on machine with high core count we cant saturate processor all the time so we switched to shared semaphore and block thread when all cores are busy. --- src/os/core/linux/os_core_linux.c | 26 ----------------------- src/os/core/os_core.h | 6 ------ src/os/core/win32/os_core_win32.c | 34 ------------------------------- 3 files changed, 66 deletions(-) diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 31d2b252..3b2c73b1 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -861,32 +861,6 @@ os_mutex_drop(OS_Handle mutex) pthread_mutex_unlock(&entity->mutex_handle); } -internal OS_Handle -os_shared_mutex_alloc(String8 name) -{ - NotImplemented; - OS_Handle handle = {0}; - return handle; -} - -internal void -os_shared_mutex_release(OS_Handle mutex) -{ - NotImplemented; -} - -internal B32 -os_shared_mutex_take(OS_Handle mutex, U64 endt_us) -{ - NotImplemented; -} - -internal void -os_shared_mutex_drop(OS_Handle mutex) -{ - NotImplemented; -} - //- rjf: reader/writer mutexes internal OS_Handle diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 867120ef..5f09ca8b 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -277,12 +277,6 @@ internal void os_rw_mutex_drop_r(OS_Handle mutex); internal void os_rw_mutex_take_w(OS_Handle mutex); internal void os_rw_mutex_drop_w(OS_Handle mutex); -//- shared mutex -internal OS_Handle os_shared_mutex_alloc(String8 name); -internal void os_shared_mutex_release(OS_Handle mutex); -internal B32 os_shared_mutex_take(OS_Handle mutex, U64 endt_us); -internal void os_shared_mutex_drop(OS_Handle mutex); - //- rjf: condition variables internal OS_Handle os_condition_variable_alloc(void); internal void os_condition_variable_release(OS_Handle cv); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index e97a203d..6a0e0281 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1106,40 +1106,6 @@ os_mutex_drop(OS_Handle mutex) LeaveCriticalSection(&entity->mutex); } -internal OS_Handle -os_shared_mutex_alloc(String8 name) -{ - Assert(name.size); - Temp scratch = scratch_begin(0,0); - String16 name16 = str16_from_8(scratch.arena, name); - HANDLE handle = CreateMutexW(0, 0, (WCHAR*)name16.str); - Assert(handle != 0); - OS_Handle mutex = {(U64)handle}; - scratch_end(scratch); - return mutex; -} - -internal void -os_shared_mutex_release(OS_Handle mutex) -{ - CloseHandle((HANDLE)mutex.u64[0]); -} - -internal B32 -os_shared_mutex_take(OS_Handle mutex, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - DWORD wait_result = WaitForSingleObject((HANDLE)mutex.u64[0], sleep_ms); - B32 result = (wait_result == WAIT_OBJECT_0); - return result; -} - -internal void -os_shared_mutex_drop(OS_Handle mutex) -{ - ReleaseMutex((HANDLE)mutex.u64[0]); -} - //- rjf: reader/writer mutexes internal OS_Handle From 5e3b500119a3d67297b452c4cc47095ec4e756e5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 28 Jan 2025 16:46:50 -0800 Subject: [PATCH 48/53] put ranges on arena --- src/linker/codeview_ext/codeview.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index a2c4df0a..f09ff50f 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1992,7 +1992,7 @@ cv_c13_parse_inline_binary_annots(Arena *arena, break; } if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) { - rng1u64_list_push(scratch.arena, &code_ranges, step.range); + rng1u64_list_push(arena, &code_ranges, step.range); } if (step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) { if (code_ranges.last) { From bd5d38ef0cee7faaa7f5ecefe1f8acd87f7b0f13 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 28 Jan 2025 16:56:12 -0800 Subject: [PATCH 49/53] handle null write --- src/linker/lnk_io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/linker/lnk_io.c b/src/linker/lnk_io.c index 377d500e..8969cd50 100644 --- a/src/linker/lnk_io.c +++ b/src/linker/lnk_io.c @@ -173,7 +173,8 @@ lnk_write_data_list_to_file_path(String8 path, String8List data) if (lnk_open_file_write((char*)path.str, path.size, &handle, sizeof(handle))) { U64 offset = 0; for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) { - if (!lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size)) { + U64 write_size = lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size); + if (write_size != data_n->string.size) { break; } offset += data_n->string.size; From 497f0e45d61b109e53722862cdad1f4ba8148c0c Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 29 Jan 2025 10:47:18 -0800 Subject: [PATCH 50/53] WIP merging RDI dump into RAD Dumper --- src/raddump/raddump.c | 689 +++++++++++++++++++++++++++++++++++++ src/raddump/raddump.h | 50 +++ src/raddump/raddump_main.c | 78 +++-- 3 files changed, 789 insertions(+), 28 deletions(-) diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 212eb6ce..b27a70cc 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -222,6 +222,55 @@ rd_is_pe(String8 raw_data) return header.magic == PE_DOS_MAGIC; } +internal String8 +rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags) +{ + String8 result; + if (list.node_count == 0 && remaining_flags == 0) { + result = str8_lit("0"); + } else { + Temp scratch = scratch_begin(&arena, 1); + if (remaining_flags != 0) { + str8_list_pushf(scratch.arena, &list, "Unknown flags: %#llx", remaining_flags); + } + result = str8_list_join(arena, &list, &(StringJoin){.sep = str8_lit(" ") }); + scratch_end(scratch); + } + return result; +} + +internal String8 +rd_string_from_array_hex_u32(Arena *arena, U32 *v, U64 count) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + for (U64 i = 0; i < count; ++i) { + str8_list_pushf(scratch.arena, &list, "%#x", v[i]); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +rd_string_from_array_hex_u64(Arena *arena, U64 *v, U64 count) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + for (U64 i = 0; i < count; ++i) { + str8_list_pushf(scratch.arena, &list, "%#llx", v[i]); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + +internal String8 +rd_string_from_range_array_u64_hex(Arena *arena, U64 *v, U64 count) +{ + NotImplemented; +} + internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) { @@ -599,6 +648,646 @@ rd_print_raw_data(Arena *arena, } } +internal String8 +str8_from_rdi_string_idx(RDI_Parsed *rdi, U32 idx) +{ + String8 result = str8_zero(); + result.str = rdi_string_from_idx(rdi, idx, &result.size); + return result; +} + +internal String8 +rdi_string_from_data_section_kind(Arena *arena, RDI_SectionKind v) +{ + String8 result; + switch (v) { + default: result = push_str8f(arena, "", v); break; +#define X(name, lower, type) case RDI_SectionKind_##name:{result = str8_lit(#name);} break; + RDI_SectionKind_XList +#undef X + } + return result; +} + +internal String8 +rdi_string_from_arch(Arena *arena, RDI_Arch v) +{ + String8 result; + switch (v) { + default:{ result = push_str8f(arena, "", v); } break; +#define X(name) case RDI_MemberKind_##name: { result = str8_lit(#name); } break; + RDI_MemberKind_XList +#undef X + } + return result; +} + +internal String8 +rdi_string_from_reg_code_x86(U64 reg_code) +{ +#define X(name, value) case RDI_RegCodeX86_##name: return str8_lit(#name); + switch (reg_code) { + RDI_RegCodeX86_XList + } +#undef X + return str8_lit(""); +} + +internal String8 +rdi_string_from_reg_code_x64(U64 reg_code) +{ +#define X(name, value) case RDI_RegCodeX64_##name: return str8_lit(#name); + switch (reg_code) { + RDI_RegCodeX64_XList + } +#undef X + return str8_lit(""); +} + +internal String8 +rdi_string_from_reg_code(Arena *arena, RDI_Arch arch, U64 reg_code) +{ + switch (arch) { + case RDI_Arch_NULL: break; + case RDI_Arch_X86: return rdi_string_from_reg_code_x86(reg_code); + case RDI_Arch_X64: return rdi_string_from_reg_code_x64(reg_code); + default: InvalidPath; + } + return push_str8f(arena, "??? (%llu)", reg_code); +} + +internal String8 +rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; +#define X(name) if (flags & RDI_BinarySectionFlag_##name) { flags &= ~RDI_BinarySectionFlag_##name; str8_list_push(scratch.arena, &list, str8_lit(#name)); } + RDI_BinarySectionFlags_XList; +#undef X + String8 result = rd_string_from_flags(arena, list, flags); + scratch_end(scratch); + return result; +} + +internal String8 +rdi_string_from_type_modifier_flags(Arena *arena, RDI_TypeModifierFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; +#define X(name) if(flags & RDI_TypeModifierFlag_##name) { flags &= ~RDI_TypeModifierFlag_##name; str8_list_push(scratch.arena, &list, str8_lit(#name)); } + RDI_TypeModifierFlags_XList; +#undef X + String8 result = rd_string_from_flags(arena, list, flags); + scratch_end(scratch); + return result; +} + +internal String8 +rdi_string_from_udt_flags(Arena *arena, RDI_UDTFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; +#define X(name) if (flags & RDI_UDTFlag_##name) { flags &= ~RDI_UDTFlag_##name; str8_list_push(scratch.arena, &list, str8_lit(#name)); } + RDI_UDTFlags_XList; +#undef X + String8 result = rd_string_from_flags(arena, list, flags); + scratch_end(scratch); +} + +internal String8 +rdi_string_from_link_flags(Arena *arena, RDI_LinkFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; +#define X(name) if (flags & RDI_LinkFlag_##name) { flags &= ~RDI_LinkFlag_##name; str8_list_push(scratch.arena, &list, str8_lit(#name)); } + RDI_LinkFlags_XList; +#undef X + String8 result = rd_string_from_flags(arena, list, flags); + scratch_end(scratch); + return result; +} + +internal void +rdi_print_data_sections(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi) +{ + Temp scratch = scratch_begin(&arena, 1); + for(U64 idx = 0; idx < rdi->sections_count; idx += 1) { + RDI_SectionKind kind = (RDI_SectionKind)idx; + RDI_Section *section = &rdi->sections[idx]; + String8 kind_str = rdi_string_from_data_section_kind(scratch.arena, kind); + rd_printf("data_section[%5llu] = {%#08llx, %7u, %7u}, %S", idx, section->off, section->encoded_size, section->unpacked_size, kind_str); + } + scratch_end(scratch); +} + +internal void +rdi_print_top_level_info(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TopLevelInfo *tli) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("arch =%S", rdi_string_from_arch(scratch.arena, tli->arch)); + rd_printf("exe_name ='%S'", str8_from_rdi_string_idx(rdi, tli->exe_name_string_idx)); + rd_printf("voff_max =%#08llx", tli->voff_max); + rd_printf("producer_name='%S'", str8_from_rdi_string_idx(rdi, tli->producer_name_string_idx)); + scratch_end(scratch); +} + +internal void +rdi_print_binary_section(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_BinarySection *bin_section) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("name ='%S'", str8_from_idx(rdi, bin_section->name_string_idx)); + rd_printf("flags =%S", rdi_string_from_binary_section_flags(scratch.arena, bin_section->flags)); + rd_printf("voff_first=%#08x", bin_section->voff_first); + rd_printf("voff_opl =%#08x", bin_section->voff_opl); + rd_printf("foff_first=%#08x", bin_section->foff_first); + rd_printf("foff_opl =%#08x", bin_section->foff_opl); + scratch_end(scratch); +} + +internal void +rdi_print_file_path(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_FilePathNode *file_path) +{ + U64 file_path_count = 0; + RDI_FilePathNode *file_path_array = rdi_table_from_name(rdi, FilePathNodes, &file_path_count); + + String8 name = str8_from_rdi_string_idx(rdi, file_path->name_string_idx); + U64 this_idx = (U64)(file_path - file_path_array); + + if (file_path->source_file_idx == 0) { + rd_printf("[%llu] '%S'", this_idx, name); + } else { + rd_printf("[%llu] '%S'; source_file=%u", this_idx, name, file_path->source_file_idx); + } + + for (U32 child = file_path->first_child; child != 0; ) { + // get node for child + RDI_FilePathNode *child_node = 0; + if (child < file_path_count) { + child_node = file_path_array + child; + } + if (child_node == 0) { + break; + } + + // stringize child + rd_indent(); + rdi_stringize_file_path(arena, out, indent, rdi, child_node); + rd_unindent(); + + // increment iterator + child = child_node->next_sibling; + } +} + +internal void +rdi_print_source_file(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceFile *source_file) +{ + rd_printf("file_path_node_idx= %u", source_file->file_path_node_idx); + rd_printf("path= 'S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)); + rd_printf("source_line_map= %u", source_file->source_line_map_idx); +} + +internal void +rdi_print_line_table(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_LineTable *line_table) +{ + RDI_ParsedLineTable parsed_line_table = {0}; + rdi_parsed_from_line_table(rdi, line_table, &parsed_line_table); + + rd_printf("lines:"); + for (U32 i = 0; i < parsed_line_table.count; i += 1) { + U64 first = parsed_line_table.voffs[i]; + U64 opl = parsed_line_table.voffs[i + 1]; + RDI_Line *line = parsed_line_table.lines + i; + RDI_Column *col = 0; + if (i < parsed_line_table.col_count) { + col = parsed_line_table.cols + i; + } + if (col == 0) { + rd_printf("[0x%08llx,0x%08llx) file=%u; line=%u", first, opl, line->file_idx, line->line_num); + } else { + rd_printf("[0x%08llx,0x%08llx) file=%u; line=%u; columns=[%u,%u)", first, opl, line->file_idx, line->line_num, col->col_first, col->col_opl); + } + } +} + +internal void +rdi_print_source_line_map(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceLineMap *map) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDI_ParsedSourceLineMap line_map = {0}; + rdi_parsed_from_source_line_map(rdi, map, &line_map); + + rd_printf("source lines:"); + for (U32 line_num_idx = 0; line_num_idx < line_map.count; ++line_num_idx) { + Temp temp = temp_begin(scratch.arena); + + String8List list = {0}; + U32 voff_lo = line_map.ranges[line_num_idx]; + U32 voff_hi = ClampTop(line_map.ranges[line_num_idx + 1], line_map.voff_count); + for (U64 voff_idx = voff_lo; voff_idx < voff_hi; ++voff_idx) { + str8_list_pushf(temp.arena, &list, "%#llx", line_map.voffs[voff_idx]); + } + + String8 voffs = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + rd_printf("%u: %S", line_map.nums[line_num_idx], voffs); + + temp_end(temp); + } + + scratch_end(scratch); +} + +internal void +rdi_print_unit(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Unit *unit) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("unit_name ='%S'", str8_from_rdi_string_idx(rdi, unit->unit_name_string_idx)); + rd_printf("compiler_name ='%S'", str8_from_rdi_string_idx(rdi, unit->compiler_name_string_idx)); + rd_printf("source_file_path =%u", unit->source_file_path_node); + rd_printf("object_file_path =%u", unit->object_file_path_node); + rd_printf("archive_file_path=%u", unit->archive_file_path_node); + rd_printf("build_path =%u", unit->build_path_node); + rd_printf("language =%S", rdi_string_from_language(scratch.arena, unit->language)); + rd_printf("line_table_idx =%u", unit->line_table_idx); + scratch_end(scratch); +} + +internal void +rdi_print_type_node(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TypeNode *type) +{ + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("kind =%S", rdi_string_from_type_kind(scratch.arena, type->kind)); + if (type->kind == RDI_TypeKind_Modifier) { + rd_printf("flags =%S", rdi_string_from_type_modifier_flags(scratch.arena, type->flags)); + } else { + if (type->flags != 0) { + rd_printf("flags=%#x (missing stringizer path)", type->flags); + } + } + rd_printf("byte_size =%u", type->byte_size); + if (RDI_TypeKind_FirstBuiltIn <= type->kind && type->kind <= RDI_TypeKind_LastBuiltIn) { + rd_printf("built_in.name ='%S'", str8_from_rdi_string_idx(rdi, type->built_in.name_string_idx)); + } else if (type->kind == RDI_TypeKind_Array) { + rd_printf("constructed.direct_type =%u", type->constructed.direct_type_idx); + rd_printf("constructed.array_count =%u", type->constructed.count); + } else if (type->kind == RDI_TypeKind_Function) { + U32 param_idx_count = 0; + U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); + String8 param_idx_str = rd_string_from_array_hex_u32(scratch.arena, param_idx_array, param_idx_count); + rd_printf("constructed.params =%S", param_idx_str); + } else if (type->kind == RDI_TypeKind_Method) { + U32 param_idx_count = 0; + U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); + String8 this_type_str = str8_lit("???"); + if (param_idx_count > 0) { + this_type_str = push_str8f(scratch.arena, "%u", param_idx_array[0]); + param_idx_count -= 1; + param_idx_array += 1; + } + String8 param_idx_str = rd_string_from_array_hex_u32(scratch.arena, param_idx_array, param_idx_count); + rd_printf("constructed.this_type =%S", this_type_str); + rd_printf("constructed.params =%S", param_idx_str); + } else if (RDI_TypeKind_FirstConstructed <= type->kind && type->kind <= RDI_TypeKind_LastConstructed) { + + rd_printf("constructed.direct_type =%u", type->constructed.direct_type_idx); + } else if (RDI_TypeKind_FirstUserDefined <= type->kind && type->kind <= RDI_TypeKind_LastUserDefined){ + rd_printf("user_defined.name ='%S'", str8_from_rdi_string_idx(rdi, type->user_defined.name_string_idx)); + rd_printf("user_defined.direct_type=%u", type->user_defined.direct_type_idx); + rd_printf("user_defined.udt =%u", type->user_defined.udt_idx); + } else if (type->kind == RDI_TypeKind_Bitfield) { + rd_printf("bitfield.off =%u", type->bitfield.off); + rd_printf("bitfield.size =%u", type->bitfield.size); + } + + scratch_end(scratch); +} + +internal void +rdi_print_udt(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_UDT *udt) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 member_count = 0; + U64 enum_member_count = 0; + RDI_Member *member_array = rdi_table_from_name(rdi, Members, &member_count); + RDI_EnumMember *enum_member_array = rdi_table_from_name(rdi, EnumMembers, &enum_member_count); + + String8 flags_str = rdi_string_from_udt_flags(scratch.arena, udt->flags); + + rd_printf("self_type=%u", udt->self_type_idx); + rd_printf("flags =%S", flags_str); + if (udt->file_idx != 0) { + rd_printf("loc ={file=%u; line=%u; col=%u}", udt->file_idx, udt->line, udt->col); + } + + // enum members + if (udt->flags & RDI_UDTFlag_EnumMembers) { + U32 member_hi = ClampTop(udt->member_first + udt->member_count, enum_member_count); + U32 member_lo = ClampTop(udt->member_first, member_hi); + if (member_lo < member_hi) { + rd_printf("members={"); + rd_indent(); + RDI_EnumMember *enum_member = enum_member_array + member_lo; + for (U32 i = member_lo; i < member_hi; ++i, ++enum_member) { + rd_printf("'%S' %llu", str8_from_rdi_string_idx(rdi, enum_member->name_string_idx), enum_member->val); + } + rd_unindent(); + rd_printf("}"); + } + } + // field members + else { + U32 member_hi = ClampTop(udt->member_first + udt->member_count, member_count); + U32 member_lo = ClampTop(udt->member_first, member_hi); + if (member_lo < member_hi) { + rd_printf("members={"); + rd_indent(); + RDI_Member *member = member_array + member_lo; + for (U32 i = member_lo; i < member_hi; ++i, ++member) { + String8 kind_str = rdi_string_from_member_kind(scratch.arena, member->kind); + String8 name_str = str8_from_rdi_string_idx(rdi, member->name_string_idx); + rd_printf("{ kind=%S, name='%S', type=%u, off=%u }", kind_str, name_str, member->type_idx, member->off); + } + rd_unindent(); + rd_printf("}"); + } + } + scratch_end(scratch); +} + +internal void +rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, gvar->name_string_idx)); + rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, gvar->link_flags)); + rd_printf("voff =%#08x", gvar->voff); + rd_printf("type_idx =%u", gvar->type_idx); + rd_printf("container_idx=%u", gvar->container_idx); + scratch_end(scratch); +} + +internal void +rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_ThreadVariable *tvar) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, tvar->name_string_idx)); + rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, tvar->link_flags)); + rd_printf("tls_off =%#08x", tvar->tls_off); + rd_printf("type_idx =%u", tvar->type_idx); + rd_printf("container_idx=%u", tvar->container_idx); + scratch_end(scratch); +} + +internal void +rdi_print_procedure(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc) +{ + Temp scratch = scratch_begin(&arena, 1); + rd_printf("name ='%S'", str8_from_rdi_string(scratch.arena, rdi, proc->name_string_idx)); + rd_printf("link_name ='%S'", str8_from_rdi_string(scratch.arena, rdi, proc->link_name_string_idx)); + rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, proc->link_flags)); + rd_printf("type_idx =%u", proc->type_idx); + rd_printf("root_scope_idx=%u", proc->root_scope_idx); + rd_printf("container_idx =%u", proc->container_idx); + scratch_end(scratch); +} + +internal void +rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Scope *scope, RDI_Arch arch) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 scope_count = 0; + U64 scope_voff_count = 0; + U64 local_count = 0; + U64 location_block_count = 0; + U64 location_data_size = 0; + RDI_Scope *scope_array = rdi_table_from_name(rdi, Scopes, &scope_count); + U64 *scope_voff_array = rdi_table_from_name(rdi, ScopeVOffData, &scope_voff_count); + RDI_Local *local_array = rdi_table_from_name(rdi, Locals, &local_count); + RDI_LocationBlock *location_block_array = rdi_table_from_name(rdi, LocationBlocks, &location_block_count); + RDI_U8 *location_data = rdi_table_from_name(rdi, LocationData, &location_data_size); + + U32 voff_range_lo = ClampTop(scope->voff_range_first, scope_voff_count); + U32 voff_range_hi = ClampTop(scope->voff_range_opl, scope_voff_count); + U32 voff_range_count = (voff_range_hi - voff_range_lo) / 2; + U64 *voff_ptr = scope_voff_array + voff_range_lo; + String8 voff_str = rd_string_from_range_array_u64_hex(scratch.arena, voff_ptr, voff_range_count); + + U64 this_idx = (U64)(scope - scope_array); + rd_printf("[%llu]", this_idx); + rd_indent(); + + rd_printf("proc_idx =%u", scope->proc_idx); + rd_printf("inline_site_idx=%u", scope->inline_site_idx); + rd_printf("voff_ranges =%S", voff_str); + + // local_array + { + U32 local_lo = ClampTop(scope->local_first, local_count); + U32 local_hi = ClampTop(local_lo + scope->local_count, local_count); + if (local_lo < local_hi) { + for (U32 local_idx = local_lo; local_idx < local_hi; ++local_idx) { + RDI_Local *local_ptr = &local_array[local_idx]; + + rd_printf("local[%u]", local_idx); + rd_indent(); + rd_printf("kind =%S", rdi_string_from_local_kind(local_ptr->kind)); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, local_ptr->name_string_idx)); + rd_printf("type_idx=%u", local_ptr->type_idx); + + U32 block_lo = ClampTop(local_ptr->location_first, location_block_count); + U32 block_hi = ClampTop(local_ptr->location_opl, location_block_count); + if (block_lo < block_hi) { + rd_printf("locations:"); + rd_indent(); + for (U32 block_idx = block_lo; block_idx < block_hi; ++block_idx) { + RDI_LocationBlock *block_ptr = &location_block_array[block_idx]; + + if (block_ptr->scope_off_first == 0 && block_ptr->scope_off_opl == max_U32) { + rd_printf("case *always*:"); + } else { + rd_printf("case [%#08x, %#08x):", block_ptr->scope_off_first, block_ptr->scope_off_opl); + } + + if (block_ptr->location_data_off >= location_data_size) { + rd_printf("", block_ptr->location_data_off); + } else { + U8 *loc_data_opl = location_data + location_data_size; + U8 *loc_base_ptr = location_data + block_ptr->location_data_off; + RDI_LocationKind kind = *(RDI_LocationKind*)loc_base_ptr; + switch (kind) { + default: { + rd_printf("???: %u", kind); + } break; + + case RDI_LocationKind_AddrBytecodeStream: { + Temp temp = temp_begin(scratch.arena); + String8 raw_bytes = str8_cstring_capped(loc_base_ptr + 1, loc_data_opl); + rd_printf("AddrBytecodeStream: %S", rd_format_hex_array(temp.arena, raw_bytes.str, raw_bytes.size)); + temp_end(temp); + } break; + + case RDI_LocationKind_ValBytecodeStream: { + Temp temp = temp_begin(scratch.arena); + String8 raw_bytes = str8_cstring_capped(loc_base_ptr + 1, loc_data_opl); + rd_printf("ValBytecodeStream: %S", rd_format_hex_array(temp.arena, raw_bytes.str, raw_bytes.size)); + temp_end(temp); + } break; + + case RDI_LocationKind_AddrRegPlusU16: { + if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl) { + rd_errorf("AddrRegPlusU16(???)"); + } else { + RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; + rd_printf("AddrRegPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); + } + } break; + + case RDI_LocationKind_AddrAddrRegPlusU16: { + if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ + rd_errorf("AddrAddrRegPlusU16(???"); + } else { + RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16 *)loc_base_ptr; + rd_printf("AddrAddrRegisterPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); + } + } break; + + case RDI_LocationKind_ValReg: { + if (loc_base_ptr + sizeof(RDI_LocationReg) > loc_data_opl) { + rd_errorf("ValReg(???)"); + } else { + RDI_LocationReg *loc = (RDI_LocationReg*)loc_base_ptr; + str8_list_pushf(arena, out, "ValReg(reg: %S)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code)); + } + } break; + } + } + } + rd_unindent(); + } + rd_unindent(); + } + } + } + + for (U32 child_scope_idx = scope->first_child_scope_idx; child_scope_idx != 0; ) { + if (child_scope_idx >= scope_count) { + rd_errorf("child scope index (%u) is out of bounds", child_scope_idx); + break; + } + + rd_indent(); + RDI_Scope *child_scope = scope_array + child_scope_idx; + rdi_print_scope(arena, out, indent, rdi, child_scope, arch); + rd_unindent(); + + // advance to next child + child_scope_idx = child_scope->next_sibling_scope_idx; + } + + rd_printf("[/%llu]", this_idx); + rd_unindent(); + + scratch_end(scratch); +} + +internal void +rdi_print_inline_site(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site) +{ + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, inline_site->name_string_idx)); + rd_printf("type_idx =%u", inline_site->type_idx); + rd_printf("owner_type_idx=%u", inline_site->owner_type_idx); + rd_printf("line_table_idx=%u", inline_site->line_table_idx); +} + +internal void +rdi_print(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RD_Option opts) +{ + if (opts & RD_Option_RdiDataSections) { + NotImplemented; + } + if (opts & RD_Option_RdiTopLevelInfo) { + NotImplemented; + } + if (opts & RD_Option_RdiBinarySections) { + NotImplemented; + } + if (opts & RD_Option_RdiFilePaths) { + NotImplemented; + } + if (opts & RD_Option_RdiSourceFiles) { + NotImplemented; + } + if (opts & RD_Option_RdiLineTables) { + NotImplemented; + } + if (opts & RD_Option_RdiSourceLineMaps) { + NotImplemented; + } + if (opts & RD_Option_RdiUnits) { + NotImplemented; + } + if (opts & RD_Option_RdiUnitVMap) { + NotImplemented; + } + if (opts & RD_Option_RdiTypeNodes) { + NotImplemented; + } + if (opts & RD_Option_RdiUserDefinedTypes) { + NotImplemented; + } + if (opts & RD_Option_RdiGlobalVars) { + NotImplemented; + } + if (opts & RD_Option_RdiThreadVars) { + NotImplemented; + } + if (opts & RD_Option_RdiScopes) { + NotImplemented; + } + if (opts & RD_Option_RdiScopeVMap) { + NotImplemented; + } + if (opts & RD_Option_RdiInlineSites) { + NotImplemented; + } + if (opts & RD_Option_RdiNameMaps) { + NotImplemented; + } + if (opts & RD_Option_RdiStrings) { + NotImplemented; + } +} + internal String8List dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) { diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index 29529060..46fbd97d 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -66,6 +66,25 @@ typedef U64 RD_Option; #define RD_Option_RelaxDwarfParser (1ull << 31ull) // RDI #define RD_Option_NoRdi (1ull << 32ull) +#define RD_Option_RdiDataSections (1ull << 33ull) +#define RD_Option_RdiTopLevelInfo (1ull << 34ull) +#define RD_Option_RdiBinarySections (1ull << 35ull) +#define RD_Option_RdiFilePaths (1ull << 36ull) +#define RD_Option_RdiSourceFiles (1ull << 37ull) +#define RD_Option_RdiLineTables (1ull << 38ull) +#define RD_Option_RdiSourceLineMaps (1ull << 39ull) +#define RD_Option_RdiUnits (1ull << 40ull) +#define RD_Option_RdiUnitVMap (1ull << 41ull) +#define RD_Option_RdiTypeNodes (1ull << 42ull) +#define RD_Option_RdiUserDefinedTypes (1ull << 43ull) +#define RD_Option_RdiGlobalVars (1ull << 44ull) +#define RD_Option_RdiThreadVars (1ull << 45ull) +#define RD_Option_RdiProcedures (1ull << 46ull) +#define RD_Option_RdiScopes (1ull << 47ull) +#define RD_Option_RdiScopeVMap (1ull << 48ull) +#define RD_Option_RdiInlineSites (1ull << 49ull) +#define RD_Option_RdiNameMaps (1ull << 50ull) +#define RD_Option_RdiStrings (1ull << 51ull) typedef struct RD_Marker { @@ -122,6 +141,8 @@ typedef struct RD_Line internal B32 rd_is_pe(String8 raw_data); +internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags); + internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); // Markers @@ -142,6 +163,35 @@ internal void rd_print_disasm (Arena *arena, String8List *o internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); +// +// RDI +// + +internal String8 rdi_string_from_data_section_kind(Arena *arena, RDI_SectionKind v); +internal String8 rdi_string_from_arch (Arena *arena, RDI_Arch v); +internal String8 rdi_string_from_language (Arena *arena, RDI_Language v); +internal String8 rdi_string_from_member_kind (Arena *arena, RDI_MemberKind v); + +internal String8 rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags); +internal String8 rdi_string_from_type_modifier (Arena *arena, RDI_TypeModifierFlags flags); +internal String8 rdi_string_from_udt_flags (Arena *arena, RDI_UDTFlags flags); +internal String8 rdi_string_from_link_flags (Arena *arena, RDI_LinkFlags flags); + +internal void rdi_print_data_sections (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi); +internal void rdi_print_top_level_info (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TopLevelInfo *tli); +internal void rdi_print_binary_section (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_BinarySection *bin_section); +internal void rdi_print_file_path (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_FilePathNode *file_path); +internal void rdi_print_source_file (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceFile *source_file); +internal void rdi_print_line_table (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_LineTable *line_table); +internal void rdi_print_source_line_map(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceLineMap *map); +internal void rdi_print_unit (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Unit *unit); +internal void rdi_print_type_node (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TypeNode *type); +internal void rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar); +internal void rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_ThreadVariable *tvar); +internal void rdi_print_procedure (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc); +internal void rdi_print_scope (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Scope *scope, RDI_Arch arch); +internal void rdi_print_inline_site (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site); + // DWARF internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index ea19187d..c4268ea6 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -94,8 +94,11 @@ global read_only struct char *name; char *help; } g_rd_dump_option_map[] = { - { RD_Option_Help, "help", "Print help and exit" }, - { RD_Option_Version, "version", "Print version and exit" }, + { RD_Option_Help, "help", "Print help and exit" }, + { RD_Option_Version, "version", "Print version and exit" }, + + { RD_Option_NoRdi, "nordi", "Don't load RAD Debug Info" }, + { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, { RD_Option_Sections, "sections", "Dump section headers as table" }, { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, @@ -111,33 +114,52 @@ global read_only struct { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, { RD_Option_Resources, "resources", "Dump resource directory" }, { RD_Option_LongNames, "longnames", "Dump archive long names" }, - { RD_Option_DebugInfo, "debug_info", "Dump .debug_info" }, - { RD_Option_DebugAbbrev, "debug_abbrev", "Dump .debug_abbrev" }, - { RD_Option_DebugLine, "debug_line", "Dump .debug_line" }, - { RD_Option_DebugStr, "debug_str", "Dump .debug_str" }, - { RD_Option_DebugLoc, "debug_loc", "Dump .debug_loc" }, - { RD_Option_DebugRanges, "debug_ranges", "Dump .debug_ranges" }, - { RD_Option_DebugARanges, "debug_aranges", "Dump .debug_aranges" }, - { RD_Option_DebugAddr, "debug_addr", "Dump .debug_addr" }, - { RD_Option_DebugLocLists, "debug_loclists", "Dump .debug_loclists" }, - { RD_Option_DebugRngLists, "debug_rnglists", "Dump .debug_rnglists" }, - { RD_Option_DebugPubNames, "debug_pubnames", "Dump .debug_pubnames" }, - { RD_Option_DebugPubTypes, "debug_pubtypes", "Dump .debug_putypes" }, - { RD_Option_DebugLineStr, "debug_linestr", "Dump .debug_linestr" }, - { RD_Option_DebugStrOffsets, "debug_stroffsets", "Dump .debug_stroffsets" }, - { RD_Option_Dwarf, "dwarf", "Dump all DWARF sections" }, - { RD_Option_RelaxDwarfParser, "relax_dwarf_parser", "Relaxes version requirement on attribute and form encodings" }, - { RD_Option_NoRdi, "nordi", "Don't load RAD Debug Info" }, - { RD_Option_Help, "h", "Alias for -help" }, - { RD_Option_Version, "v", "Alias for -version" }, - { RD_Option_Sections, "s", "Alias for -sections" }, - { RD_Option_Exceptions, "e", "Alias for -exceptions" }, - { RD_Option_Imports, "i", "Alias for -imports" }, - { RD_Option_Exports, "x", "Alias for -exports" }, - { RD_Option_LoadConfig, "l", "Alias for -loadconifg" }, - { RD_Option_Resources, "c", "Alias for -resources" }, - { RD_Option_Relocs, "r", "Alias for -relocs" }, + { RD_Option_DebugInfo, "debug_info", "Dump .debug_info" }, + { RD_Option_DebugAbbrev, "debug_abbrev", "Dump .debug_abbrev" }, + { RD_Option_DebugLine, "debug_line", "Dump .debug_line" }, + { RD_Option_DebugStr, "debug_str", "Dump .debug_str" }, + { RD_Option_DebugLoc, "debug_loc", "Dump .debug_loc" }, + { RD_Option_DebugRanges, "debug_ranges", "Dump .debug_ranges" }, + { RD_Option_DebugARanges, "debug_aranges", "Dump .debug_aranges" }, + { RD_Option_DebugAddr, "debug_addr", "Dump .debug_addr" }, + { RD_Option_DebugLocLists, "debug_loclists", "Dump .debug_loclists" }, + { RD_Option_DebugRngLists, "debug_rnglists", "Dump .debug_rnglists" }, + { RD_Option_DebugPubNames, "debug_pubnames", "Dump .debug_pubnames" }, + { RD_Option_DebugPubTypes, "debug_pubtypes", "Dump .debug_putypes" }, + { RD_Option_DebugLineStr, "debug_linestr", "Dump .debug_linestr" }, + { RD_Option_DebugStrOffsets, "debug_stroffsets", "Dump .debug_stroffsets" }, + { RD_Option_Dwarf, "dwarf", "Dump all DWARF sections" }, + { RD_Option_RelaxDwarfParser, "relax_dwarf_parser", "Relaxes version requirement on attribute and form encodings" }, + + { RD_Option_RdiDataSections, "rdi_data_sections", "Dump data sections" }, + { RD_Option_RdiTopLevelInfo, "rdi_top_level_info", "Dump top level info" }, + { RD_Option_RdiBinarySections, "rdi_binary_sections", "Dump binary sections" }, + { RD_Option_RdiFilePaths, "rdi_file_paths", "Dump file paths" }, + { RD_Option_RdiSourceFiles, "rdi_source_files", "Dump source files" }, + { RD_Option_RdiLineTables, "rdi_line_tables", "Dump line tables" }, + { RD_Option_RdiSourceLineMaps, "rdi_source_line_maps", "Dump source line maps" }, + { RD_Option_RdiUnits, "rdi_units", "Dump units" }, + { RD_Option_RdiUnitVMap, "rdi_units_virtual_map", "Dump units virtual map" }, + { RD_Option_RdiTypeNodes, "rdi_type_nodes", "Dump type nodes" }, + { RD_Option_RdiUserDefinedTypes, "rdi_udt", "Dump user defined types" }, + { RD_Option_RdiGlobalVars, "rdi_global_vars", "Dump global variables" }, + { RD_Option_RdiThreadVars, "rdi_thread_vars", "Dump thread variables" }, + { RD_Option_RdiScopes, "rdi_scopes", "Dump scopes" }, + { RD_Option_RdiScopeVMap, "rdi_scope_virtual_map", "Dump scope virtual map" }, + { RD_Option_RdiInlineSites, "rdi_inline_sites", "Dump inline sites" }, + { RD_Option_RdiNameMaps, "rdi_name_maps", "Dump name maps" }, + { RD_Option_RdiStrings, "rdi_strings", "Dump strings" }, + + { RD_Option_Help, "h", "Alias for -help" }, + { RD_Option_Version, "v", "Alias for -version" }, + { RD_Option_Sections, "s", "Alias for -sections" }, + { RD_Option_Exceptions, "e", "Alias for -exceptions" }, + { RD_Option_Imports, "i", "Alias for -imports" }, + { RD_Option_Exports, "x", "Alias for -exports" }, + { RD_Option_LoadConfig, "l", "Alias for -loadconifg" }, + { RD_Option_Resources, "c", "Alias for -resources" }, + { RD_Option_Relocs, "r", "Alias for -relocs" }, }; internal void From 5c1e2199017b1cdd9040837dbf835db8dff912da Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 29 Jan 2025 16:26:02 -0800 Subject: [PATCH 51/53] minor prof fix --- src/rdi_from_pdb/rdi_from_pdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index b396ab9b..943dcca1 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -4058,7 +4058,7 @@ ASYNC_WORK_DEF(p2r_bake_inline_site_strings_work) Arena *arena = p2r_state->work_thread_arenas[thread_idx]; P2R_BakeInlineSiteStringsIn *in = input; p2r_make_string_map_if_needed(); - ProfScope("bake inline site strings"); + ProfScope("bake inline site strings") { for(P2R_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) { From e114ea7fdbe0838dcd925422abc5cdaa205cc30f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 29 Jan 2025 16:27:15 -0800 Subject: [PATCH 52/53] hook RDI printers to the dumper --- src/raddump/raddump.c | 398 ++++++++++++++++++++++++++++++++----- src/raddump/raddump.h | 26 ++- src/raddump/raddump_main.c | 15 +- 3 files changed, 381 insertions(+), 58 deletions(-) diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index b27a70cc..9cab379d 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -222,6 +222,17 @@ rd_is_pe(String8 raw_data) return header.magic == PE_DOS_MAGIC; } +internal B32 +rd_is_rdi(String8 raw_data) +{ + B32 is_rdi = 0; + if (raw_data.size > 8) { + U64 *magic = (U64 *)raw_data.str; + is_rdi = *magic == RDI_MAGIC_CONSTANT; + } + return is_rdi; +} + internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags) { @@ -233,12 +244,25 @@ rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags) if (remaining_flags != 0) { str8_list_pushf(scratch.arena, &list, "Unknown flags: %#llx", remaining_flags); } - result = str8_list_join(arena, &list, &(StringJoin){.sep = str8_lit(" ") }); + result = str8_list_join(arena, &list, &(StringJoin){.sep = str8_lit(", ") }); scratch_end(scratch); } return result; } +internal String8 +rd_string_from_array_u32(Arena *arena, U32 *v, U64 count) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + for (U64 i = 0; i < count; ++i) { + str8_list_pushf(scratch.arena, &list, "%u", v[i]); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + internal String8 rd_string_from_array_hex_u32(Arena *arena, U32 *v, U64 count) { @@ -268,7 +292,14 @@ rd_string_from_array_hex_u64(Arena *arena, U64 *v, U64 count) internal String8 rd_string_from_range_array_u64_hex(Arena *arena, U64 *v, U64 count) { - NotImplemented; + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + for (U64 i = 0; i+2 <= count; i += 2) { + str8_list_pushf(scratch.arena, &list, "[%#llx, %#llx)", v[i+0], v[i+1]); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; } internal void @@ -287,6 +318,8 @@ rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input input_type_string = "Obj"; } else if (rd_is_pe(raw_data)) { input_type_string = "COFF/PE"; + } else if (rd_is_rdi(raw_data)) { + input_type_string = "RDI"; } DateTime universal_dt = os_now_universal_time(); @@ -695,6 +728,33 @@ rdi_string_from_language(Arena *arena, RDI_Language v) return result; } +internal String8 +rdi_string_from_local_kind(Arena *arena, RDI_LocalKind v) +{ + String8 result; + switch(v) + { + default: { result = push_str8f(arena, "", v); } break; +#define X(name) case RDI_LocalKind_##name:{ result = str8_lit(#name); } break; + RDI_LocalKind_XList +#undef X + } + return result; +} + +internal String8 +rdi_string_from_type_kind(Arena *arena, RDI_TypeKind v) +{ + String8 result; + switch (v) { + default: { result = push_str8f(arena, "%u", v); } break; +#define X(name) case RDI_TypeKind_##name: { result = str8_lit(#name); } break; + RDI_TypeKind_XList +#undef X + } + return result; +} + internal String8 rdi_string_from_member_kind(Arena *arena, RDI_MemberKind v) { @@ -778,6 +838,7 @@ rdi_string_from_udt_flags(Arena *arena, RDI_UDTFlags flags) #undef X String8 result = rd_string_from_flags(arena, list, flags); scratch_end(scratch); + return result; } internal String8 @@ -821,7 +882,7 @@ internal void rdi_print_binary_section(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_BinarySection *bin_section) { Temp scratch = scratch_begin(&arena, 1); - rd_printf("name ='%S'", str8_from_idx(rdi, bin_section->name_string_idx)); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, bin_section->name_string_idx)); rd_printf("flags =%S", rdi_string_from_binary_section_flags(scratch.arena, bin_section->flags)); rd_printf("voff_first=%#08x", bin_section->voff_first); rd_printf("voff_opl =%#08x", bin_section->voff_opl); @@ -857,7 +918,7 @@ rdi_print_file_path(Arena *arena, String8List *out, String8 indent, RDI_Parsed * // stringize child rd_indent(); - rdi_stringize_file_path(arena, out, indent, rdi, child_node); + rdi_print_file_path(arena, out, indent, rdi, child_node); rd_unindent(); // increment iterator @@ -868,9 +929,10 @@ rdi_print_file_path(Arena *arena, String8List *out, String8 indent, RDI_Parsed * internal void rdi_print_source_file(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceFile *source_file) { - rd_printf("file_path_node_idx= %u", source_file->file_path_node_idx); - rd_printf("path= 'S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)); - rd_printf("source_line_map= %u", source_file->source_line_map_idx); + rd_printf("{ file_path_node_idx= "); + rd_printf("file_path_node_idx= %u", source_file->file_path_node_idx); + rd_printf("path= '%S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)); + rd_printf("source_line_map= %u", source_file->source_line_map_idx); } internal void @@ -961,18 +1023,18 @@ rdi_print_type_node(Arena *arena, String8List *out, String8 indent, RDI_Parsed * } else if (type->kind == RDI_TypeKind_Function) { U32 param_idx_count = 0; U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); - String8 param_idx_str = rd_string_from_array_hex_u32(scratch.arena, param_idx_array, param_idx_count); + String8 param_idx_str = rd_string_from_array_u32(scratch.arena, param_idx_array, param_idx_count); rd_printf("constructed.params =%S", param_idx_str); } else if (type->kind == RDI_TypeKind_Method) { U32 param_idx_count = 0; U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); - String8 this_type_str = str8_lit("???"); + String8 this_type_str = str8_lit("\?\?\?"); if (param_idx_count > 0) { this_type_str = push_str8f(scratch.arena, "%u", param_idx_array[0]); param_idx_count -= 1; param_idx_array += 1; } - String8 param_idx_str = rd_string_from_array_hex_u32(scratch.arena, param_idx_array, param_idx_count); + String8 param_idx_str = rd_string_from_array_u32(scratch.arena, param_idx_array, param_idx_count); rd_printf("constructed.this_type =%S", this_type_str); rd_printf("constructed.params =%S", param_idx_str); } else if (RDI_TypeKind_FirstConstructed <= type->kind && type->kind <= RDI_TypeKind_LastConstructed) { @@ -1017,7 +1079,7 @@ rdi_print_udt(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, R rd_indent(); RDI_EnumMember *enum_member = enum_member_array + member_lo; for (U32 i = member_lo; i < member_hi; ++i, ++enum_member) { - rd_printf("'%S' %llu", str8_from_rdi_string_idx(rdi, enum_member->name_string_idx), enum_member->val); + rd_printf("{ %llu, '%S' }", enum_member->val, str8_from_rdi_string_idx(rdi, enum_member->name_string_idx)); } rd_unindent(); rd_printf("}"); @@ -1034,7 +1096,7 @@ rdi_print_udt(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, R for (U32 i = member_lo; i < member_hi; ++i, ++member) { String8 kind_str = rdi_string_from_member_kind(scratch.arena, member->kind); String8 name_str = str8_from_rdi_string_idx(rdi, member->name_string_idx); - rd_printf("{ kind=%S, name='%S', type=%u, off=%u }", kind_str, name_str, member->type_idx, member->off); + rd_printf("{ kind=%S, type=%u, off=%u, name='%S' }", kind_str, member->type_idx, member->off, name_str); } rd_unindent(); rd_printf("}"); @@ -1071,8 +1133,8 @@ internal void rdi_print_procedure(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc) { Temp scratch = scratch_begin(&arena, 1); - rd_printf("name ='%S'", str8_from_rdi_string(scratch.arena, rdi, proc->name_string_idx)); - rd_printf("link_name ='%S'", str8_from_rdi_string(scratch.arena, rdi, proc->link_name_string_idx)); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, proc->name_string_idx)); + rd_printf("link_name ='%S'", str8_from_rdi_string_idx(rdi, proc->link_name_string_idx)); rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, proc->link_flags)); rd_printf("type_idx =%u", proc->type_idx); rd_printf("root_scope_idx=%u", proc->root_scope_idx); @@ -1090,11 +1152,13 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, U64 local_count = 0; U64 location_block_count = 0; U64 location_data_size = 0; + U64 proc_count = 0; RDI_Scope *scope_array = rdi_table_from_name(rdi, Scopes, &scope_count); U64 *scope_voff_array = rdi_table_from_name(rdi, ScopeVOffData, &scope_voff_count); RDI_Local *local_array = rdi_table_from_name(rdi, Locals, &local_count); RDI_LocationBlock *location_block_array = rdi_table_from_name(rdi, LocationBlocks, &location_block_count); RDI_U8 *location_data = rdi_table_from_name(rdi, LocationData, &location_data_size); + RDI_Procedure *proc_array = rdi_table_from_name(rdi, Procedures, &proc_count); U32 voff_range_lo = ClampTop(scope->voff_range_first, scope_voff_count); U32 voff_range_hi = ClampTop(scope->voff_range_opl, scope_voff_count); @@ -1106,9 +1170,15 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, rd_printf("[%llu]", this_idx); rd_indent(); - rd_printf("proc_idx =%u", scope->proc_idx); - rd_printf("inline_site_idx=%u", scope->inline_site_idx); - rd_printf("voff_ranges =%S", voff_str); + String8 proc_name = str8_lit("???"); + if (scope->proc_idx < proc_count) { + RDI_Procedure *proc = &proc_array[scope->proc_idx]; + proc_name = str8_from_rdi_string_idx(rdi, proc->name_string_idx); + } + + rd_printf("proc_idx =%u '%S'", scope->proc_idx, proc_name); + rd_printf("inline_site_idx=%u", scope->inline_site_idx); + rd_printf("voff_ranges =%S", voff_str); // local_array { @@ -1120,7 +1190,7 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, rd_printf("local[%u]", local_idx); rd_indent(); - rd_printf("kind =%S", rdi_string_from_local_kind(local_ptr->kind)); + rd_printf("kind =%S", rdi_string_from_local_kind(scratch.arena, local_ptr->kind)); rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, local_ptr->name_string_idx)); rd_printf("type_idx=%u", local_ptr->type_idx); @@ -1146,7 +1216,7 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_LocationKind kind = *(RDI_LocationKind*)loc_base_ptr; switch (kind) { default: { - rd_printf("???: %u", kind); + rd_printf("\?\?\?: %u", kind); } break; case RDI_LocationKind_AddrBytecodeStream: { @@ -1165,7 +1235,7 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, case RDI_LocationKind_AddrRegPlusU16: { if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl) { - rd_errorf("AddrRegPlusU16(???)"); + rd_printf("AddrRegPlusU16(\?\?\?)"); } else { RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; rd_printf("AddrRegPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); @@ -1174,7 +1244,7 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, case RDI_LocationKind_AddrAddrRegPlusU16: { if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ - rd_errorf("AddrAddrRegPlusU16(???"); + rd_printf("AddrAddrRegPlusU16(\?\?\?)"); } else { RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16 *)loc_base_ptr; rd_printf("AddrAddrRegisterPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); @@ -1183,10 +1253,10 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, case RDI_LocationKind_ValReg: { if (loc_base_ptr + sizeof(RDI_LocationReg) > loc_data_opl) { - rd_errorf("ValReg(???)"); + rd_printf("ValReg(\?\?\?)"); } else { RDI_LocationReg *loc = (RDI_LocationReg*)loc_base_ptr; - str8_list_pushf(arena, out, "ValReg(reg: %S)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code)); + rd_printf("ValReg(reg: %S)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code)); } } break; } @@ -1214,8 +1284,8 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, child_scope_idx = child_scope->next_sibling_scope_idx; } - rd_printf("[/%llu]", this_idx); rd_unindent(); + rd_printf("[/%llu]", this_idx); scratch_end(scratch); } @@ -1229,62 +1299,298 @@ rdi_print_inline_site(Arena *arena, String8List *out, String8 indent, RDI_Parsed rd_printf("line_table_idx=%u", inline_site->line_table_idx); } +internal void +rdi_print_vmap_entry(Arena *arena, String8List *out, String8 indent, RDI_VMapEntry *v) +{ + rd_printf("%#llx: %llu", v->voff, v->idx); +} + internal void rdi_print(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RD_Option opts) { + RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); + if (opts & RD_Option_RdiDataSections) { - NotImplemented; + rd_printf("# DATA SECTIONS"); + rd_indent(); + rdi_print_data_sections(arena, out, indent, rdi); + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiTopLevelInfo) { - NotImplemented; + rd_printf("# TOP LEVEL INFO"); + rd_indent(); + rdi_print_top_level_info(arena, out, indent, rdi, tli); + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiBinarySections) { - NotImplemented; + U64 count; + RDI_BinarySection *v = rdi_table_from_name(rdi, BinarySections, &count); + rd_printf("# BINARY SECTIONS"); + rd_indent(); + for (U64 idx = 0; idx < count; ++idx) { + rd_printf("section[%llu]:", idx); + rd_indent(); + rdi_print_binary_section(arena, out, indent, rdi, &v[idx]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiFilePaths) { - NotImplemented; + U64 file_path_count = 0; + RDI_FilePathNode *file_path_array = rdi_table_from_name(rdi, FilePathNodes, &file_path_count); + rd_printf("# FILE PATHS"); + rd_indent(); + for (U64 i = 0; i < file_path_count; ++i) { + if (file_path_array[i].parent_path_node == 0) { + rdi_print_file_path(arena, out, indent, rdi, &file_path_array[i]); + } + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiSourceFiles) { - NotImplemented; - } - if (opts & RD_Option_RdiLineTables) { - NotImplemented; - } - if (opts & RD_Option_RdiSourceLineMaps) { - NotImplemented; + U64 source_file_count = 0; + RDI_SourceFile *source_file_array = rdi_table_from_name(rdi, SourceFiles, &source_file_count); + rd_printf("# SOURCE FILES"); + rd_indent(); + for (U64 i = 0; i < source_file_count; ++i) { + RDI_SourceFile *source_file = &source_file_array[i]; + rd_printf("source_file[%4llu] = { file_path_node_idx = %4u, source_line_map = %4u, path = '%S' }", + i, + source_file->file_path_node_idx, + source_file->source_line_map_idx, + str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiUnits) { - NotImplemented; + U64 unit_count = 0; + RDI_Unit *unit_array = rdi_table_from_name(rdi, Units, &unit_count); + rd_printf("# UNITS"); + rd_indent(); + for (U64 i = 0; i < unit_count; ++i) { + rd_printf("unit[%llu]:", i); + rd_indent(); + rdi_print_unit(arena, out, indent, rdi, &unit_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiUnitVMap) { - NotImplemented; + U64 vmap_count = 0; + RDI_VMapEntry *vmap_array = rdi_table_from_name(rdi, UnitVMap, &vmap_count); + rd_printf("# UNIT VMAP"); + rd_indent(); + for (U64 i = 0; i < vmap_count; ++i) { + rdi_print_vmap_entry(arena, out, indent, &vmap_array[i]); + } + rd_unindent(); + rd_newline(); + } + if (opts & RD_Option_RdiLineTables) { + U64 line_table_count = 0; + RDI_LineTable *line_table_array = rdi_table_from_name(rdi, LineTables, &line_table_count); + rd_printf("# LINE TABLES"); + rd_indent(); + for (U64 i = 0; i < line_table_count; ++i) { + rd_printf("line_table[%llu]", i); + rd_indent(); + rdi_print_line_table(arena, out, indent, rdi, &line_table_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); + } + if (opts & RD_Option_RdiSourceLineMaps) { + U64 source_line_map_count = 0; + RDI_SourceLineMap *source_line_map_array = rdi_table_from_name(rdi, SourceLineMaps, &source_line_map_count); + rd_printf("# SOURCE LINE MAPS"); + rd_indent(); + for (U64 i = 0; i < source_line_map_count; ++i) { + rd_printf("source_line_map[%llu]:", i); + rd_indent(); + rdi_print_source_line_map(arena, out, indent, rdi, &source_line_map_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiTypeNodes) { - NotImplemented; + U64 type_node_count = 0; + RDI_TypeNode *type_node_array = rdi_table_from_name(rdi, TypeNodes, &type_node_count); + rd_printf("# TYPE NODES"); + rd_indent(); + for (U64 i = 0; i < type_node_count; ++i) { + rd_printf("type[%llu]", i); + rd_indent(); + rdi_print_type_node(arena, out, indent, rdi, &type_node_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiUserDefinedTypes) { - NotImplemented; + U64 udt_count = 0; + RDI_UDT *udt_array = rdi_table_from_name(rdi, UDTs, &udt_count); + rd_printf("# UDTS"); + rd_indent(); + for (U64 i = 0; i < udt_count; ++i) { + rd_printf("udt[%u]:", i); + rd_indent(); + rdi_print_udt(arena, out, indent, rdi, &udt_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiGlobalVars) { - NotImplemented; + U64 gvar_count = 0; + RDI_GlobalVariable *gvar_array = rdi_table_from_name(rdi, GlobalVariables, &gvar_count); + rd_printf("# GLOBAL VARIABLES"); + rd_indent(); + for (U64 i = 0; i < gvar_count; ++i) { + rd_printf("global_variable[%llu]:", i); + rd_indent(); + rdi_print_global_variable(arena, out, indent, rdi, &gvar_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); + } + if (opts & RD_Option_RdiGlobalVarsVMap) { + U64 vmap_count = 0; + RDI_VMapEntry *vmap_array = rdi_table_from_name(rdi, GlobalVMap, &vmap_count); + rd_printf("# GLOBAL VMAP"); + rd_indent(); + for (U64 i = 0; i < vmap_count; ++i) { + rdi_print_vmap_entry(arena, out, indent, &vmap_array[i]); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiThreadVars) { - NotImplemented; + U64 tvar_count = 0; + RDI_ThreadVariable *tvar_array = rdi_table_from_name(rdi, ThreadVariables, &tvar_count); + rd_printf("# THREAD VARIABLES"); + rd_indent(); + for (U64 i = 0; i < tvar_count; ++i) { + rd_printf("thread_variable[%llu]:", i); + rdi_print_thread_variable(arena, out, indent, rdi, &tvar_array[i]); + } + rd_unindent(); + rd_newline(); + } + if (opts & RD_Option_RdiProcedures) { + U64 proc_count = 0; + RDI_Procedure *proc_array = rdi_table_from_name(rdi, Procedures, &proc_count); + rd_printf("# PROCEDURES"); + rd_indent(); + for (U64 i = 0; i < proc_count; ++i) { + rd_printf("procedure[%llu]:", i); + rd_indent(); + rdi_print_procedure(arena, out, indent, rdi, &proc_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiScopes) { - NotImplemented; + U64 scope_count = 0; + RDI_Scope *scope_array = rdi_table_from_name(rdi, Scopes, &scope_count); + rd_printf("# SCOPES"); + rd_indent(); + for (U64 i = 0; i < scope_count; ++i) { + if (scope_array[i].parent_scope_idx == 0) { + rdi_print_scope(arena, out, indent, rdi, &scope_array[i], tli->arch); + } + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiScopeVMap) { - NotImplemented; + U64 vmap_count = 0; + RDI_VMapEntry *vmap_array = rdi_table_from_name(rdi, ScopeVMap, &vmap_count); + rd_printf("# SCOPE VMAP"); + rd_indent(); + for (U64 i = 0; i < vmap_count; ++i) { + rdi_print_vmap_entry(arena, out, indent, &vmap_array[i]); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiInlineSites) { - NotImplemented; + U64 inline_site_count = 0; + RDI_InlineSite *inline_site_array = rdi_table_from_name(rdi, InlineSites, &inline_site_count); + rd_printf("# INLINE SITES"); + rd_indent(); + for (U64 i = 0; i < inline_site_count; ++i) { + rd_printf("inline_site[%llu]:", i); + rd_indent(); + rdi_print_inline_site(arena, out, indent, rdi, &inline_site_array[i]); + rd_unindent(); + } + rd_unindent(); + rd_newline(); } if (opts & RD_Option_RdiNameMaps) { - NotImplemented; + Temp scratch = scratch_begin(&arena, 1); + U64 name_map_count = 0; + RDI_NameMap *name_map_array = rdi_table_from_name(rdi, NameMaps, &name_map_count); + rd_printf("# NAME MAPS"); + rd_indent(); + for (U64 i = 0; i < name_map_count; ++i) { + if (i > 0) { + rd_newline(); + } + RDI_ParsedNameMap name_map = {0}; + rdi_parsed_from_name_map(rdi, &name_map_array[i], &name_map); + rd_printf("name_map[%S]",rdi_string_from_name_map_kind(i)); + rd_indent(); + for (U64 bucket_idx = 0; bucket_idx < name_map.bucket_count; ++bucket_idx) { + if (name_map.buckets[bucket_idx].node_count == 0) { + continue; + } + rd_printf("bucket[%llu]:", bucket_idx); + rd_indent(); + RDI_NameMapNode *node_ptr = name_map.nodes + name_map.buckets[bucket_idx].first_node; + RDI_NameMapNode *node_opl = node_ptr + name_map.buckets[bucket_idx].node_count; + for (; node_ptr < node_opl; ++node_ptr) { + Temp temp = temp_begin(scratch.arena); + String8 str = str8_from_rdi_string_idx(rdi, node_ptr->string_idx); + String8 indices; + if (node_ptr->match_count == 1) { + indices = push_str8f(temp.arena, "%u", node_ptr->match_idx_or_idx_run_first); + } else { + U32 idx_count = 0; + U32 *idx_array = rdi_idx_run_from_first_count(rdi, node_ptr->match_idx_or_idx_run_first, node_ptr->match_count, &idx_count); + indices = rd_string_from_array_u32(temp.arena, idx_array, idx_count); + } + rd_printf("match \"%S\": %S", str, indices); + temp_end(temp); + } + rd_unindent(); + } + rd_unindent(); + } + rd_unindent(); + rd_newline(); + scratch_end(scratch); } if (opts & RD_Option_RdiStrings) { - NotImplemented; + U64 stridx_count = 0; + U32 *stridx_array = rdi_table_from_name(rdi, StringTable, &stridx_count); + rd_printf("# STRINGS"); + rd_indent(); + for (U64 i = 0; i < stridx_count; ++i) { + rd_printf("string[%llu]: \"%S\"", i, str8_from_rdi_string_idx(rdi, i)); + } + rd_unindent(); + rd_newline(); } } diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index 46fbd97d..16e074db 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -4,7 +4,7 @@ #ifndef RADDUMP_H #define RADDUMP_H -#define RD_INDENT_WIDTH 4 +#define RD_INDENT_WIDTH 2 #define RD_INDENT_MAX 4096 #define rd_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__) @@ -78,13 +78,14 @@ typedef U64 RD_Option; #define RD_Option_RdiTypeNodes (1ull << 42ull) #define RD_Option_RdiUserDefinedTypes (1ull << 43ull) #define RD_Option_RdiGlobalVars (1ull << 44ull) -#define RD_Option_RdiThreadVars (1ull << 45ull) -#define RD_Option_RdiProcedures (1ull << 46ull) -#define RD_Option_RdiScopes (1ull << 47ull) -#define RD_Option_RdiScopeVMap (1ull << 48ull) -#define RD_Option_RdiInlineSites (1ull << 49ull) -#define RD_Option_RdiNameMaps (1ull << 50ull) -#define RD_Option_RdiStrings (1ull << 51ull) +#define RD_Option_RdiGlobalVarsVMap (1ull << 45ull) +#define RD_Option_RdiThreadVars (1ull << 46ull) +#define RD_Option_RdiProcedures (1ull << 48ull) +#define RD_Option_RdiScopes (1ull << 49ull) +#define RD_Option_RdiScopeVMap (1ull << 50ull) +#define RD_Option_RdiInlineSites (1ull << 51ull) +#define RD_Option_RdiNameMaps (1ull << 52ull) +#define RD_Option_RdiStrings (1ull << 53ull) typedef struct RD_Marker { @@ -139,7 +140,8 @@ typedef struct RD_Line // raddump -internal B32 rd_is_pe(String8 raw_data); +internal B32 rd_is_pe (String8 raw_data); +internal B32 rd_is_rdi(String8 raw_data); internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags); @@ -163,13 +165,13 @@ internal void rd_print_disasm (Arena *arena, String8List *o internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); -// // RDI -// internal String8 rdi_string_from_data_section_kind(Arena *arena, RDI_SectionKind v); internal String8 rdi_string_from_arch (Arena *arena, RDI_Arch v); internal String8 rdi_string_from_language (Arena *arena, RDI_Language v); +internal String8 rdi_string_from_local_kind (Arena *arena, RDI_LocalKind v); +internal String8 rdi_string_from_type_kind (Arena *arena, RDI_TypeKind v); internal String8 rdi_string_from_member_kind (Arena *arena, RDI_MemberKind v); internal String8 rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags); @@ -186,11 +188,13 @@ internal void rdi_print_line_table (Arena *arena, String8List *out, String8 internal void rdi_print_source_line_map(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceLineMap *map); internal void rdi_print_unit (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Unit *unit); internal void rdi_print_type_node (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TypeNode *type); +internal void rdi_print_udt (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_UDT *udt); internal void rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar); internal void rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_ThreadVariable *tvar); internal void rdi_print_procedure (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc); internal void rdi_print_scope (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Scope *scope, RDI_Arch arch); internal void rdi_print_inline_site (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site); +internal void rdi_print_vmap_entry (Arena *arena, String8List *out, String8 indent, RDI_VMapEntry *v); // DWARF diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index c4268ea6..11b876a5 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -82,6 +82,8 @@ #include "linker/codeview_ext/codeview.c" #include "linker/hash_table.h" #include "linker/hash_table.c" +#include "linker/rdi/rdi.h" +#include "linker/rdi/rdi.c" #include "raddump/raddump.h" #include "raddump/raddump.c" @@ -250,7 +252,18 @@ entry_point(CmdLine *cmdline) // format input rd_format_preamble(arena, out, indent, file_path, raw_data); - if (coff_is_regular_archive(raw_data) || coff_is_thin_archive(raw_data)) { + if (rd_is_rdi(raw_data)) { + RDI_Parsed rdi = {0}; + RDI_ParseStatus parse_status = rdi_parse(raw_data.str, raw_data.size, &rdi); + switch (parse_status) { + case RDI_ParseStatus_Good: rdi_print(arena, out, indent, &rdi, opts); break; + case RDI_ParseStatus_HeaderDoesNotMatch: rd_errorf("RDI Parse: header does not match"); break; + case RDI_ParseStatus_UnsupportedVersionNumber: rd_errorf("RDI Parse: unsupported version"); break; + case RDI_ParseStatus_InvalidDataSecionLayout: rd_errorf("RDI Parse: invalid data section layout"); break; + case RDI_ParseStatus_MissingRequiredSection: rd_errorf("RDI Parse: missing required section"); break; + default: rd_errorf("RDI Parse: unknown parse status %u", parse_status); break; + } + } else if (coff_is_regular_archive(raw_data) || coff_is_thin_archive(raw_data)) { coff_print_archive(arena, out, indent, raw_data, opts); } else if (coff_is_big_obj(raw_data)) { coff_print_big_obj(arena, out, indent, raw_data, opts); From 0a0742aa0e58434b74a80f720babdf9ea99a1077 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 29 Jan 2025 16:28:02 -0800 Subject: [PATCH 53/53] remove unused enum fields --- src/dwarf/dwarf.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index cf108131..4fd083ce 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -139,7 +139,6 @@ typedef enum DW_StdOpcode #define X(_N,_ID) DW_StdOpcode_##_N = _ID, DW_StdOpcode_XList(X) #undef X - DW_StdOpcode_Count, } DW_StdOpcode; #define DW_ExtOpcode_XList(X) \ @@ -156,7 +155,6 @@ typedef enum DW_ExtOpcode #define X(_N,_ID) DW_ExtOpcode_##_N = _ID, DW_ExtOpcode_XList(X) #undef X - DW_ExtOpcode_Count } DW_ExtOpcode; #define DW_NameCase_XList(X) \