diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 94c6aec0..24d21823 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -874,14 +874,7 @@ rb_thread_entry_point(void *p) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - if(cmd_line_has_flag(cmdline, s("a"))) - { - ProfScope("convert") pdb_bake_params = p2r_convert(arena, &convert_params); - } - else - { - ProfScope("convert") pdb_bake_params = p2r_convert2(arena, &convert_params); - } + ProfScope("convert") pdb_bake_params = p2r_convert2(arena, &convert_params); } //- rjf: RDI inputs => RDI joining diff --git a/src/rdi_from_codeview/rdi_from_codeview.c b/src/rdi_from_codeview/rdi_from_codeview.c index a05a8805..0dc2494d 100644 --- a/src/rdi_from_codeview/rdi_from_codeview.c +++ b/src/rdi_from_codeview/rdi_from_codeview.c @@ -1,6 +1,11 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +// TODO(rjf): eliminate redundant null checks, just always allocate +// empty results, and have nulls gracefully fall through +// +// (search for != 0 instances, inserted to prevent prior crashes) + //////////////////////////////// //~ rjf: Basic Helpers @@ -1134,7 +1139,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) SLLStackPush(src_file_map->slots[src_file_slot], src_file_node); src_file_node->src_file = rdim_src_file_chunk_list_push(arena, all_src_files__sequenceless, total_path_count); src_file_node->src_file->path = str8_copy(arena, file_path_sanitized); - src_file_node->src_file->checksum_kind = p2r_rdi_from_cv_c13_checksum_kind(c13_checksum_kind); + src_file_node->src_file->checksum_kind = cv2r_rdi_from_cv_c13_checksum_kind(c13_checksum_kind); src_file_node->src_file->checksum = str8_copy(arena, checksum); } } @@ -2360,7 +2365,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; if(basic_type == 0) { - RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); + RDI_TypeKind type_kind = cv2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); U32 byte_size = rdi_size_from_basic_type_kind(type_kind); basic_type = dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(byte_size == 0xffffffff) @@ -2900,7 +2905,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) } // rjf: symbol name -> container name - String8 container_name = str8_chop(str8_prefix(symbol_name, p2r_end_of_cplusplus_container_name(symbol_name)), 2); + String8 container_name = str8_chop(str8_prefix(symbol_name, cv2r_end_of_cplusplus_container_name(symbol_name)), 2); // rjf: non-empty container name -> gather if(container_name.size != 0) @@ -3050,7 +3055,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) nodes[idx] = n; } } - radsort(nodes, node_count, p2r_namespace_node_is_before); + radsort(nodes, node_count, cv2r_namespace_node_is_before); // rjf: build namespaces for this slot for EachIndex(node_in_slot_idx, node_count) @@ -3367,7 +3372,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: unpack global's container type B32 got_container = 0; RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + U64 container_name_opl = cv2r_end_of_cplusplus_container_name(name); String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); if(!got_container && container_name.size != 0) { @@ -3453,7 +3458,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: unpack proc's container type B32 got_container = 0; RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + U64 container_name_opl = cv2r_end_of_cplusplus_container_name(name); String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); if(!got_container && container_name.size != 0 && tpi_hash != 0 && tpi_leaf != 0) { @@ -3513,7 +3518,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) if(procedure_root_scope && procedure_root_scope->voff_ranges.min != 0) { U64 voff = procedure_root_scope->voff_ranges.min; - U64 hash = p2r_hash_from_voff(voff); + U64 hash = cv2r_hash_from_voff(voff); U64 bucket_idx = hash%link_name_map->buckets_count; CV2R_LinkNameNode *node = 0; for(CV2R_LinkNameNode *n = link_name_map->buckets[bucket_idx]; n != 0; n = n->next) @@ -3694,13 +3699,13 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: equip location info { // rjf: get raddbg register code - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); // TODO(rjf): real byte_size & byte_pos from cv_reg goes here U32 byte_size = 8; U32 byte_pos = 0; // rjf: build location - RDIM_Location loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Location loc = cv2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Rng1U64 voff_range = {0, max_U64}; rdim_location_case_list_push(arena, &local->location_cases, loc, voff_range); } @@ -3724,7 +3729,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: unpack thread variable's container type B32 got_container = 0; RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + U64 container_name_opl = cv2r_end_of_cplusplus_container_name(name); String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); if(!got_container && container_name.size != 0) { @@ -3846,7 +3851,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) Rng1U64 voff_range = r1u64(range_voff_first, range_voff_opl); CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); // rjf: build location RDIM_Location loc = {RDI_LocationKind_ValReg, reg_code}; @@ -3922,7 +3927,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) Rng1U64 voff_range = r1u64(range_voff_first, range_voff_opl); CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); // rjf: skip "subfield" location info - currently not supported if(defrange_subfield_register->field_offset != 0) @@ -3964,14 +3969,14 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: unpack sym CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)iter.struct_base; CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target->is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + RDI_RegCode fp_register_code = cv2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); // rjf: build location B32 extra_indirection = 0; U32 byte_size = rdi_addr_size_from_arch(arch); U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_Location loc = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location loc = cv2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); // rjf: emit location over ranges RDIM_Rng1U64 voff_range = {0, max_U64}; @@ -4169,7 +4174,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) U64 container_name_opl = 0; if(type != 0) { - container_name_opl = p2r_end_of_cplusplus_container_name(type->name); + container_name_opl = cv2r_end_of_cplusplus_container_name(type->name); } String8 name_qualified = name; if(container_name_opl != 0) @@ -4224,7 +4229,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) // rjf: determine if this pub32 was covered by another symbol record B32 was_in_other_record = 0; { - U64 hash = p2r_hash_from_voff(voff); + U64 hash = cv2r_hash_from_voff(voff); U64 slot_idx = hash%link_name_map->buckets_count; for(CV2R_LinkNameNode *n = link_name_map->buckets[slot_idx]; n != 0; n = n->next) { @@ -4300,7 +4305,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) for EachInRange(n_idx, range) { RDIM_Namespace *ns = &n->v[n_idx]; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(ns->name); + U64 container_name_opl = cv2r_end_of_cplusplus_container_name(ns->name); String8 container_name = str8_chop(str8_prefix(ns->name, container_name_opl), 2); if(container_name.size != 0) { @@ -4999,7 +5004,7 @@ cv2r_convert(Arena *arena, CV2R_ConvertParams *params) if(dst_type != 0 && dst_type->udt != 0 && udt_name.size != 0) { // rjf: unpack fully qualified namespace from udt name - U64 container_name_opl = p2r_end_of_cplusplus_container_name(udt_name); + U64 container_name_opl = cv2r_end_of_cplusplus_container_name(udt_name); String8 container_name = str8_chop(str8_prefix(udt_name, container_name_opl), 2); String8 leaf_name = str8_skip(udt_name, container_name_opl); diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 59b37521..b5d59c8e 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1,5140 +1,6 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -// TODO(rjf): eliminate redundant null checks, just always allocate -// empty results, and have nulls gracefully fall through -// -// (search for != 0 instances, inserted to prevent prior crashes) - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -p2r_end_of_cplusplus_container_name(String8 str) -{ - // NOTE: This finds the index one past the last "::" contained in str. - // if no "::" is contained in str, then the returned index is 0. - // The intent is that [0,clamp_bot(0,result - 2)) gives the - // "container name" and [result,str.size) gives the leaf name. - U64 result = 0; - if(str.size >= 2) - { - S64 template_nest_depth = 0; - for(U64 i = str.size; i >= 2; i -= 1) - { - if(template_nest_depth == 0 && str.str[i - 2] == ':' && str.str[i - 1] == ':') - { - result = i; - break; - } - if(str.str[i-1] == '>') - { - template_nest_depth += 1; - } - else if(str.str[i-1] == '<') - { - template_nest_depth -= 1; - template_nest_depth = ClampBot(template_nest_depth, 0); - } - } - } - return result; -} - -internal U64 -p2r_hash_from_voff(U64 voff) -{ - U64 hash = (voff >> 3) ^ ((7 & voff) << 6); - return hash; -} - -internal int -p2r_namespace_node_is_before(void *raw_a, void *raw_b) -{ - P2R_NamespaceNode **a = (P2R_NamespaceNode **)raw_a, **b = (P2R_NamespaceNode **)raw_b; - return (str8_compar(a[0]->string, b[0]->string, 0) < 0); -} - -//////////////////////////////// -//~ rjf: COFF <-> RDI Canonical Conversions - -internal RDI_BinarySectionFlags -p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) -{ - RDI_BinarySectionFlags result = 0; - if(flags & COFF_SectionFlag_MemRead) - { - result |= RDI_BinarySectionFlag_Read; - } - if(flags & COFF_SectionFlag_MemWrite) - { - result |= RDI_BinarySectionFlag_Write; - } - if(flags & COFF_SectionFlag_MemExecute) - { - result |= RDI_BinarySectionFlag_Execute; - } - return(result); -} - -//////////////////////////////// -//~ rjf: CodeView <-> RDI Canonical Conversions - -internal RDI_Arch -p2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) -{ - RDI_Arch result = 0; - switch(cv_arch) - { - case CV_Arch_8086:{}break; - case CV_Arch_X64:{result = RDI_Arch_X64;}break; - //case CV_Arch_8080: break; - //case CV_Arch_80286: break; - //case CV_Arch_80386: break; - //case CV_Arch_80486: break; - //case CV_Arch_PENTIUM: break; - //case CV_Arch_PENTIUMII: break; - //case CV_Arch_PENTIUMIII: break; - //case CV_Arch_MIPS: break; - //case CV_Arch_MIPS16: break; - //case CV_Arch_MIPS32: break; - //case CV_Arch_MIPS64: break; - //case CV_Arch_MIPSI: break; - //case CV_Arch_MIPSII: break; - //case CV_Arch_MIPSIII: break; - //case CV_Arch_MIPSIV: break; - //case CV_Arch_MIPSV: break; - //case CV_Arch_M68000: break; - //case CV_Arch_M68010: break; - //case CV_Arch_M68020: break; - //case CV_Arch_M68030: break; - //case CV_Arch_M68040: break; - //case CV_Arch_ALPHA: break; - //case CV_Arch_ALPHA_21164: break; - //case CV_Arch_ALPHA_21164A: break; - //case CV_Arch_ALPHA_21264: break; - //case CV_Arch_ALPHA_21364: break; - //case CV_Arch_PPC601: break; - //case CV_Arch_PPC603: break; - //case CV_Arch_PPC604: break; - //case CV_Arch_PPC620: break; - //case CV_Arch_PPCFP: break; - //case CV_Arch_PPCBE: break; - //case CV_Arch_SH3: break; - //case CV_Arch_SH3E: break; - //case CV_Arch_SH3DSP: break; - //case CV_Arch_SH4: break; - //case CV_Arch_SHMEDIA: break; - //case CV_Arch_ARM3: break; - //case CV_Arch_ARM4: break; - //case CV_Arch_ARM4T: break; - //case CV_Arch_ARM5: break; - //case CV_Arch_ARM5T: break; - //case CV_Arch_ARM6: break; - //case CV_Arch_ARM_XMAC: break; - //case CV_Arch_ARM_WMMX: break; - //case CV_Arch_ARM7: break; - //case CV_Arch_OMNI: break; - //case CV_Arch_IA64_1: break; - //case CV_Arch_IA64_2: break; - //case CV_Arch_CEE: break; - //case CV_Arch_AM33: break; - //case CV_Arch_M32R: break; - //case CV_Arch_TRICORE: break; - //case CV_Arch_EBC: break; - //case CV_Arch_THUMB: break; - //case CV_Arch_ARMNT: break; - //case CV_Arch_ARM64: break; - //case CV_Arch_D3D11_SHADER: break; - } - return result; -} - -internal RDI_RegCode -p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code) -{ - RDI_RegCode result = 0; - switch(arch) - { - case RDI_Arch_X64: - { - switch(reg_code) - { -#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX64_##RDN; break; - CV_Reg_X64_XList(X) -#undef X - } - }break; - } - return(result); -} - -internal RDI_Language -p2r_rdi_language_from_cv_language(CV_Language cv_language) -{ - RDI_Language result = 0; - switch(cv_language) - { - case CV_Language_C: result = RDI_Language_C; break; - case CV_Language_CXX: result = RDI_Language_CPlusPlus; break; - //case CV_Language_FORTRAN: result = ; break; - //case CV_Language_MASM: result = ; break; - //case CV_Language_PASCAL: result = ; break; - //case CV_Language_BASIC: result = ; break; - //case CV_Language_COBOL: result = ; break; - //case CV_Language_LINK: result = ; break; - //case CV_Language_CVTRES: result = ; break; - //case CV_Language_CVTPGD: result = ; break; - //case CV_Language_CSHARP: result = ; break; - //case CV_Language_VB: result = ; break; - //case CV_Language_ILASM: result = ; break; - //case CV_Language_JAVA: result = ; break; - //case CV_Language_JSCRIPT: result = ; break; - //case CV_Language_MSIL: result = ; break; - //case CV_Language_HLSL: result = ; break; - } - return(result); -} - -internal RDI_TypeKind -p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type) -{ - RDI_TypeKind result = RDI_TypeKind_Null; - switch(basic_type) - { - case CV_BasicType_VOID: {result = RDI_TypeKind_Void;}break; - case CV_BasicType_HRESULT: {result = RDI_TypeKind_HResult;}break; - - case CV_BasicType_RCHAR: - case CV_BasicType_CHAR: - case CV_BasicType_CHAR8: - {result = RDI_TypeKind_Char8;}break; - - case CV_BasicType_UCHAR: {result = RDI_TypeKind_UChar8;}break; - case CV_BasicType_WCHAR: {result = RDI_TypeKind_UChar16;}break; - case CV_BasicType_CHAR16: {result = RDI_TypeKind_Char16;}break; - case CV_BasicType_CHAR32: {result = RDI_TypeKind_Char32;}break; - - case CV_BasicType_BOOL8: - case CV_BasicType_INT8: - {result = RDI_TypeKind_S8;}break; - - case CV_BasicType_BOOL16: - case CV_BasicType_INT16: - case CV_BasicType_SHORT: - {result = RDI_TypeKind_S16;}break; - - case CV_BasicType_BOOL32: - case CV_BasicType_INT32: - case CV_BasicType_LONG: - {result = RDI_TypeKind_S32;}break; - - case CV_BasicType_BOOL64: - case CV_BasicType_INT64: - case CV_BasicType_QUAD: - {result = RDI_TypeKind_S64;}break; - - case CV_BasicType_INT128: - case CV_BasicType_OCT: - {result = RDI_TypeKind_S128;}break; - - case CV_BasicType_UINT8: {result = RDI_TypeKind_U8;}break; - - case CV_BasicType_UINT16: - case CV_BasicType_USHORT: - {result = RDI_TypeKind_U16;}break; - - case CV_BasicType_UINT32: - case CV_BasicType_ULONG: - {result = RDI_TypeKind_U32;}break; - - case CV_BasicType_UINT64: - case CV_BasicType_UQUAD: - {result = RDI_TypeKind_U64;}break; - - case CV_BasicType_UINT128: - case CV_BasicType_UOCT: - {result = RDI_TypeKind_U128;}break; - - case CV_BasicType_FLOAT16:{result = RDI_TypeKind_F16;}break; - case CV_BasicType_FLOAT32:{result = RDI_TypeKind_F32;}break; - case CV_BasicType_FLOAT32PP:{result = RDI_TypeKind_F32PP;}break; - case CV_BasicType_FLOAT48:{result = RDI_TypeKind_F48;}break; - case CV_BasicType_FLOAT64:{result = RDI_TypeKind_F64;}break; - case CV_BasicType_FLOAT80:{result = RDI_TypeKind_F80;}break; - case CV_BasicType_FLOAT128:{result = RDI_TypeKind_F128;}break; - case CV_BasicType_COMPLEX32:{result = RDI_TypeKind_ComplexF32;}break; - case CV_BasicType_COMPLEX64:{result = RDI_TypeKind_ComplexF64;}break; - case CV_BasicType_COMPLEX80:{result = RDI_TypeKind_ComplexF80;}break; - case CV_BasicType_COMPLEX128:{result = RDI_TypeKind_ComplexF128;}break; - case CV_BasicType_PTR:{result = RDI_TypeKind_Handle;}break; - } - return result; -} - -internal RDI_ChecksumKind -p2r_rdi_from_cv_c13_checksum_kind(CV_C13ChecksumKind k) -{ - RDI_ChecksumKind result = RDI_ChecksumKind_NULL; - switch((CV_C13ChecksumKindEnum)k) - { - case CV_C13ChecksumKind_Null: {result = RDI_ChecksumKind_NULL;}break; - case CV_C13ChecksumKind_MD5: {result = RDI_ChecksumKind_MD5;}break; - case CV_C13ChecksumKind_SHA1: {result = RDI_ChecksumKind_SHA1;}break; - case CV_C13ChecksumKind_SHA256:{result = RDI_ChecksumKind_SHA256;}break; - } - return result; -} - -//////////////////////////////// -//~ rjf: Location Info Building Helpers - -internal RDI_RegCode -p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg) -{ - RDI_RegCode result = 0; - switch(arch) - { - case RDI_Arch_X64: - { - switch(encoded_reg) - { - case CV_EncodedFramePtrReg_StackPtr: - { - result = RDI_RegCodeX64_rsp; - }break; - case CV_EncodedFramePtrReg_FramePtr: - { - result = RDI_RegCodeX64_rbp; - }break; - case CV_EncodedFramePtrReg_BasePtr: - { - result = RDI_RegCodeX64_r13; - }break; - } - }break; - } - return result; -} - -internal RDIM_Location -p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) -{ - RDIM_Location result = {0}; - if(0 <= offset && offset <= (S64)max_U16) - { - if(extra_indirection) - { - result.kind = RDI_LocationKind_AddrAddrRegPlusOff; - result.reg_code = reg_code; - result.offset = offset; - } - else - { - result.kind = RDI_LocationKind_AddrRegPlusOff; - result.reg_code = reg_code; - result.offset = offset; - } - } - else - { - RDIM_EvalBytecode bytecode = {0}; - U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); - rdim_bytecode_push_sconst(arena, &bytecode, offset); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); - if(extra_indirection) - { - U64 addr_size = rdi_addr_size_from_arch(arch); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); - } - result.kind = RDI_LocationKind_AddrBytecodeStream; - result.bytecode = bytecode; - } - return result; -} - -internal void -p2r_location_case_list_push_over_lvar_addr_range(Arena *arena, RDIM_LocationCaseList *loc_cases, RDIM_Location loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) -{ - //- rjf: extract range info - U64 voff_first = 0; - U64 voff_opl = 0; - if(section != 0) - { - voff_first = section->voff + range->off; - voff_opl = voff_first + range->len; - } - - //- rjf: emit location for ranges not coverd by gaps - CV_LvarAddrGap *gap_ptr = gaps; - U64 voff_cursor = voff_first; - for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) - { - U64 voff_gap_first = voff_first + gap_ptr->off; - U64 voff_gap_opl = voff_gap_first + gap_ptr->len; - if(voff_cursor < voff_gap_first) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; - rdim_location_case_list_push(arena, loc_cases, loc, voff_range); - } - voff_cursor = voff_gap_opl; - } - - //- rjf: emit remaining range - if(voff_cursor < voff_opl) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; - rdim_location_case_list_push(arena, loc_cases, loc, voff_range); - } -} - -//////////////////////////////// -//~ rjf: Top-Level Conversion Entry Point - -internal RDIM_BakeParams -p2r_convert(Arena *arena, P2R_ConvertParams *params) -{ - Temp scratch = scratch_begin(&arena, 1); - - ////////////////////////////////////////////////////////////// - //- rjf: do base MSF parse - // - MSF_Parsed *msf = 0; - ProfScope("do base MSF parse") - { - // rjf: setup output buckets - MSF_RawStreamTable *msf_raw_stream_table = 0; - U64 *msf_stream_take_counter = 0; - if(lane_idx() == 0) - { - msf_raw_stream_table = msf_raw_stream_table_from_data(scratch.arena, params->input_pdb_data); - msf = push_array(scratch.arena, MSF_Parsed, 1); - msf->page_size = msf_raw_stream_table->page_size; - msf->page_count = msf_raw_stream_table->total_page_count; - msf->stream_count = msf_raw_stream_table->stream_count; - msf->streams = push_array(scratch.arena, String8, msf->stream_count); - msf_stream_take_counter = push_array(scratch.arena, U64, 1); - } - lane_sync_u64(&msf, 0); - lane_sync_u64(&msf_raw_stream_table, 0); - - // rjf: do wide fill - { - lane_sync_u64(&msf_stream_take_counter, 0); - for(;;) - { - U64 stream_idx = ins_atomic_u64_inc_eval(msf_stream_take_counter) - 1; - if(stream_idx >= msf->stream_count) - { - break; - } - msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, msf_raw_stream_table, stream_idx); - } - } - lane_sync(); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: do top-level MSF/PDB extraction - // - PDB_Info *pdb_info = 0; - PDB_NamedStreamTable *named_streams = 0; - ProfScope("do top-level MSF/PDB extraction") if(lane_idx() == 0) - { - ProfScope("parse PDB info") - { - String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); - pdb_info = pdb_info_from_data(scratch.arena, info_data); - if(pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) - { - log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); - } - } - ProfScope("parse named streams table") - { - named_streams = pdb_named_stream_table_from_info(scratch.arena, pdb_info); - } - } - lane_sync_u64(&pdb_info, 0); - lane_sync_u64(&named_streams, 0); - - ////////////////////////////////////////////////////////////// - //- rjf: parse PDB strtbl & top-level streams - // - PDB_Strtbl *strtbl = 0; - String8 raw_strtbl = {0}; - PDB_DbiParsed *dbi = 0; - PDB_TpiParsed *tpi = 0; - PDB_TpiParsed *ipi = 0; - ProfScope("parse PDB strtbl & top-level streams") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") - { - MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; - String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - strtbl = pdb_strtbl_from_data(scratch.arena, strtbl_data); - raw_strtbl = str8_substr(strtbl_data, rng_1u64(strtbl->strblock_min, strtbl->strblock_max)); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") - { - String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); - dbi = pdb_dbi_from_data(scratch.arena, dbi_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") - { - String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); - tpi = pdb_tpi_from_data(scratch.arena, tpi_data); - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") - { - String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); - ipi = pdb_tpi_from_data(scratch.arena, ipi_data); - } - } - lane_sync_u64(&strtbl, lane_from_task_idx(0)); - lane_sync_u64(&raw_strtbl.size, lane_from_task_idx(0)); - lane_sync_u64(&raw_strtbl.str, lane_from_task_idx(0)); - lane_sync_u64(&dbi, lane_from_task_idx(1)); - lane_sync_u64(&tpi, lane_from_task_idx(2)); - lane_sync_u64(&ipi, lane_from_task_idx(3)); - - ////////////////////////////////////////////////////////////// - //- rjf: unpack DBI - // - COFF_SectionHeaderArray coff_sections = {0}; - PDB_GsiParsed *gsi = 0; - PDB_GsiParsed *psi_gsi_part = 0; - ProfScope("unpack DBI") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") - { - MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; - String8 section_data = msf_data_from_stream(msf, section_stream); - coff_sections = pdb_coff_section_array_from_data(scratch.arena, section_data); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") - { - String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); - gsi = pdb_gsi_from_data(scratch.arena, gsi_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") - { - String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); - String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); - psi_gsi_part = pdb_gsi_from_data(scratch.arena, psi_data_gsi_part); - } - } - lane_sync_u64(&coff_sections.v, lane_from_task_idx(0)); - lane_sync_u64(&coff_sections.count, lane_from_task_idx(0)); - lane_sync_u64(&gsi, lane_from_task_idx(1)); - lane_sync_u64(&psi_gsi_part, lane_from_task_idx(2)); - - ////////////////////////////////////////////////////////////// - //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units - // - U64 exe_hash = 0; - PDB_TpiHashParsed *tpi_hash = 0; - CV_LeafParsed *tpi_leaf = 0; - PDB_TpiHashParsed *ipi_hash = 0; - CV_LeafParsed *ipi_leaf = 0; - PDB_CompUnitArray *comp_units = 0; - PDB_CompUnitContributionArray *comp_unit_contributions = 0; - ProfScope("hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") - { - exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") - { - String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); - if(!(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs))) - { - hash_data = str8_zero(); - } - tpi_hash = pdb_tpi_hash_from_data(scratch.arena, strtbl, tpi, hash_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") - { - String8 leaf_data = pdb_leaf_data_from_tpi(tpi); - tpi_leaf = cv_leaf_from_data(scratch.arena, leaf_data, tpi->itype_first); - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") - { - String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); - if(!(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs))) - { - hash_data = str8_zero(); - } - ipi_hash = pdb_tpi_hash_from_data(scratch.arena, strtbl, ipi, hash_data); - } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") - { - String8 leaf_data = pdb_leaf_data_from_tpi(ipi); - ipi_leaf = cv_leaf_from_data(scratch.arena, leaf_data, ipi->itype_first); - } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") - { - String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); - comp_units = pdb_comp_unit_array_from_data(scratch.arena, comp_units_data); - } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") - { - String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); - comp_unit_contributions = push_array(scratch.arena, PDB_CompUnitContributionArray, 1); - comp_unit_contributions[0] = pdb_comp_unit_contribution_array_from_data(scratch.arena, contribs_data, coff_sections); - } - } - lane_sync_u64(&exe_hash, lane_from_task_idx(0)); - lane_sync_u64(&tpi_hash, lane_from_task_idx(1)); - lane_sync_u64(&tpi_leaf, lane_from_task_idx(2)); - lane_sync_u64(&ipi_hash, lane_from_task_idx(3)); - lane_sync_u64(&ipi_leaf, lane_from_task_idx(4)); - lane_sync_u64(&comp_units, lane_from_task_idx(5)); - lane_sync_u64(&comp_unit_contributions, lane_from_task_idx(6)); - - ////////////////////////////////////////////////////////////// - //- rjf: bucket compilation unit contributions - // - RDIM_Rng1U64ChunkList *unit_ranges = 0; - ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) - { - unit_ranges = push_array(scratch.arena, RDIM_Rng1U64ChunkList, comp_units->count + 1); - for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_contributions->count; comp_unit_idx += 1) - { - PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[comp_unit_idx]; - if(contribution->mod < comp_units->count) - { - RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; - rdim_rng1u64_chunk_list_push(arena, &unit_ranges[contribution->mod + 1], 256, r); - } - } - } - lane_sync_u64(&unit_ranges, 0); - - ////////////////////////////////////////////////////////////// - //- rjf: parse all syms & c13 line info streams - // - U64 all_syms_count = 0; - CV_SymParsed **all_syms = 0; - CV_C13Parsed **all_c13s = 0; - ProfScope("parse all syms & c13 line info streams") - { - //- rjf: setup outputs - U64 *task_counter = 0; - if(lane_idx() == 0) - { - all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI - all_syms = push_array(scratch.arena, CV_SymParsed *, all_syms_count); - all_c13s = push_array(scratch.arena, CV_C13Parsed *, all_syms_count); - task_counter = push_array(scratch.arena, U64, 1); - } - lane_sync_u64(&all_syms_count, 0); - lane_sync_u64(&all_syms, 0); - lane_sync_u64(&all_c13s, 0); - - //- rjf: wide fill - { - lane_sync_u64(&task_counter, 0); - U64 task_count = all_syms_count; - for(;;) - { - U64 task_idx = ins_atomic_u64_inc_eval(task_counter) - 1; - if(task_idx >= task_count) - { - break; - } - if(task_idx > 0) - { - PDB_CompUnit *unit = comp_units->units[task_idx-1]; - String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); - String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); - all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); - } - else - { - String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); - all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: calculate EXE's max voff - // - U64 exe_voff_max = 0; - { - Temp scratch2 = scratch_begin(&scratch.arena, 1); - - // rjf: set up - U64 *lane_voff_maxes = 0; - if(lane_idx() == 0) - { - lane_voff_maxes = push_array(scratch2.arena, U64, lane_count()); - } - lane_sync_u64(&lane_voff_maxes, 0); - - // rjf: compute each lane's max - { - U64 lane_voff_max = 0; - COFF_SectionHeader *sections = coff_sections.v; - Rng1U64 range = lane_range(coff_sections.count); - for EachInRange(idx, range) - { - lane_voff_max = Max(lane_voff_max, sections[idx].voff + sections[idx].vsize); - } - lane_voff_maxes[lane_idx()] = lane_voff_max; - } - lane_sync(); - - // rjf: find max from all lanes - U64 exe_voff_max = 0; - for EachIndex(l_idx, lane_count()) - { - exe_voff_max = Max(exe_voff_max, lane_voff_maxes[l_idx]); - } - lane_sync(); - - scratch_end(scratch2); - } - - ////////////////////////////////////////////////////////////// - //- rjf: determine architecture - // - RDI_Arch arch = RDI_Arch_NULL; - U64 arch_addr_size = 0; - { - // - // TODO(rjf): in some cases, the first compilation unit has a zero - // architecture, as it's sometimes used as a "nil" unit. this causes bugs - // in later stages of conversion - particularly, this was detected via - // busted location info. so i've converted this to a scan-until-we-find-an- - // architecture. however, this may still be fundamentally insufficient, - // because Nick has informed me that x86 units can be linked with x64 - // units, meaning the appropriate architecture at any point in time is not - // a top-level concept, and is rather dependent on to which compilation - // unit particular symbols belong. so in the future, to support that (odd) - // case, we'll need to not only have this be a top-level "contextual" piece - // of info, but to use the appropriate compilation unit's architecture when - // possible. assuming, of course, that we care about supporting that case. - // - for EachIndex(idx, all_syms_count) - { - arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); - if(arch != RDI_Arch_NULL) - { - break; - } - } - arch_addr_size = rdi_addr_size_from_arch(arch); - } - - ////////////////////////////////////////////////////////////// - //- rjf: predict total symbol count - // - U64 symbol_count_prediction = 0; - { - U64 *symbol_count_prediction_ptr = &symbol_count_prediction; - lane_sync_u64(&symbol_count_prediction_ptr, 0); - U64 lane_sym_count = 0; - Rng1U64 range = lane_range(all_syms_count); - for EachInRange(idx, range) - { - lane_sym_count += all_syms[idx]->sym_ranges.count; - } - ins_atomic_u64_add_eval(symbol_count_prediction_ptr, lane_sym_count); - lane_sync(); - symbol_count_prediction = *symbol_count_prediction_ptr; - } - - ////////////////////////////////////////////////////////////// - //- rjf: build link name map - // - P2R_LinkNameMap *link_name_map = 0; - ProfScope("build link name map") if(all_syms_count != 0 && lane_idx() == 0) - { - // rjf: set up - { - link_name_map = push_array(scratch.arena, P2R_LinkNameMap, 1); - link_name_map->buckets_count = Max(1, symbol_count_prediction); - link_name_map->buckets = push_array(scratch.arena, P2R_LinkNameNode *, link_name_map->buckets_count); - } - - // rjf: fill - if(params->subset_flags & RDIM_SubsetFlag_Procedures) - { - CV_SymParsed *sym = all_syms[0]; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - case CV_SymKind_PUB32: - { - // rjf: unpack sym - CV_SymPub32 *pub32 = (CV_SymPub32 *)iter.struct_base; - String8 name = str8_cstring_capped(pub32+1, iter.opl); - COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= coff_sections.count) ? &coff_sections.v[pub32->sec-1] : 0; - U64 voff = 0; - if(section != 0) - { - voff = section->voff + pub32->off; - } - - // rjf: commit to link name map - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%link_name_map->buckets_count; - P2R_LinkNameNode *node = push_array(scratch.arena, P2R_LinkNameNode, 1); - SLLStackPush(link_name_map->buckets[bucket_idx], node); - node->voff = voff; - node->name = name; - }break; - } - } - } - } - lane_sync_u64(&link_name_map, 0); - - ////////////////////////////////////////////////////////////// - //- rjf: gather all file paths - // - P2R_SrcFileStubArray *unit_file_stubs = 0; - U64Array *unit_file_paths_hashes = 0; - ProfScope("gather all file paths") - { - //- rjf: prep outputs - ProfScope("prep outputs") if(lane_idx() == 0) - { - unit_file_stubs = push_array(scratch.arena, P2R_SrcFileStubArray, comp_units->count + 1); - unit_file_paths_hashes = push_array(scratch.arena, U64Array, comp_units->count + 1); - } - lane_sync_u64(&unit_file_stubs, 0); - lane_sync_u64(&unit_file_paths_hashes, 0); - - //- rjf: do wide gather - ProfScope("do wide gather") - { - Temp scratch2 = scratch_begin(&scratch.arena, 1); - - //- rjf: build local hash table to dedup files within this lane - U64 hit_path_slots_count = 4096; - String8Node **hit_path_slots = push_array(scratch2.arena, String8Node *, hit_path_slots_count); - - //- rjf: take units across lanes, find all file paths - U64 *sym_take_counter = lane_idx() == 0 ? push_array(scratch.arena, U64, 1) : 0; - lane_sync_u64(&sym_take_counter, 0); - ProfScope("take units across lanes, find all file paths") - for(;;) - { - //- rjf: take next unit - U64 unit_idx = ins_atomic_u64_inc_eval(sym_take_counter) - 1; - if(unit_idx >= comp_units->count + 1) - { - break; - } - - //- rjf: unpack unit - CV_SymParsed *sym = all_syms[unit_idx]; - CV_C13Parsed *c13 = all_c13s[unit_idx]; - - //- rjf: produce obj name/path - String8 obj_name = str8_lit("*global*"); - if(unit_idx > 0) - { - PDB_CompUnit *comp_unit = comp_units->units[unit_idx-1]; - obj_name = comp_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - } - String8 obj_folder_path = backslashed_from_str8(scratch2.arena, str8_chop_last_slash(obj_name)); - - //- rjf: find all inline site symbols & gather file stubs - P2R_SrcFileStubNode *first_src_file_stub = 0; - P2R_SrcFileStubNode *last_src_file_stub = 0; - U64 src_file_stub_count = 0; - U64 base_voff = 0; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)iter.struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)iter.struct_base; - String8 binary_annots = str8((U8 *)(sym+1), (U64)((U8 *)iter.opl - (U8 *)(sym+1))); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = c13->file_chksms_sub_section; - - // rjf: gathered lines - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - U64 line_count = 0; - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> gather new file name - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null; - String8 checksum_value = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum *)(c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - checksum_kind = checksum->kind; - checksum_value = str8_skip(c13->data, file_chksms->off + last_file_off + sizeof(*checksum)); - checksum_value.size = Min(checksum->len, checksum_value.size); - } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch2.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch2.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch2.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch2.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_sanitized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch2.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_sanitized; - P2R_SrcFileStubNode *stub_n = push_array(scratch2.arena, P2R_SrcFileStubNode, 1); - SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); - src_file_stub_count += 1; - stub_n->v.file_path = str8_copy(scratch.arena, file_path_sanitized); - stub_n->v.checksum_kind = checksum_kind; - stub_n->v.checksum = str8_copy(scratch.arena, checksum_value); - } - line_count = 0; - } - - // rjf: count lines - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - - // rjf: find all files in this unit's (non-inline) line info - if(c13 != 0) - { - ProfScope("find all files in this unit's (non-inline) line info") - for(CV_C13SubSectionNode *node = c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - // rjf: file name -> sanitized file path - String8 file_path = lines_n->v.file_name; - String8 file_path_sanitized = str8_copy(scratch2.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch2.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch2.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch2.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_sanitized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch2.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_sanitized; - P2R_SrcFileStubNode *stub_n = push_array(scratch2.arena, P2R_SrcFileStubNode, 1); - SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); - src_file_stub_count += 1; - stub_n->v.file_path = str8_copy(scratch.arena, file_path_sanitized); - stub_n->v.checksum_kind = lines_n->v.checksum_kind; - stub_n->v.checksum = str8_copy(scratch.arena, lines_n->v.checksum); - } - } - } - } - } - - //- rjf: merge into array for this unit - unit_file_stubs[unit_idx].count = src_file_stub_count; - unit_file_stubs[unit_idx].v = push_array_no_zero(scratch.arena, P2R_SrcFileStub, unit_file_stubs[unit_idx].count); - { - U64 idx = 0; - for EachNode(n, P2R_SrcFileStubNode, first_src_file_stub) - { - unit_file_stubs[unit_idx].v[idx] = n->v; - idx += 1; - } - } - - //- rjf: hash this unit's file paths - U64Array hashes = {0}; - hashes.count = unit_file_stubs[unit_idx].count; - hashes.v = push_array(scratch.arena, U64, hashes.count); - for EachIndex(idx, unit_file_stubs[unit_idx].count) - { - hashes.v[idx] = rdi_hash(unit_file_stubs[unit_idx].v[idx].file_path.str, unit_file_stubs[unit_idx].v[idx].file_path.size); - } - unit_file_paths_hashes[unit_idx] = hashes; - } - lane_sync(); - - scratch_end(scratch2); - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: build unified collection & map for source files - // - RDIM_SrcFileChunkList *all_src_files__sequenceless = 0; - P2R_SrcFileMap *src_file_map = 0; - if(lane_idx() == 0 && params->subset_flags & (RDIM_SubsetFlag_NormalSourcePathNameMap| - RDIM_SubsetFlag_LineInfo| - RDIM_SubsetFlag_InlineLineInfo)) - { - //- rjf: set up table - U64 total_path_count = 0; - ProfScope("set up table") - { - all_src_files__sequenceless = push_array(scratch.arena, RDIM_SrcFileChunkList, 1); - src_file_map = push_array(scratch.arena, P2R_SrcFileMap, 1); - for EachIndex(idx, comp_units->count) - { - total_path_count += unit_file_stubs[idx].count; - } - src_file_map->slots_count = total_path_count + total_path_count/2 + 1; - src_file_map->slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map->slots_count); - } - - //- rjf: fill table - ProfScope("fill table") - { - for EachIndex(idx, comp_units->count) - { - P2R_SrcFileStubArray stubs = unit_file_stubs[idx]; - U64Array hashes = unit_file_paths_hashes[idx]; - for EachIndex(stub_idx, stubs.count) - { - String8 file_path_sanitized = stubs.v[stub_idx].file_path; - CV_C13ChecksumKind c13_checksum_kind = stubs.v[stub_idx].checksum_kind; - String8 checksum = stubs.v[stub_idx].checksum; - U64 file_path_sanitized_hash = hashes.v[stub_idx]; - U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - if(src_file_node == 0) - { - src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(src_file_map->slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, all_src_files__sequenceless, total_path_count); - src_file_node->src_file->path = str8_copy(arena, file_path_sanitized); - src_file_node->src_file->checksum_kind = p2r_rdi_from_cv_c13_checksum_kind(c13_checksum_kind); - src_file_node->src_file->checksum = str8_copy(arena, checksum); - } - } - } - } - } - lane_sync_u64(&all_src_files__sequenceless, 0); - lane_sync_u64(&src_file_map, 0); - - ////////////////////////////////////////////////////////////// - //- rjf: convert unit header info - // - RDIM_UnitChunkList *all_units_ptr = 0; - RDIM_LineTableChunkList *units_line_tables = 0; - RDIM_LineTable **units_first_inline_site_line_tables = 0; - ProfScope("convert unit header info") - { - //- rjf: set up outputs - ProfScope("set up outputs") if(lane_idx() == 0) - { - all_units_ptr = push_array(scratch.arena, RDIM_UnitChunkList, 1); - if(params->subset_flags & RDIM_SubsetFlag_Units) - { - for EachIndex(idx, comp_units->count + 1) - { - rdim_unit_chunk_list_push(arena, all_units_ptr, comp_units->count + 1); - } - } - units_line_tables = push_array(scratch.arena, RDIM_LineTableChunkList, comp_units->count + 1); - units_first_inline_site_line_tables = push_array(scratch.arena, RDIM_LineTable *, comp_units->count + 1); - } - lane_sync_u64(&all_units_ptr, 0); - lane_sync_u64(&units_line_tables, 0); - lane_sync_u64(&units_first_inline_site_line_tables, 0); - RDIM_Unit *units = all_units_ptr->first ? all_units_ptr->first->v : 0; - U64 units_count = all_units_ptr->first ? all_units_ptr->first->count : 0; - - //- rjf: do per-lane work - if(params->subset_flags & (RDIM_SubsetFlag_Units| - RDIM_SubsetFlag_NormalSourcePathNameMap| - RDIM_SubsetFlag_LineInfo| - RDIM_SubsetFlag_InlineLineInfo)) - { - U64 *sym_take_counter = lane_idx() == 0 ? push_array(scratch.arena, U64, 1) : 0; - lane_sync_u64(&sym_take_counter, 0); - ProfScope("wide fill") for(;;) - { - //- rjf: take next unit - U64 unit_idx = ins_atomic_u64_inc_eval(sym_take_counter) - 1; - if(unit_idx >= units_count) - { - break; - } - Temp scratch = scratch_begin(&arena, 1); - RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; - PDB_CompUnit *src_unit = (unit_idx > 0 ? comp_units->units[unit_idx-1] : 0); - CV_SymParsed *src_unit_sym = all_syms[unit_idx]; - CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx]; - RDIM_Unit *dst_unit = 0; - if(params->subset_flags & RDIM_SubsetFlag_Units) { dst_unit = &units[unit_idx]; } - - // rjf: extract unit name - String8 unit_name = {0}; - if(src_unit != 0) - { - unit_name = src_unit->obj_name; - if(unit_name.size != 0) - { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) - { - unit_name = unit_name_past_last_slash; - } - } - } - else - { - unit_name = str8_lit("*global*"); - } - - // rjf: produce obj name/path - String8 obj_name = {0}; - if(src_unit != 0) - { - obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - // rjf: extract unit group name - String8 group_name = {0}; - if(src_unit != 0) - { - group_name = src_unit->group_name; - } - - //- rjf: main unit line table conversion - RDIM_LineTable *line_table = 0; - if(params->subset_flags & RDIM_SubsetFlag_LineInfo && src_unit_c13 != 0) ProfScope("main unit line table conversion") - { - for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) - { - for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); - } - } - } - } - } - - //- rjf: fill unit - if(dst_unit != 0) - { - dst_unit->unit_name = unit_name; - dst_unit->compiler_name = src_unit_sym->info.compiler_name; - dst_unit->object_file = obj_name; - dst_unit->archive_file = group_name; - dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); - dst_unit->line_table = line_table; - dst_unit->voff_ranges = unit_ranges[unit_idx]; - } - - //- rjf: build per-inline-site line tables - if(params->subset_flags & RDIM_SubsetFlag_InlineLineInfo) ProfScope("build per-inline-site line tables") - { - U64 base_voff = 0; - for(CV_RecIter iter = {0}; cv_rec_next(src_unit_sym->data, &src_unit_sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)iter.struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)iter.struct_base; - String8 binary_annots = str8((U8 *)(sym+1), (U64)((U8 *)iter.opl - (U8 *)(sym+1))); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - typedef struct LineChunk LineChunk; - struct LineChunk - { - LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - RDIM_LineTable* line_table = 0; - - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && total_line_chunk_line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> push line chunks gathered for this file - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - - // rjf: gather all lines - RDI_U64 *voffs = 0; - RDI_U32 *line_nums = 0; - RDI_U64 line_count = 0; - if(src_file_node != 0) - { - voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - line_count = total_line_chunk_line_count; - U64 dst_idx = 0; - for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) - { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); - MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); - dst_idx += chunk->count; - } - } - - // rjf: push - if(line_count != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(units_first_inline_site_line_tables[unit_idx] == 0) - { - units_first_inline_site_line_tables[unit_idx] = line_table; - } - } - rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); - } - - // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; - total_line_chunk_line_count = 0; - } - - // rjf: new line -> emit to chunk - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) - { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 8; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); - } - chunk->voffs[chunk->count] = step.line_voff; - chunk->voffs[chunk->count+1] = step.line_voff_end; - chunk->line_nums[chunk->count] = step.ln; - chunk->count += 1; - total_line_chunk_line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - - scratch_end(scratch); - } - } - } - lane_sync(); - RDIM_UnitChunkList all_units = *all_units_ptr; - - ////////////////////////////////////////////////////////////// - //- rjf: join all line tables - // - RDIM_LineTableChunkList all_line_tables = {0}; - RDIM_LineTableChunkList *all_line_tables_ptr = &all_line_tables; - ProfScope("join all line tables") if(lane_idx() == 0) - { - for EachIndex(idx, comp_units->count + 1) - { - rdim_line_table_chunk_list_concat_in_place(&all_line_tables, &units_line_tables[idx]); - } - } - lane_sync_u64(&all_line_tables_ptr, 0); - all_line_tables = *all_line_tables_ptr; - - ////////////////////////////////////////////////////////////// - //- rjf: equip source files with line sequences - // - ProfScope("equip source files with line sequences") if(lane_idx() == 0) - { - for(RDIM_LineTableChunkNode *line_table_chunk_n = all_line_tables.first; - line_table_chunk_n != 0; - line_table_chunk_n = line_table_chunk_n->next) - { - for EachIndex(chunk_line_table_idx, line_table_chunk_n->count) - { - RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; - for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) - { - rdim_src_file_push_line_sequence(arena, all_src_files__sequenceless, s->v.src_file, &s->v); - } - } - } - } - lane_sync(); - RDIM_SrcFileChunkList all_src_files = *all_src_files__sequenceless; - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 1: produce type forward resolution map - // - // this map is used to resolve usage of "incomplete structs" in codeview's - // type info. this often happens when e.g. "struct Foo" is used to refer to - // a later-defined "Foo", which actually contains members and so on. we want - // to hook types up to their actual destination complete types wherever - // possible, and so this map can be used to do that in subsequent stages. - // - CV_TypeId *itype_fwd_map = 0; - CV_TypeId itype_first = 0; - CV_TypeId itype_opl = 0; - ProfScope("types pass 1: produce type forward resolution map") - { - //- rjf: allocate forward resolution map - if(lane_idx() == 0) - { - itype_first = tpi_leaf->itype_first; - itype_opl = tpi_leaf->itype_opl; - itype_fwd_map = push_array(scratch.arena, CV_TypeId, (U64)itype_opl); - } - lane_sync_u64(&itype_first, 0); - lane_sync_u64(&itype_opl, 0); - lane_sync_u64(&itype_fwd_map, 0); - - //- rjf: do wide fill - if(params->subset_flags & RDIM_SubsetFlag_Types) - { - Rng1U64 range = lane_range(itype_opl); - for EachInRange(idx, range) - { - CV_TypeId itype = (CV_TypeId)idx; - if(itype < itype_first) { continue; } - - //- rjf: determine if this itype resolves to another - CV_TypeId itype_fwd = 0; - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // rjf: unpack leaf header - CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // rjf: unpack leaf header - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // rjf: unpack leaf - CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves tos - if(lf_union->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && - ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // rjf: unpack leaf - CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf_enum + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_enum->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && - ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - } - } - - //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map - if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) - { - itype_fwd_map[itype] = itype_fwd; - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 2: produce per-itype itype chain - // - // this pass is to ensure that subsequent passes always produce types for - // dependent itypes first - guaranteeing rdi's "only reference backward" - // rule (which eliminates cycles). each itype slot gets a list of itypes, - // starting with the deepest dependency - when types are produced per-itype, - // this chain is walked, so that deeper dependencies are built first, and - // as such, always show up *earlier* in the actually built types. - // - P2R_TypeIdChain **itype_chains = 0; - ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") - { - //- rjf: allocate itype chain table - if(lane_idx() == 0) - { - itype_chains = push_array(scratch.arena, P2R_TypeIdChain *, (U64)itype_opl); - } - lane_sync_u64(&itype_chains, 0); - - //- rjf: do wide fill - if(params->subset_flags & RDIM_SubsetFlag_Types) - { - Rng1U64 range = lane_range(itype_opl); - for EachInRange(idx, range) - { - CV_TypeId itype = (CV_TypeId)idx; - - //- rjf: push initial itype - should be final-visited-itype for this itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = itype; - SLLStackPush(itype_chains[itype], c); - } - - //- rjf: skip basic types for dependency walk - if(itype < tpi_leaf->itype_first) - { - continue; - } - - //- rjf: walk dependent types, push to chain - Temp scratch2 = scratch_begin(&scratch.arena, 1); - P2R_TypeIdChain start_walk_task = {0, itype}; - P2R_TypeIdChain *first_walk_task = &start_walk_task; - P2R_TypeIdChain *last_walk_task = &start_walk_task; - for(P2R_TypeIdChain *walk_task = first_walk_task; - walk_task != 0; - walk_task = walk_task->next) - { - CV_TypeId walk_itype = itype_fwd_map[walk_task->itype] ? itype_fwd_map[walk_task->itype] : walk_task->itype; - if(walk_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= walk_itype) - { - continue; - } - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[walk_itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - - // rjf: push return itypes to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk return itype - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLStackPush(itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLStackPush(itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLStackPush(itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - } - } - } - scratch_end(scratch2); - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 3: gather all unique namespaces from types - // - P2R_NamespaceNode **all_namespace_slots = 0; - U64 all_namespace_slots_count = 0; - ProfScope("gather all unique namespaces from types") - { - Temp scratch2 = scratch_begin(&scratch.arena, 1); - - //- rjf: find all unique namespaces on this lane - U64 namespace_slots_count = (U64)itype_opl / lane_count(); - namespace_slots_count = Max(1, namespace_slots_count); - String8Node **namespace_slots = push_array(scratch2.arena, String8Node *, namespace_slots_count); - U64 namespace_count = 0; - Rng1U64 range = lane_range(itype_opl); - for EachInRange(idx, range) - { - CV_TypeId itype = (CV_TypeId)idx; - if(itype < itype_first) { continue; } - - // rjf: unpack itype info - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - - // rjf: gather names from types - String8 name = {0}; - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: CLASS/STRUCT - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - CV_LeafUnion *lf_struct = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf_enum = (CV_LeafEnum *)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf_enum+1); - name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }break; - - //- rjf: ALIAS - case CV_LeafKind_ALIAS: - { - CV_LeafAlias *lf = (CV_LeafAlias *)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }break; - } - } - - // rjf: add namespaces from strings - String8 name_before_templates = str8_prefix(name, str8_find_needle(name, 0, str8_lit("<"), 0)); - for(U64 scope_resolution_operator_pos = 0; - scope_resolution_operator_pos < name_before_templates.size; - scope_resolution_operator_pos = str8_find_needle(name_before_templates, scope_resolution_operator_pos+1, str8_lit("::"), 0)) - { - String8 namespace_fully_qualified_name = str8_substr(name_before_templates, r1u64(0, scope_resolution_operator_pos)); - if(namespace_fully_qualified_name.size != 0) - { - namespace_count += 1; - U64 hash = u64_hash_from_str8(namespace_fully_qualified_name); - U64 slot_idx = hash%namespace_slots_count; - B32 already_exists = 0; - for(String8Node *n = namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, namespace_fully_qualified_name, 0)) - { - already_exists = 1; - break; - } - } - if(!already_exists) - { - String8Node *node = push_array(scratch2.arena, String8Node, 1); - SLLStackPush(namespace_slots[slot_idx], node); - node->string = namespace_fully_qualified_name; - } - } - } - } - - //- rjf: on lane 0 -> combine all unique namespaces to singular map - { - // rjf: gather lane maps - typedef struct LaneNamespaceTable LaneNamespaceTable; - struct LaneNamespaceTable - { - String8Node **slots; - U64 slots_count; - }; - U64 total_namespace_count = 0; - U64 *total_namespace_count_ptr = &total_namespace_count; - LaneNamespaceTable *lane_namespace_tables = 0; - if(lane_idx() == 0) - { - lane_namespace_tables = push_array(scratch2.arena, LaneNamespaceTable, lane_count()); - } - lane_sync_u64(&total_namespace_count_ptr, 0); - lane_sync_u64(&lane_namespace_tables, 0); - lane_namespace_tables[lane_idx()].slots = namespace_slots; - lane_namespace_tables[lane_idx()].slots_count = namespace_slots_count; - ins_atomic_u64_add_eval(total_namespace_count_ptr, namespace_count); - lane_sync(); - - // rjf: combine - if(lane_idx() == 0) - { - all_namespace_slots_count = *total_namespace_count_ptr / 3; - all_namespace_slots_count = Max(all_namespace_slots_count, 1); - all_namespace_slots = push_array(scratch.arena, P2R_NamespaceNode *, all_namespace_slots_count); - for EachIndex(l_idx, lane_count()) - { - LaneNamespaceTable *tbl = &lane_namespace_tables[l_idx]; - for EachIndex(slot_idx, tbl->slots_count) - { - for(String8Node *n = tbl->slots[slot_idx]; n != 0; n = n->next) - { - U64 hash = u64_hash_from_str8(n->string); - U64 dst_slot_idx = hash%all_namespace_slots_count; - B32 already_exists = 0; - for(P2R_NamespaceNode *dst_n = all_namespace_slots[dst_slot_idx]; dst_n != 0; dst_n = dst_n->next) - { - if(str8_match(dst_n->string, n->string, 0)) - { - already_exists = 1; - break; - } - } - if(!already_exists) - { - P2R_NamespaceNode *dst_n = push_array(scratch.arena, P2R_NamespaceNode, 1); - dst_n->string = n->string; - SLLStackPush(all_namespace_slots[dst_slot_idx], dst_n); - } - } - } - } - } - lane_sync_u64(&all_namespace_slots_count, 0); - lane_sync_u64(&all_namespace_slots, 0); - } - scratch_end(scratch2); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 4: construct all types from TPI - // - // this doesn't gather struct/class/union/enum members, which is done by - // subsequent passes, to build RDI "UDT" information, which is distinct - // from regular type info. - // - RDIM_TypeChunkList all_types__pre_typedefs = {0}; - RDIM_TypeChunkList *all_types__pre_typedefs_ptr = &all_types__pre_typedefs; - RDIM_Type **itype_type_ptrs = 0; - RDIM_Type **basic_type_ptrs = 0; - if(lane_idx() == 0) ProfScope("types pass 4: construct all root/stub types from TPI") - { -#define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - itype_type_ptrs = push_array(scratch.arena, RDIM_Type *, (U64)(itype_opl)); - basic_type_ptrs = push_array(scratch.arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); - - //////////////////////////// - //- rjf: build basic types - // - if(params->subset_flags & RDIM_SubsetFlag_Types) - { - 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, all_types__pre_typedefs_ptr, 512); - type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); - type->kind = type_kind; - type->byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type_ptrs[type_kind - RDI_TypeKind_FirstBuiltIn] = type; - } - } - - //////////////////////////// - //- rjf: build basic type aliases - // - if(params->subset_flags & RDIM_SubsetFlag_Types) - { - RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, arch); - RDI_TypeKind short_type = rdim_short_type_kind_from_data_model(data_model); - RDI_TypeKind ushort_type = rdim_unsigned_short_type_kind_from_data_model(data_model); - RDI_TypeKind long_type = rdim_long_type_kind_from_data_model(data_model); - RDI_TypeKind ulong_type = rdim_unsigned_long_type_kind_from_data_model(data_model); - RDI_TypeKind long_long_type = rdim_long_long_type_kind_from_data_model(data_model); - RDI_TypeKind ulong_long_type = rdim_unsigned_long_long_type_kind_from_data_model(data_model); - RDI_TypeKind ptr_type = rdim_pointer_size_t_type_kind_from_data_model(data_model); - struct - { - char * name; - RDI_TypeKind kind_rdi; - CV_LeafKind kind_cv; - } - table[] = - { - { "signed char" , RDI_TypeKind_Char8 , CV_BasicType_CHAR }, - { "short" , short_type , CV_BasicType_SHORT }, - { "long" , long_type , CV_BasicType_LONG }, - { "long long" , long_long_type , CV_BasicType_QUAD }, - { "__int128" , RDI_TypeKind_S128 , CV_BasicType_OCT }, // Clang type - { "unsigned char" , RDI_TypeKind_UChar8 , CV_BasicType_UCHAR }, - { "unsigned short" , ushort_type , CV_BasicType_USHORT }, - { "unsigned long" , ulong_type , CV_BasicType_ULONG }, - { "unsigned long long" , ulong_long_type , CV_BasicType_UQUAD }, - { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UOCT }, // Clang type - { "bool" , RDI_TypeKind_S8 , CV_BasicType_BOOL8 }, - { "__bool16" , RDI_TypeKind_S16 , CV_BasicType_BOOL16 }, // not real C type - { "__bool32" , RDI_TypeKind_S32 , CV_BasicType_BOOL32 }, // not real C type - { "float" , RDI_TypeKind_F32 , CV_BasicType_FLOAT32 }, - { "double" , RDI_TypeKind_F64 , CV_BasicType_FLOAT64 }, - { "long double" , RDI_TypeKind_F80 , CV_BasicType_FLOAT80 }, - { "__float128" , RDI_TypeKind_F128 , CV_BasicType_FLOAT128 }, // Clang type - { "__float48" , RDI_TypeKind_F48 , CV_BasicType_FLOAT48 }, // not real C type - { "__float32pp" , RDI_TypeKind_F32PP , CV_BasicType_FLOAT32PP }, // not real C type - { "__float16" , RDI_TypeKind_F16 , CV_BasicType_FLOAT16 }, - { "_Complex float" , RDI_TypeKind_ComplexF32 , CV_BasicType_COMPLEX32 }, - { "_Complex double" , RDI_TypeKind_ComplexF64 , CV_BasicType_COMPLEX64 }, - { "_Complex long double" , RDI_TypeKind_ComplexF80 , CV_BasicType_COMPLEX80 }, - { "_Complex __float128" , RDI_TypeKind_ComplexF128, CV_BasicType_COMPLEX128 }, - { "__int8" , RDI_TypeKind_S8 , CV_BasicType_INT8 }, - { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 }, - { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 }, - { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 }, - { "int" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, - { "int32" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, - { "uint32" , RDI_TypeKind_U32 , CV_BasicType_UINT32 }, - { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 }, - { "__uint64" , RDI_TypeKind_U64 , CV_BasicType_UINT64 }, - { "__int128" , RDI_TypeKind_S128 , CV_BasicType_INT128 }, - { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UINT128 }, - { "char" , RDI_TypeKind_Char8 , CV_BasicType_RCHAR }, // always ASCII - { "wchar_t" , RDI_TypeKind_UChar16 , CV_BasicType_WCHAR }, // on windows always UTF-16 - { "char8_t" , RDI_TypeKind_Char8 , CV_BasicType_CHAR8 }, // always UTF-8 - { "char16_t" , RDI_TypeKind_Char16 , CV_BasicType_CHAR16 }, // always UTF-16 - { "char32_t" , RDI_TypeKind_Char32 , CV_BasicType_CHAR32 }, // always UTF-32 - { "__pointer" , ptr_type , CV_BasicType_PTR } - }; - for EachElement(idx, table) - { - RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, tpi_leaf->itype_opl); - builtin_alias->kind = RDI_TypeKind_Alias; - builtin_alias->name = str8_cstring(table[idx].name); - builtin_alias->direct_type = p2r_builtin_type_ptr_from_kind(table[idx].kind_rdi); - builtin_alias->byte_size = rdi_size_from_basic_type_kind(table[idx].kind_rdi); - itype_type_ptrs[table[idx].kind_cv] = builtin_alias; - } - itype_type_ptrs[CV_BasicType_HRESULT] = basic_type_ptrs[RDI_TypeKind_HResult - RDI_TypeKind_FirstBuiltIn]; - itype_type_ptrs[CV_BasicType_VOID] = basic_type_ptrs[RDI_TypeKind_Void - RDI_TypeKind_FirstBuiltIn]; - } - - //////////////////////////// - //- rjf: build types from TPI - // - if(params->subset_flags & RDIM_SubsetFlag_Types) - { - for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) - { - for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; - itype_chain != 0; - itype_chain = itype_chain->next) - { - CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; - B32 itype_is_basic = (itype < tpi->itype_first); - - ////////////////////////// - //- rjf: skip forward-reference itypes - all future resolutions will - // reference whatever this itype resolves to, and so there is no point - // in filling out this slot - // - if(itype_fwd_map[root_itype] != 0) - { - continue; - } - - ////////////////////////// - //- rjf: skip already produced dependencies - // - if(itype_type_ptrs[itype] != 0) - { - continue; - } - - ////////////////////////// - //- rjf: build basic type - // - if(itype_is_basic) - { - RDIM_Type *dst_type = 0; - - // rjf: unpack itype - CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); - CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); - - // rjf: get basic type slot, fill if unfilled - RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; - if(basic_type == 0) - { - RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); - U32 byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type = dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - if(byte_size == 0xffffffff) - { - byte_size = arch_addr_size; - } - basic_type->kind = type_kind; - basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); - basic_type->byte_size = byte_size; - } - - // rjf: nonzero ptr kind -> form ptr type to basic tpye - if(cv_basic_ptr_kind != 0) - { - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Ptr; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = basic_type; - } - - // rjf: fill this itype's slot with the finished type - itype_type_ptrs[itype] = dst_type; - } - - ////////////////////////// - //- rjf: build non-basic type - // - if(!itype_is_basic && itype >= itype_first) - { - RDIM_Type *dst_type = 0; - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: - { - // rjf: unpack leaf - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: cv -> rdi flags - RDI_TypeModifierFlags flags = 0; - if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} - if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} - - // rjf: fill type - if(flags == 0) - { - dst_type = p2r_type_ptr_from_itype(lf->itype); - } - else - { - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = flags; - dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); - dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead - - // rjf: unpack leaf - CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); - U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); - - // rjf: cv -> rdi modifier flags - RDI_TypeModifierFlags modifier_flags = 0; - if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} - if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} - if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} - - // rjf: cv info -> rdi pointer type kind - RDI_TypeKind type_kind = RDI_TypeKind_Ptr; - { - if(lf->attribs & CV_PointerAttrib_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(lf->attribs & CV_PointerAttrib_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - if(ptr_mode == CV_PointerMode_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(ptr_mode == CV_PointerMode_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - } - - // rjf: fill type - if(modifier_flags != 0) - { - RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = modifier_flags; - dst_type->direct_type = pointer_type; - dst_type->byte_size = arch_addr_size; - pointer_type->kind = type_kind; - pointer_type->byte_size = arch_addr_size; - pointer_type->direct_type = direct_type; - } - else - { - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = type_kind; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = direct_type; - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - // TODO(rjf): handle call_kind & attribs - - // rjf: unpack leaf - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type's basics - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: count non-zero arguments - U32 arglist_itypes_nonzero_count = 0; - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - if(arglist_itypes_base[idx] != 0) - { - arglist_itypes_nonzero_count += 1; - } - } - - // rjf: build param type array - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_nonzero_count); - { - U64 dst_idx = 0; - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - if(arglist_itypes_base[idx] != 0) - { - params[dst_idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - dst_idx += 1; - } - } - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_nonzero_count; - dst_type->param_types = params; - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - // TODO(rjf): handle call_kind & attribs - // TODO(rjf): preserve "this_adjust" - - // rjf: unpack leaf - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: build param type array - U64 num_this_extras = 1; - if(lf->this_itype == 0) - { - num_this_extras = 0; - } - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - } - if(lf->this_itype != 0) - { - params[0] = p2r_type_ptr_from_itype(lf->this_itype); - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_count+num_this_extras; - dst_type->param_types = params; - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - // rjf: unpack leaf - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Bitfield; - dst_type->off = lf->pos; - dst_type->count = lf->len; - dst_type->byte_size = direct_type?direct_type->byte_size:0; - dst_type->direct_type = direct_type; - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - // rjf: unpack leaf - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 full_size = cv_u64_from_numeric(&array_count); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Array; - dst_type->direct_type = direct_type; - dst_type->byte_size = full_size; - dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; - }break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: alias - case CV_LeafKind_ALIAS: - { - // rjf: unpack leaf - CV_LeafAlias *lf = (CV_LeafAlias *)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Alias; - dst_type->name = name; - dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); - if(dst_type->direct_type != 0) - { - dst_type->byte_size = dst_type->direct_type->byte_size; - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteUnion; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Union; - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); - U8 *name_ptr = (U8 *)(lf + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteEnum; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Enum; - dst_type->direct_type = direct_type; - dst_type->byte_size = direct_type ? direct_type->byte_size : 0; - dst_type->name = name; - } - }break; - } - } - - //- rjf: store finalized type to this itype's slot - itype_type_ptrs[itype] = dst_type; - } - } - } - } -#undef p2r_type_ptr_from_itype -#undef p2r_builtin_type_ptr_from_kind - } - lane_sync_u64(&itype_type_ptrs, 0); - lane_sync_u64(&basic_type_ptrs, 0); - lane_sync_u64(&all_types__pre_typedefs_ptr, 0); - all_types__pre_typedefs = *all_types__pre_typedefs_ptr; - - ////////////////////////////////////////////////////////////// - //- rjf: set bit in all namespace nodes that correspond to scopes - // - if(params->subset_flags & (RDIM_SubsetFlag_Procedures| - RDIM_SubsetFlag_GlobalVariables| - RDIM_SubsetFlag_ThreadVariables| - RDIM_SubsetFlag_Scopes| - RDIM_SubsetFlag_Locals| - RDIM_SubsetFlag_GlobalVariableNameMap| - RDIM_SubsetFlag_ThreadVariableNameMap| - RDIM_SubsetFlag_ProcedureNameMap| - RDIM_SubsetFlag_ConstantNameMap| - RDIM_SubsetFlag_LinkNameProcedureNameMap| - RDIM_SubsetFlag_Types)) - ProfScope("determine which namespace nodes correspond to scopes") - { - U64 *sym_take_counter = lane_idx() == 0 ? push_array(scratch.arena, U64, 1) : 0; - lane_sync_u64(&sym_take_counter, 0); - for(;;) - { - U64 sym_idx = ins_atomic_u64_inc_eval(sym_take_counter) - 1; - if(sym_idx >= all_syms_count) - { - break; - } - CV_SymParsed *sym = all_syms[sym_idx]; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)iter.struct_base; - String8 name = str8_cstring_capped(proc32+1, iter.opl); - U64 hash = u64_hash_from_str8(name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, name, 0)) - { - ins_atomic_u32_eval_assign(&n->corresponds_to_scope, 1); - break; - } - } - }break; - } - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: gather all namespaces which are only encoded in symbols (not found in types) - // - if(params->subset_flags & (RDIM_SubsetFlag_Procedures| - RDIM_SubsetFlag_GlobalVariables| - RDIM_SubsetFlag_ThreadVariables| - RDIM_SubsetFlag_Scopes| - RDIM_SubsetFlag_Locals| - RDIM_SubsetFlag_GlobalVariableNameMap| - RDIM_SubsetFlag_ThreadVariableNameMap| - RDIM_SubsetFlag_ProcedureNameMap| - RDIM_SubsetFlag_ConstantNameMap| - RDIM_SubsetFlag_LinkNameProcedureNameMap| - RDIM_SubsetFlag_Types)) - ProfScope("gather all namespaces which are only encoded in symbols (not found in types)") - { - Temp scratch2 = scratch_begin(&scratch.arena, 1); - U64 lane_namespace_slots_count = 4096; - String8Node **lane_namespace_slots = push_array(scratch2.arena, String8Node *, lane_namespace_slots_count); - - //- rjf: gather from syms - U64 *sym_take_counter = lane_idx() == 0 ? push_array(scratch2.arena, U64, 1) : 0; - lane_sync_u64(&sym_take_counter, 0); - for(;;) - { - U64 sym_idx = ins_atomic_u64_inc_eval(sym_take_counter) - 1; - if(sym_idx >= all_syms_count) - { - break; - } - CV_SymParsed *sym = all_syms[sym_idx]; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - // rjf: get global symbol name - String8 symbol_name = {0}; - switch(iter.kind) - { - default:{}break; - case CV_SymKind_GDATA32: - { - CV_SymData32 *data32 = (CV_SymData32 *)iter.struct_base; - symbol_name = str8_cstring_capped(data32+1, iter.opl); - }break; - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)iter.struct_base; - symbol_name = str8_cstring_capped(proc32+1, iter.opl); - }break; - case CV_SymKind_GTHREAD32: - { - CV_SymThread32 *thread32 = (CV_SymThread32 *)iter.struct_base; - symbol_name = str8_cstring_capped(thread32+1, iter.opl); - }break; - } - - // rjf: symbol name -> container name - String8 container_name = str8_chop(str8_prefix(symbol_name, p2r_end_of_cplusplus_container_name(symbol_name)), 2); - - // rjf: non-empty container name -> gather - if(container_name.size != 0) - { - U64 container_name_hash = u64_hash_from_str8(container_name); - - // rjf: first, check if this container already showed up from type info - B32 already_exists = 0; - if(!already_exists) - { - U64 slot_idx = container_name_hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, container_name, 0)) - { - already_exists = 1; - break; - } - } - } - - // rjf: next, check if we've already gathered this namespace for this lane - if(!already_exists) - { - U64 slot_idx = container_name_hash%lane_namespace_slots_count; - for(String8Node *n = lane_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, container_name, 0)) - { - already_exists = 1; - break; - } - } - } - - // rjf: if we didn't find this namespace in either those from types, or already found in this lane, then gather - if(!already_exists) - { - U64 slot_idx = container_name_hash%lane_namespace_slots_count; - String8Node *n = push_array(scratch2.arena, String8Node, 1); - SLLStackPush(lane_namespace_slots[slot_idx], n); - n->string = container_name; - } - } - } - } - lane_sync(); - - //- rjf: combine + fold into the all_namespaces table - { - // rjf: gather lane maps - typedef struct LaneNamespaceTable LaneNamespaceTable; - struct LaneNamespaceTable - { - String8Node **slots; - U64 slots_count; - }; - LaneNamespaceTable *lane_namespace_tables = 0; - if(lane_idx() == 0) - { - lane_namespace_tables = push_array(scratch2.arena, LaneNamespaceTable, lane_count()); - } - lane_sync_u64(&lane_namespace_tables, 0); - lane_namespace_tables[lane_idx()].slots = lane_namespace_slots; - lane_namespace_tables[lane_idx()].slots_count = lane_namespace_slots_count; - lane_sync(); - - // rjf: combine - if(lane_idx() == 0) - { - for EachIndex(l_idx, lane_count()) - { - LaneNamespaceTable *tbl = &lane_namespace_tables[l_idx]; - for EachIndex(slot_idx, tbl->slots_count) - { - for(String8Node *n = tbl->slots[slot_idx]; n != 0; n = n->next) - { - U64 hash = u64_hash_from_str8(n->string); - U64 dst_slot_idx = hash%all_namespace_slots_count; - B32 already_exists = 0; - for(P2R_NamespaceNode *dst_n = all_namespace_slots[dst_slot_idx]; dst_n != 0; dst_n = dst_n->next) - { - if(str8_match(dst_n->string, n->string, 0)) - { - already_exists = 1; - break; - } - } - if(!already_exists) - { - P2R_NamespaceNode *dst_n = push_array(scratch.arena, P2R_NamespaceNode, 1); - dst_n->string = n->string; - SLLStackPush(all_namespace_slots[dst_slot_idx], dst_n); - } - } - } - } - } - } - lane_sync(); - scratch_end(scratch2); - } - - ////////////////////////////////////////////////////////////// - //- rjf: upgrade namespace nodes with type info, if they match a type - // - ProfScope("upgrade namespace nodes with type info, if they match a type") - { -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - Rng1U64 range = lane_range(all_namespace_slots_count); - for EachInRange(slot_idx, range) - { - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - String8 container_string = n->string; - CV_TypeId container_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_string, 0); - if(container_type_id != 0) - { - n->type = p2r_type_ptr_from_itype(container_type_id); - } - } - } -#undef p2r_type_ptr_from_itype - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: build namespaces, that are not scopes, nor types - // - RDIM_NamespaceChunkList all_namespaces = {0}; - { - // rjf: gather all per-lane namespaces - RDIM_NamespaceChunkList lane_namespaces = {0}; - Rng1U64 range = lane_range(all_namespace_slots_count); - for EachInRange(slot_idx, range) - { - Temp scratch = scratch_begin(&arena, 1); - - // rjf: gather nodes, sort - U64 node_count = 0; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) { node_count += 1; } - P2R_NamespaceNode **nodes = push_array(scratch.arena, P2R_NamespaceNode *, node_count); - { - U64 idx = 0; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next, idx += 1) - { - nodes[idx] = n; - } - } - radsort(nodes, node_count, p2r_namespace_node_is_before); - - // rjf: build namespaces for this slot - for EachIndex(node_in_slot_idx, node_count) - { - P2R_NamespaceNode *n = nodes[node_in_slot_idx]; - if(n->corresponds_to_scope || n->scope != 0 || n->type != 0) { continue; } - String8 string = n->string; - RDIM_Namespace *ns = rdim_namespace_chunk_list_push(arena, &lane_namespaces, 32); - ns->name = string; - n->ns = ns; - } - - scratch_end(scratch); - } - - // rjf: combine all per-lane namespaces - RDIM_NamespaceChunkList *lanes_namespaces = 0; - if(lane_idx() == 0) - { - lanes_namespaces = push_array(scratch.arena, RDIM_NamespaceChunkList, lane_count()); - } - lane_sync_u64(&lanes_namespaces, 0); - lanes_namespaces[lane_idx()] = lane_namespaces; - lane_sync(); - - // rjf: join all per-lane namespaces - RDIM_NamespaceChunkList *all_namespaces_ptr = &all_namespaces; - lane_sync_u64(&all_namespaces_ptr, 0); - if(lane_idx() == 0) - { - for EachIndex(l_idx, lane_count()) - { - rdim_namespace_chunk_list_concat_in_place(all_namespaces_ptr, &lanes_namespaces[l_idx]); - } - } - lane_sync(); - all_namespaces = *all_namespaces_ptr; - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: convert symbols from all units - // - typedef struct ScopeNamespaceNode ScopeNamespaceNode; - struct ScopeNamespaceNode - { - ScopeNamespaceNode *next; - String8 string; - RDIM_Scope *scope; - }; - typedef struct ScopeNamespaceList ScopeNamespaceList; - struct ScopeNamespaceList - { - ScopeNamespaceNode *first; - ScopeNamespaceNode *last; - }; - RDIM_TypeChunkList *syms_typedefs = 0; - ScopeNamespaceList *syms_scopes_that_are_namespaces = 0; - ProfScope("produce symbols from all streams") - { -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - - //////////////////////////// - //- rjf: set up - // - if(lane_idx() == 0) - { - syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); - syms_scopes_that_are_namespaces = push_array(arena, ScopeNamespaceList, all_syms_count); - } - lane_sync_u64(&syms_typedefs, 0); - lane_sync_u64(&syms_scopes_that_are_namespaces, 0); - - //////////////////////////// - //- rjf: fill outputs for all unit sym blocks in this lane - // - if(params->subset_flags & (RDIM_SubsetFlag_Procedures| - RDIM_SubsetFlag_GlobalVariables| - RDIM_SubsetFlag_ThreadVariables| - RDIM_SubsetFlag_Scopes| - RDIM_SubsetFlag_Locals| - RDIM_SubsetFlag_GlobalVariableNameMap| - RDIM_SubsetFlag_ThreadVariableNameMap| - RDIM_SubsetFlag_ProcedureNameMap| - RDIM_SubsetFlag_ConstantNameMap| - RDIM_SubsetFlag_LinkNameProcedureNameMap| - RDIM_SubsetFlag_Types)) - { - U64 *sym_take_counter = lane_idx() == 0 ? push_array(scratch.arena, U64, 1) : 0; - lane_sync_u64(&sym_take_counter, 0); - for(;;) - { - //- rjf: take next sym - U64 sym_idx = ins_atomic_u64_inc_eval(sym_take_counter) - 1; - if(sym_idx >= all_syms_count) - { - break; - } - - //- rjf: unpack sym - Temp scratch = scratch_begin(&arena, 1); - CV_SymParsed *sym = all_syms[sym_idx]; - RDIM_Unit *sym_unit = &all_units_ptr->first->v[sym_idx]; - RDIM_SymbolChunkList *sym_procedures = &sym_unit->procedures; - RDIM_SymbolChunkList *sym_global_variables = &sym_unit->global_variables; - RDIM_SymbolChunkList *sym_thread_variables = &sym_unit->thread_variables; - RDIM_SymbolChunkList *sym_constants = &sym_unit->constants; - RDIM_ScopeChunkList *sym_scopes = &sym_unit->scopes; - RDIM_InlineSiteChunkList *sym_inline_sites = &sym_unit->inline_sites; - RDIM_TypeChunkList *typedefs = &syms_typedefs[sym_idx]; - - ////////////////////////// - //- rjf: symbols pass 0: predict symbol chunk counts by record kinds - // - U64 sym_procedures_chunk_cap = sym->sym_ranges.count/4 + 1; - U64 sym_global_variables_chunk_cap = sym->sym_ranges.count/12 + 1; - U64 sym_thread_variables_chunk_cap = sym->sym_ranges.count/12 + 1; - U64 sym_constants_chunk_cap = sym->sym_ranges.count/6 + 1; - U64 sym_scopes_chunk_cap = sym->sym_ranges.count/4 + 1; - U64 sym_inline_sites_chunk_cap = sym->sym_ranges.count/6 + 1; - ProfScope("symbols pass 0: predict symbol chunk counts by record kinds") - { - U64 procedure_record_count = 0; - U64 global_variable_record_count = 0; - U64 thread_variable_record_count = 0; - U64 constant_record_count = 0; - U64 scope_record_count = 0; - U64 inline_site_record_count = 0; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - case CV_SymKind_THUNK32: - { - procedure_record_count += 1; - scope_record_count += 1; - }break; - case CV_SymKind_BLOCK32: - { - scope_record_count += 1; - }break; - case CV_SymKind_INLINESITE: - { - scope_record_count += 1; - inline_site_record_count += 1; - }break; - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - global_variable_record_count += 1; - }break; - case CV_SymKind_CONSTANT: - { - constant_record_count += 1; - }break; - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - thread_variable_record_count += 1; - }break; - } - } - sym_procedures_chunk_cap = Max(1, procedure_record_count); - sym_global_variables_chunk_cap = Max(1, global_variable_record_count); - sym_thread_variables_chunk_cap = Max(1, thread_variable_record_count); - sym_constants_chunk_cap = Max(1, constant_record_count); - sym_scopes_chunk_cap = Max(1, scope_record_count); - sym_inline_sites_chunk_cap = Max(1, inline_site_record_count); - } - - ////////////////////////// - //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) - // - U64 procedure_frameprocs_count = 0; - U64 procedure_frameprocs_cap = sym->sym_ranges.count; - CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); - ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") - { - U64 procedure_num = 0; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - - //- rjf: FRAMEPROC - case CV_SymKind_FRAMEPROC: - { - if(procedure_num == 0) { break; } - if(procedure_num > procedure_frameprocs_cap) { break; } - CV_SymFrameproc *frameproc = (CV_SymFrameproc *)iter.struct_base; - procedure_frameprocs[procedure_num-1] = frameproc; - procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - procedure_num += 1; - }break; - } - } - U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); - arena_pop(scratch.arena, scratch_overkill); - } - - ////////////////////////// - //- rjf: symbols pass 2: construct all symbols, given procedure frame info map - // - ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") - { - RDIM_Symbol *defrange_target = 0; - U64 procedure_num = 0; - U64 procedure_base_voff = 0; - CV_ProcFlags proc_flags = 0; - U64 regrel_idx = 0; - RDIM_Symbol *curr_proc_symbol = 0; - typedef struct P2R_ScopeNode P2R_ScopeNode; - struct P2R_ScopeNode - { - P2R_ScopeNode *next; - RDIM_Scope *scope; - }; - P2R_ScopeNode *top_scope_node = 0; - P2R_ScopeNode *free_scope_node = 0; - RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - switch(iter.kind) - { - default:{}break; - - //- rjf: END - case CV_SymKind_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - }break; - - //- rjf: BLOCK32 - case CV_SymKind_BLOCK32: - { - // rjf: unpack sym - CV_SymBlock32 *block32 = (CV_SymBlock32 *)iter.struct_base; - - // rjf: build scope, insert into current parent scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - { - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + block32->off; - U64 voff_last = voff_first + block32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - }break; - - //- rjf: LDATA32/GDATA32 - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - // rjf: unpack sym - CV_SymData32 *data32 = (CV_SymData32 *)iter.struct_base; - String8 name = str8_cstring_capped(data32+1, iter.opl); - COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; - U64 voff = (section ? section->voff : 0) + data32->off; - - // rjf: determine if this is an exact duplicate global - // - // PDB likes to have duplicates of these spread across different - // symbol streams so we deduplicate across the entire translation - // context. - // - B32 is_duplicate = 0; - { - // TODO(rjf): @important global symbol dedup - } - - // rjf: is not duplicate -> push new global - if(!is_duplicate) - { - // rjf: unpack global variable's type - RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); - - // rjf: unpack global's container type - B32 got_container = 0; - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); - if(!got_container && container_name.size != 0) - { - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - got_container = (container_type != 0); - } - - // rjf: unpack global's container scope - RDIM_Scope *container_scope = 0; - if(!got_container && top_scope_node != 0 && iter.kind == CV_SymKind_LDATA32) - { - container_scope = top_scope_node->scope; - got_container = (container_scope != 0); - } - - // rjf: unpack global's container namespace - RDIM_Namespace *container_namespace = 0; - if(!got_container && container_name.size != 0) - { - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(container_name, n->string, 0) && - n->ns != 0) - { - container_namespace = n->ns; - break; - } - } - } - - // rjf: un-namespaceify the symbol name - String8 name__maybe_partially_qualified = name; - if(got_container) - { - name__maybe_partially_qualified = str8_skip(name, container_name_opl); - } - - // rjf: build symbol - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); - symbol->is_extern = (iter.kind == CV_SymKind_GDATA32); - symbol->name = name__maybe_partially_qualified; - symbol->type = type; - symbol->container_scope = container_scope; - symbol->container_type = container_type; - symbol->container_namespace = container_namespace; - RDIM_Location loc = {.kind = RDI_LocationKind_ModuleOff, .offset = voff}; - RDIM_Rng1U64 range = {0, 0xffffffffffffffffull}; - rdim_location_case_list_push(arena, &symbol->location_cases, loc, range); - } - }break; - - //- rjf: UDT (typedefs) - case CV_SymKind_UDT: - if(sym == all_syms[0] && top_scope_node == 0) - { - if(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs|RDIM_SubsetFlag_TypeNameMap)) - { - CV_SymUDT *udt = (CV_SymUDT *)iter.struct_base; - String8 name = str8_cstring_capped(udt+1, iter.opl); - RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); - type->kind = RDI_TypeKind_Alias; - type->name = name; - type->direct_type = p2r_type_ptr_from_itype(udt->itype); - if(type->direct_type != 0) - { - type->byte_size = type->direct_type->byte_size; - } - } - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - // rjf: unpack sym - CV_SymProc32 *proc32 = (CV_SymProc32 *)iter.struct_base; - String8 name = str8_cstring_capped(proc32+1, iter.opl); - RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); - - // rjf: unpack proc's container type - B32 got_container = 0; - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); - if(!got_container && container_name.size != 0 && tpi_hash != 0 && tpi_leaf != 0) - { - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - got_container = (container_type != 0); - } - - // rjf: unpack proc's container scope - RDIM_Scope *container_scope = 0; - if(!got_container && top_scope_node != 0) - { - container_scope = top_scope_node->scope; - got_container = 1; - } - - // rjf: unpack proc's container namespace - RDIM_Namespace *container_namespace = 0; - if(!got_container && container_name.size != 0) - { - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(container_name, n->string, 0) && - n->ns != 0) - { - container_namespace = n->ns; - break; - } - } - } - - // rjf: build procedure's root scope - // - // NOTE: even if there could be a containing scope at this point (which should be - // illegal in C/C++ but not necessarily in another language) we would not use - // it here because these scopes refer to the ranges of code that make up a - // procedure *not* the namespaces, so a procedure's root scope always has - // no parent. - RDIM_Scope *procedure_root_scope = 0; - if(params->subset_flags & RDIM_SubsetFlag_Scopes) - { - procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + proc32->off; - U64 voff_last = voff_first + proc32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); - procedure_base_voff = voff_first; - } - } - - // rjf: root scope voff minimum range -> link name - String8 link_name = {0}; - if(procedure_root_scope && procedure_root_scope->voff_ranges.min != 0) - { - U64 voff = procedure_root_scope->voff_ranges.min; - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%link_name_map->buckets_count; - P2R_LinkNameNode *node = 0; - for(P2R_LinkNameNode *n = link_name_map->buckets[bucket_idx]; n != 0; n = n->next) - { - if(n->voff == voff) - { - link_name = n->name; - ins_atomic_u64_inc_eval(&n->referencing_symbol_count); - break; - } - } - } - - // rjf: un-namespaceify the symbol name - String8 name__maybe_partially_qualified = name; - if(got_container) - { - name__maybe_partially_qualified = str8_skip(name, container_name_opl); - } - - // rjf: build procedure symbol - if(params->subset_flags & (RDIM_SubsetFlag_Procedures|RDIM_SubsetFlag_ProcedureNameMap)) - { - curr_proc_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); - curr_proc_symbol->is_extern = (iter.kind == CV_SymKind_GPROC32); - curr_proc_symbol->name = name__maybe_partially_qualified; - curr_proc_symbol->link_name = link_name; - curr_proc_symbol->type = type; - curr_proc_symbol->container_scope = container_scope; - curr_proc_symbol->container_type = container_type; - curr_proc_symbol->root_scope = procedure_root_scope; - if(procedure_root_scope != 0) - { - procedure_root_scope->symbol = curr_proc_symbol; - } - } - - // rjf: push scope to scope stack - if(procedure_root_scope) - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = procedure_root_scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: determine if this procedure is a namespace used for types; if so, gather - if(procedure_root_scope != 0) - { - U64 hash = u64_hash_from_str8(name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, name, 0)) - { - ScopeNamespaceNode *node = push_array(arena, ScopeNamespaceNode, 1); - node->scope = procedure_root_scope; - node->string = name; - SLLQueuePush(syms_scopes_that_are_namespaces[sym_idx].first, - syms_scopes_that_are_namespaces[sym_idx].last, - node); - break; - } - } - } - - // rjf: increment procedure counter - procedure_num += 1; - - // reset S_REGREL32 index - regrel_idx = 0; - - proc_flags = proc32->flags; - }break; - - //- rjf: THUNK32 - case CV_SymKind_THUNK32: - { - // rjf: unpack record - CV_SymThunk32 *thunk32 = (CV_SymThunk32 *)iter.struct_base; - String8 name = str8_cstring_capped(thunk32+1, iter.opl); - COFF_SectionHeader *section = (0 < thunk32->sec && thunk32->sec <= coff_sections.count) ? &coff_sections.v[thunk32->sec-1] : 0; - U64 voff_first = 0; - U64 voff_opl = 0; - if(section != 0) - { - voff_first = section->voff + thunk32->off; - voff_opl = voff_first + thunk32->len; - } - - // rjf: build symbol / scope - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); - symbol->name = name; - symbol->is_thunk = 1; - if(voff_first != voff_opl) - { - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - RDIM_Rng1U64 range = {voff_first, voff_opl}; - rdim_scope_push_voff_range(arena, sym_scopes, scope, range); - scope->symbol = symbol; - symbol->root_scope = scope; - } - }break; - - //- rjf: REGREL32 - case CV_SymKind_REGREL32: - { - if(params->subset_flags & RDIM_SubsetFlag_Locals && !(proc_flags & CV_ProcFlag_OptDbgInfo)) - { - // TODO(rjf): apparently some of the information here may end up being - // redundant with "better" information from CV_SymKind_LOCAL record. - // we don't currently handle this, but if those cases arise then it - // will obviously be better to prefer the better information from both - // records. - - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)iter.struct_base; - String8 name = str8_cstring_capped(regrel32+1, iter.opl); - RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); - CV_Reg cv_reg = regrel32->reg; - U32 var_off = regrel32->reg_off; - - // rjf: determine if this is a parameter - B32 is_param = (regrel_idx < curr_proc_symbol->type->count); - - // rjf: determine if we need an extra indirection to the value - B32 extra_indirection_to_value = 0; - if(type != 0) - { - switch(arch) - { - case RDI_Arch_X64: - { - extra_indirection_to_value = (is_param && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); - }break; - } - } - - // If the return local does not fit in a register MSVC does not assign it a type. - // So we infer the return type from the signature. - // - // rjf: redirect type, if 0, and if outside frame, to the return type of the - // containing procedure - { - B32 is_stack_reg = 0; - switch(arch) - { - default:{}break; - case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP || cv_reg == CV_Regx64_RBP);}break; - } - if(is_stack_reg) - { - if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) - { - CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; - if(var_off > frameproc->frame_size && regrel32->itype == 0 && - top_scope_node->scope->symbol != 0 && - top_scope_node->scope->symbol->type != 0) - { - type = top_scope_node->scope->symbol->type->direct_type; - extra_indirection_to_value = 1; - } - } - } - } - - // rjf: build local - { - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Symbol *local = rdim_symbol_chunk_list_push(arena, &scope->locals, 8); - local->container_scope = scope; - local->is_param = is_param; - local->name = name; - local->type = type; - - // rjf: equip location info - { - // rjf: get raddbg register code - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - // TODO(rjf): real byte_size & byte_pos from cv_reg goes here - U32 byte_size = 8; - U32 byte_pos = 0; - - // rjf: build location - RDIM_Location loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_case_list_push(arena, &local->location_cases, loc, voff_range); - } - } - } - - regrel_idx += 1; - }break; - - //- rjf: LTHREAD32/GTHREAD32 - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - if(params->subset_flags & (RDIM_SubsetFlag_ThreadVariables|RDIM_SubsetFlag_ThreadVariableNameMap)) - { - // rjf: unpack sym - CV_SymThread32 *thread32 = (CV_SymThread32 *)iter.struct_base; - String8 name = str8_cstring_capped(thread32+1, iter.opl); - U32 tls_off = thread32->tls_off; - RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); - - // rjf: unpack thread variable's container type - B32 got_container = 0; - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - String8 container_name = str8_chop(str8_prefix(name, container_name_opl), 2); - if(!got_container && container_name.size != 0) - { - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - got_container = (container_type != 0); - } - - // rjf: unpack thread variable's container symbol - RDIM_Scope *container_scope = 0; - if(!got_container && top_scope_node != 0) - { - got_container = 1; - container_scope = top_scope_node->scope; - } - - // rjf: unpack proc's container namespace - RDIM_Namespace *container_namespace = 0; - if(!got_container && container_name.size != 0) - { - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(container_name, n->string, 0) && - n->ns != 0) - { - container_namespace = n->ns; - break; - } - } - } - - // rjf: un-namespaceify the symbol name - String8 name__maybe_partially_qualified = name; - if(got_container) - { - name__maybe_partially_qualified = str8_skip(name, container_name_opl); - } - - // rjf: build symbol - RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); - tvar->name = name__maybe_partially_qualified; - tvar->type = type; - tvar->is_extern = (iter.kind == CV_SymKind_GTHREAD32); - tvar->container_type = container_type; - tvar->container_scope = container_scope; - tvar->container_namespace = container_namespace; - RDIM_Location loc = {.kind = RDI_LocationKind_TLSOff, .offset = tls_off}; - RDIM_Rng1U64 range = {0, 0xffffffffffffffffull}; - rdim_location_case_list_push(arena, &tvar->location_cases, loc, range); - }break; - - //- rjf: LOCAL - case CV_SymKind_LOCAL: - if(params->subset_flags & (RDIM_SubsetFlag_Locals)) - { - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymLocal *slocal = (CV_SymLocal *)iter.struct_base; - String8 name = str8_cstring_capped(slocal+1, iter.opl); - RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); - - // rjf: determine if this symbol encodes the beginning of a global modification - B32 is_global_modification = 0; - if((slocal->flags & CV_LocalFlag_Global) || - (slocal->flags & CV_LocalFlag_Static)) - { - is_global_modification = 1; - } - - // rjf: is global modification -> emit global modification symbol - if(is_global_modification) - { - // TODO(rjf): add global modification symbols - defrange_target = 0; - } - - // rjf: is not a global modification -> emit a local variable - if(!is_global_modification) - { - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Symbol *local = rdim_symbol_chunk_list_push(arena, &scope->locals, 8); - { - local->container_scope = scope; - local->is_param = !!(slocal->flags & CV_LocalFlag_Param); - local->name = name; - local->type = type; - } - - // rjf: save defrange target, for subsequent defrange symbols - defrange_target = local; - } - }break; - - //- rjf: DEFRANGE_REGISTER - case CV_SymKind_DEFRANGE_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)iter.struct_base; - CV_Reg cv_reg = defrange_register->reg; - CV_LvarAddrRange *range = &defrange_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); - U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: build location - RDIM_Location loc = {RDI_LocationKind_ValReg, reg_code}; - - // rjf: emit locations over ranges - p2r_location_case_list_push_over_lvar_addr_range(arena, &defrange_target->location_cases, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)iter.struct_base; - CV_LvarAddrRange *range = &defrange_fprel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); - U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target->is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel->off; - RDIM_Location location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - - // rjf: emit locations over ranges - p2r_location_case_list_push_over_lvar_addr_range(arena, &defrange_target->location_cases, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_SUBFIELD_REGISTER - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)iter.struct_base; - CV_Reg cv_reg = defrange_subfield_register->reg; - CV_LvarAddrRange *range = &defrange_subfield_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); - U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: skip "subfield" location info - currently not supported - if(defrange_subfield_register->field_offset != 0) - { - break; - } - - // rjf: build location - RDIM_Location loc = {RDI_LocationKind_ValReg, reg_code}; - - // rjf: emit locations over ranges - p2r_location_case_list_push_over_lvar_addr_range(arena, &defrange_target->location_cases, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)iter.struct_base; - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target->is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_Location loc = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - - // rjf: emit location over ranges - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_case_list_push(arena, &defrange_target->location_cases, loc, voff_range); - }break; - - //- rjf: DEFRANGE_REGISTER_REL - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)iter.struct_base; - CV_Reg cv_reg = defrange_register_rel->reg; - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - CV_LvarAddrRange *range = &defrange_register_rel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); - U64 gap_count = ((U8*)iter.opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: build location - // TODO(rjf): offset & size from cv_reg code - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - B32 extra_indirection_to_value = 0; - S64 var_off = defrange_register_rel->reg_off; - RDIM_Location loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - - // rjf: emit locations over ranges - p2r_location_case_list_push_over_lvar_addr_range(arena, &defrange_target->location_cases, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: FILESTATIC - case CV_SymKind_FILESTATIC: - { - CV_SymFileStatic *file_static = (CV_SymFileStatic*)iter.struct_base; - String8 name = str8_cstring_capped(file_static+1, iter.opl); - RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); - // TODO(rjf): emit a global modifier symbol - defrange_target = 0; - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - if(params->subset_flags & (RDIM_SubsetFlag_Scopes)) - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)iter.struct_base; - String8 binary_annots = str8((U8 *)(sym+1), (U64)((U8 *)iter.opl - (U8 *)(sym+1))); - - // rjf: extract external info about inline site - String8 name = {0}; - RDIM_Type *type = 0; - RDIM_Type *owner = 0; - if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) - { - CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; - String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); - void *raw_leaf = rec_data.str + sizeof(U16); - - // rjf: extract method inline info - if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) - { - CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; - name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(mfunc_id->itype); - owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; - } - - // rjf: extract non-method function inline info - else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafFuncId)) - { - CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; - name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(func_id->itype); - owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; - } - } - - // rjf: build inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); - inline_site->name = name; - inline_site->type = type; - inline_site->owner = owner; - inline_site->line_table = inline_site_line_table; - - // rjf: increment to next inline site line table in this unit - if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) - { - RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; - U64 current_idx = (U64)(inline_site_line_table - chunk->v); - if(current_idx+1 < chunk->count) - { - inline_site_line_table += 1; - } - else - { - chunk = chunk->next; - inline_site_line_table = 0; - if(chunk != 0) - { - inline_site_line_table = chunk->v; - } - } - } - - // rjf: build scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - scope->inline_site = inline_site; - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: parse offset ranges of this inline site - attach to scope - { - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); - for(;;) - { - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) - { - // rjf: build new range & add to scope - RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) - { - if(scope->voff_ranges.last != 0) - { - scope->voff_ranges.last->v.max = step.range.max; - } - } - - if(step.flags == 0) - { - break; - } - } - } - }break; - - //- rjf: INLINESITE_END - case CV_SymKind_INLINESITE_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - }break; - - //- rjf: CONSTANT - case CV_SymKind_CONSTANT: - if(params->subset_flags & RDIM_SubsetFlag_Constants) - { - // rjf: unpack - CV_SymConstant *sym = (CV_SymConstant *)iter.struct_base; - RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); - U8 *val_ptr = (U8 *)(sym+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, iter.opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, iter.opl); - String8 val_data = str8_struct(&val64); - U64 container_name_opl = 0; - if(type != 0) - { - container_name_opl = p2r_end_of_cplusplus_container_name(type->name); - } - String8 name_qualified = name; - if(container_name_opl != 0) - { - name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); - } - - // rjf: build constant symbol - if(name_qualified.size != 0) - { - RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); - cnst->name = name_qualified; - cnst->type = type; - RDIM_Location loc = {.kind = RDI_LocationKind_ConstantDataOff, .value_data = str8_copy(arena, val_data)}; - RDIM_Rng1U64 range = {0, 0xffffffffffffffffull}; - rdim_location_case_list_push(arena, &cnst->location_cases, loc, range); - } - }break; - } - } - } - - scratch_end(scratch); - } - } -#undef p2r_type_ptr_from_itype - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: produce stub procedures from all pub32 symbols - // - if(lane_idx() == 0) - { - CV_SymParsed *sym = all_syms[0]; - for(CV_RecIter iter = {0}; cv_rec_next(sym->data, &sym->sym_ranges, 0, &iter);) - { - RDIM_Unit *sym_unit = &all_units_ptr->first->v[0]; - RDIM_SymbolChunkList *sym_procedures = &sym_unit->procedures; - RDIM_SymbolChunkList *sym_global_variables = &sym_unit->global_variables; - RDIM_ScopeChunkList *sym_scopes = &sym_unit->scopes; - switch(iter.kind) - { - default:{}break; - case CV_SymKind_PUB32: - { - // rjf: unpack record - CV_SymPub32 *pub32 = (CV_SymPub32 *)iter.struct_base; - String8 name = str8_cstring_capped(pub32+1, iter.opl); - COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= coff_sections.count) ? &coff_sections.v[pub32->sec-1] : 0; - U64 voff = 0; - if(section != 0) - { - voff = section->voff + pub32->off; - } - - // rjf: determine if this pub32 was covered by another symbol record - B32 was_in_other_record = 0; - { - U64 hash = p2r_hash_from_voff(voff); - U64 slot_idx = hash%link_name_map->buckets_count; - for(P2R_LinkNameNode *n = link_name_map->buckets[slot_idx]; n != 0; n = n->next) - { - if(n->voff == voff) - { - was_in_other_record = (n->referencing_symbol_count != 0); - break; - } - } - } - - // rjf: find compilation unit contribution to determine pub32's size - U64 voff_opl = voff+1; - if(!was_in_other_record) - { - PDB_CompUnitContribution *contrib = pdb_comp_unit_contribution_from_voff__binary_search(comp_unit_contributions, voff); - if(contrib != 0) - { - voff_opl = contrib->voff_opl; - } - } - - // rjf: if this pub32 was *not* covered by another symbol record, build a symbol for it - if(!was_in_other_record) - { - B32 is_procedure = (pub32->flags & (CV_Pub32Flag_Code|CV_Pub32Flag_Function)); - RDIM_SymbolChunkList *symbols = is_procedure ? sym_procedures : sym_global_variables; - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, symbols, 64); - symbol->name = name; - symbol->link_name = name; - if(is_procedure) - { - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, 64); - scope->symbol = symbol; - RDIM_Rng1U64 range = {voff, voff_opl}; - rdim_scope_push_voff_range(arena, sym_scopes, scope, range); - symbol->root_scope = scope; - } - } - }break; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: upgrade namespace nodes with scopes info, if they match a scope - // - if(lane_idx() == 0) - { - for EachIndex(sym_idx, all_syms_count) - { - ScopeNamespaceList *scopes_that_are_namespaces = &syms_scopes_that_are_namespaces[sym_idx]; - for(ScopeNamespaceNode *scope_n = scopes_that_are_namespaces->first; scope_n != 0; scope_n = scope_n->next) - { - U64 hash = u64_hash_from_str8(scope_n->string); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - n->scope = scope_n->scope; - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: upgrade namespaces with container info; trim off container names - // - for EachNode(n, RDIM_NamespaceChunkNode, all_namespaces.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Namespace *ns = &n->v[n_idx]; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(ns->name); - String8 container_name = str8_chop(str8_prefix(ns->name, container_name_opl), 2); - if(container_name.size != 0) - { - String8 leaf_name = str8_skip(ns->name, container_name_opl); - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *ns_n = all_namespace_slots[slot_idx]; ns_n != 0; ns_n = ns_n->next) - { - if(str8_match(ns_n->string, container_name, 0)) - { - ns->parent_scope = ns_n->scope; - ns->parent_type = ns_n->type; - ns->parent_namespace = ns_n->ns; - break; - } - } - ns->name = leaf_name; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: join extra types from units - // - RDIM_TypeChunkList all_types = {0}; - { - RDIM_TypeChunkList *all_types_ptr = 0; - if(lane_idx() == 0) - { - all_types_ptr = push_array(scratch.arena, RDIM_TypeChunkList, 1); - } - lane_sync_u64(&all_types_ptr, 0); - if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") - { - for EachIndex(idx, all_syms_count) - { - rdim_type_chunk_list_concat_in_place(all_types__pre_typedefs_ptr, &syms_typedefs[idx]); - } - *all_types_ptr = *all_types__pre_typedefs_ptr; - } - lane_sync(); - all_types = *all_types_ptr; - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: build UDTs - // - RDIM_UDTChunkList *lanes_udts = 0; - ProfScope("build UDTs") - { -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - - //- rjf: gather this lane's UDTs - RDIM_UDTChunkList lane_udts = {0}; - if(params->subset_flags & RDIM_SubsetFlag_Types && - params->subset_flags & RDIM_SubsetFlag_UDTs) - { - U64 udts_chunk_cap = 4096; - RDIM_UDTChunkList *udts = &lane_udts; - Rng1U64 range = lane_range(itype_opl); - for EachInRange(idx, range) - { - //- rjf: skip basics - CV_TypeId itype = (CV_TypeId)idx; - if(itype < itype_first) { continue; } - - //- rjf: grab type for this itype - skip if empty - RDIM_Type *dst_type = itype_type_ptrs[itype]; - if(dst_type == 0) { continue; } - - //- rjf: unpack itype leaf range - skip if out-of-range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->off+2+header_struct_size > tpi_leaf->data.size || - range->hdr.size < 2) - { - continue; - } - - //- rjf: build UDT - String8 udt_name = {0}; - CV_TypeId field_itype = 0; - switch(kind) - { - default:{}break; - - //////////////////////// - //- rjf: structs/unions/classes -> equip members - // - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - udt_name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }goto equip_members; - case CV_LeafKind_UNION: - { - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - udt_name = str8_cstring_capped(name_ptr, itype_leaf_opl); - }goto equip_members; - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - udt_name = str8_cstring_capped(name_ptr, itype_leaf_opl); - field_itype = lf->field_itype; - }goto equip_members; - equip_members: - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_list_opl; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: MEMBER - case CV_LeafKind_MEMBER: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - U8 *name_ptr = offset_ptr + offset.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_DataField; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: STMEMBER - case CV_LeafKind_STMEMBER: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticData; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: METHOD - case CV_LeafKind_METHOD: - { - // rjf: unpack leaf - CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - //- rjf: method list itype -> range - CV_RecRange *method_list_range = &tpi_leaf->leaf_ranges.ranges[lf->list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad method lists - if(method_list_range->off+method_list_range->hdr.size > tpi_leaf->data.size || - method_list_range->hdr.size < 2 || - method_list_range->hdr.kind != CV_LeafKind_METHODLIST) - { - break; - } - - //- rjf: loop through all methods & emit members - U8 *method_list_first = tpi_leaf->data.str + method_list_range->off + 2; - U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; - for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; - method_read_ptr < method_list_opl; - method_read_ptr = next_method_read_ptr) - { - CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); - RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); - next_method_read_ptr = (U8 *)(method+1); - - // TODO(allen): PROBLEM - // We only get offsets for virtual functions (the "vbaseoff") from - // "Intro" and "PureIntro". In C++ inheritance, when we have a chain - // of inheritance (let's just talk single inheritance for now) the - // first class in the chain that introduces a new virtual function - // has this "Intro" method. If a later class in the chain redefines - // the virtual function it only has a "Virtual" method which does - // not update the offset. There is a "Virtual" and "PureVirtual" - // variant of "Virtual". The "Pure" in either case means there - // is no concrete procedure. When there is no "Pure" the method - // should have a corresponding procedure symbol id. - // - // The issue is we will want to mark all of our virtual methods as - // virtual and give them an offset, but that means we have to do - // some extra figuring to propogate offsets from "Intro" methods - // to "Virtual" methods in inheritance trees. That is - IF we want - // to start preserving the offsets of virtuals. There is room in - // the method struct to make this work, but for now I've just - // decided to drop this information. It is not urgently useful to - // us and greatly complicates matters. - - // rjf: read vbaseoff - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - if(next_method_read_ptr+4 <= method_list_opl) - { - vbaseoff = *(U32 *)next_method_read_ptr; - } - next_method_read_ptr += 4; - } - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - } - - }break; - - //- rjf: ONEMETHOD - case CV_LeafKind_ONEMETHOD: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); - U8 *vbaseoff_ptr = (U8 *)(lf+1); - U8 *vbaseoff_opl_ptr = vbaseoff_ptr; - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - vbaseoff = *(U32 *)(vbaseoff_ptr); - vbaseoff_opl_ptr += sizeof(U32); - } - U8 *name_ptr = vbaseoff_opl_ptr; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - }break; - - //- rjf: NESTTYPE - case CV_LeafKind_NESTTYPE: - { - // rjf: unpack leaf - CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: NESTTYPEEX - case CV_LeafKind_NESTTYPEEX: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: BCLASS - case CV_LeafKind_BCLASS: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = offset_ptr+offset.encoded_size; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Base; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: VBCLASS/IVBCLASS - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - { - // TODO(rjf): log on bad offsets - // TODO(rjf): handle attribs - // TODO(rjf): offsets? - - // rjf: unpack leaf - CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; - U8 *num1_ptr = (U8 *)(lf+1); - CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); - U8 *num2_ptr = num1_ptr + num1.encoded_size; - CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualBase; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: VFUNCTAB - case CV_LeafKind_VFUNCTAB: - { - CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // NOTE(rjf): currently no-op this case - (void)lf; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - - //////////////////////// - //- rjf: enums -> equip enumerates - // - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - U8 *name_ptr = (U8 *)(lf + 1); - udt_name = str8_cstring_capped(name_ptr, itype_leaf_opl); - field_itype = lf->field_itype; - }goto equip_enum_vals; - equip_enum_vals:; - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: ENUMERATE - case CV_LeafKind_ENUMERATE: - { - // TODO(rjf): attribs - - // rjf: unpack leaf - CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; - U8 *val_ptr = (U8 *)(lf+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); - enum_val->name = name; - enum_val->val = val64; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - } - - //- rjf: find container, given name's namespaces - if(dst_type != 0 && dst_type->udt != 0 && udt_name.size != 0) - { - // rjf: unpack fully qualified namespace from udt name - U64 container_name_opl = p2r_end_of_cplusplus_container_name(udt_name); - String8 container_name = str8_chop(str8_prefix(udt_name, container_name_opl), 2); - String8 leaf_name = str8_skip(udt_name, container_name_opl); - - // rjf: look up namespace node associated with namespace - P2R_NamespaceNode *ns_node = 0; - { - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, container_name, 0)) - { - ns_node = n; - break; - } - } - } - - // rjf: equip container info to udt, equip partial name to type - if(ns_node != 0) - { - RDIM_UDT *udt = dst_type->udt; - if(ns_node->scope != 0) - { - udt->container_scope = ns_node->scope; - } - else if(ns_node->ns != 0) - { - udt->container_namespace = ns_node->ns; - } - else if(ns_node->type != 0) - { - udt->container_type = ns_node->type; - } - dst_type->name = leaf_name; - } - } - } - } - - //- rjf: collect all lanes - if(lane_idx() == 0) - { - lanes_udts = push_array(scratch.arena, RDIM_UDTChunkList, lane_count()); - } - lane_sync_u64(&lanes_udts, 0); - lanes_udts[lane_idx()] = lane_udts; -#undef p2r_type_ptr_from_itype - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: join all UDTs - // - RDIM_UDTChunkList all_udts = {0}; - ProfScope("join all UDTs") if(lane_idx() == 0) - { - for EachIndex(idx, lane_count()) - { - rdim_udt_chunk_list_concat_in_place(&all_udts, &lanes_udts[idx]); - } - } - lane_sync(); - RDIM_UDTChunkList *all_udts_ptr = &all_udts; - lane_sync_u64(&all_udts_ptr, 0); - all_udts = *all_udts_ptr; - - ////////////////////////////////////////////////////////////// - //- rjf: bundle all outputs - // - RDIM_BakeParams result = {0}; - { - //- rjf: produce top-level-info - RDIM_TopLevelInfo top_level_info = {0}; - { - top_level_info.arch = arch; - top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); - top_level_info.exe_hash = exe_hash; - top_level_info.voff_max = exe_voff_max; - if(!params->deterministic) - { - MemoryCopy(&top_level_info.guid.u8[0], &pdb_info->auth_guid.v[0], Min(sizeof top_level_info.guid.u8, sizeof pdb_info->auth_guid.v)); - top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); - } - } - - //- rjf: build binary sections list - RDIM_BinarySectionList binary_sections = {0}; - if(params->subset_flags & RDIM_SubsetFlag_BinarySections) ProfScope("build binary section list") - { - COFF_SectionHeader *coff_ptr = coff_sections.v; - COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; - for(;coff_ptr < coff_opl; coff_ptr += 1) - { - char *name_first = (char *)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); - sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - sec->voff_first = coff_ptr->voff; - sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; - sec->foff_first = coff_ptr->foff; - sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; - } - } - - //- rjf: fill - result.subset_flags = params->subset_flags; - result.top_level_info = top_level_info; - result.binary_sections = binary_sections; - result.units = all_units; - result.namespaces = all_namespaces; - result.types = all_types; - result.udts = all_udts; - result.src_files = all_src_files; - result.line_tables = all_line_tables; - } - - lane_sync(); - scratch_end(scratch); - return result; -} - //////////////////////////////// //~ rjf: PDB -> (Codeview -> RDI) TPI Hash Table Building @@ -5595,7 +461,7 @@ p2r_convert2(Arena *arena, P2R_ConvertParams *params) char *name_first = (char *)src->name; char *name_opl = name_first + sizeof(src->name); dst->name = str8_cstring_capped(name_first, name_opl); - dst->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(src->flags); + dst->flags = c2r_rdi_binary_section_flags_from_coff_section_flags(src->flags); dst->voff = src->voff; dst->vsize = src->vsize; dst->foff = src->foff; diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index a4dfc87a..47df66f4 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -101,39 +101,6 @@ struct P2R_TypeIdChain CV_TypeId itype; }; -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 p2r_end_of_cplusplus_container_name(String8 str); -internal U64 p2r_hash_from_voff(U64 voff); -internal int p2r_namespace_node_is_before(void *raw_a, void *raw_b); - -//////////////////////////////// -//~ rjf: COFF => RDI Canonical Conversions - -internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); - -//////////////////////////////// -//~ rjf: CodeView => RDI Canonical Conversions - -internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); -internal RDI_RegCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); -internal RDI_Language p2r_rdi_language_from_cv_language(CV_Language language); -internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type); -internal RDI_ChecksumKind p2r_rdi_from_cv_c13_checksum_kind(CV_C13ChecksumKind k); - -//////////////////////////////// -//~ rjf: Location Info Building Helpers - -internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); -internal RDIM_Location p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); -internal void p2r_location_case_list_push_over_lvar_addr_range(Arena *arena, RDIM_LocationCaseList *loc_cases, RDIM_Location loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); - -//////////////////////////////// -//~ rjf: Top-Level Conversion Entry Point - -internal RDIM_BakeParams p2r_convert(Arena *arena, P2R_ConvertParams *params); - //////////////////////////////// //~ rjf: PDB -> (Codeview -> RDI) TPI Hash Table Building