From 8901dd30ec261a2fe7a813123c2b1f323fe2d25b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 May 2024 10:35:56 -0700 Subject: [PATCH 01/38] eliminate old pending entity code; do not build missing entity interface if data is actually present (but frontend cache still suggests missing) --- src/df/gfx/df_views.c | 68 ++----------------------------------------- src/df/gfx/df_views.h | 1 - 2 files changed, 3 insertions(+), 66 deletions(-) diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 59fee683..a2873642 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -5356,24 +5356,6 @@ DF_VIEW_CMD_FUNCTION_DEF(PendingEntity) { default:break; - // rjf: pick file - case DF_CoreCmdKind_PickFile: - { - DF_Entity *missing_file = df_entity_from_handle(pves->pick_file_override_target); - String8 pick_string = cmd->params.file_path; - if(!df_entity_is_nil(missing_file) && pick_string.size != 0) - { - DF_Entity *replacement = df_entity_from_path(pick_string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); - view->entity = df_handle_from_entity(replacement); - DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); - p.entity = df_handle_from_entity(missing_file); - p.file_path = pick_string; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); - df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetFileReplacementPath)); - } - }break; - // rjf: gather deferred commands to redispatch when entity is ready case DF_CoreCmdKind_GoToLine: case DF_CoreCmdKind_GoToAddress: @@ -5442,52 +5424,8 @@ DF_VIEW_CMD_FUNCTION_DEF(PendingEntity) DF_VIEW_UI_FUNCTION_DEF(PendingEntity) { - // rjf: grab state - DF_PendingEntityViewState *pves = df_view_user_state(view, DF_PendingEntityViewState); - DF_Entity *entity = df_entity_from_handle(view->entity); - - // rjf: entity is missing -> notify user - if(entity->flags & DF_EntityFlag_IsMissing) - { - UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) - { - Temp scratch = scratch_begin(0, 0); - String8 full_path = df_full_path_from_entity(scratch.arena, entity); - UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_em(3, 1)) - UI_Row UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) - { - UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); - ui_labelf("Could not find \"%S\".", full_path); - } - UI_PrefHeight(ui_em(3, 1)) - UI_Row UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) - UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) - UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) - UI_CornerRadius(ui_top_font_size()/3) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_Focus(UI_FocusKind_On) - if(ui_clicked(ui_buttonf("Find alternative..."))) - { - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunCommand)); - pves->pick_file_override_target = df_handle_from_entity(entity); - } - scratch_end(scratch); - } - } - - // rjf: entity is still loading -> loading animation - else - { - view->loading_t = view->loading_t_target = 1.f; - df_gfx_request_frame(); - } + view->loading_t = view->loading_t_target = 1.f; + df_gfx_request_frame(); } //////////////////////////////// @@ -5950,7 +5888,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: build missing & override interface // - if(entity_is_missing) + if(entity_is_missing && !text_info_is_ready) { UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) { diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index 7f450c41..f5bd217a 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -101,7 +101,6 @@ struct DF_PendingEntityViewState { Arena *deferred_cmd_arena; DF_CmdList deferred_cmds; - DF_Handle pick_file_override_target; Arena *complete_cfg_arena; DF_CfgNode *complete_cfg_root; }; From 33ab26dfb3663b3c662492def32cca43d6835064 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 May 2024 15:39:57 -0700 Subject: [PATCH 02/38] begin porting unwinder to ctrl layer, just built purely on in-process memory, and getting completely off of parsed binary image artifacts --- src/ctrl/ctrl_core.c | 1151 +++++++++++++++++++++++++++++++++++++++++ src/ctrl/ctrl_core.h | 19 + src/df/gfx/df_views.c | 6 +- src/pe/pe.c | 5 +- 4 files changed, 1175 insertions(+), 6 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 625b6485..9a296eee 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1245,6 +1245,25 @@ ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CT return result; } +internal B32 +ctrl_read_cached_process_memory(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + U64 needed_size = dim_1u64(range); + CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process, range, endt_us); + B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); + if(good) + { + MemoryCopy(out, slice.data.str, needed_size); + } + if(slice.stale && is_stale_out) + { + *is_stale_out = 1; + } + scratch_end(scratch); + return good; +} + //- rjf: process memory writing internal B32 @@ -1432,6 +1451,1138 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: [x64] + +internal REGS_Reg64 * +ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg) +{ + local_persist REGS_Reg64 dummy = {0}; + REGS_Reg64 *result = &dummy; + switch(gpr_reg) + { + case PE_UnwindGprRegX64_RAX:{result = ®s->rax;}break; + case PE_UnwindGprRegX64_RCX:{result = ®s->rcx;}break; + case PE_UnwindGprRegX64_RDX:{result = ®s->rdx;}break; + case PE_UnwindGprRegX64_RBX:{result = ®s->rbx;}break; + case PE_UnwindGprRegX64_RSP:{result = ®s->rsp;}break; + case PE_UnwindGprRegX64_RBP:{result = ®s->rbp;}break; + case PE_UnwindGprRegX64_RSI:{result = ®s->rsi;}break; + case PE_UnwindGprRegX64_RDI:{result = ®s->rdi;}break; + case PE_UnwindGprRegX64_R8 :{result = ®s->r8 ;}break; + case PE_UnwindGprRegX64_R9 :{result = ®s->r9 ;}break; + case PE_UnwindGprRegX64_R10:{result = ®s->r10;}break; + case PE_UnwindGprRegX64_R11:{result = ®s->r11;}break; + case PE_UnwindGprRegX64_R12:{result = ®s->r12;}break; + case PE_UnwindGprRegX64_R13:{result = ®s->r13;}break; + case PE_UnwindGprRegX64_R14:{result = ®s->r14;}break; + case PE_UnwindGprRegX64_R15:{result = ®s->r15;}break; + } + return result; +} + +internal CTRL_UnwindStepResult +ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) +{ + B32 is_stale = 0; + Temp scratch = scratch_begin(0, 0); + + ////////////////////////////// + //- rjf: unpack parameters + // + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, machine_id, module_handle); + CTRL_Entity *process = module->parent; + U64 rip_voff = regs->rip.u64 - module->vaddr_range.min; + + ////////////////////////////// + //- rjf: unpack relevant PE info + // + PE_IntelPdata *pdatas = 0; + U64 pdatas_count = 0; + if(module != &ctrl_entity_nil) + { + B32 is_valid = 1; + + //- rjf: read DOS header + PE_DosHeader dos_header = {0}; + if(is_valid) + { + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min, &is_stale, &dos_header, endt_us) || + dos_header.magic != PE_DOS_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read PE magic + U32 pe_magic = 0; + if(is_valid) + { + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + dos_header.coff_file_offset, &is_stale, &pe_magic, endt_us) || + pe_magic != PE_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read COFF header + U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_Header coff_header = {0}; + if(is_valid) + { + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + coff_header_off, &is_stale, &coff_header, endt_us)) + { + is_valid = 0; + } + } + + //- rjf: unpack range of optional extension header + U32 opt_ext_size = coff_header.optional_header_size; + Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), + coff_header_off + sizeof(coff_header) + opt_ext_size); + + //- rjf: read optional header + U16 optional_magic = 0; + U64 image_base = 0; + U64 entry_point = 0; + U32 data_dir_count = 0; + U64 virt_section_align = 0; + U64 file_section_align = 0; + Rng1U64 *data_dir_franges = 0; + if(opt_ext_size > 0) + { + // rjf: read magic number + U16 opt_ext_magic = 0; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &opt_ext_magic, endt_us); + + // rjf: read info + U32 reported_data_dir_offset = 0; + U32 reported_data_dir_count = 0; + switch(opt_ext_magic) + { + case PE_PE32_MAGIC: + { + PE_OptionalHeader32 pe_optional = {0}; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &pe_optional, endt_us); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + case PE_PE32PLUS_MAGIC: + { + PE_OptionalHeader32Plus pe_optional = {0}; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &pe_optional, endt_us); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + } + + // rjf: find number of data directories + U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); + data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + + // rjf: grab pdatas from exceptions section + if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS) + { + PE_DataDirectory dir = {0}; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &is_stale, &dir, endt_us); + Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + if(ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min + pdatas_voff_range.min, module->vaddr_range.min + pdatas_voff_range.max), &is_stale, pdatas, endt_us)) + { + pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); + } + } + } + } + + ////////////////////////////// + //- rjf: find current rip's pdata entry + // + PE_IntelPdata *first_pdata = 0; + if(pdatas_count != 0) + { + U64 first_pdata_voff = 0; + if(rip_voff >= pdatas[0].voff_first) + { + // NOTE(rjf): + // + // binary search: + // find max index s.t. pdata_array[index].voff_first <= voff + // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) + U64 index = pdatas_count; + U64 min = 0; + U64 opl = pdatas_count; + for(;;) + { + U64 mid = (min + opl)/2; + PE_IntelPdata *pdata = pdatas + mid; + if(rip_voff < pdata->voff_first) + { + opl = mid; + } + else if(pdata->voff_first < rip_voff) + { + min = mid; + } + else + { + index = mid; + break; + } + if(min + 1 >= opl) + { + index = min; + break; + } + } + + // rjf: if we are in range fill result + { + PE_IntelPdata *pdata = pdatas + index; + if(pdata->voff_first <= rip_voff && rip_voff < pdata->voff_one_past_last) + { + first_pdata = pdata; + } + } + } + } + + ////////////////////////////// + //- rjf: pdata -> detect if in epilog + // + B32 has_pdata_and_in_epilog = 0; + if(first_pdata) + { + // NOTE(allen): There are restrictions placed on how an epilog is allowed + // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) + // Here we interpret machine code directly according to the rules + // given there to determine if the code we're looking at looks like an epilog. + + //- rjf: set up parsing state + B32 is_epilog = 0; + B32 keep_parsing = 1; + U64 read_vaddr = regs->rip.u64; + U64 read_vaddr_opl = read_vaddr + 256; + + //- rjf: check first instruction + { + B32 inst_good = 0; + U8 inst[4] = {0}; + if(read_vaddr + sizeof(inst) <= read_vaddr_opl) + { + inst_good = ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, inst, endt_us); + } + if(!inst_good) + { + keep_parsing = 0; + } + else if((inst[0] & 0xF8) == 0x48) + { + switch(inst[1]) + { + // rjf: add $nnnn,%rsp + case 0x81: + { + if(inst[0] == 0x48 && inst[2] == 0xC4) + { + read_vaddr += 7; + } + else + { + keep_parsing = 0; + } + }break; + + // rjf: add $n,%rsp + case 0x83: + { + if(inst[0] == 0x48 && inst[2] == 0xC4) + { + read_vaddr += 4; + } + else + { + keep_parsing = 0; + } + }break; + + // rjf: lea n(reg),%rsp + case 0x8D: + { + if((inst[0] & 0x06) == 0 && + ((inst[2] >> 3) & 0x07) == 0x04 && + (inst[2] & 0x07) != 0x04) + { + U8 imm_size = (inst[2] >> 6); + + // rjf: 1-byte immediate + if(imm_size == 1) + { + read_vaddr += 4; + } + + // rjf: 4-byte immediate + else if(imm_size == 2) + { + read_vaddr += 7; + } + + // rjf: other case + else + { + keep_parsing = 0; + } + } + else + { + keep_parsing = 0; + } + }break; + } + } + } + + //- rjf: continue parsing instructions + for(;keep_parsing;) + { + // rjf: read next instruction byte + B32 inst_byte_good = 0; + U8 inst_byte = 0; + if(read_vaddr + sizeof(inst_byte) <= read_vaddr_opl) + { + inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + } + if(!inst_byte_good) + { + keep_parsing = 0; + } + + // rjf: when (... I don't know ...) rely on the next byte + B32 check_inst_byte_good = inst_byte_good; + U64 check_vaddr = read_vaddr; + U8 check_inst_byte = inst_byte; + if(inst_byte_good && (inst_byte & 0xF0) == 0x40) + { + check_vaddr = read_vaddr + 1; + if(read_vaddr + sizeof(check_inst_byte) <= read_vaddr_opl) + { + check_inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &check_inst_byte, endt_us); + } + if(!check_inst_byte_good) + { + keep_parsing = 0; + } + } + + // rjf: check instruction byte + if(check_inst_byte_good) + { + switch(check_inst_byte) + { + // rjf: pop + case 0x58:case 0x59:case 0x5A:case 0x5B: + case 0x5C:case 0x5D:case 0x5E:case 0x5F: + { + read_vaddr = check_vaddr + 1; + }break; + + // rjf: ret + case 0xC2: + case 0xC3: + { + is_epilog = 1; + keep_parsing = 0; + }break; + + // rjf: jmp nnnn + case 0xE9: + { + U64 imm_vaddr = check_vaddr + 1; + S32 imm = 0; + B32 imm_good = 0; + if(read_vaddr + sizeof(imm) <= read_vaddr_opl) + { + imm_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us); + } + if(!imm_good) + { + keep_parsing = 0; + } + if(imm_good) + { + U64 next_vaddr = (U64)(imm_vaddr + sizeof(imm) + imm); + U64 next_voff = next_vaddr - module->vaddr_range.min; // TODO(rjf): verify that this offset is from module base vaddr, not section + if(!(first_pdata->voff_first <= next_voff && next_voff < first_pdata->voff_one_past_last)) + { + keep_parsing = 0; + } + else + { + read_vaddr = next_vaddr; + } + } + // TODO(allen): why isn't this just the end of the epilog? + }break; + + // rjf: rep; ret (for amd64 prediction bug) + case 0xF3: + { + U8 next_inst_byte = 0; + B32 next_inst_byte_good = 0; + if(read_vaddr + sizeof(next_inst_byte) <= read_vaddr_opl) + { + next_inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &next_inst_byte, endt_us); + } + if(next_inst_byte_good) + { + is_epilog = (next_inst_byte == 0xC3); + } + keep_parsing = 0; + }break; + + default:{keep_parsing = 0;}break; + } + } + } + has_pdata_and_in_epilog = is_epilog; + } + + ////////////////////////////// + //- rjf: pdata & in epilog -> epilog unwind + // + if(first_pdata && has_pdata_and_in_epilog) + { + + } + + ////////////////////////////// + //- rjf: pdata & not in epilog -> xdata unwind + // + B32 xdata_unwind_did_machframe = 0; + if(first_pdata && !has_pdata_and_in_epilog) + { + //- rjf: get frame reg + B32 bad_frame_reg_info = 0; + REGS_Reg64 *frame_reg = 0; + U64 frame_off = 0; + { + U64 unwind_info_off = first_pdata->voff_unwind_info; + PE_UnwindInfo unwind_info = {0}; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info.frame); + U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info.frame); + if(frame_reg_id != 0) + { + frame_reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, frame_reg_id); + bad_frame_reg_info = (frame_reg == 0); // NOTE(rjf): frame_reg should never be 0 at this point, in valid exe + } + frame_off = frame_off_val; + } + + //- rjf: iterate pdatas, apply opcodes + PE_IntelPdata *last_pdata = 0; + PE_IntelPdata *pdata = first_pdata; + if(!bad_frame_reg_info) for(B32 good = 1; good && pdata != last_pdata;) + { + //- rjf: unpack unwind info & codes + B32 good_unwind_info = 1; + U64 unwind_info_off = pdata->voff_unwind_info; + PE_UnwindInfo unwind_info = {0}; + good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); + good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), + module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), + &is_stale, unwind_codes, endt_us); + + //- rjf: bad unwind info -> abort + if(!good_unwind_info) + { + break; + } + + //- rjf: unpack frame base + U64 frame_base = regs->rsp.u64; + if(frame_reg != 0) + { + U64 raw_frame_base = frame_reg->u64; + U64 adjusted_frame_base = raw_frame_base - frame_off*16; + if(adjusted_frame_base < raw_frame_base) + { + frame_base = adjusted_frame_base; + } + } + + //- rjf: apply opcodes + PE_UnwindCode *code_ptr = unwind_codes; + PE_UnwindCode *code_opl = unwind_codes + unwind_info.codes_num; + for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) + { + // rjf: unpack opcode info + U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); + U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); + U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); + if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) + { + slot_count += 1; + } + + // rjf: detect bad slot counts + if(slot_count == 0 || code_ptr+slot_count > code_opl) + { + good = 0; + break; + } + + // rjf: set next op code pointer + next_code_ptr = code_ptr + slot_count; + + // rjf: interpret this op code + U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; + if(code_voff <= rip_voff) + { + switch(op_code) + { + case PE_UnwindOpCode_PUSH_NONVOL: + { + // rjf: read value from stack pointer + U64 rsp = regs->rsp.u64; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &rsp, endt_us)) + { + good = 0; + break; + } + + // rjf: advance stack ptr + U64 new_rsp = rsp + 8; + + // rjf: commit registers + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + regs->rsp.u64 = new_rsp; + }break; + + case PE_UnwindOpCode_ALLOC_LARGE: + { + // rjf: read alloc size + U64 size = 0; + if(op_info == 0) + { + size = code_ptr[1].u16*8; + } + else if(op_info == 1) + { + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } + else + { + good = 0; + break; + } + + // rjf: advance stack pointer + U64 rsp = regs->rsp.u64; + U64 new_rsp = rsp + size; + + // rjf: advance stack pointer + regs->rsp.u64 = new_rsp; + }break; + + case PE_UnwindOpCode_ALLOC_SMALL: + { + // rjf: advance stack pointer + regs->rsp.u64 += op_info*8 + 8; + }break; + + case PE_UnwindOpCode_SET_FPREG: + { + // rjf: put stack pointer back to the frame base + regs->rsp.u64 = frame_base; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL: + { + // rjf: read value from frame base + U64 off = code_ptr[1].u16*8; + U64 addr = frame_base + off; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) + { + good = 0; + break; + } + + // rjf: commit to register + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL_FAR: + { + // rjf: read value from frame base + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) + { + good = 0; + break; + } + + // rjf: commit to register + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_EPILOG: + { + good = 0; + }break; + + case PE_UnwindOpCode_SPARE_CODE: + { + good = 0; + // TODO(rjf): ??? + }break; + + case PE_UnwindOpCode_SAVE_XMM128: + { + // rjf: read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16*16; + U64 addr = frame_base + off; + if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+sizeof(buf)), &is_stale, buf, endt_us)) + { + good = 0; + break; + } + + // rjf: commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_SAVE_XMM128_FAR: + { + // rjf: read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us)) + { + good = 0; + break; + } + + // rjf: commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_PUSH_MACHFRAME: + { + // NOTE(rjf): this was found by stepping through kernel code after an exception was + // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main + if(op_info > 1) + { + good = 0; + break; + } + + // rjf: read values + U64 sp_og = regs->rsp.u64; + U64 sp_adj = sp_og; + if(op_info == 1) + { + sp_adj += 8; + } + U64 ip_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_adj, &is_stale, &ip_value, endt_us)) + { + good = 0; + break; + } + U64 sp_after_ip = sp_adj + 8; + U16 ss_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ip, &is_stale, &ss_value, endt_us)) + { + good = 0; + break; + } + U64 sp_after_ss = sp_after_ip + 8; + U64 rflags_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us)) + { + good = 0; + break; + } + U64 sp_after_rflags = sp_after_ss + 8; + U64 sp_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us)) + { + good = 0; + break; + } + + // rjf: commit registers + regs->rip.u64 = ip_value; + regs->ss.u16 = ss_value; + regs->rflags.u64 = rflags_value; + regs->rsp.u64 = sp_value; + + // rjf: mark machine frame + xdata_unwind_did_machframe = 1; + }break; + } + } + } + + //- rjf: iterate to next pdata + if(good) + { + U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info.header); + if(!(flags & PE_UnwindInfoFlag_CHAINED)) + { + break; + } + U64 code_count_rounded = AlignPow2(unwind_info.codes_num, sizeof(PE_UnwindCode)); + U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); + U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; + last_pdata = pdata; + pdata = push_array(scratch.arena, PE_IntelPdata, 1); + ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us); + } + } + } + + ////////////////////////////// + //- rjf: no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer + // + if(!first_pdata || xdata_unwind_did_machframe) + { + // rjf: read rip from stack pointer + U64 rsp = regs->rsp.u64; + U64 new_rip = 0; + ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &new_rip, endt_us); + + // rjf: advance stack pointer + U64 new_rsp = rsp + 8; + + // rjf: commit registers + regs->rip.u64 = new_rip; + regs->rsp.u64 = new_rsp; + } + + scratch_end(scratch); + CTRL_UnwindStepResult result = {0}; + return result; + + //~ TODO(rjf): OLD +#if 0 + DMN_UnwindStepResult result = {0}; + U64 missed_read_addr = 0; + + //- grab ip_voff (several places can use this) + U64 ip_voff = regs->rip.u64 - base_vaddr; + + //- get pdata entry from current ip + PE_IntelPdata *initial_pdata = 0; + { + U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); + if(initial_pdata_off != 0) + { + initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); + } + } + + //- no pdata; unwind by reading stack pointer + if(initial_pdata == 0) + { + // read ip from stack pointer + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + //- got pdata; perform unwinding with exception handling + else + { + // try epilog unwind + B32 did_epilog_unwind = 0; + if(unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)) + { + result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); + did_epilog_unwind = 1; + } + + // try xdata unwind + if(!did_epilog_unwind) + { + B32 did_machframe = 0; + + // get frame reg + REGS_Reg64 *frame_reg = 0; + U64 frame_off = 0; + + { + U64 unwind_info_off = initial_pdata->voff_unwind_info; + PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + + U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info->frame); + U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info->frame); + + if (frame_reg_id != 0){ + frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); + // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. + } + frame_off = frame_off_val; + } + + PE_IntelPdata *last_pdata = 0; + PE_IntelPdata *pdata = initial_pdata; + for (;pdata != last_pdata;) + { + //- rjf: unpack unwind info & codes + U64 unwind_info_off = pdata->voff_unwind_info; + PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + PE_UnwindCode *unwind_codes = (PE_UnwindCode*)(unwind_info + 1); + + //- rjf: unpack frame base + U64 frame_base = regs->rsp.u64; + if(frame_reg != 0) + { + U64 raw_frame_base = frame_reg->u64; + U64 adjusted_frame_base = raw_frame_base - frame_off*16; + if(adjusted_frame_base < raw_frame_base) + { + frame_base = adjusted_frame_base; + } + else + { + frame_base = 0; + } + } + + //- rjf: bad unwind info -> abort + if(unwind_info == 0) + { + result.dead = 1; + goto error_out; + } + + //- op code interpreter + PE_UnwindCode *code_ptr = unwind_codes; + PE_UnwindCode *code_opl = unwind_codes + unwind_info->codes_num; + for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) + { + // extract op code parts + U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); + U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); + + // determine number of op code slots + U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); + if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) + { + slot_count += 1; + } + + // check op code slot count + if (slot_count == 0 || code_ptr + slot_count > code_opl){ + result.dead = 1; + goto end_xdata_unwind; + } + + // set next op code pointer + next_code_ptr = code_ptr + slot_count; + + // interpret this op code + U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; + if (code_voff <= ip_voff){ + switch (op_code){ + case PE_UnwindOpCode_PUSH_NONVOL: + { + // read value from stack pointer + U64 sp = regs->rsp.u64; + U64 value = 0; + if(!unw_memview_read_struct(memview, sp, &value)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + regs->rsp.u64 = new_sp; + }break; + + case PE_UnwindOpCode_ALLOC_LARGE: + { + // read alloc size + U64 size = 0; + if (op_info == 0){ + size = code_ptr[1].u16*8; + } + else if (op_info == 1){ + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } + else{ + result.dead = 1; + goto end_xdata_unwind; + } + + // advance stack pointer + U64 sp = regs->rsp.u64; + U64 new_sp = sp + size; + + // advance stack pointer + regs->rsp.u64 = new_sp; + }break; + + case PE_UnwindOpCode_ALLOC_SMALL: + { + // advance stack pointer + regs->rsp.u64 += op_info*8 + 8; + }break; + + case PE_UnwindOpCode_SET_FPREG: + { + // put stack pointer back to the frame base + regs->rsp.u64 = frame_base; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL: + { + // read value from frame base + U64 off = code_ptr[1].u16*8; + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL_FAR: + { + // read value from frame base + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_EPILOG: + { + result.dead = 1; + }break; + + case PE_UnwindOpCode_SPARE_CODE: + { + result.dead = 1; + // Assert(!"Hit me!"); + // TODO(allen): ??? + }break; + + case PE_UnwindOpCode_SAVE_XMM128: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16*16; + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_SAVE_XMM128_FAR: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_PUSH_MACHFRAME: + { + // NOTE(rjf): this was found by stepping through kernel code after an exception was + // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main + + if(op_info > 1) + { + result.dead = 1; + goto end_xdata_unwind; + } + + // read values + U64 sp_og = regs->rsp.u64; + U64 sp_adj = sp_og; + if(op_info == 1) + { + sp_adj += 8; + } + + U64 ip_value = 0; + if(!unw_memview_read_struct(memview, sp_adj, &ip_value)) + { + missed_read_addr = sp_adj; + goto error_out; + } + + U64 sp_after_ip = sp_adj + 8; + U16 ss_value = 0; + if(!unw_memview_read_struct(memview, sp_after_ip, &ss_value)) + { + missed_read_addr = sp_after_ip; + goto error_out; + } + + U64 sp_after_ss = sp_after_ip + 8; + U64 rflags_value = 0; + if(!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)) + { + missed_read_addr = sp_after_ss; + goto error_out; + } + + U64 sp_after_rflags = sp_after_ss + 8; + U64 sp_value = 0; + if(!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)) + { + missed_read_addr = sp_after_rflags; + goto error_out; + } + + // commit registers + regs->rip.u64 = ip_value; + regs->ss.u16 = ss_value; + regs->rflags.u64 = rflags_value; + regs->rsp.u64 = sp_value; + + // mark machine frame + did_machframe = 1; + }break; + } + } + } + + //- iterate pdata chain + U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info->header); + if (!(flags & PE_UnwindInfoFlag_CHAINED)){ + break; + } + + U64 code_count_rounded = AlignPow2(unwind_info->codes_num, sizeof(PE_UnwindCode)); + U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); + U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; + + last_pdata = pdata; + pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); + } + + if(!did_machframe) + { + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + end_xdata_unwind:; + } + } + + error_out:; + + if(missed_read_addr != 0) + { + result.dead = 1; + result.missed_read = 1; + result.missed_read_addr = missed_read_addr; + } + + if(!result.dead) + { + result.stack_pointer = regs->rsp.u64; + } + + return(result); +#endif +} + +//- rjf: abstracted unwind step + +internal CTRL_UnwindStepResult +ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us) +{ + CTRL_UnwindStepResult result = {0}; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + result = ctrl_unwind_step__pe_x64(store, machine_id, module, (REGS_RegBlockX64 *)reg_block, endt_us); + }break; + } + return result; +} + +//- rjf: abstracted full unwind + internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 0666e237..f4edf0bb 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -107,6 +107,15 @@ struct CTRL_EntityStore //////////////////////////////// //~ rjf: Unwind Types +typedef struct CTRL_UnwindStepResult CTRL_UnwindStepResult; +struct CTRL_UnwindStepResult +{ + B32 dead; + B32 missed_read; + U64 missed_read_addr; + U64 stack_pointer; +}; + typedef struct CTRL_UnwindFrame CTRL_UnwindFrame; struct CTRL_UnwindFrame { @@ -654,6 +663,8 @@ internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machin //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us); internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us); +internal B32 ctrl_read_cached_process_memory(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); +#define ctrl_read_cached_process_memory_struct(machine_id, process, vaddr, is_stale_out, ptr, endt_us) ctrl_read_cached_process_memory((machine_id), (process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) //- rjf: process memory writing internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src); @@ -672,6 +683,14 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: [x64] +internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); +internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, REGS_RegBlockX64 *regs, U64 endt_us); + +//- rjf: abstracted unwind step +internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us); + +//- rjf: abstracted full unwind internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); //////////////////////////////// diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index a2873642..79ef4584 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -6474,7 +6474,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { ui_label(full_path); ui_spacer(ui_em(1.5f, 1)); - ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_labelf("Line: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); ui_labelf("%s", @@ -7326,7 +7326,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) U64 cursor_vaddr = (1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) ? (dasm_vaddr_range.min+dasm_info.insts.v[dv->cursor.line-1].code_off) : 0; ui_labelf("%S", path_normalized_from_string(scratch.arena, module->name)); ui_spacer(ui_em(1.5f, 1)); - ui_labelf("Address: 0x%I64x, Row: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); + ui_labelf("Address: 0x%I64x, Line: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); ui_labelf("bin"); @@ -8120,7 +8120,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_Font(code_font) { - ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_labelf("Line: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); } diff --git a/src/pe/pe.c b/src/pe/pe.c index f2b243f9..9291d179 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -69,11 +69,10 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read pe magic - U32 coff_off = dos_header.coff_file_offset; U32 pe_magic = 0; if(valid) { - str8_deserial_read_struct(data, coff_off, &pe_magic); + str8_deserial_read_struct(data, dos_header.coff_file_offset, &pe_magic); } // rjf: bad pe magic -> abort @@ -83,7 +82,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read coff header - U32 coff_header_off = coff_off + sizeof(pe_magic); + U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); COFF_Header coff_header = {0}; if(valid) { From 578a56d231611469bdefdc38b8b7e66928050fdc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 May 2024 17:12:37 -0700 Subject: [PATCH 03/38] further progress on new unwinder --- src/ctrl/ctrl_core.c | 704 +++++++++++++++++------------------------- src/ctrl/ctrl_core.h | 14 +- src/df/core/df_core.c | 2 +- 3 files changed, 288 insertions(+), 432 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9a296eee..9bd61b61 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1484,6 +1484,7 @@ internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) { B32 is_stale = 0; + B32 is_good = 1; Temp scratch = scratch_begin(0, 0); ////////////////////////////// @@ -1498,7 +1499,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // PE_IntelPdata *pdatas = 0; U64 pdatas_count = 0; - if(module != &ctrl_entity_nil) + ProfScope("unpack relevant PE info") if(module != &ctrl_entity_nil) { B32 is_valid = 1; @@ -1510,6 +1511,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN dos_header.magic != PE_DOS_MAGIC) { is_valid = 0; + is_good = 0; } } @@ -1521,6 +1523,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN pe_magic != PE_MAGIC) { is_valid = 0; + is_good = 0; } } @@ -1532,6 +1535,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + coff_header_off, &is_stale, &coff_header, endt_us)) { is_valid = 0; + is_good = 0; } } @@ -1593,10 +1597,9 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN PE_DataDirectory dir = {0}; ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &is_stale, &dir, endt_us); Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); - if(ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min + pdatas_voff_range.min, module->vaddr_range.min + pdatas_voff_range.max), &is_stale, pdatas, endt_us)) - { - pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); - } + pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); + pdatas = push_array(scratch.arena, PE_IntelPdata, pdatas_count); + ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min + pdatas_voff_range.min, module->vaddr_range.min + pdatas_voff_range.max), &is_stale, pdatas, endt_us); } } } @@ -1605,7 +1608,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: find current rip's pdata entry // PE_IntelPdata *first_pdata = 0; - if(pdatas_count != 0) + if(pdatas_count != 0) ProfScope("find current RIP's pdata entry") { U64 first_pdata_voff = 0; if(rip_voff >= pdatas[0].voff_first) @@ -1657,7 +1660,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: pdata -> detect if in epilog // B32 has_pdata_and_in_epilog = 0; - if(first_pdata) + if(first_pdata) ProfScope("pdata -> detect if in epilog") { // NOTE(allen): There are restrictions placed on how an epilog is allowed // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) @@ -1856,16 +1859,228 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN ////////////////////////////// //- rjf: pdata & in epilog -> epilog unwind // - if(first_pdata && has_pdata_and_in_epilog) + if(first_pdata && has_pdata_and_in_epilog) ProfScope("pdata & in epilog -> epilog unwind") { - + U64 read_vaddr = regs->rip.u64; + for(B32 keep_parsing = 1;keep_parsing != 0;) + { + //- rjf: assume no more parsing after this instruction + keep_parsing = 0; + + //- rjf: read next instruction byte + U8 inst_byte = 0; + is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + read_vaddr += 1; + + //- rjf: extract rex from instruction byte + U8 rex = 0; + if((inst_byte & 0xF0) == 0x40) + { + rex = inst_byte & 0xF; // rex prefix + is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + read_vaddr += 1; + } + + //- rjf: parse remainder of instruction + switch(inst_byte) + { + // rjf: pop + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + { + // rjf: read value at rsp + U64 sp = regs->rsp.u64; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &sp, endt_us)) + { + is_good = 0; + break; + } + + // rjf: modify registers + PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, gpr_reg); + reg->u64 = value; + regs->rsp.u64 = sp + 8; + + // rjf: not a final instruction, so keep mparsing + keep_parsing = 1; + }break; + + // rjf: add $nnnn,%rsp + case 0x81: + { + // rjf: skip one byte (we already know what it is in this scenario) + read_vaddr += 1; + + // rjf: read the 4-byte immediate + S32 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + { + is_good = 0; + break; + } + read_vaddr += 4; + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: add $n,%rsp + case 0x83: + { + // rjf: skip one byte (we already know what it is in this scenario) + read_vaddr += 1; + + // rjf: read the 4-byte immediate + S8 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + { + is_good = 0; + break; + } + read_vaddr += 1; + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: lea imm8/imm32,$rsp + case 0x8D: + { + // rjf: read source register + U8 modrm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &modrm, endt_us)) + { + is_good = 0; + break; + } + read_vaddr += 1; + PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8; + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, gpr_reg); + U64 reg_value = reg->u64; + + // rjf: read immediate + S32 imm = 0; + { + // rjf: read 1-byte immediate + if((modrm >> 6) == 1) + { + S8 imm8 = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm8, endt_us)) + { + is_good = 0; + break; + } + read_vaddr += 1; + imm = (S32)imm8; + } + + // rjf: read 4-byte immediate + else + { + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + { + is_good = 0; + break; + } + read_vaddr += 4; + } + } + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(reg_value + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: ret $nn + case 0xC2: + { + // rjf: read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us)) + { + is_good = 0; + break; + } + + // rjf: read 2-byte immediate & advance stack pointer + U16 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + { + is_good = 0; + break; + } + U64 new_sp = sp + 8 + imm; + + // rjf: commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // rjf: ret / rep; ret + case 0xF3: + { + // Assert(!"Hit me!"); + }break; + case 0xC3: + { + // rjf: read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us)) + { + is_good = 0; + break; + } + + // rjf: advance stack pointer + U64 new_sp = sp + 8; + + // rjf: commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // rjf: jmp nnnn + case 0xE9: + { + // Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + + // rjf: Sjmp n + case 0xEB: + { + // Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + } + } } ////////////////////////////// //- rjf: pdata & not in epilog -> xdata unwind // B32 xdata_unwind_did_machframe = 0; - if(first_pdata && !has_pdata_and_in_epilog) + if(first_pdata && !has_pdata_and_in_epilog) ProfScope("pdata & not in epilog -> xdata unwind") { //- rjf: get frame reg B32 bad_frame_reg_info = 0; @@ -1874,7 +2089,10 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { U64 unwind_info_off = first_pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us)) + { + is_good = 0; + } U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info.frame); U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info.frame); if(frame_reg_id != 0) @@ -1888,7 +2106,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: iterate pdatas, apply opcodes PE_IntelPdata *last_pdata = 0; PE_IntelPdata *pdata = first_pdata; - if(!bad_frame_reg_info) for(B32 good = 1; good && pdata != last_pdata;) + if(!bad_frame_reg_info) for(B32 keep_parsing = 1; keep_parsing && pdata != last_pdata;) { //- rjf: unpack unwind info & codes B32 good_unwind_info = 1; @@ -1903,6 +2121,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: bad unwind info -> abort if(!good_unwind_info) { + is_good = 0; break; } @@ -1935,7 +2154,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: detect bad slot counts if(slot_count == 0 || code_ptr+slot_count > code_opl) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -1955,7 +2175,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &rsp, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -1982,7 +2203,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN } else { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2014,7 +2236,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2031,7 +2254,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2042,13 +2266,15 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN case PE_UnwindOpCode_EPILOG: { - good = 0; + keep_parsing = 0; + is_good = 0; }break; case PE_UnwindOpCode_SPARE_CODE: { - good = 0; // TODO(rjf): ??? + keep_parsing = 0; + is_good = 0; }break; case PE_UnwindOpCode_SAVE_XMM128: @@ -2059,7 +2285,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 addr = frame_base + off; if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+sizeof(buf)), &is_stale, buf, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2076,7 +2303,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 addr = frame_base + off; if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2091,7 +2319,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main if(op_info > 1) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2105,28 +2334,32 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 ip_value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_adj, &is_stale, &ip_value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } U64 sp_after_ip = sp_adj + 8; U16 ss_value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ip, &is_stale, &ss_value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } U64 sp_after_ss = sp_after_ip + 8; U64 rflags_value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } U64 sp_after_rflags = sp_after_ss + 8; U64 sp_value = 0; if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us)) { - good = 0; + keep_parsing = 0; + is_good = 0; break; } @@ -2144,7 +2377,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN } //- rjf: iterate to next pdata - if(good) + if(keep_parsing) { U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info.header); if(!(flags & PE_UnwindInfoFlag_CHAINED)) @@ -2164,7 +2397,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN ////////////////////////////// //- rjf: no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer // - if(!first_pdata || xdata_unwind_did_machframe) + if(!first_pdata || !xdata_unwind_did_machframe) ProfScope("no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer") { // rjf: read rip from stack pointer U64 rsp = regs->rsp.u64; @@ -2179,389 +2412,14 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN regs->rsp.u64 = new_rsp; } + ////////////////////////////// + //- rjf: fill & return + // scratch_end(scratch); CTRL_UnwindStepResult result = {0}; + if(!is_good) {result.flags |= CTRL_UnwindFlag_Error;} + if(is_stale) {result.flags |= CTRL_UnwindFlag_Stale;} return result; - - //~ TODO(rjf): OLD -#if 0 - DMN_UnwindStepResult result = {0}; - U64 missed_read_addr = 0; - - //- grab ip_voff (several places can use this) - U64 ip_voff = regs->rip.u64 - base_vaddr; - - //- get pdata entry from current ip - PE_IntelPdata *initial_pdata = 0; - { - U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); - if(initial_pdata_off != 0) - { - initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); - } - } - - //- no pdata; unwind by reading stack pointer - if(initial_pdata == 0) - { - // read ip from stack pointer - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - //- got pdata; perform unwinding with exception handling - else - { - // try epilog unwind - B32 did_epilog_unwind = 0; - if(unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)) - { - result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); - did_epilog_unwind = 1; - } - - // try xdata unwind - if(!did_epilog_unwind) - { - B32 did_machframe = 0; - - // get frame reg - REGS_Reg64 *frame_reg = 0; - U64 frame_off = 0; - - { - U64 unwind_info_off = initial_pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - - U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info->frame); - U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info->frame); - - if (frame_reg_id != 0){ - frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); - // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. - } - frame_off = frame_off_val; - } - - PE_IntelPdata *last_pdata = 0; - PE_IntelPdata *pdata = initial_pdata; - for (;pdata != last_pdata;) - { - //- rjf: unpack unwind info & codes - U64 unwind_info_off = pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - PE_UnwindCode *unwind_codes = (PE_UnwindCode*)(unwind_info + 1); - - //- rjf: unpack frame base - U64 frame_base = regs->rsp.u64; - if(frame_reg != 0) - { - U64 raw_frame_base = frame_reg->u64; - U64 adjusted_frame_base = raw_frame_base - frame_off*16; - if(adjusted_frame_base < raw_frame_base) - { - frame_base = adjusted_frame_base; - } - else - { - frame_base = 0; - } - } - - //- rjf: bad unwind info -> abort - if(unwind_info == 0) - { - result.dead = 1; - goto error_out; - } - - //- op code interpreter - PE_UnwindCode *code_ptr = unwind_codes; - PE_UnwindCode *code_opl = unwind_codes + unwind_info->codes_num; - for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) - { - // extract op code parts - U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); - U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); - - // determine number of op code slots - U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); - if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) - { - slot_count += 1; - } - - // check op code slot count - if (slot_count == 0 || code_ptr + slot_count > code_opl){ - result.dead = 1; - goto end_xdata_unwind; - } - - // set next op code pointer - next_code_ptr = code_ptr + slot_count; - - // interpret this op code - U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; - if (code_voff <= ip_voff){ - switch (op_code){ - case PE_UnwindOpCode_PUSH_NONVOL: - { - // read value from stack pointer - U64 sp = regs->rsp.u64; - U64 value = 0; - if(!unw_memview_read_struct(memview, sp, &value)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_LARGE: - { - // read alloc size - U64 size = 0; - if (op_info == 0){ - size = code_ptr[1].u16*8; - } - else if (op_info == 1){ - size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - } - else{ - result.dead = 1; - goto end_xdata_unwind; - } - - // advance stack pointer - U64 sp = regs->rsp.u64; - U64 new_sp = sp + size; - - // advance stack pointer - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_SMALL: - { - // advance stack pointer - regs->rsp.u64 += op_info*8 + 8; - }break; - - case PE_UnwindOpCode_SET_FPREG: - { - // put stack pointer back to the frame base - regs->rsp.u64 = frame_base; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL: - { - // read value from frame base - U64 off = code_ptr[1].u16*8; - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL_FAR: - { - // read value from frame base - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_EPILOG: - { - result.dead = 1; - }break; - - case PE_UnwindOpCode_SPARE_CODE: - { - result.dead = 1; - // Assert(!"Hit me!"); - // TODO(allen): ??? - }break; - - case PE_UnwindOpCode_SAVE_XMM128: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16*16; - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_SAVE_XMM128_FAR: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_PUSH_MACHFRAME: - { - // NOTE(rjf): this was found by stepping through kernel code after an exception was - // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main - - if(op_info > 1) - { - result.dead = 1; - goto end_xdata_unwind; - } - - // read values - U64 sp_og = regs->rsp.u64; - U64 sp_adj = sp_og; - if(op_info == 1) - { - sp_adj += 8; - } - - U64 ip_value = 0; - if(!unw_memview_read_struct(memview, sp_adj, &ip_value)) - { - missed_read_addr = sp_adj; - goto error_out; - } - - U64 sp_after_ip = sp_adj + 8; - U16 ss_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ip, &ss_value)) - { - missed_read_addr = sp_after_ip; - goto error_out; - } - - U64 sp_after_ss = sp_after_ip + 8; - U64 rflags_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)) - { - missed_read_addr = sp_after_ss; - goto error_out; - } - - U64 sp_after_rflags = sp_after_ss + 8; - U64 sp_value = 0; - if(!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)) - { - missed_read_addr = sp_after_rflags; - goto error_out; - } - - // commit registers - regs->rip.u64 = ip_value; - regs->ss.u16 = ss_value; - regs->rflags.u64 = rflags_value; - regs->rsp.u64 = sp_value; - - // mark machine frame - did_machframe = 1; - }break; - } - } - } - - //- iterate pdata chain - U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info->header); - if (!(flags & PE_UnwindInfoFlag_CHAINED)){ - break; - } - - U64 code_count_rounded = AlignPow2(unwind_info->codes_num, sizeof(PE_UnwindCode)); - U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); - U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; - - last_pdata = pdata; - pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); - } - - if(!did_machframe) - { - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - end_xdata_unwind:; - } - } - - error_out:; - - if(missed_read_addr != 0) - { - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - if(!result.dead) - { - result.stack_pointer = regs->rsp.u64; - } - - return(result); -#endif } //- rjf: abstracted unwind step @@ -2590,7 +2448,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); CTRL_Unwind unwind = {0}; - unwind.error = 1; + unwind.flags |= CTRL_UnwindFlag_Error; //- rjf: unpack args CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); @@ -2630,21 +2488,17 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma UNW_MemView memview = stack_memview; if(regs_block_good && stack_memview_good) { - unwind.error = 0; + unwind.flags = 0; for(;;) { // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); DMN_Handle module = {0}; - String8 module_name = {0}; - Rng1U64 module_vaddr_range = {0}; for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) { if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) { module = m->handle; - module_name = m->string; - module_vaddr_range = m->vaddr_range; break; } } @@ -2655,18 +2509,6 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma break; } - // rjf: module -> all the binary info - String8 binary_full_path = module_name; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); - String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - - // rjf: cancel on bad data - if(binary_data.size == 0) - { - unwind.error = 1; - break; - } - // rjf: valid step -> push frame CTRL_UnwindFrame *frame = push_array(arena, CTRL_UnwindFrame, 1); frame->rip = rip; @@ -2676,6 +2518,15 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma unwind.count += 1; // rjf: unwind one step + CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, module, arch, regs_block, endt_us); + unwind.flags |= step.flags; + if(step.flags & CTRL_UnwindFlag_Error || regs_rsp_from_arch_block(arch, regs_block) == 0) + { + break; + } + + // rjf: unwind one step (OLD) +#if 0 UNW_Step unwind_step = {0}; switch(arch) { @@ -2700,6 +2551,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma { break; } +#endif } } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index f4edf0bb..ec7bcecf 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -107,13 +107,17 @@ struct CTRL_EntityStore //////////////////////////////// //~ rjf: Unwind Types +typedef U32 CTRL_UnwindFlags; +enum +{ + CTRL_UnwindFlag_Error = (1<<0), + CTRL_UnwindFlag_Stale = (1<<1), +}; + typedef struct CTRL_UnwindStepResult CTRL_UnwindStepResult; struct CTRL_UnwindStepResult { - B32 dead; - B32 missed_read; - U64 missed_read_addr; - U64 stack_pointer; + CTRL_UnwindFlags flags; }; typedef struct CTRL_UnwindFrame CTRL_UnwindFrame; @@ -131,7 +135,7 @@ struct CTRL_Unwind CTRL_UnwindFrame *first; CTRL_UnwindFrame *last; U64 count; - B32 error; + CTRL_UnwindFlags flags; }; //////////////////////////////// diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 26f5bbfd..a707e200 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6245,7 +6245,7 @@ df_query_cached_unwind_from_thread(DF_Entity *thread) else { result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - if(!result.error) + if(!(result.flags & CTRL_UnwindFlag_Error)) { node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); SLLQueuePush_N(slot->first, slot->last, node, hash_next); From 301cf6b7ac9921b709b1d818c15409dbb49dd6eb Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 17 May 2024 14:15:11 -0700 Subject: [PATCH 04/38] regression fixes, better integration, and tightening up the new unwinder --- build.bat | 16 ++--- src/ctrl/ctrl_core.c | 138 ++++++++++++++++++++++++------------------ src/ctrl/ctrl_core.h | 22 +++++-- src/df/core/df_core.c | 56 ++++++----------- src/df/gfx/df_gfx.c | 13 ++-- src/df/gfx/df_views.c | 47 +++++++------- src/regs/regs.c | 8 +-- 7 files changed, 155 insertions(+), 145 deletions(-) diff --git a/build.bat b/build.bat index 348d870e..08cf20fa 100644 --- a/build.bat +++ b/build.bat @@ -54,12 +54,14 @@ set clang_out= -o :: --- Per-Build Settings ----------------------------------------------------- set link_dll=-DLL -if "%msvc%"=="1" set only_compile=/c -if "%clang%"=="1" set only_compile=-c -if "%msvc%"=="1" set EHsc=/EHsc -if "%clang%"=="1" set EHsc= -if "%msvc%"=="1" set rc=rc.exe -if "%clang%"=="1" set rc=llvm-rc.exe +if "%msvc%"=="1" set only_compile=/c +if "%clang%"=="1" set only_compile=-c +if "%msvc%"=="1" set EHsc=/EHsc +if "%clang%"=="1" set EHsc= +if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO +if "%clang%"=="1" set no_aslr=/DYNAMICBASE:NO +if "%msvc%"=="1" set rc=rc.exe +if "%clang%"=="1" set rc=llvm-rc.exe :: --- Choose Compile/Link Lines ---------------------------------------------- if "%msvc%"=="1" set compile_debug=%cl_debug% @@ -104,7 +106,7 @@ if "%raddbgi_breakpad_from_pdb%"=="1" %compile% ..\src\raddbgi_brea if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 -if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %out%mule_main.exe || exit /b 1 +if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 popd diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9bd61b61..f2c75cf2 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1036,7 +1036,6 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - B32 range_node_exists = 0; for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) { if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) @@ -1508,6 +1507,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN if(is_valid) { if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min, &is_stale, &dos_header, endt_us) || + is_stale || dos_header.magic != PE_DOS_MAGIC) { is_valid = 0; @@ -1520,6 +1520,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN if(is_valid) { if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + dos_header.coff_file_offset, &is_stale, &pe_magic, endt_us) || + is_stale || pe_magic != PE_MAGIC) { is_valid = 0; @@ -1532,7 +1533,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN COFF_Header coff_header = {0}; if(is_valid) { - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + coff_header_off, &is_stale, &coff_header, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + coff_header_off, &is_stale, &coff_header, endt_us) || + is_stale) { is_valid = 0; is_good = 0; @@ -1680,6 +1682,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN if(read_vaddr + sizeof(inst) <= read_vaddr_opl) { inst_good = ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, inst, endt_us); + inst_good = inst_good && !is_stale; } if(!inst_good) { @@ -1761,7 +1764,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); } - if(!inst_byte_good) + if(!inst_byte_good || is_stale) { keep_parsing = 0; } @@ -1777,7 +1780,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { check_inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &check_inst_byte, endt_us); } - if(!check_inst_byte_good) + if(!check_inst_byte_good || is_stale) { keep_parsing = 0; } @@ -1813,7 +1816,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { imm_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us); } - if(!imm_good) + if(!imm_good || is_stale) { keep_parsing = 0; } @@ -1870,6 +1873,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: read next instruction byte U8 inst_byte = 0; is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && !is_stale; read_vaddr += 1; //- rjf: extract rex from instruction byte @@ -1878,6 +1882,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { rex = inst_byte & 0xF; // rex prefix is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && !is_stale; read_vaddr += 1; } @@ -1897,7 +1902,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read value at rsp U64 sp = regs->rsp.u64; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &sp, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &sp, endt_us) || + is_stale) { is_good = 0; break; @@ -1921,7 +1927,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read the 4-byte immediate S32 imm = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) { is_good = 0; break; @@ -1943,7 +1950,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read the 4-byte immediate S8 imm = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) { is_good = 0; break; @@ -1962,7 +1970,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { // rjf: read source register U8 modrm = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &modrm, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &modrm, endt_us) || + is_stale) { is_good = 0; break; @@ -1979,7 +1988,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN if((modrm >> 6) == 1) { S8 imm8 = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm8, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm8, endt_us) || + is_stale) { is_good = 0; break; @@ -1991,7 +2001,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read 4-byte immediate else { - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) { is_good = 0; break; @@ -2013,7 +2024,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us) || + is_stale) { is_good = 0; break; @@ -2021,7 +2033,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read 2-byte immediate & advance stack pointer U16 imm = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) { is_good = 0; break; @@ -2043,7 +2056,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us) || + is_stale) { is_good = 0; break; @@ -2089,7 +2103,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN { U64 unwind_info_off = first_pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us) || + is_stale) { is_good = 0; } @@ -2113,6 +2128,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 unwind_info_off = pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + good_unwind_info = good_unwind_info && !is_stale; PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), @@ -2173,7 +2189,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read value from stack pointer U64 rsp = regs->rsp.u64; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &rsp, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2234,7 +2251,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 off = code_ptr[1].u16*8; U64 addr = frame_base + off; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2252,7 +2270,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); U64 addr = frame_base + off; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2301,7 +2320,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U8 buf[16]; U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); U64 addr = frame_base + off; - if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us)) + if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2332,7 +2352,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN sp_adj += 8; } U64 ip_value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_adj, &is_stale, &ip_value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_adj, &is_stale, &ip_value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2340,7 +2361,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN } U64 sp_after_ip = sp_adj + 8; U16 ss_value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ip, &is_stale, &ss_value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ip, &is_stale, &ss_value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2348,7 +2370,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN } U64 sp_after_ss = sp_after_ip + 8; U64 rflags_value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2356,7 +2379,8 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN } U64 sp_after_rflags = sp_after_ss + 8; U64 sp_value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us)) + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us) || + is_stale) { keep_parsing = 0; is_good = 0; @@ -2485,6 +2509,9 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma } //- rjf: loop & unwind + CTRL_UnwindFrameNode *first_frame_node = 0; + CTRL_UnwindFrameNode *last_frame_node = 0; + U64 frame_node_count = 0; UNW_MemView memview = stack_memview; if(regs_block_good && stack_memview_good) { @@ -2510,12 +2537,12 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma } // rjf: valid step -> push frame - CTRL_UnwindFrame *frame = push_array(arena, CTRL_UnwindFrame, 1); - frame->rip = rip; + CTRL_UnwindFrameNode *frame_node = push_array(scratch.arena, CTRL_UnwindFrameNode, 1); + CTRL_UnwindFrame *frame = &frame_node->v; frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); MemoryCopy(frame->regs, regs_block, arch_reg_block_size); - DLLPushBack(unwind.first, unwind.last, frame); - unwind.count += 1; + DLLPushBack(first_frame_node, last_frame_node, frame_node); + frame_node_count += 1; // rjf: unwind one step CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, module, arch, regs_block, endt_us); @@ -2524,34 +2551,17 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma { break; } - - // rjf: unwind one step (OLD) -#if 0 - UNW_Step unwind_step = {0}; - switch(arch) - { - default:{unwind_step.dead = 1;}break; - case Architecture_x64: - { - unwind_step = unw_unwind_pe_x64(binary_data, &dbgi->pe, module_vaddr_range.min, &memview, (REGS_RegBlockX64 *)regs_block); - }break; - } - - // rjf: cancel on bad step - if(unwind_step.dead != 0) - { - break; - } - if(unwind_step.missed_read != 0) - { - unwind.error = 1; - break; - } - if(unwind_step.stack_pointer == 0) - { - break; - } -#endif + } + } + + //- rjf: bake frames list into result array + { + unwind.frames.count = frame_node_count; + unwind.frames.v = push_array(arena, CTRL_UnwindFrame, unwind.frames.count); + U64 idx = 0; + for(CTRL_UnwindFrameNode *n = first_frame_node; n != 0; n = n->next, idx += 1) + { + unwind.frames.v[idx] = n->v; } } @@ -4636,8 +4646,9 @@ ctrl_mem_stream_thread__entry_point(void *p) Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; - U64 mem_gen = dmn_mem_gen(); - if(got_task && mem_gen != preexisting_mem_gen) + U64 pre_read_mem_gen = dmn_mem_gen(); + U64 post_read_mem_gen = 0; + if(got_task && pre_read_mem_gen != preexisting_mem_gen) { range_size = dim_1u64(vaddr_range_clamped); U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, os_page_size()); @@ -4656,7 +4667,12 @@ ctrl_mem_stream_thread__entry_point(void *p) bytes_read = dmn_process_read(process, vaddr_range_clamped_retry, range_base); if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) { - vaddr_range_clamped_retry.max -= (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + vaddr_range_clamped_retry.max -= diff; + if(diff == 0) + { + break; + } } else { @@ -4687,6 +4703,7 @@ ctrl_mem_stream_thread__entry_point(void *p) } } } + post_read_mem_gen = dmn_mem_gen(); } //- rjf: read successful -> submit to hash store @@ -4712,7 +4729,10 @@ ctrl_mem_stream_thread__entry_point(void *p) if(!u128_match(u128_zero(), hash)) { range_n->hash = hash; - range_n->mem_gen = mem_gen; + } + if(!u128_match(u128_zero(), hash)) + { + range_n->mem_gen = post_read_mem_gen; } ins_atomic_u32_eval_assign(&range_n->is_taken, 0); goto commit__break_all; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index ec7bcecf..bef126e8 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -123,18 +123,28 @@ struct CTRL_UnwindStepResult typedef struct CTRL_UnwindFrame CTRL_UnwindFrame; struct CTRL_UnwindFrame { - CTRL_UnwindFrame *next; - CTRL_UnwindFrame *prev; - U64 rip; void *regs; }; +typedef struct CTRL_UnwindFrameNode CTRL_UnwindFrameNode; +struct CTRL_UnwindFrameNode +{ + CTRL_UnwindFrameNode *next; + CTRL_UnwindFrameNode *prev; + CTRL_UnwindFrame v; +}; + +typedef struct CTRL_UnwindFrameArray CTRL_UnwindFrameArray; +struct CTRL_UnwindFrameArray +{ + CTRL_UnwindFrame *v; + U64 count; +}; + typedef struct CTRL_Unwind CTRL_Unwind; struct CTRL_Unwind { - CTRL_UnwindFrame *first; - CTRL_UnwindFrame *last; - U64 count; + CTRL_UnwindFrameArray frames; CTRL_UnwindFlags flags; }; diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index a707e200..ba7e8cd9 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1535,9 +1535,10 @@ df_search_tags_from_entity(Arena *arena, DF_Entity *entity) DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); String8List strings = {0}; - for(CTRL_UnwindFrame *f = unwind.last; f != 0; f = f->prev) + for(U64 frame_num = unwind.frames.count; frame_num > 0; frame_num -= 1) { - U64 rip_vaddr = f->rip; + CTRL_UnwindFrame *f = &unwind.frames.v[frame_num-1]; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); DF_Entity *binary = df_binary_file_from_module(module); @@ -3672,9 +3673,9 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx]; for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + if(df_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0) { - n->unwind.first->rip = vaddr; + regs_arch_block_write_rip(thread->arch, n->unwind.frames.v[0].regs, vaddr); break; } } @@ -4084,17 +4085,10 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ U64 reg_size = regs_block_size_from_architecture(arch); U64 thread_unwind_ip_vaddr = 0; void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + if(unwind.frames.count != 0) { - U64 idx = 0; - for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) - { - if(idx == unwind_count) - { - thread_unwind_ip_vaddr = f->rip; - thread_unwind_regs_block = f->regs; - break; - } - } + thread_unwind_regs_block = unwind.frames.v[unwind_count%unwind.frames.count].regs; + thread_unwind_ip_vaddr = regs_rip_from_arch_block(arch, thread_unwind_regs_block); } //- rjf: unpack module info & produce eval machine @@ -4269,17 +4263,10 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ U64 type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); U64 reg_off = eval.offset; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - if(unwind.first != 0) + if(unwind.frames.count != 0) { - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) - { - if(unwind_idx == ctrl_ctx->unwind_count && frame->regs != 0) - { - MemoryCopy(&eval.imm_u128[0], ((U8 *)frame->regs + reg_off), Min(type_byte_size, sizeof(U64)*2)); - break; - } - } + CTRL_UnwindFrame *frame = &unwind.frames.v[ctrl_ctx->unwind_count%unwind.frames.count]; + MemoryCopy(&eval.imm_u128[0], ((U8 *)frame->regs + reg_off), Min(type_byte_size, sizeof(U64)*2)); } eval.mode = EVAL_EvalMode_Value; }break; @@ -4790,11 +4777,11 @@ df_commit_eval_value(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_ CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); Architecture arch = df_architecture_from_entity(thread); U64 reg_block_size = regs_block_size_from_architecture(arch); - if(unwind.first != 0 && + if(unwind.frames.count != 0 && (0 <= dst_eval.offset && dst_eval.offset+commit_data.size < reg_block_size)) { void *new_regs = push_array(scratch.arena, U8, reg_block_size); - MemoryCopy(new_regs, unwind.first->regs, reg_block_size); + MemoryCopy(new_regs, unwind.frames.v[0].regs, reg_block_size); MemoryCopy((U8 *)new_regs+dst_eval.offset, commit_data.str, commit_data.size); result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, new_regs); } @@ -6245,7 +6232,7 @@ df_query_cached_unwind_from_thread(DF_Entity *thread) else { result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - if(!(result.flags & CTRL_UnwindFlag_Error)) + if(!(result.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) { node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); SLLQueuePush_N(slot->first, slot->last, node, hash_next); @@ -6276,14 +6263,9 @@ df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) else { CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + if(unwind.frames.count != 0) { - if(unwind_idx == unwind_count) - { - result = frame->rip; - break; - } + result = regs_rip_from_arch_block(thread->arch, unwind.frames.v[unwind_count%unwind.frames.count].regs); } } return result; @@ -7436,9 +7418,9 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); // rjf: use first unwind frame to generate trap - if(unwind.first != 0 && unwind.first->next != 0) + if(unwind.frames.count > 1) { - U64 vaddr = unwind.first->next->rip; + U64 vaddr = regs_rip_from_arch_block(thread->arch, unwind.frames.v[1].regs); CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; ctrl_trap_list_push(scratch.arena, &traps, &trap); } @@ -7603,7 +7585,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) { DF_Entity *thread = df_entity_from_handle(df_state->ctrl_ctx.thread); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 max_unwind = unwind.count ? unwind.count-1 : 0; + U64 max_unwind = unwind.frames.count ? unwind.frames.count-1 : 0; U64 index = Clamp(0, params.index, max_unwind); df_state->ctrl_ctx.unwind_count = index; }break; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index eb993471..42f34332 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -3924,9 +3924,9 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); String8List lines = {0}; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + for(U64 frame_idx = 0; frame_idx < unwind.frames.count; frame_idx += 1) { - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[frame_idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); DF_Entity *binary = df_binary_file_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); @@ -9938,9 +9938,9 @@ df_entity_tooltips(DF_Entity *entity) ui_spacer(ui_em(1.5f, 1.f)); DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + for(U64 idx = 0; idx < unwind.frames.count; idx += 1) { - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); DF_Entity *binary = df_binary_file_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); @@ -10133,9 +10133,10 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam U64 idx = 0; U64 limit = 3; ui_spacer(ui_em(1.f, 1.f)); - for(CTRL_UnwindFrame *f = unwind.last; f != 0 && idx < limit; f = f->prev) + for(U64 num = unwind.frames.count; num > 0; num -= 1) { - U64 rip_vaddr = f->rip; + CTRL_UnwindFrame *f = &unwind.frames.v[num-1]; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); DF_Entity *binary = df_binary_file_from_module(module); diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 79ef4584..3cd448d9 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -888,19 +888,12 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); Architecture arch = df_architecture_from_entity(thread); U64 reg_size = regs_block_size_from_architecture(arch); - U64 thread_unwind_ip_vaddr = 0; void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + U64 thread_unwind_ip_vaddr = 0; + if(unwind.frames.count != 0) { - U64 idx = 0; - for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) - { - if(idx == unwind_count) - { - thread_unwind_ip_vaddr = f->rip; - thread_unwind_regs_block = f->regs; - break; - } - } + thread_unwind_regs_block = unwind.frames.v[unwind_count%unwind.frames.count].regs; + thread_unwind_ip_vaddr = regs_rip_from_arch_block(arch, thread_unwind_regs_block); } //- rjf: lex & parse @@ -4815,8 +4808,8 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) scroll_list_params.flags = UI_ScrollListFlag_All; scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); scroll_list_params.dim_px = dim_2f32(rect); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, unwind.count)); - scroll_list_params.item_range = r1s64(0, unwind.count+1); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, unwind.frames.count)); + scroll_list_params.item_range = r1s64(0, unwind.frames.count+1); scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; } UI_ScrollListSignal scroll_list_sig = {0}; @@ -4849,20 +4842,20 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) } //- rjf: frame rows - U64 frame_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, frame_idx += 1) + for(S64 row_num = visible_row_range.min; row_num <= visible_row_range.max && row_num <= unwind.frames.count; row_num += 1) { - // rjf: out of range -> skip (TODO(rjf): this should be an array...) - if(frame_idx+1 < visible_row_range.min || visible_row_range.max < frame_idx+1) + if(row_num == 0) { continue; } + U64 frame_idx = row_num-1; + CTRL_UnwindFrame *frame = &unwind.frames.v[frame_idx]; // rjf: determine selection - B32 row_selected = cs->cursor.y == ((S64)frame_idx+1); + B32 row_selected = (cs->cursor.y == row_num); // rjf: regs => rip - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, frame->regs); // rjf: rip_vaddr => module DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); @@ -8485,20 +8478,22 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); //- rjf: fill unwind frame annotations - if(unwind.first != 0) + if(unwind.frames.count != 0) { - U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); - for(CTRL_UnwindFrame *f = unwind.first->next; f != 0; f = f->next) + U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); + for(U64 idx = 1; idx < unwind.frames.count; idx += 1) { + CTRL_UnwindFrame *f = &unwind.frames.v[idx]; U64 f_stack_top = regs_rsp_from_arch_block(thread->arch, f->regs); Rng1U64 frame_vaddr_range = r1u64(last_stack_top, f_stack_top); Rng1U64 frame_vaddr_range_in_viz = intersect_1u64(frame_vaddr_range, viz_range_bytes); last_stack_top = f_stack_top; if(dim_1u64(frame_vaddr_range_in_viz) != 0) { - DF_Entity *module = df_module_from_process_vaddr(process, f->rip); + U64 f_rip = regs_rip_from_arch_block(thread->arch, f->regs); + DF_Entity *module = df_module_from_process_vaddr(process, f_rip); DF_Entity *binary = df_binary_file_from_module(module); - U64 rip_voff = df_voff_from_vaddr(module, f->rip); + U64 rip_voff = df_voff_from_vaddr(module, f_rip); String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); @@ -8515,10 +8510,10 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } //- rjf: fill selected thread stack range annotation - if(unwind.first != 0) + if(unwind.frames.count > 0) { U64 stack_base_vaddr = thread->stack_base; - U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); + U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); Rng1U64 stack_vaddr_range = r1u64(stack_base_vaddr, stack_top_vaddr); Rng1U64 stack_vaddr_range_in_viz = intersect_1u64(stack_vaddr_range, viz_range_bytes); if(dim_1u64(stack_vaddr_range_in_viz) != 0) diff --git a/src/regs/regs.c b/src/regs/regs.c index 028cd559..6d701480 100644 --- a/src/regs/regs.c +++ b/src/regs/regs.c @@ -13,7 +13,7 @@ internal U64 regs_rip_from_arch_block(Architecture arch, void *block) { U64 result = 0; - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rip.u64;}break; @@ -26,7 +26,7 @@ internal U64 regs_rsp_from_arch_block(Architecture arch, void *block) { U64 result = 0; - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rsp.u64;}break; @@ -38,7 +38,7 @@ regs_rsp_from_arch_block(Architecture arch, void *block) internal void regs_arch_block_write_rip(Architecture arch, void *block, U64 rip) { - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{((REGS_RegBlockX64 *)block)->rip.u64 = rip;}break; @@ -49,7 +49,7 @@ regs_arch_block_write_rip(Architecture arch, void *block, U64 rip) internal void regs_arch_block_write_rsp(Architecture arch, void *block, U64 rsp) { - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{((REGS_RegBlockX64 *)block)->rsp.u64 = rsp;}break; From 393fb9e5f2070a535ca4c0a9b269b6fffca82f96 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 17 May 2024 15:07:21 -0700 Subject: [PATCH 05/38] eliminate old unwinder usage code; more regression fixing --- build.bat | 2 +- src/ctrl/ctrl_core.c | 65 +++++++++++++++----------------------- src/raddbg/raddbg_main.cpp | 2 -- 3 files changed, 27 insertions(+), 42 deletions(-) diff --git a/build.bat b/build.bat index 08cf20fa..defffb0b 100644 --- a/build.bat +++ b/build.bat @@ -59,7 +59,7 @@ if "%clang%"=="1" set only_compile=-c if "%msvc%"=="1" set EHsc=/EHsc if "%clang%"=="1" set EHsc= if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO -if "%clang%"=="1" set no_aslr=/DYNAMICBASE:NO +if "%clang%"=="1" set no_aslr= if "%msvc%"=="1" set rc=rc.exe if "%clang%"=="1" set rc=llvm-rc.exe diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index f2c75cf2..a24a150f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1052,7 +1052,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: out of time? -> exit if(os_now_microseconds() >= endt_us) { - if(is_good && is_stale && out_is_stale) + if(is_stale && out_is_stale) { out_is_stale[0] = 1; } @@ -1902,7 +1902,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read value at rsp U64 sp = regs->rsp.u64; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &sp, endt_us) || + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &value, endt_us) || is_stale) { is_good = 0; @@ -2128,11 +2128,11 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 unwind_info_off = pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); - good_unwind_info = good_unwind_info && !is_stale; PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), &is_stale, unwind_codes, endt_us); + good_unwind_info = good_unwind_info && !is_stale; //- rjf: bad unwind info -> abort if(!good_unwind_info) @@ -2413,7 +2413,12 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; last_pdata = pdata; pdata = push_array(scratch.arena, PE_IntelPdata, 1); - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us); + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us) || + is_stale) + { + is_good = 0; + break; + } } } } @@ -2426,14 +2431,19 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN // rjf: read rip from stack pointer U64 rsp = regs->rsp.u64; U64 new_rip = 0; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &new_rip, endt_us); - - // rjf: advance stack pointer - U64 new_rsp = rsp + 8; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &new_rip, endt_us) || + is_stale) + { + is_good = 0; + } // rjf: commit registers - regs->rip.u64 = new_rip; - regs->rsp.u64 = new_rsp; + if(is_good) + { + U64 new_rsp = rsp + 8; + regs->rip.u64 = new_rip; + regs->rsp.u64 = new_rsp; + } } ////////////////////////////// @@ -2481,39 +2491,14 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma U64 arch_reg_block_size = regs_block_size_from_architecture(arch); //- rjf: grab initial register block - void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); - B32 regs_block_good = dmn_thread_read_reg_block(thread, regs_block); - - //- rjf: grab initial memory view - B32 stack_memview_good = 0; - UNW_MemView stack_memview = {0}; - { - U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); - U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); - U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); - U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); - U64 stack_size = stack_base - stack_top; - if(stack_base >= stack_top) - { - U8 *stack_memory_base = push_array(scratch.arena, U8, stack_size); - U64 actual_stack_bytes_read = dmn_process_read(process_entity->handle, r1u64(stack_top, stack_top+stack_size), stack_memory_base); - String8 stack_memory = str8(stack_memory_base, actual_stack_bytes_read); - if(stack_memory.size >= stack_size) - { - stack_memview_good = 1; - stack_memview.data = stack_memory.str; - stack_memview.addr_first = stack_top; - stack_memview.addr_opl = stack_base; - } - } - } + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); + B32 regs_block_good = (regs_block != 0); //- rjf: loop & unwind CTRL_UnwindFrameNode *first_frame_node = 0; CTRL_UnwindFrameNode *last_frame_node = 0; U64 frame_node_count = 0; - UNW_MemView memview = stack_memview; - if(regs_block_good && stack_memview_good) + if(arch != Architecture_Null && regs_block_good) { unwind.flags = 0; for(;;) @@ -2547,7 +2532,9 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma // rjf: unwind one step CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, module, arch, regs_block, endt_us); unwind.flags |= step.flags; - if(step.flags & CTRL_UnwindFlag_Error || regs_rsp_from_arch_block(arch, regs_block) == 0) + if(step.flags & CTRL_UnwindFlag_Error || + regs_rsp_from_arch_block(arch, regs_block) == 0 || + regs_rip_from_arch_block(arch, regs_block) == 0) { break; } diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index cd62a0f2..4400d628 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -49,7 +49,6 @@ #include "dbgi/dbgi.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" -#include "unwind/unwind.h" #include "ctrl/ctrl_inc.h" #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" @@ -88,7 +87,6 @@ #include "dbgi/dbgi.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" -#include "unwind/unwind.c" #include "ctrl/ctrl_inc.c" #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" From 2d1fcd7475e8df9e639eb6931a7029d55064bfa4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 08:23:41 -0700 Subject: [PATCH 06/38] fix some unwanted frontend unwind cache behavior; fix staleness calculation in ctrl process memory cache --- src/ctrl/ctrl_core.c | 37 +++++++++++++++++---- src/ctrl/ctrl_core.h | 3 ++ src/df/core/df_core.c | 77 ++++++++++++++++++++++++------------------- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index a24a150f..fb1cb63e 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -920,6 +920,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { U128 result = {0}; U64 size = dim_1u64(range); + U64 pre_mem_gen = dmn_mem_gen(); if(size != 0) for(;;) { CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; @@ -932,7 +933,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: try to read from cache B32 is_good = 0; - B32 is_stale = 0; + B32 is_stale = 1; OS_MutexScopeR(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) @@ -947,7 +948,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { result = range_n->hash; is_good = 1; - is_stale = (range_n->mem_gen != dmn_mem_gen()); + is_stale = (range_n->mem_gen != pre_mem_gen); goto read_cache__break_all; } } @@ -1065,6 +1066,11 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle break; } } + U64 post_mem_gen = dmn_mem_gen(); + if(post_mem_gen != pre_mem_gen && out_is_stale) + { + out_is_stale[0] = 1; + } return result; } @@ -1450,6 +1456,27 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: unwind deep copier + +internal CTRL_Unwind +ctrl_unwind_deep_copy(Arena *arena, Architecture arch, CTRL_Unwind *src) +{ + CTRL_Unwind dst = {0}; + { + dst.flags = src->flags; + dst.frames.count = src->frames.count; + dst.frames.v = push_array(arena, CTRL_UnwindFrame, dst.frames.count); + MemoryCopy(dst.frames.v, src->frames.v, sizeof(dst.frames.v[0])*dst.frames.count); + U64 block_size = regs_block_size_from_architecture(arch); + for(U64 idx = 0; idx < dst.frames.count; idx += 1) + { + dst.frames.v[idx].regs = push_array_no_zero(arena, U8, block_size); + MemoryCopy(dst.frames.v[idx].regs, src->frames.v[idx].regs, block_size); + } + } + return dst; +} + //- rjf: [x64] internal REGS_Reg64 * @@ -2480,7 +2507,6 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); CTRL_Unwind unwind = {0}; unwind.flags |= CTRL_UnwindFlag_Error; @@ -2492,13 +2518,13 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma //- rjf: grab initial register block void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); - B32 regs_block_good = (regs_block != 0); + B32 regs_block_good = (arch != Architecture_Null && regs_block != 0); //- rjf: loop & unwind CTRL_UnwindFrameNode *first_frame_node = 0; CTRL_UnwindFrameNode *last_frame_node = 0; U64 frame_node_count = 0; - if(arch != Architecture_Null && regs_block_good) + if(regs_block_good) { unwind.flags = 0; for(;;) @@ -2552,7 +2578,6 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma } } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); return unwind; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index bef126e8..e940c0eb 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -697,6 +697,9 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: unwind deep copier +internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Architecture arch, CTRL_Unwind *src); + //- rjf: [x64] internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, REGS_RegBlockX64 *regs, U64 endt_us); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index ba7e8cd9..9ed6b865 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6198,50 +6198,61 @@ df_push_active_target_list(Arena *arena) internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread) { + Temp scratch = scratch_begin(0, 0); CTRL_Unwind result = {0}; - DF_Handle handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&handle)); - for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) { - DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; - if(cache_idx == 0 && cache->slots_count == 0) + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) { - cache->slots_count = 1024; - cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); - } - else if(cache->slots_count == 0) - { - break; - } - U64 slot_idx = hash%cache->slots_count; - DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; - DF_RunUnwindCacheNode *node = 0; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) - { - if(df_handle_match(n->thread, handle)) + //- rjf: grab next recent cache + DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; + if(cache_idx == 0 && cache->slots_count == 0) + { + cache->slots_count = 1024; + cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); + } + else if(cache->slots_count == 0) { - node = n; break; } - } - if(node != 0) - { - result = node->unwind; - break; - } - else - { - result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - if(!(result.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) + + //- rjf: thread/hash -> node + U64 slot_idx = hash%cache->slots_count; + DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_RunUnwindCacheNode *node = 0; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { - node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->thread = handle; - node->unwind = result; + if(df_handle_match(n->thread, handle)) + { + node = n; + break; + } + } + + //- rjf: no node? -> calculate unwind if needed - store if good & return + if(node == 0) + { + CTRL_Unwind current_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + if(!(current_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) + { + Architecture arch = df_architecture_from_entity(thread); + node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->thread = handle; + node->unwind = ctrl_unwind_deep_copy(cache->arena, arch, ¤t_unwind); + } + } + + //- rjf: cached node -> grab result & return + if(node != 0) + { + result = node->unwind; break; } } } + scratch_end(scratch); return result; } From 9919ac59bb5136f3c128c036adc3b286907bbd97 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 10:58:45 -0700 Subject: [PATCH 07/38] move module image info parse / cache management to ctrl thread, directly tie to module lifetime as ctrl thread sees it; reduce load from each unwind --- src/ctrl/ctrl_core.c | 438 ++++++++++++++++++++++++++---------------- src/ctrl/ctrl_core.h | 49 +++++ src/df/core/df_core.c | 2 +- src/df/gfx/df_gfx.c | 13 +- 4 files changed, 330 insertions(+), 172 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index fb1cb63e..4bbe61d6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -845,6 +845,15 @@ ctrl_init(void) ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); } + ctrl_state->module_image_info_cache.slots_count = 1024; + ctrl_state->module_image_info_cache.slots = push_array(arena, CTRL_ModuleImageInfoCacheSlot, ctrl_state->module_image_info_cache.slots_count); + ctrl_state->module_image_info_cache.stripes_count = os_logical_core_count(); + ctrl_state->module_image_info_cache.stripes = push_array(arena, CTRL_ModuleImageInfoCacheStripe, ctrl_state->module_image_info_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->module_image_info_cache.stripes_count; idx += 1) + { + ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc(); + ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + } ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -1453,6 +1462,78 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * return good; } +//////////////////////////////// +//~ rjf: Module Image Info Functions + +//- rjf: cache lookups + +internal PE_IntelPdata * +ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff) +{ + PE_IntelPdata *first_pdata = 0; + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + PE_IntelPdata *pdatas = n->pdatas; + U64 pdatas_count = n->pdatas_count; + if(n->pdatas_count != 0 && voff >= n->pdatas[0].voff_first) + { + // NOTE(rjf): + // + // binary search: + // find max index s.t. pdata_array[index].voff_first <= voff + // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) + U64 index = pdatas_count; + U64 min = 0; + U64 opl = pdatas_count; + for(;;) + { + U64 mid = (min + opl)/2; + PE_IntelPdata *pdata = pdatas + mid; + if(voff < pdata->voff_first) + { + opl = mid; + } + else if(pdata->voff_first < voff) + { + min = mid; + } + else + { + index = mid; + break; + } + if(min + 1 >= opl) + { + index = min; + break; + } + } + + // rjf: if we are in range fill result + { + PE_IntelPdata *pdata = pdatas + index; + if(pdata->voff_first <= voff && voff < pdata->voff_one_past_last) + { + first_pdata = push_array(arena, PE_IntelPdata, 1); + MemoryCopyStruct(first_pdata, pdata); + } + } + } + break; + } + } + } + return first_pdata; +} + //////////////////////////////// //~ rjf: Unwinding Functions @@ -1521,169 +1602,9 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN U64 rip_voff = regs->rip.u64 - module->vaddr_range.min; ////////////////////////////// - //- rjf: unpack relevant PE info + //- rjf: rip_voff -> first pdata // - PE_IntelPdata *pdatas = 0; - U64 pdatas_count = 0; - ProfScope("unpack relevant PE info") if(module != &ctrl_entity_nil) - { - B32 is_valid = 1; - - //- rjf: read DOS header - PE_DosHeader dos_header = {0}; - if(is_valid) - { - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min, &is_stale, &dos_header, endt_us) || - is_stale || - dos_header.magic != PE_DOS_MAGIC) - { - is_valid = 0; - is_good = 0; - } - } - - //- rjf: read PE magic - U32 pe_magic = 0; - if(is_valid) - { - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + dos_header.coff_file_offset, &is_stale, &pe_magic, endt_us) || - is_stale || - pe_magic != PE_MAGIC) - { - is_valid = 0; - is_good = 0; - } - } - - //- rjf: read COFF header - U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); - COFF_Header coff_header = {0}; - if(is_valid) - { - if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + coff_header_off, &is_stale, &coff_header, endt_us) || - is_stale) - { - is_valid = 0; - is_good = 0; - } - } - - //- rjf: unpack range of optional extension header - U32 opt_ext_size = coff_header.optional_header_size; - Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), - coff_header_off + sizeof(coff_header) + opt_ext_size); - - //- rjf: read optional header - U16 optional_magic = 0; - U64 image_base = 0; - U64 entry_point = 0; - U32 data_dir_count = 0; - U64 virt_section_align = 0; - U64 file_section_align = 0; - Rng1U64 *data_dir_franges = 0; - if(opt_ext_size > 0) - { - // rjf: read magic number - U16 opt_ext_magic = 0; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &opt_ext_magic, endt_us); - - // rjf: read info - U32 reported_data_dir_offset = 0; - U32 reported_data_dir_count = 0; - switch(opt_ext_magic) - { - case PE_PE32_MAGIC: - { - PE_OptionalHeader32 pe_optional = {0}; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &pe_optional, endt_us); - image_base = pe_optional.image_base; - entry_point = pe_optional.entry_point_va; - virt_section_align = pe_optional.section_alignment; - file_section_align = pe_optional.file_alignment; - reported_data_dir_offset = sizeof(pe_optional); - reported_data_dir_count = pe_optional.data_dir_count; - }break; - case PE_PE32PLUS_MAGIC: - { - PE_OptionalHeader32Plus pe_optional = {0}; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min, &is_stale, &pe_optional, endt_us); - image_base = pe_optional.image_base; - entry_point = pe_optional.entry_point_va; - virt_section_align = pe_optional.section_alignment; - file_section_align = pe_optional.file_alignment; - reported_data_dir_offset = sizeof(pe_optional); - reported_data_dir_count = pe_optional.data_dir_count; - }break; - } - - // rjf: find number of data directories - U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); - data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); - - // rjf: grab pdatas from exceptions section - if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS) - { - PE_DataDirectory dir = {0}; - ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &is_stale, &dir, endt_us); - Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); - pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); - pdatas = push_array(scratch.arena, PE_IntelPdata, pdatas_count); - ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min + pdatas_voff_range.min, module->vaddr_range.min + pdatas_voff_range.max), &is_stale, pdatas, endt_us); - } - } - } - - ////////////////////////////// - //- rjf: find current rip's pdata entry - // - PE_IntelPdata *first_pdata = 0; - if(pdatas_count != 0) ProfScope("find current RIP's pdata entry") - { - U64 first_pdata_voff = 0; - if(rip_voff >= pdatas[0].voff_first) - { - // NOTE(rjf): - // - // binary search: - // find max index s.t. pdata_array[index].voff_first <= voff - // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) - U64 index = pdatas_count; - U64 min = 0; - U64 opl = pdatas_count; - for(;;) - { - U64 mid = (min + opl)/2; - PE_IntelPdata *pdata = pdatas + mid; - if(rip_voff < pdata->voff_first) - { - opl = mid; - } - else if(pdata->voff_first < rip_voff) - { - min = mid; - } - else - { - index = mid; - break; - } - if(min + 1 >= opl) - { - index = min; - break; - } - } - - // rjf: if we are in range fill result - { - PE_IntelPdata *pdata = pdatas + index; - if(pdata->voff_first <= rip_voff && rip_voff < pdata->voff_one_past_last) - { - first_pdata = pdata; - } - } - } - } + PE_IntelPdata *first_pdata = ctrl_intel_pdata_from_module_voff(scratch.arena, machine_id, module_handle, rip_voff); ////////////////////////////// //- rjf: pdata -> detect if in epilog @@ -2955,6 +2876,195 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID } } +//- rjf: module lifetime open/close work + +internal void +ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path) +{ + ////////////////////////////// + //- rjf: open debug info + // + dbgi_binary_open(path); + + ////////////////////////////// + //- rjf: parse module image info + // + Arena *arena = arena_alloc(); + PE_IntelPdata *pdatas = 0; + U64 pdatas_count = 0; + ProfScope("unpack relevant PE info") + { + B32 is_valid = 1; + + //- rjf: read DOS header + PE_DosHeader dos_header = {0}; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min, &dos_header) || + dos_header.magic != PE_DOS_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read PE magic + U32 pe_magic = 0; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min + dos_header.coff_file_offset, &pe_magic) || + pe_magic != PE_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read COFF header + U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_Header coff_header = {0}; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min + coff_header_off, &coff_header)) + { + is_valid = 0; + } + } + + //- rjf: unpack range of optional extension header + U32 opt_ext_size = coff_header.optional_header_size; + Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), + coff_header_off + sizeof(coff_header) + opt_ext_size); + + //- rjf: read optional header + U16 optional_magic = 0; + U64 image_base = 0; + U64 entry_point = 0; + U32 data_dir_count = 0; + U64 virt_section_align = 0; + U64 file_section_align = 0; + Rng1U64 *data_dir_franges = 0; + if(opt_ext_size > 0) + { + // rjf: read magic number + U16 opt_ext_magic = 0; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &opt_ext_magic); + + // rjf: read info + U32 reported_data_dir_offset = 0; + U32 reported_data_dir_count = 0; + switch(opt_ext_magic) + { + case PE_PE32_MAGIC: + { + PE_OptionalHeader32 pe_optional = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + case PE_PE32PLUS_MAGIC: + { + PE_OptionalHeader32Plus pe_optional = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + } + + // rjf: find number of data directories + U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); + data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + + // rjf: grab pdatas from exceptions section + if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS) + { + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &dir); + Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); + pdatas = push_array(arena, PE_IntelPdata, pdatas_count); + dmn_process_read(process, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas); + } + } + } + + ////////////////////////////// + //- rjf: insert into cache + // + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + CTRL_ModuleImageInfoCacheNode *node = 0; + for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module)) + { + node = n; + break; + } + } + if(!node) + { + node = push_array(arena, CTRL_ModuleImageInfoCacheNode, 1); + DLLPushBack(slot->first, slot->last, node); + node->machine_id = machine_id; + node->module = module; + node->arena = arena; + node->pdatas = pdatas; + node->pdatas_count = pdatas_count; + } + } + } +} + +internal void +ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 path) +{ + ////////////////////////////// + //- rjf: evict module image info from cache + // + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + CTRL_ModuleImageInfoCacheNode *node = 0; + for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module)) + { + node = n; + break; + } + } + if(node) + { + DLLRemove(slot->first, slot->last, node); + arena_release(node->arena); + } + } + } + + ////////////////////////////// + //- rjf: close debug info + // + dbgi_binary_close(path); +} + //- rjf: attached process running/event gathering internal DMN_Event * @@ -3220,7 +3330,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; - dbgi_binary_open(module_path); + ctrl_thread__module_open(CTRL_MachineID_Local, event->process, event->module, r1u64(event->address, event->address+event->size), module_path); out_evt->kind = CTRL_EventKind_NewModule; out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; @@ -3255,7 +3365,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; - dbgi_binary_close(module_path); + ctrl_thread__module_close(CTRL_MachineID_Local, event->module, module_path); out_evt->kind = CTRL_EventKind_EndModule; out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index e940c0eb..b5d0d281 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -497,6 +497,44 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; +//////////////////////////////// +//~ rjf: Module Image Info Cache Types + +typedef struct CTRL_ModuleImageInfoCacheNode CTRL_ModuleImageInfoCacheNode; +struct CTRL_ModuleImageInfoCacheNode +{ + CTRL_ModuleImageInfoCacheNode *next; + CTRL_ModuleImageInfoCacheNode *prev; + CTRL_MachineID machine_id; + DMN_Handle module; + Arena *arena; + PE_IntelPdata *pdatas; + U64 pdatas_count; +}; + +typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; +struct CTRL_ModuleImageInfoCacheSlot +{ + CTRL_ModuleImageInfoCacheNode *first; + CTRL_ModuleImageInfoCacheNode *last; +}; + +typedef struct CTRL_ModuleImageInfoCacheStripe CTRL_ModuleImageInfoCacheStripe; +struct CTRL_ModuleImageInfoCacheStripe +{ + Arena *arena; + OS_Handle rw_mutex; +}; + +typedef struct CTRL_ModuleImageInfoCache CTRL_ModuleImageInfoCache; +struct CTRL_ModuleImageInfoCache +{ + U64 slots_count; + CTRL_ModuleImageInfoCacheSlot *slots; + U64 stripes_count; + CTRL_ModuleImageInfoCacheStripe *stripes; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -519,6 +557,7 @@ struct CTRL_State // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; + CTRL_ModuleImageInfoCache module_image_info_cache; // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; @@ -694,6 +733,12 @@ internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_Mac //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); +//////////////////////////////// +//~ rjf: Module Image Info Functions + +//- rjf: cache lookups +internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff); + //////////////////////////////// //~ rjf: Unwinding Functions @@ -745,6 +790,10 @@ internal void ctrl_thread__entry_point(void *p); internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +//- rjf: module lifetime open/close work +internal void ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path); +internal void ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 path); + //- rjf: attached process running/event gathering internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 9ed6b865..c9ed1bf1 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6233,7 +6233,7 @@ df_query_cached_unwind_from_thread(DF_Entity *thread) //- rjf: no node? -> calculate unwind if needed - store if good & return if(node == 0) { - CTRL_Unwind current_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + CTRL_Unwind current_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+200); if(!(current_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) { Architecture arch = df_architecture_from_entity(thread); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 42f34332..04a5edbc 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -10059,13 +10059,12 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam ui_set_next_background_color(bg_color); } ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Key key = ui_key_from_stringf(ui_top_parent()->key, "entity_ref_button_%p", entity); - UI_Box *box = ui_build_box_from_key(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - key); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "entity_ref_button_%p", entity); //- rjf: build contents UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 0)) From 5342fab86ba47f11f4a07bf7be3fb8ae8a602b33 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 11:12:29 -0700 Subject: [PATCH 08/38] bugfix in new unwinder; applying stack ptr read & unwind when doing epilog unwinds --- src/ctrl/ctrl_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 4bbe61d6..0e7ce246 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -2374,7 +2374,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN ////////////////////////////// //- rjf: no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer // - if(!first_pdata || !xdata_unwind_did_machframe) ProfScope("no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer") + if(!first_pdata || (!has_pdata_and_in_epilog && !xdata_unwind_did_machframe)) ProfScope("no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer") { // rjf: read rip from stack pointer U64 rsp = regs->rsp.u64; From fd6befecc31fd0fe4fe236866e5f8b07358a7469 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 12:55:20 -0700 Subject: [PATCH 09/38] get tls address calculation off of binary parsing path; do based on in-process memory --- src/ctrl/ctrl_core.c | 79 ++++++++++++++++++++++++++++++++++++++++++- src/ctrl/ctrl_core.h | 4 +++ src/df/core/df_core.c | 20 ++++------- src/raddbg/raddbg.h | 9 ++--- 4 files changed, 92 insertions(+), 20 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 0e7ce246..9a3a4fed 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1534,6 +1534,46 @@ ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_H return first_pdata; } +internal U64 +ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + U64 result = 0; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->entry_point_voff; + break; + } + } + return result; +} + +internal Rng1U64 +ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + Rng1U64 result = {0}; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->tls_vaddr_range; + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Unwinding Functions @@ -2892,6 +2932,8 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand Arena *arena = arena_alloc(); PE_IntelPdata *pdatas = 0; U64 pdatas_count = 0; + U64 entry_point_voff = 0; + Rng1U64 tls_vaddr_range = {0}; ProfScope("unpack relevant PE info") { B32 is_valid = 1; @@ -2991,6 +3033,40 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand pdatas = push_array(arena, PE_IntelPdata, pdatas_count); dmn_process_read(process, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas); } + + // rjf: extract tls header + PE_TLSHeader64 tls_header = {0}; + if(data_dir_count > PE_DataDirectoryIndex_TLS) + { + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir); + Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + switch(coff_header.machine) + { + default:{}break; + case COFF_MachineType_X86: + { + PE_TLSHeader32 tls_header32 = {0}; + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header32); + tls_header.raw_data_start = (U64)tls_header32.raw_data_start; + tls_header.raw_data_end = (U64)tls_header32.raw_data_end; + tls_header.index_address = (U64)tls_header32.index_address; + tls_header.callbacks_address = (U64)tls_header32.callbacks_address; + tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; + tls_header.characteristics = (U64)tls_header32.characteristics; + }break; + case COFF_MachineType_X64: + { + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header); + }break; + } + } + + // rjf: grab entry point vaddr + entry_point_voff = entry_point; + + // rjf: calculate TLS vaddr range + tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32)); } } @@ -3023,6 +3099,7 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand node->arena = arena; node->pdatas = pdatas; node->pdatas_count = pdatas_count; + node->entry_point_voff = entry_point_voff; } } } @@ -4076,7 +4153,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: add trap for PE header entry if(!entries_found) { - U64 voff = dbgi->pe.entry_point; + U64 voff = ctrl_entry_point_voff_from_module(CTRL_MachineID_Local, module->handle); if(voff != 0) { DMN_Trap trap = {process->handle, module_base_vaddr + voff}; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b5d0d281..854dfc26 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -510,6 +510,8 @@ struct CTRL_ModuleImageInfoCacheNode Arena *arena; PE_IntelPdata *pdatas; U64 pdatas_count; + U64 entry_point_voff; + Rng1U64 tls_vaddr_range; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -738,6 +740,8 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //- rjf: cache lookups internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff); +internal U64 ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); +internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); //////////////////////////////// //~ rjf: Unwinding Functions diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index c9ed1bf1..412ad503 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3541,20 +3541,14 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 DBGI_Scope *scope = dbgi_scope_open(); if(!df_ctrl_targets_running()) { - //- rjf: unpack thread info + //- rjf: unpack module info DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - PE_BinInfo *bin = &dbgi->pe; - B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF - U64 addr_size = bit_size_from_arch(bin->arch)/8; - - //- rjf: grab tls range - Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); + Rng1U64 tls_vaddr_range = ctrl_tls_vaddr_range_from_module(module->ctrl_machine_id, module->ctrl_handle); + U64 addr_size = bit_size_from_arch(process->arch)/8; //- rjf: read module's TLS index U64 tls_index = 0; + if(addr_size != 0) { CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); if(tls_index_slice.data.size >= addr_size) @@ -3564,7 +3558,7 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: PE path - if(bin_is_pe) + if(addr_size != 0) { U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; @@ -3584,10 +3578,10 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: non-PE path (not implemented) +#if 0 if(!bin_is_pe) { // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: -#if 0 // TODO(nick): This code works only if the linked c runtime library is glibc. // Implement CRT detection here. @@ -3614,8 +3608,8 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 { demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); } -#endif } +#endif } dbgi_scope_close(scope); scratch_end(scratch); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 1e7a1ce1..f2c4511f 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -52,15 +52,10 @@ // since that's not normally how Windows fonts work. //////////////////////////////// -//~ rjf: Demon/Cleanup Pass Tasks +//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // -// [ ] TLS eval -> in-process-memory EXE info -// [ ] unwinding -> in-process-memory EXE info // [ ] "root" concept in hash store, which buckets keys & allows usage code to // jettison a collection of keys in retained mode fashion - -//////////////////////////////// -//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // // [ ] Jeff Notes // [ ] highlighted text & ctrl+f -> auto-fill search query @@ -379,6 +374,8 @@ // function was displayed in the window by default next to the thread. // [x] ** It would be nice if thread listings displayed the name of the // thread, instead of just the ID. +// [x] TLS eval -> in-process-memory EXE info +// [x] unwinding -> in-process-memory EXE info #ifndef RADDBG_H #define RADDBG_H From 49eb834e2b104575011a9e827f9956393a4ba9a2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 12:58:02 -0700 Subject: [PATCH 10/38] eliminate old unwind code --- src/unwind/unwind.c | 859 -------------------------------------------- src/unwind/unwind.h | 62 ---- 2 files changed, 921 deletions(-) delete mode 100644 src/unwind/unwind.c delete mode 100644 src/unwind/unwind.h diff --git a/src/unwind/unwind.c b/src/unwind/unwind.c deleted file mode 100644 index f0d6916e..00000000 --- a/src/unwind/unwind.c +++ /dev/null @@ -1,859 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Memory View Helpers - -internal UNW_MemView -unw_memview_from_data(String8 data, U64 base_vaddr) -{ - UNW_MemView result = {0}; - result.data = data.str; - result.addr_first = base_vaddr; - result.addr_opl = base_vaddr + data.size; - return result; -} - -internal B32 -unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out) -{ - B32 result = 0; - if(memview->addr_first <= addr && addr + size <= memview->addr_opl) - { - MemoryCopy(out, (U8*)memview->data + addr - memview->addr_first, size); - result = 1; - } - return result; -} - -//////////////////////////////// -//~ rjf: PE/X64 Unwind Implementation - -//- rjf: helpers - -internal UNW_Step -unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView*memview, REGS_RegBlockX64 *regs) -{ - UNW_Step result = {0}; - U64 missed_read_addr = 0; - - //- setup parsing context - U64 ip_voff = regs->rip.u64 - base_vaddr; - U64 sec_number = pe_section_num_from_voff(bindata, bin, ip_voff); - COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); - void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); - U64 inst_size = sec->vsize; - - //- setup parsing variables - B32 keep_parsing = 1; - U64 off = ip_voff - sec->voff; - - - //- parsing loop - for(;keep_parsing;) - { - keep_parsing = 0; - - U8 inst_byte = 0; - if(off + sizeof(inst_byte) <= inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - off += 1; - - U8 rex = 0; - if((inst_byte & 0xF0) == 0x40) - { - rex = inst_byte & 0xF; // rex prefix - if(off + sizeof(inst_base) <= inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - off += 1; - } - - switch(inst_byte) - { - // pop - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - { - U64 sp = regs->rsp.u64; - U64 value = 0; - if(!unw_memview_read_struct(memview, sp, &value)) - { - missed_read_addr = sp; - goto error_out; - } - - // modify register - PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); - - // not a final instruction - keep_parsing = 1; - - // commit registers - reg->u64 = value; - regs->rsp.u64 = sp + 8; - }break; - - // add $nnnn,%rsp - case 0x81: - { - // skip one byte (we already know what it is in this scenario) - off += 1; - - // read the 4-byte immediate - S32 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 4; - - // not a final instruction - keep_parsing = 1; - - // update stack pointer - regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); - }break; - - // add $n,%rsp - case 0x83: - { - // skip one byte (we already know what it is in this scenario) - off += 1; - - // read the 1-byte immediate - S8 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 1; - - // update stack pointer - regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); - keep_parsing = 1; - }break; - - // lea imm8/imm32,$rsp - case 0x8D: - { - // read source register - U8 modrm = 0; - if(off + sizeof(modrm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&modrm, ptr, sizeof(modrm)); - } - PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8; - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); - U64 reg_value = reg->u64; - - // advance to the immediate - off += 1; - - S32 imm = 0; - // read 1-byte immediate - if((modrm >> 6) == 1) - { - S8 imm8 = 0; - if(off + sizeof(imm8) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm8, ptr, sizeof(imm8)); - } - imm = imm8; - off += 1; - } - - // read 4-byte immediate - else - { - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 4; - } - - regs->rsp.u64 = (U64)(reg_value + imm); - keep_parsing = 1; - }break; - - // ret $nn - case 0xC2: - { - // read new ip - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // read 2-byte immediate & advance stack pointer - U16 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - U64 new_sp = sp + 8 + imm; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - }break; - - // ret / rep; ret - case 0xF3: - { - Assert(!"Hit me!"); - } - case 0xC3: - { - // read new ip - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - }break; - - // jmp nnnn - case 0xE9: - { - Assert(!"Hit Me"); - // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done - // we don't have any cases to exercise this right now. no guess implementation! - }break; - - // jmp n - case 0xEB: - { - Assert(!"Hit Me"); - // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done - // we don't have any cases to exercise this right now. no guess implementation! - }break; - } - - } - - error_out:; - - if(missed_read_addr != 0) - { - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - return(result); -} - -internal B32 -unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata) -{ - // NOTE(allen): There are restrictions placed on how an epilog is allowed - // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) - // Here we interpret machine code directly according to the rules - // given there to determine if the code we're looking at looks like an epilog. - - // TODO(allen): Figure out how to verify this. - - //- setup parsing context - U64 sec_number = pe_section_num_from_voff(bindata, bin, voff); - COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); - void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); - U64 inst_size = sec->vsize; - - //- setup parsing variables - B32 is_epilog = 0; - B32 keep_parsing = 1; - U64 off = voff - sec->voff; - - //- check first instruction - { - B32 inst_read_success = 0; - U8 inst[4]; - if (off + sizeof(inst) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst, ptr, sizeof(inst)); - inst_read_success = 1; - } - - if (!inst_read_success){ - keep_parsing = 0; - } - else{ - if ((inst[0] & 0xF8) == 0x48){ - switch (inst[1]){ - // add $nnnn,%rsp - case 0x81: - { - if (inst[0] == 0x48 && inst[2] == 0xC4){ - off += 7; - } - else{ - keep_parsing = 0; - } - }break; - - // add $n,%rsp - case 0x83: - { - if (inst[0] == 0x48 && inst[2] == 0xC4){ - off += 4; - } - else{ - keep_parsing = 0; - } - }break; - - // lea n(reg),%rsp - case 0x8D: - { - if ((inst[0] & 0x06) == 0 && - ((inst[2] >> 3) & 0x07) == 0x04 && - (inst[2] & 0x07) != 0x04){ - U8 imm_size = (inst[2] >> 6); - // 1-byte immediate - if (imm_size == 1){ - off += 4; - } - // 4-byte immediate - else if (imm_size == 2){ - off += 7; - } - else{ - keep_parsing = 0; - } - } - else{ - keep_parsing = 0; - } - }break; - } - } - } - } - - //- parsing loop - if (keep_parsing){ - for (;;){ - // read inst - U8 inst_byte = 0; - if (off + sizeof(inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - else{ - goto loop_break; - } - - // when (... I don't know ...) rely on the next byte - U64 check_off = off; - U8 check_inst_byte = inst_byte; - if ((inst_byte & 0xF0) == 0x40){ - check_off = off + 1; - if (off + sizeof(check_inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&check_inst_byte, ptr, sizeof(check_inst_byte)); - } - else{ - goto loop_break; - } - } - - switch (check_inst_byte){ - // pop - case 0x58:case 0x59:case 0x5A:case 0x5B: - case 0x5C:case 0x5D:case 0x5E:case 0x5F: - { - off = check_off + 1; - }break; - - // ret - case 0xC2:case 0xC3: - { - is_epilog = 1; - goto loop_break; - }break; - - // jmp nnnn - case 0xE9: - { - U64 imm_off = check_off + 1; - S32 imm = 0; - if (off + sizeof(imm) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - else{ - goto loop_break; - } - - U64 next_off = (U64)(imm_off + sizeof(imm) + imm); - if (!(final_pdata->voff_first <= next_off && next_off < final_pdata->voff_one_past_last)){ - goto loop_break; - } - - off = next_off; - // TODO(allen): why isn't this just the end of the epilog? - }break; - - // rep; ret (for amd64 prediction bug) - case 0xF3: - { - U8 next_inst_byte = 0; - if (off + sizeof(next_inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&next_inst_byte, ptr, sizeof(next_inst_byte)); - } - is_epilog = (next_inst_byte == 0xC3); - goto loop_break; - }break; - - default: goto loop_break; - } - } - - loop_break:; - } - - //- fill result - B32 result = is_epilog; - return(result); -} - -internal REGS_Reg64* -unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg){ - static REGS_Reg64 dummy = {0}; - REGS_Reg64 *result = &dummy; - switch (unw_reg){ - case PE_UnwindGprRegX64_RAX: result = ®s->rax; break; - case PE_UnwindGprRegX64_RCX: result = ®s->rcx; break; - case PE_UnwindGprRegX64_RDX: result = ®s->rdx; break; - case PE_UnwindGprRegX64_RBX: result = ®s->rbx; break; - case PE_UnwindGprRegX64_RSP: result = ®s->rsp; break; - case PE_UnwindGprRegX64_RBP: result = ®s->rbp; break; - case PE_UnwindGprRegX64_RSI: result = ®s->rsi; break; - case PE_UnwindGprRegX64_RDI: result = ®s->rdi; break; - case PE_UnwindGprRegX64_R8 : result = ®s->r8 ; break; - case PE_UnwindGprRegX64_R9 : result = ®s->r9 ; break; - case PE_UnwindGprRegX64_R10: result = ®s->r10; break; - case PE_UnwindGprRegX64_R11: result = ®s->r11; break; - case PE_UnwindGprRegX64_R12: result = ®s->r12; break; - case PE_UnwindGprRegX64_R13: result = ®s->r13; break; - case PE_UnwindGprRegX64_R14: result = ®s->r14; break; - case PE_UnwindGprRegX64_R15: result = ®s->r15; break; - } - return(result); -} - -//- rjf: unwind step - -internal UNW_Step -unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs) -{ - UNW_Step result = {0}; - U64 missed_read_addr = 0; - - //- grab ip_voff (several places can use this) - U64 ip_voff = regs->rip.u64 - base_vaddr; - - //- get pdata entry from current ip - PE_IntelPdata *initial_pdata = 0; - { - U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); - if(initial_pdata_off != 0) - { - initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); - } - } - - //- no pdata; unwind by reading stack pointer - if(initial_pdata == 0) - { - // read ip from stack pointer - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - //- got pdata; perform unwinding with exception handling - else - { - // try epilog unwind - B32 did_epilog_unwind = 0; - if(unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)) - { - result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); - did_epilog_unwind = 1; - } - - // try xdata unwind - if(!did_epilog_unwind) - { - B32 did_machframe = 0; - - // get frame reg - REGS_Reg64 *frame_reg = 0; - U64 frame_off = 0; - - { - U64 unwind_info_off = initial_pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - - U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info->frame); - U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info->frame); - - if (frame_reg_id != 0){ - frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); - // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. - } - frame_off = frame_off_val; - } - - PE_IntelPdata *last_pdata = 0; - PE_IntelPdata *pdata = initial_pdata; - for (;pdata != last_pdata;) - { - //- rjf: unpack unwind info & codes - U64 unwind_info_off = pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - PE_UnwindCode *unwind_codes = (PE_UnwindCode*)(unwind_info + 1); - - //- rjf: unpack frame base - U64 frame_base = regs->rsp.u64; - if(frame_reg != 0) - { - U64 raw_frame_base = frame_reg->u64; - U64 adjusted_frame_base = raw_frame_base - frame_off*16; - if(adjusted_frame_base < raw_frame_base) - { - frame_base = adjusted_frame_base; - } - else - { - frame_base = 0; - } - } - - //- rjf: bad unwind info -> abort - if(unwind_info == 0) - { - result.dead = 1; - goto error_out; - } - - //- op code interpreter - PE_UnwindCode *code_ptr = unwind_codes; - PE_UnwindCode *code_opl = unwind_codes + unwind_info->codes_num; - for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) - { - // extract op code parts - U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); - U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); - - // determine number of op code slots - U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); - if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) - { - slot_count += 1; - } - - // check op code slot count - if (slot_count == 0 || code_ptr + slot_count > code_opl){ - result.dead = 1; - goto end_xdata_unwind; - } - - // set next op code pointer - next_code_ptr = code_ptr + slot_count; - - // interpret this op code - U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; - if (code_voff <= ip_voff){ - switch (op_code){ - case PE_UnwindOpCode_PUSH_NONVOL: - { - // read value from stack pointer - U64 sp = regs->rsp.u64; - U64 value = 0; - if(!unw_memview_read_struct(memview, sp, &value)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_LARGE: - { - // read alloc size - U64 size = 0; - if (op_info == 0){ - size = code_ptr[1].u16*8; - } - else if (op_info == 1){ - size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - } - else{ - result.dead = 1; - goto end_xdata_unwind; - } - - // advance stack pointer - U64 sp = regs->rsp.u64; - U64 new_sp = sp + size; - - // advance stack pointer - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_SMALL: - { - // advance stack pointer - regs->rsp.u64 += op_info*8 + 8; - }break; - - case PE_UnwindOpCode_SET_FPREG: - { - // put stack pointer back to the frame base - regs->rsp.u64 = frame_base; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL: - { - // read value from frame base - U64 off = code_ptr[1].u16*8; - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL_FAR: - { - // read value from frame base - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_EPILOG: - { - result.dead = 1; - }break; - - case PE_UnwindOpCode_SPARE_CODE: - { - result.dead = 1; - // Assert(!"Hit me!"); - // TODO(allen): ??? - }break; - - case PE_UnwindOpCode_SAVE_XMM128: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16*16; - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_SAVE_XMM128_FAR: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_PUSH_MACHFRAME: - { - // NOTE(rjf): this was found by stepping through kernel code after an exception was - // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main - - if(op_info > 1) - { - result.dead = 1; - goto end_xdata_unwind; - } - - // read values - U64 sp_og = regs->rsp.u64; - U64 sp_adj = sp_og; - if(op_info == 1) - { - sp_adj += 8; - } - - U64 ip_value = 0; - if(!unw_memview_read_struct(memview, sp_adj, &ip_value)) - { - missed_read_addr = sp_adj; - goto error_out; - } - - U64 sp_after_ip = sp_adj + 8; - U16 ss_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ip, &ss_value)) - { - missed_read_addr = sp_after_ip; - goto error_out; - } - - U64 sp_after_ss = sp_after_ip + 8; - U64 rflags_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)) - { - missed_read_addr = sp_after_ss; - goto error_out; - } - - U64 sp_after_rflags = sp_after_ss + 8; - U64 sp_value = 0; - if(!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)) - { - missed_read_addr = sp_after_rflags; - goto error_out; - } - - // commit registers - regs->rip.u64 = ip_value; - regs->ss.u16 = ss_value; - regs->rflags.u64 = rflags_value; - regs->rsp.u64 = sp_value; - - // mark machine frame - did_machframe = 1; - }break; - } - } - } - - //- iterate pdata chain - U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info->header); - if (!(flags & PE_UnwindInfoFlag_CHAINED)){ - break; - } - - U64 code_count_rounded = AlignPow2(unwind_info->codes_num, sizeof(PE_UnwindCode)); - U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); - U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; - - last_pdata = pdata; - pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); - } - - if(!did_machframe) - { - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - end_xdata_unwind:; - } - } - - error_out:; - - if(missed_read_addr != 0) - { - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - if(!result.dead) - { - result.stack_pointer = regs->rsp.u64; - } - - return(result); -} diff --git a/src/unwind/unwind.h b/src/unwind/unwind.h deleted file mode 100644 index 310e940c..00000000 --- a/src/unwind/unwind.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef UNWIND_H -#define UNWIND_H - -//////////////////////////////// -//~ rjf: Memory View Types -// -// Memory views are used to provide a slice (or, in the future, slices) of data -// required to do a proper unwind. This is generally a very small region in an -// address space, generally some things on the stack. But, some formats don't -// restrict this in an organized way, and so theoretically you might have some -// unwind information require arbitrary reads at an unknown address. So this -// "memory view" concept serves as kind of a "stand-in" for "provided memory -// info from the user". This keeps the control flow of this layer simpler, so -// we aren't calling a user-supplied hook to read memory or anything like that. - -typedef struct UNW_MemView UNW_MemView; -struct UNW_MemView -{ - // Upgrade Path: - // 1. A list of ranges like this one - // 2. Binary-searchable list of ranges - // 3. In-line growth strategy for missing pages (hardwired to source of new data) - // 4. Abstracted source of new data - void *data; - U64 addr_first; - U64 addr_opl; -}; - -//////////////////////////////// -//~ rjf: Unwind Step Results - -typedef struct UNW_Step UNW_Step; -struct UNW_Step -{ - B32 dead; - B32 missed_read; - U64 missed_read_addr; - U64 stack_pointer; -}; - -//////////////////////////////// -//~ rjf: Memory View Helpers - -internal UNW_MemView unw_memview_from_data(String8 data, U64 base_vaddr); -internal B32 unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out); -#define unw_memview_read_struct(v,addr,p) unw_memview_read((v), (addr), sizeof(*(p)), (p)) - -//////////////////////////////// -//~ rjf: PE/X64 Unwind Implementation - -//- rjf: helpers -internal UNW_Step unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); -internal B32 unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata); -internal REGS_Reg64 *unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg); - -//- rjf: unwind step -internal UNW_Step unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); - -#endif // UNWIND_H From 6e41bdf11baafab14ae60442e782b4902e4773a9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 16:28:52 -0700 Subject: [PATCH 11/38] first pass at loader portion of new dbgi layer replacement; set up ctrl entity for per-module debug info selection path info --- src/base/base_entry_point.c | 3 + src/ctrl/ctrl_core.c | 70 ++++- src/ctrl/ctrl_core.h | 3 + src/dbgi2/dbgi2.c | 588 ++++++++++++++++++++++++++++++++++++ src/dbgi2/dbgi2.h | 205 +++++++++++++ src/raddbg/raddbg.h | 1 + src/raddbg/raddbg_main.cpp | 2 + 7 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 src/dbgi2/dbgi2.c create mode 100644 src/dbgi2/dbgi2.h diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 325d1f83..51b47b6a 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -39,6 +39,9 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum #if defined(DBGI_H) dbgi_init(); #endif +#if defined(DI_H) + di_init(); +#endif #if defined(TXTI_H) txti_init(); #endif diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9a3a4fed..646db65e 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -481,6 +481,8 @@ ctrl_entity_store_release(CTRL_EntityStore *cache) arena_release(cache->arena); } +//- rjf: string allocation/deletion + internal U64 ctrl_name_bucket_idx_from_string_size(U64 size) { @@ -2934,6 +2936,7 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand U64 pdatas_count = 0; U64 entry_point_voff = 0; Rng1U64 tls_vaddr_range = {0}; + String8 builtin_debug_info_path = {0}; ProfScope("unpack relevant PE info") { B32 is_valid = 1; @@ -3067,11 +3070,75 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand // rjf: calculate TLS vaddr range tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32)); + + // rjf: grab data about debug info + U32 dbg_time = 0; + U32 dbg_age = 0; + OS_Guid dbg_guid = {0}; + if(data_dir_count > PE_DataDirectoryIndex_DEBUG) + { + // rjf: read data dir + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, &dir); + + // rjf: read debug directory + PE_DebugDirectory dbg_data = {0}; + dmn_process_read_struct(process, vaddr_range.min+(U64)dir.virt_off, &dbg_data); + + // rjf: extract external file info from codeview header + if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW) + { + U64 dbg_path_off = 0; + U64 dbg_path_size = 0; + U64 cv_offset = dbg_data.voff; + U32 cv_magic = 0; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv_magic); + switch(cv_magic) + { + default:break; + case PE_CODEVIEW_PDB20_MAGIC: + { + PE_CvHeaderPDB20 cv = {0}; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv); + dbg_time = cv.time; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + case PE_CODEVIEW_PDB70_MAGIC: + { + PE_CvHeaderPDB70 cv = {0}; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv); + dbg_guid = cv.guid; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + } + if(dbg_path_off > 0) + { + Temp scratch = scratch_begin(0, 0); + String8List parts = {0}; + for(U64 off = dbg_path_off;; off += 256) + { + U8 bytes[256] = {0}; + dmn_process_read(process, r1u64(vaddr_range.min+off, vaddr_range.min+off+sizeof(bytes)), bytes); + U64 size = cstring8_length(&bytes[0]); + String8 part = str8(bytes, size); + str8_list_push(scratch.arena, &parts, part); + if(size < sizeof(bytes)) + { + break; + } + } + builtin_debug_info_path = str8_list_join(arena, &parts, 0); + scratch_end(scratch); + } + } + } } } ////////////////////////////// - //- rjf: insert into cache + //- rjf: insert info into cache // { U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module); @@ -3100,6 +3167,7 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand node->pdatas = pdatas; node->pdatas_count = pdatas_count; node->entry_point_voff = entry_point_voff; + node->builtin_debug_info_path = builtin_debug_info_path; } } } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 854dfc26..913558c8 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -49,6 +49,7 @@ typedef enum CTRL_EntityKind CTRL_EntityKind_Thread, CTRL_EntityKind_Module, CTRL_EntityKind_EntryPoint, + CTRL_EntityKind_DebugInfoPath, CTRL_EntityKind_COUNT } CTRL_EntityKind; @@ -512,6 +513,7 @@ struct CTRL_ModuleImageInfoCacheNode U64 pdatas_count; U64 entry_point_voff; Rng1U64 tls_vaddr_range; + String8 builtin_debug_info_path; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -679,6 +681,7 @@ internal CTRL_EntityStore *ctrl_entity_store_alloc(void); internal void ctrl_entity_store_release(CTRL_EntityStore *store); //- rjf: string allocation/deletion +internal U64 ctrl_name_bucket_idx_from_string_size(U64 size); internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string); internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string); diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c new file mode 100644 index 00000000..0eff15f7 --- /dev/null +++ b/src/dbgi2/dbgi2.c @@ -0,0 +1,588 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +di_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +di_init(void) +{ + Arena *arena = arena_alloc(); + di_shared = push_array(arena, DI_Shared, 1); + di_shared->arena = arena; + di_shared->slots_count = 1024; + di_shared->slots = push_array(arena, DI_Slot, di_shared->slots_count); + di_shared->stripes_count = Min(di_shared->slots_count, os_logical_core_count()); + di_shared->stripes = push_array(arena, DI_Stripe, di_shared->stripes_count); + for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) + { + di_shared->stripes[idx].arena = arena_alloc(); + di_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + di_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + di_shared->u2p_ring_mutex = os_mutex_alloc(); + di_shared->u2p_ring_cv = os_condition_variable_alloc(); + di_shared->u2p_ring_size = KB(64); + di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); + di_shared->parse_thread_count = Max(2, os_logical_core_count()/2); + di_shared->parse_threads = push_array(arena, OS_Handle, di_shared->parse_thread_count); + for(U64 idx = 0; idx < di_shared->parse_thread_count; idx += 1) + { + di_shared->parse_threads[idx] = os_launch_thread(di_parse_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Scope Functions + +internal DI_Scope * +di_scope_open(void) +{ + if(di_tctx == 0) + { + Arena *arena = arena_alloc(); + di_tctx = push_array(arena, DI_TCTX, 1); + di_tctx->arena = arena; + } + DI_Scope *scope = di_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(di_tctx->free_scope); + } + else + { + scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); + } + MemoryZeroStruct(scope); +} + +internal void +di_scope_close(DI_Scope *scope) +{ + for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) + { + next = t->next; + SLLStackPush(di_tctx->free_touch, t); + if(t->node != 0) + { + ins_atomic_u64_dec_eval(&t->node->touch_count); + } + } + SLLStackPush(di_tctx->free_scope, scope); +} + +internal void +di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) +{ + if(node != 0) + { + ins_atomic_u64_inc_eval(&node->touch_count); + } + DI_Touch *touch = di_tctx->free_touch; + if(touch != 0) + { + SLLStackPop(di_tctx->free_touch); + } + else + { + touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); + } + MemoryZeroStruct(touch); + SLLQueuePush(scope->first_touch, scope->last_touch, touch); + touch->node = node; +} + +//////////////////////////////// +//~ rjf: Per-Slot Functions + +internal DI_Node * +di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp) +{ + DI_Node *node = 0; + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 most_recent_timestamp = max_U64; + for(DI_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, match_flags) && + min_timestamp <= n->min_timestamp && + (n->min_timestamp - min_timestamp) <= most_recent_timestamp) + { + node = n; + most_recent_timestamp = (n->min_timestamp - min_timestamp); + } + } + return node; +} + +//////////////////////////////// +//~ rjf: Per-Stripe Functions + +internal U64 +di_string_bucket_idx_from_string_size(U64 size) +{ + U64 size_rounded = u64_up_to_pow2(size+1); + size_rounded = ClampBot((1<<4), size_rounded); + U64 bucket_idx = 0; + switch(size_rounded) + { + case 1<<4: {bucket_idx = 0;}break; + case 1<<5: {bucket_idx = 1;}break; + case 1<<6: {bucket_idx = 2;}break; + case 1<<7: {bucket_idx = 3;}break; + case 1<<8: {bucket_idx = 4;}break; + case 1<<9: {bucket_idx = 5;}break; + case 1<<10:{bucket_idx = 6;}break; + default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; + } + return bucket_idx; +} + +internal String8 +di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return str8_zero();} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = stripe->free_string_chunks[bucket_idx]; + + // rjf: pull from bucket free list + if(node != 0) + { + if(bucket_idx == ArrayCount(stripe->free_string_chunks)-1) + { + node = 0; + DI_StringChunkNode *prev = 0; + for(DI_StringChunkNode *n = stripe->free_string_chunks[bucket_idx]; + n != 0; + prev = n, n = n->next) + { + if(n->size >= string.size+1) + { + if(prev == 0) + { + stripe->free_string_chunks[bucket_idx] = n->next; + } + else + { + prev->next = n->next; + } + node = n; + break; + } + } + } + else + { + SLLStackPop(stripe->free_string_chunks[bucket_idx]); + } + } + + // rjf: no found node -> allocate new + if(node == 0) + { + U64 chunk_size = 0; + if(bucket_idx < ArrayCount(stripe->free_string_chunks)-1) + { + chunk_size = 1<<(bucket_idx+4); + } + else + { + chunk_size = u64_up_to_pow2(string.size); + } + U8 *chunk_memory = push_array(stripe->arena, U8, chunk_size); + node = (DI_StringChunkNode *)chunk_memory; + } + + // rjf: fill string & return + String8 allocated_string = str8((U8 *)node, string.size); + MemoryCopy((U8 *)node, string.str, string.size); + return allocated_string; +} + +internal void +di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return;} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = (DI_StringChunkNode *)string.str; + node->size = u64_up_to_pow2(string.size); + SLLStackPush(stripe->free_string_chunks[bucket_idx], node); +} + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void +di_open(String8 path, U64 min_timestamp) +{ + Temp scratch = scratch_begin(0, 0); + if(path.size != 0) + { + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + U64 hash = di_hash_from_string(path_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("opening debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + + //- rjf: allocate node if none exists; insert into slot + if(node == 0) + { + node = stripe->free_node; + if(node != 0) + { + SLLStackPop(stripe->free_node); + } + else + { + node = push_array_no_zero(stripe->arena, DI_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, path_normalized); + node->path = path_stored; + node->min_timestamp; + } + + //- rjf: increment node reference count + node->ref_count += 1; + if(node->ref_count == 1) + { + di_u2p_enqueue_key(path_normalized, min_timestamp, 0); + } + } + } + scratch_end(scratch); +} + +internal void +di_close(String8 path, U64 min_timestamp) +{ + Temp scratch = scratch_begin(0, 0); + if(path.size != 0) + { + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = di_hash_from_string(path_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("closing debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + + //- rjf: node exists -> decrement reference count; release + if(node != 0) + { + node->ref_count -= 1; + if(node->ref_count == 0) + { + //- rjf: wait for touch count to go to 0 + for(;ins_atomic_u64_eval(&node->touch_count) != 0;){} + + //- rjf: release + di_string_release__stripe_mutex_w_guarded(stripe, node->path); + if(node->file_base != 0) + { + os_file_map_view_close(node->file_map, node->file_base); + } + if(!os_handle_match(node->file_map, os_handle_zero())) + { + os_file_map_close(node->file_map); + } + if(!os_handle_match(node->file, os_handle_zero())) + { + os_file_close(node->file); + } + if(node->arena != 0) + { + arena_release(node->arena); + } + DLLRemove(slot->first, slot->last, node); + SLLStackPush(stripe->free_node, node); + } + } + } + } + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed * +di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us) +{ + RDI_Parsed *result = &di_rdi_parsed_nil; + if(path.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = di_hash_from_string(path_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + + //- rjf: parse done -> touch, grab result + if(node != 0 && node->parse_done) + { + di_scope_touch_node__stripe_mutex_r_guarded(scope, node); + result = &node->rdi; + break; + } + + //- rjf: parse not done, not working, asked a while ago -> ask for parse + if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); + } + } + + //- rjf: time expired -> break + if(os_now_microseconds() >= endt_us) + { + break; + } + + //- rjf: wait on this stripe + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + scratch_end(scratch); + } + return result; +} + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 +di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us) +{ + B32 sent = 0; + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + U64 available_size = di_shared->u2p_ring_size - unconsumed_size; + if(available_size >= sizeof(path.size) + path.size + sizeof(min_timestamp)) + { + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &path.size); + di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, path.str, path.size); + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &min_timestamp); + di_shared->u2p_ring_write_pos += 7; + di_shared->u2p_ring_write_pos -= di_shared->u2p_ring_write_pos%8; + sent = 1; + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); + } + if(sent) + { + os_condition_variable_broadcast(di_shared->u2p_ring_cv); + } + return sent; +} + +internal void +di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp) +{ + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + if(unconsumed_size >= sizeof(out_path->size) + sizeof(out_min_timestamp[0])) + { + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_path->size); + out_path->str = push_array(arena, U8, out_path->size); + di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_path->str, out_path->size); + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_min_timestamp); + di_shared->u2p_ring_read_pos += 7; + di_shared->u2p_ring_read_pos -= di_shared->u2p_ring_read_pos%8; + break; + } + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); + } + os_condition_variable_broadcast(di_shared->u2p_ring_cv); +} + +internal void +di_parse_thread__entry_point(void *p) +{ + ThreadNameF("[di] parse #%I64u", (U64)p); + for(;;) + { + Temp scratch = scratch_begin(0, 0); + + //////////////////////////// + //- rjf: grab next key + // + String8 path = {0}; + U64 min_timestamp = 0; + di_u2p_dequeue_key(scratch.arena, &path, &min_timestamp); + + //////////////////////////// + //- rjf: unpack key + // + U64 hash = di_hash_from_string(path); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + + //////////////////////////// + //- rjf: take task + // + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path, min_timestamp); + if(node != 0) + { + got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); + } + } + + //////////////////////////// + //- rjf: got task -> open file + // + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + if(got_task) + { + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); + } + + //////////////////////////// + //- rjf: do initial parse of rdi + // + RDI_Parsed rdi_parsed_maybe_compressed = dbgi_parse_nil.rdi; + if(got_task) + { + RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); + (void)parse_status; + } + + //////////////////////////// + //- rjf: decompress & re-parse, if necessary + // + Arena *rdi_parsed_arena = 0; + RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; + if(got_task) + { + U64 decompressed_size = file_props.size; + for(U64 dsec_idx = 0; dsec_idx < rdi_parsed_maybe_compressed.dsec_count; dsec_idx += 1) + { + decompressed_size += (rdi_parsed_maybe_compressed.dsecs[dsec_idx].unpacked_size - rdi_parsed_maybe_compressed.dsecs[dsec_idx].encoded_size); + } + if(decompressed_size > file_props.size) + { + rdi_parsed_arena = arena_alloc(); + U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); + + // rjf: copy header + RDI_Header *src_header = (RDI_Header *)file_base; + RDI_Header *dst_header = (RDI_Header *)decompressed_data; + { + MemoryCopy(dst_header, src_header, sizeof(RDI_Header)); + } + + // rjf: copy & adjust sections for decompressed version + if(rdi_parsed_maybe_compressed.dsec_count != 0) + { + RDI_DataSection *dsec_base = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); + MemoryCopy(dsec_base, (U8 *)file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); + U64 off = dst_header->data_section_off + sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count; + off += 7; + off -= off%8; + for(U64 idx = 0; idx < rdi_parsed_maybe_compressed.dsec_count; idx += 1) + { + dsec_base[idx].encoding = RDI_DataSectionEncoding_Unpacked; + dsec_base[idx].off = off; + dsec_base[idx].encoded_size = dsec_base[idx].unpacked_size; + off += dsec_base[idx].unpacked_size; + off += 7; + off -= off%8; + } + } + + // rjf: decompress sections into new decompressed file buffer + if(rdi_parsed_maybe_compressed.dsec_count != 0) + { + RDI_DataSection *src_first = rdi_parsed_maybe_compressed.dsecs; + RDI_DataSection *dst_first = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); + RDI_DataSection *src_opl = src_first + rdi_parsed_maybe_compressed.dsec_count; + RDI_DataSection *dst_opl = dst_first + rdi_parsed_maybe_compressed.dsec_count; + for(RDI_DataSection *src = src_first, *dst = dst_first; + src < src_opl && dst < dst_opl; + src += 1, dst += 1) + { + rr_lzb_simple_decode((U8*)file_base + src->off, src->encoded_size, + decompressed_data + dst->off, dst->unpacked_size); + } + } + + // rjf: re-parse + RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); + (void)parse_status; + } + } + + //////////////////////////// + //- rjf: commit parsed info to cache + // + if(got_task) OS_MutexScopeW(stripe->rw_mutex) + { + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path, min_timestamp); + if(node != 0) + { + node->is_working = 0; + node->file = file; + node->file_map = file_map; + node->file_base = file_base; + node->file_props = file_props; + node->arena = rdi_parsed_arena; + node->rdi = rdi_parsed; + node->parse_done = 1; + } + } + + scratch_end(scratch); + } +} diff --git a/src/dbgi2/dbgi2.h b/src/dbgi2/dbgi2.h new file mode 100644 index 00000000..9333b64b --- /dev/null +++ b/src/dbgi2/dbgi2.h @@ -0,0 +1,205 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DI_H +#define DI_H + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct DI_StringChunkNode DI_StringChunkNode; +struct DI_StringChunkNode +{ + DI_StringChunkNode *next; + U64 size; +}; + +typedef struct DI_Node DI_Node; +struct DI_Node +{ + // rjf: links + DI_Node *next; + DI_Node *prev; + + // rjf: metadata + U64 ref_count; + U64 touch_count; + U64 is_working; + U64 last_time_requested_us; + + // rjf: key + String8 path; + U64 min_timestamp; + + // rjf: file handles + OS_Handle file; + OS_Handle file_map; + void *file_base; + FileProperties file_props; + + // rjf: parse artifacts + Arena *arena; + RDI_Parsed rdi; + B32 parse_done; +}; + +typedef struct DI_Slot DI_Slot; +struct DI_Slot +{ + DI_Node *first; + DI_Node *last; +}; + +typedef struct DI_Stripe DI_Stripe; +struct DI_Stripe +{ + Arena *arena; + DI_Node *free_node; + DI_StringChunkNode *free_string_chunks[8]; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct DI_Touch DI_Touch; +struct DI_Touch +{ + DI_Touch *next; + DI_Node *node; +}; + +typedef struct DI_Scope DI_Scope; +struct DI_Scope +{ + DI_Scope *next; + DI_Touch *first_touch; + DI_Touch *last_touch; +}; + +typedef struct DI_TCTX DI_TCTX; +struct DI_TCTX +{ + Arena *arena; + DI_Scope *free_scope; + DI_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State Types + +typedef struct DI_Shared DI_Shared; +struct DI_Shared +{ + Arena *arena; + + // rjf: node cache + U64 slots_count; + DI_Slot *slots; + U64 stripes_count; + DI_Stripe *stripes; + + // rjf: user -> parse ring + OS_Handle u2p_ring_mutex; + OS_Handle u2p_ring_cv; + U64 u2p_ring_size; + U8 *u2p_ring_base; + U64 u2p_ring_write_pos; + U64 u2p_ring_read_pos; + + // rjf: threads + U64 parse_thread_count; + OS_Handle *parse_threads; +}; + +//////////////////////////////// +//~ rjf: Globals + +global DI_Shared *di_shared = 0; +thread_static DI_TCTX *di_tctx = 0; +global RDI_Parsed di_rdi_parsed_nil = +{ + 0, + 0, + 0, + 0, + {0}, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &rdi_binary_section_nil, 1, + &rdi_file_path_node_nil, 1, + &rdi_source_file_nil, 1, + &rdi_unit_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_type_node_nil, 1, + &rdi_udt_nil, 1, + &rdi_member_nil, 1, + &rdi_enum_member_nil, 1, + &rdi_global_variable_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_thread_variable_nil, 1, + &rdi_procedure_nil, 1, + &rdi_scope_nil, 1, + &rdi_voff_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_local_nil, 1, + &rdi_location_block_nil, 1, + 0, 0, + 0, 0, +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 di_hash_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void di_init(void); + +//////////////////////////////// +//~ rjf: Scope Functions + +internal DI_Scope *di_scope_open(void); +internal void di_scope_close(DI_Scope *scope); +internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node); + +//////////////////////////////// +//~ rjf: Per-Slot Functions + +internal DI_Node *di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp); + +//////////////////////////////// +//~ rjf: Per-Stripe Functions + +internal U64 di_string_bucket_idx_from_string_size(U64 size); +internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); +internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void di_open(String8 path, U64 min_timestamp); +internal void di_close(String8 path, U64 min_timestamp); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed *di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us); + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us); +internal void di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp); + +internal void di_parse_thread__entry_point(void *p); + +#endif // DI_H diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index f2c4511f..f55e3c09 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -39,6 +39,7 @@ // // [ ] robustify dbgi layer to renames (cache should not be based only on // path - must invalidate naturally when new filetime occurs) +// [ ] new fuzzy searching layer // // [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly // [ ] PDB files distributed with the build are not found by DbgHelp!!! diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 4400d628..7b2d9ba5 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -47,6 +47,7 @@ #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" +#include "dbgi2/dbgi2.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" #include "ctrl/ctrl_inc.h" @@ -85,6 +86,7 @@ #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" +#include "dbgi2/dbgi2.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" #include "ctrl/ctrl_inc.c" From b9ac10427688397c6dabc9831a06e87987def73a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 17:15:11 -0700 Subject: [PATCH 12/38] begin stitching new dbgi layer usage code into ctrl layer; keep track of per-module preferred pdb paths via event-synchronized ctrl entity tree; still need conversion --- src/ctrl/ctrl_core.c | 124 +++++++++++++++++++++++++++++++++++++++++-- src/ctrl/ctrl_core.h | 12 ++++- 2 files changed, 131 insertions(+), 5 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 646db65e..a51c0d1b 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -419,6 +419,7 @@ ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event) str8_serial_push_struct(scratch.arena, &srl, &event->rip_vaddr); str8_serial_push_struct(scratch.arena, &srl, &event->stack_base); str8_serial_push_struct(scratch.arena, &srl, &event->tls_root); + str8_serial_push_struct(scratch.arena, &srl, &event->timestamp); str8_serial_push_struct(scratch.arena, &srl, &event->exception_code); str8_serial_push_struct(scratch.arena, &srl, &event->string.size); str8_serial_push_data(scratch.arena, &srl, event->string.str, event->string.size); @@ -448,6 +449,7 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) read_off += str8_deserial_read_struct(string, read_off, &event.rip_vaddr); read_off += str8_deserial_read_struct(string, read_off, &event.stack_base); read_off += str8_deserial_read_struct(string, read_off, &event.tls_root); + read_off += str8_deserial_read_struct(string, read_off, &event.timestamp); read_off += str8_deserial_read_struct(string, read_off, &event.exception_code); read_off += str8_deserial_read_struct(string, read_off, &event.string.size); event.string.str = push_array_no_zero(arena, U8, event.string.size); @@ -734,6 +736,23 @@ ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machi return entity; } +internal CTRL_Entity * +ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_EntityKind kind) +{ + CTRL_Entity *result = &ctrl_entity_nil; + for(CTRL_Entity *child = parent->first; + child != &ctrl_entity_nil; + child = child->next) + { + if(child->kind == kind) + { + result = child; + break; + } + } + return result; +} + //- rjf: applying events to entity caches internal void @@ -789,16 +808,33 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) //- rjf: modules case CTRL_EventKind_NewModule: { + Temp scratch = scratch_begin(0, 0); CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->machine_id, event->entity, event->vaddr_rng.min); ctrl_entity_equip_string(store, module, event->string); + module->timestamp = event->timestamp; + CTRL_Entity *debug_info_path = ctrl_entity_alloc(store, module, CTRL_EntityKind_DebugInfoPath, Architecture_Null, 0, dmn_handle_zero(), 0); + String8 initial_debug_info_path = ctrl_initial_debug_info_path_from_module(scratch.arena, event->machine_id, event->entity); + ctrl_entity_equip_string(store, debug_info_path, initial_debug_info_path); module->vaddr_range = event->vaddr_rng; + debug_info_path->timestamp = module->timestamp; + scratch_end(scratch); }break; case CTRL_EventKind_EndModule: { CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); ctrl_entity_release(store, module); }break; + case CTRL_EventKind_ModuleDebugInfoPathChange: + { + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + if(debug_info_path == &ctrl_entity_nil) + { + debug_info_path = ctrl_entity_alloc(store, module, CTRL_EntityKind_DebugInfoPath, Architecture_Null, 0, dmn_handle_zero(), 0); + } + ctrl_entity_equip_string(store, debug_info_path, event->string); + }break; } } } @@ -1576,6 +1612,26 @@ ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_ha return result; } +internal String8 +ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + String8 result = {0}; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = push_str8_copy(arena, n->initial_debug_info_path); + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Unwinding Functions @@ -2780,6 +2836,22 @@ ctrl_thread__entry_point(void *p) str8_list_push(ctrl_state->user_entry_point_arena, &ctrl_state->user_entry_points, n->string); } }break; + case CTRL_MsgKind_SetModuleDebugInfoPath: + { + String8 path = msg->path; + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, msg->machine_id, msg->entity); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + di_close(debug_info_path->string, module->timestamp); + ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path); + di_open(path, module->timestamp); + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange; + evt->machine_id = msg->machine_id; + evt->entity = msg->entity; + evt->string = path; + ctrl_c2u_push_events(&evts); + }break; } } } @@ -2921,7 +2993,7 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID //- rjf: module lifetime open/close work internal void -ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path) +ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path, U64 exe_timestamp) { ////////////////////////////// //- rjf: open debug info @@ -3137,6 +3209,39 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand } } + ////////////////////////////// + //- rjf: pick default initial debug info path + // + String8 initial_debug_info_path = builtin_debug_info_path; + { + Temp scratch = scratch_begin(0, 0); + String8 exe_folder = str8_chop_last_slash(path); + String8 builtin_debug_info_path__absolute = builtin_debug_info_path; + String8 builtin_debug_info_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, builtin_debug_info_path); + String8 dbg_path_candidates[] = + { + /* inferred (treated as absolute): */ builtin_debug_info_path__absolute, + /* inferred (treated as relative): */ builtin_debug_info_path__relative, + /* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(path)), + /* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", path), + }; + for(U64 idx = 0; idx < ArrayCount(dbg_path_candidates); idx += 1) + { + FileProperties props = os_properties_from_file_path(dbg_path_candidates[idx]); + if(props.modified != 0 && props.size != 0) + { + initial_debug_info_path = push_str8_copy(arena, dbg_path_candidates[idx]); + break; + } + } + scratch_end(scratch); + } + + ////////////////////////////// + //- rjf: open debug info + // + di_open(initial_debug_info_path, exe_timestamp); + ////////////////////////////// //- rjf: insert info into cache // @@ -3167,7 +3272,7 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand node->pdatas = pdatas; node->pdatas_count = pdatas_count; node->entry_point_voff = entry_point_voff; - node->builtin_debug_info_path = builtin_debug_info_path; + node->initial_debug_info_path = initial_debug_info_path; } } } @@ -3204,6 +3309,16 @@ ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 } } + ////////////////////////////// + //- rjf: close debug info + // + { + CTRL_Entity *module_ent = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); + CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); + String8 debug_info_path = debug_info_path_ent->string; + di_close(debug_info_path, debug_info_path_ent->timestamp); + } + ////////////////////////////// //- rjf: close debug info // @@ -3475,7 +3590,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; - ctrl_thread__module_open(CTRL_MachineID_Local, event->process, event->module, r1u64(event->address, event->address+event->size), module_path); + U64 timestamp = os_properties_from_file_path(module_path).modified; + ctrl_thread__module_open(CTRL_MachineID_Local, event->process, event->module, r1u64(event->address, event->address+event->size), module_path, timestamp); out_evt->kind = CTRL_EventKind_NewModule; out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; @@ -3485,6 +3601,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->entity_id = event->code; out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); out_evt->rip_vaddr = event->address; + out_evt->timestamp = timestamp; out_evt->string = module_path; }break; case DMN_EventKind_ExitProcess: @@ -3515,6 +3632,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; out_evt->entity = event->module; + out_evt->string = module_path; }break; case DMN_EventKind_DebugString: { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 913558c8..220da859 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -68,6 +68,7 @@ struct CTRL_Entity DMN_Handle handle; U64 id; Rng1U64 vaddr_range; + U64 timestamp; String8 string; }; @@ -248,6 +249,7 @@ typedef enum CTRL_MsgKind CTRL_MsgKind_Run, CTRL_MsgKind_SingleStep, CTRL_MsgKind_SetUserEntryPoints, + CTRL_MsgKind_SetModuleDebugInfoPath, CTRL_MsgKind_COUNT, } CTRL_MsgKind; @@ -316,6 +318,9 @@ typedef enum CTRL_EventKind CTRL_EventKind_EndThread, CTRL_EventKind_EndModule, + //- rjf: debug info changes + CTRL_EventKind_ModuleDebugInfoPathChange, + //- rjf: debug strings CTRL_EventKind_DebugString, CTRL_EventKind_ThreadName, @@ -372,6 +377,7 @@ struct CTRL_Event U64 rip_vaddr; U64 stack_base; U64 tls_root; + U64 timestamp; U32 exception_code; String8 string; }; @@ -513,7 +519,7 @@ struct CTRL_ModuleImageInfoCacheNode U64 pdatas_count; U64 entry_point_voff; Rng1U64 tls_vaddr_range; - String8 builtin_debug_info_path; + String8 initial_debug_info_path; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -694,6 +700,7 @@ internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *ent //- rjf: entity store lookups internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle); +internal CTRL_Entity *ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_EntityKind kind); //- rjf: applying events to entity caches internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list); @@ -745,6 +752,7 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff); internal U64 ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); +internal String8 ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle); //////////////////////////////// //~ rjf: Unwinding Functions @@ -798,7 +806,7 @@ internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CT internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //- rjf: module lifetime open/close work -internal void ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path); +internal void ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path, U64 exe_timestamp); internal void ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 path); //- rjf: attached process running/event gathering From a019115b95e05750593e1d1bb282f21cb4a97f0a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 21 May 2024 10:08:28 -0700 Subject: [PATCH 13/38] get ctrl and debug frontend layers onto new pdb-path-based debug info loader layer; sketch out standalone fuzzy search layer, to replace old dbgi searching functionality; shift all debug frontend code from referring to debug info via 'binaries' to referring to debug info via 'dbgis', just file entities at the location of o.g. debug info --- src/base/base_entry_point.c | 3 + src/ctrl/ctrl_core.c | 116 +++++------- src/dasm_cache/dasm_cache.c | 44 ++--- src/dasm_cache/dasm_cache.h | 3 +- src/dbgi2/dbgi2.c | 294 +++++++++++++++++++++++++++-- src/dbgi2/dbgi2.h | 46 +++++ src/df/core/df_core.c | 321 ++++++++++++++------------------ src/df/core/df_core.h | 65 +++---- src/df/gfx/df_gfx.c | 130 ++++++------- src/df/gfx/df_gfx.h | 14 +- src/df/gfx/df_view_rules.c | 35 ++-- src/df/gfx/df_view_rules.h | 8 +- src/df/gfx/df_views.c | 173 +++++++++-------- src/df/gfx/df_views.h | 2 +- src/fuzzy_search/fuzzy_search.c | 83 +++++++++ src/fuzzy_search/fuzzy_search.h | 185 ++++++++++++++++++ src/raddbg/raddbg_main.cpp | 6 +- 17 files changed, 1029 insertions(+), 499 deletions(-) create mode 100644 src/fuzzy_search/fuzzy_search.c create mode 100644 src/fuzzy_search/fuzzy_search.h diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 51b47b6a..7aa20d7f 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -42,6 +42,9 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum #if defined(DI_H) di_init(); #endif +#if defined(FUZZY_SEARCH_H) + fzy_init(); +#endif #if defined(TXTI_H) txti_init(); #endif diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index a51c0d1b..5a66aa37 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -2879,11 +2879,10 @@ internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); - String8 exe_path = module_entity->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); + RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, debug_info_path_entity->string, debug_info_path_entity->timestamp, max_U64); U64 base_vaddr = module_entity->vaddr_range.min; for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { @@ -2972,7 +2971,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID m }break; } } - dbgi_scope_close(scope); + di_scope_close(di_scope); scratch_end(scratch); } @@ -2995,11 +2994,6 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID internal void ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path, U64 exe_timestamp) { - ////////////////////////////// - //- rjf: open debug info - // - dbgi_binary_open(path); - ////////////////////////////// //- rjf: parse module image info // @@ -3237,11 +3231,6 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand scratch_end(scratch); } - ////////////////////////////// - //- rjf: open debug info - // - di_open(initial_debug_info_path, exe_timestamp); - ////////////////////////////// //- rjf: insert info into cache // @@ -3315,14 +3304,12 @@ ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 { CTRL_Entity *module_ent = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); - String8 debug_info_path = debug_info_path_ent->string; - di_close(debug_info_path, debug_info_path_ent->timestamp); + if(debug_info_path_ent != &ctrl_entity_nil) + { + String8 debug_info_path = debug_info_path_ent->string; + di_close(debug_info_path, debug_info_path_ent->timestamp); + } } - - ////////////////////////////// - //- rjf: close debug info - // - dbgi_binary_close(path); } //- rjf: attached process running/event gathering @@ -3402,7 +3389,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, if(!should_filter_event && ev->code == 0xc0000005 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->process); CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) @@ -3418,9 +3405,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - String8 module_path = module->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); if(rdi->global_variables != 0 && unparsed_map != 0) { @@ -3463,7 +3449,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, } } - dbgi_scope_close(scope); + di_scope_close(di_scope); } }break; } @@ -3588,21 +3574,31 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, }break; case DMN_EventKind_LoadModule: { - CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + CTRL_Event *out_evt1 = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; U64 timestamp = os_properties_from_file_path(module_path).modified; ctrl_thread__module_open(CTRL_MachineID_Local, event->process, event->module, r1u64(event->address, event->address+event->size), module_path, timestamp); - out_evt->kind = CTRL_EventKind_NewModule; - out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Local; - out_evt->entity = event->module; - out_evt->parent = event->process; - out_evt->arch = event->arch; - out_evt->entity_id = event->code; - out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); - out_evt->rip_vaddr = event->address; - out_evt->timestamp = timestamp; - out_evt->string = module_path; + out_evt1->kind = CTRL_EventKind_NewModule; + out_evt1->msg_id = msg->msg_id; + out_evt1->machine_id = CTRL_MachineID_Local; + out_evt1->entity = event->module; + out_evt1->parent = event->process; + out_evt1->arch = event->arch; + out_evt1->entity_id = event->code; + out_evt1->vaddr_rng = r1u64(event->address, event->address+event->size); + out_evt1->rip_vaddr = event->address; + out_evt1->timestamp = timestamp; + out_evt1->string = module_path; + CTRL_Event *out_evt2 = ctrl_event_list_push(scratch.arena, &evts); + String8 initial_debug_info_path = ctrl_initial_debug_info_path_from_module(scratch.arena, CTRL_MachineID_Local, event->module); + out_evt2->kind = CTRL_EventKind_ModuleDebugInfoPathChange; + out_evt2->msg_id = msg->msg_id; + out_evt2->machine_id = CTRL_MachineID_Local; + out_evt2->entity = event->module; + out_evt2->parent = event->process; + out_evt2->timestamp = timestamp; + out_evt2->string = initial_debug_info_path; + di_open(initial_debug_info_path, timestamp); }break; case DMN_EventKind_ExitProcess: { @@ -3748,7 +3744,6 @@ ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, msg->entity_id); @@ -3795,7 +3790,6 @@ ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -3805,7 +3799,6 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); DMN_Handle process = msg->entity; U32 exit_code = msg->exit_code; @@ -3849,7 +3842,6 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -3859,7 +3851,6 @@ ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); DMN_Handle process = msg->entity; //- rjf: detach @@ -3902,7 +3893,6 @@ ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -3912,7 +3902,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; DMN_Handle target_thread = msg->entity; @@ -4214,9 +4204,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } } U64 module_base_vaddr = module->vaddr_range.min; - String8 exe_path = module->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); RDI_ParsedNameMap map = {0}; rdi_name_map_parse(rdi, unparsed_map, &map); @@ -4396,24 +4385,25 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; U64 thread_rip_vaddr = dmn_rip_from_thread(event->thread); - DMN_Handle module = {0}; - String8 module_name = {0}; - U64 module_base_vaddr = 0; - U64 thread_rip_voff = 0; + CTRL_Entity *module = &ctrl_entity_nil; { CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); - for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + for(CTRL_Entity *m = process->first; m != &ctrl_entity_nil; m = m->next) { - if(module->kind == CTRL_EntityKind_Module && contains_1u64(module->vaddr_range, thread_rip_vaddr)) + if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, thread_rip_vaddr)) { - module_name = module->string; - module_base_vaddr = module->vaddr_range.min; - thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + module = m; break; } } } + ////////////////////////// + //- rjf: extract module-dependent info + // + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + U64 thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + ////////////////////////// //- rjf: stepping logic // @@ -4508,9 +4498,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - String8 exe_path = module_name; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { String8 string = condition_n->string; @@ -4548,7 +4536,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = module_base_vaddr; + U64 module_base = module->vaddr_range.min; U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread); EVAL_Machine machine = {0}; machine.u = &event->process; @@ -4855,7 +4843,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); + di_scope_close(di_scope); scratch_end(scratch); ProfEnd(); } @@ -4865,7 +4853,6 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); //- rjf: record start { @@ -4918,7 +4905,6 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index b150acd7..618ca388 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -24,7 +24,8 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - str8_match(a->exe_path, b->exe_path, 0)); + str8_match(a->dbg_path, b->dbg_path, 0) && + a->dbg_timestamp == b->dbg_timestamp); return result; } @@ -189,7 +190,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node) ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx()); touch->hash = node->hash; MemoryCopyStruct(&touch->params, &node->params); - touch->params.exe_path = push_str8_copy(dasm_tctx->arena, touch->params.exe_path); + touch->params.dbg_path = push_str8_copy(dasm_tctx->arena, touch->params.dbg_path); SLLStackPush(scope->top_touch, touch); } @@ -250,7 +251,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) node->hash = hash; MemoryCopyStruct(&node->params, params); // TODO(rjf): need to make this releasable - currently all exe_paths just leak - node->params.exe_path = push_str8_copy(stripe->arena, node->params.exe_path); + node->params.dbg_path = push_str8_copy(stripe->arena, node->params.dbg_path); node_is_new = 1; } } @@ -294,7 +295,7 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->exe_path.size) + if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbg_path.size+sizeof(U64)) { good = 1; dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash); @@ -303,8 +304,9 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->style_flags); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->syntax); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->base_vaddr); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->exe_path.size); - dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->exe_path.str, params->exe_path.size); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbg_path.size); + dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbg_path.str, params->dbg_path.size); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbg_timestamp); dasm_shared->u2p_ring_write_pos += 7; dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8; break; @@ -328,7 +330,7 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out) OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)) + if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64)) { dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, hash_out); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->vaddr); @@ -336,9 +338,10 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out) dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->style_flags); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->syntax); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->base_vaddr); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->exe_path.size); - params_out->exe_path.str = push_array(arena, U8, params_out->exe_path.size); - dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->exe_path.str, params_out->exe_path.size); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbg_path.size); + params_out->dbg_path.str = push_array(arena, U8, params_out->dbg_path.size); + dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbg_path.str, params_out->dbg_path.size); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbg_timestamp); dasm_shared->u2p_ring_read_pos += 7; dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8; break; @@ -362,7 +365,7 @@ dasm_parse_thread__entry_point(void *p) dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms); U64 change_gen = fs_change_gen(); HS_Scope *hs_scope = hs_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); //- rjf: unpack hash @@ -386,12 +389,11 @@ dasm_parse_thread__entry_point(void *p) } //- rjf: get dbg info - DBGI_Parse *dbgi = &dbgi_parse_nil; - if(got_task && params.exe_path.size != 0) + RDI_Parsed *rdi = &di_rdi_parsed_nil; + if(got_task && params.dbg_path.size != 0) { - dbgi = dbgi_parse_from_exe_path(dbgi_scope, params.exe_path, max_U64); + rdi = di_rdi_from_path_min_timestamp(di_scope, params.dbg_path, params.dbg_timestamp, max_U64); } - RDI_Parsed *rdi = &dbgi->rdi; //- rjf: hash -> data String8 data = {0}; @@ -442,7 +444,7 @@ dasm_parse_thread__entry_point(void *p) // rjf: push strings derived from voff -> line info if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines)) { - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { U64 voff = (params.vaddr+off) - params.base_vaddr; U32 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); @@ -517,7 +519,7 @@ dasm_parse_thread__entry_point(void *p) String8 addr_part = {0}; if(params.style_flags & DASM_StyleFlag_Addresses) { - addr_part = push_str8f(scratch.arena, "%s%016I64X ", dbgi != &dbgi_parse_nil ? " " : "", params.vaddr+off); + addr_part = push_str8f(scratch.arena, "%s%016I64X ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off); } String8 code_bytes_part = {0}; if(params.style_flags & DASM_StyleFlag_CodeBytes) @@ -539,7 +541,7 @@ dasm_parse_thread__entry_point(void *p) code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); } String8 symbol_part = {0}; - if(jump_dst_vaddr != 0 && dbgi != &dbgi_parse_nil && params.style_flags & DASM_StyleFlag_SymbolNames) + if(jump_dst_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) { RDI_U32 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, jump_dst_vaddr-params.base_vaddr); if(scope_idx != 0) @@ -590,7 +592,7 @@ dasm_parse_thread__entry_point(void *p) (U64)params.arch, (U64)params.style_flags, (U64)params.syntax, - (U64)dbgi, + (U64)rdi, 0x4d534144, }; text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data))); @@ -614,7 +616,7 @@ dasm_parse_thread__entry_point(void *p) { n->info_arena = info_arena; MemoryCopyStruct(&n->info, &info); - if(dbgi != &dbgi_parse_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) + if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) { n->change_gen = change_gen; } @@ -630,7 +632,7 @@ dasm_parse_thread__entry_point(void *p) } txt_scope_close(txt_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); hs_scope_close(hs_scope); scratch_end(scratch); } diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 3e5d4e9f..6629aed1 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -36,7 +36,8 @@ struct DASM_Params DASM_StyleFlags style_flags; DASM_Syntax syntax; U64 base_vaddr; - String8 exe_path; + String8 dbg_path; + U64 dbg_timestamp; }; //////////////////////////////// diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c index 0eff15f7..31b5b841 100644 --- a/src/dbgi2/dbgi2.c +++ b/src/dbgi2/dbgi2.c @@ -38,6 +38,10 @@ di_init(void) di_shared->u2p_ring_cv = os_condition_variable_alloc(); di_shared->u2p_ring_size = KB(64); di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); + di_shared->p2u_ring_mutex = os_mutex_alloc(); + di_shared->p2u_ring_cv = os_condition_variable_alloc(); + di_shared->p2u_ring_size = KB(64); + di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); di_shared->parse_thread_count = Max(2, os_logical_core_count()/2); di_shared->parse_threads = push_array(arena, OS_Handle, di_shared->parse_thread_count); for(U64 idx = 0; idx < di_shared->parse_thread_count; idx += 1) @@ -68,6 +72,7 @@ di_scope_open(void) scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); } MemoryZeroStruct(scope); + return scope; } internal void @@ -246,6 +251,11 @@ di_open(String8 path, U64 min_timestamp) //- rjf: allocate node if none exists; insert into slot if(node == 0) { + U64 current_timestamp = os_properties_from_file_path(path).modified; + if(current_timestamp == 0) + { + current_timestamp = min_timestamp; + } node = stripe->free_node; if(node != 0) { @@ -259,14 +269,17 @@ di_open(String8 path, U64 min_timestamp) DLLPushBack(slot->first, slot->last, node); String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, path_normalized); node->path = path_stored; - node->min_timestamp; + node->min_timestamp = current_timestamp; } //- rjf: increment node reference count - node->ref_count += 1; - if(node->ref_count == 1) + if(node != 0) { - di_u2p_enqueue_key(path_normalized, min_timestamp, 0); + node->ref_count += 1; + if(node->ref_count == 1) + { + di_u2p_enqueue_key(path_normalized, node->min_timestamp, 0); + } } } } @@ -350,6 +363,12 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, //- rjf: find existing node DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + //- rjf: no node? this path is not opened + if(node == 0) + { + break; + } + //- rjf: parse done -> touch, grab result if(node != 0 && node->parse_done) { @@ -437,6 +456,57 @@ di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp) os_condition_variable_broadcast(di_shared->u2p_ring_cv); } +internal void +di_p2u_push_event(DI_Event *event) +{ + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + U64 available_size = di_shared->p2u_ring_size-unconsumed_size; + U64 needed_size = sizeof(DI_EventKind) + sizeof(U64) + event->string.size; + if(available_size >= needed_size) + { + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->kind); + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->string.size); + di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); + di_shared->p2u_ring_write_pos += 7; + di_shared->p2u_ring_write_pos -= di_shared->p2u_ring_write_pos%8; + break; + } + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); + } + os_condition_variable_broadcast(di_shared->p2u_ring_cv); +} + +internal DI_EventList +di_p2u_pop_events(Arena *arena, U64 endt_us) +{ + DI_EventList events = {0}; + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) + { + DI_EventNode *n = push_array(arena, DI_EventNode, 1); + SLLQueuePush(events.first, events.last, n); + events.count += 1; + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.kind); + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.string.size); + n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); + di_shared->p2u_ring_read_pos += ring_read(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); + di_shared->p2u_ring_read_pos += 7; + di_shared->p2u_ring_read_pos -= di_shared->p2u_ring_read_pos%8; + } + else if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); + } + os_condition_variable_broadcast(di_shared->p2u_ring_cv); + return events; +} + internal void di_parse_thread__entry_point(void *p) { @@ -448,14 +518,14 @@ di_parse_thread__entry_point(void *p) //////////////////////////// //- rjf: grab next key // - String8 path = {0}; + String8 og_path = {0}; U64 min_timestamp = 0; - di_u2p_dequeue_key(scratch.arena, &path, &min_timestamp); + di_u2p_dequeue_key(scratch.arena, &og_path, &min_timestamp); //////////////////////////// //- rjf: unpack key // - U64 hash = di_hash_from_string(path); + U64 hash = di_hash_from_string(og_path); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; @@ -467,13 +537,214 @@ di_parse_thread__entry_point(void *p) B32 got_task = 0; OS_MutexScopeR(stripe->rw_mutex) { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path, min_timestamp); + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); if(node != 0) { got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); } } + //////////////////////////// + //- rjf: got task -> open O.G. file (may or may not be RDI) + // + B32 og_format_is_known = 0; + B32 og_is_pe = 0; + B32 og_is_pdb = 0; + B32 og_is_elf = 0; + B32 og_is_rdi = 0; + FileProperties og_props = {0}; + if(got_task) ProfScope("analyze %.*s", str8_varg(og_path)) + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_path); + OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); + FileProperties props = og_props = os_properties_from_file(file); + void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); + String8 data = str8((U8 *)base, props.size); + if(!og_format_is_known) + { + String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); + String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); + String8 msfxx_magic = str8_lit("Microsoft C/C++"); + if((data.size >= msf20_magic.size && str8_match(data, msf20_magic, StringMatchFlag_RightSideSloppy)) || + (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || + (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) + { + og_format_is_known = 1; + og_is_pdb = 1; + } + } + if(!og_format_is_known) + { + if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) + { + og_format_is_known = 1; + og_is_rdi = 1; + } + } + if(!og_format_is_known) + { + if(data.size >= 4 && + data.str[0] == 0x7f && + data.str[1] == 'E' && + data.str[2] == 'L' && + data.str[3] == 'F') + { + og_format_is_known = 1; + og_is_elf = 1; + } + } + if(!og_format_is_known) + { + if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) + { + og_format_is_known = 1; + og_is_pe = 1; + } + } + os_file_map_view_close(file_map, base); + os_file_map_close(file_map); + os_file_close(file); + } + + //////////////////////////// + //- rjf: given O.G. path & analysis, determine RDI path + // + String8 rdi_path = {0}; + if(got_task) + { + if(og_is_rdi) + { + rdi_path = og_path; + } + else if(og_format_is_known && og_is_pdb) + { + rdi_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + } + } + + //////////////////////////// + //- rjf: check if rdi file is up-to-date + // + B32 rdi_file_is_up_to_date = 0; + if(got_task) + { + if(rdi_path.size != 0) ProfScope("check %.*s is up-to-date", str8_varg(rdi_path)) + { + FileProperties props = os_properties_from_file_path(rdi_path); + rdi_file_is_up_to_date = (props.modified > og_props.modified); + } + } + + //////////////////////////// + //- rjf: if raddbg file is up to date based on timestamp, check the + // encoding generation number & size, to see if we need to regenerate it + // regardless + // + if(got_task && rdi_file_is_up_to_date) ProfScope("check %.*s version matches our's", str8_varg(rdi_path)) + { + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, rdi_path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); + if(sizeof(RDI_Header) <= file_props.size) + { + RDI_Header *header = (RDI_Header*)file_base; + if(header->encoding_version != RDI_ENCODING_VERSION) + { + rdi_file_is_up_to_date = 0; + } + } + else + { + rdi_file_is_up_to_date = 0; + } + os_file_map_view_close(file_map, file_base); + os_file_map_close(file_map); + os_file_close(file); + } + + //////////////////////////// + //- rjf: heuristically choose compression settings + // + B32 should_compress = 0; +#if 0 + if(og_dbg_props.size > MB(64)) + { + should_compress = 1; + } +#endif + + //////////////////////////// + //- rjf: rdi file not up-to-date? we need to generate it + // + if(got_task && !rdi_file_is_up_to_date) ProfScope("generate %.*s", str8_varg(rdi_path)) + { + if(og_is_pdb) + { + //- rjf: push conversion task begin event + { + DI_Event event = {DI_EventKind_ConversionStarted}; + event.string = rdi_path; + di_p2u_push_event(&event); + } + + //- rjf: kick off process + OS_Handle process = {0}; + { + OS_LaunchOptions opts = {0}; + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); + opts.inherit_env = 1; + opts.consoleless = 1; + str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); + if(should_compress) + { + str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); + } + //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", rdi_path); + os_launch_process(&opts, &process); + } + + //- rjf: wait for process to complete + { + U64 start_wait_t = os_now_microseconds(); + for(;;) + { + B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); + if(wait_done) + { + rdi_file_is_up_to_date = 1; + break; + } + } + } + + //- rjf: push conversion task end event + { + DI_Event event = {DI_EventKind_ConversionEnded}; + event.string = rdi_path; + di_p2u_push_event(&event); + } + } + else + { + // NOTE(rjf): we cannot convert from this O.G. debug info format right now. + //- rjf: push conversion task failure event + { + DI_Event event = {DI_EventKind_ConversionFailureUnsupportedFormat}; + event.string = rdi_path; + di_p2u_push_event(&event); + } + } + } + //////////////////////////// //- rjf: got task -> open file // @@ -483,7 +754,7 @@ di_parse_thread__entry_point(void *p) void *file_base = 0; if(got_task) { - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); file_map = os_file_map_open(OS_AccessFlag_Read, file); file_props = os_properties_from_file(file); file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); @@ -492,7 +763,7 @@ di_parse_thread__entry_point(void *p) //////////////////////////// //- rjf: do initial parse of rdi // - RDI_Parsed rdi_parsed_maybe_compressed = dbgi_parse_nil.rdi; + RDI_Parsed rdi_parsed_maybe_compressed = di_rdi_parsed_nil; if(got_task) { RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); @@ -569,7 +840,7 @@ di_parse_thread__entry_point(void *p) // if(got_task) OS_MutexScopeW(stripe->rw_mutex) { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path, min_timestamp); + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); if(node != 0) { node->is_working = 0; @@ -582,6 +853,7 @@ di_parse_thread__entry_point(void *p) node->parse_done = 1; } } + os_condition_variable_broadcast(stripe->cv); scratch_end(scratch); } diff --git a/src/dbgi2/dbgi2.h b/src/dbgi2/dbgi2.h index 9333b64b..a6857aa2 100644 --- a/src/dbgi2/dbgi2.h +++ b/src/dbgi2/dbgi2.h @@ -4,6 +4,41 @@ #ifndef DI_H #define DI_H +//////////////////////////////// +//~ rjf: Event Types + +typedef enum DI_EventKind +{ + DI_EventKind_Null, + DI_EventKind_ConversionStarted, + DI_EventKind_ConversionEnded, + DI_EventKind_ConversionFailureUnsupportedFormat, + DI_EventKind_COUNT +} +DI_EventKind; + +typedef struct DI_Event DI_Event; +struct DI_Event +{ + DI_EventKind kind; + String8 string; +}; + +typedef struct DI_EventNode DI_EventNode; +struct DI_EventNode +{ + DI_EventNode *next; + DI_Event v; +}; + +typedef struct DI_EventList DI_EventList; +struct DI_EventList +{ + DI_EventNode *first; + DI_EventNode *last; + U64 count; +}; + //////////////////////////////// //~ rjf: Cache Types @@ -108,6 +143,14 @@ struct DI_Shared U64 u2p_ring_write_pos; U64 u2p_ring_read_pos; + // rjf: parse -> user event ring + OS_Handle p2u_ring_mutex; + OS_Handle p2u_ring_cv; + U64 p2u_ring_size; + U8 *p2u_ring_base; + U64 p2u_ring_write_pos; + U64 p2u_ring_read_pos; + // rjf: threads U64 parse_thread_count; OS_Handle *parse_threads; @@ -200,6 +243,9 @@ internal RDI_Parsed *di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 pat internal B32 di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us); internal void di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp); +internal void di_p2u_push_event(DI_Event *event); +internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); + internal void di_parse_thread__entry_point(void *p); #endif // DI_H diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 412ad503..bd5b226c 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1077,7 +1077,7 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams use_numeric_eval: { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); U64 vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -1121,7 +1121,7 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams { error = push_str8f(scratch.arena, "Couldn't evaluate \"%S\" as an address", query); } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); }break; } @@ -1541,8 +1541,8 @@ df_search_tags_from_entity(Arena *arena, DF_Entity *entity) U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 procedure_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + DF_Entity *debug = df_dbgi_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_voff(scratch.arena, debug, rip_voff); if(procedure_name.size != 0) { str8_list_push(scratch.arena, &strings, procedure_name); @@ -2008,6 +2008,14 @@ df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src) df_entity_notify_mutation(entity); } +internal void +df_entity_equip_timestamp(DF_Entity *entity, U64 timestamp) +{ + df_require_entity_nonnil(entity, return); + entity->timestamp = timestamp; + df_entity_notify_mutation(entity); +} + //- rjf: control layer correllation equipment internal void @@ -2692,29 +2700,6 @@ df_core_view_rule_spec_from_string(String8 string) return spec; } -//////////////////////////////// -//~ rjf: Debug Info Mapping - -internal String8 -df_debug_info_path_from_module(Arena *arena, DF_Entity *module) -{ - ProfBeginFunction(); - String8 result = {0}; - DF_Entity *override_entity = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoOverride); - if(!df_entity_is_nil(override_entity) && override_entity->name.size != 0) - { - result = override_entity->name; - } - else - { - String8 exe_path = module->name; - String8 dbg_path = push_str8f(arena, "%S.pdb", str8_chop_last_dot(exe_path)); - result = dbg_path; - } - ProfEnd(); - return result; -} - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -2856,7 +2841,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *debug = df_dbgi_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2864,7 +2849,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -2878,7 +2863,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -2981,7 +2966,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *debug = df_dbgi_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2989,7 +2974,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -3003,7 +2988,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -3094,25 +3079,25 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> binary file +//- rjf: module <=> debug info file internal DF_Entity * -df_binary_file_from_module(DF_Entity *module) +df_dbgi_from_module(DF_Entity *module) { - DF_Entity *binary = df_entity_from_handle(module->entity_handle); - return binary; + DF_Entity *debug = df_entity_from_handle(module->entity_handle); + return debug; } internal DF_EntityList -df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info) +df_modules_from_dbgi(Arena *arena, DF_Entity *debug) { DF_EntityList list = {0}; DF_EntityList all_modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = all_modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *module_binary_info = df_binary_file_from_module(module); - if(module_binary_info == binary_info) + DF_Entity *module_debug_info = df_dbgi_from_module(module); + if(module_debug_info == debug) { df_entity_list_push(arena, &list, module); } @@ -3168,30 +3153,28 @@ df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_rng) //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: binary file -> dbgi parse +//- rjf: debug file -> rdi -internal DBGI_Parse * -df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary) +internal RDI_Parsed * +df_rdi_from_dbgi(DI_Scope *scope, DF_Entity *dbgi) { Temp scratch = scratch_begin(0, 0); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, 0); + String8 path = df_full_path_from_entity(scratch.arena, dbgi); + RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(scope, path, dbgi->timestamp, 0); scratch_end(scratch); - return dbgi; + return rdi; } //- rjf: symbol lookups internal String8 -df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) +df_symbol_name_from_dbgi_voff(Arena *arena, DF_Entity *dbgi, U64 voff) { String8 result = {0}; { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - String8 path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); if(result.size == 0 && rdi->scope_vmap != 0) { U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); @@ -3210,7 +3193,7 @@ df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) U8 *name_ptr = rdi_string_from_idx(rdi, global_var->name_string_idx, &name_size); result = push_str8_copy(arena, str8(name_ptr, name_size)); } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); } return result; @@ -3222,9 +3205,9 @@ df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr) String8 result = {0}; { DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - result = df_symbol_name_from_binary_voff(arena, binary, voff); + result = df_symbol_name_from_dbgi_voff(arena, dbgi, voff); } return result; } @@ -3240,8 +3223,8 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit src2dasm_array.v = push_array(arena, DF_TextLineSrc2DasmInfoList, src2dasm_array.count); } Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DI_Scope *scope = di_scope_open(); + DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); for(DF_EntityNode *override_n = overrides.first; override_n != 0; @@ -3250,20 +3233,18 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *binary_n = binaries.first; - binary_n != 0; - binary_n = binary_n->next) + for(DF_EntityNode *dbgi_n = dbgis.first; + dbgi_n != 0; + dbgi_n = dbgi_n->next) { // rjf: binary -> rdi - DF_Entity *binary = binary_n->entity; - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DF_Entity *dbgi = dbgi_n->entity; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; U32 src_id = 0; - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); if(mapptr != 0) @@ -3313,7 +3294,7 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.binary = binary; + src2dasm_n->v.dbgi = dbgi; SLLQueuePush(src2dasm_list->first, src2dasm_list->last, src2dasm_n); src2dasm_list->count += 1; } @@ -3324,11 +3305,11 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit // rjf: good src id -> push to relevant binaries if(good_src_id) { - df_entity_list_push(arena, &src2dasm_array.binaries, binary); + df_entity_list_push(arena, &src2dasm_array.dbgis, dbgi); } } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); return src2dasm_array; } @@ -3336,15 +3317,13 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit //- rjf: voff -> src lookups internal DF_TextLineDasm2SrcInfo -df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) +df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff) { Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); - String8 path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); DF_TextLineDasm2SrcInfo result = {0}; - result.file = result.binary = &df_g_nil_entity; + result.file = result.dbgi = &df_g_nil_entity; if(rdi->unit_vmap != 0 && rdi->units != 0 && rdi->source_files != 0) { U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); @@ -3359,7 +3338,7 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) RDI_SourceFile *file = &rdi->source_files[line->file_idx]; String8 file_normalized_full_path = {0}; file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); - result.binary = binary; + result.dbgi = dbgi; if(line->file_idx != 0 && file_normalized_full_path.size != 0) { result.file = df_entity_from_path(file_normalized_full_path, DF_EntityFromPathFlag_All); @@ -3368,8 +3347,7 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) result.voff_range = r1u64(unit_line_info.voffs[line_info_idx], unit_line_info.voffs[line_info_idx+1]); } } - - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); return result; } @@ -3377,22 +3355,20 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) //- rjf: symbol -> voff lookups internal U64 -df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) +df_voff_from_dbgi_symbol_name(DF_Entity *dbgi, String8 symbol_name) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 result = 0; { - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); RDI_NameMapKind name_map_kinds[] = { RDI_NameMapKind_GlobalVariables, RDI_NameMapKind_Procedures, }; - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { for(U64 name_map_kind_idx = 0; name_map_kind_idx < ArrayCount(name_map_kinds); @@ -3453,23 +3429,20 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) } } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); return result; } internal U64 -df_type_num_from_binary_name(DF_Entity *binary, String8 name) +df_type_num_from_dbgi_name(DF_Entity *dbgi, String8 name) { ProfBeginFunction(); - DBGI_Scope *scope = dbgi_scope_open(); - Temp scratch = scratch_begin(0, 0); + DI_Scope *scope = di_scope_open(); U64 result = 0; { - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Types); RDI_ParsedNameMap parsed_name_map = {0}; rdi_name_map_parse(rdi, name_map, &parsed_name_map); @@ -3496,16 +3469,13 @@ df_type_num_from_binary_name(DF_Entity *binary, String8 name) } result = entity_num; } - scratch_end(scratch); - dbgi_scope_close(scope); + di_scope_close(scope); ProfEnd(); return result; } //////////////////////////////// -//~ rjf: Process/Thread Info Lookups - -//- rjf: thread info extraction helpers +//~ rjf: Process/Thread/Module Info Lookups internal DF_Entity * df_module_from_process_vaddr(DF_Entity *process, U64 vaddr) @@ -3538,7 +3508,6 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 ProfBeginFunction(); U64 base_vaddr = 0; Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); if(!df_ctrl_targets_running()) { //- rjf: unpack module info @@ -3611,7 +3580,6 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } #endif } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); return base_vaddr; @@ -3624,26 +3592,18 @@ df_architecture_from_entity(DF_Entity *entity) } internal EVAL_String2NumMap * -df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +df_push_locals_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff) { - Temp scratch = scratch_begin(&arena, 1); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); EVAL_String2NumMap *result = eval_push_locals_map_from_rdi_voff(arena, rdi, voff); - scratch_end(scratch); return result; } internal EVAL_String2NumMap * -df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +df_push_member_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff) { - Temp scratch = scratch_begin(&arena, 1); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); EVAL_String2NumMap *result = eval_push_member_map_from_rdi_voff(arena, rdi, voff); - scratch_end(scratch); return result; } @@ -3765,7 +3725,6 @@ df_push_ctrl_msg(CTRL_Msg *msg) internal void df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_TrapList *run_traps) { - DBGI_Scope *scope = dbgi_scope_open(); Temp scratch = scratch_begin(0, 0); // rjf: build run message @@ -3881,7 +3840,6 @@ df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_Tra df_state->ctrl_ctx.unwind_count = 0; scratch_end(scratch); - dbgi_scope_close(scope); } //- rjf: stopped info from the control thread @@ -3914,22 +3872,20 @@ df_eval_memory_read(void *u, void *out, U64 addr, U64 size) } internal EVAL_ParseCtx -df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 vaddr) +df_eval_parse_ctx_from_process_vaddr(DI_Scope *scope, DF_Entity *process, U64 vaddr) { Temp scratch = scratch_begin(0, 0); //- rjf: extract info DF_Entity *module = df_module_from_process_vaddr(process, vaddr); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DF_Entity *debug = df_dbgi_from_module(module); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, debug); Architecture arch = df_architecture_from_entity(process); EVAL_String2NumMap *reg_map = ctrl_string2reg_from_arch(arch); EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, voff); - EVAL_String2NumMap *member_map = df_query_cached_member_map_from_binary_voff(binary, voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_voff(debug, voff); + EVAL_String2NumMap *member_map = df_query_cached_member_map_from_dbgi_voff(debug, voff); //- rjf: build ctx EVAL_ParseCtx ctx = zero_struct; @@ -3948,11 +3904,11 @@ df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 } internal EVAL_ParseCtx -df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) +df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) { Temp scratch = scratch_begin(0, 0); EVAL_ParseCtx ctx = zero_struct; - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); DF_TextLineSrc2DasmInfoList src2dasm_list = {0}; //- rjf: search for line info in all binaries for this file:pt @@ -3964,15 +3920,13 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *binary_n = binaries.first; - binary_n != 0; - binary_n = binary_n->next) + for(DF_EntityNode *dbgi_n = dbgis.first; + dbgi_n != 0; + dbgi_n = dbgi_n->next) { - // rjf: binary -> rdi - DF_Entity *binary = binary_n->entity; - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + // rjf: debug file -> rdi + DF_Entity *dbgi = dbgi_n->entity; + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -4018,7 +3972,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(scratch.arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.binary = binary; + src2dasm_n->v.dbgi = dbgi; SLLQueuePush(src2dasm_list.first, src2dasm_list.last, src2dasm_n); src2dasm_list.count += 1; } @@ -4033,7 +3987,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list.first; n != 0; n = n->next) { DF_TextLineSrc2DasmInfo *src2dasm = &n->v; - DF_EntityList modules = df_modules_from_binary_file(scratch.arena, src2dasm->binary); + DF_EntityList modules = df_modules_from_dbgi(scratch.arena, src2dasm->dbgi); if(modules.count != 0) { DF_Entity *module = modules.first->entity; @@ -4050,7 +4004,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) //- rjf: bad ctx -> reset with graceful defaults if(good_ctx == 0) { - ctx.rdi = &dbgi_parse_nil.rdi; + ctx.rdi = &di_rdi_parsed_nil; ctx.type_graph = tg_graph_begin(8, 256); ctx.regs_map = &eval_string2num_map_nil; ctx.regs_map = &eval_string2num_map_nil; @@ -4064,7 +4018,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) } internal DF_Eval -df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string) +df_eval_from_string(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -4179,9 +4133,9 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ { U64 vaddr = result.imm_u64; DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, voff); + String8 symbol_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, voff); if(symbol_name.size != 0) { result.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, tg_key_basic(TG_Kind_Void), 0); @@ -4339,7 +4293,7 @@ df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx } internal DF_Eval -df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg) +df_eval_from_eval_cfg_table(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg) { ProfBeginFunction(); @@ -4969,8 +4923,8 @@ df_eval_viz_block_split_and_continue(Arena *arena, DF_EvalVizBlockList *list, DF continue_block->string = split_block->string; continue_block->member = split_block->member; continue_block->visual_idx_range = continue_block->semantic_idx_range = r1u64(split_idx+1, total_count); - continue_block->backing_search_items = split_block->backing_search_items; - continue_block->dbgi_target = split_block->dbgi_target; + continue_block->fzy_backing_items = split_block->fzy_backing_items; + continue_block->fzy_target = split_block->fzy_target; continue_block->cfg_table = split_block->cfg_table; continue_block->link_member_type_key = split_block->link_member_type_key; continue_block->link_member_off = split_block->link_member_off; @@ -4988,7 +4942,7 @@ df_eval_viz_block_end(DF_EvalVizBlockList *list, DF_EvalVizBlock *block) } internal void -df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *eval_view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out) +df_append_viz_blocks_for_parent__rec(Arena *arena, DI_Scope *scope, DF_EvalView *eval_view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -5394,7 +5348,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie } internal DF_EvalVizBlockList -df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key) +df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key) { ProfBeginFunction(); DF_EvalVizBlockList blocks = {0}; @@ -5475,9 +5429,9 @@ df_row_num_from_viz_block_list_key(DF_EvalVizBlockList *blocks, DF_ExpandKey key { B32 this_block_contains_this_key = 0; { - if(block->backing_search_items.v != 0) + if(block->fzy_backing_items.v != 0) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&block->backing_search_items, key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&block->fzy_backing_items, key.child_num); this_block_contains_this_key = (item_num != 0 && contains_1u64(block->semantic_idx_range, item_num-1)); } else @@ -5488,9 +5442,9 @@ df_row_num_from_viz_block_list_key(DF_EvalVizBlockList *blocks, DF_ExpandKey key if(this_block_contains_this_key) { found = 1; - if(block->backing_search_items.v != 0) + if(block->fzy_backing_items.v != 0) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&block->backing_search_items, key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&block->fzy_backing_items, key.child_num); row_num += item_num-1-block->semantic_idx_range.min; } else @@ -5524,12 +5478,12 @@ df_key_from_viz_block_list_row_num(DF_EvalVizBlockList *blocks, S64 row_num) if(contains_1s64(vb_row_num_range, row_num)) { key = vb->key; - if(vb->backing_search_items.v != 0) + if(vb->fzy_backing_items.v != 0) { U64 item_idx = (U64)((row_num - vb_row_num_range.min) + vb->semantic_idx_range.min); - if(item_idx < vb->backing_search_items.count) + if(item_idx < vb->fzy_backing_items.count) { - key.child_num = vb->backing_search_items.v[item_idx].idx; + key.child_num = vb->fzy_backing_items.v[item_idx].idx; } } else @@ -6159,17 +6113,17 @@ df_query_cached_entity_list_with_kind(DF_EntityKind kind) } internal DF_EntityList -df_push_active_binary_list(Arena *arena) +df_push_active_dbgi_list(Arena *arena) { - DF_EntityList binaries = {0}; + DF_EntityList dbgis = {0}; DF_EntityList modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *binary = df_binary_file_from_module(module); - df_entity_list_push(arena, &binaries, binary); + DF_Entity *dbgi = df_dbgi_from_module(module); + df_entity_list_push(arena, &dbgis, dbgi); } - return binaries; + return dbgis; } internal DF_EntityList @@ -6328,7 +6282,7 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo } internal EVAL_String2NumMap * -df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) +df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6344,14 +6298,14 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(binary); + DF_Handle handle = df_handle_from_entity(dbgi); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->binary, handle) && n->voff == voff) + if(df_handle_match(n->dbgi, handle) && n->voff == voff) { node = n; break; @@ -6359,17 +6313,17 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } if(node == 0) { - DBGI_Scope *scope = dbgi_scope_open(); - EVAL_String2NumMap *map = df_push_locals_map_from_binary_voff(cache->arena, scope, binary, voff); + DI_Scope *scope = di_scope_open(); + EVAL_String2NumMap *map = df_push_locals_map_from_dbgi_voff(cache->arena, scope, dbgi, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->binary = handle; + node->dbgi = handle; node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - dbgi_scope_close(scope); + di_scope_close(scope); } if(node != 0 && node->locals_map->slots_count != 0) { @@ -6382,7 +6336,7 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } internal EVAL_String2NumMap * -df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) +df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6398,14 +6352,14 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(binary); + DF_Handle handle = df_handle_from_entity(dbgi); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->binary, handle) && n->voff == voff) + if(df_handle_match(n->dbgi, handle) && n->voff == voff) { node = n; break; @@ -6413,17 +6367,17 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) } if(node == 0) { - DBGI_Scope *scope = dbgi_scope_open(); - EVAL_String2NumMap *map = df_push_member_map_from_binary_voff(cache->arena, scope, binary, voff); + DI_Scope *scope = di_scope_open(); + EVAL_String2NumMap *map = df_push_member_map_from_dbgi_voff(cache->arena, scope, dbgi, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->binary = handle; + node->dbgi = handle; node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - dbgi_scope_close(scope); + di_scope_close(scope); } if(node != 0 && node->locals_map->slots_count != 0) { @@ -6745,9 +6699,9 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *debug = df_dbgi_from_module(module); U64 stop_thread_voff = df_voff_from_vaddr(module, stop_thread_vaddr); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, stop_thread_voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, stop_thread_voff); DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = user_bps.first; n != 0; n = n->next) { @@ -6926,11 +6880,13 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_equip_name(0, module, event->string); df_entity_equip_vaddr_rng(module, event->vaddr_rng); df_entity_equip_vaddr(module, event->rip_vaddr); + df_entity_equip_timestamp(module, event->timestamp); - // rjf: create & attach binary file - String8 bin_path = module->name; - DF_Entity *binary = df_entity_from_path(bin_path, DF_EntityFromPathFlag_All); - df_entity_equip_entity_handle(module, df_handle_from_entity(binary)); + // rjf: create & attach debug info path + CTRL_Entity *ctrl_module = ctrl_entity_from_machine_id_handle(df_state->ctrl_entity_store, event->machine_id, event->entity); + CTRL_Entity *ctrl_debug_info = ctrl_entity_child_from_kind(ctrl_module, CTRL_EntityKind_DebugInfoPath); + DF_Entity *debug_info = df_entity_from_path(ctrl_debug_info->string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + df_entity_equip_entity_handle(module, df_handle_from_entity(debug_info)); // rjf: is first -> find target, equip process & module & first thread with target color if(is_first) @@ -6977,6 +6933,15 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_mark_for_deletion(module); }break; + //- rjf: debug info changes + + case CTRL_EventKind_ModuleDebugInfoPathChange: + { + DF_Entity *module = df_entity_from_ctrl_handle(event->machine_id, event->entity); + DF_Entity *debug_info = df_entity_from_path(event->string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + df_entity_equip_entity_handle(module, df_handle_from_entity(debug_info)); + }break; + //- rjf: debug strings case CTRL_EventKind_DebugString: @@ -7089,23 +7054,23 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) scratch_end(scratch); } - //- rjf: sync with dbgi parsers - ProfScope("sync with dbgi parsers") + //- rjf: sync with di parsers + ProfScope("sync with di parsers") { Temp scratch = scratch_begin(&arena, 1); - DBGI_EventList events = dbgi_p2u_pop_events(scratch.arena, 0); - for(DBGI_EventNode *n = events.first; n != 0; n = n->next) + DI_EventList events = di_p2u_pop_events(scratch.arena, 0); + for(DI_EventNode *n = events.first; n != 0; n = n->next) { - DBGI_Event *event = &n->v; + DI_Event *event = &n->v; switch(event->kind) { default:{}break; - case DBGI_EventKind_ConversionStarted: + case DI_EventKind_ConversionStarted: { DF_Entity *task = df_entity_alloc(0, df_entity_root(), DF_EntityKind_ConversionTask); df_entity_equip_name(0, task, event->string); }break; - case DBGI_EventKind_ConversionEnded: + case DI_EventKind_ConversionEnded: { DF_Entity *task = df_entity_from_name_and_kind(event->string, DF_EntityKind_ConversionTask); if(!df_entity_is_nil(task)) @@ -7113,7 +7078,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_mark_for_deletion(task); } }break; - case DBGI_EventKind_ConversionFailureUnsupportedFormat: + case DI_EventKind_ConversionFailureUnsupportedFormat: { // DF_Entity *task = df_entity_alloc(df_entity_root(), DF_EntityKind_ConversionFail); // df_entity_equip_name(task, event->string); diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 302d030c..49dbfa0d 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -265,10 +265,10 @@ struct DF_Eval //////////////////////////////// //~ rjf: View Rule Hook Types -#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(name) DF_Eval name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, struct DF_CfgVal *val) +#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(name) DF_Eval name(Arena *arena, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, struct DF_CfgVal *val) #define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name) df_core_view_rule_eval_resolution__##name #define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name)) -#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(name) void name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_EvalView *eval_view, DF_Eval eval, String8 string, struct DF_CfgTable *cfg_table, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth, struct DF_CfgNode *cfg, struct DF_EvalVizBlockList *out) +#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(name) void name(Arena *arena, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_EvalView *eval_view, DF_Eval eval, String8 string, struct DF_CfgTable *cfg_table, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth, struct DF_CfgNode *cfg, struct DF_EvalVizBlockList *out) #define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name) df_core_view_rule_viz_block_prod__##name #define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name)) typedef DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CoreViewRuleEvalResolutionHookFunctionType); @@ -521,7 +521,7 @@ struct DF_TextLineSrc2DasmInfo { Rng1U64 voff_range; S64 remap_line; - DF_Entity *binary; + DF_Entity *dbgi; }; typedef struct DF_TextLineSrc2DasmInfoNode DF_TextLineSrc2DasmInfoNode; @@ -543,7 +543,7 @@ typedef struct DF_TextLineSrc2DasmInfoListArray DF_TextLineSrc2DasmInfoListArray struct DF_TextLineSrc2DasmInfoListArray { DF_TextLineSrc2DasmInfoList *v; - DF_EntityList binaries; + DF_EntityList dbgis; U64 count; }; @@ -552,7 +552,7 @@ struct DF_TextLineSrc2DasmInfoListArray typedef struct DF_TextLineDasm2SrcInfo DF_TextLineDasm2SrcInfo; struct DF_TextLineDasm2SrcInfo { - DF_Entity *binary; + DF_Entity *dbgi; DF_Entity *file; TxtPt pt; Rng1U64 voff_range; @@ -708,8 +708,8 @@ struct DF_EvalVizBlock // rjf: info about ranges that this block spans Rng1U64 visual_idx_range; Rng1U64 semantic_idx_range; - DBGI_FuzzySearchTarget dbgi_target; - DBGI_FuzzySearchItemArray backing_search_items; + FZY_Target fzy_target; + FZY_ItemArray fzy_backing_items; // rjf: visualization config extensions DF_CfgTable cfg_table; @@ -1004,7 +1004,7 @@ typedef struct DF_RunLocalsCacheNode DF_RunLocalsCacheNode; struct DF_RunLocalsCacheNode { DF_RunLocalsCacheNode *hash_next; - DF_Handle binary; + DF_Handle dbgi; U64 voff; EVAL_String2NumMap *locals_map; }; @@ -1459,6 +1459,7 @@ internal void df_entity_equip_color_rgba(DF_Entity *entity, Vec4F32 rgba); internal void df_entity_equip_color_hsva(DF_Entity *entity, Vec4F32 hsva); internal void df_entity_equip_death_timer(DF_Entity *entity, F32 seconds_til_death); internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src); +internal void df_entity_equip_timestamp(DF_Entity *entity, U64 timestamp); //- rjf: control layer correllation equipment internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id); @@ -1507,11 +1508,6 @@ internal DF_CmdSpecList df_push_cmd_spec_list(Arena *arena); internal void df_register_core_view_rule_specs(DF_CoreViewRuleSpecInfoArray specs); internal DF_CoreViewRuleSpec *df_core_view_rule_spec_from_string(String8 string); -//////////////////////////////// -//~ rjf: Debug Info Mapping - -internal String8 df_debug_info_path_from_module(Arena *arena, DF_Entity *module); - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -1522,9 +1518,9 @@ internal CTRL_TrapList df_trap_net_from_thread__step_into_line(Arena *arena, DF_ //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> binary file -internal DF_Entity *df_binary_file_from_module(DF_Entity *module); -internal DF_EntityList df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info); +//- rjf: module <=> debug info file +internal DF_Entity *df_dbgi_from_module(DF_Entity *module); +internal DF_EntityList df_modules_from_dbgi(Arena *arena, DF_Entity *debug); //- rjf: voff <=> vaddr internal U64 df_base_vaddr_from_module(DF_Entity *module); @@ -1536,33 +1532,32 @@ internal Rng1U64 df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_ //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: binary file -> dbgi parse -internal DBGI_Parse *df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary); +//- rjf: debug file -> rdi +internal RDI_Parsed *df_rdi_from_dbgi(DI_Scope *scope, DF_Entity *dbgi); //- rjf: voff|vaddr -> symbol lookups -internal String8 df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff); +internal String8 df_symbol_name_from_dbgi_voff(Arena *arena, DF_Entity *dbgi, U64 voff); internal String8 df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr); //- rjf: src -> voff lookups internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entity *file, Rng1S64 line_num_range); //- rjf: voff -> src lookups -internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff); +internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff); //- rjf: symbol -> voff lookups -internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name); -internal U64 df_type_num_from_binary_name(DF_Entity *binary, String8 name); +internal U64 df_voff_from_dbgi_symbol_name(DF_Entity *dbgi, String8 symbol_name); +internal U64 df_type_num_from_dbgi_name(DF_Entity *dbgi, String8 name); //////////////////////////////// -//~ rjf: Process/Thread Info Lookups +//~ rjf: Process/Thread/Module Info Lookups -//- rjf: thread info extraction helpers internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); internal DF_Entity *df_module_from_thread(DF_Entity *thread); internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal Architecture df_architecture_from_entity(DF_Entity *entity); -internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); -internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_push_locals_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff); +internal EVAL_String2NumMap *df_push_member_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff); internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); internal DF_Entity *df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates); @@ -1587,12 +1582,12 @@ internal CTRL_Event df_ctrl_last_stop_event(void); //~ rjf: Evaluation internal B32 df_eval_memory_read(void *u, void *out, U64 addr, U64 size); -internal EVAL_ParseCtx df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 vaddr); -internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt); -internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string); +internal EVAL_ParseCtx df_eval_parse_ctx_from_process_vaddr(DI_Scope *scope, DF_Entity *process, U64 vaddr); +internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt); +internal DF_Eval df_eval_from_string(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string); internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); internal DF_Eval df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); -internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg); +internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg); //////////////////////////////// //~ rjf: Evaluation Views @@ -1630,8 +1625,8 @@ internal DF_EvalLinkBaseArray df_eval_link_base_array_from_chunk_list(Arena *are internal DF_EvalVizBlock *df_eval_viz_block_begin(Arena *arena, DF_EvalVizBlockKind kind, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth); internal DF_EvalVizBlock *df_eval_viz_block_split_and_continue(Arena *arena, DF_EvalVizBlockList *list, DF_EvalVizBlock *split_block, U64 split_idx); internal void df_eval_viz_block_end(DF_EvalVizBlockList *list, DF_EvalVizBlock *block); -internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); -internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key); +internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key); internal void df_eval_viz_block_list_concat__in_place(DF_EvalVizBlockList *dst, DF_EvalVizBlockList *to_push); //- rjf: viz block list <-> table coordinates @@ -1684,7 +1679,7 @@ internal String8 df_info_summary_from_string(Architecture arch, String8 string); //- rjf: entity kind cache internal DF_EntityList df_query_cached_entity_list_with_kind(DF_EntityKind kind); -internal DF_EntityList df_push_active_binary_list(Arena *arena); +internal DF_EntityList df_push_active_dbgi_list(Arena *arena); internal DF_EntityList df_push_active_target_list(Arena *arena); //- rjf: per-run caches @@ -1692,8 +1687,8 @@ internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal U64 df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); -internal EVAL_String2NumMap *df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff); -internal EVAL_String2NumMap *df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff); +internal EVAL_String2NumMap *df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff); //- rjf: top-level command dispatch internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 04a5edbc..bca2d81d 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -583,17 +583,17 @@ df_queue_drag_drop(void) } internal void -df_set_hovered_line_info(DF_Entity *binary, U64 voff) +df_set_hovered_line_info(DF_Entity *dbgi, U64 voff) { - df_gfx_state->hover_line_binary = df_handle_from_entity(binary); + df_gfx_state->hover_line_dbgi = df_handle_from_entity(dbgi); df_gfx_state->hover_line_voff = voff; df_gfx_state->hover_line_set_this_frame = 1; } internal DF_Entity * -df_get_hovered_line_info_binary(void) +df_get_hovered_line_info_dbgi(void) { - return df_entity_from_handle(df_gfx_state->hover_line_binary); + return df_entity_from_handle(df_gfx_state->hover_line_dbgi); } internal U64 @@ -2488,7 +2488,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: thread finding case DF_CoreCmdKind_FindThread: { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_Entity *thread = df_entity_from_handle(params.entity); U64 unwind_count = params.index; if(thread->kind == DF_EntityKind_Thread) @@ -2499,15 +2499,15 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *debug = df_dbgi_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, debug); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, rip_voff); // rjf: snap to resolved line B32 missing_rip = (rip_vaddr == 0); - B32 binary_missing = (binary->flags & DF_EntityFlag_IsMissing); - B32 dbg_info_pending = !binary_missing && dbgi == &dbgi_parse_nil; + B32 binary_missing = (debug->flags & DF_EntityFlag_IsMissing); + B32 dbg_info_pending = !binary_missing && rdi == &di_rdi_parsed_nil; B32 has_line_info = (line_info.voff_range.max != line_info.voff_range.min); B32 has_module = !df_entity_is_nil(module); B32 has_dbg_info = has_module && !binary_missing; @@ -2537,7 +2537,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); } } - dbgi_scope_close(scope); + di_scope_close(scope); }break; case DF_CoreCmdKind_FindSelectedThread: { @@ -2561,17 +2561,17 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: try to resolve name as a symbol U64 voff = 0; - DF_Entity *voff_binary = &df_g_nil_entity; + DF_Entity *voff_dbgi = &df_g_nil_entity; if(name_resolved == 0) { - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); - for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) + DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); + for(DF_EntityNode *n = dbgis.first; n != 0; n = n->next) { - U64 binary_voff = df_voff_from_binary_symbol_name(n->entity, name); + U64 binary_voff = df_voff_from_dbgi_symbol_name(n->entity, name); if(binary_voff != 0) { voff = binary_voff; - voff_binary = n->entity; + voff_dbgi = n->entity; name_resolved = 1; break; } @@ -2680,19 +2680,25 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: name resolved to voff * dbg info if(name_resolved != 0 && voff != 0) { - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(voff_binary, voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(voff_dbgi, voff); DF_CmdParams p = params; { p.file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); p.text_point = dasm2src_info.pt; df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); df_cmd_params_mark_slot(&p, DF_CmdParamSlot_TextPoint); - if(!df_entity_is_nil(voff_binary)) + if(!df_entity_is_nil(voff_dbgi)) { - p.entity = df_handle_from_entity(voff_binary); - p.voff = dasm2src_info.voff_range.min; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualOff); + DF_EntityList modules = df_modules_from_dbgi(scratch.arena, voff_dbgi); + DF_Entity *module = df_first_entity_from_list(&modules); + DF_Entity *process = df_entity_ancestor_from_kind(module, DF_EntityKind_Process); + if(!df_entity_is_nil(process)) + { + p.entity = df_handle_from_entity(process); + p.vaddr = module->vaddr_rng.min + dasm2src_info.voff_range.min; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualAddr); + } } } df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); @@ -2911,7 +2917,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { for(DF_TextLineSrc2DasmInfoNode *n = src2dasm.v[src2dasm_idx].first; n != 0; n = n->next) { - DF_EntityList modules = df_modules_from_binary_file(scratch.arena, n->v.binary); + DF_EntityList modules = df_modules_from_dbgi(scratch.arena, n->v.dbgi); DF_Entity *module = df_module_from_thread_candidates(thread, &modules); vaddr = df_vaddr_from_voff(module, n->v.voff_range.min); goto end_lookup; @@ -3411,26 +3417,10 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) case DF_EntityKind_Module: { - DF_Entity *bin_file = df_binary_file_from_module(entity); - if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "Inspect Binary File Memory"))) - { - DF_CmdParams params = df_cmd_params_from_panel(ws, panel); - params.entity = df_handle_from_entity(bin_file); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); - ui_ctx_menu_close(); - } - if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "View Binary File Disassembly"))) - { - DF_CmdParams params = df_cmd_params_from_panel(ws, panel); - params.entity = df_handle_from_entity(bin_file); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); - ui_ctx_menu_close(); - } }break; case DF_EntityKind_Process: { +#if 0 if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Process Log"))) { DF_Entity *log = df_log_from_entity(entity); @@ -3440,9 +3430,11 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); ui_ctx_menu_close(); } +#endif }break; case DF_EntityKind_Thread: { +#if 0 if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Thread Log"))) { DF_Entity *log = df_log_from_entity(entity); @@ -3452,6 +3444,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); ui_ctx_menu_close(); } +#endif }break; } } @@ -3928,9 +3921,9 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[frame_idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); if(symbol.size != 0) { str8_list_pushf(scratch.arena, &lines, "0x%I64x: %S", rip_vaddr, symbol); @@ -4255,7 +4248,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); //- rjf: gather lister items DF_AutoCompListerItemChunkList item_list = {0}; @@ -4263,7 +4256,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: gather locals if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Locals) { - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, thread_rip_voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_voff(dbgi, thread_rip_voff); for(EVAL_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) { DF_AutoCompListerItem item = {0}; @@ -5716,7 +5709,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_CtrlCtx ctrl_ctx = ws->hover_eval_ctrl_ctx; DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -5983,7 +5976,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); } } @@ -8311,7 +8304,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags } internal DF_EvalVizWindowedRowList -df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks) +df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -8697,12 +8690,12 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { // rjf: unpack info about this row - String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->dbgi_target, block->backing_search_items.v[idx].idx); + String8 name = push_str8f(arena, "Item %I64u", idx); // TODO(rjf): dbgi_fuzzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->dbgi_target, block->fzy_backing_items.v[idx].idx); // rjf: get keys for this row DF_ExpandKey parent_key = block->parent_key; DF_ExpandKey key = block->key; - key.child_num = block->backing_search_items.v[idx].idx; + key.child_num = block->fzy_backing_items.v[idx].idx; // rjf: get eval for this row DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, macro_map, name); @@ -9942,9 +9935,9 @@ df_entity_tooltips(DF_Entity *entity) { U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); UI_PrefWidth(ui_children_sum(1)) UI_Row { UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("0x%I64x", rip_vaddr); @@ -10138,8 +10131,8 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 procedure_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + DF_Entity *dbgi = df_dbgi_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); if(procedure_name.size != 0) { FuzzyMatchRangeList fuzzy_matches = {0}; @@ -10582,7 +10575,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -10649,7 +10642,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ n != 0; n = n->next) { - if(n->v.binary == binary) + if(n->v.dbgi == dbgi) { line_info = &n->v; break; @@ -10964,7 +10957,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // UI_Focus(UI_FocusKind_Off) { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; line_num < params->line_num_range.max; @@ -11029,7 +11022,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } } } - dbgi_scope_close(scope); + di_scope_close(scope); } ////////////////////////////// @@ -11257,11 +11250,11 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(params->line_src2dasm[line_slice_idx].first != 0 && params->line_src2dasm[line_slice_idx].first->v.remap_line == mouse_pt.line) { - df_set_hovered_line_info(params->line_src2dasm[line_slice_idx].first->v.binary, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(params->line_src2dasm[line_slice_idx].first->v.dbgi, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); } if(params->line_dasm2src[line_slice_idx].first != 0) { - df_set_hovered_line_info(params->line_dasm2src[line_slice_idx].first->v.binary, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(params->line_dasm2src[line_slice_idx].first->v.dbgi, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); } } @@ -11399,7 +11392,6 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } if(dasm2src_info != 0) { - DF_Entity *binary = dasm2src_info->binary; has_line_info = 1; line_info_line_num = dasm2src_info->pt.line; line_info_t = selected_thread_module->alive_t; @@ -11426,7 +11418,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // UI_Parent(text_container_box) ProfScope("build line text") UI_Focus(UI_FocusKind_Off) { - DF_Entity *hovered_line_binary = df_get_hovered_line_info_binary(); + DF_Entity *hovered_line_dbgi = df_get_hovered_line_info_dbgi(); U64 hovered_line_voff = df_get_hovered_line_info_voff(); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); UI_WidthFill @@ -11501,12 +11493,12 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(token->kind == TXT_TokenKind_Identifier || token->kind == TXT_TokenKind_Keyword) { B32 mapped_special = 0; - for(DF_EntityNode *n = params->relevant_binaries.first; n != 0; n = n->next) + for(DF_EntityNode *n = params->relevant_dbgis.first; n != 0; n = n->next) { - DF_Entity *binary = n->entity; + DF_Entity *dbgi = n->entity; if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 voff = df_voff_from_binary_symbol_name(binary, token_string); + U64 voff = df_voff_from_dbgi_symbol_name(dbgi, token_string); if(voff != 0) { mapped_special = 1; @@ -11516,7 +11508,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 type_num = df_type_num_from_binary_name(binary, token_string); + U64 type_num = df_type_num_from_dbgi_name(dbgi, token_string); if(type_num != 0) { mapped_special = 1; @@ -11708,7 +11700,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list->first; n != 0; n = n->next) { if(n->v.remap_line == line_num && - n->v.binary == hovered_line_binary && + n->v.dbgi == hovered_line_dbgi && n->v.voff_range.min <= hovered_line_voff && hovered_line_voff < n->v.voff_range.max) { matches = 1; @@ -11721,8 +11713,8 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // rjf: check dasm2src if(dasm2src_list->first != 0) { - DF_Entity *binary = dasm2src_list->first->v.binary; - if(binary == hovered_line_binary) + DF_Entity *dbgi = dasm2src_list->first->v.dbgi; + if(dbgi == hovered_line_dbgi) { for(DF_TextLineDasm2SrcInfoNode *n = dasm2src_list->first; n != 0; n = n->next) { @@ -13829,7 +13821,7 @@ df_gfx_end_frame(void) //- rjf: clear hover line info if(df_gfx_state->hover_line_set_this_frame == 0) { - df_gfx_state->hover_line_binary = df_handle_zero(); + df_gfx_state->hover_line_dbgi = df_handle_zero(); df_gfx_state->hover_line_voff = 0; } diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index a7c1b964..54d06be3 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -300,11 +300,11 @@ enum #define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name) df_gfx_view_rule_line_stringize__##name #define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(name) internal DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name)) -#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(name) void name(DF_ExpandKey key, DF_Eval eval, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg) +#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(name) void name(DF_ExpandKey key, DF_Eval eval, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg) #define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name) df_gfx_view_rule_row_ui__##name #define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name)) -#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, DF_ExpandKey key, DF_Eval eval, String8 string, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg, Vec2F32 dim) +#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, DF_ExpandKey key, DF_Eval eval, String8 string, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg, Vec2F32 dim) #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name) df_gfx_view_rule_block_ui__##name #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name)) @@ -405,7 +405,7 @@ struct DF_CodeSliceParams DF_EntityList *line_pins; DF_TextLineDasm2SrcInfoList *line_dasm2src; DF_TextLineSrc2DasmInfoList *line_src2dasm; - DF_EntityList relevant_binaries; + DF_EntityList relevant_dbgis; // rjf: visual parameters F_Tag font; @@ -714,7 +714,7 @@ struct DF_GfxState DF_DragDropState drag_drop_state; // rjf: hover line info correllation state - DF_Handle hover_line_binary; + DF_Handle hover_line_dbgi; U64 hover_line_voff; B32 hover_line_set_this_frame; @@ -871,8 +871,8 @@ internal B32 df_drag_drop(DF_DragDropPayload *out_payload); internal void df_drag_kill(void); internal void df_queue_drag_drop(void); -internal void df_set_hovered_line_info(DF_Entity *binary, U64 voff); -internal DF_Entity *df_get_hovered_line_info_binary(void); +internal void df_set_hovered_line_info(DF_Entity *dbgi, U64 voff); +internal DF_Entity *df_get_hovered_line_info_dbgi(void); internal U64 df_get_hovered_line_info_voff(void); //////////////////////////////// @@ -930,7 +930,7 @@ internal void df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdLis internal String8 df_eval_escaped_from_raw_string(Arena *arena, String8 raw); internal String8List df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table); -internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); +internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); //////////////////////////////// //~ rjf: Hover Eval diff --git a/src/df/gfx/df_view_rules.c b/src/df/gfx/df_view_rules.c index c17b4cf4..3a8c889a 100644 --- a/src/df/gfx/df_view_rules.c +++ b/src/df/gfx/df_view_rules.c @@ -23,7 +23,7 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) str8_list_push(scratch.arena, &array_size_expr_strs, child->string); } String8 array_size_expr = str8_list_join(scratch.arena, &array_size_expr_strs, 0); - DF_Eval array_size_eval = df_eval_from_string(arena, dbgi_scope, ctrl_ctx, parse_ctx, macro_map, array_size_expr); + DF_Eval array_size_eval = df_eval_from_string(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, array_size_expr); DF_Eval array_size_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, array_size_eval); eval_error_list_concat_in_place(&eval.errors, &array_size_eval.errors); array_size = array_size_eval_value.imm_u64; @@ -468,7 +468,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) //~ rjf: "text" internal DF_TxtTopologyInfo -df_vr_txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_TxtTopologyInfo result = zero_struct; @@ -526,7 +526,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) // DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - DF_TxtTopologyInfo top = df_vr_txt_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_TxtTopologyInfo top = df_vr_txt_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); @@ -609,7 +609,7 @@ DF_VIEW_UI_FUNCTION_DEF(text) //~ rjf: "disasm" internal DF_DisasmTopologyInfo -df_vr_disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_DisasmTopologyInfo result = zero_struct; @@ -668,7 +668,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) state->last_open_frame_idx = df_frame_index(); { //- rjf: unpack params - DF_DisasmTopologyInfo top = df_vr_disasm_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_DisasmTopologyInfo top = df_vr_disasm_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); //- rjf: resolve to address value & range DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); @@ -691,7 +691,6 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) dasm_params.style_flags = DASM_StyleFlag_Addresses; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = 0; - dasm_params.exe_path = str8_zero(); } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &data_hash); String8 dasm_text_data = {0}; @@ -820,7 +819,7 @@ df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 r } internal DF_BitmapTopologyInfo -df_vr_bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_BitmapTopologyInfo info = {0}; @@ -945,7 +944,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) // DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; - DF_BitmapTopologyInfo topology_info = df_vr_bitmap_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_BitmapTopologyInfo topology_info = df_vr_bitmap_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); U64 expected_size = topology_info.width*topology_info.height*r_tex2d_format_bytes_per_pixel_table[topology_info.fmt]; Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr+expected_size); @@ -1000,7 +999,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) DF_VIEW_SETUP_FUNCTION_DEF(bitmap) { DF_BitmapViewState *bvs = df_view_user_state(view, DF_BitmapViewState); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DF_CfgNode *view_center_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("view_center"), StringMatchFlag_CaseInsensitive); DF_CfgNode *zoom_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("zoom"), StringMatchFlag_CaseInsensitive); DF_CfgNode *bitmap_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("bitmap"), StringMatchFlag_CaseInsensitive); @@ -1008,16 +1007,16 @@ DF_VIEW_SETUP_FUNCTION_DEF(bitmap) DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, thread_unwind_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_unwind_rip_vaddr); bvs->view_center_pos.x = (F32)f64_from_str8(bitmap_cfg->first->string); bvs->view_center_pos.y = (F32)f64_from_str8(bitmap_cfg->first->next->string); bvs->zoom = (F32)f64_from_str8(zoom_cfg->first->string); - bvs->top = df_vr_bitmap_topology_info_from_cfg(dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, bitmap_cfg); + bvs->top = df_vr_bitmap_topology_info_from_cfg(di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, bitmap_cfg); if(bvs->zoom == 0) { bvs->zoom = 1.f; } - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); } DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(bitmap) @@ -1068,7 +1067,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) { DF_BitmapViewState *bvs = df_view_user_state(view, DF_BitmapViewState); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); HS_Scope *hs_scope = hs_scope_open(); TEX_Scope *tex_scope = tex_scope_open(); @@ -1079,13 +1078,13 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, thread_unwind_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_unwind_rip_vaddr); ////////////////////////////// //- rjf: evaluate expression // String8 expr = str8(view->query_buffer, view->query_string_size); - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; U64 expected_size = bvs->top.width*bvs->top.height*r_tex2d_format_bytes_per_pixel_table[bvs->top.fmt]; @@ -1163,7 +1162,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) hs_scope_close(hs_scope); tex_scope_close(tex_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); scratch_end(scratch); } @@ -1171,7 +1170,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) //~ rjf: "geo" internal DF_GeoTopologyInfo -df_vr_geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_GeoTopologyInfo result = {0}; @@ -1292,7 +1291,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; //- rjf: extract extra geo topology info from view rule - DF_GeoTopologyInfo top = df_vr_geo_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_GeoTopologyInfo top = df_vr_geo_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); Rng1U64 index_buffer_vaddr_range = r1u64(base_vaddr, base_vaddr+top.index_count*sizeof(U32)); Rng1U64 vertex_buffer_vaddr_range = top.vertices_vaddr_range; diff --git a/src/df/gfx/df_view_rules.h b/src/df/gfx/df_view_rules.h index d69435ca..9d895ed1 100644 --- a/src/df/gfx/df_view_rules.h +++ b/src/df/gfx/df_view_rules.h @@ -38,7 +38,7 @@ struct DF_VR_TextState F32 loaded_t; }; -internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "disasm" @@ -61,7 +61,7 @@ struct DF_VR_DisasmState F32 loaded_t; }; -internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "bitmap" @@ -104,7 +104,7 @@ internal Vec2F32 df_bitmap_view_state__screen_from_canvas_pos(DF_BitmapViewState internal Rng2F32 df_bitmap_view_state__screen_from_canvas_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 cvs); internal Vec2F32 df_bitmap_view_state__canvas_from_screen_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 scr); internal Rng2F32 df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 scr); -internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "geo" @@ -139,6 +139,6 @@ struct DF_VR_GeoBoxDrawData F32 loaded_t; }; -internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); #endif // DF_VIEW_RULES_H diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 3cd448d9..03867dd3 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -543,7 +543,7 @@ df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint p //- rjf: windowed watch tree visualization (both single-line and multi-line) internal DF_EvalVizBlockList -df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) +df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -551,7 +551,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_EvalViewKey eval_view_key = df_eval_view_key_from_eval_watch_view(ews); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); String8 filter = str8(view->query_buffer, view->query_string_size); - DBGI_FuzzySearchTarget dbgi_target = DBGI_FuzzySearchTarget_UDTs; + FZY_Target fzy_target = FZY_Target_UDTs; switch(ews->fill_kind) { //////////////////////////// @@ -635,10 +635,10 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //////////////////////////// //- rjf: debug info table fill -> build split debug info table blocks // - case DF_WatchViewFillKind_Globals: dbgi_target = DBGI_FuzzySearchTarget_GlobalVariables; goto dbgi_table; - case DF_WatchViewFillKind_ThreadLocals: dbgi_target = DBGI_FuzzySearchTarget_ThreadVariables; goto dbgi_table; - case DF_WatchViewFillKind_Types: dbgi_target = DBGI_FuzzySearchTarget_UDTs; goto dbgi_table; - case DF_WatchViewFillKind_Procedures: dbgi_target = DBGI_FuzzySearchTarget_Procedures; goto dbgi_table; + case DF_WatchViewFillKind_Globals: fzy_target = FZY_Target_GlobalVariables; goto dbgi_table; + case DF_WatchViewFillKind_ThreadLocals: fzy_target = FZY_Target_ThreadVariables; goto dbgi_table; + case DF_WatchViewFillKind_Types: fzy_target = FZY_Target_UDTs; goto dbgi_table; + case DF_WatchViewFillKind_Procedures: fzy_target = FZY_Target_Procedures; goto dbgi_table; dbgi_table:; { //- rjf: unpack context @@ -646,10 +646,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_rip_unwind_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_unwind_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RDI_Parsed *rdi = &dbgi->rdi; + DF_Entity *dbgi = df_dbgi_from_module(module); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); //- rjf: calculate top-level keys, expand root-level, grab root expansion node DF_ExpandKey parent_key = df_expand_key_make(5381, 0); @@ -660,7 +658,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - DBGI_FuzzySearchItemArray items = dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, filter, dbgi_target, os_now_microseconds()+100, &items_stale); + // TODO(rjf) + FZY_ItemArray items = {0}; // dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, filter, dbgi_target, os_now_microseconds()+100, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -691,7 +690,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF U64 idx = 0; for(DF_ExpandNode *child = root_node->first; child != 0; child = child->next) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&items, child->key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&items, child->key.child_num); if(item_num != 0) { sub_expand_keys[idx] = child->key; @@ -731,8 +730,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_EvalVizBlock *last_vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_DebugInfoTable, parent_key, root_key, 0); { last_vb->visual_idx_range = last_vb->semantic_idx_range = r1u64(0, items.count); - last_vb->dbgi_target = dbgi_target; - last_vb->backing_search_items = items; + last_vb->fzy_target = fzy_target; + last_vb->fzy_backing_items = items; } for(U64 sub_expand_idx = 0; sub_expand_idx < sub_expand_keys_count; sub_expand_idx += 1) { @@ -740,7 +739,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF last_vb = df_eval_viz_block_split_and_continue(arena, &blocks, last_vb, sub_expand_item_idxs[sub_expand_idx]); // rjf: grab name for the expanded row - String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(&dbgi->rdi, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); + // TODO(rjf) + String8 name = {0}; // dbgi_fuzzy_item_string_from_rdi_target_element_idx(&dbgi->rdi, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); // rjf: recurse for sub-expansion { @@ -817,7 +817,7 @@ internal void df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect) { ProfBeginFunction(); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); Temp scratch = scratch_begin(0, 0); ////////////////////////////// @@ -2035,7 +2035,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS } scratch_end(scratch); - dbgi_scope_close(scope); + di_scope_close(scope); ProfEnd(); } @@ -3228,15 +3228,15 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); + DF_Entity *dbgi = df_dbgi_from_module(module); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); String8 query = str8(view->query_buffer, view->query_string_size); TG_Graph *graph = tg_graph_begin(bit_size_from_arch(df_architecture_from_entity(thread))/8, 256); @@ -3250,10 +3250,9 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: query -> raddbg, filtered items U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RDI_Parsed *rdi = &dbgi->rdi; B32 items_stale = 0; - DBGI_FuzzySearchItemArray items = dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); + // TODO(rjf) + FZY_ItemArray items = {0}; // dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -3304,7 +3303,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) idx += 1) UI_Focus((slv->cursor.y == idx+1) ? UI_FocusKind_On : UI_FocusKind_Off) { - DBGI_FuzzySearchItem *item = &items.v[idx]; + FZY_Item *item = &items.v[idx]; RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx); U64 name_size = 0; U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); @@ -3339,8 +3338,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } if(ui_hovering(sig)) UI_Tooltip { - U64 binary_voff = df_voff_from_binary_symbol_name(binary, name); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, binary_voff); + U64 binary_voff = df_voff_from_dbgi_symbol_name(dbgi, name); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, binary_voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); S64 line_num = dasm2src_info.pt.line; df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); @@ -3360,7 +3359,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -4520,7 +4519,6 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); String8 query = str8(view->query_buffer, view->query_string_size); DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); @@ -4735,8 +4733,8 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) U64 rip_vaddr = df_query_cached_rip_from_thread(entity); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + DF_Entity *dbgi = df_dbgi_from_module(module); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); if(!df_entity_is_nil(line_info.file)) { UI_PrefWidth(ui_children_sum(0)) df_entity_src_loc_button(ws, line_info.file, line_info.pt); @@ -4753,7 +4751,6 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) sv->selected_column = cursor.x; sv->selected_entity = (1 <= cursor.y && cursor.y <= items.count) ? df_handle_from_entity(items.v[cursor.y-1].entity) : df_handle_zero(); - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -5029,7 +5026,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Modules) { String8 exe_path = module->name; String8 dbg_path = pick_string; - dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + // TODO(rjf) } scratch_end(scratch); }break; @@ -5041,7 +5038,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); String8 query = str8(view->query_buffer, view->query_string_size); //- rjf: get state @@ -5208,16 +5205,17 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) B32 brw_is_selected = (row_is_selected && cursor.x == 3); // rjf: unpack module info - DF_Entity *binary = df_binary_file_from_module(entity); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - B32 dbgi_is_valid = (dbgi->dbg_props.modified != 0); + DF_Entity *dbgi = df_dbgi_from_module(entity); + String8 dbgi_path = df_full_path_from_entity(scratch.arena, dbgi); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + B32 dbgi_is_valid = (rdi != &di_rdi_parsed_nil); // rjf: begin editing if(txt_is_selected && edit_begin) { mv->txt_editing = 1; - mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); - MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi_path.size); + MemoryCopy(mv->txt_buffer, dbgi_path.str, mv->txt_size); mv->txt_cursor = txt_pt(1, 1+mv->txt_size); mv->txt_mark = txt_pt(1, 1); } @@ -5229,7 +5227,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) UI_WidthFill { UI_TextColor(!dbgi_is_valid ? df_rgba_from_theme_color(DF_ThemeColor_FailureBackground) : ui_top_text_color()) - sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi->dbg_path, "###dbg_path_%p", entity); + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi_path, "###dbg_path_%p", entity); edit_commit = (edit_commit || ui_committed(sig)); } @@ -5247,8 +5245,8 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { ui_kill_action(); mv->txt_editing = 1; - mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); - MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi_path.size); + MemoryCopy(mv->txt_buffer, dbgi_path.str, mv->txt_size); mv->txt_cursor = txt_pt(1, 1+mv->txt_size); mv->txt_mark = txt_pt(1, 1); } @@ -5287,7 +5285,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { String8 exe_path = commit_module->name; String8 dbg_path = str8(mv->txt_buffer, mv->txt_size); - dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + // TODO(rjf) } if(edit_submit) { @@ -5305,7 +5303,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) mv->selected_column = cursor.x; mv->selected_entity = (1 <= cursor.y && cursor.y <= items.count) ? df_handle_from_entity(items.v[cursor.y-1].entity) : df_handle_zero(); - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -5539,8 +5537,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *dbgi = src2dasm_list->first->v.dbgi; + DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -5665,7 +5663,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); HS_Scope *hs_scope = hs_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); @@ -5692,7 +5690,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 unwind_count = ctrl_ctx.unwind_count; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, rip_vaddr); ////////////////////////////// //- rjf: unpack file/text entity info @@ -5842,8 +5840,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; DF_Entity *module = df_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + DF_Entity *dbgi = df_dbgi_from_module(module); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); if(dasm2src_info.file == entity && visible_line_num_range.min <= dasm2src_info.pt.line && dasm2src_info.pt.line <= visible_line_num_range.max) { U64 slice_line_idx = dasm2src_info.pt.line-visible_line_num_range.min; @@ -5874,7 +5872,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { MemoryCopy(code_slice_params.line_src2dasm, src2dasm.v, sizeof(DF_TextLineSrc2DasmInfoList)*src2dasm.count); } - code_slice_params.relevant_binaries = src2dasm.binaries; + code_slice_params.relevant_dbgis = src2dasm.dbgis; } } @@ -6118,7 +6116,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) String8 expr = txt_string_from_info_data_txt_rng(&text_info, data, expr_rng); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, entity, sig.mouse_pt, 0, expr); @@ -6190,8 +6188,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *dbgi = src2dasm_list->first->v.dbgi; + DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); DF_Entity *thread_dst_module = df_module_from_thread_candidates(dropped_entity, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -6247,8 +6245,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *dbgi = src2dasm_list->first->v.dbgi; + DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -6406,20 +6404,19 @@ DF_VIEW_UI_FUNCTION_DEF(Code) //- rjf: determine up-to-dateness of source file // B32 file_is_out_of_date = 0; - String8 out_of_date_binary_name = {0}; - for(DF_EntityNode *n = code_slice_params.relevant_binaries.first; n != 0; n = n->next) + String8 out_of_date_dbgi_name = {0}; + for(DF_EntityNode *n = code_slice_params.relevant_dbgis.first; n != 0; n = n->next) { - DF_Entity *binary = n->entity; - if(!df_entity_is_nil(binary)) + DF_Entity *dbgi = n->entity; + if(!df_entity_is_nil(dbgi)) { String8 full_path = df_full_path_from_entity(scratch.arena, entity); TXTI_Handle handle = txti_handle_from_path(full_path); TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); - DBGI_Parse *parse = df_dbgi_parse_from_binary_file(dbgi_scope, binary); - if(parse->exe_props.modified < info.timestamp) + if(dbgi->timestamp < info.timestamp) { file_is_out_of_date = 1; - out_of_date_binary_name = binary->name; + out_of_date_dbgi_name = dbgi->name; break; } } @@ -6457,9 +6454,9 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) { - ui_labelf("This file has changed since ", out_of_date_binary_name); - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) ui_label(out_of_date_binary_name); - ui_labelf(" was built."); + ui_labelf("This file has changed since ", out_of_date_dbgi_name); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) ui_label(out_of_date_dbgi_name); + ui_labelf(" was produced."); } } } @@ -6479,7 +6476,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) } txt_scope_close(txt_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); @@ -6521,8 +6518,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) DF_Entity *process = df_entity_from_handle(dv->process); Architecture arch = df_architecture_from_entity(process); U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); - DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_binary = df_binary_file_from_module(dasm_module); + DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); + DF_Entity *dasm_dbgi = df_dbgi_from_module(dasm_module); Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; @@ -6533,7 +6530,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.exe_path = df_full_path_from_entity(scratch.arena, dasm_binary); + dasm_params.dbg_path = df_full_path_from_entity(scratch.arena, dasm_dbgi); + dasm_params.dbg_timestamp = dasm_dbgi->timestamp; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6732,7 +6730,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) HS_Scope *hs_scope = hs_scope_open(); DASM_Scope *dasm_scope = dasm_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); ////////////////////////////// @@ -6757,7 +6755,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_Entity *selected_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); U64 unwind_count = ctrl_ctx.unwind_count; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(selected_thread, unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, selected_process, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, selected_process, rip_vaddr); ////////////////////////////// //- rjf: no disasm process open? -> snap to selected thread @@ -6776,7 +6774,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) Architecture arch = df_architecture_from_entity(process); U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_binary = df_binary_file_from_module(dasm_module); + DF_Entity *dasm_dbgi = df_dbgi_from_module(dasm_module); Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; @@ -6787,7 +6785,8 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.exe_path = df_full_path_from_entity(scratch.arena, dasm_binary); + dasm_params.dbg_path = df_full_path_from_entity(scratch.arena, dasm_dbgi); + dasm_params.dbg_timestamp = dasm_dbgi->timestamp; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6800,7 +6799,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: unpack module info for this region // DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); ////////////////////////////// //- rjf: is loading -> equip view with loading information @@ -6889,7 +6888,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { code_slice_params.margin_float_off_px = 0; } - df_entity_list_push(scratch.arena, &code_slice_params.relevant_binaries, binary); + df_entity_list_push(scratch.arena, &code_slice_params.relevant_dbgis, dbgi); // rjf: fill text info { @@ -6971,7 +6970,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // rjf: fill dasm -> src info { DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { U64 vaddr = dasm_vaddr_range.min + dasm_inst_array_code_off_from_idx(&dasm_info.insts, line_num-1); @@ -6980,7 +6979,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_TextLineDasm2SrcInfoNode *dasm2src_n = push_array(scratch.arena, DF_TextLineDasm2SrcInfoNode, 1); SLLQueuePush(code_slice_params.line_dasm2src[slice_idx].first, code_slice_params.line_dasm2src[slice_idx].last, dasm2src_n); code_slice_params.line_dasm2src[slice_idx].count += 1; - dasm2src_n->v = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + dasm2src_n->v = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, voff); } } } @@ -7050,7 +7049,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) String8 expr = str8_substr(code_slice_params.line_text[line_idx], r1u64(sig.mouse_expr_rng.min.column-1, sig.mouse_expr_rng.max.column-1)); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.mouse_expr_rng.min.line-1); @@ -7150,9 +7149,9 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { U64 vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.goto_src_line_num-1); DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src.file); DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.text_point = dasm2src.pt; @@ -7326,7 +7325,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } } - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); txt_scope_close(txt_scope); dasm_scope_close(dasm_scope); hs_scope_close(hs_scope); @@ -7598,7 +7597,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); ////////////////////////////// @@ -8119,7 +8118,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -8492,9 +8491,9 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) { U64 f_rip = regs_rip_from_arch_block(thread->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, f_rip); - DF_Entity *binary = df_binary_file_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, f_rip); - String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + String8 symbol_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); annotation->kind_string = str8_lit("Call Stack Frame"); @@ -8544,7 +8543,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) df_rgba_from_theme_color(DF_ThemeColor_Thread6), df_rgba_from_theme_color(DF_ThemeColor_Thread7), }; - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_rip_vaddr); RDI_Parsed *rdi = parse_ctx.rdi; @@ -8575,7 +8574,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } } } - dbgi_scope_close(scope); + di_scope_close(scope); } } diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index f5bd217a..961c85fc 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -495,7 +495,7 @@ internal String8 df_string_from_eval_viz_row_column_kind(Arena *arena, DF_EvalVi internal DF_WatchViewTextEditState *df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint pt); //- rjf: windowed watch tree visualization -internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); //- rjf: eval/watch views main hooks internal void df_watch_view_init(DF_WatchViewState *ewv, DF_View *view, DF_WatchViewFillKind fill_kind); diff --git a/src/fuzzy_search/fuzzy_search.c b/src/fuzzy_search/fuzzy_search.c new file mode 100644 index 00000000..0faa9c12 --- /dev/null +++ b/src/fuzzy_search/fuzzy_search.c @@ -0,0 +1,83 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 +fzy_hash_from_string(String8 string, StringMatchFlags match_flags) +{ + return 0; +} + +internal U64 +fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx) +{ + return 0; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +fzy_init(void) +{ + +} + +//////////////////////////////// +//~ rjf: Scope Functions + +internal FZY_Scope * +fzy_scope_open(void) +{ + +} + +internal void +fzy_scope_close(FZY_Scope *scope) +{ + +} + +internal void +fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node) +{ + +} + +//////////////////////////////// +//~ rjf: Cache Lookup Functions + +internal FZY_ItemArray +fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out) +{ + +} + +//////////////////////////////// +//~ rjf: Searcher Threads + +internal B32 +fzy_u2s_enqueue_req(U128 key, U64 endt_us) +{ + +} + +internal void +fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out) +{ + +} + +internal int +fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b) +{ + +} + +internal void +fzy_search_thread__entry_point(void *p) +{ + +} diff --git a/src/fuzzy_search/fuzzy_search.h b/src/fuzzy_search/fuzzy_search.h new file mode 100644 index 00000000..99fc5aa8 --- /dev/null +++ b/src/fuzzy_search/fuzzy_search.h @@ -0,0 +1,185 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FUZZY_SEARCH_H +#define FUZZY_SEARCH_H + +//////////////////////////////// +//~ rjf: Fuzzy Search Types + +typedef enum FZY_Target +{ + FZY_Target_Procedures, + FZY_Target_GlobalVariables, + FZY_Target_ThreadVariables, + FZY_Target_UDTs, + FZY_Target_COUNT +} +FZY_Target; + +typedef struct FZY_Params FZY_Params; +struct FZY_Params +{ + FZY_Target target; +}; + +typedef struct FZY_Item FZY_Item; +struct FZY_Item +{ + U64 idx; + U64 missed_size; + FuzzyMatchRangeList match_ranges; +}; + +typedef struct FZY_ItemChunk FZY_ItemChunk; +struct FZY_ItemChunk +{ + FZY_ItemChunk *next; + FZY_Item *v; + U64 count; + U64 cap; +}; + +typedef struct FZY_ItemChunkList FZY_ItemChunkList; +struct FZY_ItemChunkList +{ + FZY_ItemChunk *first; + FZY_ItemChunk *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct FZY_ItemArray FZY_ItemArray; +struct FZY_ItemArray +{ + FZY_Item *v; + U64 count; +}; + +typedef struct FZY_Bucket FZY_Bucket; +struct FZY_Bucket +{ + Arena *arena; + String8 query; + FZY_Target target; +}; + +typedef struct FZY_Node FZY_Node; +struct FZY_Node +{ + FZY_Node *next; + U128 key; + U64 scope_touch_count; + U64 last_time_submitted_us; + FZY_Bucket buckets[3]; + U64 gen; + U64 submit_gen; + FZY_ItemArray gen_items; +}; + +typedef struct FZY_Slot FZY_Slot; +struct FZY_Slot +{ + FZY_Node *first; + FZY_Node *last; +}; + +typedef struct FZY_Stripe FZY_Stripe; +struct FZY_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +typedef struct FZY_Thread FZY_Thread; +struct FZY_Thread +{ + OS_Handle thread; + OS_Handle u2f_ring_mutex; + OS_Handle u2f_ring_cv; + U64 u2f_ring_size; + U8 *u2f_ring_base; + U64 u2f_ring_write_pos; + U64 u2f_ring_read_pos; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct FZY_Touch FZY_Touch; +struct FZY_Touch +{ + FZY_Touch *next; + FZY_Node *node; +}; + +typedef struct FZY_Scope FZY_Scope; +struct FZY_Scope +{ + FZY_Scope *next; + FZY_Touch *first_touch; + FZY_Touch *last_touch; +}; + +typedef struct FZY_TCTX FZY_TCTX; +struct FZY_TCTX +{ + Arena *arena; + FZY_Scope *free_scope; + FZY_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State Types + +typedef struct FZY_Shared FZY_Shared; +struct FZY_Shared +{ + Arena *arena; + + // rjf: search artifact cache table + U64 slots_count; + U64 stripes_count; + FZY_Slot *slots; + FZY_Stripe *stripes; + + // rjf: threads + U64 thread_count; + FZY_Thread *threads; +}; + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 fzy_hash_from_string(String8 string, StringMatchFlags match_flags); +internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void fzy_init(void); + +//////////////////////////////// +//~ rjf: Scope Functions + +internal FZY_Scope *fzy_scope_open(void); +internal void fzy_scope_close(FZY_Scope *scope); +internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookup Functions + +internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out); + +//////////////////////////////// +//~ rjf: Searcher Threads + +internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us); +internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out); + +internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b); + +internal void fzy_search_thread__entry_point(void *p); + +#endif // FUZZY_SEARCH_H diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 7b2d9ba5..75dae216 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -46,8 +46,9 @@ #include "regs/regs.h" #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" -#include "dbgi/dbgi.h" +//#include "dbgi/dbgi.h" #include "dbgi2/dbgi2.h" +#include "fuzzy_search/fuzzy_search.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" #include "ctrl/ctrl_inc.h" @@ -85,8 +86,9 @@ #include "regs/regs.c" #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" -#include "dbgi/dbgi.c" +//#include "dbgi/dbgi.c" #include "dbgi2/dbgi2.c" +#include "fuzzy_search/fuzzy_search.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" #include "ctrl/ctrl_inc.c" From b74db17375a37ba707fc98331e49ae6f6ecfde5f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 21 May 2024 11:29:19 -0700 Subject: [PATCH 14/38] peb trampling mule --- build.bat | 5 +++ project.4coder | 2 +- src/dbgi2/dbgi2.c | 7 ++-- src/mule/mule_peb_trample.c | 66 +++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/mule/mule_peb_trample.c diff --git a/build.bat b/build.bat index defffb0b..509b4082 100644 --- a/build.bat +++ b/build.bat @@ -109,6 +109,11 @@ if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 +if "%mule_peb_trample%"=="1" ( + if exist mule_peb_trample_old.exe del mule_peb_trample_old.exe + if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old.exe + %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample.exe || exit /b 1 +) popd :: --- Unset ------------------------------------------------------------------ diff --git a/project.4coder b/project.4coder index 0fb436c2..157ea4c7 100644 --- a/project.4coder +++ b/project.4coder @@ -56,7 +56,7 @@ commands = }, .rjf_f2 = { - .win = "build raddbgi_from_pdb telemetry release", + .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c index 31b5b841..13a5d65a 100644 --- a/src/dbgi2/dbgi2.c +++ b/src/dbgi2/dbgi2.c @@ -378,9 +378,10 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, } //- rjf: parse not done, not working, asked a while ago -> ask for parse + B32 sent = 0; if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); @@ -394,7 +395,9 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, } //- rjf: wait on this stripe - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } } scratch_end(scratch); } diff --git a/src/mule/mule_peb_trample.c b/src/mule/mule_peb_trample.c new file mode 100644 index 00000000..7a72eb3b --- /dev/null +++ b/src/mule/mule_peb_trample.c @@ -0,0 +1,66 @@ +#include +#include + +static void +HideModuleFromWindowsReload(HMODULE ModuleToFlush) +{ + /* NOTE(casey): Normally you cannot "reload" an executable module with the same name, + because Windows checks a linked list of loaded modules and assumes that if + it's already loaded, it doesn't need to reload it, even though it may have to because + it has changed on disk. + + This solution to that problem comes from some excellent spelunking by Martins Mozeiko, + who figured out that you could overwrite the filenames Windows stores in your process's + loaded module table, thus thwarting the Windows filename check against loaded modules, + allowing you to reload an existing module that has changed without requiring it to + have a different filename! + */ + + PEB *Peb = (PEB *)__readgsqword(offsetof(TEB, ProcessEnvironmentBlock)); + LIST_ENTRY *Head = &Peb->Ldr->InMemoryOrderModuleList; + for(LIST_ENTRY *Entry = Head->Flink; + Entry != Head; + Entry = Entry->Flink) + { + LDR_DATA_TABLE_ENTRY *Mod = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + if(Mod->DllBase == ModuleToFlush) + { + ZeroMemory(Mod->FullDllName.Buffer, Mod->FullDllName.Length); + Mod->DllBase = 0; + break; + } + } +} + +__declspec(dllexport) void +loop_iteration(int it) +{ + printf("foobar iteration #%i\n", it); +} + +int main(int argument_count, char **arguments) +{ + char *exe_name = arguments[0]; + HANDLE last_module = GetModuleHandle(0); + void (*loop_iteration_function)(int it) = (void (*)(int))GetProcAddress(last_module, "loop_iteration"); + FILETIME last_filetime = {0}; + int should_exit = 0; + for(int it = 0; !should_exit; it += 1) + { + loop_iteration_function(it); + Sleep(50); + FILETIME current_filetime = {0}; + HANDLE current_exe_file = CreateFile(exe_name, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + GetFileTime(current_exe_file, 0, 0, ¤t_filetime); + CloseHandle(current_exe_file); + if(it != 0 && CompareFileTime(&last_filetime, ¤t_filetime) < 0) + { + HideModuleFromWindowsReload(last_module); + //last_module = LoadLibrary(arguments[0]); + last_module = LoadLibrary("foobar.exe"); + loop_iteration_function = (void (*)(int))GetProcAddress(last_module, "loop_iteration"); + } + last_filetime = current_filetime; + } + return 0; +} From b33559b0814eb99cd61f66878390d6980004923b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 21 May 2024 12:40:21 -0700 Subject: [PATCH 15/38] tweaks to mule_peb_trample --- build.bat | 6 +++--- src/mule/mule_peb_trample.c | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.bat b/build.bat index 509b4082..eb6653d8 100644 --- a/build.bat +++ b/build.bat @@ -110,9 +110,9 @@ if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 if "%mule_peb_trample%"=="1" ( - if exist mule_peb_trample_old.exe del mule_peb_trample_old.exe - if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old.exe - %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample.exe || exit /b 1 + if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe + %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1 + move mule_peb_trample_new.exe mule_peb_trample.exe ) popd diff --git a/src/mule/mule_peb_trample.c b/src/mule/mule_peb_trample.c index 7a72eb3b..f44bcea1 100644 --- a/src/mule/mule_peb_trample.c +++ b/src/mule/mule_peb_trample.c @@ -32,22 +32,23 @@ HideModuleFromWindowsReload(HMODULE ModuleToFlush) } } -__declspec(dllexport) void +__declspec(dllexport) int loop_iteration(int it) { - printf("foobar iteration #%i\n", it); + return it*it; } int main(int argument_count, char **arguments) { char *exe_name = arguments[0]; HANDLE last_module = GetModuleHandle(0); - void (*loop_iteration_function)(int it) = (void (*)(int))GetProcAddress(last_module, "loop_iteration"); + int (*loop_iteration_function)(int it) = (int (*)(int))GetProcAddress(last_module, "loop_iteration"); FILETIME last_filetime = {0}; int should_exit = 0; for(int it = 0; !should_exit; it += 1) { - loop_iteration_function(it); + int result = loop_iteration_function(it); + printf("%i\n", result); Sleep(50); FILETIME current_filetime = {0}; HANDLE current_exe_file = CreateFile(exe_name, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); @@ -56,9 +57,8 @@ int main(int argument_count, char **arguments) if(it != 0 && CompareFileTime(&last_filetime, ¤t_filetime) < 0) { HideModuleFromWindowsReload(last_module); - //last_module = LoadLibrary(arguments[0]); - last_module = LoadLibrary("foobar.exe"); - loop_iteration_function = (void (*)(int))GetProcAddress(last_module, "loop_iteration"); + last_module = LoadLibrary(arguments[0]); + loop_iteration_function = (int (*)(int))GetProcAddress(last_module, "loop_iteration"); } last_filetime = current_filetime; } From 7a4e939886b3c4a6de37bbf05c86a42cde783393 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 22 May 2024 11:13:08 -0700 Subject: [PATCH 16/38] fix incorrectly referring to root entity for debug info if missing; fix thread register cache issues; fix new dbgi layer issues --- src/ctrl/ctrl_core.c | 20 +++++++++++++++++--- src/dbgi2/dbgi2.c | 12 ++++++------ src/dbgi2/dbgi2.h | 2 +- src/df/core/df_core.c | 4 ++-- src/df/gfx/df_gfx.c | 17 +++++++++-------- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5a66aa37..37a64e47 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1459,9 +1459,23 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C B32 need_stale = 1; if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) { - need_stale = 0; - node->reg_gen = current_reg_gen; - MemoryCopy(node->block, result, reg_block_size); + OS_MutexScopeRWPromote(stripe->rw_mutex) + { + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + if(node != 0) + { + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } + } } if(need_stale) { diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c index 13a5d65a..11afcb21 100644 --- a/src/dbgi2/dbgi2.c +++ b/src/dbgi2/dbgi2.c @@ -5,12 +5,12 @@ //~ rjf: Basic Helpers internal U64 -di_hash_from_string(String8 string) +di_hash_from_string(String8 string, StringMatchFlags match_flags) { U64 result = 5381; for(U64 i = 0; i < string.size; i += 1) { - result = ((result << 5) + result) + string.str[i]; + result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? char_to_lower(string.str[i]) : string.str[i]); } return result; } @@ -237,7 +237,7 @@ di_open(String8 path, U64 min_timestamp) if(path.size != 0) { String8 path_normalized = path_normalized_from_string(scratch.arena, path); - U64 hash = di_hash_from_string(path_normalized); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; @@ -294,7 +294,7 @@ di_close(String8 path, U64 min_timestamp) { String8 path_normalized = path_normalized_from_string(scratch.arena, path); StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; @@ -353,7 +353,7 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, Temp scratch = scratch_begin(0, 0); String8 path_normalized = path_normalized_from_string(scratch.arena, path); StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; @@ -528,7 +528,7 @@ di_parse_thread__entry_point(void *p) //////////////////////////// //- rjf: unpack key // - U64 hash = di_hash_from_string(og_path); + U64 hash = di_hash_from_string(og_path, StringMatchFlag_CaseInsensitive); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; diff --git a/src/dbgi2/dbgi2.h b/src/dbgi2/dbgi2.h index a6857aa2..fc275350 100644 --- a/src/dbgi2/dbgi2.h +++ b/src/dbgi2/dbgi2.h @@ -200,7 +200,7 @@ global RDI_Parsed di_rdi_parsed_nil = //////////////////////////////// //~ rjf: Basic Helpers -internal U64 di_hash_from_string(String8 string); +internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); //////////////////////////////// //~ rjf: Main Layer Initialization diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index bd5b226c..d8cbb9b4 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2185,7 +2185,7 @@ df_entity_from_path(String8 path, DF_EntityFromPathFlags flags) // rjf: next parent -> follow it parent = next_parent; } - file_no_override = parent; + file_no_override = (parent != df_entity_root() ? parent : &df_g_nil_entity); } //- rjf: pass 2: follow overrides @@ -2244,7 +2244,7 @@ df_entity_from_path(String8 path, DF_EntityFromPathFlags flags) // rjf: next parent -> follow it parent = next_parent; } - file_overrides_applied = parent; + file_overrides_applied = (parent != df_entity_root() ? parent : &df_g_nil_entity);; } //- rjf: pick & return result diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index bca2d81d..7d2a72ca 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -2499,19 +2499,19 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *debug = df_dbgi_from_module(module); + DF_Entity *dbgi = df_dbgi_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, debug); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, rip_voff); + RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); // rjf: snap to resolved line B32 missing_rip = (rip_vaddr == 0); - B32 binary_missing = (debug->flags & DF_EntityFlag_IsMissing); - B32 dbg_info_pending = !binary_missing && rdi == &di_rdi_parsed_nil; + B32 dbgi_missing = (dbgi->flags & DF_EntityFlag_IsMissing || df_entity_is_nil(dbgi)); + B32 dbgi_pending = !dbgi_missing && rdi == &di_rdi_parsed_nil; B32 has_line_info = (line_info.voff_range.max != line_info.voff_range.min); B32 has_module = !df_entity_is_nil(module); - B32 has_dbg_info = has_module && !binary_missing; - if(!dbg_info_pending && (has_line_info || has_module)) + B32 has_dbg_info = has_module && !dbgi_missing; + if(!dbgi_pending && (has_line_info || has_module)) { DF_CmdParams params = df_cmd_params_from_window(ws); if(has_line_info) @@ -2527,12 +2527,13 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) params.index = unwind_count; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualOff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); } // rjf: retry on stopped, pending debug info - if(!df_ctrl_targets_running() && (dbg_info_pending || missing_rip)) + if(!df_ctrl_targets_running() && (dbgi_pending || missing_rip)) { df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); } From 0160d05e8ad20ef9666e98108d5c95fb9d74ceb1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 22 May 2024 11:39:23 -0700 Subject: [PATCH 17/38] further tweaks to mule_peb_trample --- build.bat | 2 ++ src/mule/mule_peb_trample.c | 7 +------ src/mule/mule_peb_trample_reload.c | 10 ++++++++++ 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 src/mule/mule_peb_trample_reload.c diff --git a/build.bat b/build.bat index eb6653d8..e23cdf5f 100644 --- a/build.bat +++ b/build.bat @@ -111,6 +111,8 @@ if "%mule_module%"=="1" %compile% ..\src\mule\mule_mo if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 if "%mule_peb_trample%"=="1" ( if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe + if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb + if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1 move mule_peb_trample_new.exe mule_peb_trample.exe ) diff --git a/src/mule/mule_peb_trample.c b/src/mule/mule_peb_trample.c index f44bcea1..a0aaa2c9 100644 --- a/src/mule/mule_peb_trample.c +++ b/src/mule/mule_peb_trample.c @@ -1,5 +1,6 @@ #include #include +#include "mule_peb_trample_reload.c" static void HideModuleFromWindowsReload(HMODULE ModuleToFlush) @@ -32,12 +33,6 @@ HideModuleFromWindowsReload(HMODULE ModuleToFlush) } } -__declspec(dllexport) int -loop_iteration(int it) -{ - return it*it; -} - int main(int argument_count, char **arguments) { char *exe_name = arguments[0]; diff --git a/src/mule/mule_peb_trample_reload.c b/src/mule/mule_peb_trample_reload.c new file mode 100644 index 00000000..8e90550f --- /dev/null +++ b/src/mule/mule_peb_trample_reload.c @@ -0,0 +1,10 @@ +__declspec(dllexport) int +loop_iteration(int it) +{ + int sum = 0; + for(int i = 0; i < 1000; i += 1) + { + sum += it*i; + } + return sum; +} From a5e2235fc66240053e9edc4cd400a60fbd6d5dc6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 22 May 2024 11:54:27 -0700 Subject: [PATCH 18/38] fix deadlocks on di_close contending with passive scoped dbgi access --- src/dbgi2/dbgi2.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c index 11afcb21..c8fed823 100644 --- a/src/dbgi2/dbgi2.c +++ b/src/dbgi2/dbgi2.c @@ -309,31 +309,40 @@ di_close(String8 path, U64 min_timestamp) if(node != 0) { node->ref_count -= 1; - if(node->ref_count == 0) + if(node->ref_count == 0) for(;;) { //- rjf: wait for touch count to go to 0 - for(;ins_atomic_u64_eval(&node->touch_count) != 0;){} + if(ins_atomic_u64_eval(&node->touch_count) != 0) + { + os_rw_mutex_drop_w(stripe->rw_mutex); + for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); + os_rw_mutex_take_w(stripe->rw_mutex); + } //- rjf: release - di_string_release__stripe_mutex_w_guarded(stripe, node->path); - if(node->file_base != 0) + if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) { - os_file_map_view_close(node->file_map, node->file_base); + di_string_release__stripe_mutex_w_guarded(stripe, node->path); + if(node->file_base != 0) + { + os_file_map_view_close(node->file_map, node->file_base); + } + if(!os_handle_match(node->file_map, os_handle_zero())) + { + os_file_map_close(node->file_map); + } + if(!os_handle_match(node->file, os_handle_zero())) + { + os_file_close(node->file); + } + if(node->arena != 0) + { + arena_release(node->arena); + } + DLLRemove(slot->first, slot->last, node); + SLLStackPush(stripe->free_node, node); + break; } - if(!os_handle_match(node->file_map, os_handle_zero())) - { - os_file_map_close(node->file_map); - } - if(!os_handle_match(node->file, os_handle_zero())) - { - os_file_close(node->file); - } - if(node->arena != 0) - { - arena_release(node->arena); - } - DLLRemove(slot->first, slot->last, node); - SLLStackPush(stripe->free_node, node); } } } From c17072053b1c8ed0a022e7e58ec969fc80e6c1df Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 22 May 2024 15:27:39 -0700 Subject: [PATCH 19/38] adjust d3d11 resize path --- src/render/d3d11/render_d3d11.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/render/d3d11/render_d3d11.cpp b/src/render/d3d11/render_d3d11.cpp index 30205966..a8346387 100644 --- a/src/render/d3d11/render_d3d11.cpp +++ b/src/render/d3d11/render_d3d11.cpp @@ -496,7 +496,7 @@ r_window_equip(OS_Handle handle) os_graphical_message(1, str8_lit("Fatal Error"), str8_cstring(buffer)); os_exit_process(1); } - + r_d3d11_state->dxgi_factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); //- rjf: create framebuffer & view @@ -846,13 +846,6 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) { wnd->last_resolution = resolution; - // rjf: resize swapchain & main framebuffer - wnd->framebuffer_rtv->Release(); - wnd->framebuffer->Release(); - wnd->swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); - wnd->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&wnd->framebuffer)); - r_d3d11_state->device->CreateRenderTargetView(wnd->framebuffer, 0, &wnd->framebuffer_rtv); - // rjf: release screen-sized render target resources, if there if(wnd->stage_scratch_color_srv){wnd->stage_scratch_color_srv->Release();} if(wnd->stage_scratch_color_rtv){wnd->stage_scratch_color_rtv->Release();} @@ -867,6 +860,13 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) if(wnd->geo3d_depth_dsv) {wnd->geo3d_depth_dsv->Release();} if(wnd->geo3d_depth) {wnd->geo3d_depth->Release();} + // rjf: resize swapchain & main framebuffer + wnd->framebuffer_rtv->Release(); + wnd->framebuffer->Release(); + wnd->swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); + wnd->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&wnd->framebuffer)); + r_d3d11_state->device->CreateRenderTargetView(wnd->framebuffer, 0, &wnd->framebuffer_rtv); + // rjf: create stage color targets { D3D11_TEXTURE2D_DESC color_desc = {}; @@ -946,6 +946,7 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) Vec4F32 clear_color = {0, 0, 0, 0}; d_ctx->ClearRenderTargetView(wnd->framebuffer_rtv, clear_color.v); d_ctx->ClearRenderTargetView(wnd->stage_color_rtv, clear_color.v); + d_ctx->Flush(); } ProfEnd(); } From 30f8e1675ecb8db5fa9aa54d8744db717bcf9efe Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 07:01:34 -0700 Subject: [PATCH 20/38] new multi-dbgi-capable fuzzy search layer first pass --- src/df/core/df_core.h | 2 +- src/df/gfx/df_gfx.c | 2 +- src/df/gfx/df_views.c | 55 ++-- src/df/gfx/df_views.h | 2 +- src/fuzzy_search/fuzzy_search.c | 523 +++++++++++++++++++++++++++++++- src/fuzzy_search/fuzzy_search.h | 114 +++++-- 6 files changed, 626 insertions(+), 72 deletions(-) diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 49dbfa0d..a27f7416 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1148,7 +1148,7 @@ struct DF_State // rjf: per-run caches U64 unwind_cache_reggen_idx; U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_caches[2]; + DF_RunUnwindCache unwind_caches[4]; U64 unwind_cache_gen; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 7d2a72ca..8b679140 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -8691,7 +8691,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DI_Scope *scope, for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { // rjf: unpack info about this row - String8 name = push_str8f(arena, "Item %I64u", idx); // TODO(rjf): dbgi_fuzzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->dbgi_target, block->fzy_backing_items.v[idx].idx); + String8 name = fzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->fzy_target, block->fzy_backing_items.v[idx].idx); // rjf: get keys for this row DF_ExpandKey parent_key = block->parent_key; diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 03867dd3..df97121f 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -543,7 +543,7 @@ df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint p //- rjf: windowed watch tree visualization (both single-line and multi-line) internal DF_EvalVizBlockList -df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) +df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, FZY_Scope *fzy_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -568,7 +568,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C { DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); DF_ExpandKey key = df_expand_key_from_eval_root(root); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -594,7 +594,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -606,7 +606,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -626,7 +626,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -647,7 +647,6 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C U64 thread_rip_unwind_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_unwind_vaddr); DF_Entity *dbgi = df_dbgi_from_module(module); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); //- rjf: calculate top-level keys, expand root-level, grab root expansion node DF_ExpandKey parent_key = df_expand_key_make(5381, 0); @@ -658,8 +657,13 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - // TODO(rjf) - FZY_ItemArray items = {0}; // dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, filter, dbgi_target, os_now_microseconds()+100, &items_stale); + FZY_DbgiKey key = {df_full_path_from_entity(scratch.arena, dbgi), dbgi->timestamp}; + FZY_Params params = {fzy_target}; + { + params.dbgi_keys.count = 1; + params.dbgi_keys.v = &key; + } + FZY_ItemArray items = fzy_items_from_key_params_query(fzy_scope, fuzzy_search_key, ¶ms, filter, os_now_microseconds()+100, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -739,8 +743,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C last_vb = df_eval_viz_block_split_and_continue(arena, &blocks, last_vb, sub_expand_item_idxs[sub_expand_idx]); // rjf: grab name for the expanded row - // TODO(rjf) - String8 name = {0}; // dbgi_fuzzy_item_string_from_rdi_target_element_idx(&dbgi->rdi, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); + String8 name = fzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, fzy_target, sub_expand_keys[sub_expand_idx].child_num); // rjf: recurse for sub-expansion { @@ -752,8 +755,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_C df_cfg_table_push_unparsed_string(arena, &child_cfg, view_rule_string, DF_CfgSrc_User); } } - DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, macro_map, name); - df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, macro_map, parent_key, sub_expand_keys[sub_expand_idx], name, eval, 0, &child_cfg, 0, &blocks); + DF_Eval eval = df_eval_from_string(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, name); + df_append_viz_blocks_for_parent__rec(arena, di_scope, eval_view, ctrl_ctx, parse_ctx, macro_map, parent_key, sub_expand_keys[sub_expand_idx], name, eval, 0, &child_cfg, 0, &blocks); } } df_eval_viz_block_end(&blocks, last_vb); @@ -817,7 +820,8 @@ internal void df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect) { ProfBeginFunction(); - DI_Scope *scope = di_scope_open(); + DI_Scope *di_scope = di_scope_open(); + FZY_Scope *fzy_scope = fzy_scope_open(); Temp scratch = scratch_begin(0, 0); ////////////////////////////// @@ -837,7 +841,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS ////////////////////////////// //- rjf: process * thread info -> parse_ctx // - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_ip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_ip_vaddr); ////////////////////////////// //- rjf: determine autocompletion string @@ -912,7 +916,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS // if(state_dirty) { - blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); + blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, di_scope, fzy_scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); } ////////////////////////// @@ -1050,7 +1054,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS ewv->text_edit_state_slots_count = u64_up_to_pow2(selection_dim.y+1); ewv->text_edit_state_slots_count = Max(ewv->text_edit_state_slots_count, 64); ewv->text_edit_state_slots = push_array(ewv->text_edit_arena, DF_WatchViewTextEditState*, ewv->text_edit_state_slots_count); - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1082,7 +1086,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS if(!ewv->text_editing && evt->slot == UI_EventActionSlot_Accept && selection_tbl.min.x <= 0) { taken = 1; - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1181,13 +1185,13 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS case DF_WatchViewColumnKind_Value: if(editing_complete && evt->slot != UI_EventActionSlot_Cancel) { - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, y-1), ui_scroll_list_row_from_item(&row_blocks, y-1)+1), &blocks); B32 success = 0; if(rows.first != 0) { - DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, new_string); + DF_Eval write_eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, new_string); success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, rows.first->eval, write_eval); } if(!success) @@ -1223,7 +1227,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS { taken = 1; String8List strs = {0}; - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1559,7 +1563,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS //- rjf: viz blocks -> rows DF_EvalVizWindowedRowList rows = {0}; { - rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); + rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); } //- rjf: build table @@ -1624,7 +1628,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS { Vec2F32 canvas_dim = v2f32(scroll_list_params.dim_px.x - ui_top_font_size()*1.5f, (row->skipped_size_in_rows+row->size_in_rows+row->chopped_size_in_rows)*scroll_list_params.row_height_px); - row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, row->edit_expr, scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->expand_ui_rule_node, canvas_dim); + row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, row->edit_expr, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->expand_ui_rule_node, canvas_dim); } } } @@ -1899,7 +1903,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); UI_Parent(box) { - row->value_ui_rule_spec->info.row_ui(row->key, row->eval, scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->value_ui_rule_node); + row->value_ui_rule_spec->info.row_ui(row->key, row->eval, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->value_ui_rule_node); } sig = ui_signal_from_box(box); } @@ -2035,7 +2039,8 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS } scratch_end(scratch); - di_scope_close(scope); + fzy_scope_close(fzy_scope); + di_scope_close(di_scope); ProfEnd(); } @@ -3251,7 +3256,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: query -> raddbg, filtered items U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - // TODO(rjf) + // TODO(rjf): @fuzzy FZY_ItemArray items = {0}; // dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); if(items_stale) { diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index 961c85fc..80af1789 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -495,7 +495,7 @@ internal String8 df_string_from_eval_viz_row_column_kind(Arena *arena, DF_EvalVi internal DF_WatchViewTextEditState *df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint pt); //- rjf: windowed watch tree visualization -internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, FZY_Scope *fzy_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); //- rjf: eval/watch views main hooks internal void df_watch_view_init(DF_WatchViewState *ewv, DF_View *view, DF_WatchViewFillKind fill_kind); diff --git a/src/fuzzy_search/fuzzy_search.c b/src/fuzzy_search/fuzzy_search.c index 0faa9c12..5d4ba473 100644 --- a/src/fuzzy_search/fuzzy_search.c +++ b/src/fuzzy_search/fuzzy_search.c @@ -5,15 +5,119 @@ //~ rjf: Helpers internal U64 -fzy_hash_from_string(String8 string, StringMatchFlags match_flags) +fzy_hash_from_string(U64 seed, String8 string) { - return 0; + U64 result = seed; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal U64 +fzy_hash_from_params(FZY_Params *params) +{ + U64 hash = 5381; + hash = fzy_hash_from_string(hash, str8_struct(¶ms->target)); + for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1) + { + hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].timestamp)); + hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path); + } + return hash; } internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx) { - return 0; + U64 fuzzy_item_num = 0; + for(U64 idx = 0; idx < array->count; idx += 1) + { + if(array->v[idx].idx == element_idx) + { + fuzzy_item_num = idx+1; + break; + } + } + return fuzzy_item_num; +} + +internal String8 +fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx) +{ + String8 result = {0}; + switch(target) + { + // NOTE(rjf): no default - warn if we miss a case + case FZY_Target_Procedures: + { + RDI_Procedure *proc = rdi_element_from_idx(rdi, procedures, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_GlobalVariables: + { + RDI_GlobalVariable *gvar = rdi_element_from_idx(rdi, global_variables, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_ThreadVariables: + { + RDI_ThreadVariable *tvar = rdi_element_from_idx(rdi, thread_variables, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_UDTs: + { + RDI_UDT *udt = rdi_element_from_idx(rdi, udts, element_idx); + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_COUNT:{}break; + } + return result; +} + +internal void +fzy_dbgi_key_list_push(Arena *arena, FZY_DbgiKeyList *list, FZY_DbgiKey key) +{ + FZY_DbgiKeyNode *n = push_array(arena, FZY_DbgiKeyNode, 1); + n->v = key; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal FZY_DbgiKeyArray +fzy_dbgi_key_array_from_list(Arena *arena, FZY_DbgiKeyList *list) +{ + FZY_DbgiKeyArray array = {0}; + array.v = push_array(arena, FZY_DbgiKey, list->count); + U64 idx = 0; + for(FZY_DbgiKeyNode *n = list->first; n != 0; n = n->next, idx += 1) + { + array.v[idx] = n->v; + } + return array; +} + +internal FZY_Params +fzy_params_copy(Arena *arena, FZY_Params *src) +{ + FZY_Params dst = {0}; + MemoryCopyStruct(&dst, src); + dst.dbgi_keys.v = push_array(arena, FZY_DbgiKey, dst.dbgi_keys.count); + MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(FZY_DbgiKey)*src->dbgi_keys.count); + for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1) + { + dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path); + } + return dst; } //////////////////////////////// @@ -22,7 +126,29 @@ fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 ele internal void fzy_init(void) { - + Arena *arena = arena_alloc(); + fzy_shared = push_array(arena, FZY_Shared, 1); + fzy_shared->arena = arena; + fzy_shared->slots_count = 256; + fzy_shared->stripes_count = os_logical_core_count(); + fzy_shared->slots = push_array(arena, FZY_Slot, fzy_shared->slots_count); + fzy_shared->stripes = push_array(arena, FZY_Stripe, fzy_shared->stripes_count); + for(U64 idx = 0; idx < fzy_shared->stripes_count; idx += 1) + { + fzy_shared->stripes[idx].arena = arena_alloc(); + fzy_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + fzy_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + fzy_shared->thread_count = Min(os_logical_core_count(), 2); + fzy_shared->threads = push_array(arena, FZY_Thread, fzy_shared->thread_count); + for(U64 idx = 0; idx < fzy_shared->thread_count; idx += 1) + { + fzy_shared->threads[idx].u2f_ring_mutex = os_mutex_alloc(); + fzy_shared->threads[idx].u2f_ring_cv = os_condition_variable_alloc(); + fzy_shared->threads[idx].u2f_ring_size = KB(64); + fzy_shared->threads[idx].u2f_ring_base = push_array_no_zero(arena, U8, fzy_shared->threads[idx].u2f_ring_size); + fzy_shared->threads[idx].thread = os_launch_thread(fzy_search_thread__entry_point, (void *)idx, 0); + } } //////////////////////////////// @@ -31,19 +157,59 @@ fzy_init(void) internal FZY_Scope * fzy_scope_open(void) { - + if(fzy_tctx == 0) + { + Arena *arena = arena_alloc(); + fzy_tctx = push_array(arena, FZY_TCTX, 1); + fzy_tctx->arena = arena; + } + FZY_Scope *scope = fzy_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(fzy_tctx->free_scope); + } + else + { + scope = push_array_no_zero(fzy_tctx->arena, FZY_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; } internal void fzy_scope_close(FZY_Scope *scope) { - + for(FZY_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) + { + next = t->next; + SLLStackPush(fzy_tctx->free_touch, t); + if(t->node != 0) + { + ins_atomic_u64_dec_eval(&t->node->touch_count); + } + } + SLLStackPush(fzy_tctx->free_scope, scope); } internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node) { - + if(node != 0) + { + ins_atomic_u64_inc_eval(&node->touch_count); + } + FZY_Touch *touch = fzy_tctx->free_touch; + if(touch != 0) + { + SLLStackPop(fzy_tctx->free_touch); + } + else + { + touch = push_array_no_zero(fzy_tctx->arena, FZY_Touch, 1); + } + MemoryZeroStruct(touch); + SLLQueuePush(scope->first_touch, scope->last_touch, touch); + touch->node = node; } //////////////////////////////// @@ -52,7 +218,88 @@ fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node) internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out) { + Temp scratch = scratch_begin(0, 0); + FZY_ItemArray items = {0}; + //- rjf: hash parameters + U64 params_hash = fzy_hash_from_params(params); + + //- rjf: unpack key + U64 slot_idx = key.u64[1]%fzy_shared->slots_count; + U64 stripe_idx = slot_idx%fzy_shared->stripes_count; + FZY_Slot *slot = &fzy_shared->slots[slot_idx]; + FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx]; + + //- rjf: query and/or request + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + // rjf: map key -> node + FZY_Node *node = 0; + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + node = n; + break; + } + } + + // rjf: no node? -> allocate + if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + node = push_array(stripe->arena, FZY_Node, 1); + SLLQueuePush(slot->first, slot->last, node); + node->key = key; + for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1) + { + node->buckets[idx].arena = arena_alloc(); + } + } + + // rjf: try to grab last valid results for this key/query; determine if stale + B32 stale = 1; + if(params_hash == node->buckets[node->gen%ArrayCount(node->buckets)].params_hash && + node->gen != 0) + { + fzy_scope_touch_node__stripe_mutex_r_guarded(scope, node); + items = node->gen_items; + stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0); + if(stale_out != 0) + { + *stale_out = stale; + } + } + + // rjf: if stale -> request again + if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1) + { + node->submit_gen += 1; + arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].params = fzy_params_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, params); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].params_hash = params_hash; + } + if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) && + fzy_u2s_enqueue_req(key, endt_us)) + { + node->last_time_submitted_us = os_now_microseconds(); + } + } + + // rjf: not stale, or timeout -> break + if(!stale || os_now_microseconds() >= endt_us) + { + break; + } + + // rjf: no results, but have time to wait -> wait + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + + scratch_end(scratch); + return items; } //////////////////////////////// @@ -61,23 +308,277 @@ fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us) { - + B32 sent = 0; + FZY_Thread *thread = &fzy_shared->threads[key.u64[1]%fzy_shared->thread_count]; + OS_MutexScope(thread->u2f_ring_mutex) for(;;) + { + U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; + U64 available_size = thread->u2f_ring_size - unconsumed_size; + if(available_size >= sizeof(U128)) + { + sent = 1; + thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key); + break; + } + os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us); + } + if(sent) + { + os_condition_variable_broadcast(thread->u2f_ring_cv); + } + return sent; } internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out) { - + OS_MutexScope(thread->u2f_ring_mutex) for(;;) + { + U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; + if(unconsumed_size >= sizeof(U128)) + { + thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out); + break; + } + os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64); + } + os_condition_variable_broadcast(thread->u2f_ring_cv); } internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b) { - + int result = 0; + if(a->match_ranges.count > b->match_ranges.count) + { + result = -1; + } + else if(a->match_ranges.count < b->match_ranges.count) + { + result = +1; + } + else if(a->missed_size < b->missed_size) + { + result = -1; + } + else if(a->missed_size > b->missed_size) + { + result = +1; + } + return result; } internal void fzy_search_thread__entry_point(void *p) { - + ThreadNameF("[fzy] searcher #%I64u", (U64)p); + FZY_Thread *thread = &fzy_shared->threads[(U64)p]; + for(;;) + { + Temp scratch = scratch_begin(0, 0); + DI_Scope *di_scope = di_scope_open(); + + //////////////////////////// + //- rjf: dequeue next request + // + U128 key = {0}; + fzy_u2s_dequeue_req(scratch.arena, thread, &key); + U64 slot_idx = key.u64[1]%fzy_shared->slots_count; + U64 stripe_idx = slot_idx%fzy_shared->stripes_count; + FZY_Slot *slot = &fzy_shared->slots[slot_idx]; + FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx]; + + //////////////////////////// + //- rjf: grab next exe_path/query for this key + // + B32 task_is_good = 0; + Arena *task_arena = 0; + String8 query = {0}; + FZY_Params params = {FZY_Target_Procedures}; + U64 initial_submit_gen = 0; + OS_MutexScopeW(stripe->rw_mutex) + { + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + FZY_Bucket *bucket = &n->buckets[n->submit_gen%ArrayCount(n->buckets)]; + task_is_good = 1; + initial_submit_gen = n->submit_gen; + task_arena = bucket->arena; + query = bucket->query; + params = bucket->params; + break; + } + } + } + + //////////////////////////// + //- rjf: params -> look up all rdis + // + U64 rdis_count = params.dbgi_keys.count; + RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); + if(task_is_good) + { + for(U64 idx = 0; idx < rdis_count; idx += 1) + { + rdis[idx] = di_rdi_from_path_min_timestamp(di_scope, params.dbgi_keys.v[idx].path, params.dbgi_keys.v[idx].timestamp, max_U64); + } + } + + //////////////////////////// + //- rjf: search target -> info about search space + // + U64 table_ptr_off = 0; + U64 table_count_off = 0; + U64 element_name_idx_off = 0; + U64 element_size = 0; + if(task_is_good) + { + switch(params.target) + { + // NOTE(rjf): no default! + case FZY_Target_COUNT:{}break; + case FZY_Target_Procedures: + { + table_ptr_off = OffsetOf(RDI_Parsed, procedures); + table_count_off = OffsetOf(RDI_Parsed, procedures_count); + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + element_size = sizeof(RDI_Procedure); + }break; + case FZY_Target_GlobalVariables: + { + table_ptr_off = OffsetOf(RDI_Parsed, global_variables); + table_count_off = OffsetOf(RDI_Parsed, global_variables_count); + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + element_size = sizeof(RDI_GlobalVariable); + }break; + case FZY_Target_ThreadVariables: + { + table_ptr_off = OffsetOf(RDI_Parsed, thread_variables); + table_count_off = OffsetOf(RDI_Parsed, thread_variables_count); + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + element_size = sizeof(RDI_ThreadVariable); + }break; + case FZY_Target_UDTs: + { + table_ptr_off = OffsetOf(RDI_Parsed, udts); + table_count_off = OffsetOf(RDI_Parsed, udts_count); + element_size = sizeof(RDI_UDT); + }break; + } + } + + //////////////////////////// + //- rjf: rdis * query * params -> item list + // + FZY_ItemChunkList items_list = {0}; + if(task_is_good) + { + U64 base_idx = 0; + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) + { + RDI_Parsed *rdi = rdis[rdi_idx]; + void *table_base = (U8*)rdi + table_ptr_off; + U64 element_count = *MemberFromOffset(U64 *, rdi, table_count_off); + for(U64 idx = 1; task_is_good && idx < element_count; idx += 1) + { + void *element = (U8 *)(*(void **)table_base) + element_size*idx; + U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off); + if(params.target == FZY_Target_UDTs) + { + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); + name_idx_ptr = &type_node->user_defined.name_string_idx; + } + U32 name_idx = *name_idx_ptr; + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); + String8 name = str8(name_base, name_size); + if(name.size == 0) { continue; } + FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name); + if(matches.count == matches.needle_part_count) + { + FZY_ItemChunk *chunk = items_list.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, FZY_ItemChunk, 1); + chunk->cap = 1024; + chunk->count = 0; + chunk->v = push_array_no_zero(scratch.arena, FZY_Item, chunk->cap); + SLLQueuePush(items_list.first, items_list.last, chunk); + items_list.chunk_count += 1; + } + chunk->v[chunk->count].idx = base_idx + idx; + chunk->v[chunk->count].match_ranges = matches; + chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0; + chunk->count += 1; + items_list.total_count += 1; + } + if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex) + { + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen) + { + task_is_good = 0; + break; + } + } + } + } + base_idx += element_count; + } + } + + //- rjf: item list -> item array + FZY_ItemArray items = {0}; + if(task_is_good) + { + items.count = items_list.total_count; + items.v = push_array_no_zero(task_arena, FZY_Item, items.count); + U64 idx = 0; + for(FZY_ItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next) + { + MemoryCopy(items.v+idx, chunk->v, sizeof(FZY_Item)*chunk->count); + idx += chunk->count; + } + } + + //- rjf: sort item array + if(items.count != 0 && query.size != 0) + { + qsort(items.v, items.count, sizeof(FZY_Item), (int (*)(const void *, const void *))fzy_qsort_compare_items); + } + + //- rjf: commit to cache - busyloop on scope touches + if(task_is_good) + { + for(B32 done = 0; !done;) + { + B32 found = 0; + OS_MutexScopeW(stripe->rw_mutex) for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + if(n->touch_count == 0) + { + n->gen = initial_submit_gen; + n->gen_items = items; + done = 1; + } + found = 1; + break; + } + } + if(!found) + { + break; + } + } + } + + di_scope_close(di_scope); + scratch_end(scratch); + } } diff --git a/src/fuzzy_search/fuzzy_search.h b/src/fuzzy_search/fuzzy_search.h index 99fc5aa8..a2b83a1e 100644 --- a/src/fuzzy_search/fuzzy_search.h +++ b/src/fuzzy_search/fuzzy_search.h @@ -5,28 +5,12 @@ #define FUZZY_SEARCH_H //////////////////////////////// -//~ rjf: Fuzzy Search Types - -typedef enum FZY_Target -{ - FZY_Target_Procedures, - FZY_Target_GlobalVariables, - FZY_Target_ThreadVariables, - FZY_Target_UDTs, - FZY_Target_COUNT -} -FZY_Target; - -typedef struct FZY_Params FZY_Params; -struct FZY_Params -{ - FZY_Target target; -}; +//~ rjf: Result Types typedef struct FZY_Item FZY_Item; struct FZY_Item { - U64 idx; + U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count) U64 missed_size; FuzzyMatchRangeList match_ranges; }; @@ -56,12 +40,65 @@ struct FZY_ItemArray U64 count; }; +//////////////////////////////// +//~ rjf: Search Parameter Types + +typedef enum FZY_Target +{ + FZY_Target_Procedures, + FZY_Target_GlobalVariables, + FZY_Target_ThreadVariables, + FZY_Target_UDTs, + FZY_Target_COUNT +} +FZY_Target; + +typedef struct FZY_DbgiKey FZY_DbgiKey; +struct FZY_DbgiKey +{ + String8 path; + U64 timestamp; +}; + +typedef struct FZY_DbgiKeyNode FZY_DbgiKeyNode; +struct FZY_DbgiKeyNode +{ + FZY_DbgiKeyNode *next; + FZY_DbgiKey v; +}; + +typedef struct FZY_DbgiKeyList FZY_DbgiKeyList; +struct FZY_DbgiKeyList +{ + FZY_DbgiKeyNode *first; + FZY_DbgiKeyNode *last; + U64 count; +}; + +typedef struct FZY_DbgiKeyArray FZY_DbgiKeyArray; +struct FZY_DbgiKeyArray +{ + FZY_DbgiKey *v; + U64 count; +}; + +typedef struct FZY_Params FZY_Params; +struct FZY_Params +{ + FZY_Target target; + FZY_DbgiKeyArray dbgi_keys; +}; + +//////////////////////////////// +//~ rjf: Cache Types + typedef struct FZY_Bucket FZY_Bucket; struct FZY_Bucket { Arena *arena; String8 query; - FZY_Target target; + FZY_Params params; + U64 params_hash; }; typedef struct FZY_Node FZY_Node; @@ -69,7 +106,7 @@ struct FZY_Node { FZY_Node *next; U128 key; - U64 scope_touch_count; + U64 touch_count; U64 last_time_submitted_us; FZY_Bucket buckets[3]; U64 gen; @@ -92,18 +129,6 @@ struct FZY_Stripe OS_Handle cv; }; -typedef struct FZY_Thread FZY_Thread; -struct FZY_Thread -{ - OS_Handle thread; - OS_Handle u2f_ring_mutex; - OS_Handle u2f_ring_cv; - U64 u2f_ring_size; - U8 *u2f_ring_base; - U64 u2f_ring_write_pos; - U64 u2f_ring_read_pos; -}; - //////////////////////////////// //~ rjf: Scoped Access Types @@ -133,6 +158,18 @@ struct FZY_TCTX //////////////////////////////// //~ rjf: Shared State Types +typedef struct FZY_Thread FZY_Thread; +struct FZY_Thread +{ + OS_Handle thread; + OS_Handle u2f_ring_mutex; + OS_Handle u2f_ring_cv; + U64 u2f_ring_size; + U8 *u2f_ring_base; + U64 u2f_ring_write_pos; + U64 u2f_ring_read_pos; +}; + typedef struct FZY_Shared FZY_Shared; struct FZY_Shared { @@ -149,11 +186,22 @@ struct FZY_Shared FZY_Thread *threads; }; +//////////////////////////////// +//~ rjf: Globals + +global FZY_Shared *fzy_shared = 0; +thread_static FZY_TCTX *fzy_tctx = 0; + //////////////////////////////// //~ rjf: Helpers -internal U64 fzy_hash_from_string(String8 string, StringMatchFlags match_flags); +internal U64 fzy_hash_from_string(U64 seed, String8 string); +internal U64 fzy_hash_from_params(FZY_Params *params); internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx); +internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx); +internal void fzy_dbgi_key_list_push(Arena *arena, FZY_DbgiKeyList *list, FZY_DbgiKey key); +internal FZY_DbgiKeyArray fzy_dbgi_key_array_from_list(Arena *arena, FZY_DbgiKeyList *list); +internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src); //////////////////////////////// //~ rjf: Main Layer Initialization From 4a3d439c44a6c41f6ea50ee77fd3aa8ce76c4962 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 07:34:24 -0700 Subject: [PATCH 21/38] adjust symbol lister to apply to all loaded debug infos, rather than just the selected thread's debug info --- src/df/gfx/df_views.c | 102 ++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index df97121f..4528ca31 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -3233,17 +3233,37 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DI_Scope *scope = di_scope_open(); + DI_Scope *di_scope = di_scope_open(); + FZY_Scope *fzy_scope = fzy_scope_open(); F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); - DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); String8 query = str8(view->query_buffer, view->query_string_size); - TG_Graph *graph = tg_graph_begin(bit_size_from_arch(df_architecture_from_entity(thread))/8, 256); + DF_EntityList dbgis_list = df_push_active_dbgi_list(scratch.arena); + DF_EntityArray dbgis = df_entity_array_from_list(scratch.arena, &dbgis_list); + U64 endt_us = os_now_microseconds()+200; + + //- rjf: produce fuzzy search parameters + FZY_Params params = {FZY_Target_Procedures}; + { + params.dbgi_keys.count = dbgis.count; + params.dbgi_keys.v = push_array(scratch.arena, FZY_DbgiKey, params.dbgi_keys.count); + for(U64 idx = 0; idx < params.dbgi_keys.count; idx += 1) + { + params.dbgi_keys.v[idx].path = df_full_path_from_entity(scratch.arena, dbgis.v[idx]); + params.dbgi_keys.v[idx].timestamp = dbgis.v[idx]->timestamp; + } + } + + //- rjf: grab rdis, make type graphs for each + U64 rdis_count = dbgis.count; + RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); + TG_Graph **graphs = push_array(scratch.arena, TG_Graph *, rdis_count); + { + for(U64 idx = 0; idx < rdis_count; idx += 1) + { + rdis[idx] = di_rdi_from_path_min_timestamp(di_scope, params.dbgi_keys.v[idx].path, params.dbgi_keys.v[idx].timestamp, endt_us); + graphs[idx] = tg_graph_begin(rdi_addr_size_from_arch(rdis[idx]->top_level_info->architecture), 256); + } + } //- rjf: grab state typedef struct DF_SymbolListerViewState DF_SymbolListerViewState; @@ -3256,8 +3276,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: query -> raddbg, filtered items U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - // TODO(rjf): @fuzzy - FZY_ItemArray items = {0}; // dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); + FZY_ItemArray items = fzy_items_from_key_params_query(fzy_scope, fuzzy_search_key, ¶ms, query, endt_us, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -3266,16 +3285,27 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: submit best match when hitting enter w/ no selection if(slv->cursor.y == 0 && items.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) { - RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, items.v[0].idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); - String8 name = str8(name_base, name_size); - if(name.size != 0) + FZY_Item *item = &items.v[0]; + U64 base_idx = 0; + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) { - DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); - p.string = name; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); - df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); + RDI_Parsed *rdi = rdis[rdi_idx]; + if(base_idx <= item->idx && item->idx < base_idx + rdi->procedures_count) + { + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx-base_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); + String8 name = str8(name_base, name_size); + if(name.size != 0) + { + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.string = name; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); + } + break; + } + base_idx += rdi->procedures_count; } } @@ -3309,12 +3339,35 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) UI_Focus((slv->cursor.y == idx+1) ? UI_FocusKind_On : UI_FocusKind_Off) { FZY_Item *item = &items.v[idx]; - RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx); + + //- rjf: determine dbgi/rdi to which this item belongs + DF_Entity *dbgi = &df_g_nil_entity; + RDI_Parsed *rdi = &di_rdi_parsed_nil; + TG_Graph *graph = 0; + U64 base_idx = 0; + { + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) + { + if(base_idx <= item->idx && item->idx < base_idx + rdis[rdi_idx]->procedures_count) + { + dbgi = dbgis.v[rdi_idx]; + rdi = rdis[rdi_idx]; + graph = graphs[rdi_idx]; + break; + } + base_idx += rdis[rdi_idx]->procedures_count; + } + } + + //- rjf: unpack this item's info + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx-base_idx); U64 name_size = 0; U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); String8 name = str8(name_base, name_size); RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, procedure->type_idx); TG_Key type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), procedure->type_idx); + + //- rjf: build item button ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBackground| @@ -3327,12 +3380,14 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { UI_Box *box = df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges); - if(!tg_key_match(tg_key_zero(), type_key)) + if(!tg_key_match(tg_key_zero(), type_key) && graph != 0) { String8 type_string = tg_string_from_key(scratch.arena, graph, rdi, type_key); df_code_label(0.5f, 0, df_rgba_from_theme_color(DF_ThemeColor_WeakText), type_string); } } + + //- rjf: interact UI_Signal sig = ui_signal_from_box(box); if(ui_clicked(sig)) { @@ -3364,7 +3419,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } } - di_scope_close(scope); + fzy_scope_close(fzy_scope); + di_scope_close(di_scope); scratch_end(scratch); ProfEnd(); } From 21fcfd28a4e5d4fed0997f39a3ff705d87c57d5f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 07:38:30 -0700 Subject: [PATCH 22/38] appease clang --- src/df/core/df_core.h | 2 +- src/fuzzy_search/fuzzy_search.c | 2 +- src/raddbg/raddbg.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index a27f7416..49dbfa0d 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1148,7 +1148,7 @@ struct DF_State // rjf: per-run caches U64 unwind_cache_reggen_idx; U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_caches[4]; + DF_RunUnwindCache unwind_caches[2]; U64 unwind_cache_gen; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; diff --git a/src/fuzzy_search/fuzzy_search.c b/src/fuzzy_search/fuzzy_search.c index 5d4ba473..a6e3f0fa 100644 --- a/src/fuzzy_search/fuzzy_search.c +++ b/src/fuzzy_search/fuzzy_search.c @@ -109,7 +109,7 @@ fzy_dbgi_key_array_from_list(Arena *arena, FZY_DbgiKeyList *list) internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src) { - FZY_Params dst = {0}; + FZY_Params dst = zero_struct; MemoryCopyStruct(&dst, src); dst.dbgi_keys.v = push_array(arena, FZY_DbgiKey, dst.dbgi_keys.count); MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(FZY_DbgiKey)*src->dbgi_keys.count); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index f55e3c09..73d12983 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -39,7 +39,6 @@ // // [ ] robustify dbgi layer to renames (cache should not be based only on // path - must invalidate naturally when new filetime occurs) -// [ ] new fuzzy searching layer // // [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly // [ ] PDB files distributed with the build are not found by DbgHelp!!! @@ -377,6 +376,7 @@ // thread, instead of just the ID. // [x] TLS eval -> in-process-memory EXE info // [x] unwinding -> in-process-memory EXE info +// [x] new fuzzy searching layer #ifndef RADDBG_H #define RADDBG_H From 1621dc0637f94af52e81aa750fe2d8b03d5996ba Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 07:54:28 -0700 Subject: [PATCH 23/38] correct nil rdi top-level-info --- src/dbgi2/dbgi2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbgi2/dbgi2.h b/src/dbgi2/dbgi2.h index fc275350..73fc0da8 100644 --- a/src/dbgi2/dbgi2.h +++ b/src/dbgi2/dbgi2.h @@ -174,7 +174,7 @@ global RDI_Parsed di_rdi_parsed_nil = 0, 0, 0, - 0, + &rdi_top_level_info_nil, &rdi_binary_section_nil, 1, &rdi_file_path_node_nil, 1, &rdi_source_file_nil, 1, From 68a92e910a31a5bfc3ba6b6347ff55561b570943 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 08:26:16 -0700 Subject: [PATCH 24/38] eliminate old dbgi layer --- src/dbgi/dbgi.c | 1633 ++++++++++++------------------------ src/dbgi/dbgi.h | 524 ++++-------- src/dbgi2/dbgi2.c | 872 ------------------- src/dbgi2/dbgi2.h | 251 ------ src/raddbg/raddbg_main.cpp | 6 +- 5 files changed, 721 insertions(+), 2565 deletions(-) delete mode 100644 src/dbgi2/dbgi2.c delete mode 100644 src/dbgi2/dbgi2.h diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 1a341c20..c8fed823 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -2,90 +2,10 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -dbgi_init(void) -{ - Arena *arena = arena_alloc(); - dbgi_shared = push_array(arena, DBGI_Shared, 1); - dbgi_shared->arena = arena; - dbgi_shared->force_slots_count = 1024; - dbgi_shared->force_stripes_count = Min(dbgi_shared->force_slots_count, os_logical_core_count()); - dbgi_shared->force_slots = push_array(arena, DBGI_ForceSlot, dbgi_shared->force_slots_count); - dbgi_shared->force_stripes = push_array(arena, DBGI_ForceStripe, dbgi_shared->force_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->force_stripes_count; idx += 1) - { - dbgi_shared->force_stripes[idx].arena = arena_alloc(); - dbgi_shared->force_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->force_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->binary_slots_count = 1024; - dbgi_shared->binary_stripes_count = Min(dbgi_shared->binary_slots_count, os_logical_core_count()); - dbgi_shared->binary_slots = push_array(arena, DBGI_BinarySlot, dbgi_shared->binary_slots_count); - dbgi_shared->binary_stripes = push_array(arena, DBGI_BinaryStripe, dbgi_shared->binary_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->binary_stripes_count; idx += 1) - { - dbgi_shared->binary_stripes[idx].arena = arena_alloc(); - dbgi_shared->binary_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->binary_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->fuzzy_search_slots_count = 64; - dbgi_shared->fuzzy_search_stripes_count = Min(dbgi_shared->fuzzy_search_slots_count, os_logical_core_count()); - dbgi_shared->fuzzy_search_slots = push_array(arena, DBGI_FuzzySearchSlot, dbgi_shared->fuzzy_search_slots_count); - dbgi_shared->fuzzy_search_stripes = push_array(arena, DBGI_FuzzySearchStripe, dbgi_shared->fuzzy_search_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->fuzzy_search_stripes_count; idx += 1) - { - dbgi_shared->fuzzy_search_stripes[idx].arena = arena_alloc(); - dbgi_shared->fuzzy_search_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->fuzzy_search_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->u2p_ring_mutex = os_mutex_alloc(); - dbgi_shared->u2p_ring_cv = os_condition_variable_alloc(); - dbgi_shared->u2p_ring_size = KB(64); - dbgi_shared->u2p_ring_base = push_array_no_zero(arena, U8, dbgi_shared->u2p_ring_size); - dbgi_shared->p2u_ring_mutex = os_mutex_alloc(); - dbgi_shared->p2u_ring_cv = os_condition_variable_alloc(); - dbgi_shared->p2u_ring_size = KB(64); - dbgi_shared->p2u_ring_base = push_array_no_zero(arena, U8, dbgi_shared->p2u_ring_size); - dbgi_shared->parse_thread_count = Max(os_logical_core_count()-1, 1); - dbgi_shared->parse_threads = push_array(arena, OS_Handle, dbgi_shared->parse_thread_count); - for(U64 idx = 0; idx < dbgi_shared->parse_thread_count; idx += 1) - { - dbgi_shared->parse_threads[idx] = os_launch_thread(dbgi_parse_thread_entry_point, (void *)idx, 0); - } - dbgi_shared->fuzzy_thread_count = Clamp(1, os_logical_core_count()-1, 1); - dbgi_shared->fuzzy_threads = push_array(arena, DBGI_FuzzySearchThread, dbgi_shared->fuzzy_thread_count); - for(U64 idx = 0; idx < dbgi_shared->fuzzy_thread_count; idx += 1) - { - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[idx]; - thread->u2f_ring_mutex = os_mutex_alloc(); - thread->u2f_ring_cv = os_condition_variable_alloc(); - thread->u2f_ring_size = KB(64); - thread->u2f_ring_base = push_array_no_zero(dbgi_shared->arena, U8, thread->u2f_ring_size); - thread->thread = os_launch_thread(dbgi_fuzzy_thread__entry_point, (void *)idx, 0); - } -} - -//////////////////////////////// -//~ rjf: Thread-Context Idempotent Initialization - -internal void -dbgi_ensure_tctx_inited(void) -{ - if(dbgi_tctx == 0) - { - Arena *arena = arena_alloc(); - dbgi_tctx = push_array(arena, DBGI_ThreadCtx, 1); - dbgi_tctx->arena = arena; - } -} - -//////////////////////////////// -//~ rjf: Helpers +//~ rjf: Basic Helpers internal U64 -dbgi_hash_from_string(String8 string, StringMatchFlags match_flags) +di_hash_from_string(String8 string, StringMatchFlags match_flags) { U64 result = 5381; for(U64 i = 0; i < string.size; i += 1) @@ -95,459 +15,422 @@ dbgi_hash_from_string(String8 string, StringMatchFlags match_flags) return result; } -internal U64 -dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx) -{ - U64 fuzzy_item_num = 0; - for(U64 idx = 0; idx < array->count; idx += 1) - { - if(array->v[idx].idx == element_idx) - { - fuzzy_item_num = idx+1; - break; - } - } - return fuzzy_item_num; -} - -internal String8 -dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx) -{ - String8 result = {0}; - switch(target) - { - // NOTE(rjf): no default - warn if we miss a case - case DBGI_FuzzySearchTarget_Procedures: - { - RDI_Procedure *proc = rdi_element_from_idx(rdi, procedures, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_GlobalVariables: - { - RDI_GlobalVariable *gvar = rdi_element_from_idx(rdi, global_variables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_ThreadVariables: - { - RDI_ThreadVariable *tvar = rdi_element_from_idx(rdi, thread_variables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_UDTs: - { - RDI_UDT *udt = rdi_element_from_idx(rdi, udts, element_idx); - RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_COUNT:{}break; - } - return result; -} - //////////////////////////////// -//~ rjf: Forced Override Cache Functions +//~ rjf: Main Layer Initialization internal void -dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path) +di_init(void) { - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->force_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; - DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; - DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + Arena *arena = arena_alloc(); + di_shared = push_array(arena, DI_Shared, 1); + di_shared->arena = arena; + di_shared->slots_count = 1024; + di_shared->slots = push_array(arena, DI_Slot, di_shared->slots_count); + di_shared->stripes_count = Min(di_shared->slots_count, os_logical_core_count()); + di_shared->stripes = push_array(arena, DI_Stripe, di_shared->stripes_count); + for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) { - DBGI_ForceNode *node = 0; - for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) - { - if(str8_match(n->exe_path, exe_path, match_flags)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(stripe->arena, DBGI_ForceNode, 1); - SLLQueuePush(slot->first, slot->first, node); - node->exe_path = push_str8_copy(stripe->arena, exe_path); - node->dbg_path_cap = 1024; - node->dbg_path_base = push_array_no_zero(stripe->arena, U8, node->dbg_path_cap); - } - String8 dbg_path_clamped = dbg_path; - dbg_path_clamped.size = Min(dbg_path_clamped.size, node->dbg_path_cap); - MemoryCopy(node->dbg_path_base, dbg_path_clamped.str, dbg_path_clamped.size); - node->dbg_path_size = dbg_path_clamped.size; + di_shared->stripes[idx].arena = arena_alloc(); + di_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + di_shared->stripes[idx].cv = os_condition_variable_alloc(); } -} - -internal String8 -dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 result = {0}; - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->force_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; - DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; - DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + di_shared->u2p_ring_mutex = os_mutex_alloc(); + di_shared->u2p_ring_cv = os_condition_variable_alloc(); + di_shared->u2p_ring_size = KB(64); + di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); + di_shared->p2u_ring_mutex = os_mutex_alloc(); + di_shared->p2u_ring_cv = os_condition_variable_alloc(); + di_shared->p2u_ring_size = KB(64); + di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); + di_shared->parse_thread_count = Max(2, os_logical_core_count()/2); + di_shared->parse_threads = push_array(arena, OS_Handle, di_shared->parse_thread_count); + for(U64 idx = 0; idx < di_shared->parse_thread_count; idx += 1) { - DBGI_ForceNode *node = 0; - for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) - { - if(str8_match(exe_path, n->exe_path, match_flags)) - { - node = n; - break; - } - } - if(node != 0) - { - String8 dbg_path = str8(node->dbg_path_base, node->dbg_path_size); - result = push_str8_copy(arena, dbg_path); - } + di_shared->parse_threads[idx] = os_launch_thread(di_parse_thread__entry_point, (void *)idx, 0); } - return result; } //////////////////////////////// //~ rjf: Scope Functions -internal DBGI_Scope * -dbgi_scope_open(void) +internal DI_Scope * +di_scope_open(void) { - dbgi_ensure_tctx_inited(); - DBGI_Scope *scope = dbgi_tctx->free_scope; + if(di_tctx == 0) + { + Arena *arena = arena_alloc(); + di_tctx = push_array(arena, DI_TCTX, 1); + di_tctx->arena = arena; + } + DI_Scope *scope = di_tctx->free_scope; if(scope != 0) { - SLLStackPop(dbgi_tctx->free_scope); - MemoryZeroStruct(scope); + SLLStackPop(di_tctx->free_scope); } else { - scope = push_array(dbgi_tctx->arena, DBGI_Scope, 1); + scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); } + MemoryZeroStruct(scope); return scope; } internal void -dbgi_scope_close(DBGI_Scope *scope) +di_scope_close(DI_Scope *scope) { - for(DBGI_TouchedBinary *tb = scope->first_tb, *next = 0; tb != 0; tb = next) + for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) { - next = tb->next; - ins_atomic_u64_dec_eval(&tb->binary->scope_touch_count); - SLLStackPush(dbgi_tctx->free_tb, tb); + next = t->next; + SLLStackPush(di_tctx->free_touch, t); + if(t->node != 0) + { + ins_atomic_u64_dec_eval(&t->node->touch_count); + } } - for(DBGI_TouchedFuzzySearch *tfs = scope->first_tfs, *next = 0; tfs != 0; tfs = next) - { - next = tfs->next; - ins_atomic_u64_dec_eval(&tfs->node->scope_touch_count); - SLLStackPush(dbgi_tctx->free_tfs, tfs); - } - SLLStackPush(dbgi_tctx->free_scope, scope); + SLLStackPush(di_tctx->free_scope, scope); } internal void -dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary) +di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) { - DBGI_TouchedBinary *tb = dbgi_tctx->free_tb; - ins_atomic_u64_inc_eval(&binary->scope_touch_count); - if(tb != 0) + if(node != 0) { - SLLStackPop(dbgi_tctx->free_tb); + ins_atomic_u64_inc_eval(&node->touch_count); + } + DI_Touch *touch = di_tctx->free_touch; + if(touch != 0) + { + SLLStackPop(di_tctx->free_touch); } else { - tb = push_array(dbgi_tctx->arena, DBGI_TouchedBinary, 1); + touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); } - tb->binary = binary; - SLLQueuePush(scope->first_tb, scope->last_tb, tb); -} - -internal void -dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_FuzzySearchNode *node) -{ - DBGI_TouchedFuzzySearch *tfs = dbgi_tctx->free_tfs; - ins_atomic_u64_inc_eval(&node->scope_touch_count); - if(tfs != 0) - { - SLLStackPop(dbgi_tctx->free_tfs); - } - else - { - tfs = push_array(dbgi_tctx->arena, DBGI_TouchedFuzzySearch, 1); - } - tfs->node = node; - SLLQueuePush(scope->first_tfs, scope->last_tfs, tfs); + MemoryZeroStruct(touch); + SLLQueuePush(scope->first_touch, scope->last_touch, touch); + touch->node = node; } //////////////////////////////// -//~ rjf: Binary Cache Functions +//~ rjf: Per-Slot Functions -internal void -dbgi_binary_open(String8 exe_path) +internal DI_Node * +di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp) { - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); + DI_Node *node = 0; StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - B32 is_new = 0; - OS_MutexScopeW(stripe->rw_mutex) + U64 most_recent_timestamp = max_U64; + for(DI_Node *n = slot->first; n != 0; n = n->next) { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + if(str8_match(n->path, path, match_flags) && + min_timestamp <= n->min_timestamp && + (n->min_timestamp - min_timestamp) <= most_recent_timestamp) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary == 0) - { - binary = push_array(stripe->arena, DBGI_Binary, 1); - SLLQueuePush(slot->first, slot->last, binary); - binary->exe_path = push_str8_copy(stripe->arena, exe_path); - binary->gen += 1; - } - binary->refcount += 1; - is_new = (binary->refcount == 1); - } - if(is_new) - { - dbgi_u2p_enqueue_exe_path(exe_path, 0); - } - scratch_end(scratch); -} - -internal void -dbgi_binary_close(String8 exe_path) -{ - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) - { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - B32 need_deletion = 0; - if(binary != 0 && binary->refcount>0) - { - binary->refcount -= 1; - need_deletion = (binary->refcount == 0); - } - if(need_deletion) for(;;) - { - os_rw_mutex_drop_w(stripe->rw_mutex); - for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); - os_rw_mutex_take_w(stripe->rw_mutex); - if(binary->refcount == 0 && ins_atomic_u64_eval(&binary->scope_touch_count) == 0) - { - if(binary->parse.arena != 0) { arena_release(binary->parse.arena); } - if(binary->parse.exe_base != 0) { os_file_map_view_close(binary->exe_file_map, binary->parse.exe_base); } - if(!os_handle_match(os_handle_zero(), binary->exe_file_map)) { os_file_map_close(binary->exe_file_map); } - if(!os_handle_match(os_handle_zero(), binary->exe_file)) { os_file_close(binary->exe_file); } - if(binary->parse.dbg_base != 0) { os_file_map_view_close(binary->dbg_file_map, binary->parse.dbg_base); } - if(!os_handle_match(os_handle_zero(), binary->dbg_file_map)) { os_file_map_close(binary->dbg_file_map); } - if(!os_handle_match(os_handle_zero(), binary->dbg_file)) { os_file_close(binary->dbg_file); } - binary->exe_file_map = binary->exe_file = os_handle_zero(); - binary->dbg_file_map = binary->dbg_file = os_handle_zero(); - MemoryZeroStruct(&binary->parse); - binary->last_time_enqueued_for_parse_us = 0; - binary->gen = 1; - break; - } + node = n; + most_recent_timestamp = (n->min_timestamp - min_timestamp); } } - scratch_end(scratch); -} - -internal DBGI_Parse * -dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us) -{ - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); - DBGI_Parse *parse = &dbgi_parse_nil; - if(exe_path.size != 0) - { - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - B32 sent = 0; - OS_MutexScopeR(stripe->rw_mutex) for(;;) - { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary != 0 && !(binary->flags & DBGI_BinaryFlag_ParseInFlight)) - { - if(binary->parse.gen == binary->gen) - { - dbgi_scope_touch_binary__stripe_mutex_r_guarded(scope, binary); - parse = &binary->parse; - break; - } - else if(!sent && - ins_atomic_u64_eval(&binary->last_time_enqueued_for_parse_us) == 0 && - dbgi_u2p_enqueue_exe_path(exe_path, endt_us)) - { - sent = 1; - ins_atomic_u64_eval_assign(&binary->last_time_enqueued_for_parse_us, os_now_microseconds()); - } - } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - } - scratch_end(scratch); - return parse; + return node; } //////////////////////////////// -//~ rjf: Fuzzy Search Cache Functions +//~ rjf: Per-Stripe Functions -internal DBGI_FuzzySearchItemArray -dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 exe_path, String8 query, DBGI_FuzzySearchTarget target, U64 endt_us, B32 *stale_out) +internal U64 +di_string_bucket_idx_from_string_size(U64 size) { - Temp scratch = scratch_begin(0, 0); - DBGI_FuzzySearchItemArray items = {0}; - exe_path = path_normalized_from_string(scratch.arena, exe_path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 size_rounded = u64_up_to_pow2(size+1); + size_rounded = ClampBot((1<<4), size_rounded); + U64 bucket_idx = 0; + switch(size_rounded) { - //- rjf: unpack key - U64 slot_idx = key.u64[1]%dbgi_shared->fuzzy_search_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *slot = &dbgi_shared->fuzzy_search_slots[slot_idx]; - DBGI_FuzzySearchStripe *stripe = &dbgi_shared->fuzzy_search_stripes[stripe_idx]; - - //- rjf: query and/or request - OS_MutexScopeR(stripe->rw_mutex) for(;;) + case 1<<4: {bucket_idx = 0;}break; + case 1<<5: {bucket_idx = 1;}break; + case 1<<6: {bucket_idx = 2;}break; + case 1<<7: {bucket_idx = 3;}break; + case 1<<8: {bucket_idx = 4;}break; + case 1<<9: {bucket_idx = 5;}break; + case 1<<10:{bucket_idx = 6;}break; + default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; + } + return bucket_idx; +} + +internal String8 +di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return str8_zero();} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = stripe->free_string_chunks[bucket_idx]; + + // rjf: pull from bucket free list + if(node != 0) + { + if(bucket_idx == ArrayCount(stripe->free_string_chunks)-1) { - // rjf: map key -> node - DBGI_FuzzySearchNode *node = 0; - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) + node = 0; + DI_StringChunkNode *prev = 0; + for(DI_StringChunkNode *n = stripe->free_string_chunks[bucket_idx]; + n != 0; + prev = n, n = n->next) { - if(u128_match(n->key, key)) + if(n->size >= string.size+1) { + if(prev == 0) + { + stripe->free_string_chunks[bucket_idx] = n->next; + } + else + { + prev->next = n->next; + } node = n; break; } } + } + else + { + SLLStackPop(stripe->free_string_chunks[bucket_idx]); + } + } + + // rjf: no found node -> allocate new + if(node == 0) + { + U64 chunk_size = 0; + if(bucket_idx < ArrayCount(stripe->free_string_chunks)-1) + { + chunk_size = 1<<(bucket_idx+4); + } + else + { + chunk_size = u64_up_to_pow2(string.size); + } + U8 *chunk_memory = push_array(stripe->arena, U8, chunk_size); + node = (DI_StringChunkNode *)chunk_memory; + } + + // rjf: fill string & return + String8 allocated_string = str8((U8 *)node, string.size); + MemoryCopy((U8 *)node, string.str, string.size); + return allocated_string; +} + +internal void +di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return;} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = (DI_StringChunkNode *)string.str; + node->size = u64_up_to_pow2(string.size); + SLLStackPush(stripe->free_string_chunks[bucket_idx], node); +} + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void +di_open(String8 path, U64 min_timestamp) +{ + Temp scratch = scratch_begin(0, 0); + if(path.size != 0) + { + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("opening debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); - // rjf: no node? -> allocate - if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + //- rjf: allocate node if none exists; insert into slot + if(node == 0) { - node = push_array(stripe->arena, DBGI_FuzzySearchNode, 1); - SLLQueuePush(slot->first, slot->last, node); - node->key = key; - for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1) + U64 current_timestamp = os_properties_from_file_path(path).modified; + if(current_timestamp == 0) { - node->buckets[idx].arena = arena_alloc(); + current_timestamp = min_timestamp; } + node = stripe->free_node; + if(node != 0) + { + SLLStackPop(stripe->free_node); + } + else + { + node = push_array_no_zero(stripe->arena, DI_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, path_normalized); + node->path = path_stored; + node->min_timestamp = current_timestamp; } - // rjf: try to grab last valid results for this key/query; determine if stale - B32 stale = 1; - if(str8_match(exe_path, node->buckets[node->gen%ArrayCount(node->buckets)].exe_path, match_flags) && - target == node->buckets[node->gen%ArrayCount(node->buckets)].target && - node->gen != 0) + //- rjf: increment node reference count + if(node != 0) { - dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(scope, node); - items = node->gen_items; - stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0); - *stale_out = stale; - } - - // rjf: if stale -> request again - if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex) - { - if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1) + node->ref_count += 1; + if(node->ref_count == 1) { - node->submit_gen += 1; - arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].exe_path = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, exe_path); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].target = target; - } - if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) && - dbgi_u2f_enqueue_req(key, endt_us)) - { - node->last_time_submitted_us = os_now_microseconds(); + di_u2p_enqueue_key(path_normalized, node->min_timestamp, 0); } } + } + } + scratch_end(scratch); +} + +internal void +di_close(String8 path, U64 min_timestamp) +{ + Temp scratch = scratch_begin(0, 0); + if(path.size != 0) + { + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("closing debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); - // rjf: not stale, or timeout -> break - if(!stale || os_now_microseconds() >= endt_us) + //- rjf: node exists -> decrement reference count; release + if(node != 0) + { + node->ref_count -= 1; + if(node->ref_count == 0) for(;;) + { + //- rjf: wait for touch count to go to 0 + if(ins_atomic_u64_eval(&node->touch_count) != 0) + { + os_rw_mutex_drop_w(stripe->rw_mutex); + for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); + os_rw_mutex_take_w(stripe->rw_mutex); + } + + //- rjf: release + if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) + { + di_string_release__stripe_mutex_w_guarded(stripe, node->path); + if(node->file_base != 0) + { + os_file_map_view_close(node->file_map, node->file_base); + } + if(!os_handle_match(node->file_map, os_handle_zero())) + { + os_file_map_close(node->file_map); + } + if(!os_handle_match(node->file, os_handle_zero())) + { + os_file_close(node->file); + } + if(node->arena != 0) + { + arena_release(node->arena); + } + DLLRemove(slot->first, slot->last, node); + SLLStackPush(stripe->free_node, node); + break; + } + } + } + } + } + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed * +di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us) +{ + RDI_Parsed *result = &di_rdi_parsed_nil; + if(path.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 path_normalized = path_normalized_from_string(scratch.arena, path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + //- rjf: find existing node + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + + //- rjf: no node? this path is not opened + if(node == 0) { break; } - // rjf: no results, but have time to wait -> wait - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + //- rjf: parse done -> touch, grab result + if(node != 0 && node->parse_done) + { + di_scope_touch_node__stripe_mutex_r_guarded(scope, node); + result = &node->rdi; + break; + } + + //- rjf: parse not done, not working, asked a while ago -> ask for parse + B32 sent = 0; + if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); + } + } + + //- rjf: time expired -> break + if(os_now_microseconds() >= endt_us) + { + break; + } + + //- rjf: wait on this stripe + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } } + scratch_end(scratch); } - scratch_end(scratch); - return items; + return result; } //////////////////////////////// -//~ rjf: Analysis Threads +//~ rjf: Parse Threads internal B32 -dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us) +di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us) { B32 sent = 0; - OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); - U64 available_size = dbgi_shared->u2p_ring_size-unconsumed_size; - U64 needed_size = sizeof(U64)+exe_path.size; - needed_size += 7; - needed_size -= needed_size%8; - if(available_size >= needed_size) + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + U64 available_size = di_shared->u2p_ring_size - unconsumed_size; + if(available_size >= sizeof(path.size) + path.size + sizeof(min_timestamp)) { - dbgi_shared->u2p_ring_write_pos += ring_write_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, &exe_path.size); - dbgi_shared->u2p_ring_write_pos += ring_write(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, exe_path.str, exe_path.size); - dbgi_shared->u2p_ring_write_pos += 7; - dbgi_shared->u2p_ring_write_pos -= dbgi_shared->u2p_ring_write_pos%8; + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &path.size); + di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, path.str, path.size); + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &min_timestamp); + di_shared->u2p_ring_write_pos += 7; + di_shared->u2p_ring_write_pos -= di_shared->u2p_ring_write_pos%8; sent = 1; break; } @@ -555,210 +438,141 @@ dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us) { break; } - os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, endt_us); + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); + } + if(sent) + { + os_condition_variable_broadcast(di_shared->u2p_ring_cv); } - os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); return sent; } -internal String8 -dbgi_u2p_dequeue_exe_path(Arena *arena) +internal void +di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp) { - String8 result = {0}; - OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); - if(unconsumed_size != 0) + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + if(unconsumed_size >= sizeof(out_path->size) + sizeof(out_min_timestamp[0])) { - dbgi_shared->u2p_ring_read_pos += ring_read_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, &result.size); - result.str = push_array_no_zero(arena, U8, result.size); - dbgi_shared->u2p_ring_read_pos += ring_read(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, result.str, result.size); - dbgi_shared->u2p_ring_read_pos += 7; - dbgi_shared->u2p_ring_read_pos -= dbgi_shared->u2p_ring_read_pos%8; + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_path->size); + out_path->str = push_array(arena, U8, out_path->size); + di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_path->str, out_path->size); + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_min_timestamp); + di_shared->u2p_ring_read_pos += 7; + di_shared->u2p_ring_read_pos -= di_shared->u2p_ring_read_pos%8; break; } - os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, max_U64); + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); } - os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); - return result; + os_condition_variable_broadcast(di_shared->u2p_ring_cv); } internal void -dbgi_p2u_push_event(DBGI_Event *event) +di_p2u_push_event(DI_Event *event) { - OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); - U64 available_size = dbgi_shared->p2u_ring_size-unconsumed_size; - U64 needed_size = sizeof(DBGI_EventKind) + sizeof(U64) + event->string.size; + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + U64 available_size = di_shared->p2u_ring_size-unconsumed_size; + U64 needed_size = sizeof(DI_EventKind) + sizeof(U64) + event->string.size; if(available_size >= needed_size) { - dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->kind); - dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->string.size); - dbgi_shared->p2u_ring_write_pos += ring_write(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, event->string.str, event->string.size); - dbgi_shared->p2u_ring_write_pos += 7; - dbgi_shared->p2u_ring_write_pos -= dbgi_shared->p2u_ring_write_pos%8; + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->kind); + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->string.size); + di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); + di_shared->p2u_ring_write_pos += 7; + di_shared->p2u_ring_write_pos -= di_shared->p2u_ring_write_pos%8; break; } - os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, max_U64); + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); } - os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); + os_condition_variable_broadcast(di_shared->p2u_ring_cv); } -internal DBGI_EventList -dbgi_p2u_pop_events(Arena *arena, U64 endt_us) +internal DI_EventList +di_p2u_pop_events(Arena *arena, U64 endt_us) { - DBGI_EventList events = {0}; - OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + DI_EventList events = {0}; + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); - if(unconsumed_size >= sizeof(DBGI_EventKind) + sizeof(U64)) + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) { - DBGI_EventNode *n = push_array(arena, DBGI_EventNode, 1); + DI_EventNode *n = push_array(arena, DI_EventNode, 1); SLLQueuePush(events.first, events.last, n); events.count += 1; - dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.kind); - dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.string.size); + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.kind); + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.string.size); n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); - dbgi_shared->p2u_ring_read_pos += ring_read(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); - dbgi_shared->p2u_ring_read_pos += 7; - dbgi_shared->p2u_ring_read_pos -= dbgi_shared->p2u_ring_read_pos%8; + di_shared->p2u_ring_read_pos += ring_read(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); + di_shared->p2u_ring_read_pos += 7; + di_shared->p2u_ring_read_pos -= di_shared->p2u_ring_read_pos%8; } else if(os_now_microseconds() >= endt_us) { break; } - os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, endt_us); + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); } - os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); + os_condition_variable_broadcast(di_shared->p2u_ring_cv); return events; } internal void -dbgi_parse_thread_entry_point(void *p) +di_parse_thread__entry_point(void *p) { - ThreadNameF("[dbgi] parse #%I64U", (U64)p); + ThreadNameF("[di] parse #%I64u", (U64)p); for(;;) { Temp scratch = scratch_begin(0, 0); - //- rjf: grab next path & unpack - String8 exe_path = dbgi_u2p_dequeue_exe_path(scratch.arena); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - ProfBegin("begin task for \"%.*s\"", str8_varg(exe_path)); - U64 hash = dbgi_hash_from_string(exe_path, path_match_flags_from_os(operating_system_from_context())); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + //////////////////////////// + //- rjf: grab next key + // + String8 og_path = {0}; + U64 min_timestamp = 0; + di_u2p_dequeue_key(scratch.arena, &og_path, &min_timestamp); - //- rjf: determine if binary's analysis work is taken by another thread. - // if not, take it - B32 task_is_taken_by_other_thread = 0; - OS_MutexScopeW(stripe->rw_mutex) + //////////////////////////// + //- rjf: unpack key + // + U64 hash = di_hash_from_string(og_path, StringMatchFlag_CaseInsensitive); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + + //////////////////////////// + //- rjf: take task + // + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); + if(node != 0) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary == 0 || binary->flags&DBGI_BinaryFlag_ParseInFlight || binary->refcount == 0) - { - task_is_taken_by_other_thread = 1; - } - else if(binary != 0) - { - binary->flags |= DBGI_BinaryFlag_ParseInFlight; + got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); } } - //- rjf: is the work taken? -> abort - B32 do_task = 1; - if(task_is_taken_by_other_thread) + //////////////////////////// + //- rjf: got task -> open O.G. file (may or may not be RDI) + // + B32 og_format_is_known = 0; + B32 og_is_pe = 0; + B32 og_is_pdb = 0; + B32 og_is_elf = 0; + B32 og_is_rdi = 0; + FileProperties og_props = {0}; + if(got_task) ProfScope("analyze %.*s", str8_varg(og_path)) { - do_task = 0; - } - - //- rjf: open exe file & map into address space - OS_Handle exe_file = {0}; - FileProperties exe_file_props = {0}; - OS_Handle exe_file_map = {0}; - void *exe_file_base = 0; - if(do_task) - { - exe_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, exe_path); - exe_file_props = os_properties_from_file(exe_file); - exe_file_map = os_file_map_open(OS_AccessFlag_Read, exe_file); - exe_file_base = os_file_map_view_open(exe_file_map, OS_AccessFlag_Read, r1u64(0, exe_file_props.size)); - } - - //- rjf: parse exe file info - Arena *parse_arena = 0; - PE_BinInfo exe_pe_info = {0}; - String8 exe_dbg_path_embedded_absolute = {0}; - String8 exe_dbg_path_embedded_relative = {0}; - if(do_task) - { - parse_arena = arena_alloc(); - if(exe_file_props.size >= 2 && *(U16 *)exe_file_base == PE_DOS_MAGIC) - { - String8 exe_data = str8((U8 *)exe_file_base, exe_file_props.size); - exe_pe_info = pe_bin_info_from_data(parse_arena, exe_data); - exe_dbg_path_embedded_absolute = str8_cstring_capped((char *)exe_data.str+exe_pe_info.dbg_path_off, (char *)exe_data.str+exe_pe_info.dbg_path_off+Min(exe_data.size-exe_pe_info.dbg_path_off, 4096)); - String8 exe_folder = str8_chop_last_slash(exe_path); - exe_dbg_path_embedded_relative = push_str8f(scratch.arena, "%S/%S", exe_folder, exe_dbg_path_embedded_absolute); - } - } - - //- rjf: determine O.G. (may or may not be RADDBG) dbg path - String8 og_dbg_path = {0}; - if(do_task) ProfScope("determine O.G. dbg path") - { - String8 forced_og_dbg_path = dbgi_forced_dbg_path_from_exe_path(scratch.arena, exe_path); - if(forced_og_dbg_path.size != 0) - { - og_dbg_path = forced_og_dbg_path; - } - else - { - String8 possible_og_dbg_paths[] = - { - /* inferred (treated as absolute): */ exe_dbg_path_embedded_absolute, - /* inferred (treated as relative): */ exe_dbg_path_embedded_relative, - /* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)), - /* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", exe_path), - }; - for(U64 idx = 0; idx < ArrayCount(possible_og_dbg_paths); idx += 1) - { - FileProperties props = os_properties_from_file_path(possible_og_dbg_paths[idx]); - if(props.modified != 0 && props.size != 0) - { - og_dbg_path = possible_og_dbg_paths[idx]; - break; - } - } - } - } - - //- rjf: analyze O.G. dbg file - B32 og_dbg_format_is_known = 0; - B32 og_dbg_is_pe = 0; - B32 og_dbg_is_pdb = 0; - B32 og_dbg_is_elf = 0; - B32 og_dbg_is_raddbg = 0; - FileProperties og_dbg_props = {0}; - if(do_task) ProfScope("analyze O.G. dbg file") - { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_dbg_path); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_path); OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); - FileProperties props = og_dbg_props = os_properties_from_file(file); + FileProperties props = og_props = os_properties_from_file(file); void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); String8 data = str8((U8 *)base, props.size); - if(!og_dbg_format_is_known) + if(!og_format_is_known) { String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); @@ -767,19 +581,19 @@ dbgi_parse_thread_entry_point(void *p) (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) { - og_dbg_format_is_known = 1; - og_dbg_is_pdb = 1; + og_format_is_known = 1; + og_is_pdb = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) { - og_dbg_format_is_known = 1; - og_dbg_is_raddbg = 1; + og_format_is_known = 1; + og_is_rdi = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { if(data.size >= 4 && data.str[0] == 0x7f && @@ -787,16 +601,16 @@ dbgi_parse_thread_entry_point(void *p) data.str[2] == 'L' && data.str[3] == 'F') { - og_dbg_format_is_known = 1; - og_dbg_is_elf = 1; + og_format_is_known = 1; + og_is_elf = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) { - og_dbg_format_is_known = 1; - og_dbg_is_pe = 1; + og_format_is_known = 1; + og_is_pe = 1; } } os_file_map_view_close(file_map, base); @@ -804,41 +618,47 @@ dbgi_parse_thread_entry_point(void *p) os_file_close(file); } - //- rjf: given O.G. path & analysis, determine RADDBG file path - String8 raddbgi_path = {0}; - if(do_task) + //////////////////////////// + //- rjf: given O.G. path & analysis, determine RDI path + // + String8 rdi_path = {0}; + if(got_task) { - if(og_dbg_is_raddbg) + if(og_is_rdi) { - raddbgi_path = og_dbg_path; + rdi_path = og_path; } - else if(og_dbg_format_is_known && og_dbg_is_pdb) + else if(og_format_is_known && og_is_pdb) { - raddbgi_path = push_str8f(scratch.arena, "%S.raddbgi", str8_chop_last_dot(og_dbg_path)); + rdi_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); } } - //- rjf: check if raddbg file is up-to-date - B32 raddbgi_file_is_up_to_date = 0; - if(do_task) + //////////////////////////// + //- rjf: check if rdi file is up-to-date + // + B32 rdi_file_is_up_to_date = 0; + if(got_task) { - if(raddbgi_path.size != 0) + if(rdi_path.size != 0) ProfScope("check %.*s is up-to-date", str8_varg(rdi_path)) { - FileProperties props = os_properties_from_file_path(raddbgi_path); - raddbgi_file_is_up_to_date = (props.modified > og_dbg_props.modified); + FileProperties props = os_properties_from_file_path(rdi_path); + rdi_file_is_up_to_date = (props.modified > og_props.modified); } } + //////////////////////////// //- rjf: if raddbg file is up to date based on timestamp, check the // encoding generation number & size, to see if we need to regenerate it // regardless - if(do_task && raddbgi_file_is_up_to_date) + // + if(got_task && rdi_file_is_up_to_date) ProfScope("check %.*s version matches our's", str8_varg(rdi_path)) { OS_Handle file = {0}; OS_Handle file_map = {0}; FileProperties file_props = {0}; void *file_base = 0; - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, raddbgi_path); + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, rdi_path); file_map = os_file_map_open(OS_AccessFlag_Read, file); file_props = os_properties_from_file(file); file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); @@ -847,213 +667,140 @@ dbgi_parse_thread_entry_point(void *p) RDI_Header *header = (RDI_Header*)file_base; if(header->encoding_version != RDI_ENCODING_VERSION) { - raddbgi_file_is_up_to_date = 0; + rdi_file_is_up_to_date = 0; } } else { - raddbgi_file_is_up_to_date = 0; + rdi_file_is_up_to_date = 0; } os_file_map_view_close(file_map, file_base); os_file_map_close(file_map); os_file_close(file); } + //////////////////////////// //- rjf: heuristically choose compression settings + // B32 should_compress = 0; +#if 0 if(og_dbg_props.size > MB(64)) { should_compress = 1; } +#endif - //- rjf: raddbg file not up-to-date? we need to generate it - if(do_task) + //////////////////////////// + //- rjf: rdi file not up-to-date? we need to generate it + // + if(got_task && !rdi_file_is_up_to_date) ProfScope("generate %.*s", str8_varg(rdi_path)) { - if(!raddbgi_file_is_up_to_date) ProfScope("generate raddbg file") + if(og_is_pdb) { - if(og_dbg_is_pdb) + //- rjf: push conversion task begin event { - // rjf: push conversion task begin event + DI_Event event = {DI_EventKind_ConversionStarted}; + event.string = rdi_path; + di_p2u_push_event(&event); + } + + //- rjf: kick off process + OS_Handle process = {0}; + { + OS_LaunchOptions opts = {0}; + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); + opts.inherit_env = 1; + opts.consoleless = 1; + str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); + if(should_compress) { - DBGI_Event event = {DBGI_EventKind_ConversionStarted}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); } - - // rjf: kick off process - OS_Handle process = {0}; + //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", rdi_path); + os_launch_process(&opts, &process); + } + + //- rjf: wait for process to complete + { + U64 start_wait_t = os_now_microseconds(); + for(;;) { - OS_LaunchOptions opts = {0}; - opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); - opts.inherit_env = 1; - opts.consoleless = 1; - str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); - if(should_compress) + B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); + if(wait_done) { - str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); - } - //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--exe:%S", exe_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_dbg_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", raddbgi_path); - os_launch_process(&opts, &process); - } - - // rjf: wait for process to complete - { - U64 start_wait_t = os_now_microseconds(); - for(;;) - { - B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); - if(wait_done) - { - raddbgi_file_is_up_to_date = 1; - break; - } - if(os_now_microseconds()-start_wait_t > 10000000 && og_dbg_props.size < MB(64)) - { - // os_graphical_message(1, str8_lit("RADDBG INTERNAL DEVELOPMENT MESSAGE"), str8_lit("this is taking a while... indicative of something that seemed like a bug that Jeff hit before. attach with debugger now & see where the callstack is?")); - } + rdi_file_is_up_to_date = 1; + break; } } - - // rjf: push conversion task end event - { - DBGI_Event event = {DBGI_EventKind_ConversionEnded}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); - } } - else + + //- rjf: push conversion task end event { - // NOTE(rjf): we cannot convert from this O.G. debug info format right now. - // rjf: push conversion task failure event - { - DBGI_Event event = {DBGI_EventKind_ConversionFailureUnsupportedFormat}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); - } + DI_Event event = {DI_EventKind_ConversionEnded}; + event.string = rdi_path; + di_p2u_push_event(&event); } } - } - - //- rjf: open raddbg file & gather info - OS_Handle raddbgi_file = {0}; - OS_Handle raddbgi_file_map = {0}; - FileProperties raddbgi_file_props = {0}; - void *raddbgi_file_base = 0; - if(do_task && raddbgi_file_is_up_to_date) - { - raddbgi_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, raddbgi_path); - raddbgi_file_map = os_file_map_open(OS_AccessFlag_Read, raddbgi_file); - raddbgi_file_props = os_properties_from_file(raddbgi_file); - raddbgi_file_base = os_file_map_view_open(raddbgi_file_map, OS_AccessFlag_Read, r1u64(0, raddbgi_file_props.size)); - } - - //- rjf: cache write, step 0: busy-loop-wait for all scope touches to be done - if(do_task) ProfScope("cache write, step 0: busy-loop-wait for all scope touches to be done") - { - for(B32 done = 0; done == 0;) + else { - OS_MutexScopeR(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + // NOTE(rjf): we cannot convert from this O.G. debug info format right now. + //- rjf: push conversion task failure event { - if(str8_match(bin->exe_path, exe_path, match_flags) && - bin->scope_touch_count == 0) - { - done = 1; - break; - } + DI_Event event = {DI_EventKind_ConversionFailureUnsupportedFormat}; + event.string = rdi_path; + di_p2u_push_event(&event); } } } - //- rjf: cache write, step 1: check if refcount is still nonzero, & - // either EXE or raddbg file is new. if so, clear all old results & - // store new top-level info - B32 binary_refcount_is_zero = 0; - B32 raddbgi_or_exe_file_is_updated = 0; - if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear") + //////////////////////////// + //- rjf: got task -> open file + // + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + if(got_task) { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - if(bin->refcount == 0) - { - binary_refcount_is_zero = 1; - break; - } - if(bin->parse.dbg_props.modified != raddbgi_file_props.modified || - bin->parse.exe_props.modified != exe_file_props.modified) - { - raddbgi_or_exe_file_is_updated = 1; - - // rjf: clean up old stuff - if(bin->parse.arena != 0) { arena_release(bin->parse.arena); } - if(bin->parse.exe_base != 0) {os_file_map_view_close(bin->exe_file_map, bin->parse.exe_base);} - if(!os_handle_match(os_handle_zero(), bin->exe_file_map)) {os_file_map_close(bin->exe_file_map);} - if(!os_handle_match(os_handle_zero(), bin->exe_file)) {os_file_close(bin->exe_file);} - if(bin->parse.dbg_base != 0) {os_file_map_view_close(bin->dbg_file_map, bin->parse.dbg_base);} - if(!os_handle_match(os_handle_zero(), bin->dbg_file_map)) {os_file_map_close(bin->dbg_file_map);} - if(!os_handle_match(os_handle_zero(), bin->dbg_file)) {os_file_close(bin->dbg_file);} - MemoryZeroStruct(&bin->parse); - bin->last_time_enqueued_for_parse_us = 0; - - // rjf: store new handles & props - bin->exe_file = exe_file; - bin->exe_file_map = exe_file_map; - bin->parse.exe_base = exe_file_base; - bin->parse.exe_props = exe_file_props; - bin->dbg_file = raddbgi_file; - bin->dbg_file_map = raddbgi_file_map; - bin->parse.dbg_base = raddbgi_file_base; - bin->parse.dbg_props = raddbgi_file_props; - bin->gen += 1; - } - break; - } - } + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); } - //- rjf: raddbg file or exe is not new? cache can stay unmodified, close - // handles & skip to end. - if(do_task) if((!raddbgi_or_exe_file_is_updated && raddbgi_file_is_up_to_date) || binary_refcount_is_zero) + //////////////////////////// + //- rjf: do initial parse of rdi + // + RDI_Parsed rdi_parsed_maybe_compressed = di_rdi_parsed_nil; + if(got_task) { - os_file_map_view_close(raddbgi_file_map, raddbgi_file_base); - os_file_map_close(raddbgi_file_map); - os_file_close(raddbgi_file); - os_file_map_view_close(exe_file_map, exe_file_base); - os_file_map_close(exe_file_map); - os_file_close(exe_file); - arena_release(parse_arena); - do_task = 0; - } - - //- rjf: initial parse of raddbg info - RDI_Parsed rdi_parsed_maybe_compressed = dbgi_parse_nil.rdi; - if(do_task) - { - RDI_ParseStatus parse_status = rdi_parse((U8 *)raddbgi_file_base, raddbgi_file_props.size, &rdi_parsed_maybe_compressed); + RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); (void)parse_status; } - //- rjf: decompress, if necessary + //////////////////////////// + //- rjf: decompress & re-parse, if necessary + // + Arena *rdi_parsed_arena = 0; RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; - if(do_task) + if(got_task) { - U64 decompressed_size = raddbgi_file_props.size; + U64 decompressed_size = file_props.size; for(U64 dsec_idx = 0; dsec_idx < rdi_parsed_maybe_compressed.dsec_count; dsec_idx += 1) { decompressed_size += (rdi_parsed_maybe_compressed.dsecs[dsec_idx].unpacked_size - rdi_parsed_maybe_compressed.dsecs[dsec_idx].encoded_size); } - if(decompressed_size > raddbgi_file_props.size) + if(decompressed_size > file_props.size) { - U8 *decompressed_data = push_array_no_zero(parse_arena, U8, decompressed_size); + rdi_parsed_arena = arena_alloc(); + U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); // rjf: copy header - RDI_Header *src_header = (RDI_Header *)raddbgi_file_base; + RDI_Header *src_header = (RDI_Header *)file_base; RDI_Header *dst_header = (RDI_Header *)decompressed_data; { MemoryCopy(dst_header, src_header, sizeof(RDI_Header)); @@ -1063,7 +810,7 @@ dbgi_parse_thread_entry_point(void *p) if(rdi_parsed_maybe_compressed.dsec_count != 0) { RDI_DataSection *dsec_base = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); - MemoryCopy(dsec_base, (U8 *)raddbgi_file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); + MemoryCopy(dsec_base, (U8 *)file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); U64 off = dst_header->data_section_off + sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count; off += 7; off -= off%8; @@ -1089,8 +836,8 @@ dbgi_parse_thread_entry_point(void *p) src < src_opl && dst < dst_opl; src += 1, dst += 1) { - rr_lzb_simple_decode((U8*)raddbgi_file_base + src->off, src->encoded_size, - decompressed_data + dst->off, dst->unpacked_size); + rr_lzb_simple_decode((U8*)file_base + src->off, src->encoded_size, + decompressed_data + dst->off, dst->unpacked_size); } } @@ -1100,312 +847,26 @@ dbgi_parse_thread_entry_point(void *p) } } - //- rjf: cache write, step 2: store parse artifacts - B32 parse_store_good = 0; - if(do_task) ProfScope("cache write, step 2: store parse") + //////////////////////////// + //- rjf: commit parsed info to cache + // + if(got_task) OS_MutexScopeW(stripe->rw_mutex) { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); + if(node != 0) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - String8 dbg_path = og_dbg_path; - if(dbg_path.size == 0) - { - dbg_path = exe_dbg_path_embedded_absolute; - } - if(dbg_path.size == 0) - { - dbg_path = exe_dbg_path_embedded_relative; - } - if(dbg_path.size == 0) - { - dbg_path = push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)); - } - parse_store_good = 1; - bin->parse.arena = parse_arena; - bin->parse.dbg_path = push_str8_copy(parse_arena, dbg_path); - MemoryCopyStruct(&bin->parse.pe, &exe_pe_info); - MemoryCopyStruct(&bin->parse.rdi, &rdi_parsed); - bin->parse.gen = bin->gen; - break; - } + node->is_working = 0; + node->file = file; + node->file_map = file_map; + node->file_base = file_base; + node->file_props = file_props; + node->arena = rdi_parsed_arena; + node->rdi = rdi_parsed; + node->parse_done = 1; } } + os_condition_variable_broadcast(stripe->cv); - //- rjf: bad parse store? abort - if(do_task && !parse_store_good) - { - arena_release(parse_arena); - } - - //- rjf: cache write, step 3: mark binary work as complete - if(!task_is_taken_by_other_thread) ProfScope("cache write, step 4: mark binary work as complete") - { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - bin->flags &= ~DBGI_BinaryFlag_ParseInFlight; - break; - } - } - os_condition_variable_broadcast(stripe->cv); - } - - ProfEnd(); - scratch_end(scratch); - } -} - -//////////////////////////////// -//~ rjf: Fuzzy Searching Threads - -internal B32 -dbgi_u2f_enqueue_req(U128 key, U64 endt_us) -{ - B32 sent = 0; - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[key.u64[1]%dbgi_shared->fuzzy_thread_count]; - OS_MutexScope(thread->u2f_ring_mutex) for(;;) - { - U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; - U64 available_size = thread->u2f_ring_size - unconsumed_size; - if(available_size >= sizeof(U128)) - { - sent = 1; - thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key); - break; - } - os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us); - } - if(sent) - { - os_condition_variable_broadcast(thread->u2f_ring_cv); - } - return sent; -} - -internal void -dbgi_u2f_dequeue_req(Arena *arena, DBGI_FuzzySearchThread *thread, U128 *key_out) -{ - OS_MutexScope(thread->u2f_ring_mutex) for(;;) - { - U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; - if(unconsumed_size >= sizeof(U128)) - { - thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out); - break; - } - os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64); - } - os_condition_variable_broadcast(thread->u2f_ring_cv); -} - -internal int -dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchItem *b) -{ - int result = 0; - if(a->match_ranges.count > b->match_ranges.count) - { - result = -1; - } - else if(a->match_ranges.count < b->match_ranges.count) - { - result = +1; - } - else if(a->missed_size < b->missed_size) - { - result = -1; - } - else if(a->missed_size > b->missed_size) - { - result = +1; - } - return result; -} - -internal void -dbgi_fuzzy_thread__entry_point(void *p) -{ - ThreadNameF("[dbgi] fuzzy search #%I64U", (U64)p); - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[(U64)p]; - for(;;) - { - Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); - - //- rjf: dequeue next request - U128 key = {0}; - dbgi_u2f_dequeue_req(scratch.arena, thread, &key); - U64 slot_idx = key.u64[1]%dbgi_shared->fuzzy_search_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *slot = &dbgi_shared->fuzzy_search_slots[slot_idx]; - DBGI_FuzzySearchStripe *stripe = &dbgi_shared->fuzzy_search_stripes[stripe_idx]; - - //- rjf: grab next exe_path/query for this key - B32 task_is_good = 0; - Arena *task_arena = 0; - String8 exe_path = {0}; - String8 query = {0}; - DBGI_FuzzySearchTarget target = DBGI_FuzzySearchTarget_Procedures; - U64 initial_submit_gen = 0; - OS_MutexScopeW(stripe->rw_mutex) - { - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - task_is_good = 1; - initial_submit_gen = n->submit_gen; - task_arena = n->buckets[n->submit_gen%ArrayCount(n->buckets)].arena; - exe_path = n->buckets[n->submit_gen%ArrayCount(n->buckets)].exe_path; - query = n->buckets[n->submit_gen%ArrayCount(n->buckets)].query; - target = n->buckets[n->submit_gen%ArrayCount(n->buckets)].target; - break; - } - } - } - - //- rjf: exe_path -> dbgi_parse, raddbg - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; - - //- rjf: rdi * query -> item list - U64 table_ptr_off = 0; - U64 element_name_idx_off = 0; - U64 element_count = 0; - U64 element_size = 0; - switch(target) - { - // NOTE(rjf): no default! - case DBGI_FuzzySearchTarget_COUNT:{}break; - case DBGI_FuzzySearchTarget_Procedures: - { - table_ptr_off = OffsetOf(RDI_Parsed, procedures); - element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); - element_count = rdi->procedures_count; - element_size = sizeof(RDI_Procedure); - }break; - case DBGI_FuzzySearchTarget_GlobalVariables: - { - table_ptr_off = OffsetOf(RDI_Parsed, global_variables); - element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); - element_count = rdi->global_variables_count; - element_size = sizeof(RDI_GlobalVariable); - }break; - case DBGI_FuzzySearchTarget_ThreadVariables: - { - table_ptr_off = OffsetOf(RDI_Parsed, thread_variables); - element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); - element_count = rdi->thread_variables_count; - element_size = sizeof(RDI_ThreadVariable); - }break; - case DBGI_FuzzySearchTarget_UDTs: - { - table_ptr_off = OffsetOf(RDI_Parsed, udts); - element_count = rdi->udts_count; - element_size = sizeof(RDI_UDT); - }break; - } - DBGI_FuzzySearchItemChunkList items_list = {0}; - if(task_is_good) - { - void *table_base = (U8*)rdi + table_ptr_off; - for(U64 idx = 1; task_is_good && idx < element_count; idx += 1) - { - void *element = (U8 *)(*(void **)table_base) + element_size*idx; - U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off); - if(target == DBGI_FuzzySearchTarget_UDTs) - { - RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); - name_idx_ptr = &type_node->user_defined.name_string_idx; - } - U32 name_idx = *name_idx_ptr; - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); - String8 name = str8(name_base, name_size); - if(name.size == 0) { continue; } - FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name); - if(matches.count == matches.needle_part_count) - { - DBGI_FuzzySearchItemChunk *chunk = items_list.last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(scratch.arena, DBGI_FuzzySearchItemChunk, 1); - chunk->cap = 512; - chunk->count = 0; - chunk->v = push_array_no_zero(scratch.arena, DBGI_FuzzySearchItem, chunk->cap); - SLLQueuePush(items_list.first, items_list.last, chunk); - items_list.chunk_count += 1; - } - chunk->v[chunk->count].idx = idx; - chunk->v[chunk->count].match_ranges = matches; - chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0; - chunk->count += 1; - items_list.total_count += 1; - } - if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex) - { - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen) - { - task_is_good = 0; - break; - } - } - } - } - } - - //- rjf: item list -> item array - DBGI_FuzzySearchItemArray items = {0}; - if(task_is_good) - { - items.count = items_list.total_count; - items.v = push_array_no_zero(task_arena, DBGI_FuzzySearchItem, items.count); - U64 idx = 0; - for(DBGI_FuzzySearchItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next) - { - MemoryCopy(items.v+idx, chunk->v, sizeof(DBGI_FuzzySearchItem)*chunk->count); - idx += chunk->count; - } - } - - //- rjf: sort item array - if(items.count != 0 && query.size != 0) - { - qsort(items.v, items.count, sizeof(DBGI_FuzzySearchItem), (int (*)(const void *, const void *))dbgi_qsort_compare_fuzzy_search_items); - } - - //- rjf: commit to cache - busyloop on scope touches - if(task_is_good) - { - for(B32 done = 0; !done;) - { - B32 found = 0; - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - if(n->scope_touch_count == 0) - { - n->gen = initial_submit_gen; - n->gen_items = items; - done = 1; - } - found = 1; - break; - } - } - if(!found) - { - break; - } - } - } - - dbgi_scope_close(scope); scratch_end(scratch); } } diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 2ca9952e..73fc0da8 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -1,294 +1,139 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef DBGI_H -#define DBGI_H - -//////////////////////////////// -//~ rjf: Info Bundle Types - -typedef struct DBGI_Parse DBGI_Parse; -struct DBGI_Parse -{ - U64 gen; - Arena *arena; - void *exe_base; - FileProperties exe_props; - String8 dbg_path; - void *dbg_base; - FileProperties dbg_props; - PE_BinInfo pe; - RDI_Parsed rdi; -}; - -//////////////////////////////// -//~ rjf: Exe -> Debug Forced Override Cache Types - -typedef struct DBGI_ForceNode DBGI_ForceNode; -struct DBGI_ForceNode -{ - DBGI_ForceNode *next; - String8 exe_path; - U64 dbg_path_cap; - U64 dbg_path_size; - U8 *dbg_path_base; -}; - -typedef struct DBGI_ForceSlot DBGI_ForceSlot; -struct DBGI_ForceSlot -{ - DBGI_ForceNode *first; - DBGI_ForceNode *last; -}; - -typedef struct DBGI_ForceStripe DBGI_ForceStripe; -struct DBGI_ForceStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -//////////////////////////////// -//~ rjf: Binary Cache State Types - -typedef U32 DBGI_BinaryFlags; -enum -{ - DBGI_BinaryFlag_ParseInFlight = (1<<0), -}; - -typedef struct DBGI_Binary DBGI_Binary; -struct DBGI_Binary -{ - // rjf: links & metadata - DBGI_Binary *next; - String8 exe_path; - U64 refcount; - U64 scope_touch_count; - U64 last_time_enqueued_for_parse_us; - DBGI_BinaryFlags flags; - U64 gen; - - // rjf: exe handles - OS_Handle exe_file; - OS_Handle exe_file_map; - - // rjf: debug handles - OS_Handle dbg_file; - OS_Handle dbg_file_map; - - // rjf: analysis results - DBGI_Parse parse; -}; - -typedef struct DBGI_BinarySlot DBGI_BinarySlot; -struct DBGI_BinarySlot -{ - DBGI_Binary *first; - DBGI_Binary *last; -}; - -typedef struct DBGI_BinaryStripe DBGI_BinaryStripe; -struct DBGI_BinaryStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -//////////////////////////////// -//~ rjf: Fuzzy Search Cache Types - -typedef enum DBGI_FuzzySearchTarget -{ - DBGI_FuzzySearchTarget_Procedures, - DBGI_FuzzySearchTarget_GlobalVariables, - DBGI_FuzzySearchTarget_ThreadVariables, - DBGI_FuzzySearchTarget_UDTs, - DBGI_FuzzySearchTarget_COUNT -} -DBGI_FuzzySearchTarget; - -typedef struct DBGI_FuzzySearchItem DBGI_FuzzySearchItem; -struct DBGI_FuzzySearchItem -{ - U64 idx; - U64 missed_size; - FuzzyMatchRangeList match_ranges; -}; - -typedef struct DBGI_FuzzySearchItemChunk DBGI_FuzzySearchItemChunk; -struct DBGI_FuzzySearchItemChunk -{ - DBGI_FuzzySearchItemChunk *next; - DBGI_FuzzySearchItem *v; - U64 count; - U64 cap; -}; - -typedef struct DBGI_FuzzySearchItemChunkList DBGI_FuzzySearchItemChunkList; -struct DBGI_FuzzySearchItemChunkList -{ - DBGI_FuzzySearchItemChunk *first; - DBGI_FuzzySearchItemChunk *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct DBGI_FuzzySearchItemArray DBGI_FuzzySearchItemArray; -struct DBGI_FuzzySearchItemArray -{ - DBGI_FuzzySearchItem *v; - U64 count; -}; - -typedef struct DBGI_FuzzySearchBucket DBGI_FuzzySearchBucket; -struct DBGI_FuzzySearchBucket -{ - Arena *arena; - String8 exe_path; - String8 query; - DBGI_FuzzySearchTarget target; -}; - -typedef struct DBGI_FuzzySearchNode DBGI_FuzzySearchNode; -struct DBGI_FuzzySearchNode -{ - DBGI_FuzzySearchNode *next; - U128 key; - U64 scope_touch_count; - U64 last_time_submitted_us; - DBGI_FuzzySearchBucket buckets[3]; - U64 gen; - U64 submit_gen; - DBGI_FuzzySearchItemArray gen_items; -}; - -typedef struct DBGI_FuzzySearchSlot DBGI_FuzzySearchSlot; -struct DBGI_FuzzySearchSlot -{ - DBGI_FuzzySearchNode *first; - DBGI_FuzzySearchNode *last; -}; - -typedef struct DBGI_FuzzySearchStripe DBGI_FuzzySearchStripe; -struct DBGI_FuzzySearchStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -typedef struct DBGI_FuzzySearchThread DBGI_FuzzySearchThread; -struct DBGI_FuzzySearchThread -{ - OS_Handle thread; - OS_Handle u2f_ring_mutex; - OS_Handle u2f_ring_cv; - U64 u2f_ring_size; - U8 *u2f_ring_base; - U64 u2f_ring_write_pos; - U64 u2f_ring_read_pos; -}; - -//////////////////////////////// -//~ rjf: Weak Access Scope Types - -typedef struct DBGI_TouchedBinary DBGI_TouchedBinary; -struct DBGI_TouchedBinary -{ - DBGI_TouchedBinary *next; - DBGI_Binary *binary; -}; - -typedef struct DBGI_TouchedFuzzySearch DBGI_TouchedFuzzySearch; -struct DBGI_TouchedFuzzySearch -{ - DBGI_TouchedFuzzySearch *next; - DBGI_FuzzySearchNode *node; -}; - -typedef struct DBGI_Scope DBGI_Scope; -struct DBGI_Scope -{ - DBGI_Scope *next; - DBGI_TouchedBinary *first_tb; - DBGI_TouchedBinary *last_tb; - DBGI_TouchedFuzzySearch *first_tfs; - DBGI_TouchedFuzzySearch *last_tfs; -}; - -typedef struct DBGI_ThreadCtx DBGI_ThreadCtx; -struct DBGI_ThreadCtx -{ - Arena *arena; - DBGI_Scope *free_scope; - DBGI_TouchedBinary *free_tb; - DBGI_TouchedFuzzySearch *free_tfs; -}; +#ifndef DI_H +#define DI_H //////////////////////////////// //~ rjf: Event Types -typedef enum DBGI_EventKind +typedef enum DI_EventKind { - DBGI_EventKind_Null, - DBGI_EventKind_ConversionStarted, - DBGI_EventKind_ConversionEnded, - DBGI_EventKind_ConversionFailureUnsupportedFormat, - DBGI_EventKind_COUNT + DI_EventKind_Null, + DI_EventKind_ConversionStarted, + DI_EventKind_ConversionEnded, + DI_EventKind_ConversionFailureUnsupportedFormat, + DI_EventKind_COUNT } -DBGI_EventKind; +DI_EventKind; -typedef struct DBGI_Event DBGI_Event; -struct DBGI_Event +typedef struct DI_Event DI_Event; +struct DI_Event { - DBGI_EventKind kind; + DI_EventKind kind; String8 string; }; -typedef struct DBGI_EventNode DBGI_EventNode; -struct DBGI_EventNode +typedef struct DI_EventNode DI_EventNode; +struct DI_EventNode { - DBGI_EventNode *next; - DBGI_Event v; + DI_EventNode *next; + DI_Event v; }; -typedef struct DBGI_EventList DBGI_EventList; -struct DBGI_EventList +typedef struct DI_EventList DI_EventList; +struct DI_EventList { - DBGI_EventNode *first; - DBGI_EventNode *last; + DI_EventNode *first; + DI_EventNode *last; U64 count; }; //////////////////////////////// -//~ rjf: Cross-Thread Shared State +//~ rjf: Cache Types -typedef struct DBGI_Shared DBGI_Shared; -struct DBGI_Shared +typedef struct DI_StringChunkNode DI_StringChunkNode; +struct DI_StringChunkNode +{ + DI_StringChunkNode *next; + U64 size; +}; + +typedef struct DI_Node DI_Node; +struct DI_Node +{ + // rjf: links + DI_Node *next; + DI_Node *prev; + + // rjf: metadata + U64 ref_count; + U64 touch_count; + U64 is_working; + U64 last_time_requested_us; + + // rjf: key + String8 path; + U64 min_timestamp; + + // rjf: file handles + OS_Handle file; + OS_Handle file_map; + void *file_base; + FileProperties file_props; + + // rjf: parse artifacts + Arena *arena; + RDI_Parsed rdi; + B32 parse_done; +}; + +typedef struct DI_Slot DI_Slot; +struct DI_Slot +{ + DI_Node *first; + DI_Node *last; +}; + +typedef struct DI_Stripe DI_Stripe; +struct DI_Stripe +{ + Arena *arena; + DI_Node *free_node; + DI_StringChunkNode *free_string_chunks[8]; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct DI_Touch DI_Touch; +struct DI_Touch +{ + DI_Touch *next; + DI_Node *node; +}; + +typedef struct DI_Scope DI_Scope; +struct DI_Scope +{ + DI_Scope *next; + DI_Touch *first_touch; + DI_Touch *last_touch; +}; + +typedef struct DI_TCTX DI_TCTX; +struct DI_TCTX +{ + Arena *arena; + DI_Scope *free_scope; + DI_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State Types + +typedef struct DI_Shared DI_Shared; +struct DI_Shared { - // rjf: arena Arena *arena; - // rjf: forced override table - U64 force_slots_count; - U64 force_stripes_count; - DBGI_ForceSlot *force_slots; - DBGI_ForceStripe *force_stripes; - - // rjf: binary table - U64 binary_slots_count; - U64 binary_stripes_count; - DBGI_BinarySlot *binary_slots; - DBGI_BinaryStripe *binary_stripes; - - // rjf: fuzzy search cache table - U64 fuzzy_search_slots_count; - U64 fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *fuzzy_search_slots; - DBGI_FuzzySearchStripe *fuzzy_search_stripes; + // rjf: node cache + U64 slots_count; + DI_Slot *slots; + U64 stripes_count; + DI_Stripe *stripes; // rjf: user -> parse ring OS_Handle u2p_ring_mutex; @@ -309,123 +154,98 @@ struct DBGI_Shared // rjf: threads U64 parse_thread_count; OS_Handle *parse_threads; - U64 fuzzy_thread_count; - DBGI_FuzzySearchThread *fuzzy_threads; }; //////////////////////////////// //~ rjf: Globals -global DBGI_Shared *dbgi_shared = 0; -thread_static DBGI_ThreadCtx *dbgi_tctx = 0; -global DBGI_Parse dbgi_parse_nil = +global DI_Shared *di_shared = 0; +thread_static DI_TCTX *di_tctx = 0; +global RDI_Parsed di_rdi_parsed_nil = { 0, 0, 0, - {0}, - {0}, 0, {0}, - {0}, - { - 0, - 0, - 0, - 0, - {0}, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - &rdi_binary_section_nil, 1, - &rdi_file_path_node_nil, 1, - &rdi_source_file_nil, 1, - &rdi_unit_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_type_node_nil, 1, - &rdi_udt_nil, 1, - &rdi_member_nil, 1, - &rdi_enum_member_nil, 1, - &rdi_global_variable_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_thread_variable_nil, 1, - &rdi_procedure_nil, 1, - &rdi_scope_nil, 1, - &rdi_voff_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_local_nil, 1, - &rdi_location_block_nil, 1, - 0, 0, - 0, 0, - }, + 0, + 0, + 0, + 0, + 0, + 0, + &rdi_top_level_info_nil, + &rdi_binary_section_nil, 1, + &rdi_file_path_node_nil, 1, + &rdi_source_file_nil, 1, + &rdi_unit_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_type_node_nil, 1, + &rdi_udt_nil, 1, + &rdi_member_nil, 1, + &rdi_enum_member_nil, 1, + &rdi_global_variable_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_thread_variable_nil, 1, + &rdi_procedure_nil, 1, + &rdi_scope_nil, 1, + &rdi_voff_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_local_nil, 1, + &rdi_location_block_nil, 1, + 0, 0, + 0, 0, }; +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); + //////////////////////////////// //~ rjf: Main Layer Initialization -internal void dbgi_init(void); - -//////////////////////////////// -//~ rjf: Thread-Context Idempotent Initialization - -internal void dbgi_ensure_tctx_inited(void); - -//////////////////////////////// -//~ rjf: Helpers - -internal U64 dbgi_hash_from_string(String8 string, StringMatchFlags match_flags); -internal U64 dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx); -internal String8 dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx); - -//////////////////////////////// -//~ rjf: Forced Override Cache Functions - -internal void dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path); -internal String8 dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +internal void di_init(void); //////////////////////////////// //~ rjf: Scope Functions -internal DBGI_Scope *dbgi_scope_open(void); -internal void dbgi_scope_close(DBGI_Scope *scope); -internal void dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary); -internal void dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_FuzzySearchNode *node); +internal DI_Scope *di_scope_open(void); +internal void di_scope_close(DI_Scope *scope); +internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node); //////////////////////////////// -//~ rjf: Binary Cache Functions +//~ rjf: Per-Slot Functions -internal void dbgi_binary_open(String8 exe_path); -internal void dbgi_binary_close(String8 exe_path); -internal DBGI_Parse *dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us); +internal DI_Node *di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp); //////////////////////////////// -//~ rjf: Fuzzy Search Cache Functions +//~ rjf: Per-Stripe Functions -internal DBGI_FuzzySearchItemArray dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 exe_path, String8 query, DBGI_FuzzySearchTarget target, U64 endt_us, B32 *stale_out); +internal U64 di_string_bucket_idx_from_string_size(U64 size); +internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); +internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void di_open(String8 path, U64 min_timestamp); +internal void di_close(String8 path, U64 min_timestamp); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed *di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us); //////////////////////////////// //~ rjf: Parse Threads -internal B32 dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us); -internal String8 dbgi_u2p_dequeue_exe_path(Arena *arena); +internal B32 di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us); +internal void di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp); -internal void dbgi_p2u_push_event(DBGI_Event *event); -internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us); +internal void di_p2u_push_event(DI_Event *event); +internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); -internal void dbgi_parse_thread_entry_point(void *p); +internal void di_parse_thread__entry_point(void *p); -//////////////////////////////// -//~ rjf: Fuzzy Searching Threads - -internal B32 dbgi_u2f_enqueue_req(U128 key, U64 endt_us); -internal void dbgi_u2f_dequeue_req(Arena *arena, DBGI_FuzzySearchThread *thread, U128 *key_out); - -internal int dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchItem *b); - -internal void dbgi_fuzzy_thread__entry_point(void *p); - -#endif //DBGI_H +#endif // DI_H diff --git a/src/dbgi2/dbgi2.c b/src/dbgi2/dbgi2.c deleted file mode 100644 index c8fed823..00000000 --- a/src/dbgi2/dbgi2.c +++ /dev/null @@ -1,872 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -di_hash_from_string(String8 string, StringMatchFlags match_flags) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? char_to_lower(string.str[i]) : string.str[i]); - } - return result; -} - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -di_init(void) -{ - Arena *arena = arena_alloc(); - di_shared = push_array(arena, DI_Shared, 1); - di_shared->arena = arena; - di_shared->slots_count = 1024; - di_shared->slots = push_array(arena, DI_Slot, di_shared->slots_count); - di_shared->stripes_count = Min(di_shared->slots_count, os_logical_core_count()); - di_shared->stripes = push_array(arena, DI_Stripe, di_shared->stripes_count); - for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) - { - di_shared->stripes[idx].arena = arena_alloc(); - di_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - di_shared->stripes[idx].cv = os_condition_variable_alloc(); - } - di_shared->u2p_ring_mutex = os_mutex_alloc(); - di_shared->u2p_ring_cv = os_condition_variable_alloc(); - di_shared->u2p_ring_size = KB(64); - di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); - di_shared->p2u_ring_mutex = os_mutex_alloc(); - di_shared->p2u_ring_cv = os_condition_variable_alloc(); - di_shared->p2u_ring_size = KB(64); - di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); - di_shared->parse_thread_count = Max(2, os_logical_core_count()/2); - di_shared->parse_threads = push_array(arena, OS_Handle, di_shared->parse_thread_count); - for(U64 idx = 0; idx < di_shared->parse_thread_count; idx += 1) - { - di_shared->parse_threads[idx] = os_launch_thread(di_parse_thread__entry_point, (void *)idx, 0); - } -} - -//////////////////////////////// -//~ rjf: Scope Functions - -internal DI_Scope * -di_scope_open(void) -{ - if(di_tctx == 0) - { - Arena *arena = arena_alloc(); - di_tctx = push_array(arena, DI_TCTX, 1); - di_tctx->arena = arena; - } - DI_Scope *scope = di_tctx->free_scope; - if(scope != 0) - { - SLLStackPop(di_tctx->free_scope); - } - else - { - scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -di_scope_close(DI_Scope *scope) -{ - for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) - { - next = t->next; - SLLStackPush(di_tctx->free_touch, t); - if(t->node != 0) - { - ins_atomic_u64_dec_eval(&t->node->touch_count); - } - } - SLLStackPush(di_tctx->free_scope, scope); -} - -internal void -di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) -{ - if(node != 0) - { - ins_atomic_u64_inc_eval(&node->touch_count); - } - DI_Touch *touch = di_tctx->free_touch; - if(touch != 0) - { - SLLStackPop(di_tctx->free_touch); - } - else - { - touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); - } - MemoryZeroStruct(touch); - SLLQueuePush(scope->first_touch, scope->last_touch, touch); - touch->node = node; -} - -//////////////////////////////// -//~ rjf: Per-Slot Functions - -internal DI_Node * -di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp) -{ - DI_Node *node = 0; - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 most_recent_timestamp = max_U64; - for(DI_Node *n = slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, match_flags) && - min_timestamp <= n->min_timestamp && - (n->min_timestamp - min_timestamp) <= most_recent_timestamp) - { - node = n; - most_recent_timestamp = (n->min_timestamp - min_timestamp); - } - } - return node; -} - -//////////////////////////////// -//~ rjf: Per-Stripe Functions - -internal U64 -di_string_bucket_idx_from_string_size(U64 size) -{ - U64 size_rounded = u64_up_to_pow2(size+1); - size_rounded = ClampBot((1<<4), size_rounded); - U64 bucket_idx = 0; - switch(size_rounded) - { - case 1<<4: {bucket_idx = 0;}break; - case 1<<5: {bucket_idx = 1;}break; - case 1<<6: {bucket_idx = 2;}break; - case 1<<7: {bucket_idx = 3;}break; - case 1<<8: {bucket_idx = 4;}break; - case 1<<9: {bucket_idx = 5;}break; - case 1<<10:{bucket_idx = 6;}break; - default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; - } - return bucket_idx; -} - -internal String8 -di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) -{ - if(string.size == 0) {return str8_zero();} - U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); - DI_StringChunkNode *node = stripe->free_string_chunks[bucket_idx]; - - // rjf: pull from bucket free list - if(node != 0) - { - if(bucket_idx == ArrayCount(stripe->free_string_chunks)-1) - { - node = 0; - DI_StringChunkNode *prev = 0; - for(DI_StringChunkNode *n = stripe->free_string_chunks[bucket_idx]; - n != 0; - prev = n, n = n->next) - { - if(n->size >= string.size+1) - { - if(prev == 0) - { - stripe->free_string_chunks[bucket_idx] = n->next; - } - else - { - prev->next = n->next; - } - node = n; - break; - } - } - } - else - { - SLLStackPop(stripe->free_string_chunks[bucket_idx]); - } - } - - // rjf: no found node -> allocate new - if(node == 0) - { - U64 chunk_size = 0; - if(bucket_idx < ArrayCount(stripe->free_string_chunks)-1) - { - chunk_size = 1<<(bucket_idx+4); - } - else - { - chunk_size = u64_up_to_pow2(string.size); - } - U8 *chunk_memory = push_array(stripe->arena, U8, chunk_size); - node = (DI_StringChunkNode *)chunk_memory; - } - - // rjf: fill string & return - String8 allocated_string = str8((U8 *)node, string.size); - MemoryCopy((U8 *)node, string.str, string.size); - return allocated_string; -} - -internal void -di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) -{ - if(string.size == 0) {return;} - U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); - DI_StringChunkNode *node = (DI_StringChunkNode *)string.str; - node->size = u64_up_to_pow2(string.size); - SLLStackPush(stripe->free_string_chunks[bucket_idx], node); -} - -//////////////////////////////// -//~ rjf: Key Opening/Closing - -internal void -di_open(String8 path, U64 min_timestamp) -{ - Temp scratch = scratch_begin(0, 0); - if(path.size != 0) - { - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("opening debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); - OS_MutexScopeW(stripe->rw_mutex) - { - //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); - - //- rjf: allocate node if none exists; insert into slot - if(node == 0) - { - U64 current_timestamp = os_properties_from_file_path(path).modified; - if(current_timestamp == 0) - { - current_timestamp = min_timestamp; - } - node = stripe->free_node; - if(node != 0) - { - SLLStackPop(stripe->free_node); - } - else - { - node = push_array_no_zero(stripe->arena, DI_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, path_normalized); - node->path = path_stored; - node->min_timestamp = current_timestamp; - } - - //- rjf: increment node reference count - if(node != 0) - { - node->ref_count += 1; - if(node->ref_count == 1) - { - di_u2p_enqueue_key(path_normalized, node->min_timestamp, 0); - } - } - } - } - scratch_end(scratch); -} - -internal void -di_close(String8 path, U64 min_timestamp) -{ - Temp scratch = scratch_begin(0, 0); - if(path.size != 0) - { - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("closing debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); - OS_MutexScopeW(stripe->rw_mutex) - { - //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); - - //- rjf: node exists -> decrement reference count; release - if(node != 0) - { - node->ref_count -= 1; - if(node->ref_count == 0) for(;;) - { - //- rjf: wait for touch count to go to 0 - if(ins_atomic_u64_eval(&node->touch_count) != 0) - { - os_rw_mutex_drop_w(stripe->rw_mutex); - for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); - os_rw_mutex_take_w(stripe->rw_mutex); - } - - //- rjf: release - if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) - { - di_string_release__stripe_mutex_w_guarded(stripe, node->path); - if(node->file_base != 0) - { - os_file_map_view_close(node->file_map, node->file_base); - } - if(!os_handle_match(node->file_map, os_handle_zero())) - { - os_file_map_close(node->file_map); - } - if(!os_handle_match(node->file, os_handle_zero())) - { - os_file_close(node->file); - } - if(node->arena != 0) - { - arena_release(node->arena); - } - DLLRemove(slot->first, slot->last, node); - SLLStackPush(stripe->free_node, node); - break; - } - } - } - } - } - scratch_end(scratch); -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal RDI_Parsed * -di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us) -{ - RDI_Parsed *result = &di_rdi_parsed_nil; - if(path.size != 0) - { - Temp scratch = scratch_begin(0, 0); - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(;;) - { - //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); - - //- rjf: no node? this path is not opened - if(node == 0) - { - break; - } - - //- rjf: parse done -> touch, grab result - if(node != 0 && node->parse_done) - { - di_scope_touch_node__stripe_mutex_r_guarded(scope, node); - result = &node->rdi; - break; - } - - //- rjf: parse not done, not working, asked a while ago -> ask for parse - B32 sent = 0; - if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); - } - } - - //- rjf: time expired -> break - if(os_now_microseconds() >= endt_us) - { - break; - } - - //- rjf: wait on this stripe - { - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - } - scratch_end(scratch); - } - return result; -} - -//////////////////////////////// -//~ rjf: Parse Threads - -internal B32 -di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us) -{ - B32 sent = 0; - OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; - U64 available_size = di_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(path.size) + path.size + sizeof(min_timestamp)) - { - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &path.size); - di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, path.str, path.size); - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &min_timestamp); - di_shared->u2p_ring_write_pos += 7; - di_shared->u2p_ring_write_pos -= di_shared->u2p_ring_write_pos%8; - sent = 1; - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); - } - if(sent) - { - os_condition_variable_broadcast(di_shared->u2p_ring_cv); - } - return sent; -} - -internal void -di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp) -{ - OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(out_path->size) + sizeof(out_min_timestamp[0])) - { - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_path->size); - out_path->str = push_array(arena, U8, out_path->size); - di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_path->str, out_path->size); - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_min_timestamp); - di_shared->u2p_ring_read_pos += 7; - di_shared->u2p_ring_read_pos -= di_shared->u2p_ring_read_pos%8; - break; - } - os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); - } - os_condition_variable_broadcast(di_shared->u2p_ring_cv); -} - -internal void -di_p2u_push_event(DI_Event *event) -{ - OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) - { - U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); - U64 available_size = di_shared->p2u_ring_size-unconsumed_size; - U64 needed_size = sizeof(DI_EventKind) + sizeof(U64) + event->string.size; - if(available_size >= needed_size) - { - di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->kind); - di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->string.size); - di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); - di_shared->p2u_ring_write_pos += 7; - di_shared->p2u_ring_write_pos -= di_shared->p2u_ring_write_pos%8; - break; - } - os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); - } - os_condition_variable_broadcast(di_shared->p2u_ring_cv); -} - -internal DI_EventList -di_p2u_pop_events(Arena *arena, U64 endt_us) -{ - DI_EventList events = {0}; - OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) - { - U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); - if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) - { - DI_EventNode *n = push_array(arena, DI_EventNode, 1); - SLLQueuePush(events.first, events.last, n); - events.count += 1; - di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.kind); - di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.string.size); - n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); - di_shared->p2u_ring_read_pos += ring_read(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); - di_shared->p2u_ring_read_pos += 7; - di_shared->p2u_ring_read_pos -= di_shared->p2u_ring_read_pos%8; - } - else if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); - } - os_condition_variable_broadcast(di_shared->p2u_ring_cv); - return events; -} - -internal void -di_parse_thread__entry_point(void *p) -{ - ThreadNameF("[di] parse #%I64u", (U64)p); - for(;;) - { - Temp scratch = scratch_begin(0, 0); - - //////////////////////////// - //- rjf: grab next key - // - String8 og_path = {0}; - U64 min_timestamp = 0; - di_u2p_dequeue_key(scratch.arena, &og_path, &min_timestamp); - - //////////////////////////// - //- rjf: unpack key - // - U64 hash = di_hash_from_string(og_path, StringMatchFlag_CaseInsensitive); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - - //////////////////////////// - //- rjf: take task - // - B32 got_task = 0; - OS_MutexScopeR(stripe->rw_mutex) - { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); - if(node != 0) - { - got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); - } - } - - //////////////////////////// - //- rjf: got task -> open O.G. file (may or may not be RDI) - // - B32 og_format_is_known = 0; - B32 og_is_pe = 0; - B32 og_is_pdb = 0; - B32 og_is_elf = 0; - B32 og_is_rdi = 0; - FileProperties og_props = {0}; - if(got_task) ProfScope("analyze %.*s", str8_varg(og_path)) - { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_path); - OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); - FileProperties props = og_props = os_properties_from_file(file); - void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); - String8 data = str8((U8 *)base, props.size); - if(!og_format_is_known) - { - String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); - String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); - String8 msfxx_magic = str8_lit("Microsoft C/C++"); - if((data.size >= msf20_magic.size && str8_match(data, msf20_magic, StringMatchFlag_RightSideSloppy)) || - (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || - (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) - { - og_format_is_known = 1; - og_is_pdb = 1; - } - } - if(!og_format_is_known) - { - if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) - { - og_format_is_known = 1; - og_is_rdi = 1; - } - } - if(!og_format_is_known) - { - if(data.size >= 4 && - data.str[0] == 0x7f && - data.str[1] == 'E' && - data.str[2] == 'L' && - data.str[3] == 'F') - { - og_format_is_known = 1; - og_is_elf = 1; - } - } - if(!og_format_is_known) - { - if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) - { - og_format_is_known = 1; - og_is_pe = 1; - } - } - os_file_map_view_close(file_map, base); - os_file_map_close(file_map); - os_file_close(file); - } - - //////////////////////////// - //- rjf: given O.G. path & analysis, determine RDI path - // - String8 rdi_path = {0}; - if(got_task) - { - if(og_is_rdi) - { - rdi_path = og_path; - } - else if(og_format_is_known && og_is_pdb) - { - rdi_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); - } - } - - //////////////////////////// - //- rjf: check if rdi file is up-to-date - // - B32 rdi_file_is_up_to_date = 0; - if(got_task) - { - if(rdi_path.size != 0) ProfScope("check %.*s is up-to-date", str8_varg(rdi_path)) - { - FileProperties props = os_properties_from_file_path(rdi_path); - rdi_file_is_up_to_date = (props.modified > og_props.modified); - } - } - - //////////////////////////// - //- rjf: if raddbg file is up to date based on timestamp, check the - // encoding generation number & size, to see if we need to regenerate it - // regardless - // - if(got_task && rdi_file_is_up_to_date) ProfScope("check %.*s version matches our's", str8_varg(rdi_path)) - { - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, rdi_path); - file_map = os_file_map_open(OS_AccessFlag_Read, file); - file_props = os_properties_from_file(file); - file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); - if(sizeof(RDI_Header) <= file_props.size) - { - RDI_Header *header = (RDI_Header*)file_base; - if(header->encoding_version != RDI_ENCODING_VERSION) - { - rdi_file_is_up_to_date = 0; - } - } - else - { - rdi_file_is_up_to_date = 0; - } - os_file_map_view_close(file_map, file_base); - os_file_map_close(file_map); - os_file_close(file); - } - - //////////////////////////// - //- rjf: heuristically choose compression settings - // - B32 should_compress = 0; -#if 0 - if(og_dbg_props.size > MB(64)) - { - should_compress = 1; - } -#endif - - //////////////////////////// - //- rjf: rdi file not up-to-date? we need to generate it - // - if(got_task && !rdi_file_is_up_to_date) ProfScope("generate %.*s", str8_varg(rdi_path)) - { - if(og_is_pdb) - { - //- rjf: push conversion task begin event - { - DI_Event event = {DI_EventKind_ConversionStarted}; - event.string = rdi_path; - di_p2u_push_event(&event); - } - - //- rjf: kick off process - OS_Handle process = {0}; - { - OS_LaunchOptions opts = {0}; - opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); - opts.inherit_env = 1; - opts.consoleless = 1; - str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); - if(should_compress) - { - str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); - } - //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", rdi_path); - os_launch_process(&opts, &process); - } - - //- rjf: wait for process to complete - { - U64 start_wait_t = os_now_microseconds(); - for(;;) - { - B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); - if(wait_done) - { - rdi_file_is_up_to_date = 1; - break; - } - } - } - - //- rjf: push conversion task end event - { - DI_Event event = {DI_EventKind_ConversionEnded}; - event.string = rdi_path; - di_p2u_push_event(&event); - } - } - else - { - // NOTE(rjf): we cannot convert from this O.G. debug info format right now. - //- rjf: push conversion task failure event - { - DI_Event event = {DI_EventKind_ConversionFailureUnsupportedFormat}; - event.string = rdi_path; - di_p2u_push_event(&event); - } - } - } - - //////////////////////////// - //- rjf: got task -> open file - // - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; - if(got_task) - { - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); - file_map = os_file_map_open(OS_AccessFlag_Read, file); - file_props = os_properties_from_file(file); - file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); - } - - //////////////////////////// - //- rjf: do initial parse of rdi - // - RDI_Parsed rdi_parsed_maybe_compressed = di_rdi_parsed_nil; - if(got_task) - { - RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); - (void)parse_status; - } - - //////////////////////////// - //- rjf: decompress & re-parse, if necessary - // - Arena *rdi_parsed_arena = 0; - RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; - if(got_task) - { - U64 decompressed_size = file_props.size; - for(U64 dsec_idx = 0; dsec_idx < rdi_parsed_maybe_compressed.dsec_count; dsec_idx += 1) - { - decompressed_size += (rdi_parsed_maybe_compressed.dsecs[dsec_idx].unpacked_size - rdi_parsed_maybe_compressed.dsecs[dsec_idx].encoded_size); - } - if(decompressed_size > file_props.size) - { - rdi_parsed_arena = arena_alloc(); - U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); - - // rjf: copy header - RDI_Header *src_header = (RDI_Header *)file_base; - RDI_Header *dst_header = (RDI_Header *)decompressed_data; - { - MemoryCopy(dst_header, src_header, sizeof(RDI_Header)); - } - - // rjf: copy & adjust sections for decompressed version - if(rdi_parsed_maybe_compressed.dsec_count != 0) - { - RDI_DataSection *dsec_base = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); - MemoryCopy(dsec_base, (U8 *)file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); - U64 off = dst_header->data_section_off + sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count; - off += 7; - off -= off%8; - for(U64 idx = 0; idx < rdi_parsed_maybe_compressed.dsec_count; idx += 1) - { - dsec_base[idx].encoding = RDI_DataSectionEncoding_Unpacked; - dsec_base[idx].off = off; - dsec_base[idx].encoded_size = dsec_base[idx].unpacked_size; - off += dsec_base[idx].unpacked_size; - off += 7; - off -= off%8; - } - } - - // rjf: decompress sections into new decompressed file buffer - if(rdi_parsed_maybe_compressed.dsec_count != 0) - { - RDI_DataSection *src_first = rdi_parsed_maybe_compressed.dsecs; - RDI_DataSection *dst_first = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); - RDI_DataSection *src_opl = src_first + rdi_parsed_maybe_compressed.dsec_count; - RDI_DataSection *dst_opl = dst_first + rdi_parsed_maybe_compressed.dsec_count; - for(RDI_DataSection *src = src_first, *dst = dst_first; - src < src_opl && dst < dst_opl; - src += 1, dst += 1) - { - rr_lzb_simple_decode((U8*)file_base + src->off, src->encoded_size, - decompressed_data + dst->off, dst->unpacked_size); - } - } - - // rjf: re-parse - RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); - (void)parse_status; - } - } - - //////////////////////////// - //- rjf: commit parsed info to cache - // - if(got_task) OS_MutexScopeW(stripe->rw_mutex) - { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); - if(node != 0) - { - node->is_working = 0; - node->file = file; - node->file_map = file_map; - node->file_base = file_base; - node->file_props = file_props; - node->arena = rdi_parsed_arena; - node->rdi = rdi_parsed; - node->parse_done = 1; - } - } - os_condition_variable_broadcast(stripe->cv); - - scratch_end(scratch); - } -} diff --git a/src/dbgi2/dbgi2.h b/src/dbgi2/dbgi2.h deleted file mode 100644 index 73fc0da8..00000000 --- a/src/dbgi2/dbgi2.h +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DI_H -#define DI_H - -//////////////////////////////// -//~ rjf: Event Types - -typedef enum DI_EventKind -{ - DI_EventKind_Null, - DI_EventKind_ConversionStarted, - DI_EventKind_ConversionEnded, - DI_EventKind_ConversionFailureUnsupportedFormat, - DI_EventKind_COUNT -} -DI_EventKind; - -typedef struct DI_Event DI_Event; -struct DI_Event -{ - DI_EventKind kind; - String8 string; -}; - -typedef struct DI_EventNode DI_EventNode; -struct DI_EventNode -{ - DI_EventNode *next; - DI_Event v; -}; - -typedef struct DI_EventList DI_EventList; -struct DI_EventList -{ - DI_EventNode *first; - DI_EventNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct DI_StringChunkNode DI_StringChunkNode; -struct DI_StringChunkNode -{ - DI_StringChunkNode *next; - U64 size; -}; - -typedef struct DI_Node DI_Node; -struct DI_Node -{ - // rjf: links - DI_Node *next; - DI_Node *prev; - - // rjf: metadata - U64 ref_count; - U64 touch_count; - U64 is_working; - U64 last_time_requested_us; - - // rjf: key - String8 path; - U64 min_timestamp; - - // rjf: file handles - OS_Handle file; - OS_Handle file_map; - void *file_base; - FileProperties file_props; - - // rjf: parse artifacts - Arena *arena; - RDI_Parsed rdi; - B32 parse_done; -}; - -typedef struct DI_Slot DI_Slot; -struct DI_Slot -{ - DI_Node *first; - DI_Node *last; -}; - -typedef struct DI_Stripe DI_Stripe; -struct DI_Stripe -{ - Arena *arena; - DI_Node *free_node; - DI_StringChunkNode *free_string_chunks[8]; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -//////////////////////////////// -//~ rjf: Scoped Access Types - -typedef struct DI_Touch DI_Touch; -struct DI_Touch -{ - DI_Touch *next; - DI_Node *node; -}; - -typedef struct DI_Scope DI_Scope; -struct DI_Scope -{ - DI_Scope *next; - DI_Touch *first_touch; - DI_Touch *last_touch; -}; - -typedef struct DI_TCTX DI_TCTX; -struct DI_TCTX -{ - Arena *arena; - DI_Scope *free_scope; - DI_Touch *free_touch; -}; - -//////////////////////////////// -//~ rjf: Shared State Types - -typedef struct DI_Shared DI_Shared; -struct DI_Shared -{ - Arena *arena; - - // rjf: node cache - U64 slots_count; - DI_Slot *slots; - U64 stripes_count; - DI_Stripe *stripes; - - // rjf: user -> parse ring - OS_Handle u2p_ring_mutex; - OS_Handle u2p_ring_cv; - U64 u2p_ring_size; - U8 *u2p_ring_base; - U64 u2p_ring_write_pos; - U64 u2p_ring_read_pos; - - // rjf: parse -> user event ring - OS_Handle p2u_ring_mutex; - OS_Handle p2u_ring_cv; - U64 p2u_ring_size; - U8 *p2u_ring_base; - U64 p2u_ring_write_pos; - U64 p2u_ring_read_pos; - - // rjf: threads - U64 parse_thread_count; - OS_Handle *parse_threads; -}; - -//////////////////////////////// -//~ rjf: Globals - -global DI_Shared *di_shared = 0; -thread_static DI_TCTX *di_tctx = 0; -global RDI_Parsed di_rdi_parsed_nil = -{ - 0, - 0, - 0, - 0, - {0}, - 0, - 0, - 0, - 0, - 0, - 0, - &rdi_top_level_info_nil, - &rdi_binary_section_nil, 1, - &rdi_file_path_node_nil, 1, - &rdi_source_file_nil, 1, - &rdi_unit_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_type_node_nil, 1, - &rdi_udt_nil, 1, - &rdi_member_nil, 1, - &rdi_enum_member_nil, 1, - &rdi_global_variable_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_thread_variable_nil, 1, - &rdi_procedure_nil, 1, - &rdi_scope_nil, 1, - &rdi_voff_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_local_nil, 1, - &rdi_location_block_nil, 1, - 0, 0, - 0, 0, -}; - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void di_init(void); - -//////////////////////////////// -//~ rjf: Scope Functions - -internal DI_Scope *di_scope_open(void); -internal void di_scope_close(DI_Scope *scope); -internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node); - -//////////////////////////////// -//~ rjf: Per-Slot Functions - -internal DI_Node *di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp); - -//////////////////////////////// -//~ rjf: Per-Stripe Functions - -internal U64 di_string_bucket_idx_from_string_size(U64 size); -internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); -internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); - -//////////////////////////////// -//~ rjf: Key Opening/Closing - -internal void di_open(String8 path, U64 min_timestamp); -internal void di_close(String8 path, U64 min_timestamp); - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal RDI_Parsed *di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us); - -//////////////////////////////// -//~ rjf: Parse Threads - -internal B32 di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us); -internal void di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp); - -internal void di_p2u_push_event(DI_Event *event); -internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); - -internal void di_parse_thread__entry_point(void *p); - -#endif // DI_H diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 75dae216..7522ace2 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -46,8 +46,7 @@ #include "regs/regs.h" #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" -//#include "dbgi/dbgi.h" -#include "dbgi2/dbgi2.h" +#include "dbgi/dbgi.h" #include "fuzzy_search/fuzzy_search.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" @@ -86,8 +85,7 @@ #include "regs/regs.c" #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" -//#include "dbgi/dbgi.c" -#include "dbgi2/dbgi2.c" +#include "dbgi/dbgi.c" #include "fuzzy_search/fuzzy_search.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" From f26b4c3b06633462bff18015d30b9840a0735ea3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 10:30:23 -0700 Subject: [PATCH 25/38] eliminate path-tree-based keying of debug info on frontend; use dbgi-layer-defined debug info keys, which can be more robust to changes to the same debug info path across time (e.g. during hot reloads --- src/ctrl/ctrl_core.c | 25 ++-- src/dasm_cache/dasm_cache.c | 28 ++--- src/dasm_cache/dasm_cache.h | 3 +- src/dbgi/dbgi.c | 147 ++++++++++++++-------- src/dbgi/dbgi.h | 53 ++++++-- src/df/core/df_core.c | 178 +++++++++++++-------------- src/df/core/df_core.h | 37 +++--- src/df/core/df_core.mdesk | 6 +- src/df/core/generated/df_core.meta.c | 26 ++-- src/df/core/generated/df_core.meta.h | 14 +-- src/df/gfx/df_gfx.c | 81 ++++++------ src/df/gfx/df_gfx.h | 9 +- src/df/gfx/df_views.c | 98 +++++++-------- src/fuzzy_search/fuzzy_search.c | 30 +---- src/fuzzy_search/fuzzy_search.h | 33 +---- src/mule/mule_peb_trample_reload.c | 3 + src/raddbg/raddbg_main.cpp | 4 +- 17 files changed, 390 insertions(+), 385 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 37a64e47..06355133 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -2855,9 +2855,11 @@ ctrl_thread__entry_point(void *p) String8 path = msg->path; CTRL_Entity *module = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, msg->machine_id, msg->entity); CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - di_close(debug_info_path->string, module->timestamp); + DI_Key old_dbgi_key = {debug_info_path->string, module->timestamp}; + di_close(&old_dbgi_key); ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path); - di_open(path, module->timestamp); + DI_Key new_dbgi_key = {debug_info_path->string, module->timestamp}; + di_open(&new_dbgi_key); CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange; @@ -2896,7 +2898,8 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID m DI_Scope *di_scope = di_scope_open(); CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); - RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, debug_info_path_entity->string, debug_info_path_entity->timestamp, max_U64); + DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); U64 base_vaddr = module_entity->vaddr_range.min; for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { @@ -3320,8 +3323,8 @@ ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); if(debug_info_path_ent != &ctrl_entity_nil) { - String8 debug_info_path = debug_info_path_ent->string; - di_close(debug_info_path, debug_info_path_ent->timestamp); + DI_Key dbgi_key = {debug_info_path_ent->string, debug_info_path_ent->timestamp}; + di_close(&dbgi_key); } } } @@ -3420,7 +3423,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); if(rdi->global_variables != 0 && unparsed_map != 0) { @@ -3612,7 +3616,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt2->parent = event->process; out_evt2->timestamp = timestamp; out_evt2->string = initial_debug_info_path; - di_open(initial_debug_info_path, timestamp); + DI_Key initial_dbgi_key = {initial_debug_info_path, timestamp}; + di_open(&initial_dbgi_key); }break; case DMN_EventKind_ExitProcess: { @@ -4219,7 +4224,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } U64 module_base_vaddr = module->vaddr_range.min; CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); RDI_ParsedNameMap map = {0}; rdi_name_map_parse(rdi, unparsed_map, &map); @@ -4512,7 +4518,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(di_scope, dbg_path->string, dbg_path->timestamp, max_U64); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { String8 string = condition_n->string; diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 618ca388..89b90885 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -24,8 +24,8 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - str8_match(a->dbg_path, b->dbg_path, 0) && - a->dbg_timestamp == b->dbg_timestamp); + str8_match(a->dbgi_key.path, b->dbgi_key.path, 0) && + a->dbgi_key.min_timestamp == b->dbgi_key.min_timestamp); return result; } @@ -190,7 +190,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node) ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx()); touch->hash = node->hash; MemoryCopyStruct(&touch->params, &node->params); - touch->params.dbg_path = push_str8_copy(dasm_tctx->arena, touch->params.dbg_path); + touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key); SLLStackPush(scope->top_touch, touch); } @@ -251,7 +251,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) node->hash = hash; MemoryCopyStruct(&node->params, params); // TODO(rjf): need to make this releasable - currently all exe_paths just leak - node->params.dbg_path = push_str8_copy(stripe->arena, node->params.dbg_path); + node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); node_is_new = 1; } } @@ -295,7 +295,7 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbg_path.size+sizeof(U64)) + if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64)) { good = 1; dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash); @@ -304,9 +304,9 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->style_flags); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->syntax); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->base_vaddr); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbg_path.size); - dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbg_path.str, params->dbg_path.size); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbg_timestamp); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size); + dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp); dasm_shared->u2p_ring_write_pos += 7; dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8; break; @@ -338,10 +338,10 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out) dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->style_flags); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->syntax); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->base_vaddr); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbg_path.size); - params_out->dbg_path.str = push_array(arena, U8, params_out->dbg_path.size); - dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbg_path.str, params_out->dbg_path.size); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbg_timestamp); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.path.size); + params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size); + dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp); dasm_shared->u2p_ring_read_pos += 7; dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8; break; @@ -390,9 +390,9 @@ dasm_parse_thread__entry_point(void *p) //- rjf: get dbg info RDI_Parsed *rdi = &di_rdi_parsed_nil; - if(got_task && params.dbg_path.size != 0) + if(got_task && params.dbgi_key.path.size != 0) { - rdi = di_rdi_from_path_min_timestamp(di_scope, params.dbg_path, params.dbg_timestamp, max_U64); + rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64); } //- rjf: hash -> data diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 6629aed1..5c588b56 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -36,8 +36,7 @@ struct DASM_Params DASM_StyleFlags style_flags; DASM_Syntax syntax; U64 base_vaddr; - String8 dbg_path; - U64 dbg_timestamp; + DI_Key dbgi_key; }; //////////////////////////////// diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index c8fed823..0375ab7a 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -15,6 +15,58 @@ di_hash_from_string(String8 string, StringMatchFlags match_flags) return result; } +internal U64 +di_hash_from_key(DI_Key *k) +{ + U64 hash = di_hash_from_string(k->path, StringMatchFlag_CaseInsensitive); + return hash; +} + +internal B32 +di_key_match(DI_Key *a, DI_Key *b) +{ + return (str8_match(a->path, b->path, StringMatchFlag_CaseInsensitive) && a->min_timestamp == b->min_timestamp); +} + +internal DI_Key +di_key_copy(Arena *arena, DI_Key *src) +{ + DI_Key dst = {0}; + MemoryCopyStruct(&dst, src); + dst.path = push_str8_copy(arena, src->path); + return dst; +} + +internal DI_Key +di_normalized_key_from_key(Arena *arena, DI_Key *src) +{ + DI_Key dst = {path_normalized_from_string(arena, src->path), src->min_timestamp}; + return dst; +} + +internal void +di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key) +{ + DI_KeyNode *n = push_array(arena, DI_KeyNode, 1); + MemoryCopyStruct(&n->v, key); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DI_KeyArray +di_key_array_from_list(Arena *arena, DI_KeyList *list) +{ + DI_KeyArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, DI_Key, array.count); + U64 idx = 0; + for(DI_KeyNode *n = list->first; n != 0; n = n->next, idx += 1) + { + MemoryCopyStruct(&array.v[idx], &n->v); + } + return array; +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -115,19 +167,19 @@ di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) //~ rjf: Per-Slot Functions internal DI_Node * -di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp) +di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key) { DI_Node *node = 0; StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); U64 most_recent_timestamp = max_U64; for(DI_Node *n = slot->first; n != 0; n = n->next) { - if(str8_match(n->path, path, match_flags) && - min_timestamp <= n->min_timestamp && - (n->min_timestamp - min_timestamp) <= most_recent_timestamp) + if(str8_match(n->key.path, key->path, match_flags) && + key->min_timestamp <= n->key.min_timestamp && + (n->key.min_timestamp - key->min_timestamp) <= most_recent_timestamp) { node = n; - most_recent_timestamp = (n->min_timestamp - min_timestamp); + most_recent_timestamp = (n->key.min_timestamp - key->min_timestamp); } } return node; @@ -231,30 +283,30 @@ di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) //~ rjf: Key Opening/Closing internal void -di_open(String8 path, U64 min_timestamp) +di_open(DI_Key *key) { Temp scratch = scratch_begin(0, 0); - if(path.size != 0) + if(key->path.size != 0) { - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("opening debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + log_infof("opening debug info: %S [0x%I64x]\n", key_normalized.path, key_normalized.min_timestamp); OS_MutexScopeW(stripe->rw_mutex) { //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); //- rjf: allocate node if none exists; insert into slot if(node == 0) { - U64 current_timestamp = os_properties_from_file_path(path).modified; + U64 current_timestamp = os_properties_from_file_path(key_normalized.path).modified; if(current_timestamp == 0) { - current_timestamp = min_timestamp; + current_timestamp = key_normalized.min_timestamp; } node = stripe->free_node; if(node != 0) @@ -267,9 +319,9 @@ di_open(String8 path, U64 min_timestamp) } MemoryZeroStruct(node); DLLPushBack(slot->first, slot->last, node); - String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, path_normalized); - node->path = path_stored; - node->min_timestamp = current_timestamp; + String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, key_normalized.path); + node->key.path = path_stored; + node->key.min_timestamp = current_timestamp; } //- rjf: increment node reference count @@ -278,7 +330,7 @@ di_open(String8 path, U64 min_timestamp) node->ref_count += 1; if(node->ref_count == 1) { - di_u2p_enqueue_key(path_normalized, node->min_timestamp, 0); + di_u2p_enqueue_key(&key_normalized, max_U64); } } } @@ -287,23 +339,22 @@ di_open(String8 path, U64 min_timestamp) } internal void -di_close(String8 path, U64 min_timestamp) +di_close(DI_Key *key) { Temp scratch = scratch_begin(0, 0); - if(path.size != 0) + if(key->path.size != 0) { - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("closing debug info: %S [0x%I64x]\n", path_normalized, min_timestamp); + log_infof("closing debug info: %S [0x%I64x]\n", key_normalized.path, key_normalized.min_timestamp); OS_MutexScopeW(stripe->rw_mutex) { //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); //- rjf: node exists -> decrement reference count; release if(node != 0) @@ -322,7 +373,7 @@ di_close(String8 path, U64 min_timestamp) //- rjf: release if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) { - di_string_release__stripe_mutex_w_guarded(stripe, node->path); + di_string_release__stripe_mutex_w_guarded(stripe, node->key.path); if(node->file_base != 0) { os_file_map_view_close(node->file_map, node->file_base); @@ -354,15 +405,14 @@ di_close(String8 path, U64 min_timestamp) //~ rjf: Cache Lookups internal RDI_Parsed * -di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us) +di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us) { RDI_Parsed *result = &di_rdi_parsed_nil; - if(path.size != 0) + if(key->path.size != 0) { Temp scratch = scratch_begin(0, 0); - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = di_hash_from_string(path_normalized, StringMatchFlag_CaseInsensitive); + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); U64 slot_idx = hash%di_shared->slots_count; U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; @@ -370,7 +420,7 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, OS_MutexScopeR(stripe->rw_mutex) for(;;) { //- rjf: find existing node - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, path_normalized, min_timestamp); + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); //- rjf: no node? this path is not opened if(node == 0) @@ -390,7 +440,7 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, B32 sent = 0; if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); @@ -417,18 +467,18 @@ di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, //~ rjf: Parse Threads internal B32 -di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us) +di_u2p_enqueue_key(DI_Key *key, U64 endt_us) { B32 sent = 0; OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; U64 available_size = di_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(path.size) + path.size + sizeof(min_timestamp)) + if(available_size >= sizeof(key->path.size) + key->path.size + sizeof(key->min_timestamp)) { - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &path.size); - di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, path.str, path.size); - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &min_timestamp); + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->path.size); + di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, key->path.str, key->path.size); + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->min_timestamp); di_shared->u2p_ring_write_pos += 7; di_shared->u2p_ring_write_pos -= di_shared->u2p_ring_write_pos%8; sent = 1; @@ -448,17 +498,17 @@ di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us) } internal void -di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp) +di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) { OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(out_path->size) + sizeof(out_min_timestamp[0])) + if(unconsumed_size >= sizeof(out_key->path.size) + sizeof(out_key->min_timestamp)) { - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_path->size); - out_path->str = push_array(arena, U8, out_path->size); - di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_path->str, out_path->size); - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_min_timestamp); + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->path.size); + out_key->path.str = push_array(arena, U8, out_key->path.size); + di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_key->path.str, out_key->path.size); + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->min_timestamp); di_shared->u2p_ring_read_pos += 7; di_shared->u2p_ring_read_pos -= di_shared->u2p_ring_read_pos%8; break; @@ -530,9 +580,10 @@ di_parse_thread__entry_point(void *p) //////////////////////////// //- rjf: grab next key // - String8 og_path = {0}; - U64 min_timestamp = 0; - di_u2p_dequeue_key(scratch.arena, &og_path, &min_timestamp); + DI_Key key = {0}; + di_u2p_dequeue_key(scratch.arena, &key); + String8 og_path = key.path; + U64 min_timestamp = key.min_timestamp; //////////////////////////// //- rjf: unpack key @@ -549,7 +600,7 @@ di_parse_thread__entry_point(void *p) B32 got_task = 0; OS_MutexScopeR(stripe->rw_mutex) { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); if(node != 0) { got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); @@ -852,7 +903,7 @@ di_parse_thread__entry_point(void *p) // if(got_task) OS_MutexScopeW(stripe->rw_mutex) { - DI_Node *node = di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(slot, og_path, min_timestamp); + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); if(node != 0) { node->is_working = 0; diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 73fc0da8..ece98ae6 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -4,6 +4,38 @@ #ifndef DI_H #define DI_H +//////////////////////////////// +//~ rjf: Cache Key Type + +typedef struct DI_Key DI_Key; +struct DI_Key +{ + String8 path; + U64 min_timestamp; +}; + +typedef struct DI_KeyNode DI_KeyNode; +struct DI_KeyNode +{ + DI_KeyNode *next; + DI_Key v; +}; + +typedef struct DI_KeyList DI_KeyList; +struct DI_KeyList +{ + DI_KeyNode *first; + DI_KeyNode *last; + U64 count; +}; + +typedef struct DI_KeyArray DI_KeyArray; +struct DI_KeyArray +{ + DI_Key *v; + U64 count; +}; + //////////////////////////////// //~ rjf: Event Types @@ -63,8 +95,7 @@ struct DI_Node U64 last_time_requested_us; // rjf: key - String8 path; - U64 min_timestamp; + DI_Key key; // rjf: file handles OS_Handle file; @@ -201,6 +232,12 @@ global RDI_Parsed di_rdi_parsed_nil = //~ rjf: Basic Helpers internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); +internal U64 di_hash_from_key(DI_Key *k); +internal B32 di_key_match(DI_Key *a, DI_Key *b); +internal DI_Key di_key_copy(Arena *arena, DI_Key *src); +internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src); +internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key); +internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list); //////////////////////////////// //~ rjf: Main Layer Initialization @@ -217,7 +254,7 @@ internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_No //////////////////////////////// //~ rjf: Per-Slot Functions -internal DI_Node *di_node_from_path_min_timestamp_slot__stripe_mutex_r_guarded(DI_Slot *slot, String8 path, U64 min_timestamp); +internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key); //////////////////////////////// //~ rjf: Per-Stripe Functions @@ -229,19 +266,19 @@ internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, Strin //////////////////////////////// //~ rjf: Key Opening/Closing -internal void di_open(String8 path, U64 min_timestamp); -internal void di_close(String8 path, U64 min_timestamp); +internal void di_open(DI_Key *key); +internal void di_close(DI_Key *key); //////////////////////////////// //~ rjf: Cache Lookups -internal RDI_Parsed *di_rdi_from_path_min_timestamp(DI_Scope *scope, String8 path, U64 min_timestamp, U64 endt_us); +internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us); //////////////////////////////// //~ rjf: Parse Threads -internal B32 di_u2p_enqueue_key(String8 path, U64 min_timestamp, U64 endt_us); -internal void di_u2p_dequeue_key(Arena *arena, String8 *out_path, U64 *out_min_timestamp); +internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us); +internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key); internal void di_p2u_push_event(DI_Event *event); internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index d8cbb9b4..50c697aa 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1541,8 +1541,8 @@ df_search_tags_from_entity(Arena *arena, DF_Entity *entity) U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *debug = df_dbgi_from_module(module); - String8 procedure_name = df_symbol_name_from_dbgi_voff(scratch.arena, debug, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(procedure_name.size != 0) { str8_list_push(scratch.arena, &strings, procedure_name); @@ -2841,7 +2841,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *debug = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2849,7 +2849,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -2863,7 +2863,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -2966,7 +2966,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *debug = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2974,7 +2974,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -2988,7 +2988,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -3079,25 +3079,26 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> debug info file +//- rjf: module <=> debug info keys -internal DF_Entity * -df_dbgi_from_module(DF_Entity *module) +internal DI_Key +df_dbgi_key_from_module(DF_Entity *module) { - DF_Entity *debug = df_entity_from_handle(module->entity_handle); - return debug; + DF_Entity *debug_info_path = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoPath); + DI_Key key = {debug_info_path->name, debug_info_path->timestamp}; + return key; } internal DF_EntityList -df_modules_from_dbgi(Arena *arena, DF_Entity *debug) +df_modules_from_dbgi_key(Arena *arena, DI_Key *dbgi_key) { DF_EntityList list = {0}; DF_EntityList all_modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = all_modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *module_debug_info = df_dbgi_from_module(module); - if(module_debug_info == debug) + DI_Key module_dbgi_key = df_dbgi_key_from_module(module); + if(di_key_match(&module_dbgi_key, dbgi_key)) { df_entity_list_push(arena, &list, module); } @@ -3153,28 +3154,16 @@ df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_rng) //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: debug file -> rdi - -internal RDI_Parsed * -df_rdi_from_dbgi(DI_Scope *scope, DF_Entity *dbgi) -{ - Temp scratch = scratch_begin(0, 0); - String8 path = df_full_path_from_entity(scratch.arena, dbgi); - RDI_Parsed *rdi = di_rdi_from_path_min_timestamp(scope, path, dbgi->timestamp, 0); - scratch_end(scratch); - return rdi; -} - //- rjf: symbol lookups internal String8 -df_symbol_name_from_dbgi_voff(Arena *arena, DF_Entity *dbgi, U64 voff) +df_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) { String8 result = {0}; { Temp scratch = scratch_begin(&arena, 1); DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); if(result.size == 0 && rdi->scope_vmap != 0) { U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); @@ -3205,9 +3194,9 @@ df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr) String8 result = {0}; { DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - result = df_symbol_name_from_dbgi_voff(arena, dbgi, voff); + result = df_symbol_name_from_dbgi_key_voff(arena, &dbgi_key, voff); } return result; } @@ -3224,7 +3213,7 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit } Temp scratch = scratch_begin(&arena, 1); DI_Scope *scope = di_scope_open(); - DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); + DI_KeyList dbgi_keys = df_push_active_dbgi_key_list(scratch.arena); DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); for(DF_EntityNode *override_n = overrides.first; override_n != 0; @@ -3233,13 +3222,13 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *dbgi_n = dbgis.first; - dbgi_n != 0; - dbgi_n = dbgi_n->next) + for(DI_KeyNode *dbgi_key_n = dbgi_keys.first; + dbgi_key_n != 0; + dbgi_key_n = dbgi_key_n->next) { // rjf: binary -> rdi - DF_Entity *dbgi = dbgi_n->entity; - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + DI_Key key = dbgi_key_n->v; + RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -3294,7 +3283,7 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.dbgi = dbgi; + src2dasm_n->v.dbgi_key = key; SLLQueuePush(src2dasm_list->first, src2dasm_list->last, src2dasm_n); src2dasm_list->count += 1; } @@ -3302,10 +3291,10 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit } } - // rjf: good src id -> push to relevant binaries + // rjf: good src id -> push to relevant dbgi keys if(good_src_id) { - df_entity_list_push(arena, &src2dasm_array.dbgis, dbgi); + di_key_list_push(arena, &src2dasm_array.dbgi_keys, &key); } } } @@ -3317,13 +3306,13 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit //- rjf: voff -> src lookups internal DF_TextLineDasm2SrcInfo -df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff) +df_text_line_dasm2src_info_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { Temp scratch = scratch_begin(0, 0); DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); DF_TextLineDasm2SrcInfo result = {0}; - result.file = result.dbgi = &df_g_nil_entity; + result.file = &df_g_nil_entity; if(rdi->unit_vmap != 0 && rdi->units != 0 && rdi->source_files != 0) { U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); @@ -3338,7 +3327,7 @@ df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff) RDI_SourceFile *file = &rdi->source_files[line->file_idx]; String8 file_normalized_full_path = {0}; file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); - result.dbgi = dbgi; + MemoryCopyStruct(&result.dbgi_key, dbgi_key); if(line->file_idx != 0 && file_normalized_full_path.size != 0) { result.file = df_entity_from_path(file_normalized_full_path, DF_EntityFromPathFlag_All); @@ -3355,14 +3344,14 @@ df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff) //- rjf: symbol -> voff lookups internal U64 -df_voff_from_dbgi_symbol_name(DF_Entity *dbgi, String8 symbol_name) +df_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DI_Scope *scope = di_scope_open(); U64 result = 0; { - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); RDI_NameMapKind name_map_kinds[] = { RDI_NameMapKind_GlobalVariables, @@ -3436,13 +3425,13 @@ df_voff_from_dbgi_symbol_name(DF_Entity *dbgi, String8 symbol_name) } internal U64 -df_type_num_from_dbgi_name(DF_Entity *dbgi, String8 name) +df_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name) { ProfBeginFunction(); DI_Scope *scope = di_scope_open(); U64 result = 0; { - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Types); RDI_ParsedNameMap parsed_name_map = {0}; rdi_name_map_parse(rdi, name_map, &parsed_name_map); @@ -3592,17 +3581,17 @@ df_architecture_from_entity(DF_Entity *entity) } internal EVAL_String2NumMap * -df_push_locals_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff) +df_push_locals_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff) { - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); EVAL_String2NumMap *result = eval_push_locals_map_from_rdi_voff(arena, rdi, voff); return result; } internal EVAL_String2NumMap * -df_push_member_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff) +df_push_member_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff) { - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); EVAL_String2NumMap *result = eval_push_member_map_from_rdi_voff(arena, rdi, voff); return result; } @@ -3879,13 +3868,13 @@ df_eval_parse_ctx_from_process_vaddr(DI_Scope *scope, DF_Entity *process, U64 va //- rjf: extract info DF_Entity *module = df_module_from_process_vaddr(process, vaddr); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_Entity *debug = df_dbgi_from_module(module); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, debug); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); Architecture arch = df_architecture_from_entity(process); EVAL_String2NumMap *reg_map = ctrl_string2reg_from_arch(arch); EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_voff(debug, voff); - EVAL_String2NumMap *member_map = df_query_cached_member_map_from_dbgi_voff(debug, voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_key_voff(&dbgi_key, voff); + EVAL_String2NumMap *member_map = df_query_cached_member_map_from_dbgi_key_voff(&dbgi_key, voff); //- rjf: build ctx EVAL_ParseCtx ctx = zero_struct; @@ -3908,7 +3897,7 @@ df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) { Temp scratch = scratch_begin(0, 0); EVAL_ParseCtx ctx = zero_struct; - DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); + DI_KeyList dbgi_keys = df_push_active_dbgi_key_list(scratch.arena); DF_TextLineSrc2DasmInfoList src2dasm_list = {0}; //- rjf: search for line info in all binaries for this file:pt @@ -3920,13 +3909,13 @@ df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *dbgi_n = dbgis.first; - dbgi_n != 0; - dbgi_n = dbgi_n->next) + for(DI_KeyNode *dbgi_key_n = dbgi_keys.first; + dbgi_key_n != 0; + dbgi_key_n = dbgi_key_n->next) { - // rjf: debug file -> rdi - DF_Entity *dbgi = dbgi_n->entity; - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + // rjf: key -> rdi + DI_Key key = dbgi_key_n->v; + RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -3972,7 +3961,7 @@ df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(scratch.arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.dbgi = dbgi; + src2dasm_n->v.dbgi_key = key; SLLQueuePush(src2dasm_list.first, src2dasm_list.last, src2dasm_n); src2dasm_list.count += 1; } @@ -3987,7 +3976,7 @@ df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list.first; n != 0; n = n->next) { DF_TextLineSrc2DasmInfo *src2dasm = &n->v; - DF_EntityList modules = df_modules_from_dbgi(scratch.arena, src2dasm->dbgi); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &src2dasm->dbgi_key); if(modules.count != 0) { DF_Entity *module = modules.first->entity; @@ -4133,9 +4122,9 @@ df_eval_from_string(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_Pa { U64 vaddr = result.imm_u64; DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - String8 symbol_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, voff); + String8 symbol_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); if(symbol_name.size != 0) { result.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, tg_key_basic(TG_Kind_Void), 0); @@ -6112,16 +6101,18 @@ df_query_cached_entity_list_with_kind(DF_EntityKind kind) return result; } -internal DF_EntityList -df_push_active_dbgi_list(Arena *arena) +//- rjf: active entity based queries + +internal DI_KeyList +df_push_active_dbgi_key_list(Arena *arena) { - DF_EntityList dbgis = {0}; + DI_KeyList dbgis = {0}; DF_EntityList modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *dbgi = df_dbgi_from_module(module); - df_entity_list_push(arena, &dbgis, dbgi); + DI_Key key = df_dbgi_key_from_module(module); + di_key_list_push(arena, &dbgis, &key); } return dbgis; } @@ -6282,7 +6273,7 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo } internal EVAL_String2NumMap * -df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) +df_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6298,14 +6289,13 @@ df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(dbgi); - U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 hash = di_hash_from_key(dbgi_key); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->dbgi, handle) && n->voff == voff) + if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -6314,11 +6304,11 @@ df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) if(node == 0) { DI_Scope *scope = di_scope_open(); - EVAL_String2NumMap *map = df_push_locals_map_from_dbgi_voff(cache->arena, scope, dbgi, voff); + EVAL_String2NumMap *map = df_push_locals_map_from_dbgi_key_voff(cache->arena, scope, dbgi_key, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->dbgi = handle; + node->dbgi_key = di_key_copy(cache->arena, dbgi_key); node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); @@ -6336,7 +6326,7 @@ df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) } internal EVAL_String2NumMap * -df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) +df_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6352,14 +6342,13 @@ df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(dbgi); - U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 hash = di_hash_from_key(dbgi_key); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->dbgi, handle) && n->voff == voff) + if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -6368,11 +6357,11 @@ df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff) if(node == 0) { DI_Scope *scope = di_scope_open(); - EVAL_String2NumMap *map = df_push_member_map_from_dbgi_voff(cache->arena, scope, dbgi, voff); + EVAL_String2NumMap *map = df_push_member_map_from_dbgi_key_voff(cache->arena, scope, dbgi_key, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->dbgi = handle; + node->dbgi_key = di_key_copy(cache->arena, dbgi_key); node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); @@ -6699,9 +6688,9 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); - DF_Entity *debug = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 stop_thread_voff = df_voff_from_vaddr(module, stop_thread_vaddr); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(debug, stop_thread_voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, stop_thread_voff); DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = user_bps.first; n != 0; n = n->next) { @@ -6882,12 +6871,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_equip_vaddr(module, event->rip_vaddr); df_entity_equip_timestamp(module, event->timestamp); - // rjf: create & attach debug info path - CTRL_Entity *ctrl_module = ctrl_entity_from_machine_id_handle(df_state->ctrl_entity_store, event->machine_id, event->entity); - CTRL_Entity *ctrl_debug_info = ctrl_entity_child_from_kind(ctrl_module, CTRL_EntityKind_DebugInfoPath); - DF_Entity *debug_info = df_entity_from_path(ctrl_debug_info->string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); - df_entity_equip_entity_handle(module, df_handle_from_entity(debug_info)); - // rjf: is first -> find target, equip process & module & first thread with target color if(is_first) { @@ -6938,8 +6921,13 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) case CTRL_EventKind_ModuleDebugInfoPathChange: { DF_Entity *module = df_entity_from_ctrl_handle(event->machine_id, event->entity); - DF_Entity *debug_info = df_entity_from_path(event->string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); - df_entity_equip_entity_handle(module, df_handle_from_entity(debug_info)); + DF_Entity *debug_info = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoPath); + if(df_entity_is_nil(debug_info)) + { + debug_info = df_entity_alloc(0, module, DF_EntityKind_DebugInfoPath); + } + df_entity_equip_name(0, debug_info, event->string); + df_entity_equip_timestamp(debug_info, event->timestamp); }break; //- rjf: debug strings diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 49dbfa0d..24fceb96 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -521,7 +521,7 @@ struct DF_TextLineSrc2DasmInfo { Rng1U64 voff_range; S64 remap_line; - DF_Entity *dbgi; + DI_Key dbgi_key; }; typedef struct DF_TextLineSrc2DasmInfoNode DF_TextLineSrc2DasmInfoNode; @@ -543,7 +543,7 @@ typedef struct DF_TextLineSrc2DasmInfoListArray DF_TextLineSrc2DasmInfoListArray struct DF_TextLineSrc2DasmInfoListArray { DF_TextLineSrc2DasmInfoList *v; - DF_EntityList dbgis; + DI_KeyList dbgi_keys; U64 count; }; @@ -552,7 +552,7 @@ struct DF_TextLineSrc2DasmInfoListArray typedef struct DF_TextLineDasm2SrcInfo DF_TextLineDasm2SrcInfo; struct DF_TextLineDasm2SrcInfo { - DF_Entity *dbgi; + DI_Key dbgi_key; DF_Entity *file; TxtPt pt; Rng1U64 voff_range; @@ -1004,7 +1004,7 @@ typedef struct DF_RunLocalsCacheNode DF_RunLocalsCacheNode; struct DF_RunLocalsCacheNode { DF_RunLocalsCacheNode *hash_next; - DF_Handle dbgi; + DI_Key dbgi_key; U64 voff; EVAL_String2NumMap *locals_map; }; @@ -1518,9 +1518,9 @@ internal CTRL_TrapList df_trap_net_from_thread__step_into_line(Arena *arena, DF_ //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> debug info file -internal DF_Entity *df_dbgi_from_module(DF_Entity *module); -internal DF_EntityList df_modules_from_dbgi(Arena *arena, DF_Entity *debug); +//- rjf: module <=> debug info keys +internal DI_Key df_dbgi_key_from_module(DF_Entity *module); +internal DF_EntityList df_modules_from_dbgi_key(Arena *arena, DI_Key *dbgi_key); //- rjf: voff <=> vaddr internal U64 df_base_vaddr_from_module(DF_Entity *module); @@ -1532,22 +1532,19 @@ internal Rng1U64 df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_ //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: debug file -> rdi -internal RDI_Parsed *df_rdi_from_dbgi(DI_Scope *scope, DF_Entity *dbgi); - //- rjf: voff|vaddr -> symbol lookups -internal String8 df_symbol_name_from_dbgi_voff(Arena *arena, DF_Entity *dbgi, U64 voff); +internal String8 df_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff); internal String8 df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr); //- rjf: src -> voff lookups internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entity *file, Rng1S64 line_num_range); //- rjf: voff -> src lookups -internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_dbgi_voff(DF_Entity *dbgi, U64 voff); +internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); //- rjf: symbol -> voff lookups -internal U64 df_voff_from_dbgi_symbol_name(DF_Entity *dbgi, String8 symbol_name); -internal U64 df_type_num_from_dbgi_name(DF_Entity *dbgi, String8 name); +internal U64 df_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name); +internal U64 df_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name); //////////////////////////////// //~ rjf: Process/Thread/Module Info Lookups @@ -1556,8 +1553,8 @@ internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); internal DF_Entity *df_module_from_thread(DF_Entity *thread); internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal Architecture df_architecture_from_entity(DF_Entity *entity); -internal EVAL_String2NumMap *df_push_locals_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff); -internal EVAL_String2NumMap *df_push_member_map_from_dbgi_voff(Arena *arena, DI_Scope *scope, DF_Entity *dbgi, U64 voff); +internal EVAL_String2NumMap *df_push_locals_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff); +internal EVAL_String2NumMap *df_push_member_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff); internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); internal DF_Entity *df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates); @@ -1679,7 +1676,9 @@ internal String8 df_info_summary_from_string(Architecture arch, String8 string); //- rjf: entity kind cache internal DF_EntityList df_query_cached_entity_list_with_kind(DF_EntityKind kind); -internal DF_EntityList df_push_active_dbgi_list(Arena *arena); + +//- rjf: active entity based queries +internal DI_KeyList df_push_active_dbgi_key_list(Arena *arena); internal DF_EntityList df_push_active_target_list(Arena *arena); //- rjf: per-run caches @@ -1687,8 +1686,8 @@ internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal U64 df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); -internal EVAL_String2NumMap *df_query_cached_locals_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff); -internal EVAL_String2NumMap *df_query_cached_member_map_from_dbgi_voff(DF_Entity *dbgi, U64 voff); +internal EVAL_String2NumMap *df_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); +internal EVAL_String2NumMap *df_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); //- rjf: top-level command dispatch internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); diff --git a/src/df/core/df_core.mdesk b/src/df/core/df_core.mdesk index cf37ac1e..e1a15028 100644 --- a/src/df/core/df_core.mdesk +++ b/src/df/core/df_core.mdesk @@ -26,14 +26,10 @@ DF_EntityKindTable: //- rjf: filesystem modeling {File file 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "File" } {OverrideFileLink override_file_link 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Override File Link" } - {PendingFileChange pending_file_change 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Pending File Change" } //- rjf: auto view rules {AutoViewRule auto_view_rule 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 "Label" Binoculars "Auto View Rule" } - //- rjf: diagnostics log - {DiagLog diag_log 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Diagnostics Log" } - //- rjf: text attachments {FlashMarker flash_marker 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Flash Marker" } @@ -59,8 +55,8 @@ DF_EntityKindTable: {Process process 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Process" } {Thread thread 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Thread "Thread" } {Module module 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Module" } - {DebugInfoOverride debug_info_override 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 "Label" Null "Debug Info Override" } {PendingThreadName pending_thread_name 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Pending Thread Name" } + {DebugInfoPath debug_info_path 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Debug Info Path" } //- rjf: parser task entities {ConversionTask conversion_task 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Conversion Task" } diff --git a/src/df/core/generated/df_core.meta.c b/src/df/core/generated/df_core.meta.c index 03e9c0f9..b6edc57a 100644 --- a/src/df/core/generated/df_core.meta.c +++ b/src/df/core/generated/df_core.meta.c @@ -30,16 +30,14 @@ Rng1U64 df_g_cmd_param_slot_range_table[22] = {OffsetOf(DF_CmdParams, dir2), OffsetOf(DF_CmdParams, dir2) + sizeof(Dir2)}, }; -DF_IconKind df_g_entity_kind_icon_kind_table[27] = +DF_IconKind df_g_entity_kind_icon_kind_table[25] = { DF_IconKind_Null, DF_IconKind_Null, DF_IconKind_Machine, DF_IconKind_FileOutline, DF_IconKind_FileOutline, -DF_IconKind_FileOutline, DF_IconKind_Binoculars, -DF_IconKind_FileOutline, DF_IconKind_Null, DF_IconKind_Pin, DF_IconKind_CircleFilled, @@ -54,23 +52,21 @@ DF_IconKind_Null, DF_IconKind_Threads, DF_IconKind_Thread, DF_IconKind_Module, -DF_IconKind_Null, DF_IconKind_Threads, +DF_IconKind_Module, DF_IconKind_Null, DF_IconKind_Null, DF_IconKind_Null, }; -String8 df_g_entity_kind_display_string_table[27] = +String8 df_g_entity_kind_display_string_table[25] = { str8_lit_comp("Nil"), str8_lit_comp("Root"), str8_lit_comp("Machine"), str8_lit_comp("File"), str8_lit_comp("Override File Link"), -str8_lit_comp("Pending File Change"), str8_lit_comp("Auto View Rule"), -str8_lit_comp("Diagnostics Log"), str8_lit_comp("Flash Marker"), str8_lit_comp("Watch Pin"), str8_lit_comp("Breakpoint"), @@ -85,14 +81,14 @@ str8_lit_comp("Destination"), str8_lit_comp("Process"), str8_lit_comp("Thread"), str8_lit_comp("Module"), -str8_lit_comp("Debug Info Override"), str8_lit_comp("Pending Thread Name"), +str8_lit_comp("Debug Info Path"), str8_lit_comp("Conversion Task"), str8_lit_comp("Conversion Failure"), str8_lit_comp("EndedProcess"), }; -String8 df_g_entity_kind_name_label_table[27] = +String8 df_g_entity_kind_name_label_table[25] = { str8_lit_comp("Label"), str8_lit_comp("Label"), @@ -101,8 +97,6 @@ str8_lit_comp("Label"), str8_lit_comp("Label"), str8_lit_comp("Label"), str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), str8_lit_comp("Expression"), str8_lit_comp("Label"), str8_lit_comp("Expression"), @@ -123,17 +117,15 @@ str8_lit_comp("Label"), str8_lit_comp("Label"), }; -DF_EntityKindFlags df_g_entity_kind_flags_table[27] = +DF_EntityKindFlags df_g_entity_kind_flags_table[25] = { (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (1*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 1*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), @@ -147,14 +139,14 @@ DF_EntityKindFlags df_g_entity_kind_flags_table[27] = (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 1*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 1*DF_EntityKindFlag_TreeMutationSoftHalt | 1*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), }; -DF_EntityOpFlags df_g_entity_kind_op_flags_table[27] = +DF_EntityOpFlags df_g_entity_kind_op_flags_table[25] = { (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), @@ -163,8 +155,6 @@ DF_EntityOpFlags df_g_entity_kind_op_flags_table[27] = (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), (1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (1*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), diff --git a/src/df/core/generated/df_core.meta.h b/src/df/core/generated/df_core.meta.h index 9e7faeef..daf1d7b6 100644 --- a/src/df/core/generated/df_core.meta.h +++ b/src/df/core/generated/df_core.meta.h @@ -22,9 +22,7 @@ DF_EntityKind_Root, DF_EntityKind_Machine, DF_EntityKind_File, DF_EntityKind_OverrideFileLink, -DF_EntityKind_PendingFileChange, DF_EntityKind_AutoViewRule, -DF_EntityKind_DiagLog, DF_EntityKind_FlashMarker, DF_EntityKind_WatchPin, DF_EntityKind_Breakpoint, @@ -39,8 +37,8 @@ DF_EntityKind_Dest, DF_EntityKind_Process, DF_EntityKind_Thread, DF_EntityKind_Module, -DF_EntityKind_DebugInfoOverride, DF_EntityKind_PendingThreadName, +DF_EntityKind_DebugInfoPath, DF_EntityKind_ConversionTask, DF_EntityKind_ConversionFail, DF_EntityKind_EndedProcess, @@ -1531,11 +1529,11 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = }; C_LINKAGE_BEGIN extern Rng1U64 df_g_cmd_param_slot_range_table[22]; -extern DF_IconKind df_g_entity_kind_icon_kind_table[27]; -extern String8 df_g_entity_kind_display_string_table[27]; -extern String8 df_g_entity_kind_name_label_table[27]; -extern DF_EntityKindFlags df_g_entity_kind_flags_table[27]; -extern DF_EntityOpFlags df_g_entity_kind_op_flags_table[27]; +extern DF_IconKind df_g_entity_kind_icon_kind_table[25]; +extern String8 df_g_entity_kind_display_string_table[25]; +extern String8 df_g_entity_kind_name_label_table[25]; +extern DF_EntityKindFlags df_g_entity_kind_flags_table[25]; +extern DF_EntityOpFlags df_g_entity_kind_op_flags_table[25]; extern String8 df_g_cfg_src_string_table[4]; extern DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[4]; extern DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[4]; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 8b679140..da8cb55f 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -583,17 +583,18 @@ df_queue_drag_drop(void) } internal void -df_set_hovered_line_info(DF_Entity *dbgi, U64 voff) +df_set_hovered_line_info(DI_Key *dbgi_key, U64 voff) { - df_gfx_state->hover_line_dbgi = df_handle_from_entity(dbgi); + arena_clear(df_gfx_state->hover_line_arena); + df_gfx_state->hover_line_dbgi_key = di_key_copy(df_gfx_state->hover_line_arena, dbgi_key); df_gfx_state->hover_line_voff = voff; df_gfx_state->hover_line_set_this_frame = 1; } -internal DF_Entity * -df_get_hovered_line_info_dbgi(void) +internal DI_Key +df_get_hovered_line_info_dbgi_key(void) { - return df_entity_from_handle(df_gfx_state->hover_line_dbgi); + return df_gfx_state->hover_line_dbgi_key; } internal U64 @@ -2499,14 +2500,14 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); // rjf: snap to resolved line B32 missing_rip = (rip_vaddr == 0); - B32 dbgi_missing = (dbgi->flags & DF_EntityFlag_IsMissing || df_entity_is_nil(dbgi)); + B32 dbgi_missing = (dbgi_key.min_timestamp == 0 || dbgi_key.path.size == 0); B32 dbgi_pending = !dbgi_missing && rdi == &di_rdi_parsed_nil; B32 has_line_info = (line_info.voff_range.max != line_info.voff_range.min); B32 has_module = !df_entity_is_nil(module); @@ -2562,17 +2563,17 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: try to resolve name as a symbol U64 voff = 0; - DF_Entity *voff_dbgi = &df_g_nil_entity; + DI_Key voff_dbgi_key = {0}; if(name_resolved == 0) { - DF_EntityList dbgis = df_push_active_dbgi_list(scratch.arena); - for(DF_EntityNode *n = dbgis.first; n != 0; n = n->next) + DI_KeyList keys = df_push_active_dbgi_key_list(scratch.arena); + for(DI_KeyNode *n = keys.first; n != 0; n = n->next) { - U64 binary_voff = df_voff_from_dbgi_symbol_name(n->entity, name); + U64 binary_voff = df_voff_from_dbgi_key_symbol_name(&n->v, name); if(binary_voff != 0) { voff = binary_voff; - voff_dbgi = n->entity; + voff_dbgi_key = n->v; name_resolved = 1; break; } @@ -2681,16 +2682,16 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: name resolved to voff * dbg info if(name_resolved != 0 && voff != 0) { - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(voff_dbgi, voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&voff_dbgi_key, voff); DF_CmdParams p = params; { p.file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); p.text_point = dasm2src_info.pt; df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); df_cmd_params_mark_slot(&p, DF_CmdParamSlot_TextPoint); - if(!df_entity_is_nil(voff_dbgi)) + if(voff_dbgi_key.path.size != 0) { - DF_EntityList modules = df_modules_from_dbgi(scratch.arena, voff_dbgi); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &voff_dbgi_key); DF_Entity *module = df_first_entity_from_list(&modules); DF_Entity *process = df_entity_ancestor_from_kind(module, DF_EntityKind_Process); if(!df_entity_is_nil(process)) @@ -2918,7 +2919,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { for(DF_TextLineSrc2DasmInfoNode *n = src2dasm.v[src2dasm_idx].first; n != 0; n = n->next) { - DF_EntityList modules = df_modules_from_dbgi(scratch.arena, n->v.dbgi); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &n->v.dbgi_key); DF_Entity *module = df_module_from_thread_candidates(thread, &modules); vaddr = df_vaddr_from_voff(module, n->v.voff_range.min); goto end_lookup; @@ -3493,6 +3494,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) avg_ui_hash_chain_length = chain_length_sum / chain_count; } ui_labelf("Target Hz: %.2f", 1.f/df_dt()); + ui_labelf("Unwind Cache Gen: %I64u", df_state->unwind_cache_gen); ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen()); ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen()); ui_labelf("Window %p", window); @@ -3922,9 +3924,9 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[frame_idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(symbol.size != 0) { str8_list_pushf(scratch.arena, &lines, "0x%I64x: %S", rip_vaddr, symbol); @@ -4249,7 +4251,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); //- rjf: gather lister items DF_AutoCompListerItemChunkList item_list = {0}; @@ -4257,7 +4259,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: gather locals if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Locals) { - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_voff(dbgi, thread_rip_voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_key_voff(&dbgi_key, thread_rip_voff); for(EVAL_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) { DF_AutoCompListerItem item = {0}; @@ -9936,9 +9938,9 @@ df_entity_tooltips(DF_Entity *entity) { U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); UI_PrefWidth(ui_children_sum(1)) UI_Row { UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("0x%I64x", rip_vaddr); @@ -10132,8 +10134,8 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); - String8 procedure_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(procedure_name.size != 0) { FuzzyMatchRangeList fuzzy_matches = {0}; @@ -10576,7 +10578,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -10643,7 +10645,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ n != 0; n = n->next) { - if(n->v.dbgi == dbgi) + if(di_key_match(&n->v.dbgi_key, &dbgi_key)) { line_info = &n->v; break; @@ -11251,11 +11253,11 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(params->line_src2dasm[line_slice_idx].first != 0 && params->line_src2dasm[line_slice_idx].first->v.remap_line == mouse_pt.line) { - df_set_hovered_line_info(params->line_src2dasm[line_slice_idx].first->v.dbgi, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(¶ms->line_src2dasm[line_slice_idx].first->v.dbgi_key, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); } if(params->line_dasm2src[line_slice_idx].first != 0) { - df_set_hovered_line_info(params->line_dasm2src[line_slice_idx].first->v.dbgi, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(¶ms->line_dasm2src[line_slice_idx].first->v.dbgi_key, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); } } @@ -11419,7 +11421,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // UI_Parent(text_container_box) ProfScope("build line text") UI_Focus(UI_FocusKind_Off) { - DF_Entity *hovered_line_dbgi = df_get_hovered_line_info_dbgi(); + DI_Key hovered_line_dbgi_key = df_get_hovered_line_info_dbgi_key(); U64 hovered_line_voff = df_get_hovered_line_info_voff(); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); UI_WidthFill @@ -11494,12 +11496,12 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(token->kind == TXT_TokenKind_Identifier || token->kind == TXT_TokenKind_Keyword) { B32 mapped_special = 0; - for(DF_EntityNode *n = params->relevant_dbgis.first; n != 0; n = n->next) + for(DI_KeyNode *n = params->relevant_dbgi_keys.first; n != 0; n = n->next) { - DF_Entity *dbgi = n->entity; + DI_Key dbgi_key = n->v; if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 voff = df_voff_from_dbgi_symbol_name(dbgi, token_string); + U64 voff = df_voff_from_dbgi_key_symbol_name(&dbgi_key, token_string); if(voff != 0) { mapped_special = 1; @@ -11509,7 +11511,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 type_num = df_type_num_from_dbgi_name(dbgi, token_string); + U64 type_num = df_type_num_from_dbgi_key_name(&dbgi_key, token_string); if(type_num != 0) { mapped_special = 1; @@ -11701,7 +11703,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list->first; n != 0; n = n->next) { if(n->v.remap_line == line_num && - n->v.dbgi == hovered_line_dbgi && + di_key_match(&n->v.dbgi_key, &hovered_line_dbgi_key) && n->v.voff_range.min <= hovered_line_voff && hovered_line_voff < n->v.voff_range.max) { matches = 1; @@ -11714,8 +11716,8 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // rjf: check dasm2src if(dasm2src_list->first != 0) { - DF_Entity *dbgi = dasm2src_list->first->v.dbgi; - if(dbgi == hovered_line_dbgi) + DI_Key dbgi_key = dasm2src_list->first->v.dbgi_key; + if(di_key_match(&dbgi_key, &dasm2src_list->first->v.dbgi_key)) { for(DF_TextLineDasm2SrcInfoNode *n = dasm2src_list->first; n != 0; n = n->next) { @@ -12813,6 +12815,7 @@ df_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, DF_StateDe df_gfx_state->repaint_hook = window_repaint_entry_point; df_gfx_state->cfg_main_font_path_arena = arena_alloc(); df_gfx_state->cfg_code_font_path_arena = arena_alloc(); + df_gfx_state->hover_line_arena = arena_alloc(); df_clear_bindings(); // rjf: register gfx layer views @@ -13822,7 +13825,7 @@ df_gfx_end_frame(void) //- rjf: clear hover line info if(df_gfx_state->hover_line_set_this_frame == 0) { - df_gfx_state->hover_line_dbgi = df_handle_zero(); + MemoryZeroStruct(&df_gfx_state->hover_line_dbgi_key); df_gfx_state->hover_line_voff = 0; } diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 54d06be3..59a7c679 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -405,7 +405,7 @@ struct DF_CodeSliceParams DF_EntityList *line_pins; DF_TextLineDasm2SrcInfoList *line_dasm2src; DF_TextLineSrc2DasmInfoList *line_src2dasm; - DF_EntityList relevant_dbgis; + DI_KeyList relevant_dbgi_keys; // rjf: visual parameters F_Tag font; @@ -714,7 +714,8 @@ struct DF_GfxState DF_DragDropState drag_drop_state; // rjf: hover line info correllation state - DF_Handle hover_line_dbgi; + Arena *hover_line_arena; + DI_Key hover_line_dbgi_key; U64 hover_line_voff; B32 hover_line_set_this_frame; @@ -871,8 +872,8 @@ internal B32 df_drag_drop(DF_DragDropPayload *out_payload); internal void df_drag_kill(void); internal void df_queue_drag_drop(void); -internal void df_set_hovered_line_info(DF_Entity *dbgi, U64 voff); -internal DF_Entity *df_get_hovered_line_info_dbgi(void); +internal void df_set_hovered_line_info(DI_Key *dbgi_key, U64 voff); +internal DI_Key df_get_hovered_line_info_dbgi_key(void); internal U64 df_get_hovered_line_info_voff(void); //////////////////////////////// diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 4528ca31..d311ef3c 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -646,7 +646,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, F DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_rip_unwind_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_unwind_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); //- rjf: calculate top-level keys, expand root-level, grab root expansion node DF_ExpandKey parent_key = df_expand_key_make(5381, 0); @@ -657,11 +657,10 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, F //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - FZY_DbgiKey key = {df_full_path_from_entity(scratch.arena, dbgi), dbgi->timestamp}; FZY_Params params = {fzy_target}; { params.dbgi_keys.count = 1; - params.dbgi_keys.v = &key; + params.dbgi_keys.v = &dbgi_key; } FZY_ItemArray items = fzy_items_from_key_params_query(fzy_scope, fuzzy_search_key, ¶ms, filter, os_now_microseconds()+100, &items_stale); if(items_stale) @@ -3237,30 +3236,19 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) FZY_Scope *fzy_scope = fzy_scope_open(); F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); String8 query = str8(view->query_buffer, view->query_string_size); - DF_EntityList dbgis_list = df_push_active_dbgi_list(scratch.arena); - DF_EntityArray dbgis = df_entity_array_from_list(scratch.arena, &dbgis_list); + DI_KeyList dbgi_keys_list = df_push_active_dbgi_key_list(scratch.arena); + DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); + FZY_Params params = {FZY_Target_Procedures, dbgi_keys}; U64 endt_us = os_now_microseconds()+200; - //- rjf: produce fuzzy search parameters - FZY_Params params = {FZY_Target_Procedures}; - { - params.dbgi_keys.count = dbgis.count; - params.dbgi_keys.v = push_array(scratch.arena, FZY_DbgiKey, params.dbgi_keys.count); - for(U64 idx = 0; idx < params.dbgi_keys.count; idx += 1) - { - params.dbgi_keys.v[idx].path = df_full_path_from_entity(scratch.arena, dbgis.v[idx]); - params.dbgi_keys.v[idx].timestamp = dbgis.v[idx]->timestamp; - } - } - //- rjf: grab rdis, make type graphs for each - U64 rdis_count = dbgis.count; + U64 rdis_count = dbgi_keys.count; RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); TG_Graph **graphs = push_array(scratch.arena, TG_Graph *, rdis_count); { for(U64 idx = 0; idx < rdis_count; idx += 1) { - rdis[idx] = di_rdi_from_path_min_timestamp(di_scope, params.dbgi_keys.v[idx].path, params.dbgi_keys.v[idx].timestamp, endt_us); + rdis[idx] = di_rdi_from_key(di_scope, &dbgi_keys.v[idx], endt_us); graphs[idx] = tg_graph_begin(rdi_addr_size_from_arch(rdis[idx]->top_level_info->architecture), 256); } } @@ -3341,7 +3329,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) FZY_Item *item = &items.v[idx]; //- rjf: determine dbgi/rdi to which this item belongs - DF_Entity *dbgi = &df_g_nil_entity; + DI_Key dbgi_key = {0}; RDI_Parsed *rdi = &di_rdi_parsed_nil; TG_Graph *graph = 0; U64 base_idx = 0; @@ -3350,7 +3338,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { if(base_idx <= item->idx && item->idx < base_idx + rdis[rdi_idx]->procedures_count) { - dbgi = dbgis.v[rdi_idx]; + dbgi_key = dbgi_keys.v[rdi_idx]; rdi = rdis[rdi_idx]; graph = graphs[rdi_idx]; break; @@ -3398,8 +3386,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } if(ui_hovering(sig)) UI_Tooltip { - U64 binary_voff = df_voff_from_dbgi_symbol_name(dbgi, name); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, binary_voff); + U64 binary_voff = df_voff_from_dbgi_key_symbol_name(&dbgi_key, name); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, binary_voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); S64 line_num = dasm2src_info.pt.line; df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); @@ -4794,8 +4782,8 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) U64 rip_vaddr = df_query_cached_rip_from_thread(entity); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); if(!df_entity_is_nil(line_info.file)) { UI_PrefWidth(ui_children_sum(0)) df_entity_src_loc_button(ws, line_info.file, line_info.pt); @@ -5266,9 +5254,9 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) B32 brw_is_selected = (row_is_selected && cursor.x == 3); // rjf: unpack module info - DF_Entity *dbgi = df_dbgi_from_module(entity); - String8 dbgi_path = df_full_path_from_entity(scratch.arena, dbgi); - RDI_Parsed *rdi = df_rdi_from_dbgi(scope, dbgi); + DI_Key dbgi_key = df_dbgi_key_from_module(entity); + String8 dbgi_path = dbgi_key.path; + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); B32 dbgi_is_valid = (rdi != &di_rdi_parsed_nil); // rjf: begin editing @@ -5598,8 +5586,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *dbgi = src2dasm_list->first->v.dbgi; - DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -5901,8 +5889,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; DF_Entity *module = df_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); if(dasm2src_info.file == entity && visible_line_num_range.min <= dasm2src_info.pt.line && dasm2src_info.pt.line <= visible_line_num_range.max) { U64 slice_line_idx = dasm2src_info.pt.line-visible_line_num_range.min; @@ -5933,7 +5921,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { MemoryCopy(code_slice_params.line_src2dasm, src2dasm.v, sizeof(DF_TextLineSrc2DasmInfoList)*src2dasm.count); } - code_slice_params.relevant_dbgis = src2dasm.dbgis; + code_slice_params.relevant_dbgi_keys = src2dasm.dbgi_keys; } } @@ -6249,8 +6237,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *dbgi = src2dasm_list->first->v.dbgi; - DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread_dst_module = df_module_from_thread_candidates(dropped_entity, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -6306,8 +6294,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *dbgi = src2dasm_list->first->v.dbgi; - DF_EntityList possible_modules = df_modules_from_dbgi(scratch.arena, dbgi); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -6466,18 +6454,18 @@ DF_VIEW_UI_FUNCTION_DEF(Code) // B32 file_is_out_of_date = 0; String8 out_of_date_dbgi_name = {0}; - for(DF_EntityNode *n = code_slice_params.relevant_dbgis.first; n != 0; n = n->next) + for(DI_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) { - DF_Entity *dbgi = n->entity; - if(!df_entity_is_nil(dbgi)) + DI_Key key = n->v; + if(key.path.size != 0) { String8 full_path = df_full_path_from_entity(scratch.arena, entity); TXTI_Handle handle = txti_handle_from_path(full_path); TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); - if(dbgi->timestamp < info.timestamp) + if(key.min_timestamp < info.timestamp) { file_is_out_of_date = 1; - out_of_date_dbgi_name = dbgi->name; + out_of_date_dbgi_name = str8_skip_last_slash(key.path); break; } } @@ -6580,7 +6568,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) Architecture arch = df_architecture_from_entity(process); U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_dbgi = df_dbgi_from_module(dasm_module); + DI_Key dasm_dbgi_key = df_dbgi_key_from_module(dasm_module); Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; @@ -6591,8 +6579,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.dbg_path = df_full_path_from_entity(scratch.arena, dasm_dbgi); - dasm_params.dbg_timestamp = dasm_dbgi->timestamp; + dasm_params.dbgi_key = dasm_dbgi_key; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6835,7 +6822,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) Architecture arch = df_architecture_from_entity(process); U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_dbgi = df_dbgi_from_module(dasm_module); + DI_Key dasm_dbgi_key = df_dbgi_key_from_module(dasm_module); Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; @@ -6846,8 +6833,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.dbg_path = df_full_path_from_entity(scratch.arena, dasm_dbgi); - dasm_params.dbg_timestamp = dasm_dbgi->timestamp; + dasm_params.dbgi_key = dasm_dbgi_key; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6860,7 +6846,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: unpack module info for this region // DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); ////////////////////////////// //- rjf: is loading -> equip view with loading information @@ -6949,7 +6935,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { code_slice_params.margin_float_off_px = 0; } - df_entity_list_push(scratch.arena, &code_slice_params.relevant_dbgis, dbgi); + di_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, &dbgi_key); // rjf: fill text info { @@ -7031,7 +7017,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // rjf: fill dasm -> src info { DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { U64 vaddr = dasm_vaddr_range.min + dasm_inst_array_code_off_from_idx(&dasm_info.insts, line_num-1); @@ -7040,7 +7026,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_TextLineDasm2SrcInfoNode *dasm2src_n = push_array(scratch.arena, DF_TextLineDasm2SrcInfoNode, 1); SLLQueuePush(code_slice_params.line_dasm2src[slice_idx].first, code_slice_params.line_dasm2src[slice_idx].last, dasm2src_n); code_slice_params.line_dasm2src[slice_idx].count += 1; - dasm2src_n->v = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, voff); + dasm2src_n->v = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, voff); } } } @@ -7210,9 +7196,9 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { U64 vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.goto_src_line_num-1); DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_dbgi_voff(dbgi, voff); + DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src.file); DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.text_point = dasm2src.pt; @@ -8552,9 +8538,9 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) { U64 f_rip = regs_rip_from_arch_block(thread->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, f_rip); - DF_Entity *dbgi = df_dbgi_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, f_rip); - String8 symbol_name = df_symbol_name_from_dbgi_voff(scratch.arena, dbgi, rip_voff); + String8 symbol_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); annotation->kind_string = str8_lit("Call Stack Frame"); diff --git a/src/fuzzy_search/fuzzy_search.c b/src/fuzzy_search/fuzzy_search.c index a6e3f0fa..24cc8b13 100644 --- a/src/fuzzy_search/fuzzy_search.c +++ b/src/fuzzy_search/fuzzy_search.c @@ -22,7 +22,7 @@ fzy_hash_from_params(FZY_Params *params) hash = fzy_hash_from_string(hash, str8_struct(¶ms->target)); for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1) { - hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].timestamp)); + hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].min_timestamp)); hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path); } return hash; @@ -84,35 +84,13 @@ fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, return result; } -internal void -fzy_dbgi_key_list_push(Arena *arena, FZY_DbgiKeyList *list, FZY_DbgiKey key) -{ - FZY_DbgiKeyNode *n = push_array(arena, FZY_DbgiKeyNode, 1); - n->v = key; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal FZY_DbgiKeyArray -fzy_dbgi_key_array_from_list(Arena *arena, FZY_DbgiKeyList *list) -{ - FZY_DbgiKeyArray array = {0}; - array.v = push_array(arena, FZY_DbgiKey, list->count); - U64 idx = 0; - for(FZY_DbgiKeyNode *n = list->first; n != 0; n = n->next, idx += 1) - { - array.v[idx] = n->v; - } - return array; -} - internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src) { FZY_Params dst = zero_struct; MemoryCopyStruct(&dst, src); - dst.dbgi_keys.v = push_array(arena, FZY_DbgiKey, dst.dbgi_keys.count); - MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(FZY_DbgiKey)*src->dbgi_keys.count); + dst.dbgi_keys.v = push_array(arena, DI_Key, dst.dbgi_keys.count); + MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(DI_Key)*src->dbgi_keys.count); for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1) { dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path); @@ -422,7 +400,7 @@ fzy_search_thread__entry_point(void *p) { for(U64 idx = 0; idx < rdis_count; idx += 1) { - rdis[idx] = di_rdi_from_path_min_timestamp(di_scope, params.dbgi_keys.v[idx].path, params.dbgi_keys.v[idx].timestamp, max_U64); + rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], max_U64); } } diff --git a/src/fuzzy_search/fuzzy_search.h b/src/fuzzy_search/fuzzy_search.h index a2b83a1e..5608c902 100644 --- a/src/fuzzy_search/fuzzy_search.h +++ b/src/fuzzy_search/fuzzy_search.h @@ -53,40 +53,11 @@ typedef enum FZY_Target } FZY_Target; -typedef struct FZY_DbgiKey FZY_DbgiKey; -struct FZY_DbgiKey -{ - String8 path; - U64 timestamp; -}; - -typedef struct FZY_DbgiKeyNode FZY_DbgiKeyNode; -struct FZY_DbgiKeyNode -{ - FZY_DbgiKeyNode *next; - FZY_DbgiKey v; -}; - -typedef struct FZY_DbgiKeyList FZY_DbgiKeyList; -struct FZY_DbgiKeyList -{ - FZY_DbgiKeyNode *first; - FZY_DbgiKeyNode *last; - U64 count; -}; - -typedef struct FZY_DbgiKeyArray FZY_DbgiKeyArray; -struct FZY_DbgiKeyArray -{ - FZY_DbgiKey *v; - U64 count; -}; - typedef struct FZY_Params FZY_Params; struct FZY_Params { FZY_Target target; - FZY_DbgiKeyArray dbgi_keys; + DI_KeyArray dbgi_keys; }; //////////////////////////////// @@ -199,8 +170,6 @@ internal U64 fzy_hash_from_string(U64 seed, String8 string); internal U64 fzy_hash_from_params(FZY_Params *params); internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx); internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx); -internal void fzy_dbgi_key_list_push(Arena *arena, FZY_DbgiKeyList *list, FZY_DbgiKey key); -internal FZY_DbgiKeyArray fzy_dbgi_key_array_from_list(Arena *arena, FZY_DbgiKeyList *list); internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src); //////////////////////////////// diff --git a/src/mule/mule_peb_trample_reload.c b/src/mule/mule_peb_trample_reload.c index 8e90550f..f505a882 100644 --- a/src/mule/mule_peb_trample_reload.c +++ b/src/mule/mule_peb_trample_reload.c @@ -1,10 +1,13 @@ __declspec(dllexport) int loop_iteration(int it) { + return 111; +#if 0 int sum = 0; for(int i = 0; i < 1000; i += 1) { sum += it*i; } return sum; +#endif } diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 7522ace2..f259abee 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -32,7 +32,6 @@ #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" #include "text_cache/text_cache.h" -#include "dasm_cache/dasm_cache.h" #include "path/path.h" #include "txti/txti.h" #include "coff/coff.h" @@ -47,6 +46,7 @@ #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" +#include "dasm_cache/dasm_cache.h" #include "fuzzy_search/fuzzy_search.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" @@ -71,7 +71,6 @@ #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" #include "text_cache/text_cache.c" -#include "dasm_cache/dasm_cache.c" #include "path/path.c" #include "txti/txti.c" #include "coff/coff.c" @@ -86,6 +85,7 @@ #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" +#include "dasm_cache/dasm_cache.c" #include "fuzzy_search/fuzzy_search.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" From bc40d1c0b0a97454716860356e9cc94bbbc0e6fc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 11:16:34 -0700 Subject: [PATCH 26/38] rewrite frontend unwind cache to always preserve stale results until a new unwind successfully completes --- src/df/core/df_core.c | 131 ++++++++++++++++++++---------------------- src/df/core/df_core.h | 33 +++++------ src/df/gfx/df_gfx.c | 1 - 3 files changed, 80 insertions(+), 85 deletions(-) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 50c697aa..3ba03165 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3607,14 +3607,14 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) // rjf: early mutation of unwind cache for immediate frontend effect if(result) { - DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; - if(unwind_cache->slots_count != 0) + DF_UnwindCache *cache = &df_state->unwind_cache; + if(cache->slots_count != 0) { DF_Handle thread_handle = df_handle_from_entity(thread); U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % unwind_cache->slots_count; - DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx]; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + U64 slot_idx = hash%cache->slots_count; + DF_UnwindCacheSlot *slot = &cache->slots[slot_idx]; + for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next) { if(df_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0) { @@ -6139,57 +6139,52 @@ df_query_cached_unwind_from_thread(DF_Entity *thread) { Temp scratch = scratch_begin(0, 0); CTRL_Unwind result = {0}; + if(thread->kind == DF_EntityKind_Thread) { + U64 reg_gen = ctrl_reg_gen(); + U64 mem_gen = ctrl_mem_gen(); + DF_UnwindCache *cache = &df_state->unwind_cache; DF_Handle handle = df_handle_from_entity(thread); U64 hash = df_hash_from_string(str8_struct(&handle)); - for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) + U64 slot_idx = hash%cache->slots_count; + DF_UnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_UnwindCacheNode *node = 0; + for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next) { - //- rjf: grab next recent cache - DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; - if(cache_idx == 0 && cache->slots_count == 0) + if(df_handle_match(handle, n->thread)) { - cache->slots_count = 1024; - cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); - } - else if(cache->slots_count == 0) - { - break; - } - - //- rjf: thread/hash -> node - U64 slot_idx = hash%cache->slots_count; - DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; - DF_RunUnwindCacheNode *node = 0; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) - { - if(df_handle_match(n->thread, handle)) - { - node = n; - break; - } - } - - //- rjf: no node? -> calculate unwind if needed - store if good & return - if(node == 0) - { - CTRL_Unwind current_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+200); - if(!(current_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) - { - Architecture arch = df_architecture_from_entity(thread); - node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->thread = handle; - node->unwind = ctrl_unwind_deep_copy(cache->arena, arch, ¤t_unwind); - } - } - - //- rjf: cached node -> grab result & return - if(node != 0) - { - result = node->unwind; + node = n; break; } } + if(node == 0) + { + node = cache->free_node; + if(node != 0) + { + SLLStackPop(cache->free_node); + } + else + { + node = push_array_no_zero(df_state->arena, DF_UnwindCacheNode, 1); + } + DLLPushBack(slot->first, slot->last, node); + MemoryZeroStruct(node); + node->arena = arena_alloc(); + node->thread = handle; + } + if(node->reggen != reg_gen || + node->memgen != mem_gen) + { + CTRL_Unwind new_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+100); + if(!(new_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) + { + node->unwind = ctrl_unwind_deep_copy(node->arena, thread->arch, &new_unwind); + node->reggen = reg_gen; + node->memgen = mem_gen; + } + } + result = node->unwind; } scratch_end(scratch); return result; @@ -6498,11 +6493,9 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) df_register_core_view_rule_specs(array); } - // rjf: set up per-run caches - for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1) - { - df_state->unwind_caches[idx].arena = arena_alloc(); - } + // rjf: set up caches + df_state->unwind_cache.slots_count = 1024; + df_state->unwind_cache.slots = push_array(arena, DF_UnwindCacheSlot, df_state->unwind_cache.slots_count); for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1) { df_state->tls_base_caches[idx].arena = arena_alloc(); @@ -6661,7 +6654,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } // rjf: select & snap to thread causing stop - if(!df_entity_is_nil(stop_thread)) + if(stop_thread->kind == DF_EntityKind_Thread) { DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(stop_thread); @@ -6987,20 +6980,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } } - //- rjf: clear unwind cache - if((df_state->unwind_cache_memgen_idx != new_mem_gen || - df_state->unwind_cache_reggen_idx != new_reg_gen) && - !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") - { - df_state->unwind_cache_gen += 1; - DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; - arena_clear(cache->arena); - cache->slots_count = 0; - cache->slots = 0; - df_state->unwind_cache_memgen_idx = new_mem_gen; - df_state->unwind_cache_reggen_idx = new_reg_gen; - } - //- rjf: clear tls base cache if((df_state->tls_base_cache_reggen_idx != new_reg_gen || df_state->tls_base_cache_memgen_idx != new_mem_gen) && @@ -8784,6 +8763,22 @@ df_core_end_frame(void) } } + //- rjf: garbage collect eliminated thread unwinds + for(U64 slot_idx = 0; slot_idx < df_state->unwind_cache.slots_count; slot_idx += 1) + { + DF_UnwindCacheSlot *slot = &df_state->unwind_cache.slots[slot_idx]; + for(DF_UnwindCacheNode *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(df_entity_is_nil(df_entity_from_handle(n->thread))) + { + DLLRemove(slot->first, slot->last, n); + arena_release(n->arena); + SLLStackPush(df_state->unwind_cache.free_node, n); + } + } + } + //- rjf: write config changes ProfScope("write config changes") { diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 24fceb96..406e6795 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -946,29 +946,33 @@ struct DF_AutoViewRuleMapCache DF_AutoViewRuleSlot *slots; }; -//- rjf: per-run unwind cache +//- rjf: per-thread unwind cache -typedef struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode; -struct DF_RunUnwindCacheNode +typedef struct DF_UnwindCacheNode DF_UnwindCacheNode; +struct DF_UnwindCacheNode { - DF_RunUnwindCacheNode *hash_next; + DF_UnwindCacheNode *next; + DF_UnwindCacheNode *prev; + U64 reggen; + U64 memgen; + Arena *arena; DF_Handle thread; CTRL_Unwind unwind; }; -typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot; -struct DF_RunUnwindCacheSlot +typedef struct DF_UnwindCacheSlot DF_UnwindCacheSlot; +struct DF_UnwindCacheSlot { - DF_RunUnwindCacheNode *first; - DF_RunUnwindCacheNode *last; + DF_UnwindCacheNode *first; + DF_UnwindCacheNode *last; }; -typedef struct DF_RunUnwindCache DF_RunUnwindCache; -struct DF_RunUnwindCache +typedef struct DF_UnwindCache DF_UnwindCache; +struct DF_UnwindCache { - Arena *arena; U64 slots_count; - DF_RunUnwindCacheSlot *slots; + DF_UnwindCacheSlot *slots; + DF_UnwindCacheNode *free_node; }; //- rjf: per-run tls-base-vaddr cache @@ -1146,10 +1150,7 @@ struct DF_State DF_AutoViewRuleMapCache auto_view_rule_cache; // rjf: per-run caches - U64 unwind_cache_reggen_idx; - U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_caches[2]; - U64 unwind_cache_gen; + DF_UnwindCache unwind_cache; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; DF_RunTLSBaseCache tls_base_caches[2]; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index da8cb55f..8a0a9511 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -3494,7 +3494,6 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) avg_ui_hash_chain_length = chain_length_sum / chain_count; } ui_labelf("Target Hz: %.2f", 1.f/df_dt()); - ui_labelf("Unwind Cache Gen: %I64u", df_state->unwind_cache_gen); ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen()); ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen()); ui_labelf("Window %p", window); From 905d04ab0b04f3de312d3d11bc951dc8cd907b25 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 11:34:23 -0700 Subject: [PATCH 27/38] adjust disasm window limits; too often hitting non-read-only memory --- src/dasm_cache/dasm_cache.c | 11 +++++++++-- src/df/gfx/df_views.c | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 89b90885..ffbea99b 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -24,8 +24,7 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - str8_match(a->dbgi_key.path, b->dbgi_key.path, 0) && - a->dbgi_key.min_timestamp == b->dbgi_key.min_timestamp); + di_key_match(&a->dbgi_key, &b->dbgi_key)); return result; } @@ -237,6 +236,14 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } if(node == 0) { + log_infof("[dasm] cache miss, creating node...\n"); + log_infof(" hash: [0x%I64x 0x%I64x]\n", hash.u64[0], hash.u64[1]); + log_infof(" vaddr: 0x%I64x\n", params->vaddr); + log_infof(" arch: %S\n", string_from_architecture(params->arch)); + log_infof(" style_flags: 0x%x\n", params->style_flags); + log_infof(" syntax: %i\n", params->syntax); + log_infof(" base_vaddr: 0x%I64x\n", params->base_vaddr); + log_infof(" dbgi_key: [%S 0x%I64x]\n", params->dbgi_key.path, params->dbgi_key.min_timestamp); node = stripe->free_node; if(node) { diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index d311ef3c..18d6e932 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -6820,10 +6820,10 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // DF_Entity *process = df_entity_from_handle(dv->process); Architecture arch = df_architecture_from_entity(process); - U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); + U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(16)); DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); DI_Key dasm_dbgi_key = df_dbgi_key_from_module(dasm_module); - Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); + Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(16)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; DASM_Params dasm_params = {0}; From 68a980235723629750dcb4a9f7ccd0c6be6e18d4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 11:36:51 -0700 Subject: [PATCH 28/38] re-implement keyboard-driven path for opening dedicated view rule tabs --- src/df/gfx/df_views.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 18d6e932..4483019d 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -1096,6 +1096,25 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS B32 is_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, !is_expanded); } + if(row->flags & DF_EvalVizRowFlag_Canvas) + { + DF_CfgNode *cfg = df_cfg_tree_copy(scratch.arena, row->expand_ui_rule_node); + DF_CfgNode *cfg_root = push_array(scratch.arena, DF_CfgNode, 1); + cfg_root->first = cfg_root->last = cfg; + cfg_root->next = cfg_root->parent = &df_g_nil_cfg_node; + if(cfg != &df_g_nil_cfg_node) + { + cfg->parent = cfg_root; + } + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.string = row->edit_expr; + p.view_spec = df_tab_view_spec_from_gfx_view_rule_spec(row->expand_ui_rule_spec); + p.cfg_node = cfg_root; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_ViewSpec); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CfgNode); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenTab)); + } } } From e850f6fc935ba0d76ea866845d1a202576f0db32 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 12:39:14 -0700 Subject: [PATCH 29/38] c++ module extensions --- src/raddbg/raddbg.h | 7 +++---- src/text_cache/text_cache.c | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 73d12983..0a870216 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -37,13 +37,9 @@ //////////////////////////////// //~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy) // -// [ ] robustify dbgi layer to renames (cache should not be based only on -// path - must invalidate naturally when new filetime occurs) -// // [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly // [ ] PDB files distributed with the build are not found by DbgHelp!!! // [ ] Jai compiler debugging crash -// [ ] raddbgi file regeneration too strict // // [ ] Jump table thunks, on code w/o /INCREMENTAL:NO // @@ -377,6 +373,9 @@ // [x] TLS eval -> in-process-memory EXE info // [x] unwinding -> in-process-memory EXE info // [x] new fuzzy searching layer +// [x] robustify dbgi layer to renames (cache should not be based only on +// path - must invalidate naturally when new filetime occurs) +// [x] raddbgi file regeneration too strict #ifndef RADDBG_H #define RADDBG_H diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 18e21dc5..11924354 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -17,6 +17,12 @@ txt_lang_kind_from_extension(String8 extension) str8_match(extension, str8_lit("cxx"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("cc"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("c++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("ixx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cxxm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("c++m"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("ccm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cppm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("mpp"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("C"), 0) || str8_match(extension, str8_lit("hpp"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("hxx"), StringMatchFlag_CaseInsensitive) || From f431ac7f80a042dfc611c30e5e50e52803f6e44f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 14:34:01 -0700 Subject: [PATCH 30/38] rewrite ipc communication; do ipc message reception on separate thread, wake up main thread; fix various robustness issues. do not necessarily initialize slower-to-initialize layers in conversion/ipc instances --- src/base/base_entry_point.c | 41 +++-- src/df/core/df_core.c | 1 + src/df/core/df_core.mdesk | 2 +- src/df/core/generated/df_core.meta.c | 2 +- src/df/gfx/df_gfx.c | 3 +- src/df/gfx/df_gfx.h | 1 + src/os/core/linux/os_core_linux.c | 2 +- src/raddbg/raddbg.c | 2 +- src/raddbg/raddbg.h | 17 +- src/raddbg/raddbg_main.cpp | 244 ++++++++++++++++++++------- 10 files changed, 225 insertions(+), 90 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 7aa20d7f..3c4b9926 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -18,65 +18,62 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum { ProfBeginCapture(arguments[0]); } -#if defined(OS_CORE_H) +#if defined(OS_CORE_H) && !defined(OS_INIT_MANUAL) os_init(); #endif -#if defined(TASK_SYSTEM_H) +#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL) ts_init(); #endif -#if defined(HASH_STORE_H) +#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) hs_init(); #endif -#if defined(FILE_STREAM_H) +#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) fs_init(); #endif -#if defined(TEXT_CACHE_H) +#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL) txt_init(); #endif -#if defined(DASM_CACHE_H) +#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) dasm_init(); #endif -#if defined(DBGI_H) - dbgi_init(); -#endif -#if defined(DI_H) +#if defined(DI_H) && !defined(DI_INIT_MANUAL) di_init(); #endif -#if defined(FUZZY_SEARCH_H) +#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL) fzy_init(); #endif -#if defined(TXTI_H) +#if defined(TXTI_H) && !defined(TXTI_INIT_MANUAL) txti_init(); #endif -#if defined(DEMON_CORE_H) +#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); #endif -#if defined(CTRL_CORE_H) +#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) ctrl_init(); #endif -#if defined(OS_GRAPHICAL_H) +#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL) os_graphical_init(); #endif -#if defined(FONT_PROVIDER_H) +#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) fp_init(); #endif -#if defined(RENDER_CORE_H) +#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) r_init(&cmdline); #endif -#if defined(TEXTURE_CACHE_H) +#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL) tex_init(); #endif -#if defined(GEO_CACHE_H) +#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) geo_init(); #endif -#if defined(FONT_CACHE_H) +#if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL) f_init(); #endif -#if defined(DF_CORE_H) +#if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL) DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); df_core_init(&cmdline, hist); #endif -#if defined(DF_GFX_H) +#if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL) df_gfx_init(update_and_render, df_state_delta_history()); #endif entry_point(&cmdline); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 3ba03165..e2980b29 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6379,6 +6379,7 @@ internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec) { // rjf: log + if(params->os_event == 0 || params->os_event->kind != OS_EventKind_MouseMove) { Temp scratch = scratch_begin(0, 0); DF_Entity *entity = df_entity_from_handle(params->entity); diff --git a/src/df/core/df_core.mdesk b/src/df/core/df_core.mdesk index e1a15028..c879873c 100644 --- a/src/df/core/df_core.mdesk +++ b/src/df/core/df_core.mdesk @@ -333,7 +333,7 @@ DF_CoreCmdTable:// | | | {DuplicateEntity 1 Null Nil 0 0 0 0 0 0 Null "duplicate_entity" "Duplicate Entity" "Duplicates an entity." "" } //- rjf: breakpoints - {TextBreakpoint 1 Null Nil 0 0 0 0 0 0 CircleFilled "text_breakpoint" "Text Breakpoint" "Places or removes a breakpoint on the specified line of source code." "" } + {TextBreakpoint 1 FilePath Nil 0 0 0 0 0 0 CircleFilled "text_breakpoint" "Text Breakpoint" "Places or removes a breakpoint on the specified line of source code." "" } {AddressBreakpoint 0 VirtualAddr Nil 0 0 0 0 1 1 CircleFilled "address_breakpoint" "Address Breakpoint" "Places or removes a breakpoint on the specified address." "" } {FunctionBreakpoint 0 String Nil 0 0 0 0 1 1 CircleFilled "function_breakpoint" "Function Breakpoint" "Places or removes a breakpoint on the first address(es) of the specified function." "" } {ToggleBreakpointAtCursor 0 Null Nil 0 0 0 0 0 0 CircleFilled "toggle_breakpoint_cursor" "Toggle Breakpoint At Cursor" "Places or removes a breakpoint on the line on which the active cursor sits." "" } diff --git a/src/df/core/generated/df_core.meta.c b/src/df/core/generated/df_core.meta.c index b6edc57a..c2c5f704 100644 --- a/src/df/core/generated/df_core.meta.c +++ b/src/df/core/generated/df_core.meta.c @@ -374,7 +374,7 @@ DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[220] = { str8_lit_comp("name_entity"), str8_lit_comp("Equips an entity with a name."), str8_lit_comp(""), str8_lit_comp("Name Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, { str8_lit_comp("edit_entity"), str8_lit_comp("Opens the editor for an entity."), str8_lit_comp(""), str8_lit_comp("Edit Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, { str8_lit_comp("duplicate_entity"), str8_lit_comp("Duplicates an entity."), str8_lit_comp(""), str8_lit_comp("Duplicate Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, -{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, +{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, { str8_lit_comp("address_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("Address Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled}, { str8_lit_comp("function_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("Function Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled}, { str8_lit_comp("toggle_breakpoint_cursor"), str8_lit_comp("Places or removes a breakpoint on the line on which the active cursor sits."), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 8a0a9511..ee64236b 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -1039,7 +1039,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) ////////////////////////////// //- rjf: unpack context // - B32 window_is_focused = os_window_is_focused(ws->os); + B32 window_is_focused = os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc; B32 confirm_open = df_gfx_state->confirm_active; B32 query_is_open = !df_view_is_nil(ws->query_view_stack_top); B32 hover_eval_is_open = (!confirm_open && @@ -1050,6 +1050,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { ws->menu_bar_key_held = 0; } + ws->window_temporarily_focused_ipc = 0; ui_select_state(ws->ui); ////////////////////////////// diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 59a7c679..60e0f83f 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -513,6 +513,7 @@ struct DF_Window UI_State *ui; F32 code_font_size_delta; F32 main_font_size_delta; + B32 window_temporarily_focused_ipc; // rjf: view state delta history DF_StateDeltaHistory *view_state_hist; diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index f8b07e81..8a6db843 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1607,7 +1607,7 @@ os_semaphore_close(OS_Handle semaphore) } internal B32 -os_semaphore_take(OS_Handle semaphore) +os_semaphore_take(OS_Handle semaphore, U64 endt_us) { NotImplemented; return 0; diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index c0af86cc..2b636d6a 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -393,7 +393,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) ProfEnd(); } -internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook) +internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl) { os_send_wakeup_event(); } diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 0a870216..c571a6b4 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -401,12 +401,23 @@ struct IPCInfo //////////////////////////////// //~ rjf: Globals -#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(16) +//- rjf: IPC resources +#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4) StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement); -read_only global String8 ipc_shared_memory_name = str8_lit_comp("_raddbg_ipc_shared_memory_"); -read_only global String8 ipc_semaphore_name = str8_lit_comp("_raddbg_ipc_semaphore_"); +global OS_Handle ipc_signal_semaphore = {0}; +global OS_Handle ipc_lock_semaphore = {0}; +global U8 *ipc_shared_memory_base = 0; +global U8 ipc_s2m_ring_buffer[MB(4)] = {0}; +global U64 ipc_s2m_ring_write_pos = 0; +global U64 ipc_s2m_ring_read_pos = 0; +global OS_Handle ipc_s2m_ring_mutex = {0}; +global OS_Handle ipc_s2m_ring_cv = {0}; + +//- rjf: frame time history global U64 frame_time_us_history[64] = {0}; global U64 frame_time_us_history_idx = 0; + +//- rjf: main thread log global Log *main_thread_log = 0; global String8 main_thread_log_path = {0}; diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index f259abee..280435af 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -11,6 +11,13 @@ #define BUILD_TITLE "The RAD Debugger" #define OS_FEATURE_GRAPHICAL 1 +#define R_INIT_MANUAL 1 +#define TEX_INIT_MANUAL 1 +#define GEO_INIT_MANUAL 1 +#define F_INIT_MANUAL 1 +#define DF_INIT_MANUAL 1 +#define DF_GFX_INIT_MANUAL 1 + //////////////////////////////// //~ rjf: Includes @@ -100,6 +107,42 @@ #include "df/df_inc.c" #include "raddbg.c" +//////////////////////////////// +//~ rjf: IPC Signaler Thread + +internal void +ipc_signaler_thread__entry_point(void *p) +{ + for(;;) + { + if(os_semaphore_take(ipc_signal_semaphore, max_U64)) + { + if(os_semaphore_take(ipc_lock_semaphore, max_U64)) + { + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + String8 msg = str8((U8 *)(ipc_info+1), ipc_info->msg_size); + msg.size = Min(msg.size, IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo)); + OS_MutexScope(ipc_s2m_ring_mutex) for(;;) + { + U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; + U64 available_size = (sizeof(ipc_s2m_ring_buffer) - unconsumed_size); + if(available_size >= sizeof(U64)+sizeof(msg.size)) + { + ipc_s2m_ring_write_pos += ring_write_struct(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_write_pos, &msg.size); + ipc_s2m_ring_write_pos += ring_write(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_write_pos, msg.str, msg.size); + break; + } + os_condition_variable_wait(ipc_s2m_ring_cv, ipc_s2m_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ipc_s2m_ring_cv); + os_send_wakeup_event(); + ipc_info->msg_size = 0; + os_semaphore_drop(ipc_lock_semaphore); + } + } + } +} + //////////////////////////////// //~ rjf: Entry Point @@ -178,7 +221,7 @@ entry_point(CmdLine *cmd_line) } //- rjf: set up layers - ctrl_set_wakeup_hook(wakeup_hook); + ctrl_set_wakeup_hook(wakeup_hook_ctrl); //- rjf: dispatch to top-level codepath based on execution mode switch(exec_mode) @@ -187,12 +230,16 @@ entry_point(CmdLine *cmd_line) default: case ExecMode_Normal: { - //- rjf: set up shared memory for ipc - OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); - OS_Handle ipc_semaphore = os_semaphore_alloc(1, 1, ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - ipc_info->msg_size = 0; + //- rjf: manual layer initialization + { + r_init(cmd_line); + tex_init(); + geo_init(); + f_init(); + DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); + df_core_init(cmd_line, hist); + df_gfx_init(update_and_render, df_state_delta_history()); + } //- rjf: setup initial target from command line args { @@ -247,56 +294,97 @@ entry_point(CmdLine *cmd_line) } } + //- rjf: set up shared resources for ipc to this instance; launch IPC signaler thread + { + Temp scratch = scratch_begin(0, 0); + U32 instance_pid = os_get_pid(); + String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", instance_pid); + String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", instance_pid); + String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", instance_pid); + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name); + ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name); + ipc_s2m_ring_mutex = os_mutex_alloc(); + ipc_s2m_ring_cv = os_condition_variable_alloc(); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + MemoryZeroStruct(ipc_info); + os_launch_thread(ipc_signaler_thread__entry_point, 0, 0); + scratch_end(scratch); + } + //- rjf: main application loop { for(;;) { - //- rjf: get IPC messages & dispatch ui commands from them + //- rjf: consume IPC messages, dispatch UI commands { - if(os_semaphore_take(ipc_semaphore, max_U64)) + Temp scratch = scratch_begin(0, 0); + B32 consumed = 0; + String8 msg = {0}; + OS_MutexScope(ipc_s2m_ring_mutex) { - if(ipc_info->msg_size != 0) + U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; + if(unconsumed_size >= sizeof(U64)) { - U8 *buffer = (U8 *)(ipc_info+1); - U64 msg_size = ipc_info->msg_size; - String8 cmd_string = str8(buffer, msg_size); - ipc_info->msg_size = 0; - DF_Window *dst_window = df_gfx_state->first_window; - for(DF_Window *window = dst_window; window != 0; window = window->next) + consumed = 1; + ipc_s2m_ring_read_pos += ring_read_struct(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_read_pos, &msg.size); + msg.size = Min(msg.size, unconsumed_size); + msg.str = push_array(scratch.arena, U8, msg.size); + ipc_s2m_ring_read_pos += ring_read(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_read_pos, msg.str, msg.size); + } + } + if(consumed) + { + os_condition_variable_broadcast(ipc_s2m_ring_cv); + } + if(msg.size != 0) + { + log_infof("IPC message received: \"%S\"", msg); + DF_Window *dst_window = df_gfx_state->first_window; + for(DF_Window *window = dst_window; window != 0; window = window->next) + { + if(os_window_is_focused(window->os)) { - if(os_window_is_focused(window->os)) - { - dst_window = window; - break; - } - } - if(dst_window != 0) - { - Temp scratch = scratch_begin(0, 0); - String8 cmd_spec_string = df_cmd_name_part_from_string(cmd_string); - DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); - if(!df_cmd_spec_is_nil(cmd_spec)) - { - DF_CmdParams params = df_cmd_params_from_gfx(); - DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); - String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(cmd_string)); - if(error.size == 0) - { - df_push_cmd__root(¶ms, cmd_spec); - } - else - { - DF_CmdParams params = df_cmd_params_from_window(dst_window); - params.string = error; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); - } - } - scratch_end(scratch); + dst_window = window; + break; + } + } + if(dst_window != 0) + { + dst_window->window_temporarily_focused_ipc = 1; + String8 cmd_spec_string = df_cmd_name_part_from_string(msg); + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); + if(!df_cmd_spec_is_nil(cmd_spec)) + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); + String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(msg)); + if(error.size == 0) + { + df_push_cmd__root(¶ms, cmd_spec); + df_gfx_request_frame(); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = error; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + df_gfx_request_frame(); + } + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = push_str8f(scratch.arena, "\"%S\" is not a command.", cmd_spec_string); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + df_gfx_request_frame(); } } - os_semaphore_drop(ipc_semaphore); } + scratch_end(scratch); } //- rjf: update & render frame @@ -344,25 +432,61 @@ entry_point(CmdLine *cmd_line) { Temp scratch = scratch_begin(0, 0); - //- rjf: grab ipc shared memory - OS_Handle ipc_shared_memory = os_shared_memory_open(ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, MB(16))); - if(ipc_shared_memory_base != 0) + //- rjf: grab explicit PID argument + U32 dst_pid = 0; + if(cmd_line_has_argument(cmd_line, str8_lit("pid"))) { - OS_Handle ipc_semaphore = os_semaphore_open(ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - if(os_semaphore_take(ipc_semaphore, os_now_microseconds() + Million(6))) + String8 dst_pid_string = cmd_line_string(cmd_line, str8_lit("pid")); + U64 dst_pid_u64 = 0; + if(dst_pid_string.size != 0 && + try_u64_from_str8_c_rules(dst_pid_string, &dst_pid_u64)) { - U8 *buffer = (U8 *)(ipc_info+1); - U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join); - ipc_info->msg_size = Min(buffer_max, msg.size); - MemoryCopy(buffer, msg.str, ipc_info->msg_size); - os_semaphore_drop(ipc_semaphore); + dst_pid = (U32)dst_pid_u64; } } + //- rjf: no explicit PID? -> find PID to send message to, by looking for other raddbg instances + if(dst_pid == 0) + { + U32 this_pid = os_get_pid(); + DMN_ProcessIter it = {0}; + dmn_process_iter_begin(&it); + for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &it, &info);) + { + if(str8_match(str8_skip_last_slash(str8_chop_last_dot(cmd_line->exe_name)), str8_skip_last_slash(str8_chop_last_dot(info.name)), StringMatchFlag_CaseInsensitive) && + this_pid != info.pid) + { + dst_pid = info.pid; + break; + } + } + dmn_process_iter_end(&it); + } + + //- rjf: grab destination instance's shared memory resources + String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", dst_pid); + String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", dst_pid); + String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", dst_pid); + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name); + ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name); + + //- rjf: got resources -> write message + if(ipc_shared_memory_base != 0 && + os_semaphore_take(ipc_lock_semaphore, max_U64)) + { + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + U8 *buffer = (U8 *)(ipc_info+1); + U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join); + ipc_info->msg_size = Min(buffer_max, msg.size); + MemoryCopy(buffer, msg.str, ipc_info->msg_size); + os_semaphore_drop(ipc_signal_semaphore); + os_semaphore_drop(ipc_lock_semaphore); + } + scratch_end(scratch); }break; From ece414c575d6e2b9eb0cbdf21ec30390ed29f5ba Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 14:40:23 -0700 Subject: [PATCH 31/38] prioritize title-bar-client-areas over built-in window borders; expand top bar rect a bit to ensure edge of window coverage --- src/df/gfx/df_gfx.c | 4 ++-- src/os/gfx/win32/os_gfx_win32.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index ee64236b..ad18002a 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -3308,7 +3308,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // Rng2F32 window_rect = os_client_rect_from_window(ws->os); Vec2F32 window_rect_dim = dim_2f32(window_rect); - Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x, window_rect.y0+ui_top_pref_height().value); + Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x+1, window_rect.y0+ui_top_pref_height().value); Rng2F32 bottom_bar_rect = r2f32p(window_rect.x0, window_rect_dim.y - ui_top_pref_height().value, window_rect.x0+window_rect_dim.x, window_rect.y0+window_rect_dim.y); Rng2F32 content_rect = r2f32p(window_rect.x0, top_bar_rect.y1, window_rect.x0+window_rect_dim.x, bottom_bar_rect.y0); F32 window_edge_px = os_dpi_from_window(ws->os)*0.035f; @@ -5302,7 +5302,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) } os_window_push_custom_title_bar_client_area(ws->os, min_sig.box->rect); os_window_push_custom_title_bar_client_area(ws->os, max_sig.box->rect); - os_window_push_custom_title_bar_client_area(ws->os, cls_sig.box->rect); + os_window_push_custom_title_bar_client_area(ws->os, pad_2f32(cls_sig.box->rect, 2.f)); } } } diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index e94e07df..f10e93ac 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -771,12 +771,6 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) result = HTCAPTION; } - // rjf: title bar client area - if(is_over_title_bar_client_area) - { - result = HTCLIENT; - } - // rjf: normal edges if(is_over_left) { result = HTLEFT; } if(is_over_right) { result = HTRIGHT; } @@ -788,6 +782,12 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if(is_over_left && is_over_bottom) { result = HTBOTTOMLEFT; } if(is_over_right && is_over_top) { result = HTTOPRIGHT; } if(is_over_right && is_over_bottom) { result = HTBOTTOMRIGHT; } + + // rjf: title bar client area + if(is_over_title_bar_client_area) + { + result = HTCLIENT; + } } } }break; From fdfee3722846b6575be00d1a0c118fcd0e2854f2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 14:45:32 -0700 Subject: [PATCH 32/38] oops - only d3d11 flush on resize --- src/render/d3d11/render_d3d11.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/render/d3d11/render_d3d11.cpp b/src/render/d3d11/render_d3d11.cpp index a8346387..eef97d94 100644 --- a/src/render/d3d11/render_d3d11.cpp +++ b/src/render/d3d11/render_d3d11.cpp @@ -841,9 +841,11 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) Vec2S32 resolution = {(S32)(client_rect.x1 - client_rect.x0), (S32)(client_rect.y1 - client_rect.y0)}; //- rjf: resolution change + B32 resize_done = 0; if(wnd->last_resolution.x != resolution.x || wnd->last_resolution.y != resolution.y) { + resize_done = 1; wnd->last_resolution = resolution; // rjf: release screen-sized render target resources, if there @@ -946,7 +948,10 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) Vec4F32 clear_color = {0, 0, 0, 0}; d_ctx->ClearRenderTargetView(wnd->framebuffer_rtv, clear_color.v); d_ctx->ClearRenderTargetView(wnd->stage_color_rtv, clear_color.v); - d_ctx->Flush(); + if(resize_done) + { + d_ctx->Flush(); + } } ProfEnd(); } From dc5dda3f718fb49cf6783ef2aef8069f45b015e0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 14:47:42 -0700 Subject: [PATCH 33/38] visualize handle basic types --- src/df/core/df_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index e2980b29..ad1de92e 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -4493,6 +4493,12 @@ df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, { default:{}break; + case TG_Kind_Handle: + { + U64 min_digits = (radix == 16) ? type_byte_size*2 : 0; + result = str8_from_s64(arena, eval.imm_s64, radix, 0, digit_group_separator); + }break; + case TG_Kind_Char8: case TG_Kind_Char16: case TG_Kind_Char32: From 35c599dea35b403b93e07347e11d88f4dc8d5f80 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 15:09:53 -0700 Subject: [PATCH 34/38] raddbgi -> rdi --- README.md | 89 +++++++------------ build.bat | 10 +-- project.4coder | 12 +-- .../rdi_format.c} | 0 .../rdi_format.h} | 8 +- .../rdi_format_parse.c} | 0 .../rdi_format_parse.h} | 0 .../rdi_make.c} | 0 .../rdi_make.h} | 12 +-- src/raddbg/raddbg.h | 2 +- src/raddbg/raddbg_main.cpp | 20 ++--- .../rdi_breakpad_from_pdb_main.c} | 20 ++--- .../raddbgi_dump.c => rdi_dump/rdi_dump.c} | 4 +- .../raddbgi_dump.h => rdi_dump/rdi_dump.h} | 12 +-- .../rdi_dump_main.c} | 20 ++--- .../rdi_dwarf.c} | 0 .../rdi_dwarf.h} | 6 +- .../rdi_dwarf_stringize.c} | 0 .../rdi_dwarf_stringize.h} | 6 +- .../rdi_elf.c} | 0 .../rdi_elf.h} | 6 +- .../rdi_from_dwarf.c} | 22 ++--- .../rdi_from_dwarf.h} | 6 +- .../rdi_from_pdb.c} | 8 +- .../rdi_from_pdb.h} | 10 +-- .../rdi_from_pdb_main.c} | 16 ++-- .../rdi_make_local.c} | 2 +- .../rdi_make_local.h} | 2 +- .../generated/regs_rdi.meta.c} | 0 .../generated/regs_rdi.meta.h} | 6 +- .../regs_raddbgi.c => rdi/regs_rdi.c} | 2 +- .../regs_raddbgi.h => rdi/regs_rdi.h} | 6 +- .../regs_raddbgi.mdesk => rdi/regs_rdi.mdesk} | 0 src/scratch/ryan_scratch.c | 20 ++--- 34 files changed, 153 insertions(+), 174 deletions(-) rename src/{lib_raddbgi_format/raddbgi_format.c => lib_rdi_format/rdi_format.c} (100%) rename src/{lib_raddbgi_format/raddbgi_format.h => lib_rdi_format/rdi_format.h} (99%) rename src/{lib_raddbgi_format/raddbgi_format_parse.c => lib_rdi_format/rdi_format_parse.c} (100%) rename src/{lib_raddbgi_format/raddbgi_format_parse.h => lib_rdi_format/rdi_format_parse.h} (100%) rename src/{lib_raddbgi_make/raddbgi_make.c => lib_rdi_make/rdi_make.c} (100%) rename src/{lib_raddbgi_make/raddbgi_make.h => lib_rdi_make/rdi_make.h} (99%) rename src/{raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c => rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c} (95%) rename src/{raddbgi_dump/raddbgi_dump.c => rdi_dump/rdi_dump.c} (99%) rename src/{raddbgi_dump/raddbgi_dump.h => rdi_dump/rdi_dump.h} (94%) rename src/{raddbgi_dump/raddbgi_dump_main.c => rdi_dump/rdi_dump_main.c} (96%) rename src/{raddbgi_from_dwarf/raddbgi_dwarf.c => rdi_from_dwarf/rdi_dwarf.c} (100%) rename src/{raddbgi_from_dwarf/raddbgi_dwarf.h => rdi_from_dwarf/rdi_dwarf.h} (99%) rename src/{raddbgi_from_dwarf/raddbgi_dwarf_stringize.c => rdi_from_dwarf/rdi_dwarf_stringize.c} (100%) rename src/{raddbgi_from_dwarf/raddbgi_dwarf_stringize.h => rdi_from_dwarf/rdi_dwarf_stringize.h} (87%) rename src/{raddbgi_from_dwarf/raddbgi_elf.c => rdi_from_dwarf/rdi_elf.c} (100%) rename src/{raddbgi_from_dwarf/raddbgi_elf.h => rdi_from_dwarf/rdi_elf.h} (99%) rename src/{raddbgi_from_dwarf/raddbgi_from_dwarf.c => rdi_from_dwarf/rdi_from_dwarf.c} (98%) rename src/{raddbgi_from_dwarf/raddbgi_from_dwarf.h => rdi_from_dwarf/rdi_from_dwarf.h} (91%) rename src/{raddbgi_from_pdb/raddbgi_from_pdb.c => rdi_from_pdb/rdi_from_pdb.c} (99%) rename src/{raddbgi_from_pdb/raddbgi_from_pdb.h => rdi_from_pdb/rdi_from_pdb.h} (98%) rename src/{raddbgi_from_pdb/raddbgi_from_pdb_main.c => rdi_from_pdb/rdi_from_pdb_main.c} (91%) rename src/{raddbgi_make_local/raddbgi_make_local.c => rdi_make_local/rdi_make_local.c} (72%) rename src/{raddbgi_make_local/raddbgi_make_local.h => rdi_make_local/rdi_make_local.h} (97%) rename src/regs/{raddbgi/generated/regs_raddbgi.meta.c => rdi/generated/regs_rdi.meta.c} (100%) rename src/regs/{raddbgi/generated/regs_raddbgi.meta.h => rdi/generated/regs_rdi.meta.h} (65%) rename src/regs/{raddbgi/regs_raddbgi.c => rdi/regs_rdi.c} (67%) rename src/regs/{raddbgi/regs_raddbgi.h => rdi/regs_rdi.h} (81%) rename src/regs/{raddbgi/regs_raddbgi.mdesk => rdi/regs_rdi.mdesk} (100%) diff --git a/README.md b/README.md index 13d40cec..0dfe8775 100644 --- a/README.md +++ b/README.md @@ -20,26 +20,20 @@ You can download pre-built binaries for the debugger [here](https://github.com/EpicGames/raddebugger/releases). The RAD Debugger project aims to simplify the debugger by simplifying and -unifying the underlying debug info format. In that pursuit we've built -the RADDBGI debug info format, which is what the debugger parses and uses. To -work with existing toolchains, we convert PDB (and eventually PE/ELF files -with embedded DWARF) into the RADDBGI format on-demand. This conversion process -is currently an unoptimized reference version. Nevertheless it's still quite -fast for smaller PDB files (in many cases faster than many other programs -simply deserialize the PDBs). It is much slower for much larger projects at the -moment, but we expect this will vastly improve overtime. +unifying the underlying debug info format. In that pursuit we've built the RAD +Debug Info (RDI) format, which is what the debugger parses and uses. To work +with existing toolchains, we convert PDB (and eventually PE/ELF files with +embedded DWARF) into the RDI format on-demand. -The RADDBGI format is currently specified in code, in the files within the -`src/lib_raddbgi_format` folder. The other relevant folders for working with -the format are: +The RDI format is currently specified in code, in the files within the +`src/lib_rdi_format` folder. The other relevant folders for working with the +format are: -- `lib_raddbgi_make`: The "RAD Debug Info Make" library, for making RADDBGI - debug info. -- `raddbgi_from_pdb`: Our PDB-to-RADDBGI converter. Can be used as a helper - codebase layer, or built as an executable with a command line interface - frontend. -- `raddbgi_from_dwarf`: Our in-progress DWARF-to-RADDBGI converter. -- `raddbgi_dump`: Our RADDBGI textual dumping utility. +- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info. +- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase + layer, or built as an executable with a command line interface frontend. +- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter. +- `rdi_dump`: Our RDI textual dumping utility. ## Development Setup Instructions @@ -126,18 +120,6 @@ there are still cases where the debugger has not been tested, and so there are still issues. So, we feel that the top priority is eliminating these issues, such that the debugging experience is rock solid. -Additionally, the debug info conversion process is not fast (nor wide) enough -to support extremely large projects. This is for two reasons: (a) the -PDB-to-RADDBGI converter is an unoptimized reference implementation, and (b) -the debugger learns of new modules (and thus which PDBs to load) in a -serially-dependent way (this is necessarily the case for correct debugging -results). We expect that the conversion process' performance can be massively -improved, and also that some heuristics can be used to begin converting PDBs -to RADDBGIs before the debugger knows those PDBs are needed, thus ensuring the -associated RADDBGI files are ready instantaneously when the associated modules -are finally loaded by the debugger. Improving this situation is a major part of -this phase, as it will make the debugger much more usable for large projects. - ### Local x64 Linux Debugging Phase The next priority for the project is to take the rock solid x64 Windows @@ -152,11 +134,10 @@ The major parts of this phase are: - Porting the `src/demon` layer to implement the Demon local process control abstraction API. -- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there -is only an x64 PE unwinding implementation). -- Creating a DWARF-to-RADDBGI converter (in the same way that we've built a -PDB-to-RADDBGI converter). A partial implementation of this is in -`src/raddbgi_from_dwarf`. +- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer. +- Creating a DWARF-to-RDI converter (in the same way that we've built a +PDB-to-RDI converter). A partial implementation of this is in +`src/rdi_from_dwarf`. - Porting the `src/render` layer to implement all of the rendering features the frontend needs on a Linux-compatible API (the backend used on Windows is D3D11). - Porting the `src/font_provider` layer to a Linux-compatible font @@ -218,7 +199,7 @@ so in other words, layers are arranged into a directed acyclic graph. A few layers are built to be used completely independently from the rest of the codebase, as libraries in other codebases and projects. As such, these layers do not depend on any other layers in the codebase. The folders which contain these -layers are prefixed with `lib_`, like `lib_raddbgi_format`. +layers are prefixed with `lib_`, like `lib_rdi_format`. A list of the layers in the codebase and their associated namespaces is below: - `base` (no namespace): Universal, codebase-wide constructs. Strings, math, @@ -235,11 +216,11 @@ A list of the layers in the codebase and their associated namespaces is below: - `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for disassembly for a particular virtual address range in a process, and threads implemented in this layer decode and cache the disassembly for that range. -- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug - info stored in the RADDBGI format. Users ask for debug info for a particular - executable, and on separate threads, this layer loads the associated debug - info file. If necessary, it will launch a separate conversion process to - convert original debug info into the RADDBGI format. +- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info + stored in the RDI format. Users ask for debug info for a particular path, and + on separate threads, this layer loads the associated debug info file. If + necessary, it will launch a separate conversion process to convert original + debug info into the RDI format. - `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process control. The abstraction is used to provide a common interface for process control on target platforms. Used to implement part of `ctrl`. @@ -274,13 +255,13 @@ A list of the layers in the codebase and their associated namespaces is below: - `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user programs to work with various features in the `raddbg` debugger. Does not depend on `base`, and can be independently relocated to other codebases. -- `lib_raddbgi_make` (`RDIM_`): Standalone library for constructing RADDBGI - debug info data. Does not depend on `base`, and can be independently relocated +- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info + data. Does not depend on `base`, and can be independently relocated to other codebases. -- `lib_raddbgi_format` (`RDI_`): Standalone library which defines the core - RADDBGI types and helper functions for reading and writing the RADDBGI debug - info file format. Does not depend on `base`, and can be independently - relocated to other codebases. +- `lib_rdi_format` (`RDI_`): Standalone library which defines the core RDI types + and helper functions for reading and writing the RDI debug info file format. + Does not depend on `base`, and can be independently relocated to other + codebases. - `metagen` (`MG_`): A metaprogram which is used to generate primarily code and data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and generates C code which is then included by hand-written C code. Currently, it @@ -315,11 +296,11 @@ A list of the layers in the codebase and their associated namespaces is below: - `raddbg` (no namespace): The layer which ties everything together for the main graphical debugger. Not much "meat", just drives `df`, implements command line options, and so on. -- `raddbgi_from_pdb` (`P2R_`): Our implementation of PDB-to-RADDBGI conversion. -- `raddbgi_from_dwarf` (`D2R_`): Our in-progress implementation of - DWARF-to-RADDBGI conversion. -- `raddbgi_dump` (`RADDBGIDUMP_`): A dumper utility program for dumping - textualizations of RADDBGI debug info files. +- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion. +- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI + conversion. +- `rdi_dump` (no namespace): A dumper utility program for dumping + textualizations of RDI debug info files. - `regs` (`REGS_`): Types, helper functions, and metadata for registers on supported architectures. Used in reading/writing registers in `demon`, or in looking up register metadata. @@ -338,11 +319,9 @@ A list of the layers in the codebase and their associated namespaces is below: Used by the debugger to visualize source code files. Users ask for text lines, tokens, and metadata, and it is prepared on background threads. - `type_graph` (`TG_`): Code for analyzing and navigating type structures from - RADDBGI debug info files, with the additional capability of constructing + RDI debug info files, with the additional capability of constructing synthetic types *not* found in debug info. Used in `eval` and for various visualization features. - `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a core immediate mode hierarchical user interface data structure building API, and has helper layers for building some higher-level widgets. -- `unwind` (`UNW_`): Code for generating unwind information from threads, for - supported operating systems and architectures. diff --git a/build.bat b/build.bat index e23cdf5f..dd11f047 100644 --- a/build.bat +++ b/build.bat @@ -15,7 +15,7 @@ cd /D "%~dp0" :: `build raddbg clang` :: `build raddbg release` :: `build raddbg asan telemetry` -:: `build raddbgi_from_pdb` +:: `build rdi_from_pdb` :: :: For a full list of possible build targets and their build command lines, :: search for @build_targets in this file. @@ -99,10 +99,10 @@ if not "%no_meta%"=="1" ( :: --- Build Everything (@build_targets) -------------------------------------- pushd build if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1 -if "%raddbgi_from_pdb%"=="1" %compile% ..\src\raddbgi_from_pdb\raddbgi_from_pdb_main.c %compile_link% %out%raddbgi_from_pdb.exe || exit /b 1 -if "%raddbgi_from_dwarf%"=="1" %compile% ..\src\raddbgi_from_dwarf\raddbgi_from_dwarf.c %compile_link% %out%raddbgi_from_dwarf.exe || exit /b 1 -if "%raddbgi_dump%"=="1" %compile% ..\src\raddbgi_dump\raddbgi_dump_main.c %compile_link% %out%raddbgi_dump.exe || exit /b 1 -if "%raddbgi_breakpad_from_pdb%"=="1" %compile% ..\src\raddbgi_breakpad_from_pdb\raddbgi_breakpad_from_pdb_main.c %compile_link% %out%raddbgi_breakpad_from_pdb.exe || exit /b 1 +if "%rdi_from_pdb%"=="1" %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1 +if "%rdi_from_dwarf%"=="1" %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 +if "%rdi_dump%"=="1" %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1 +if "%rdi_breakpad_from_pdb%"=="1" %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1 if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 diff --git a/project.4coder b/project.4coder index 157ea4c7..4b6edfe2 100644 --- a/project.4coder +++ b/project.4coder @@ -74,7 +74,7 @@ commands = }, .rjf_f4 = { - .win = "build raddbgi_from_pdb release telemetry && pushd build && raddbgi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.raddbgi --capture && popd", + .win = "build rdi_from_pdb release telemetry && pushd build && rdi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.rdi --capture && popd", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -83,7 +83,7 @@ commands = }, .rjf_f5 = { - .win = "pushd build && raddbgi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.raddbg --capture && popd", + .win = "pushd build && rdi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.rdi --capture && popd", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -108,18 +108,18 @@ commands = .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbgi_from_pdb = + .build_rdi_from_pdb = { - .win = "build raddbgi_from_pdb", + .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbgi_dump = + .build_rdi_dump = { - .win = "build raddbgi_dump", + .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/lib_raddbgi_format/raddbgi_format.c b/src/lib_rdi_format/rdi_format.c similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format.c rename to src/lib_rdi_format/rdi_format.c diff --git a/src/lib_raddbgi_format/raddbgi_format.h b/src/lib_rdi_format/rdi_format.h similarity index 99% rename from src/lib_raddbgi_format/raddbgi_format.h rename to src/lib_rdi_format/rdi_format.h index f0bc7b75..23fd54d0 100644 --- a/src/lib_raddbgi_format/raddbgi_format.h +++ b/src/lib_rdi_format/rdi_format.h @@ -4,11 +4,11 @@ //////////////////////////////////////////////////////////////// // RAD Debug Info, (R)AD(D)BG(I) Format Library // -// Defines standard RADDBGI debug information format types and +// Defines standard RDI debug information format types and // functions. -#ifndef RADDBGI_FORMAT_H -#define RADDBGI_FORMAT_H +#ifndef RDI_FORMAT_H +#define RDI_FORMAT_H //////////////////////////////////////////////////////////////// // Overridable procedure decoration @@ -924,4 +924,4 @@ RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_rule(RDI_EvalTypeGroup in, R RDI_PROC RDI_U8* rdi_eval_conversion_message(RDI_EvalConversionKind conversion_kind, RDI_U64 *lennout); RDI_PROC RDI_S32 rdi_eval_opcode_type_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); -#endif // RADDBGI_FORMAT_H +#endif // RDI_FORMAT_H diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.c b/src/lib_rdi_format/rdi_format_parse.c similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format_parse.c rename to src/lib_rdi_format/rdi_format_parse.c diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.h b/src/lib_rdi_format/rdi_format_parse.h similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format_parse.h rename to src/lib_rdi_format/rdi_format_parse.h diff --git a/src/lib_raddbgi_make/raddbgi_make.c b/src/lib_rdi_make/rdi_make.c similarity index 100% rename from src/lib_raddbgi_make/raddbgi_make.c rename to src/lib_rdi_make/rdi_make.c diff --git a/src/lib_raddbgi_make/raddbgi_make.h b/src/lib_rdi_make/rdi_make.h similarity index 99% rename from src/lib_raddbgi_make/raddbgi_make.h rename to src/lib_rdi_make/rdi_make.h index 6c773aa4..3a497e43 100644 --- a/src/lib_raddbgi_make/raddbgi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -5,14 +5,14 @@ // RAD Debug Info Make, (R)AD(D)BG(I) (M)ake Library // // Library for building loose data structures which contain -// RADDBGI debug information, and baking that down into the -// proper flattened RADDBGI format. +// RDI debug information, and baking that down into the +// proper flattened RDI format. // // Requires prior inclusion of the RAD Debug Info, (R)AD(D)BG(I) -// Format Library, in raddbgi_format.h. +// Format Library, in rdi_format.h. -#ifndef RADDBGI_MAKE_H -#define RADDBGI_MAKE_H +#ifndef RDI_MAKE_H +#define RDI_MAKE_H //////////////////////////////// //~ rjf: Overrideable Memory Operations @@ -1252,4 +1252,4 @@ RDI_PROC RDIM_BakeSectionList rdim_bake_idx_run_section_list_from_idx_run_map(RD RDI_PROC RDIM_String8List rdim_serialized_strings_from_params_bake_section_list(RDIM_Arena *arena, RDIM_BakeParams *params, RDIM_BakeSectionList *sections); -#endif // RADDBGI_MAKE_H +#endif // RDI_MAKE_H diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index c571a6b4..92dfcd92 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -375,7 +375,7 @@ // [x] new fuzzy searching layer // [x] robustify dbgi layer to renames (cache should not be based only on // path - must invalidate naturally when new filetime occurs) -// [x] raddbgi file regeneration too strict +// [x] rdi file regeneration too strict #ifndef RADDBG_H #define RADDBG_H diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 280435af..7f28f917 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -22,10 +22,10 @@ //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format_parse.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -34,7 +34,7 @@ #include "os/os_inc.h" #include "task_system/task_system.h" #include "ico/ico.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" @@ -48,9 +48,9 @@ #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" #include "regs/regs.h" -#include "regs/raddbgi/regs_raddbgi.h" +#include "regs/rdi/regs_rdi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" #include "dasm_cache/dasm_cache.h" @@ -73,7 +73,7 @@ #include "os/os_inc.c" #include "task_system/task_system.c" #include "ico/ico.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" @@ -87,9 +87,9 @@ #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" #include "regs/regs.c" -#include "regs/raddbgi/regs_raddbgi.c" +#include "regs/rdi/regs_rdi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" #include "dasm_cache/dasm_cache.c" diff --git a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c similarity index 95% rename from src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c rename to src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c index 1576b8c0..134c7048 100644 --- a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c +++ b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c @@ -5,17 +5,17 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_breakpad_from_pdb" +#define BUILD_TITLE "rdi_breakpad_from_pdb" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -24,27 +24,27 @@ #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" #include "codeview/codeview_stringize.h" #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" #include "codeview/codeview_stringize.c" #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" //////////////////////////////// //~ rjf: Baking Tasks @@ -209,7 +209,7 @@ entry_point(CmdLine *cmdline) //- rjf: display help if(do_help || user2convert->errors.node_count != 0) { - fprintf(stderr, "--- raddbgi_breakpad_from_pdb -------------------------------------------------\n\n"); + fprintf(stderr, "--- rdi_breakpad_from_pdb -----------------------------------------------------\n\n"); fprintf(stderr, "This utility converts debug information from PDBs into the textual Breakpad\n"); fprintf(stderr, "symbol information format, used for various external utilities, using the RAD\n"); diff --git a/src/raddbgi_dump/raddbgi_dump.c b/src/rdi_dump/rdi_dump.c similarity index 99% rename from src/raddbgi_dump/raddbgi_dump.c rename to src/rdi_dump/rdi_dump.c index 019be63b..92f96225 100644 --- a/src/raddbgi_dump/raddbgi_dump.c +++ b/src/rdi_dump/rdi_dump.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: RADDBGI Enum -> String Functions +//~ rjf: RDI Enum -> String Functions internal String8 rdi_string_from_data_section_tag(RDI_DataSectionTag tag){ @@ -79,7 +79,7 @@ rdi_string_from_local_kind(RDI_LocalKind local_kind){ } //////////////////////////////// -//~ rjf: RADDBGI Flags -> String Functions +//~ rjf: RDI Flags -> String Functions internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, diff --git a/src/raddbgi_dump/raddbgi_dump.h b/src/rdi_dump/rdi_dump.h similarity index 94% rename from src/raddbgi_dump/raddbgi_dump.h rename to src/rdi_dump/rdi_dump.h index add5f987..473093d9 100644 --- a/src/raddbgi_dump/raddbgi_dump.h +++ b/src/rdi_dump/rdi_dump.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DUMP_H -#define RADDBGI_DUMP_H +#ifndef RDI_DUMP_H +#define RDI_DUMP_H //////////////////////////////// //~ rjf: RADDBG Stringize Helper Types @@ -39,7 +39,7 @@ struct RDI_ScopeBundle }; //////////////////////////////// -//~ rjf: RADDBGI Enum -> String Functions +//~ rjf: RDI Enum -> String Functions internal String8 rdi_string_from_data_section_tag(RDI_DataSectionTag tag); internal String8 rdi_string_from_arch(RDI_Arch arch); @@ -49,7 +49,7 @@ internal String8 rdi_string_from_member_kind(RDI_MemberKind member_kind); internal String8 rdi_string_from_local_kind(RDI_LocalKind local_kind); //////////////////////////////// -//~ rjf: RADDBGI Flags -> String Functions +//~ rjf: RDI Flags -> String Functions internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags); internal void rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, RDI_TypeModifierFlags flags); @@ -57,7 +57,7 @@ internal void rdi_stringize_user_defined_type_flags(Arena *arena, String8List *o internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags); //////////////////////////////// -//~ rjf: RADDBG Compound Stringize Functions +//~ rjf: RDI Compound Stringize Functions internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *parsed, U32 indent_level); internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_TopLevelInfo *tli, U32 indent_level); @@ -72,4 +72,4 @@ internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_ internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_Procedure *proc, U32 indent_level); internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level); -#endif // RADDBGI_DUMP_H +#endif // RDI_DUMP_H diff --git a/src/raddbgi_dump/raddbgi_dump_main.c b/src/rdi_dump/rdi_dump_main.c similarity index 96% rename from src/raddbgi_dump/raddbgi_dump_main.c rename to src/rdi_dump/rdi_dump_main.c index 2fea4fb5..c4145f09 100644 --- a/src/raddbgi_dump/raddbgi_dump_main.c +++ b/src/rdi_dump/rdi_dump_main.c @@ -8,27 +8,27 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_dump" +#define BUILD_TITLE "rdi_dump" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" -#include "raddbgi_dump.h" +#include "rdi_dump.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" -#include "raddbgi_dump.c" +#include "rdi_dump.c" //////////////////////////////// //~ rjf: Entry Point @@ -73,8 +73,8 @@ entry_point(CmdLine *cmd_line) // rjf: extract input file path & load data input_name = str8_list_first(&cmd_line->inputs); if(input_name.size > 0) { input_data = os_data_from_file_path(arena, input_name); } - else {str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file specified.");} - if(input_name.size != 0 && input_data.size == 0) { str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file successfully loaded; either the path or file contents are invalid."); } + else {str8_list_pushf(arena, &errors, "error (input): No input RDI file specified.");} + if(input_name.size != 0 && input_data.size == 0) { str8_list_pushf(arena, &errors, "error (input): No input RDI file successfully loaded; either the path or file contents are invalid."); } // rjf: extract dump options { @@ -116,7 +116,7 @@ entry_point(CmdLine *cmd_line) parse_status = rdi_parse(input_data.str, input_data.size, &raddbg_); if(parse_status != RDI_ParseStatus_Good) { - str8_list_pushf(arena, &errors, "error (parse): RADDBGI file wasn't parsed successfully. (0x%x)", parse_status); + str8_list_pushf(arena, &errors, "error (parse): RDI file wasn't parsed successfully. (0x%x)", parse_status); } } diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf.c b/src/rdi_from_dwarf/rdi_dwarf.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_dwarf.c rename to src/rdi_from_dwarf/rdi_dwarf.c diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf.h b/src/rdi_from_dwarf/rdi_dwarf.h similarity index 99% rename from src/raddbgi_from_dwarf/raddbgi_dwarf.h rename to src/rdi_from_dwarf/rdi_dwarf.h index 186f0486..273ae521 100644 --- a/src/raddbgi_from_dwarf/raddbgi_dwarf.h +++ b/src/rdi_from_dwarf/rdi_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DWARF_H -#define RADDBGI_DWARF_H +#ifndef RDI_DWARF_H +#define RDI_DWARF_H // https://dwarfstd.org/doc/DWARF4.pdf // https://dwarfstd.org/doc/DWARF5.pdf @@ -1489,5 +1489,5 @@ static String8 dwarf_string_from_line_ext_op(DWARF_LineExtOp op); static String8 dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format); static String8 dwarf_string_from_section_code(DWARF_SectionCode sec_code); -#endif //RADDBGI_DWARF_H +#endif //RDI_DWARF_H diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c b/src/rdi_from_dwarf/rdi_dwarf_stringize.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c rename to src/rdi_from_dwarf/rdi_dwarf_stringize.c diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h b/src/rdi_from_dwarf/rdi_dwarf_stringize.h similarity index 87% rename from src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h rename to src/rdi_from_dwarf/rdi_dwarf_stringize.h index d8cd9e87..0fa77da1 100644 --- a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h +++ b/src/rdi_from_dwarf/rdi_dwarf_stringize.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DWARF_STRINGIZE_H -#define RADDBGI_DWARF_STRINGIZE_H +#ifndef RDI_DWARF_STRINGIZE_H +#define RDI_DWARF_STRINGIZE_H //////////////////////////////// //~ DWARF Stringize Functions @@ -25,4 +25,4 @@ dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 i -#endif //RADDBGI_DWARF_STRINGIZE_H +#endif //RDI_DWARF_STRINGIZE_H diff --git a/src/raddbgi_from_dwarf/raddbgi_elf.c b/src/rdi_from_dwarf/rdi_elf.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_elf.c rename to src/rdi_from_dwarf/rdi_elf.c diff --git a/src/raddbgi_from_dwarf/raddbgi_elf.h b/src/rdi_from_dwarf/rdi_elf.h similarity index 99% rename from src/raddbgi_from_dwarf/raddbgi_elf.h rename to src/rdi_from_dwarf/rdi_elf.h index 99882ec4..ae0bf781 100644 --- a/src/raddbgi_from_dwarf/raddbgi_elf.h +++ b/src/rdi_from_dwarf/rdi_elf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_ELF_H -#define RADDBGI_ELF_H +#ifndef RDI_ELF_H +#define RDI_ELF_H // https://refspecs.linuxfoundation.org/elf/elf.pdf @@ -514,4 +514,4 @@ static String8 elf_string_from_symbol_binding(ELF_SymbolBinding binding); static String8 elf_string_from_symbol_type(ELF_SymbolType type); static String8 elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility); -#endif //RADDBGI_ELF_H +#endif //RDI_ELF_H diff --git a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c similarity index 98% rename from src/raddbgi_from_dwarf/raddbgi_from_dwarf.c rename to src/rdi_from_dwarf/rdi_from_dwarf.c index e8607272..6c89740f 100644 --- a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1,27 +1,27 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_rdi_format/rdi_format.h" #include "base/base_inc.h" #include "os/os_inc.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" -#include "raddbgi_elf.h" -#include "raddbgi_dwarf.h" +#include "rdi_elf.h" +#include "rdi_dwarf.h" -#include "raddbgi_dwarf_stringize.h" +#include "rdi_dwarf_stringize.h" -#include "raddbgi_from_dwarf.h" +#include "rdi_from_dwarf.h" -#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_rdi_format/rdi_format.c" #include "base/base_inc.c" #include "os/os_inc.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" -#include "raddbgi_elf.c" -#include "raddbgi_dwarf.c" +#include "rdi_elf.c" +#include "rdi_dwarf.c" -#include "raddbgi_dwarf_stringize.c" +#include "rdi_dwarf_stringize.c" // TODO(allen): // [ ] need sample data for .debug_names diff --git a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h similarity index 91% rename from src/raddbgi_from_dwarf/raddbgi_from_dwarf.h rename to src/rdi_from_dwarf/rdi_from_dwarf.h index 82052c44..bf9689c9 100644 --- a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_FROM_DWARF_H -#define RADDBGI_FROM_DWARF_H +#ifndef RDI_FROM_DWARF_H +#define RDI_FROM_DWARF_H //////////////////////////////// //~ Program Parameters Type @@ -47,4 +47,4 @@ static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLin -#endif //RADDBGI_FROM_DWARF_H +#endif //RDI_FROM_DWARF_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c similarity index 99% rename from src/raddbgi_from_pdb/raddbgi_from_pdb.c rename to src/rdi_from_pdb/rdi_from_pdb.c index a85e1105..8ea57171 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -147,7 +147,7 @@ Case("source_path_name_map",NormalSourcePathNameMap)\ } //////////////////////////////// -//~ rjf: COFF <-> RADDBGI Canonical Conversions +//~ rjf: COFF <-> RDI Canonical Conversions internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) @@ -169,7 +169,7 @@ p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) } //////////////////////////////// -//~ rjf: CodeView <-> RADDBGI Canonical Conversions +//~ rjf: CodeView <-> RDI Canonical Conversions internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) @@ -2935,7 +2935,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- 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 raddbgi's "only reference backward" + // 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 @@ -2974,7 +2974,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: types pass 3: construct all types from TPI // // this doesn't gather struct/class/union/enum members, which is done by - // subsequent passes, to build RADDBGI "UDT" information, which is distinct + // subsequent passes, to build RDI "UDT" information, which is distinct // from regular type info. // RDIM_Type **itype_type_ptrs = 0; diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h similarity index 98% rename from src/raddbgi_from_pdb/raddbgi_from_pdb.h rename to src/rdi_from_pdb/rdi_from_pdb.h index 226c0bde..088d4521 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_FROM_PDB_H -#define RADDBGI_FROM_PDB_H +#ifndef RDI_FROM_PDB_H +#define RDI_FROM_PDB_H //////////////////////////////// //~ rjf: Export Artifact Flags @@ -514,12 +514,12 @@ internal U64 p2r_hash_from_voff(U64 voff); internal P2R_User2Convert *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline); //////////////////////////////// -//~ rjf: COFF => RADDBGI Canonical Conversions +//~ rjf: COFF => RDI Canonical Conversions internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); //////////////////////////////// -//~ rjf: CodeView => RADDBGI Canonical Conversions +//~ rjf: CodeView => RDI Canonical Conversions internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); internal RDI_RegisterCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); @@ -626,4 +626,4 @@ internal P2R_Bake2Serialize *p2r_bake(Arena *arena, P2R_Convert2Bake *in); internal P2R_Bake2Serialize *p2r_compress(Arena *arena, P2R_Bake2Serialize *in); -#endif // RADDBGI_FROM_PDB_H +#endif // RDI_FROM_PDB_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c similarity index 91% rename from src/raddbgi_from_pdb/raddbgi_from_pdb_main.c rename to src/rdi_from_pdb/rdi_from_pdb_main.c index fbf5a91c..75eb0723 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -8,15 +8,15 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_from_pdb" +#define BUILD_TITLE "rdi_from_pdb" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -24,27 +24,27 @@ #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" #include "codeview/codeview_stringize.h" #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb.h" +#include "rdi_from_pdb.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" #include "codeview/codeview_stringize.c" #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb.c" +#include "rdi_from_pdb.c" //////////////////////////////// //~ rjf: Entry Point @@ -62,7 +62,7 @@ entry_point(CmdLine *cmdline) //- rjf: display help if(do_help || user2convert->errors.node_count != 0) { - fprintf(stderr, "--- raddbgi_from_pdb ----------------------------------------------------------\n\n"); + fprintf(stderr, "--- rdi_from_pdb --------------------------------------------------------------\n\n"); fprintf(stderr, "This utility converts debug information from PDBs into the RAD Debug Info.\n"); fprintf(stderr, "format. The following arguments are accepted:\n\n"); diff --git a/src/raddbgi_make_local/raddbgi_make_local.c b/src/rdi_make_local/rdi_make_local.c similarity index 72% rename from src/raddbgi_make_local/raddbgi_make_local.c rename to src/rdi_make_local/rdi_make_local.c index 7e476d6c..981c819e 100644 --- a/src/raddbgi_make_local/raddbgi_make_local.c +++ b/src/rdi_make_local/rdi_make_local.c @@ -1,4 +1,4 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "lib_raddbgi_make/raddbgi_make.c" +#include "lib_rdi_make/rdi_make.c" diff --git a/src/raddbgi_make_local/raddbgi_make_local.h b/src/rdi_make_local/rdi_make_local.h similarity index 97% rename from src/raddbgi_make_local/raddbgi_make_local.h rename to src/rdi_make_local/rdi_make_local.h index d4201e24..873cee30 100644 --- a/src/raddbgi_make_local/raddbgi_make_local.h +++ b/src/rdi_make_local/rdi_make_local.h @@ -45,6 +45,6 @@ #define RDIM_ProfBegin(...) ProfBeginDynamic(__VA_ARGS__) #define RDIM_ProfEnd(...) ProfEnd() -#include "lib_raddbgi_make/raddbgi_make.h" +#include "lib_rdi_make/rdi_make.h" #endif // RDI_CONS_LOCAL_H diff --git a/src/regs/raddbgi/generated/regs_raddbgi.meta.c b/src/regs/rdi/generated/regs_rdi.meta.c similarity index 100% rename from src/regs/raddbgi/generated/regs_raddbgi.meta.c rename to src/regs/rdi/generated/regs_rdi.meta.c diff --git a/src/regs/raddbgi/generated/regs_raddbgi.meta.h b/src/regs/rdi/generated/regs_rdi.meta.h similarity index 65% rename from src/regs/raddbgi/generated/regs_raddbgi.meta.h rename to src/regs/rdi/generated/regs_rdi.meta.h index 4082c723..30461e08 100644 --- a/src/regs/raddbgi/generated/regs_raddbgi.meta.h +++ b/src/regs/rdi/generated/regs_rdi.meta.h @@ -3,10 +3,10 @@ //- GENERATED CODE -#ifndef REGS_RADDBGI_META_H -#define REGS_RADDBGI_META_H +#ifndef REGS_RDI_META_H +#define REGS_RDI_META_H C_LINKAGE_BEGIN C_LINKAGE_END -#endif // REGS_RADDBGI_META_H +#endif // REGS_RDI_META_H diff --git a/src/regs/raddbgi/regs_raddbgi.c b/src/regs/rdi/regs_rdi.c similarity index 67% rename from src/regs/raddbgi/regs_raddbgi.c rename to src/regs/rdi/regs_rdi.c index b72739f4..1e130772 100644 --- a/src/regs/raddbgi/regs_raddbgi.c +++ b/src/regs/rdi/regs_rdi.c @@ -1,4 +1,4 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "regs/raddbgi/generated/regs_raddbgi.meta.c" +#include "regs/rdi/generated/regs_rdi.meta.c" diff --git a/src/regs/raddbgi/regs_raddbgi.h b/src/regs/rdi/regs_rdi.h similarity index 81% rename from src/regs/raddbgi/regs_raddbgi.h rename to src/regs/rdi/regs_rdi.h index 4049a5b1..72a52ce6 100644 --- a/src/regs/raddbgi/regs_raddbgi.h +++ b/src/regs/rdi/regs_rdi.h @@ -1,10 +1,10 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef REGS_RADDBGI_H -#define REGS_RADDBGI_H +#ifndef REGS_RDI_H +#define REGS_RDI_H internal RDI_RegisterCode regs_rdi_code_from_arch_reg_code(Architecture arch, REGS_RegCode code); internal REGS_RegCode regs_reg_code_from_arch_rdi_code(Architecture arch, RDI_RegisterCode reg); -#endif //REGS_RADDBGI_H +#endif //REGS_RDI_H diff --git a/src/regs/raddbgi/regs_raddbgi.mdesk b/src/regs/rdi/regs_rdi.mdesk similarity index 100% rename from src/regs/raddbgi/regs_raddbgi.mdesk rename to src/regs/rdi/regs_rdi.mdesk diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 0d49c41e..1087cf13 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -15,16 +15,16 @@ //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" @@ -38,9 +38,9 @@ #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" #include "regs/regs.h" -#include "regs/raddbgi/regs_raddbgi.h" +#include "regs/rdi/regs_rdi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" #include "demon/demon_inc.h" @@ -52,7 +52,7 @@ #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" @@ -66,9 +66,9 @@ #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" #include "regs/regs.c" -#include "regs/raddbgi/regs_raddbgi.c" +#include "regs/rdi/regs_rdi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" #include "demon/demon_inc.c" From 6837d8d71a783f576186da992032cdeb7ed5cde1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 15:16:53 -0700 Subject: [PATCH 35/38] move rdi_dump over to dbgi layer --- src/dbgi/dbgi.c | 4 +- src/rdi_dump/rdi_dump_main.c | 161 +++++++++++++++++++---------------- 2 files changed, 88 insertions(+), 77 deletions(-) diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 0375ab7a..0b8811cb 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -203,7 +203,7 @@ di_string_bucket_idx_from_string_size(U64 size) case 1<<8: {bucket_idx = 4;}break; case 1<<9: {bucket_idx = 5;}break; case 1<<10:{bucket_idx = 6;}break; - default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; + default:{bucket_idx = ArrayCount(((DI_Stripe *)0)->free_string_chunks)-1;}break; } return bucket_idx; } @@ -658,7 +658,7 @@ di_parse_thread__entry_point(void *p) } if(!og_format_is_known) { - if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) + if(data.size >= 2 && *(U16 *)data.str == 0x5a4d) { og_format_is_known = 1; og_is_pe = 1; diff --git a/src/rdi_dump/rdi_dump_main.c b/src/rdi_dump/rdi_dump_main.c index c4145f09..315850e9 100644 --- a/src/rdi_dump/rdi_dump_main.c +++ b/src/rdi_dump/rdi_dump_main.c @@ -19,15 +19,21 @@ #include "lib_rdi_format/rdi_format_parse.h" #include "lib_rdi_format/rdi_format.c" #include "lib_rdi_format/rdi_format_parse.c" +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" +#include "path/path.h" +#include "dbgi/dbgi.h" #include "rdi_dump.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" +#include "path/path.c" +#include "dbgi/dbgi.c" #include "rdi_dump.c" //////////////////////////////// @@ -40,6 +46,7 @@ entry_point(CmdLine *cmd_line) //- rjf: set up // Arena *arena = arena_alloc(); + DI_Scope *di_scope = di_scope_open(); String8List errors = {0}; ////////////////////////////// @@ -70,11 +77,8 @@ entry_point(CmdLine *cmd_line) String8 input_data = {0}; DumpFlags dump_flags = (U32)0xffffffff; { - // rjf: extract input file path & load data + // rjf: extract input file path input_name = str8_list_first(&cmd_line->inputs); - if(input_name.size > 0) { input_data = os_data_from_file_path(arena, input_name); } - else {str8_list_pushf(arena, &errors, "error (input): No input RDI file specified.");} - if(input_name.size != 0 && input_data.size == 0) { str8_list_pushf(arena, &errors, "error (input): No input RDI file successfully loaded; either the path or file contents are invalid."); } // rjf: extract dump options { @@ -107,17 +111,22 @@ entry_point(CmdLine *cmd_line) } ////////////////////////////// - //- rjf: parse raddbg from input data + //- rjf: obtain rdi parse // - RDI_ParseStatus parse_status = RDI_ParseStatus_Good; - RDI_Parsed raddbg_ = {0}; - RDI_Parsed *raddbg = &raddbg_; + RDI_Parsed *rdi = &di_rdi_parsed_nil; + if(input_name.size == 0) { - parse_status = rdi_parse(input_data.str, input_data.size, &raddbg_); - if(parse_status != RDI_ParseStatus_Good) - { - str8_list_pushf(arena, &errors, "error (parse): RDI file wasn't parsed successfully. (0x%x)", parse_status); - } + str8_list_pushf(arena, &errors, "error (input): No input RDI file specified."); + } + else + { + DI_Key key = {input_name}; + di_open(&key); + rdi = di_rdi_from_key(di_scope, &key, max_U64); + } + if(rdi == &di_rdi_parsed_nil) + { + str8_list_pushf(arena, &errors, "error (input): No input RDI file successfully loaded; either the path or file contents are invalid."); } ////////////////////////////// @@ -133,13 +142,13 @@ entry_point(CmdLine *cmd_line) //- rjf: build dump strings // String8List dump = {0}; - if(parse_status == RDI_ParseStatus_Good) + if(rdi != &di_rdi_parsed_nil) { //- rjf: DATA SECTIONS if(dump_flags & DumpFlag_DataSections) { str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); - rdi_stringize_data_sections(arena, &dump, raddbg, 1); + rdi_stringize_data_sections(arena, &dump, rdi, 1); str8_list_push(arena, &dump, str8_lit("\n")); } @@ -147,7 +156,7 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_TopLevelInfo) { str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); - rdi_stringize_top_level_info(arena, &dump, raddbg, raddbg->top_level_info, 1); + rdi_stringize_top_level_info(arena, &dump, rdi, rdi->top_level_info, 1); str8_list_push(arena, &dump, str8_lit("\n")); } @@ -155,11 +164,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_BinarySections) { str8_list_pushf(arena, &dump, "# BINARY SECTIONS:\n"); - RDI_BinarySection *ptr = raddbg->binary_sections; - for(U32 i = 0; i < raddbg->binary_sections_count; i += 1, ptr += 1) + RDI_BinarySection *ptr = rdi->binary_sections; + for(U32 i = 0; i < rdi->binary_sections_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " section[%u]:\n", i); - rdi_stringize_binary_section(arena, &dump, raddbg, ptr, 2); + rdi_stringize_binary_section(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -170,16 +179,16 @@ entry_point(CmdLine *cmd_line) { RDI_FilePathBundle file_path_bundle = {0}; { - file_path_bundle.file_paths = raddbg->file_paths; - file_path_bundle.file_path_count = raddbg->file_paths_count; + file_path_bundle.file_paths = rdi->file_paths; + file_path_bundle.file_path_count = rdi->file_paths_count; } str8_list_pushf(arena, &dump, "# FILE PATHS\n"); - RDI_FilePathNode *ptr = raddbg->file_paths; - for(U32 i = 0; i < raddbg->file_paths_count; i += 1, ptr += 1) + RDI_FilePathNode *ptr = rdi->file_paths; + for(U32 i = 0; i < rdi->file_paths_count; i += 1, ptr += 1) { if(ptr->parent_path_node == 0) { - rdi_stringize_file_path(arena, &dump, raddbg, &file_path_bundle, ptr, 1); + rdi_stringize_file_path(arena, &dump, rdi, &file_path_bundle, ptr, 1); } } str8_list_push(arena, &dump, str8_lit("\n")); @@ -189,11 +198,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_SourceFiles) { str8_list_pushf(arena, &dump, "# SOURCE FILES\n"); - RDI_SourceFile *ptr = raddbg->source_files; - for(U32 i = 0; i < raddbg->source_files_count; i += 1, ptr += 1) + RDI_SourceFile *ptr = rdi->source_files; + for(U32 i = 0; i < rdi->source_files_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " source_file[%u]:\n", i); - rdi_stringize_source_file(arena, &dump, raddbg, ptr, 2); + rdi_stringize_source_file(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -203,11 +212,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Units) { str8_list_pushf(arena, &dump, "# UNITS\n"); - RDI_Unit *ptr = raddbg->units; - for (U32 i = 0; i < raddbg->units_count; i += 1, ptr += 1) + RDI_Unit *ptr = rdi->units; + for (U32 i = 0; i < rdi->units_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - rdi_stringize_unit(arena, &dump, raddbg, ptr, 2); + rdi_stringize_unit(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -217,8 +226,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_UnitVMap) { str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); - RDI_VMapEntry *ptr = raddbg->unit_vmap; - for(U32 i = 0; i < raddbg->unit_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->unit_vmap; + for(U32 i = 0; i < rdi->unit_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -229,11 +238,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_TypeNodes) { str8_list_pushf(arena, &dump, "# TYPE NODES:\n"); - RDI_TypeNode *ptr = raddbg->type_nodes; - for(U32 i = 0; i < raddbg->type_nodes_count; i += 1, ptr += 1) + RDI_TypeNode *ptr = rdi->type_nodes; + for(U32 i = 0; i < rdi->type_nodes_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " type[%u]:\n", i); - rdi_stringize_type_node(arena, &dump, raddbg, ptr, 2); + rdi_stringize_type_node(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -244,17 +253,17 @@ entry_point(CmdLine *cmd_line) { RDI_UDTMemberBundle member_bundle = {0}; { - member_bundle.members = raddbg->members; - member_bundle.enum_members = raddbg->enum_members; - member_bundle.member_count = raddbg->members_count; - member_bundle.enum_member_count = raddbg->enum_members_count; + member_bundle.members = rdi->members; + member_bundle.enum_members = rdi->enum_members; + member_bundle.member_count = rdi->members_count; + member_bundle.enum_member_count = rdi->enum_members_count; } str8_list_pushf(arena, &dump, "# UDTS:\n"); - RDI_UDT *ptr = raddbg->udts; - for(U32 i = 0; i < raddbg->udts_count; i += 1, ptr += 1) + RDI_UDT *ptr = rdi->udts; + for(U32 i = 0; i < rdi->udts_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " udt[%u]:\n", i); - rdi_stringize_udt(arena, &dump, raddbg, &member_bundle, ptr, 2); + rdi_stringize_udt(arena, &dump, rdi, &member_bundle, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -264,11 +273,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_GlobalVariables) { str8_list_pushf(arena, &dump, "# GLOBAL VARIABLES:\n"); - RDI_GlobalVariable *ptr = raddbg->global_variables; - for(U32 i = 0; i < raddbg->global_variables_count; i += 1, ptr += 1) + RDI_GlobalVariable *ptr = rdi->global_variables; + for(U32 i = 0; i < rdi->global_variables_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " global_variable[%u]:\n", i); - rdi_stringize_global_variable(arena, &dump, raddbg, ptr, 2); + rdi_stringize_global_variable(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -278,8 +287,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_GlobalVMap) { str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); - RDI_VMapEntry *ptr = raddbg->global_vmap; - for(U32 i = 0; i < raddbg->global_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->global_vmap; + for(U32 i = 0; i < rdi->global_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -290,11 +299,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_ThreadVariables) { str8_list_pushf(arena, &dump, "# THREAD VARIABLES:\n"); - RDI_ThreadVariable *ptr = raddbg->thread_variables; - for(U32 i = 0; i < raddbg->thread_variables_count; i += 1, ptr += 1) + RDI_ThreadVariable *ptr = rdi->thread_variables; + for(U32 i = 0; i < rdi->thread_variables_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " thread_variable[%u]:\n", i); - rdi_stringize_thread_variable(arena, &dump, raddbg, ptr, 2); + rdi_stringize_thread_variable(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -304,11 +313,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Procedures) { str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); - RDI_Procedure *ptr = raddbg->procedures; - for(U32 i = 0; i < raddbg->procedures_count; i += 1, ptr += 1) + RDI_Procedure *ptr = rdi->procedures; + for(U32 i = 0; i < rdi->procedures_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " procedure[%u]:\n", i); - rdi_stringize_procedure(arena, &dump, raddbg, ptr, 2); + rdi_stringize_procedure(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -319,24 +328,24 @@ entry_point(CmdLine *cmd_line) { RDI_ScopeBundle scope_bundle = {0}; { - scope_bundle.scopes = raddbg->scopes; - scope_bundle.scope_count = raddbg->scopes_count; - scope_bundle.scope_voffs = raddbg->scope_voffs; - scope_bundle.scope_voff_count = raddbg->scope_voffs_count; - scope_bundle.locals = raddbg->locals; - scope_bundle.local_count = raddbg->locals_count; - scope_bundle.location_blocks = raddbg->location_blocks; - scope_bundle.location_block_count = raddbg->location_blocks_count; - scope_bundle.location_data = raddbg->location_data; - scope_bundle.location_data_size = raddbg->location_data_size; + scope_bundle.scopes = rdi->scopes; + scope_bundle.scope_count = rdi->scopes_count; + scope_bundle.scope_voffs = rdi->scope_voffs; + scope_bundle.scope_voff_count = rdi->scope_voffs_count; + scope_bundle.locals = rdi->locals; + scope_bundle.local_count = rdi->locals_count; + scope_bundle.location_blocks = rdi->location_blocks; + scope_bundle.location_block_count = rdi->location_blocks_count; + scope_bundle.location_data = rdi->location_data; + scope_bundle.location_data_size = rdi->location_data_size; } str8_list_pushf(arena, &dump, "# SCOPES:\n"); - RDI_Scope *ptr = raddbg->scopes; - for(U32 i = 0; i < raddbg->scopes_count; i += 1, ptr += 1) + RDI_Scope *ptr = rdi->scopes; + for(U32 i = 0; i < rdi->scopes_count; i += 1, ptr += 1) { if(ptr->parent_scope_idx == 0) { - rdi_stringize_scope(arena, &dump, raddbg, &scope_bundle, ptr, 1); + rdi_stringize_scope(arena, &dump, rdi, &scope_bundle, ptr, 1); str8_list_push(arena, &dump, str8_lit("\n")); } } @@ -347,8 +356,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_ScopeVMap) { str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); - RDI_VMapEntry *ptr = raddbg->scope_vmap; - for(U32 i = 0; i < raddbg->scope_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->scope_vmap; + for(U32 i = 0; i < rdi->scope_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -359,11 +368,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_NameMaps) { str8_list_pushf(arena, &dump, "# NAME MAP:\n"); - RDI_NameMap *ptr = raddbg->name_maps; - for(U32 i = 0; i < raddbg->name_maps_count; i += 1, ptr += 1) + RDI_NameMap *ptr = rdi->name_maps; + for(U32 i = 0; i < rdi->name_maps_count; i += 1, ptr += 1) { RDI_ParsedNameMap name_map = {0}; - rdi_name_map_parse(raddbg, ptr, &name_map); + rdi_name_map_parse(rdi, ptr, &name_map); str8_list_pushf(arena, &dump, " name_map[%u]:\n", i); RDI_NameMapBucket *bucket = name_map.buckets; for(U32 j = 0; j < name_map.bucket_count; j += 1, bucket += 1) @@ -376,7 +385,7 @@ entry_point(CmdLine *cmd_line) for(;node < node_opl; node += 1) { String8 string = {0}; - string.str = rdi_string_from_idx(raddbg, node->string_idx, &string.size); + string.str = rdi_string_from_idx(rdi, node->string_idx, &string.size); str8_list_pushf(arena, &dump, " match \"%.*s\": ", str8_varg(string)); if(node->match_count == 1) { @@ -386,7 +395,7 @@ entry_point(CmdLine *cmd_line) { RDI_U32 idx_count = 0; RDI_U32 *idx_run = - rdi_idx_run_from_first_count(raddbg, node->match_idx_or_idx_run_first, + rdi_idx_run_from_first_count(rdi, node->match_idx_or_idx_run_first, node->match_count, &idx_count); if(idx_count > 0) { @@ -411,10 +420,10 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Strings) { str8_list_pushf(arena, &dump, "# STRINGS:\n"); - for(U64 string_idx = 0; string_idx < raddbg->string_count; string_idx += 1) + for(U64 string_idx = 0; string_idx < rdi->string_count; string_idx += 1) { String8 string = {0}; - string.str = rdi_string_from_idx(raddbg, string_idx, &string.size); + string.str = rdi_string_from_idx(rdi, string_idx, &string.size); str8_list_pushf(arena, &dump, " string[%I64u]: \"%S\"\n", string_idx, string); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -428,4 +437,6 @@ entry_point(CmdLine *cmd_line) { fwrite(n->string.str, 1, n->string.size, stdout); } + + di_scope_close(di_scope); } From bafc2170ca5ad75d87598f7647728bcc2b07b7d7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 15:21:53 -0700 Subject: [PATCH 36/38] do not consume passthrough --s in command line parser --- src/base/base_command_line.c | 4 +++- src/raddbg/raddbg.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/base/base_command_line.c b/src/base/base_command_line.c index 1bf3312d..2c761583 100644 --- a/src/base/base_command_line.c +++ b/src/base/base_command_line.c @@ -92,6 +92,7 @@ cmd_line_from_string_list(Arena *arena, String8List command_line) // NOTE(rjf): Parse command line. B32 after_passthrough_option = 0; + B32 first_passthrough = 1; for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next) { next = node->next; @@ -175,10 +176,11 @@ cmd_line_from_string_list(Arena *arena, String8List command_line) // NOTE(rjf): Default path, treat as a passthrough config option to be // handled by tool-specific code. - else if(!str8_match(node->string, str8_lit("--"), 0)) + else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough) { str8_list_push(arena, &parsed.inputs, node->string); after_passthrough_option = 1; + first_passthrough = 0; } } diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 92dfcd92..927e2393 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -37,7 +37,6 @@ //////////////////////////////// //~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy) // -// [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly // [ ] PDB files distributed with the build are not found by DbgHelp!!! // [ ] Jai compiler debugging crash // @@ -376,6 +375,7 @@ // [x] robustify dbgi layer to renames (cache should not be based only on // path - must invalidate naturally when new filetime occurs) // [x] rdi file regeneration too strict +// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly #ifndef RADDBG_H #define RADDBG_H From 35b97d9c206119efed945c803e0d5d034f3f34e4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 15:38:51 -0700 Subject: [PATCH 37/38] process name on stop-reason strings --- src/df/gfx/df_gfx.c | 23 +++++++++++++++-------- src/mule/mule_module.cpp | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index ad18002a..e1bbd3c9 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -9543,6 +9543,13 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, Temp scratch = scratch_begin(&arena, 1); DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); String8 thread_display_string = df_display_string_from_entity(scratch.arena, thread); + String8 process_thread_string = thread_display_string; + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + if(process->kind == DF_EntityKind_Process) + { + String8 process_display_string = df_display_string_from_entity(scratch.arena, process); + process_thread_string = push_str8f(scratch.arena, "%S: %S", process_display_string, thread_display_string); + } switch(event->kind) { default: @@ -9554,7 +9561,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, { if(!df_entity_is_nil(thread)) { - explanation = push_str8f(arena, "%S completed step", thread_display_string); + explanation = push_str8f(arena, "%S completed step", process_thread_string); } else { @@ -9566,7 +9573,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, if(!df_entity_is_nil(thread)) { icon = DF_IconKind_CircleFilled; - explanation = push_str8f(arena, "%S hit a breakpoint", thread_display_string); + explanation = push_str8f(arena, "%S hit a breakpoint", process_thread_string); } }break; case CTRL_EventCause_InterruptedByException: @@ -9579,30 +9586,30 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, default: { String8 exception_code_string = df_string_from_exception_code(event->exception_code); - explanation = push_str8f(arena, "Exception thrown by %S - 0x%x%s%S", thread_display_string, event->exception_code, exception_code_string.size > 0 ? ": " : "", exception_code_string); + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x%s%S", process_thread_string, event->exception_code, exception_code_string.size > 0 ? ": " : "", exception_code_string); }break; case CTRL_ExceptionKind_CppThrow: { - explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: C++ exception", thread_display_string, event->exception_code); + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: C++ exception", process_thread_string, event->exception_code); }break; case CTRL_ExceptionKind_MemoryRead: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation reading 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; case CTRL_ExceptionKind_MemoryWrite: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation writing 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; case CTRL_ExceptionKind_MemoryExecute: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation executing 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; @@ -9617,7 +9624,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, case CTRL_EventCause_InterruptedByTrap: { icon = DF_IconKind_WarningBig; - explanation = push_str8f(arena, "%S interrupted by trap - 0x%x", thread_display_string, event->exception_code); + explanation = push_str8f(arena, "%S interrupted by trap - 0x%x", process_thread_string, event->exception_code); }break; case CTRL_EventCause_InterruptedByHalt: { diff --git a/src/mule/mule_module.cpp b/src/mule/mule_module.cpp index 6fd7170f..c7dcec7e 100644 --- a/src/mule/mule_module.cpp +++ b/src/mule/mule_module.cpp @@ -39,4 +39,5 @@ dll_type_eval_tests(void) Basics basics2 = {4, 5, 6, 7}; int x = 0; (void)x; + *(int *)0 = 0; } From 489ae56223210c3ceefe39a899c34f8b4c9ffb54 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 23 May 2024 16:17:31 -0700 Subject: [PATCH 38/38] fix moduleless unwinding and find-threads without debug info --- src/ctrl/ctrl_core.c | 10 +++++----- src/ctrl/ctrl_core.h | 4 ++-- src/df/gfx/df_gfx.c | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 06355133..427ac1d0 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1700,7 +1700,7 @@ ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX } internal CTRL_UnwindStepResult -ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) +ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) { B32 is_stale = 0; B32 is_good = 1; @@ -1710,7 +1710,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: unpack parameters // CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, machine_id, module_handle); - CTRL_Entity *process = module->parent; + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, machine_id, process_handle); U64 rip_voff = regs->rip.u64 - module->vaddr_range.min; ////////////////////////////// @@ -2519,7 +2519,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN //- rjf: abstracted unwind step internal CTRL_UnwindStepResult -ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us) +ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us) { CTRL_UnwindStepResult result = {0}; switch(arch) @@ -2527,7 +2527,7 @@ ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle default:{}break; case Architecture_x64: { - result = ctrl_unwind_step__pe_x64(store, machine_id, module, (REGS_RegBlockX64 *)reg_block, endt_us); + result = ctrl_unwind_step__pe_x64(store, machine_id, process, module, (REGS_RegBlockX64 *)reg_block, endt_us); }break; } return result; @@ -2589,7 +2589,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma frame_node_count += 1; // rjf: unwind one step - CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, module, arch, regs_block, endt_us); + CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, process_entity->handle, module, arch, regs_block, endt_us); unwind.flags |= step.flags; if(step.flags & CTRL_UnwindFlag_Error || regs_rsp_from_arch_block(arch, regs_block) == 0 || diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 220da859..995d6b66 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -762,10 +762,10 @@ internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Architecture arch, CTRL //- rjf: [x64] internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); -internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, REGS_RegBlockX64 *regs, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module, REGS_RegBlockX64 *regs, U64 endt_us); //- rjf: abstracted unwind step -internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us); //- rjf: abstracted full unwind internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index e1bbd3c9..6f1ba709 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -2534,6 +2534,21 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); } + // rjf: snap to resolved address w/o line info + if(!missing_rip && !dbgi_pending && !has_line_info && !has_module) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(thread); + params.voff = rip_voff; + params.vaddr = rip_vaddr; + params.index = unwind_count; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualOff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + // rjf: retry on stopped, pending debug info if(!df_ctrl_targets_running() && (dbgi_pending || missing_rip)) {