From b9ac10427688397c6dabc9831a06e87987def73a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 20 May 2024 17:15:11 -0700 Subject: [PATCH] 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