From edd982852eeed1c6e07b2d22fc86bc06170e04cf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 5 Feb 2026 17:42:24 -0800 Subject: [PATCH] pass over DWARF converter - prepare to thread line table conversion - error handling - organizational improvements --- src/radbin/radbin_main.c | 2 + src/raddbg/raddbg_main.c | 2 + src/rdi_from_dwarf/rdi_from_dwarf.c | 2105 +++++++++++++++------------ src/rdi_from_dwarf/rdi_from_dwarf.h | 293 ++-- 4 files changed, 1340 insertions(+), 1062 deletions(-) diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index 5b742c04..64e03163 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -13,6 +13,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "linker/hash_table.h" +#include "linker/lf_hash_table.h" #include "os/os_inc.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" @@ -39,6 +40,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "linker/hash_table.c" +#include "linker/lf_hash_table.c" #include "os/os_inc.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 7812a03a..1b3bcfb3 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -196,6 +196,7 @@ #include "base/base_inc.h" #include "x64/x64.h" #include "linker/hash_table.h" +#include "linker/lf_hash_table.h" #include "os/os_inc.h" #include "artifact_cache/artifact_cache.h" #include "rdi/rdi_local.h" @@ -249,6 +250,7 @@ #include "base/base_inc.c" #include "x64/x64.c" #include "linker/hash_table.c" +#include "linker/lf_hash_table.c" #include "os/os_inc.c" #include "artifact_cache/artifact_cache.c" #include "rdi/rdi_local.c" diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index ce8ebd1e..5ae83a54 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -3,241 +3,7 @@ //////////////////////////////// -thread_static D2R_Log g_d2r_log; - -//////////////////////////////// - -static const U64 UNIT_CHUNK_CAP = 256; -static const U64 UDT_CHUNK_CAP = 256; -static const U64 TYPE_CHUNK_CAP = 256; -static const U64 SRC_FILE_CAP = 256; -static const U64 LINE_TABLE_CAP = 256; -static const U64 LOCATIONS_CAP = 256; -static const U64 GVAR_CHUNK_CAP = 256; -static const U64 TVAR_CHUNK_CAP = 256; -static const U64 PROC_CHUNK_CAP = 256; -static const U64 SCOPE_CHUNK_CAP = 256; -static const U64 INLINE_SITE_CHUNK_CAP = 256; - -RDIM_TopLevelInfo top_level_info = {0}; -RDIM_BinarySectionList binary_sections = {0}; -RDIM_UnitChunkList units = {0}; -RDIM_UDTChunkList udts = {0}; -RDIM_TypeChunkList types = {0}; -RDIM_SrcFileChunkList src_files = {0}; -RDIM_LineTableChunkList line_tables = {0}; -RDIM_LocationChunkList locations = {0}; -RDIM_SymbolChunkList gvars = {0}; -RDIM_SymbolChunkList tvars = {0}; -RDIM_SymbolChunkList procs = {0}; -RDIM_ScopeChunkList scopes = {0}; -RDIM_InlineSiteChunkList inline_sites = {0}; - -//////////////////////////////// -//~ rjf: Enum Conversion Helpers - -internal RDI_Language -d2r_rdi_language_from_dw_language(DW_Language v) -{ - RDI_Language result = RDI_Language_NULL; - switch(v) - { - default:{}break; - - case DW_Language_C89: - case DW_Language_C99: - case DW_Language_C11: - case DW_Language_C: - { - result = RDI_Language_C; - }break; - - case DW_Language_CPlusPlus03: - case DW_Language_CPlusPlus11: - case DW_Language_CPlusPlus14: - case DW_Language_CPlusPlus: - { - result = RDI_Language_CPlusPlus; - }break; - } - return result; -} - -internal RDI_RegCodeX64 -d2r_rdi_reg_code_from_dw_reg_x64(DW_RegX64 v) -{ - RDI_RegCodeX64 result = RDI_RegCode_nil; - switch(v) - { - default:{}break; -#define X(reg_dw, val_dw, reg_rdi, off, size) case DW_RegX64_##reg_dw:{result = RDI_RegCodeX64_##reg_rdi;}break; - DW_Regs_X64_XList -#undef X - } - return result; -} - -internal RDI_RegCode -d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v) -{ - RDI_RegCode result = RDI_RegCode_nil; - switch(arch) - { - default: NotImplemented; break; - case Arch_Null: break; - case Arch_x64:{result = d2r_rdi_reg_code_from_dw_reg_x64(v);}break; - } - return result; -} - -//////////////////////////////// -//~ rjf: Type Conversion Helpers - -internal RDIM_Type * -d2r_create_type(Arena *arena, D2R_TypeTable *type_table) -{ - RDIM_Type *type = rdim_type_chunk_list_push(arena, type_table->types, type_table->type_chunk_cap); - return type; -} - -internal RDIM_Type * -d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) -{ - RDIM_Type *type = d2r_create_type(arena, type_table); - Assert(hash_table_search_u64_raw(type_table->ht, info_off) == 0); - hash_table_push_u64_raw(arena, type_table->ht, info_off, type); - return type; -} - -internal RDIM_Type * -d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off) -{ - RDIM_Type *type = hash_table_search_u64_raw(type_table->ht, info_off); - if (type == 0) { - type = type_table->builtin_types[RDI_TypeKind_NULL]; - } - return type; -} - -internal RDIM_Type * -d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_Void]; - - // find attrib - DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); - - // does tag have this attribute? - if (attrib->attrib_kind == kind) { - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - - if (value_class == DW_AttribClass_Reference) { - // resolve reference - DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); - - // TODO: support for external compile unit references - AssertAlways(ref.cu == cu); - - // find type - type = d2r_type_from_offset(type_table, ref.info_off); - } else { - Assert(!"unexpected attrib class"); - } - } - - return type; -} - -internal Rng1U64List -d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) -{ - // collect non-contiguous range - Rng1U64List raw_ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); - - // exclude invalid ranges caused by linker optimizations - Rng1U64List ranges = {0}; - for (Rng1U64Node *n = raw_ranges.first, *next = 0; n != 0; n = next) { - next = n->next; - if (n->v.min < image_base || n->v.min > n->v.max) { - continue; - } - rng1u64_list_push_node(&ranges, n); - } - - // debase ranges - for EachNode(r, Rng1U64Node, ranges.first) { - r->v.min -= image_base; - r->v.max -= image_base; - } - - // collect contiguous range - { - DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_LowPc); - DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); - if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { - U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); - - U64 hi_pc = 0; - DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); - if (hi_pc_class == DW_AttribClass_Address) { - hi_pc = dw_address_from_attrib(input, cu, hi_pc_attrib); - } else if (hi_pc_class == DW_AttribClass_Const) { - hi_pc = dw_const_u64_from_attrib(input, cu, hi_pc_attrib); - hi_pc += lo_pc; - } else { - AssertAlways(!"unexpected attribute encoding"); - } - - if (lo_pc >= image_base && hi_pc >= image_base) { - if (lo_pc < hi_pc) { - rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); - } else { - // TODO: error handling - } - } else { - // invalid low and hi PC are likely are caused by an optimization pass during linking - } - } else if ((lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) || - (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null)) { - // TODO: error handling - } - } - - return ranges; -} - -internal RDIM_Type ** -d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out) -{ - Temp scratch = scratch_begin(&arena, 1); - - RDIM_TypeList list = {0}; - B32 has_vargs = 0; - for (DW_TagNode *i = cur_node->first_child; i != 0; i = i->sibling) { - if (i->tag.kind == DW_TagKind_FormalParameter) { - RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); - n->v = d2r_type_from_attrib(type_table, input, cu, i->tag, DW_AttribKind_Type); - SLLQueuePush(list.first, list.last, n); - ++list.count; - } else if (i->tag.kind == DW_TagKind_UnspecifiedParameters) { - has_vargs = 1; - } - } - - if (has_vargs) { - RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); - n->v = type_table->builtin_types[RDI_TypeKind_Variadic]; - SLLQueuePush(list.first, list.last, n); - ++list.count; - } - - // collect params - *param_count_out = list.count; - RDIM_Type **params = rdim_array_from_type_list(arena, list); - - scratch_end(scratch); - return params; -} +static D2R_Shared g_d2r_shared; //////////////////////////////// @@ -258,10 +24,11 @@ rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc) return is_static; } -internal U64 -rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) +internal B32 +rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out) { Temp scratch = scratch_begin(0,0); + B32 is_ok = 0; typedef union { U16 u16; U32 u32; U64 u64; S64 s64; F32 f32; F64 f64; } Value; U64 stack_cap = 128, stack_count = 0; @@ -273,9 +40,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) { U32 pop_count = RDI_POPN_FROM_CTRLBITS(rdi_eval_op_ctrlbits_table[opcode_n->op]); if (pop_count > stack_count) { - // TODO: report error - Assert(!"malformed byte code"); - break; + goto exit; } stack_count -= pop_count; svals = stack + stack_count; @@ -315,7 +80,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = abs_s64(svals[0].s64); } break; case RDI_EvalTypeGroup_F32: { nval.f32 = abs_f32(svals[0].f32); } break; case RDI_EvalTypeGroup_F64: { nval.f64 = abs_f64(svals[0].f64); } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Neg: { @@ -325,7 +90,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.u64 = ~svals[0].u64 + 1; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = -svals[0].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = -svals[0].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Add: { @@ -335,7 +100,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 + svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 + svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 + svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Sub: { @@ -345,7 +110,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 - svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 - svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 - svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Mul: { @@ -355,7 +120,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 * svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 * svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 * svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Div: { @@ -366,11 +131,13 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { is_div_by_zero = svals[1].s64 == 0; } break; case RDI_EvalTypeGroup_F32: { is_div_by_zero = svals[1].f32 == 0.0f; } break; case RDI_EvalTypeGroup_F64: { is_div_by_zero = svals[1].f64 == 0.0; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } - // TODO: report error - AssertAlways(!is_div_by_zero); + if (is_div_by_zero) { + Assert(!"trying to div by zero"); + goto exit; + } switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; @@ -378,7 +145,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 / svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 / svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 / svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Mod: { @@ -386,39 +153,39 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_Other: {} break; case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 % svals[1].u64; } break; case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 % svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 MOD is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 MOD is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_F32: { Assert(!"F32 MOD is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 MOD is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_LShift: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 << svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 << svals[1].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 LShift is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 LShift is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 LShift is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 LShift is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_RShift: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >> svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 >> svals[1].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 RShift is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 RShift is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0 ] .u64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[1 ] .s64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 RShift is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 RShift is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_BitAnd: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 | svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 | svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise AND is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise AND is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 | svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 | svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 bitwise AND is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 bitwise AND is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_BitXor: { @@ -426,19 +193,19 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_Other: {} break; case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 ^ svals[1].u64; } break; case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 ^ svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 XOR is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 XOR is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_F32: { Assert(!"F32 XOR is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 XOR is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_BitNot: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = ~svals[0].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = ~svals[0].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise NOT is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise NOT is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 bitwise NOT is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 bitwise NOT is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_LogAnd: { @@ -446,29 +213,29 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_Other: {} break; case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 && svals[1].u64; } break; case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 && svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 AND is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 AND is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_F32: { Assert(!"F32 AND is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 AND is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_LogOr: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 || svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 || svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 OR is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 OR is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 || svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 || svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 OR is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 OR is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_LogNot: { switch (imm.u64) { case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = !svals[0].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = !svals[0].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 NOT is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 NOT is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + case RDI_EvalTypeGroup_U: { nval.u64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { Assert(!"F32 NOT is not supported"); } goto exit; + case RDI_EvalTypeGroup_F64: { Assert(!"F64 NOT is not supported"); } goto exit; + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_EqEq: { @@ -484,7 +251,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 <= svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 <= svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 <= svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_GrEq: { @@ -494,7 +261,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 >= svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 >= svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 >= svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Less: { @@ -504,7 +271,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 < svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 < svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 < svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Grtr: { @@ -514,7 +281,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 > svals[1].s64; } break; case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 > svals[1].f32; } break; case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 > svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error + default: { Assert(!"unexpected eval type group"); } goto exit; } } break; case RDI_EvalOp_Trunc: { @@ -522,8 +289,8 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) U64 mask = max_U64 >> (64 - imm.u64); nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); } else if (imm.u64 > 64) { - // TODO: report error - AssertAlways(!"malformed bytecode"); + Assert(!"malformed bytecode"); + goto exit; } } break; case RDI_EvalOp_TruncSigned: { @@ -536,8 +303,8 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) } nval.u64 = high | (svals[0].u64 & mask); } else if (imm.u64 > 64) { - // TODO: report error - AssertAlways(!"malformed bytecode"); + Assert(!"malformed bytecode"); + goto exit; } } break; case RDI_EvalOp_Convert: { @@ -555,7 +322,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; } break; case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; } break; case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; } break; - default: { Assert(!"unexpected conversion case"); } break; // report error + default: { Assert(!"unexpected conversion case"); } goto exit; } } } break; @@ -563,8 +330,8 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) if (stack_count > imm.u64) { nval = stack[stack_count - imm.u64 - 1]; } else { - // TODO: report error - AssertAlways(!"malformed bytecode"); + Assert(!"malformed bytecode"); + goto exit; } } break; case RDI_EvalOp_Pop: {} break; @@ -576,8 +343,8 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) MemoryCopy(shift, dst, imm.u64 * sizeof(Value)); *dst = tval; } else { - // TODO: report error - AssertAlways(!"malformed bytecode"); + Assert(!"malformed bytecode"); + goto exit; } } break; case RDI_EvalOp_ValueRead: { @@ -595,7 +362,7 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) case 2: { nval.u16 = bswap_u16(svals[0].u16); } break; case 4: { nval.u32 = bswap_u16(svals[0].u32); } break; case 8: { nval.u64 = bswap_u16(svals[0].u64); } break; - default: { AssertAlways(!"malformed bytecode"); } break; // TODO: report error + default: { Assert(!"malformed bytecode"); } goto exit; } } break; case RDI_EvalOp_Swap: { @@ -612,7 +379,8 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) stack[stack_count] = nval; stack_count += 1; } else { - AssertAlways(!"stack overflow"); // TODO: report error + Assert(!"stack overflow"); + goto exit; } } } @@ -622,13 +390,64 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) if (stack_count >= 1) { result = stack[0].u64 - image_base; } + if (voff_out) { + *voff_out = result; + } + is_ok = 1; +exit:; scratch_end(scratch); + return is_ok; +} + +internal RDI_Language +d2r_rdi_language_from_dw_language(DW_Language v) +{ + RDI_Language result = RDI_Language_NULL; + switch (v) { + default: {} break; + + case DW_Language_C89: + case DW_Language_C99: + case DW_Language_C11: + case DW_Language_C: { + result = RDI_Language_C; + } break; + + case DW_Language_CPlusPlus03: + case DW_Language_CPlusPlus11: + case DW_Language_CPlusPlus14: + case DW_Language_CPlusPlus: { + result = RDI_Language_CPlusPlus; + } break; + } return result; } -//////////////////////////////// -//~ rjf: Bytecode Conversion Helpers +internal RDI_RegCodeX64 +d2r_rdi_reg_code_from_dw_reg_x64(DW_RegX64 v) +{ + RDI_RegCodeX64 result = RDI_RegCode_nil; + switch (v) { + default: {} break; +#define X(reg_dw, val_dw, reg_rdi, off, size) case DW_RegX64_##reg_dw: { result = RDI_RegCodeX64_##reg_rdi; } break; + DW_Regs_X64_XList +#undef X + } + return result; +} + +internal RDI_RegCode +d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v) +{ + RDI_RegCode result = RDI_RegCode_nil; + switch (arch) { + default: NotImplemented; break; + case Arch_Null: break; + case Arch_x64:{ result = d2r_rdi_reg_code_from_dw_reg_x64(v); } break; + } + return result; +} internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type) @@ -666,103 +485,92 @@ d2r_value_type_stack_peek(D2R_ValueTypeStack *stack) return stack->top ? stack->top->type : D2R_ValueType_Generic; } -internal D2R_ValueType -d2r_unsigned_value_type_from_bit_size(U64 bit_size) -{ - switch (bit_size) { - case 8: return D2R_ValueType_U8; - case 16: return D2R_ValueType_U16; - case 32: return D2R_ValueType_U32; - case 64: return D2R_ValueType_U64; - case 128: return D2R_ValueType_U128; - case 256: return D2R_ValueType_U256; - case 512: return D2R_ValueType_U512; - } - AssertAlways(!"no suitable unsigned type was found for the specified size"); - return D2R_ValueType_Generic; -} - internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size) { switch (bit_size) { - case 8: return D2R_ValueType_S8; - case 16: return D2R_ValueType_S16; - case 32: return D2R_ValueType_S32; - case 64: return D2R_ValueType_S64; - case 128: return D2R_ValueType_S128; - case 256: return D2R_ValueType_S256; - case 512: return D2R_ValueType_S512; +#define X(_N, _AT, _S) case _S: return D2R_ValueType_##_N; + D2R_ValueType_Signed_XList +#undef X } AssertAlways(!"no suitable signed type was found for the specified size"); return D2R_ValueType_Generic; } internal D2R_ValueType -d2r_float_type_from_bit_size(U64 bit_size) +d2r_unsigned_value_type_from_bit_size(U64 bit_size) { switch (bit_size) { - case 4: return D2R_ValueType_F32; - case 8: return D2R_ValueType_F64; +#define X(_N, _AT, _S) case _S: return D2R_ValueType_##_N; + D2R_ValueType_Unsigned_XList +#undef X } + AssertAlways(!"no suitable unsigned type was found for the specified size"); + return D2R_ValueType_Generic; +} + +internal D2R_ValueType +d2r_float_type_from_bit_size(U64 bit_size) +{ +#define X(_N, _AT, _S) case _S: return D2R_ValueType_##_N; + switch (bit_size) { + D2R_ValueType_Float_XList + } +#undef X AssertAlways(!"no suitable type was found for the specified size"); return D2R_ValueType_Generic; } -internal RDI_EvalTypeGroup -d2r_value_type_to_rdi(D2R_ValueType v) +internal D2R_ArithmeticType +d2r_arithmetic_type_from_value_type(D2R_ValueType v) { - RDI_EvalTypeGroup result = RDI_EvalTypeGroup_Other; - switch(v) - { - case D2R_ValueType_Generic: - {result = RDI_EvalTypeGroup_Other;}break; - case D2R_ValueType_U8: - case D2R_ValueType_U16: - case D2R_ValueType_U32: - case D2R_ValueType_U64: - {result = RDI_EvalTypeGroup_U;}break; - case D2R_ValueType_S8: - case D2R_ValueType_S16: - case D2R_ValueType_S32: - case D2R_ValueType_S64: - {result = RDI_EvalTypeGroup_S;}break; - case D2R_ValueType_F32: - {result = RDI_EvalTypeGroup_F32;}break; - case D2R_ValueType_F64: - {result = RDI_EvalTypeGroup_F64;}break; - case D2R_ValueType_Address: - {result = RDI_EvalTypeGroup_U;}break; - default: - case D2R_ValueType_ImplicitValue: - {AssertAlways(!"unable to convert value type to RDI equivalent");}break; +#define X(_N, _AT, ...) case D2R_ValueType_##_N: return D2R_ArithmeticType_##_AT; + switch (v) { + D2R_ValueType_XList } - return result; +#undef X + return D2R_ArithmeticType_Null; +} + +internal B32 +d2r_is_value_type_signed(D2R_ValueType v) +{ + return d2r_arithmetic_type_from_value_type(v) == D2R_ArithmeticType_Signed; +} + +internal B32 +d2r_is_value_type_integral(D2R_ValueType v) +{ + D2R_ArithmeticType at = d2r_arithmetic_type_from_value_type(v); + return at == D2R_ArithmeticType_Unsigned || at == D2R_ArithmeticType_Signed; +} + +internal B32 +d2r_is_value_type_unsigned(D2R_ValueType v) +{ + return d2r_arithmetic_type_from_value_type(v) == D2R_ArithmeticType_Unsigned; +} + +internal B32 +d2r_is_value_type_float(D2R_ValueType v) +{ + return d2r_arithmetic_type_from_value_type(v) == D2R_ArithmeticType_Float; } internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type) { - switch (value_type) { - case D2R_ValueType_Address: return addr_size; - case D2R_ValueType_U8: return 1; - case D2R_ValueType_U16: return 2; - case D2R_ValueType_U32: return 4; - case D2R_ValueType_U64: return 8; - case D2R_ValueType_U128: return 16; - case D2R_ValueType_U256: return 32; - case D2R_ValueType_U512: return 64; - case D2R_ValueType_S8: return 1; - case D2R_ValueType_S16: return 2; - case D2R_ValueType_S32: return 4; - case D2R_ValueType_S64: return 8; - case D2R_ValueType_S128: return 16; - case D2R_ValueType_S256: return 32; - case D2R_ValueType_S512: return 64; - case D2R_ValueType_F32: return 4; - case D2R_ValueType_F64: return 8; - default: return 0; + if (value_type == D2R_ValueType_Address) { + return addr_size; } + + switch (value_type) { +#define X(_N, _AT, _S) case D2R_ValueType_##_N: return _S; + D2R_ValueType_XList +#undef X + } + + return 0; } internal D2R_ValueType @@ -772,16 +580,16 @@ d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs) return lhs; } // unsigned vs unsigned - else if (D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsUnsigned(rhs)) { + else if (d2r_is_value_type_unsigned(lhs) && d2r_is_value_type_unsigned(rhs)) { return Max(lhs, rhs); } // signed vs signed - else if (D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsSigned(rhs)) { + else if (d2r_is_value_type_signed(lhs) && d2r_is_value_type_signed(rhs)) { return Max(lhs, rhs); } // (unsigned vs signed) || (signed vs unsigned) - else if ((D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsSigned(rhs)) || - (D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsUnsigned(rhs))) { + else if ((d2r_is_value_type_unsigned(lhs) && d2r_is_value_type_signed(rhs)) || + (d2r_is_value_type_signed(lhs) && d2r_is_value_type_unsigned(rhs))) { U64 lhs_size = d2r_size_from_value_type(0, lhs); U64 rhs_size = d2r_size_from_value_type(0, rhs); if (lhs_size < rhs_size) { @@ -793,31 +601,31 @@ d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs) } } // float vs int - else if (D2R_ValueType_IsFloat(lhs) && D2R_ValueType_IsInt(rhs)) { + else if (d2r_is_value_type_float(lhs) && d2r_is_value_type_integral(rhs)) { return lhs; } // int vs float - else if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsFloat(rhs)) { + else if (d2r_is_value_type_integral(lhs) && d2r_is_value_type_float(rhs)) { return rhs; } // float vs float - else if (D2R_ValueType_IsFloat(lhs) && D2R_ValueType_IsFloat(rhs)) { + else if (d2r_is_value_type_float(lhs) && d2r_is_value_type_float(rhs)) { return Max(lhs, rhs); } // address vs int - else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsInt(rhs)) { + else if (lhs == D2R_ValueType_Address && d2r_is_value_type_integral(rhs)) { return D2R_ValueType_Address; } // int vs address - else if (D2R_ValueType_IsInt(lhs) && rhs == D2R_ValueType_Address) { + else if (d2r_is_value_type_integral(lhs) && rhs == D2R_ValueType_Address) { return D2R_ValueType_Address; } // address vs float - else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsFloat(rhs)) { + else if (lhs == D2R_ValueType_Address && d2r_is_value_type_float(rhs)) { return D2R_ValueType_Generic; } // float vs address - else if (D2R_ValueType_IsFloat(lhs) && rhs == D2R_ValueType_Address) { + else if (d2r_is_value_type_float(lhs) && rhs == D2R_ValueType_Address) { return D2R_ValueType_Generic; } // no conversion for implicit value @@ -828,6 +636,40 @@ d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs) return D2R_ValueType_Generic; } +internal RDI_EvalTypeGroup +d2r_value_type_to_rdi(D2R_ValueType v) +{ + if (v == D2R_ValueType_Generic) { + return RDI_EvalTypeGroup_Other; + } + + if (v == D2R_ValueType_Address) { + return RDI_EvalTypeGroup_U; + } + + if (d2r_is_value_type_unsigned(v)) { + return RDI_EvalTypeGroup_U; + } + + if (d2r_is_value_type_signed(v)) { + return RDI_EvalTypeGroup_S; + } + + if (d2r_is_value_type_float(v)) { + if (v == D2R_ValueType_F16) { NotImplemented; } + else if (v == D2R_ValueType_F32) { return RDI_EvalTypeGroup_F32; } + else if (v == D2R_ValueType_F48) { NotImplemented; } + else if (v == D2R_ValueType_F64) { return RDI_EvalTypeGroup_F64; } + else if (v == D2R_ValueType_F80) { return RDI_EvalTypeGroup_F80; } + else if (v == D2R_ValueType_F96) { NotImplemented; } + else if (v == D2R_ValueType_F128) { return RDI_EvalTypeGroup_F128; } + else { InvalidPath; } + } + + InvalidPath; + return RDI_EvalTypeGroup_Other; +} + internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc) { @@ -858,12 +700,12 @@ d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecod D2R_ValueType rhs = d2r_value_type_stack_pop(stack); D2R_ValueType lhs = d2r_value_type_stack_pop(stack); D2R_ValueType common_type; - if (D2R_ValueType_IsInt(lhs) && rhs == D2R_ValueType_Address) { + if (d2r_is_value_type_integral(lhs) && rhs == D2R_ValueType_Address) { rdim_bytecode_push_op(arena, bc, RDI_EvalOp_Swap, 0); rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(lhs), RDI_EvalTypeGroup_U); rdim_bytecode_push_op(arena, bc, RDI_EvalOp_Swap, 0); common_type = D2R_ValueType_Address; - } else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsInt(rhs)) { + } else if (lhs == D2R_ValueType_Address && d2r_is_value_type_integral(rhs)) { rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(rhs), RDI_EvalTypeGroup_U); common_type = D2R_ValueType_Address; } else { @@ -874,35 +716,32 @@ d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecod } internal RDIM_EvalBytecode -d2r_bytecode_from_expression(Arena *arena, - DW_Input *input, - U64 image_base, - U64 address_size, - Arch arch, - DW_ListUnit *addr_lu, - String8 raw_expr, - DW_CompUnit *cu, +d2r_bytecode_from_expression(Arena *arena, + DW_Input *input, + U64 image_base, + Arch arch, + DW_ListUnit *addr_lu, + String8 raw_expr, + DW_CompUnit *cu, D2R_ValueType *result_type_out) { Temp scratch = scratch_begin(&arena, 1); - Temp arena_restore_point = temp_begin(arena); - + Temp temp = temp_begin(arena); + B32 is_ok = 0; + RDIM_EvalBytecode bc = {0}; - DW_Expr expr = dw_expr_from_data(scratch.arena, cu->format, address_size, raw_expr); + DW_Expr expr = dw_expr_from_data(scratch.arena, cu->format, cu->address_size, raw_expr); D2R_ValueTypeStack *stack = push_array(scratch.arena, D2R_ValueTypeStack, 1); RDIM_EvalBytecodeOp **converted_insts = push_array(scratch.arena, RDIM_EvalBytecodeOp *, expr.count); - B32 is_ok = 1; U64 inst_idx = 0; for EachNode(inst, DW_ExprInst, expr.first) { RDIM_EvalBytecodeOp *last_op = bc.last_op; U64 pop_count = dw_pop_count_from_expr_op(inst->opcode); if (pop_count > stack->count) { - // TODO: report error Assert(!"not enough values on the stack to evaluate instruction"); - is_ok = 0; - break; + goto exit; } switch (inst->opcode) { @@ -962,13 +801,14 @@ d2r_bytecode_from_expression(Arena *arena, d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); } break; case DW_ExprOp_Addr: { - if (inst->operands[0].u64 >= image_base) { - U64 voff = inst->operands[0].u64 - image_base; - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } else { - is_ok = 0; + if (inst->operands[0].u64 < image_base) { + Assert(!"invalid address"); + goto exit; } + + U64 voff = inst->operands[0].u64 - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); } 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: @@ -996,7 +836,24 @@ d2r_bytecode_from_expression(Arena *arena, RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, inst->operands[0].u64); U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); - d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); + D2R_ValueType value_type; + if (arch == Arch_x64) { + if (reg_code_rdi == RDI_RegCodeX64_st0 || + reg_code_rdi == RDI_RegCodeX64_st1 || + reg_code_rdi == RDI_RegCodeX64_st2 || + reg_code_rdi == RDI_RegCodeX64_st3 || + reg_code_rdi == RDI_RegCodeX64_st4 || + reg_code_rdi == RDI_RegCodeX64_st5 || + reg_code_rdi == RDI_RegCodeX64_st6 || + reg_code_rdi == RDI_RegCodeX64_st7) { + value_type = d2r_float_type_from_bit_size(reg_size); + } else { + value_type = d2r_unsigned_value_type_from_bit_size(reg_size); + } + } else { + value_type = d2r_unsigned_value_type_from_bit_size(reg_size); + } + d2r_value_type_stack_push(scratch.arena, stack, value_type); } break; case DW_ExprOp_ImplicitValue: { if (inst->operands[0].block.size <= sizeof(U64)) { @@ -1006,7 +863,8 @@ d2r_bytecode_from_expression(Arena *arena, d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(inst->operands[0].block.size * 8)); } else { // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp - NotImplemented; + Assert(!"TODO:"); + goto exit; } } break; case DW_ExprOp_Piece: { @@ -1027,8 +885,8 @@ d2r_bytecode_from_expression(Arena *arena, rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, inst->operands[0].u64); d2r_value_type_stack_push(scratch.arena, stack, n->type); } else { - // TODO: report error - AssertAlways(!"out of bounds pick"); + Assert(!"out of bounds pick"); + goto exit; } } break; case DW_ExprOp_Over: { @@ -1036,8 +894,8 @@ d2r_bytecode_from_expression(Arena *arena, rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); d2r_value_type_stack_push(scratch.arena, stack, stack->top->next->type); } else { - // TODO: report error - AssertAlways(!"out of bounds over"); + Assert(!"out of bounds over"); + goto exit; } } break; case DW_ExprOp_PlusUConst: { @@ -1053,21 +911,33 @@ d2r_bytecode_from_expression(Arena *arena, U16 cursor = 0; U64 inst_count = 0; for (DW_ExprInst *i = skip_fwd ? inst : inst->prev; i != 0 && cursor < delta; i = skip_fwd ? inst->next : inst->prev) { - cursor += inst->size; + cursor += i->size; inst_count += 1; } + + if (cursor != delta) { Assert(!"skip landed in middle of an instruction"); goto exit; } + if (inst_count > min_S16) { Assert(!"operand overflow"); goto exit; } + if (inst_idx > max_U32) { Assert(!"index overflow"); goto exit; } - // TODO: report error (skip does not land on first byte of an instruction) - AssertAlways(cursor == delta); - // TODO: report overflow - AssertAlways(inst_count <= min_S16); - AssertAlways(inst_idx <= max_U32); - - U64 imm = Compose64Bit(inst_idx, skip_fwd ? (S16)inst_count : -(S16)inst_count); + U64 imm = Compose64Bit(inst_idx, skip_fwd ? (S16)inst_count : (U16)(-(S16)inst_count)); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, imm); } break; case DW_ExprOp_Bra: { - NotImplemented; + B32 skip_fwd = inst->operands[0].s16 >= 0; + U16 delta = abs_s64(inst->operands[0].s16); + U16 cursor = 0; + U64 inst_count = 0; + for (DW_ExprInst *i = skip_fwd ? inst->next : inst->prev; i != 0 && cursor < delta; i = skip_fwd ? inst->next : inst->prev) { + cursor += i->size; + inst_count += 1; + } + + if (cursor != delta) { Assert(!"cond landed in middle of an instruction"); goto exit; } + if (inst_count > min_S16) { Assert(!"operand overflow"); goto exit; } + if (inst_idx > max_U32) { Assert(!"index overflow"); goto exit; } + + U64 imm = Compose64Bit(inst_idx, skip_fwd ? inst_count : (U16)(-(S16)inst_count)); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Cond, imm); } 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: @@ -1111,46 +981,47 @@ d2r_bytecode_from_expression(Arena *arena, } break; case DW_ExprOp_Deref: { D2R_ValueType address_type = d2r_value_type_stack_pop(stack); - if (address_type != D2R_ValueType_Address && !D2R_ValueType_IsInt(address_type)) { - // TODO: report error + if (address_type != D2R_ValueType_Address && !d2r_is_value_type_integral(address_type)) { Assert(!"value must be of integral type"); - break; + goto exit; } - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, cu->address_size); d2r_value_type_stack_push(scratch.arena, stack, address_type); } break; case DW_ExprOp_DerefSize: { D2R_ValueType address_type = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(address_type) && address_type != D2R_ValueType_Address ) { - // TODO: report error + if (!d2r_is_value_type_integral(address_type) && address_type != D2R_ValueType_Address ) { Assert(!"value must be of integral type"); - break; + goto exit; } U8 deref_size_in_bytes = inst->operands[0].u64; - if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { + if (0 < deref_size_in_bytes && deref_size_in_bytes <= cu->address_size) { rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); } else { - // TODO: error handling - AssertAlways(!"ill formed expression"); + Assert(!"ill formed expression"); + goto exit; } d2r_value_type_stack_push(scratch.arena, stack, address_type); } break; case DW_ExprOp_XDeref: { - // TODO: error handling - AssertAlways(!"multiple address spaces are not supported"); + Assert(!"multiple address spaces are not supported"); + goto exit; + } break; + case DW_ExprOp_XDerefSize: { + Assert(!"no suitable conversion"); + goto exit; } break; - // TODO: error handling - case DW_ExprOp_XDerefSize: { AssertAlways(!"no suitable conversion"); } break; case DW_ExprOp_Call2: case DW_ExprOp_Call4: case DW_ExprOp_CallRef: { - // TODO: error handling - AssertAlways(!"calls are not supported"); + Assert(!"calls are not supported"); + goto exit; } break; case DW_ExprOp_ImplicitPointer: case DW_ExprOp_GNU_ImplicitPointer: { - // TODO: - AssertAlways(!"sample"); + // TODO: RDI does not support encoding of implicit pointers + //Assert(!"TODO: implicit pointer"); + goto exit; } break; case DW_ExprOp_Convert: case DW_ExprOp_GNU_Convert: { @@ -1165,41 +1036,48 @@ d2r_bytecode_from_expression(Arena *arena, out = D2R_ValueType_Generic; } else { // find ref tag - DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, inst->operands[0].u64); - DW_Tag tag = tag_node->tag; + U64 ref_tag_info_off = cu->info_range.min + inst->operands[0].u64; + DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, ref_tag_info_off); + if (tag_node == 0) { + Assert(!"invalid .debug_info offset"); + goto exit; + } + + DW_Tag tag = tag_node->tag; if (tag.kind == DW_TagKind_BaseType) { // extract encoding attribute DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - + // DW_ATE -> RDI_EvalTypeGroup switch (encoding) { - case DW_ATE_Null: { - out = D2R_ValueType_Generic; - } break; - case DW_ATE_Address: { - out = D2R_ValueType_Address; - } break; - case DW_ATE_Boolean: { - out = D2R_ValueType_S8; - } break; - case DW_ATE_SignedChar: - case DW_ATE_Signed: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_signed_value_type_from_bit_size(byte_size * 8); - } break; - case DW_ATE_UnsignedChar: - case DW_ATE_Unsigned: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_unsigned_value_type_from_bit_size(byte_size * 8); - } break; - case DW_ATE_Float: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_float_type_from_bit_size(byte_size * 8); - } break; - default: InvalidPath; break; + case DW_ATE_Null: { + out = D2R_ValueType_Generic; + } break; + case DW_ATE_Address: { + out = D2R_ValueType_Address; + } break; + case DW_ATE_Boolean: { + out = D2R_ValueType_S8; + } break; + case DW_ATE_SignedChar: + case DW_ATE_Signed: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_signed_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_UnsignedChar: + case DW_ATE_Unsigned: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_unsigned_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_Float: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_float_type_from_bit_size(byte_size * 8); + } break; + default: InvalidPath; break; } } else { - AssertAlways(!"unexpected tag"); // TODO: error handling + Assert(!"unexpected tag"); + goto exit; } } @@ -1207,20 +1085,27 @@ d2r_bytecode_from_expression(Arena *arena, d2r_value_type_stack_push(scratch.arena, stack, out); rdim_bytecode_push_convert(arena, &bc, d2r_value_type_to_rdi(in), d2r_value_type_to_rdi(out)); } break; - // TODO: - case DW_ExprOp_GNU_ParameterRef: { AssertAlways(!"sample"); } break; - // TODO: + case DW_ExprOp_GNU_ParameterRef: { + Assert(!"TODO: sample"); + goto exit; + } case DW_ExprOp_DerefType: - case DW_ExprOp_GNU_DerefType: { AssertAlways(!"sample"); } break; - // TODO: + case DW_ExprOp_GNU_DerefType: { + goto exit; + } case DW_ExprOp_ConstType: - case DW_ExprOp_GNU_ConstType: { AssertAlways(!"sample"); } break; - // TODO: - case DW_ExprOp_RegvalType: { AssertAlways(!"sample"); } break; + case DW_ExprOp_GNU_ConstType: { + Assert(!"TODO: sample"); + goto exit; + } + case DW_ExprOp_RegvalType: { + Assert(!"sample"); + goto exit; + } case DW_ExprOp_EntryValue: case DW_ExprOp_GNU_EntryValue: { D2R_ValueType call_site_result_type = 0; - RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, inst->operands[0].block, cu, &call_site_result_type); + RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, arch, addr_lu, inst->operands[0].block, cu, &call_site_result_type); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, safe_cast_u32(call_site_bc.encoded_size)); rdim_bytecode_concat_in_place(&bc, &call_site_bc); @@ -1235,12 +1120,12 @@ d2r_bytecode_from_expression(Arena *arena, rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); } else { - // TODO: error handling - AssertAlways(!"unable to relocate address"); + Assert(!"unable to relocate address"); + goto exit; } } else { - // TODO: error handling - AssertAlways(!"out of bounds index"); + Assert(!"out of bounds index"); + goto exit; } } break; case DW_ExprOp_CallFrameCfa: { @@ -1248,8 +1133,9 @@ d2r_bytecode_from_expression(Arena *arena, d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); } break; case DW_ExprOp_PushObjectAddress: { - AssertAlways(!"sample"); - } break; + Assert(!"TODO: sample"); + goto exit; + } case DW_ExprOp_Nop: {} break; case DW_ExprOp_Eq: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_EqEq); } break; case DW_ExprOp_Ge: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_GrEq); } break; @@ -1268,57 +1154,51 @@ d2r_bytecode_from_expression(Arena *arena, case DW_ExprOp_Shr: { D2R_ValueType rhs = d2r_value_type_stack_pop(stack); D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (D2R_ValueType_IsInt(rhs) && D2R_ValueType_IsInt(lhs)) { + if (d2r_is_value_type_integral(rhs) && d2r_is_value_type_integral(lhs)) { D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); - D2R_ValueType result_type = d2r_unsigned_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + D2R_ValueType result_type = d2r_unsigned_value_type_from_bit_size(d2r_size_from_value_type((cu->address_size), common_type) * 8); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); d2r_value_type_stack_push(scratch.arena, stack, result_type); } else { - // TODO: report error - AssertAlways(!"operands must be of integral type"); + Assert(!"operands must be of integral type"); + goto exit; } } break; case DW_ExprOp_Shra: { D2R_ValueType rhs = d2r_value_type_stack_pop(stack); D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsInt(rhs)) { + if (d2r_is_value_type_integral(lhs) && d2r_is_value_type_integral(rhs)) { D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); - D2R_ValueType result_type = d2r_signed_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + D2R_ValueType result_type = d2r_signed_value_type_from_bit_size(d2r_size_from_value_type((cu->address_size), common_type) * 8); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); d2r_value_type_stack_push(scratch.arena, stack, result_type); } else { - // TODO: report error - AssertAlways(!"operands must be of integral type"); + Assert(!"operands must be of integral type"); + goto exit; } } break; case DW_ExprOp_Mod: { D2R_ValueType rhs = d2r_value_type_stack_pop(stack); D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(rhs) || !D2R_ValueType_IsInt(lhs)) { - // TODO: report error - AssertAlways(!"operands must be of integral type"); - is_ok = 0; - break; + if (!d2r_is_value_type_integral(rhs) || !d2r_is_value_type_integral(lhs)) { + Assert(!"operands must be of integral type"); + goto exit; } D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, d2r_value_type_to_rdi(common_type)); d2r_value_type_stack_push(scratch.arena, stack, common_type); } break; case DW_ExprOp_Abs: { - if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack)) && !D2R_ValueType_IsFloat(d2r_value_type_stack_peek(stack))) { - // TODO: report error - AssertAlways(!"operand must be of integral type or float"); - is_ok = 0; - break; + if (!d2r_is_value_type_integral(d2r_value_type_stack_peek(stack)) && !d2r_is_value_type_float(d2r_value_type_stack_peek(stack))) { + Assert(!"operand must be of integral type or float"); + goto exit; } rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); } break; case DW_ExprOp_Neg: { - if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack))) { - // TODO: report error - AssertAlways(!"operand must be of integral type"); - is_ok = 0; - break; + if (!d2r_is_value_type_integral(d2r_value_type_stack_peek(stack))) { + Assert(!"operand must be of integral type"); + goto exit; } rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); } break; @@ -1329,7 +1209,10 @@ d2r_bytecode_from_expression(Arena *arena, rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 0); d2r_value_type_stack_push(scratch.arena, stack, d2r_value_type_stack_peek(stack)); } break; - case DW_ExprOp_Rot: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Rot: { + Assert(!"no suitable conversion"); + goto exit; + } case DW_ExprOp_Swap: { D2R_ValueType a = d2r_value_type_stack_pop(stack); D2R_ValueType b = d2r_value_type_stack_pop(stack); @@ -1350,9 +1233,9 @@ d2r_bytecode_from_expression(Arena *arena, case DW_ExprOp_FormTlsAddress: case DW_ExprOp_GNU_PushTlsAddress: { D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(lhs)) { - // TODO: report error - AssertAlways(!"lhs must be of integral type"); + if (!d2r_is_value_type_integral(lhs)) { + Assert(!"lhs must be of integral type"); + goto exit; } rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(lhs)); @@ -1361,9 +1244,8 @@ d2r_bytecode_from_expression(Arena *arena, case DW_ExprOp_GNU_UnInit: { // TODO: flag value as unitialized; this must be last opcode; possible to use with DW_ExprOp_Piece; } break; - default: InvalidPath; break; + default: goto exit; } - if (!is_ok) { break; } // store converted instruction if (last_op != bc.last_op) { @@ -1374,73 +1256,74 @@ d2r_bytecode_from_expression(Arena *arena, inst_idx += 1; } - if (is_ok) { - // fixup bytecode - for EachNode(op, RDIM_EvalBytecodeOp, bc.first_op) { - if (op->op == RDI_EvalOp_Skip) { - // unpack skip info - U32 inst_idx = Extract32(op->p, 0); - S16 skip_count_signed = (S16)Extract32(op->p, 1); - U16 skip_count = abs_s64(skip_count_signed); - B32 skip_fwd = skip_count_signed > 0; - - // setup being/end links - RDIM_EvalBytecodeOp *begin = 0, *end = 0; - if (skip_fwd) { - if (inst_idx + skip_count <= expr.count) { - begin = converted_insts[inst_idx]; - end = (inst_idx + skip_count) < expr.count ? converted_insts[inst_idx + skip_count] : 0; - } else { - // TODO: report error - AssertAlways(!"out of bounds skip"); - } + // fixup bytecode jumps + for EachNode(op, RDIM_EvalBytecodeOp, bc.first_op) { + if (op->op == RDI_EvalOp_Skip || op->op == RDI_EvalOp_Cond) { + // unpack skip info + U32 inst_idx = Extract32(op->p, 1); + S16 skip_count_signed = (S16)Extract32(op->p, 0); + U16 skip_count = abs_s64(skip_count_signed); + B32 skip_fwd = skip_count_signed > 0; + + // setup being/end links + RDIM_EvalBytecodeOp *begin = 0, *end = 0; + if (skip_fwd) { + if (inst_idx + skip_count <= expr.count) { + begin = converted_insts[inst_idx]; + end = (inst_idx + skip_count) < expr.count ? converted_insts[inst_idx + skip_count] : 0; } else { - if (skip_count <= inst_idx) { - begin = converted_insts[inst_idx - skip_count]; - end = converted_insts[inst_idx]; - } else { - // TODO: report error - AssertAlways(!"out of bounds skip"); - } + Assert(!"out of bounds skip"); + goto exit; } - - // compute skip delta - U64 skip_delta = 0; - for (RDIM_EvalBytecodeOp *n = begin; n != end; n = n->next) { - skip_delta += n->p_size; + } else { + if (skip_count <= inst_idx) { + begin = converted_insts[inst_idx - skip_count]; + end = converted_insts[inst_idx]; + } else { + Assert(!"out of bounds skip"); + goto exit; } - - // rewrite skip operand with byte delta - AssertAlways(skip_delta <= max_S16); - op->p = skip_fwd ? (S16)skip_delta : -(S16)skip_delta; } + + // compute skip delta + U64 skip_delta = 0; + for (RDIM_EvalBytecodeOp *n = begin; n != end; n = n->next) { + skip_delta += n->p_size; + } + + // rewrite skip operand with byte delta + AssertAlways(skip_delta <= max_S16); + op->p = skip_fwd ? (S16)skip_delta : -(S16)skip_delta; } - - if (result_type_out) { - *result_type_out = d2r_value_type_stack_peek(stack); - } - } else { - MemoryZeroStruct(&bc); - temp_end(arena_restore_point); } + if (result_type_out) { + *result_type_out = d2r_value_type_stack_peek(stack); + } + + is_ok = 1; +exit:; + if (!is_ok) { + MemoryZeroStruct(&bc); + temp_end(temp); + } scratch_end(scratch); return bc; } internal RDIM_Location * -d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr) +d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr) { RDIM_Location *loc = 0; if (expr.size) { D2R_ValueType result_type = 0; - RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &result_type); + RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, arch, addr_lu, expr, cu, &result_type); RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); loc_info->kind = result_type == D2R_ValueType_Address ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bytecode; - loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); + loc = rdim_location_chunk_list_push_new(arena, locations, D2R_LOCATIONS_CAP, loc_info); } return loc; } @@ -1449,7 +1332,7 @@ internal RDIM_Location * d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind) { String8 expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, kind); - RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, arch, cu->addr_lu, cu, expr); return location; } @@ -1479,7 +1362,7 @@ d2r_locset_from_attrib(Arena *arena, // convert location list to RDIM location set for EachNode(loc_n, DW_LocNode, loclist.first) { - RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, loc_n->v.expr); + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, arch, cu->addr_lu, cu, loc_n->v.expr); RDIM_Rng1U64 voff_range = { .min = loc_n->v.range.min - image_base, .max = loc_n->v.range.max - image_base }; rdim_push_location_case(arena, scopes, &locset, location, voff_range); } @@ -1490,12 +1373,12 @@ d2r_locset_from_attrib(Arena *arena, String8 expr = dw_exprloc_from_attrib(input, cu, attrib); // convert expression and inherit life-time ranges from enclosed scope - RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, arch, cu->addr_lu, cu, expr); for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { rdim_push_location_case(arena, scopes, &locset, location, range_n->v); } } else if (attrib_class != DW_AttribClass_Null) { - AssertAlways(!"unexpected attrib class"); + log_user_errorf("unexpected attrib class @ .debug_info+%llx", tag.info_off); } return locset; @@ -1518,8 +1401,8 @@ d2r_var_locset_from_tag(Arena *arena, B32 has_location = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Location); if (has_const_value && has_location) { - // TODO: error handling - AssertAlways(!"unexpected variable encoding"); + log_user_errorf("unexpected variable encoding @ .debug_info+%llx", tag.info_off); + return locset; } if (has_const_value) { @@ -1534,7 +1417,7 @@ d2r_var_locset_from_tag(Arena *arena, RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); loc_info->kind = RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bc; - RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, D2R_LOCATIONS_CAP, loc_info); // push location cases for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { @@ -1547,140 +1430,62 @@ d2r_var_locset_from_tag(Arena *arena, return locset; } -internal D2R_CompUnitContribMap -d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) +internal RDIM_Type * +d2r_create_type(Arena *arena, D2R_TypeTable *type_table) { - Temp scratch = scratch_begin(&arena, 1); + RDIM_Type *type = rdim_type_chunk_list_push(arena, type_table->types, type_table->type_chunk_cap); + return type; +} + +internal RDIM_Type * +d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) +{ + RDIM_Type *type = d2r_create_type(arena, type_table); + Assert(hash_table_search_u64_raw(type_table->ht, info_off) == 0); + hash_table_push_u64_raw(arena, type_table->ht, info_off, type); + return type; +} + +internal RDIM_Type * +d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off) +{ + RDIM_Type *type = hash_table_search_u64_raw(type_table->ht, info_off); + if (type == 0) { + type = type_table->builtin_types[RDI_TypeKind_NULL]; + } + return type; +} + +internal RDIM_Type * +d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_Void]; - String8 aranges_data = input->sec[DW_Section_ARanges].data; - Rng1U64List unit_range_list = dw_unit_ranges_from_data(scratch.arena, aranges_data); + // find attrib + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); - D2R_CompUnitContribMap cm = {0}; - cm.count = 0; - cm.info_off_arr = push_array(arena, U64, unit_range_list.count); - cm.voff_range_arr = push_array(arena, RDIM_Rng1U64ChunkList, unit_range_list.count); - - for EachNode(range_n, Rng1U64Node, unit_range_list.first) { - String8 unit_data = str8_substr(aranges_data, range_n->v); - U64 unit_cursor = 0; + // does tag have this attribute? + if (attrib->attrib_kind == kind) { + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - U64 unit_length = 0; - U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, unit_cursor, &unit_length); - if (unit_length_size == 0) { continue; } - unit_cursor += unit_length_size; - - DW_Version version = 0; - U64 version_size = str8_deserial_read_struct(unit_data, unit_cursor, &version); - if (version_size == 0) { continue; } - unit_cursor += version; - - if (version != DW_Version_2) { - AssertAlways(!"unknown .debug_aranges version"); - continue; - } - - DW_Format unit_format = DW_FormatFromSize(unit_length); - U64 cu_info_off = 0; - U64 cu_info_off_size = str8_deserial_read_dwarf_uint(unit_data, unit_cursor, unit_format, &cu_info_off); - if (cu_info_off_size == 0) { continue; } - unit_cursor += cu_info_off_size; - - U8 address_size = 0; - U64 address_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &address_size); - if (address_size_size == 0) { continue; } - unit_cursor += address_size_size; - - U8 segment_selector_size = 0; - U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &segment_selector_size); - if (segment_selector_size_size == 0) { continue; } - unit_cursor += segment_selector_size_size; - - U64 tuple_size = address_size * 2 + segment_selector_size; - U64 bytes_too_far_past_boundary = unit_cursor % tuple_size; - if (bytes_too_far_past_boundary > 0) { - unit_cursor += tuple_size - bytes_too_far_past_boundary; - } - - RDIM_Rng1U64ChunkList voff_ranges = {0}; - if (segment_selector_size == 0) { - while (unit_cursor + address_size * 2 <= unit_data.size) { - U64 address = 0; - U64 length = 0; - unit_cursor += str8_deserial_read(unit_data, unit_cursor, &address, address_size, address_size); - unit_cursor += str8_deserial_read(unit_data, unit_cursor, &length, address_size, address_size); - - if (address == 0 && length == 0) { break; } - if (address == 0) { continue; } - - // TODO: error handling - AssertAlways(address >= image_base); - - U64 min = address - image_base; - U64 max = min + length; - rdim_rng1u64_chunk_list_push(arena, &voff_ranges, 256, (RDIM_Rng1U64){.min = min, .max = max}); + if (value_class == DW_AttribClass_Reference) { + // resolve reference + DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); + + if (ref.cu == cu) { + // find type + type = d2r_type_from_offset(type_table, ref.info_off); + } else { + NotImplemented; } } else { - // TODO: segment relative addressing - NotImplemented; + log_user_errorf("unexpected attrib class @ .debug_info+%llx", tag.info_off); } - - U64 map_idx = cm.count++; - cm.info_off_arr[map_idx] = cu_info_off; - cm.voff_range_arr[map_idx] = voff_ranges; } - scratch_end(scratch); - return cm; + return type; } -//////////////////////////////// -//~ rjf: Compilation Unit / Scope Conversion Helpers - -internal RDIM_Rng1U64ChunkList -d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) -{ - RDIM_Rng1U64ChunkList voff_ranges = {0}; - U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); - if (voff_list_idx < map.count) { - voff_ranges = map.voff_range_arr[voff_list_idx]; - } - return voff_ranges; -} - -internal RDIM_Scope * -d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges) -{ - // fill out scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, scopes, scope_chunk_cap); - - // push ranges - for EachNode(i, Rng1U64Node, ranges.first) { - rdim_scope_push_voff_range(arena, scopes, scope, (RDIM_Rng1U64){.min = i->v.min, i->v.max}); - } - - // associate scope with tag - tag_stack->scope = scope; - - // update scope hierarchy - DW_TagKind parent_tag_kind = tag_stack->next->node->tag.kind; - if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine || parent_tag_kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *parent = tag_stack->next->scope; - - scope->parent_scope = parent; - scope->symbol = parent->symbol; - - if (parent->last_child) { - parent->last_child->next_sibling = scope; - } - SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); - } - - return scope; -} - -//////////////////////////////// -//~ rjf: Main Conversion Entry Point - internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root) { @@ -1688,8 +1493,7 @@ d2r_tag_iterator_init(Arena *arena, DW_TagNode *root) iter->free_list = 0; iter->stack = push_array(arena, D2R_TagFrame, 1); iter->stack->node = push_array(arena, DW_TagNode, 1); - if(root != 0) - { + if (root != 0) { *iter->stack->node = *root; } iter->stack->node->sibling = 0; @@ -1762,7 +1566,7 @@ d2r_is_type_tag_converted(DW_TagNode *tag_node) } internal RDIM_Type * -d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_Tag tag, DW_AttribKind kind) +d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, DW_Tag tag, DW_AttribKind kind) { RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_Void]; @@ -1777,27 +1581,27 @@ d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *inpu // resolve reference DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); - // TODO: support for external compile unit references - AssertAlways(ref.cu == cu); - - // find type - type = d2r_type_from_offset(type_table, ref.info_off); - - // was type converted? - if (type == 0) { - // issue type conversion - DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); - d2r_convert_types(arena, type_table, input, cu, cu_lang, arch_addr_size, ref_node); - - // if we do not have a converted type at this point then debug info is malformed + if (ref.cu == cu) { + // find type type = d2r_type_from_offset(type_table, ref.info_off); - if(type == 0) - { - type = type_table->builtin_types[RDI_TypeKind_NULL]; + + // was type converted? + if (type == 0) { + // issue type conversion + DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); + d2r_convert_types(arena, type_table, input, cu, cu_lang, ref_node); + + // if we do not have a converted type at this point then debug info is malformed + type = d2r_type_from_offset(type_table, ref.info_off); + if (type == 0) { + type = type_table->builtin_types[RDI_TypeKind_NULL]; + } } + } else { + NotImplemented; } } else { - Assert(!"unexpected attrib class"); + log_user_errorf("unexpected attrib class @ .debug_info+%llx", tag.info_off); } } @@ -1810,7 +1614,6 @@ d2r_convert_types(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, - U64 arch_addr_size, DW_TagNode *root) { Temp scratch = scratch_begin(&arena, 1); @@ -1836,7 +1639,7 @@ d2r_convert_types(Arena *arena, Assert(!tag_node->first_child); d2r_tag_iterator_skip_children(it); } else { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); type->kind = RDI_TypeKind_Class; @@ -1851,9 +1654,11 @@ d2r_convert_types(Arena *arena, type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); type->kind = RDI_TypeKind_IncompleteStruct; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); + if (tag_node->first_child) { + d2r_tag_iterator_skip_children(it); + } else { + log_user_errorf("childless struct @ .debug_info+%llx", tag.info_off); + } } else { RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); @@ -1868,9 +1673,11 @@ d2r_convert_types(Arena *arena, type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); type->kind = RDI_TypeKind_IncompleteUnion; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); + if (tag_node->first_child) { + d2r_tag_iterator_skip_children(it); + } else { + log_user_errorf("childless union @ .debug_info+%llx", tag.info_off); + } } else { RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); @@ -1884,11 +1691,13 @@ d2r_convert_types(Arena *arena, RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); type->kind = RDI_TypeKind_IncompleteEnum; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); + if (tag_node->first_child) { + d2r_tag_iterator_skip_children(it); + } else { + log_user_errorf("childless enum @ .debug_info+%llx", tag.info_off); + } } else { - RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); type->kind = RDI_TypeKind_Enum; @@ -1897,7 +1706,7 @@ d2r_convert_types(Arena *arena, } } break; case DW_TagKind_SubroutineType: { - RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); // collect parameters RDIM_TypeList param_list = {0}; @@ -1908,15 +1717,14 @@ d2r_convert_types(Arena *arena, } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); + log_user_errorf("unexpected tag @ .debug_info+%llx", tag.info_off); } } // init proceudre type RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; + type->byte_size = cu->address_size; type->direct_type = ret_type; type->count = param_list.count; type->param_types = rdim_array_from_type_list(arena, param_list); @@ -1924,7 +1732,7 @@ d2r_convert_types(Arena *arena, d2r_tag_iterator_skip_children(it); } break; case DW_TagKind_Typedef: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); @@ -1952,7 +1760,7 @@ d2r_convert_types(Arena *arena, case 8: kind = RDI_TypeKind_ComplexF64; break; case 10: kind = RDI_TypeKind_ComplexF80; break; case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_Float: { @@ -1962,7 +1770,7 @@ d2r_convert_types(Arena *arena, case 6: kind = RDI_TypeKind_F48; break; case 8: kind = RDI_TypeKind_F64; break; case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_Signed: { @@ -1974,7 +1782,7 @@ d2r_convert_types(Arena *arena, case 16: kind = RDI_TypeKind_S128; break; case 32: kind = RDI_TypeKind_S256; break; case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_SignedChar: { @@ -1982,7 +1790,7 @@ d2r_convert_types(Arena *arena, case 1: kind = RDI_TypeKind_Char8; break; case 2: kind = RDI_TypeKind_Char16; break; case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_Unsigned: { @@ -1994,7 +1802,7 @@ d2r_convert_types(Arena *arena, case 16: kind = RDI_TypeKind_U128; break; case 32: kind = RDI_TypeKind_U256; break; case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_UnsignedChar: { @@ -2002,7 +1810,7 @@ d2r_convert_types(Arena *arena, case 1: kind = RDI_TypeKind_UChar8; break; case 2: kind = RDI_TypeKind_UChar16; break; case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + default: log_user_errorf("unexpected size"); break; } } break; case DW_ATE_ImaginaryFloat: { @@ -2035,7 +1843,7 @@ d2r_convert_types(Arena *arena, case DW_ATE_Ascii: { NotImplemented; } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + default: log_user_errorf("unexpected base type encoding"); break; } RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); @@ -2045,17 +1853,26 @@ d2r_convert_types(Arena *arena, type->byte_size = byte_size; } break; case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - // TODO(rjf): this is not an invalid case; it shows up in `mule_main` pointer types - // Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)) { + log_infof("TODO: handle allocated attrib @ .debug_info+%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)) { + log_infof("TODO: handle associated attrib @ .debug_info%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)) { + log_infof("TODO: handle alignment attrib @ .debug_info+%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)) { + log_infof("TODO: handle name attrib @ .debug_info+%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)) { + log_infof("TODO: handle address class attrib @ .debug_info+%llx", tag.info_off); + } - U64 byte_size = arch_addr_size; + U64 byte_size = cu->address_size; if (cu->version == DW_Version_5 || cu->relaxed) { dw_try_byte_size_from_tag(input, cu, tag, &byte_size); } @@ -2067,36 +1884,44 @@ d2r_convert_types(Arena *arena, } break; case DW_TagKind_RestrictType: { // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)) { + log_infof("TODO: handle alignment attrib @ .debug_info+%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)) { + log_infof("TODO: handle name attrib @ .debug_info+%llx", tag.info_off); + } - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; + type->byte_size = cu->address_size; type->flags = RDI_TypeModifierFlag_Restrict; type->direct_type = direct_type; } break; case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)) { + log_infof("TODO: handle name attrib @ .debug_info+%llx", tag.info_off); + } - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; + type->byte_size = cu->address_size; type->flags = RDI_TypeModifierFlag_Volatile; type->direct_type = direct_type; } break; case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)) { + log_infof("TODO: handle name attrib @ .debug_info+%llx", tag.info_off); + } + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)) { + log_infof("TODO: handle alignment attrib @ .debug_info+%llx", tag.info_off); + } - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; + type->byte_size = cu->address_size; type->flags = RDI_TypeModifierFlag_Const; type->direct_type = direct_type; } break; @@ -2129,7 +1954,7 @@ d2r_convert_types(Arena *arena, struct SubrangeNode *subrange_stack = 0; for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { if (n->tag.kind != DW_TagKind_SubrangeType) { - d2r_log("[%llx] while scanning for DW_TagKind_SubrangeType found an unexpected child tag %S @ %llx\n", tag.info_off, dw_string_from_tag_kind(g_d2r_log.arena, n->tag.kind), n->tag.info_off); + log_user_errorf("[%llx] while scanning for DW_TagKind_SubrangeType found an unexpected child tag %S @ %llx\n", tag.info_off, dw_string_from_tag_kind(scratch.arena, n->tag.kind), n->tag.info_off); goto array_type_exit; } @@ -2138,7 +1963,7 @@ d2r_convert_types(Arena *arena, if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { B32 is_vla = dw_is_attrib_var_ref(input, cu, dw_attrib_from_tag(input, cu, n->tag, DW_AttribKind_LowerBound)); if (is_vla) { - d2r_log("[%llx] TODO: lower bound is a variable\n", n->tag.info_off); + log_user_errorf("[%llx] TODO: lower bound is a variable\n", n->tag.info_off); } else { lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); } @@ -2154,7 +1979,7 @@ d2r_convert_types(Arena *arena, } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { B32 is_vla = dw_is_attrib_var_ref(input, cu, dw_attrib_from_tag(input, cu, n->tag, DW_AttribKind_UpperBound)); if (is_vla) { - d2r_log("[%llx] TODO: upper bound is a variable\n", n->tag.info_off); + log_user_errorf("[%llx] TODO: upper bound is a variable\n", n->tag.info_off); goto array_type_exit; } else { upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); @@ -2169,7 +1994,7 @@ d2r_convert_types(Arena *arena, SLLStackPush(subrange_stack, s); } - RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); RDIM_Type *direct_type = array_base_type; U64 size_cursor = array_base_type->byte_size; for EachNode(s, struct SubrangeNode, subrange_stack) { @@ -2199,22 +2024,20 @@ d2r_convert_types(Arena *arena, d2r_tag_iterator_skip_children(it); } break; case DW_TagKind_SubrangeType: { - // TODO: error handling - AssertAlways(!"unexpected tag"); + log_user_errorf("unexpected tag"); } break; case DW_TagKind_Inheritance: { DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); + if (parent_tag.kind == DW_TagKind_StructureType || parent_tag.kind == DW_TagKind_ClassType) { + RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &g_d2r_shared.udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } else { + log_user_errorf("unexpected parent tag"); } - - RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = type; - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); } break; } } @@ -2241,7 +2064,7 @@ d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, R d2r_inline_anonymous_udt_member(arena, top_udt, base_off + curr->off, curr->type->udt); } else { // copy member and adjust its offset relative to inlined position in the root UDT - RDIM_UDTMember *m = rdim_udt_push_member(arena, &udts, top_udt); + RDIM_UDTMember *m = rdim_udt_push_member(arena, &g_d2r_shared.udts, top_udt); *m = *curr; m->off += base_off; } @@ -2254,7 +2077,6 @@ d2r_convert_udts(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, - U64 arch_addr_size, DW_TagNode *root) { Temp scratch = scratch_begin(&arena, 1); @@ -2276,7 +2098,7 @@ d2r_convert_udts(Arena *arena, d2r_tag_iterator_skip_children(it); } else { RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &g_d2r_shared.udts, D2R_UDT_CHUNK_CAP); udt->self_type = type; type->udt = udt; } @@ -2286,7 +2108,7 @@ d2r_convert_udts(Arena *arena, d2r_tag_iterator_skip_children(it); } else { RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &g_d2r_shared.udts, D2R_UDT_CHUNK_CAP); udt->self_type = type; type->udt = udt; } @@ -2307,38 +2129,156 @@ d2r_convert_udts(Arena *arena, if (member_udt == 0) { DW_Language ref_cu_lang = dw_const_u64_from_tag_attrib_kind(input, type_ref.cu, type_ref.cu->tag, DW_AttribKind_Language); DW_TagNode *ref_tag_node = dw_tag_node_from_info_off(type_ref.cu, type_ref.info_off); - d2r_convert_udts(arena, type_table, input, type_ref.cu, ref_cu_lang, arch_addr_size, ref_tag_node); + d2r_convert_udts(arena, type_table, input, type_ref.cu, ref_cu_lang, ref_tag_node); Assert(member_type->udt); member_udt = member_type->udt; } d2r_inline_anonymous_udt_member(arena, parent_type->udt, off, member_udt); } else { - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent_type->udt); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &g_d2r_shared.udts, parent_type->udt); member->kind = RDI_MemberKind_DataField; member->name = name; member->type = type; member->off = off; } } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); + log_user_errorf("unexpected parent tag @ .debug_info+%llx", tag.info_off); } } else if (tag.kind == DW_TagKind_Enumerator) { DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); if (parent_tag.kind == DW_TagKind_EnumerationType) { RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); + RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &g_d2r_shared.udts, parent_type->udt); udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); + log_user_errorf("unexpected parent tag @ .debug_info+%llx", tag.info_off); } } } scratch_end(scratch); } +internal RDIM_Scope * +d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges) +{ + // fill out scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, scopes, scope_chunk_cap); + + // push ranges + for EachNode(i, Rng1U64Node, ranges.first) { + rdim_scope_push_voff_range(arena, scopes, scope, (RDIM_Rng1U64){.min = i->v.min, i->v.max}); + } + + // associate scope with tag + tag_stack->scope = scope; + + // update scope hierarchy + DW_TagKind parent_tag_kind = tag_stack->next->node->tag.kind; + if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine || parent_tag_kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *parent = tag_stack->next->scope; + + scope->parent_scope = parent; + scope->symbol = parent->symbol; + + if (parent->last_child) { + parent->last_child->next_sibling = scope; + } + SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); + } + + return scope; +} + +internal RDIM_Type ** +d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDIM_TypeList list = {0}; + B32 has_vargs = 0; + for (DW_TagNode *i = cur_node->first_child; i != 0; i = i->sibling) { + if (i->tag.kind == DW_TagKind_FormalParameter) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = d2r_type_from_attrib(type_table, input, cu, i->tag, DW_AttribKind_Type); + SLLQueuePush(list.first, list.last, n); + ++list.count; + } else if (i->tag.kind == DW_TagKind_UnspecifiedParameters) { + has_vargs = 1; + } + } + + if (has_vargs) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = type_table->builtin_types[RDI_TypeKind_Variadic]; + SLLQueuePush(list.first, list.last, n); + ++list.count; + } + + // collect params + *param_count_out = list.count; + RDIM_Type **params = rdim_array_from_type_list(arena, list); + + scratch_end(scratch); + return params; +} + +internal Rng1U64List +d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) +{ + // collect non-contiguous range + Rng1U64List raw_ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); + + // exclude invalid ranges caused by linker optimizations + Rng1U64List ranges = {0}; + for (Rng1U64Node *n = raw_ranges.first, *next = 0; n != 0; n = next) { + next = n->next; + if (n->v.min < image_base || n->v.min > n->v.max) { + continue; + } + rng1u64_list_push_node(&ranges, n); + } + + // debase ranges + for EachNode(r, Rng1U64Node, ranges.first) { + r->v.min -= image_base; + r->v.max -= image_base; + } + + // collect contiguous range + { + DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_LowPc); + DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); + if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { + U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); + + U64 hi_pc = 0; + DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); + if (hi_pc_class == DW_AttribClass_Address) { + hi_pc = dw_address_from_attrib(input, cu, hi_pc_attrib); + } else if (hi_pc_class == DW_AttribClass_Const) { + hi_pc = dw_const_u64_from_attrib(input, cu, hi_pc_attrib); + hi_pc += lo_pc; + } + + if (lo_pc >= image_base && hi_pc >= image_base) { + if (lo_pc < hi_pc) { + rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); + } else { + log_user_errorf("invalid range @ .debug_info+%llx", tag.info_off); + } + } else { + // invalid low and hi PC are likely are caused by an optimization pass during linking + } + } else if ((lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) || + (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null)) { + log_user_errorf("invalid range @ .debug_info+%llx", tag.info_off); + } + } + + return ranges; +} + internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, @@ -2346,7 +2286,6 @@ d2r_convert_symbols(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, - U64 arch_addr_size, U64 image_base, Arch arch, DW_TagNode *root) @@ -2392,7 +2331,7 @@ d2r_convert_symbols(Arena *arena, // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; + proc_type->byte_size = cu->address_size; proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; @@ -2407,11 +2346,11 @@ d2r_convert_symbols(Arena *arena, String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &g_d2r_shared.procs, D2R_PROC_CHUNK_CAP); // make scope Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + RDIM_Scope *root_scope = d2r_push_scope(arena, &g_d2r_shared.scopes, D2R_SCOPE_CHUNK_CAP, it->stack, ranges); root_scope->symbol = proc; // fill out proc @@ -2422,7 +2361,7 @@ d2r_convert_symbols(Arena *arena, proc->container_symbol = 0; proc->container_type = container_type; proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); + proc->location_cases = d2r_locset_from_attrib(arena, &g_d2r_shared.scopes, root_scope, &g_d2r_shared.locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); // sub program with user-defined parent tag is a method DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); @@ -2433,16 +2372,16 @@ d2r_convert_symbols(Arena *arena, case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; + default: { log_user_errorf("unhandled virtuality kind"); } break; } RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &g_d2r_shared.udts, type->udt); member->kind = member_kind; member->type = type; member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); } else if (parent_tag.kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); + log_user_errorf("unexpected tag @ .debug_info+%llx", tag.info_off); } it->stack->scope = root_scope; @@ -2465,7 +2404,7 @@ d2r_convert_symbols(Arena *arena, // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; + proc_type->byte_size = cu->address_size; proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; @@ -2477,7 +2416,7 @@ d2r_convert_symbols(Arena *arena, } // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &g_d2r_shared.inline_sites, D2R_INLINE_SITE_CHUNK_CAP); inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); inline_site->type = proc_type; inline_site->owner = owner; @@ -2485,7 +2424,7 @@ d2r_convert_symbols(Arena *arena, // make scope Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + RDIM_Scope *root_scope = d2r_push_scope(arena, &g_d2r_shared.scopes, D2R_SCOPE_CHUNK_CAP, it->stack, ranges); root_scope->inline_site = inline_site; } break; case DW_TagKind_Variable: { @@ -2497,14 +2436,14 @@ d2r_convert_symbols(Arena *arena, parent_tag.kind == DW_TagKind_InlinedSubroutine || parent_tag.kind == DW_TagKind_LexicalBlock) { RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); + RDIM_Local *local = rdim_scope_push_local(arena, &g_d2r_shared.scopes, scope); local->kind = RDI_LocalKind_Variable; local->name = name; local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + local->location_cases = d2r_var_locset_from_tag(arena, &g_d2r_shared.scopes, scope, &g_d2r_shared.locations, input, cu, image_base, arch, tag); } else { - // NOTE: due to a bug in clang in stb_sprint.h local variables + // NOTE: due to a bug in clang in stb_sprintf.h local variables // are declared in global scope without a name if (name.size == 0) { break; } @@ -2522,13 +2461,15 @@ d2r_convert_symbols(Arena *arena, String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); D2R_ValueType expr_type = 0; - RDIM_EvalBytecode bc = d2r_bytecode_from_expression(temp.arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &expr_type); + RDIM_EvalBytecode bc = d2r_bytecode_from_expression(temp.arena, input, image_base, arch, cu->addr_lu, expr, cu, &expr_type); // evaluate bytecode to virutal offset if possible if (expr_type == D2R_ValueType_Address) { B32 is_static = rdim_is_eval_bytecode_static(bc); if (is_static) { - voff = rdim_virt_off_from_eval_bytecode(bc, image_base); + if (!rdim_static_eval_bytecode_to_voff(bc, image_base, &voff)) { + log_user_errorf("failed to evalute byte code to virtual offset @ .debug_info+%llx", tag.info_off); + } } } @@ -2540,8 +2481,8 @@ d2r_convert_symbols(Arena *arena, } RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; - if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } - else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } + if (is_thread_var) { var_chunks = &g_d2r_shared.tvars; var_chunks_cap = D2R_TVAR_CHUNK_CAP; } + else { var_chunks = &g_d2r_shared.gvars; var_chunks_cap = D2R_GVAR_CHUNK_CAP; } RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); @@ -2557,14 +2498,14 @@ d2r_convert_symbols(Arena *arena, DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + RDIM_Local *param = rdim_scope_push_local(arena, &g_d2r_shared.scopes, scope); param->kind = RDI_LocalKind_Parameter; param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + param->location_cases = d2r_var_locset_from_tag(arena, &g_d2r_shared.scopes, scope, &g_d2r_shared.locations, input, cu, image_base, arch, tag); } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); + Assert(!"this is a local variable"); + log_user_errorf(".debug_info+%llx out of scope formal parameter", tag.info_off); } } break; case DW_TagKind_LexicalBlock: { @@ -2573,7 +2514,7 @@ d2r_convert_symbols(Arena *arena, parent_tag.kind == DW_TagKind_InlinedSubroutine || parent_tag.kind == DW_TagKind_LexicalBlock) { Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + d2r_push_scope(arena, &g_d2r_shared.scopes, D2R_SCOPE_CHUNK_CAP, it->stack, ranges); } } break; case DW_TagKind_CallSite: { @@ -2595,25 +2536,157 @@ d2r_convert_symbols(Arena *arena, default: { // NotImplemented; - }break; + } break; } } scratch_end(scratch); } +force_inline int +d2r_src_file_lookup_compar(void *raw_a, void *raw_b) +{ + D2R_SrcFileLookup *a = raw_a, *b = raw_b; + DW_LineFile *file_a = a->file, *file_b = b->file; + String8 dir_path_a = a->vm->header.dir_table.v[file_a->dir_idx]; + String8 dir_path_b = b->vm->header.dir_table.v[file_b->dir_idx]; + int cmp = str8_compar(dir_path_a, dir_path_b, 0); + if (cmp == 0) { + cmp = str8_compar(file_a->file_name, file_b->file_name, 0); + } + return cmp; +} + +force_inline +LFHT_IS_KEY_EQUAL_FUNC(d2r_src_file_lookup_is_equal) +{ + return d2r_src_file_lookup_compar(a, b) == 0; +} + +force_inline int +d2r_src_file_lfht_key_value_is_before(void *raw_a, void *raw_b) +{ + return d2r_src_file_lookup_compar(*(D2R_SrcFileLookup **)raw_a, *(D2R_SrcFileLookup **)raw_b) < 0; +} + +internal U64 +d2r_hash_line_file(String8 dir_path, DW_LineFile *file) +{ + XXH3_state_t hasher = {0}; + XXH3_64bits_reset(&hasher); + XXH3_64bits_update(&hasher, dir_path.str, dir_path.size); + XXH3_64bits_update(&hasher, file->file_name.str, file->file_name.size); + XXH3_64bits_update(&hasher, &file->modify_time, sizeof(file->modify_time)); + XXH3_64bits_update(&hasher, &file->md5_digest, sizeof(file->md5_digest)); + XXH64_hash_t hash = XXH3_64bits_digest(&hasher); + return hash; +} + +internal void +d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b)) +{ + radsort(ptrs, count, is_before); +} + +internal D2R_CompUnitContribMap +d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) +{ + Temp scratch = scratch_begin(&arena, 1); + Temp temp = temp_begin(arena); + B32 parse_failed = 1; + + Rng1U64List unit_range_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_ARanges].data); + + D2R_CompUnitContribMap cm = {0}; + cm.info_off_arr = push_array(temp.arena, U64, unit_range_list.count); + cm.voff_range_arr = push_array(temp.arena, RDIM_Rng1U64ChunkList, unit_range_list.count); + + for EachNode(range_n, Rng1U64Node, unit_range_list.first) { + String8 unit_data = str8_substr(input->sec[DW_Section_ARanges].data, range_n->v); + U64 unit_cursor = 0; + + U64 unit_length; + TryRead(str8_deserial_read_dwarf_packed_size(unit_data, unit_cursor, &unit_length), unit_cursor, exit); + DW_Format unit_format = DW_FormatFromSize(unit_length); + + DW_Version version; + TryRead(str8_deserial_read_struct(unit_data, unit_cursor, &version), unit_cursor, exit); + + if (version != DW_Version_2) { + log_user_errorf("unknown .debug_aranges version %u @ 0x%llx", version, range_n->v.min); + continue; + } + + U64 cu_info_off; + TryRead(str8_deserial_read_dwarf_uint(unit_data, unit_cursor, unit_format, &cu_info_off), unit_cursor, exit); + + U8 address_size = 0; + TryRead(str8_deserial_read_struct(unit_data, unit_cursor, &address_size), unit_cursor, exit); + + U8 segment_selector_size = 0; + TryRead(str8_deserial_read_struct(unit_data, unit_cursor, &segment_selector_size), unit_cursor, exit); + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = unit_cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + unit_cursor += tuple_size - bytes_too_far_past_boundary; + } + + RDIM_Rng1U64ChunkList voff_ranges = {0}; + if (segment_selector_size == 0) { + while (unit_cursor + address_size * 2 <= unit_data.size) { + U64 address = 0; + U64 length = 0; + TryRead(str8_deserial_read(unit_data, unit_cursor, &address, address_size, address_size), unit_cursor, exit); + TryRead(str8_deserial_read(unit_data, unit_cursor, &length, address_size, address_size), unit_cursor, exit); + + if (address == 0 && length == 0) { break; } + if (address == 0) { continue; } + + if (address < image_base) { + log_user_errorf("invalid address 0x%llx in .debug_aranges+%llx", range_n->v.min + unit_cursor); + continue; + } + + U64 min = address - image_base; + U64 max = min + length; + rdim_rng1u64_chunk_list_push(temp.arena, &voff_ranges, 256, (RDIM_Rng1U64){.min = min, .max = max}); + } + } else { + NotImplemented; + } + + U64 map_idx = cm.count++; + cm.info_off_arr[map_idx] = cu_info_off; + cm.voff_range_arr[map_idx] = voff_ranges; + } + + parse_failed = 0; + exit:; + if (parse_failed) { + MemoryZeroStruct(&cm); + temp_end(temp); + } + scratch_end(scratch); + return cm; +} + +internal RDIM_Rng1U64ChunkList +d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) +{ + RDIM_Rng1U64ChunkList voff_ranges = {0}; + U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); + if (voff_list_idx < map.count) { + voff_ranges = map.voff_range_arr[voff_list_idx]; + } + return voff_ranges; +} + internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params) { Temp scratch = scratch_begin(&arena, 1); - if (lane_idx() == 0) { - g_d2r_log.arena = arena_alloc(); - //////////////////////////////// - - ProfBegin("compute exe hash"); - U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); - ProfEnd(); - + if (lane_idx() == 0) { //////////////////////////////// Arch arch = Arch_Null; @@ -2621,41 +2694,42 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) DW_Input input = {0}; PathStyle path_style = PathStyle_Null; - switch(params->exe_kind) { - default:{}break; + switch (params->exe_kind) { + case ExecutableImageKind_Null: {} break; case ExecutableImageKind_CoffPe: { PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); String8 string_table = str8_substr(params->exe_data, pe.string_table_range); - arch = pe.arch; - image_base = pe.image_base; - binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); - input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); - path_style = PathStyle_WindowsAbsolute; + + arch = pe.arch; + image_base = pe.image_base; + input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); + path_style = PathStyle_WindowsAbsolute; + + g_d2r_shared.binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); } break; case ExecutableImageKind_Elf32: case ExecutableImageKind_Elf64: { ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); - arch = arch_from_elf_machine(bin.hdr.e_machine); - image_base = elf_base_addr_from_bin(&bin); - binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); - input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); - path_style = PathStyle_UnixAbsolute; + + arch = arch_from_elf_machine(bin.hdr.e_machine); + image_base = elf_base_addr_from_bin(&bin); + input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); + path_style = PathStyle_UnixAbsolute; + + g_d2r_shared.binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); } break; + default: { InvalidPath; } break; } //////////////////////////////// + + ProfBegin("compute exe hash"); + U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); + ProfEnd(); - top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); - - //////////////////////////////// - - U64 arch_addr_size = rdi_addr_size_from_arch(top_level_info.arch); - - //////////////////////////////// - - RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); + g_d2r_shared.top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, g_d2r_shared.binary_sections); //////////////////////////////// @@ -2675,139 +2749,241 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) //////////////////////////////// ProfBegin("Parse Compile Unit Headers"); - // TODO(rjf): parse should always be relaxed. any verification checks we do - // should just be logged via log_info(...), and then the caller of this - // converter can collect those & display as necessary. - B32 is_parse_relaxed = 1; DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { - cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); + cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, params->is_parse_relaxed); } ProfEnd(); //////////////////////////////// - - ProfBegin("Parse Line Tables"); - DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); - for EachIndex(cu_idx, cu_ranges.count) { - DW_CompUnit *cu = &cu_arr[cu_idx]; - String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_StmtList); - String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); - cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); - } - ProfEnd(); - - //////////////////////////////// - - ProfBegin("Convert Line Tables"); - HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); + + ProfBeginV("Convert Line Tables [Count: %llu]", cu_ranges.count); RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); - for EachIndex(cu_idx, cu_ranges.count) { - cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); - - DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; - DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; - DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; - RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); - for EachIndex(file_idx, file_table->count) { - DW_LineFile *file = &file_table->v[file_idx]; - String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); - String8List file_path_split = str8_split_path(scratch.arena, file_path); - str8_path_list_resolve_dots_in_place(&file_path_split, path_style); - String8 file_path_resolved = str8_path_list_join_by_style(scratch.arena, &file_path_split, path_style); - RDIM_SrcFile *src_file = hash_table_search_path_raw(source_file_ht, file_path_resolved); - if (src_file == 0) { - src_file = rdim_src_file_chunk_list_push(arena, &src_files, SRC_FILE_CAP); - src_file->path = push_str8_copy(arena, file_path_resolved); - hash_table_push_path_raw(scratch.arena, source_file_ht, src_file->path, src_file); - } - src_file_map[file_idx] = src_file; + { + Temp temp = temp_begin(scratch.arena); + + // TODO: per thread task + ProfBegin("Up front parse line VM headers"); + DW_LineVM **line_vms = push_array(temp.arena, DW_LineVM *, cu_ranges.count); + for EachIndex(cu_idx, cu_ranges.count) { + line_vms[cu_idx] = dw_line_vm_init(&input, &cu_arr[cu_idx]); } - - for EachNode(line_seq, DW_LineSeqNode, line_table->first_seq) { - if (line_seq->count == 0) { continue; } - - U64 *voffs = push_array(arena, U64, line_seq->count); - U32 *line_nums = push_array(arena, U32, line_seq->count); - U16 *col_nums = 0; - U64 line_idx = 0; - - DW_LineNode *file_line_n = line_seq->first; - U64 file_line_count = 0; - - for EachNode(line_n, DW_LineNode, file_line_n) { - if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { - U64 file_index = file_line_n->v.file_index; - U64 *file_voffs = &voffs[line_idx]; - U32 *file_line_nums = &line_nums[line_idx]; - U16 *file_col_nums = 0; - - U64 lines_written = 0; - U64 prev_ln = max_U64; - DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; - for (; file_line_n != sentinel; file_line_n = file_line_n->next) { - if (file_line_n->v.line != prev_ln) { - if (file_line_n->v.address == 0) { continue; } - - voffs[line_idx] = file_line_n->v.address - image_base; - line_nums[line_idx] = file_line_n->v.line; - - ++lines_written; - ++line_idx; - - prev_ln = file_line_n->v.line; - } + ProfEnd(); + + // TODO: sync + // + // sum all source files (including duplicates) + U64 total_file_count = 0; + for EachIndex(cu_idx, cu_ranges.count) { total_file_count += line_vms[cu_idx]->header.file_table.count; } + + // TODO: sync + ProfBeginV("Dedup source files [Count: %llu]", total_file_count); + LFHT_NodeChunkList *src_file_lfht_nodes = push_array(temp.arena, LFHT_NodeChunkList, lane_count()); + LFHT_Node *src_file_lfht = 0; + + // TODO: per thread + { + D2R_SrcFileLookup *lookup = 0; + for EachIndex(cu_idx, cu_ranges.count) { + DW_LineVM *vm = line_vms[cu_idx]; + for EachIndex(file_idx, vm->header.file_table.count) { + DW_LineFile *file = &vm->header.file_table.v[file_idx]; + + if (lookup == 0) { lookup = push_array(temp.arena, D2R_SrcFileLookup, 1); } + lookup->vm = vm; + lookup->file = file; + + LFHT_NodeChunkList *node_chunks = &src_file_lfht_nodes[lane_idx()]; + U64 hash = d2r_hash_line_file(vm->header.dir_table.v[file->dir_idx], file); + B32 was_inserted = lfht_insert(temp.arena, node_chunks, &src_file_lfht, hash, lookup, d2r_src_file_lookup_is_equal, 0); + if (was_inserted) { + lookup = 0; } - - RDIM_SrcFile *src_file = src_file_map[file_index]; - RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); - rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - - file_line_count = 1; - } else { - file_line_count += 1; } } - - // handle last line - if (file_line_n) { - U64 file_index = file_line_n->v.file_index; - U64 *file_voffs = &voffs[line_idx]; - U32 *file_line_nums = &line_nums[line_idx]; - U16 *file_col_nums = 0; - - for (; file_line_n != 0; file_line_n = file_line_n->next, line_idx += 1) { - // TODO: error handling - AssertAlways(file_line_n->v.address >= image_base); - voffs[line_idx] = file_line_n->v.address - image_base; - line_nums[line_idx] = file_line_n->v.line; - } - - RDIM_SrcFile *src_file = src_file_map[file_index]; - RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); - rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - } - - //Assert(line_idx == line_seq->count); } + ProfEnd(); + + // TODO: sync + ProfBegin("Extract source file lookups"); + U64 unique_file_count = lfht_total_count_from_node_chunk_lists(lane_count(), src_file_lfht_nodes); + void **lookups = lfht_data_from_node_chunk_lists(temp.arena, unique_file_count, lane_count(), src_file_lfht_nodes); + ProfEnd(); + + // TODO: sync + ProfBeginV("Sort unique source files [Count: %llu]", unique_file_count); + d2r_sort_ptrs(lookups, unique_file_count, d2r_src_file_lfht_key_value_is_before); + ProfEnd(); + + // TODO: per thread task + ProfBegin("Convert source files"); + for EachIndex(i, unique_file_count) { + D2R_SrcFileLookup *lookup = lookups[i]; + + DW_LineFile *src = lookup->file; + RDIM_SrcFile *dst = rdim_src_file_chunk_list_push(arena, &g_d2r_shared.src_files, D2R_SRC_FILE_CAP); + + // make file path + String8 path; + { + String8List path_list = {0}; + str8_list_push_node(&path_list, &(String8Node){ .string = lookup->vm->header.dir_table.v[src->dir_idx] }); + str8_list_push_node(&path_list, &(String8Node){ .string = src->file_name }); + path = str8_path_list_join_by_style(arena, &path_list, path_style); + } + + // fill out source file + dst->path = path; + if ( ! u128_match(src->md5_digest, u128_zero())) { + dst->checksum_kind = RDI_ChecksumKind_MD5; + dst->checksum = str8_copy(arena, str8_struct(&src->md5_digest)); + } else if (src->modify_time != 0) { + dst->checksum_kind = RDI_ChecksumKind_Timestamp; + dst->checksum = str8_copy(arena, str8_struct(&src->modify_time)); + } + + lookup->src_file = dst; + } + ProfEnd(); + + // TODO: sync + RDIM_LineTableChunkList *lane_line_table_chunks = push_array(temp.arena, RDIM_LineTableChunkList, lane_count()); + + // TODO: per thread task + ProfBegin("Convert line sequences"); + U64 *line_seq_counts_per_lane = push_array(scratch.arena, U64, lane_count()); + for EachIndex(cu_idx, cu_ranges.count) { + RDIM_LineTableChunkList *lane_line_table_chunk_list = &lane_line_table_chunks[lane_idx()]; + + // push new line table for the compile unit + RDIM_LineTable *line_table = rdim_line_table_chunk_list_push(arena, lane_line_table_chunk_list, D2R_LINE_TABLE_CAP); + cu_line_tables_rdi[cu_idx] = line_table; + + // push line buffer +#define D2R_LineBufferMax 1024 + struct LineBuffer { U64 file_index; U64 voffs[D2R_LineBufferMax]; U32 line_nums[D2R_LineBufferMax]; U32 col_nums[D2R_LineBufferMax]; } LineBuffer; + struct LineBuffer *line_buffer = push_array(temp.arena, struct LineBuffer, 1); + U64 line_buffer_size = 0; + + // decode line sequences + DW_LineVM *vm = line_vms[cu_idx]; + U64 *line_seq_counts_per_file = push_array(temp.arena, U64, vm->header.file_table.count); + while (dw_line_vm_step(vm)) { + if (vm->new_line) { + // lazy defined files are not supported + if (vm->state.file_index >= vm->header.file_table.count) { continue; } + + // time to flush the buffer? + if ((line_buffer_size >= D2R_LineBufferMax || line_buffer->file_index != vm->state.file_index) && line_buffer_size > 0) { + // lookup source file + DW_LineFile *file = &vm->header.file_table.v[vm->state.file_index]; + U64 hash = d2r_hash_line_file(vm->header.dir_table.v[file->dir_idx], file); + D2R_SrcFileLookup *lookup = lfht_search(src_file_lfht, hash, &(D2R_SrcFileLookup){ .file = file, .vm = vm }, d2r_src_file_lookup_is_equal, 0); + RDIM_SrcFile *src_file = lookup->src_file; + + // copy line info + U64 *voffs = push_array_no_zero(arena, U64, line_buffer_size + 1); + U32 *line_nums = push_array_no_zero(arena, U32, line_buffer_size); + voffs[line_buffer_size] = vm->state.address; + MemoryCopyTyped(voffs, line_buffer->voffs, line_buffer_size); + MemoryCopyTyped(line_nums, line_buffer->line_nums, line_buffer_size); + + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, lane_line_table_chunk_list, line_table, src_file, voffs, line_nums, 0, line_buffer_size); + + // atomic implementation of @rdim_src_file_push_line_sequence + { + // associate line fragment with source file + RDIM_SrcFileLineMapFragment *line_frag = push_array(arena, RDIM_SrcFileLineMapFragment, 1); + line_frag->seq = line_seq; + + // insert line fragment node + for (;;) { + RDIM_SrcFileLineMapFragment *next = src_file->first_line_map_fragment; + line_frag->next = next; + RDIM_SrcFileLineMapFragment *curr = ins_atomic_ptr_eval_cond_assign(&src_file->first_line_map_fragment, line_frag, next); + if (curr == 0) { + ins_atomic_u64_add_eval(&g_d2r_shared.src_files.source_line_map_count, 1); + } + if (curr == next) { break; } + } + + // accumulate line sequence counts per file + line_seq_counts_per_file[vm->state.file_index] += line_seq->line_count; + + // accumulate line sequence counts per lane + line_seq_counts_per_lane[lane_idx()] += line_seq->line_count; + } + + // reset line buffer size tracker + line_buffer_size = 0; + } + + if (line_buffer_size > 0 && line_buffer->voffs[line_buffer_size - 1] == vm->state.address) { + line_buffer->line_nums[line_buffer_size - 1] = Min(line_buffer->line_nums[line_buffer_size - 1], safe_cast_u32(vm->state.line)); + } else { + // append line to the buffer + line_buffer->file_index = vm->state.file_index; + line_buffer->voffs[line_buffer_size] = vm->state.address; + line_buffer->line_nums[line_buffer_size] = safe_cast_u32(vm->state.line); + line_buffer_size += 1; + } + } + } + + // update line sequence counts per source file @rdim_src_file_push_line_sequence + for EachIndex(file_idx, vm->header.file_table.count) { + if (line_seq_counts_per_file[file_idx] > 0) { + DW_LineFile *file = &vm->header.file_table.v[file_idx]; + U64 hash = d2r_hash_line_file(vm->header.dir_table.v[file->dir_idx], file); + D2R_SrcFileLookup *lookup = lfht_search(src_file_lfht, hash, &(D2R_SrcFileLookup){ .file = file, .vm = vm }, d2r_src_file_lookup_is_equal, 0); + RDIM_SrcFile *src_file = lookup->src_file; + ins_atomic_u64_add_eval(&src_file->total_line_count, line_seq_counts_per_file[file_idx]); + } + } + } + + // TODO: sync + // + // update total line sequences count in shared @rdim_src_file_push_line_sequence + for EachIndex(i, lane_count()) { + g_d2r_shared.src_files.total_line_count += line_seq_counts_per_lane[i]; + } + + // TODO: sync + for EachIndex(i, lane_count()) { + rdim_line_table_chunk_list_concat_in_place(&g_d2r_shared.line_tables, &lane_line_table_chunks[i]); + } + + // TODO: per thread task + ProfBegin("Relase line VMs"); + for EachIndex(i, cu_ranges.count) { + dw_line_vm_release(line_vms[i]); + } + ProfEnd(); + + temp_end(temp); } ProfEnd(); + //////////////////////////////// + + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &g_d2r_shared.scopes, D2R_SCOPE_CHUNK_CAP); + //////////////////////////////// RDIM_Type *builtin_types[RDI_TypeKind_Count] = {0}; for (RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { - RDIM_Type *type = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); + RDIM_Type *type = rdim_type_chunk_list_push(arena, &g_d2r_shared.types, D2R_TYPE_CHUNK_CAP); type->kind = type_kind; type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); type->byte_size = rdi_size_from_basic_type_kind(type_kind); builtin_types[type_kind] = type; } - builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; - builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; - builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); + builtin_types[RDI_TypeKind_Void]->byte_size = rdi_addr_size_from_arch(g_d2r_shared.top_level_info.arch); + builtin_types[RDI_TypeKind_Handle]->byte_size = rdi_addr_size_from_arch(g_d2r_shared.top_level_info.arch); + + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &g_d2r_shared.types, D2R_TYPE_CHUNK_CAP); builtin_types[RDI_TypeKind_Variadic]->kind = RDI_TypeKind_Variadic; //////////////////////////////// @@ -2844,14 +3020,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // init type table D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); type_table->ht = hash_table_init(comp_temp.arena, 0x4000); - type_table->types = &types; - type_table->type_chunk_cap = TYPE_CHUNK_CAP; + type_table->types = &g_d2r_shared.types; + type_table->type_chunk_cap = D2R_TYPE_CHUNK_CAP; type_table->builtin_types = builtin_types; // convert debug info - d2r_convert_types(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); - d2r_convert_udts(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); - d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, arch_addr_size, image_base, arch, tag_tree.root); + d2r_convert_types(arena, type_table, &input, cu, cu_lang, tag_tree.root); + d2r_convert_udts(arena, type_table, &input, cu, cu_lang, tag_tree.root); + d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, image_base, arch, tag_tree.root); RDIM_Rng1U64ChunkList cu_voff_ranges = {0}; if (cu_idx < cu_contrib_map.count) { @@ -2865,7 +3041,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // convert compile unit { - RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); + RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &g_d2r_shared.units, D2R_UNIT_CHUNK_CAP); unit->unit_name = cu_name; unit->compiler_name = cu_prod; unit->source_file = str8_zero(); // TODO @@ -2887,20 +3063,21 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) RDIM_BakeParams bake_params = {0}; bake_params.subset_flags = params->subset_flags; - bake_params.top_level_info = top_level_info; - bake_params.binary_sections = binary_sections; - bake_params.units = units; - bake_params.types = types; - bake_params.udts = udts; - bake_params.src_files = src_files; - bake_params.line_tables = line_tables; - bake_params.locations = locations; - bake_params.global_variables = gvars; - bake_params.thread_variables = tvars; - bake_params.procedures = procs; - bake_params.scopes = scopes; - bake_params.inline_sites = inline_sites; + bake_params.top_level_info = g_d2r_shared.top_level_info; + bake_params.binary_sections = g_d2r_shared.binary_sections; + bake_params.units = g_d2r_shared.units; + bake_params.types = g_d2r_shared.types; + bake_params.udts = g_d2r_shared.udts; + bake_params.src_files = g_d2r_shared.src_files; + bake_params.line_tables = g_d2r_shared.line_tables; + bake_params.locations = g_d2r_shared.locations; + bake_params.global_variables = g_d2r_shared.gvars; + bake_params.thread_variables = g_d2r_shared.tvars; + bake_params.procedures = g_d2r_shared.procs; + bake_params.scopes = g_d2r_shared.scopes; + bake_params.inline_sites = g_d2r_shared.inline_sites; scratch_end(scratch); return bake_params; } + diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 939daf17..543dbd8d 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -1,18 +1,13 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#pragma once +#ifndef RDI_FROM_DWARF_H +#define RDI_FROM_DWARF_H -typedef struct D2R_Log -{ - Arena *arena; - String8List v; -} D2R_Log; +//////////////////////////////// +//~ Conversion -#define d2r_log(...) str8_list_pushf(g_d2r_log.arena, &g_d2r_log.v, __FILE__ ":" Stringify(__LINE__) " " __VA_ARGS__) - -typedef struct D2R_ConvertParams D2R_ConvertParams; -struct D2R_ConvertParams +typedef struct D2R_ConvertParams { String8 dbg_name; String8 dbg_data; @@ -21,7 +16,107 @@ struct D2R_ConvertParams ExecutableImageKind exe_kind; RDIM_SubsetFlags subset_flags; B32 deterministic; -}; + B32 is_parse_relaxed; +} D2R_ConvertParams; + +#define D2R_UNIT_CHUNK_CAP 512 +#define D2R_UDT_CHUNK_CAP 1024 +#define D2R_TYPE_CHUNK_CAP 1024 +#define D2R_SRC_FILE_CAP 1024 +#define D2R_LINE_TABLE_CAP 1024 +#define D2R_GVAR_CHUNK_CAP 1024 +#define D2R_TVAR_CHUNK_CAP 1024 +#define D2R_LOCATIONS_CAP 4096 +#define D2R_PROC_CHUNK_CAP 4096 +#define D2R_SCOPE_CHUNK_CAP 4096 +#define D2R_INLINE_SITE_CHUNK_CAP 4096 + +typedef struct D2R_Shared +{ + RDIM_TopLevelInfo top_level_info; + RDIM_BinarySectionList binary_sections; + RDIM_UnitChunkList units; + RDIM_UDTChunkList udts; + RDIM_TypeChunkList types; + RDIM_SrcFileChunkList src_files; + RDIM_LineTableChunkList line_tables; + RDIM_LocationChunkList locations; + RDIM_SymbolChunkList gvars; + RDIM_SymbolChunkList tvars; + RDIM_SymbolChunkList procs; + RDIM_ScopeChunkList scopes; + RDIM_InlineSiteChunkList inline_sites; +} D2R_Shared; + +//////////////////////////////// +//~ Value Types + +typedef enum +{ + D2R_ArithmeticType_Null, + D2R_ArithmeticType_Signed, + D2R_ArithmeticType_Unsigned, + D2R_ArithmeticType_Float, +} D2R_ArithmeticType; + +#define D2R_ValueType_Signed_XList \ + X(S8, Signed, 1 ) \ + X(S16, Signed, 2 ) \ + X(S32, Signed, 4 ) \ + X(S64, Signed, 8 ) \ + X(S128, Signed, 16) \ + X(S256, Signed, 32) \ + X(S512, Signed, 64) + +#define D2R_ValueType_Unsigned_XList \ + X(U8, Unsigned, 1 ) \ + X(U16, Unsigned, 2 ) \ + X(U32, Unsigned, 4 ) \ + X(U64, Unsigned, 8 ) \ + X(U128, Unsigned, 16) \ + X(U256, Unsigned, 32) \ + X(U512, Unsigned, 64) + +#define D2R_ValueType_Float_XList \ + X(F16, Float, 2 ) \ + X(F32, Float, 4 ) \ + X(F48, Float, 6 ) \ + X(F64, Float, 8 ) \ + X(F80, Float, 10) \ + X(F96, Float, 12) \ + X(F128, Float, 16) + +#define D2R_ValueType_XList \ + X(Generic, Null, 0 ) \ + X(ImplicitValue, Null, 0 ) \ + X(Address, Unsigned, 0 ) \ + D2R_ValueType_Signed_XList \ + D2R_ValueType_Unsigned_XList \ + D2R_ValueType_Float_XList + +typedef enum +{ +#define X(t, ...) D2R_ValueType_##t, + D2R_ValueType_XList +#undef X + D2R_ValueType_Bool = D2R_ValueType_S8, +} D2R_ValueType; + +typedef struct D2R_ValueTypeNode +{ + D2R_ValueType type; + struct D2R_ValueTypeNode *next; +} D2R_ValueTypeNode; + +typedef struct D2R_ValueTypeStack +{ + U64 count; + D2R_ValueTypeNode *top; + D2R_ValueTypeNode *free_list; +} D2R_ValueTypeStack; + +//////////////////////////////// +//~ Type Table typedef struct D2R_TypeTable { @@ -31,6 +126,9 @@ typedef struct D2R_TypeTable RDIM_Type **builtin_types; } D2R_TypeTable; +//////////////////////////////// +//~ Tag Iterator + typedef DW_TagSpare D2R_TagFlags; enum { @@ -53,6 +151,19 @@ typedef struct D2R_TagIterator B32 visit_children; } D2R_TagIterator; +//////////////////////////////// +//~ Line Table Conversion + +typedef struct D2R_SrcFileLookup +{ + DW_LineFile *file; + DW_LineVM *vm; + RDIM_SrcFile *src_file; +} D2R_SrcFileLookup; + +//////////////////////////////// +//~ Contrib Map + typedef struct D2R_CompUnitContribMap { U64 count; @@ -60,124 +171,110 @@ typedef struct D2R_CompUnitContribMap RDIM_Rng1U64ChunkList *voff_range_arr; } D2R_CompUnitContribMap; -#define D2R_ValueType_IsSigned(x) ((x) == D2R_ValueType_S8 || (x) == D2R_ValueType_S16 || (x) == D2R_ValueType_S32 || (x) == D2R_ValueType_S64 || (x) == D2R_ValueType_S128 || (x) == D2R_ValueType_S256 || (x) == D2R_ValueType_S512) -#define D2R_ValueType_IsUnsigned(x) ((x) == D2R_ValueType_U8 || (x) == D2R_ValueType_U16 || (x) == D2R_ValueType_U32 || (x) == D2R_ValueType_U64 || (x) == D2R_ValueType_U128 || (x) == D2R_ValueType_U256 || (x) == D2R_ValueType_U512) -#define D2R_ValueType_IsFloat(x) ((x) == D2R_ValueType_F32 || (x) == D2R_ValueType_F64) -#define D2R_ValueType_IsInt(x) (D2R_ValueType_IsSigned(x) || D2R_ValueType_IsUnsigned(x) || (x) == D2R_ValueType_Address) -typedef enum D2R_ValueType -{ - D2R_ValueType_Generic, - D2R_ValueType_U8, - D2R_ValueType_U16, - D2R_ValueType_U32, - D2R_ValueType_U64, - D2R_ValueType_U128, - D2R_ValueType_U256, - D2R_ValueType_U512, - D2R_ValueType_S8, - D2R_ValueType_S16, - D2R_ValueType_S32, - D2R_ValueType_S64, - D2R_ValueType_S128, - D2R_ValueType_S256, - D2R_ValueType_S512, - D2R_ValueType_F32, - D2R_ValueType_F64, - D2R_ValueType_Address, - D2R_ValueType_ImplicitValue, - D2R_ValueType_Bool = D2R_ValueType_S8, -} D2R_ValueType; +//////////////////////////////// +//~ RDIM Bytecode Extensions -typedef struct D2R_ValueTypeNode -{ - D2R_ValueType type; - - struct D2R_ValueTypeNode *next; -} D2R_ValueTypeNode; - -typedef struct D2R_ValueTypeStack -{ - U64 count; - D2R_ValueTypeNode *top; - D2R_ValueTypeNode *free_list; -} D2R_ValueTypeStack; +internal B32 rdim_is_eval_bytecode_static (RDIM_EvalBytecode bc); +internal B32 rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out); //////////////////////////////// -//~ rjf: Enum Conversion Helpers +//~ DWARF -> RDI Enums internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v); -internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64(DW_RegX64 v); -internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v); +internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64 (DW_RegX64 v); +internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg (Arch arch, DW_Reg v); //////////////////////////////// -//~ rjf: Type Conversion Helpers - -internal RDIM_Type * d2r_create_type(Arena *arena, D2R_TypeTable *type_table); -internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); -internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off); -internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag); -internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); -internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size); -internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size); -internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x); - -//////////////////////////////// -//~ RDIM Bytecode Helpers - -internal B32 rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc); -internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base); - -//////////////////////////////// -//~ rjf: Bytecode Conversion Helpers +//~ Value Type internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type); -internal D2R_ValueType d2r_value_type_stack_pop(D2R_ValueTypeStack *stack); +internal D2R_ValueType d2r_value_type_stack_pop (D2R_ValueTypeStack *stack); internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack); -internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size); -internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size); -internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size); -internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v); -internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type); +internal D2R_ValueType d2r_signed_value_type_from_bit_size (U64 bit_size); +internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_float_type_from_bit_size (U64 bit_size); + +internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type); +internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v); +internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v); +internal B32 d2r_is_value_type_signed (D2R_ValueType v); +internal B32 d2r_is_value_type_integral(D2R_ValueType v); +internal B32 d2r_is_value_type_unsigned(D2R_ValueType v); +internal B32 d2r_is_value_type_float (D2R_ValueType v); + internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs); +internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v); internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc); internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); -internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out); -internal RDIM_Location * d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); -internal RDIM_Location * d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); -internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); -internal RDIM_LocationCaseList d2r_var_locset_from_tag(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag); +//////////////////////////////// +//~ Expression Conversion + +internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out); +internal RDIM_Location * d2r_transpile_expression (Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); +internal RDIM_Location * d2r_location_from_attrib (Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); +internal RDIM_LocationCaseList d2r_locset_from_attrib (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); +internal RDIM_LocationCaseList d2r_var_locset_from_tag (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag); //////////////////////////////// -//~ rjf: Compilation Unit / Scope Conversion Helpers +//~ Type Table -internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base); -internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off); +internal RDIM_Type * d2r_create_type (Arena *arena, D2R_TypeTable *type_table); +internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); +internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off); +internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); //////////////////////////////// //~ Tag Iterator internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root); internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter); -internal void d2r_tag_iterator_skip_children(D2R_TagIterator *iter); +internal void d2r_tag_iterator_skip_children (D2R_TagIterator *iter); internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter); -internal DW_Tag d2r_tag_iterator_parent_tag(D2R_TagIterator *iter); +internal DW_Tag d2r_tag_iterator_parent_tag (D2R_TagIterator *iter); //////////////////////////////// -//~ Type/UDT/Symbol Conversion +//~ Type Conversion -internal void d2r_flag_converted_tag(DW_TagNode *tag_node); -internal B8 d2r_is_tag_converted(DW_TagNode *tag_node); - -internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_TagNode *root); -internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_TagNode *root); -internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, RDIM_Scope *global_scope, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, U64 image_base, Arch arch, DW_TagNode *root); +internal void d2r_flag_converted_tag(DW_TagNode *tag_node); +internal B8 d2r_is_tag_converted (DW_TagNode *tag_node); +internal RDIM_Type * d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, DW_Tag tag, DW_AttribKind kind); +internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root); //////////////////////////////// -//~ rjf: Main Conversion Entry Point +//~ UDT Conversion + +internal B8 d2r_is_udt_tag_converted (DW_TagNode *tag_node); +internal void d2r_flag_converted_udt_tag(DW_TagNode *tag_node); +internal void d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, RDIM_UDT *udt); +internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root); + +//////////////////////////////// +//~ Symbol Conversion + +internal RDIM_Scope * d2r_push_scope (Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges); +internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); +internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag); +internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, RDIM_Scope *global_scope, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 image_base, Arch arch, DW_TagNode *root); + +//////////////////////////////// +//~ Line Table Conversion + +internal U64 d2r_hash_line_file(String8 dir_path, DW_LineFile *file); +internal void d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b)); + +//////////////////////////////// +//~ Contrib Map + +internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base); +internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off); + +//////////////////////////////// +//~ Entry Point internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params); + +#endif // RDI_FROM_DWARF_H