diff --git a/project.raddbg b/project.raddbg index 76b56383..929febbb 100644 --- a/project.raddbg +++ b/project.raddbg @@ -5,7 +5,7 @@ target: { executable: "build/raddbg.exe" working_directory: "../raddebugger" - arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user --project:C:/devel/raddebugger/build/raddbg_test.project" + arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user --project:C:/devel/raddebugger/build/raddbg_test.project --capture" debug_subprocesses: 0 enabled: 1 } @@ -57,5 +57,5 @@ target: { executable: "build/raddbg.exe" working_directory: build - arguments: "--bin --rdi --thread_count=1 C:/SymbolCache/kernelbase.pdb/53B51385668728BA4297C9C78EEC92DD1/kernelbase.pdb" + arguments: "--bin --rdi --thread_count=1 C:/SymbolCache/kernel32.pdb/E02F64ED8DA50EC6E7691C0AC0BC25781/kernel32.pdb" } diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index f4a6a12f..7e4672e4 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -1044,12 +1044,12 @@ CV_ThunkOrdinalEnum; typedef struct CV_SymThunk32 CV_SymThunk32; struct CV_SymThunk32 { - U32 parent; - U32 end; - U32 next; - U32 off; - U16 sec; - U16 len; + U32 parent; + U32 end; + U32 next; + U32 off; + U16 sec; + U16 len; CV_ThunkOrdinal ord; // U8[] name (null terminated) // U8[] variant (null terminated) diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 7dae3be5..bc80c2d1 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -270,9 +270,10 @@ enum { D_TrapFlag_IgnoreStackPointerCheck = (1<<0), D_TrapFlag_SingleStepAfterHit = (1<<1), - D_TrapFlag_SaveStackPointer = (1<<2), - D_TrapFlag_BeginSpoofMode = (1<<3), - D_TrapFlag_EndStepping = (1<<4), + D_TrapFlag_SaveStackPointerBefore = (1<<2), + D_TrapFlag_SaveStackPointerAfter = (1<<3), + D_TrapFlag_BeginSpoofMode = (1<<4), + D_TrapFlag_EndStepping = (1<<5), }; typedef struct D_Trap D_Trap; diff --git a/src/dbg_engine/dbg_engine_ctrl.c b/src/dbg_engine/dbg_engine_ctrl.c index 4e7b78d6..af3c1627 100644 --- a/src/dbg_engine/dbg_engine_ctrl.c +++ b/src/dbg_engine/dbg_engine_ctrl.c @@ -2666,10 +2666,12 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM ////////////////////////////// //- rjf: no found debug info path -> try to fall back on symbol server cache path // +#if 0 if(initial_debug_info_path.size == 0) { initial_debug_info_path = smsv_local_path_from_key(arena, str8_skip_last_slash(module_info->debug_info_path), module_info->debug_info_guid, module_info->debug_info_age); } +#endif ////////////////////////////// //- rjf: write 1 at attachment marker, to signify attachment @@ -3086,25 +3088,25 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D { d_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } - } - } - - //- rjf: irrespective of what event came back, we should ALWAYS check the - // spoof's thread and see if it hit the spoof address, because we may have - // simply been sent other debug events first - if(spoof != 0) - { - D_Entity *thread = d_entity_from_handle(spoof->thread); - Arch arch = thread->arch; - ARCH_Info *arch_info = arch_info_from_arch(arch); - U64 arch_reg_block_size = arch_info->reg_block_size; - void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); - d_thread_read_reg_block(spoof->thread, regs_block); - U64 spoof_thread_rip = arch_ip_from_reg_block(arch_info, regs_block); - if(spoof_thread_rip == spoof->new_ip_value) - { - arch_reg_block_write_ip(arch_info, regs_block, spoof_old_ip_value); - d_thread_write_reg_block(spoof->thread, regs_block); + + // rjf: irrespective of what event came back, we should ALWAYS check the + // spoof's thread and see if it hit the spoof address, because we may have + // simply been sent other debug events first + if(spoof != 0) + { + D_Entity *thread = d_entity_from_handle(spoof->thread); + Arch arch = thread->arch; + ARCH_Info *arch_info = arch_info_from_arch(arch); + U64 arch_reg_block_size = arch_info->reg_block_size; + void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); + d_thread_read_reg_block(spoof->thread, regs_block); + U64 spoof_thread_rip = arch_ip_from_reg_block(arch_info, regs_block); + if(spoof_thread_rip == spoof->new_ip_value) + { + arch_reg_block_write_ip(arch_info, regs_block, spoof_old_ip_value); + d_thread_write_reg_block(spoof->thread, regs_block); + } + } } } @@ -5154,22 +5156,38 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) } } - //- rjf: trap net on on-target threads trigger trap net logic - B32 use_trap_net_logic = 0; - if(!hard_stop && use_stepping_logic && hit_trap_net_bp) + //- rjf: trap net logic: stack pointer check on target thread + B32 stack_pointer_check_passes = 0; + if(!hard_stop && use_stepping_logic && hit_trap_net_bp && dmn_handle_match(event->thread, d_dmn_from_handle(target_thread))) { - if(dmn_handle_match(event->thread, d_dmn_from_handle(target_thread))) + U64 sp = d_sp_from_thread(target_thread); + stack_pointer_check_passes = ((hit_trap_flags & D_TrapFlag_IgnoreStackPointerCheck) || (sp == sp_check_value)); + } + + //- rjf: trap net on on-target threads trigger trap net logic, *if* the stack pointer check passes. + // if it doesn't -> step over trap net & continue + B32 use_trap_net_logic = 0; + if(!hard_stop && use_stepping_logic && hit_trap_net_bp && dmn_handle_match(event->thread, d_dmn_from_handle(target_thread))) + { + if(stack_pointer_check_passes) { use_trap_net_logic = 1; } + else + { + step_past_trap_net = 1; + use_stepping_logic = 0; + } } - //- rjf: trap net logic: stack pointer check - B32 stack_pointer_matches = 0; - if(use_trap_net_logic) + //- rjf: trap net logic: save stack pointer *before* step-over + if(!hard_stop && use_trap_net_logic) { - U64 sp = d_sp_from_thread(target_thread); - stack_pointer_matches = (sp == sp_check_value); + if(hit_trap_flags & D_TrapFlag_SaveStackPointerBefore) + { + sp_check_value = d_sp_from_thread(target_thread); + log_infof("sp_check_value = 0x%I64x\n", sp_check_value); + } } //- rjf: trap net logic: single step after hit @@ -5217,6 +5235,16 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) } } + //- rjf: trap net logic: save stack pointer *after* step-over + if(!hard_stop && use_trap_net_logic) + { + if(hit_trap_flags & D_TrapFlag_SaveStackPointerAfter) + { + sp_check_value = d_sp_from_thread(target_thread); + log_infof("sp_check_value = 0x%I64x\n", sp_check_value); + } + } + //- rjf: trap net logic: begin spoof mode B32 begin_spoof_mode = 0; if(!hard_stop && use_trap_net_logic) @@ -5234,33 +5262,14 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) } } - //- rjf: trap net logic: save stack pointer - B32 save_stack_pointer = 0; - if(!hard_stop && use_trap_net_logic) - { - if(hit_trap_flags & D_TrapFlag_SaveStackPointer) - { - if(stack_pointer_matches) LogInfoNamedBlockF("trap_net__save_sp") - { - save_stack_pointer = 1; - sp_check_value = d_sp_from_thread(target_thread); - log_infof("sp_check_value = 0x%I64x\n", sp_check_value); - } - } - } - //- rjf: trap net logic: end stepping B32 trap_net_stop = 0; if(!hard_stop && use_trap_net_logic) { if(hit_trap_flags & D_TrapFlag_EndStepping) LogInfoNamedBlockF("trap_net__end_step") { - if((hit_trap_flags & D_TrapFlag_IgnoreStackPointerCheck) || - stack_pointer_matches) - { - trap_net_stop = 1; - use_trap_net_logic = 0; - } + trap_net_stop = 1; + use_trap_net_logic = 0; } } diff --git a/src/dbg_engine/dbg_engine_user.c b/src/dbg_engine/dbg_engine_user.c index 7c7ba17a..b3fc7594 100644 --- a/src/dbg_engine/dbg_engine_user.c +++ b/src/dbg_engine/dbg_engine_user.c @@ -516,16 +516,24 @@ d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread) } + // rjf: call => save stack pointer before, single-step to go into call; trap on return + else if(point->inst_flags & DASM_InstFlag_Call) + { + flags |= (D_TrapFlag_SaveStackPointerBefore|D_TrapFlag_SingleStepAfterHit); + } + +#if 0 // TODO(rjf): @spoof_stepping // rjf: call => place spoof at return spot in stack, single-step after hitting else if(point->inst_flags & DASM_InstFlag_Call) { flags |= (D_TrapFlag_BeginSpoofMode|D_TrapFlag_SingleStepAfterHit); } +#endif - // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping + // rjf: instruction changes stack pointer => single-step over, save off the stack pointer, keep stepping else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer) { - flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointer); + flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointerAfter); } // rjf: add if appropriate @@ -734,7 +742,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread) // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer) { - flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointer); + flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointerAfter); } // rjf: add if appropriate diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 79c3d77b..bb12c6fe 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -682,6 +682,7 @@ di_async_tick(void) //- rjf: kick off symbol server download, or check to see if we are actively downloading O.G. B32 og_is_downloading = 0; + if(og_path.size != 0) { B32 file_is_present = (properties_from_file_path(og_path).modified != 0); if(!file_is_present) diff --git a/src/http/http.h b/src/http/http.h index 24f73a9f..c7d570b8 100644 --- a/src/http/http.h +++ b/src/http/http.h @@ -146,6 +146,8 @@ typedef struct HTTP_Response HTTP_Response; struct HTTP_Response { U64 id; + U64 off; + U64 off_opl; B32 has_more; HTTP_StatusCode code; String8 body; diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index f5c65910..a1b93520 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -396,6 +396,7 @@ typedef RDI_U8 RDI_SymbolFlags; typedef enum RDI_SymbolFlagsEnum { RDI_SymbolFlag_IsParam = 0x1, +RDI_SymbolFlag_IsThunk = 0x2, } RDI_SymbolFlagsEnum; typedef RDI_U8 RDI_LocationKind; diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 66d6c826..f7ee2a40 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -849,6 +849,7 @@ typedef struct RDIM_Symbol RDIM_Symbol; struct RDIM_Symbol { struct RDIM_SymbolChunkNode *chunk; + RDI_S32 is_thunk; RDI_S32 is_extern; RDI_S32 is_param; RDIM_String8 name; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 2ad9f1c4..309e5628 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -6634,18 +6634,14 @@ rd_window_frame(void) UI_PermissionFlag_All) { B32 has_footer = (is_lister && !is_anchored); - F32 container_corner_top_radius_px = is_lister ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f; - F32 container_corner_bottom_radius_px = has_footer ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f; + F32 container_corner_radius_px = has_footer ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f; // rjf: build top-level container box UI_Box *container = &ui_nil_box; UI_Rect(rect) UI_ChildLayoutAxis(Axis2_Y) UI_Squish(0.1f-0.1f*open_t) UI_Transparency(1.f-open_t) - UI_CornerRadius00(container_corner_top_radius_px) - UI_CornerRadius10(container_corner_top_radius_px) - UI_CornerRadius01(container_corner_bottom_radius_px) - UI_CornerRadius11(container_corner_bottom_radius_px) + UI_CornerRadius(container_corner_radius_px) { container = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBorder| @@ -11108,7 +11104,7 @@ rd_frame(void) for(HTTP_Response response = {0}; http_pop_response(rd_state->update_check_arena, rd_state->update_check_http_ring, &response, 0);) { str8_list_push(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, response.body); - if(response.has_more == 0) + if(!response.has_more) { done = 1; } @@ -12318,7 +12314,7 @@ rd_frame(void) }); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); expr->type_key = collection_type_key; - expr->space = e_space_make(RD_EvalSpaceKind_MetaCtrlEntity); + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); } diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 28baa269..a06ac207 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1020,6 +1020,7 @@ RDI_LocationKindTable: RDI_SymbolFlagTable: { {IsParam 0x1} + {IsThunk 0x2} } @table(name type desc) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 5d7c3cd2..19072fe5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3194,6 +3194,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) default:{}break; case CV_SymKind_LPROC32: case CV_SymKind_GPROC32: + case CV_SymKind_THUNK32: { procedure_record_count += 1; scope_record_count += 1; @@ -3600,6 +3601,35 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) proc_flags = proc32->flags; }break; + //- rjf: THUNK32 + case CV_SymKind_THUNK32: + { + // rjf: unpack record + CV_SymThunk32 *thunk32 = (CV_SymThunk32 *)iter.struct_base; + String8 name = str8_cstring_capped(thunk32+1, iter.opl); + COFF_SectionHeader *section = (0 < thunk32->sec && thunk32->sec <= coff_sections.count) ? &coff_sections.v[thunk32->sec-1] : 0; + U64 voff_first = 0; + U64 voff_opl = 0; + if(section != 0) + { + voff_first = section->voff + thunk32->off; + voff_opl = voff_first + thunk32->len; + } + + // rjf: build symbol / scope + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); + symbol->name = name; + symbol->is_thunk = 1; + if(voff_first != voff_opl) + { + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + RDIM_Rng1U64 range = {voff_first, voff_opl}; + rdim_scope_push_voff_range(arena, sym_scopes, scope, range); + scope->symbol = symbol; + symbol->root_scope = scope; + } + }break; + //- rjf: REGREL32 case CV_SymKind_REGREL32: { diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index c788c0fa..095672d7 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -3353,10 +3353,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); - if (src->is_param) + if(src->is_param) { dst->symbol_flags |= RDI_SymbolFlag_IsParam; } + if(src->is_thunk) + { + dst->symbol_flags |= RDI_SymbolFlag_IsThunk; + } // rjf: fill container info if(src->is_extern) diff --git a/src/win32/http/win32_http.c b/src/win32/http/win32_http.c index 0f6c3059..daa6f850 100644 --- a/src/win32/http/win32_http.c +++ b/src/win32/http/win32_http.c @@ -344,12 +344,24 @@ http_async_tick(void) DWORD status_code = 0; DWORD status_code_size = sizeof(status_code); WinHttpQueryHeaders(req->hRequest, - WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_size, WINHTTP_NO_HEADER_INDEX); req->status_code = status_code; } + // rjf: figure out total bytes + if(req->total_response_bytes == 0) + { + DWORD buffer_size = sizeof(req->total_response_bytes); + WinHttpQueryHeaders(req->hRequest, + WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER64, + WINHTTP_HEADER_NAME_BY_INDEX, + &req->total_response_bytes, + &buffer_size, + WINHTTP_NO_HEADER_INDEX); + } + // rjf: join all currently read body contents String8 body = str8_list_join(scratch.arena, &req->finished_body_pieces, 0); @@ -359,7 +371,7 @@ http_async_tick(void) // rjf: compute size per record header U64 max_record_size = req->out_ring->ring->size; - U64 bytes_per_record_header = sizeof(U64) + sizeof(U64) + sizeof(B32) + sizeof(HTTP_StatusCode); + U64 bytes_per_record_header = sizeof(U64) + sizeof(U64) + sizeof(U64) + sizeof(U64) + sizeof(B32) + sizeof(HTTP_StatusCode); // rjf: push response records for(U64 off = 0, next_off = 0; off <= body.size; off = next_off) @@ -383,6 +395,8 @@ http_async_tick(void) B32 has_more = !is_last; str8_list_push(scratch.arena, &pieces, str8_struct(&record_size)); str8_list_push(scratch.arena, &pieces, str8_struct(&req->id)); + str8_list_push(scratch.arena, &pieces, str8_struct(&req->total_response_bytes_sent)); + str8_list_push(scratch.arena, &pieces, str8_struct(&req->total_response_bytes)); str8_list_push(scratch.arena, &pieces, str8_struct(&has_more)); str8_list_push(scratch.arena, &pieces, str8_struct(&req->status_code)); str8_list_push(scratch.arena, &pieces, str8_substr(body, r1u64(off, next_off))); @@ -396,12 +410,18 @@ http_async_tick(void) if(!guarded_ring_write_string_or_wait(&g, record_data, 0)) { push_failed = 1; - String8 unpushed_body_piece = str8_substr(body, r1u64(off, next_off)); + String8 unpushed_body_piece = str8_substr(body, r1u64(off, body.size)); str8_list_push(req->arena, &req->finished_body_pieces, str8_copy(req->arena, unpushed_body_piece)); } guarded_ring_close(&g); } + // rjf: advance total bytes sent + if(!push_failed) + { + req->total_response_bytes_sent += (next_off - off); + } + // rjf: cancel on no movement if(next_off == off || push_failed) { @@ -528,6 +548,8 @@ http_pop_response(Arena *arena, GuardedRing *out_ring, HTTP_Response *response_o guarded_ring_read_or_wait(&g, data.size, data.str, max_U64); U64 off = 0; off += str8_deserial_read_struct(data, off, &response_out->id); + off += str8_deserial_read_struct(data, off, &response_out->off); + off += str8_deserial_read_struct(data, off, &response_out->off_opl); off += str8_deserial_read_struct(data, off, &response_out->has_more); off += str8_deserial_read_struct(data, off, &response_out->code); response_out->body.size = (data.size - off); diff --git a/src/win32/http/win32_http.h b/src/win32/http/win32_http.h index 75fe3d5c..d1fc8ac6 100644 --- a/src/win32/http/win32_http.h +++ b/src/win32/http/win32_http.h @@ -35,6 +35,8 @@ struct W32_HTTP_Request void *optional; // NOTE(rjf): must persist with in-flight requests U64 optional_size; HTTP_StatusCode status_code; + U64 total_response_bytes_sent; + U64 total_response_bytes; U64 arena_start_body_read_pos; String8List finished_body_pieces; void *next_body_piece; diff --git a/src/win32/symbol_server/win32_symbol_server.c b/src/win32/symbol_server/win32_symbol_server.c index 9b54a49b..74f5149c 100644 --- a/src/win32/symbol_server/win32_symbol_server.c +++ b/src/win32/symbol_server/win32_symbol_server.c @@ -201,7 +201,7 @@ smsv_async_tick(void) { str8_list_push(task->arena, &task->file_pieces, str8_copy(task->arena, r.body)); } - if(r.has_more == 0 && task->status != W32_SMSV_TaskStatus_DoneDownloading) + if(!r.has_more && task->status != W32_SMSV_TaskStatus_DoneDownloading) { task->status = W32_SMSV_TaskStatus_DoneDownloading; W32_SMSV_TaskNode *n = push_array(scratch.arena, W32_SMSV_TaskNode, 1); @@ -329,6 +329,11 @@ smsv_async_tick(void) } } write_data_list_to_file_path(task->local_path, task->file_pieces); + if(task->current_server_url_node != 0) + { + String8 origin_path = str8f(scratch.arena, "%S/origin.txt", str8_chop_last_slash(task->local_path)); + write_data_to_file_path(origin_path, task->current_server_url_node->string); + } } // rjf: evict task from cache