setting for auto-downloading missing debug info (off by default); command for manually loading module debug info as-needed

This commit is contained in:
Ryan Fleury
2026-06-09 14:01:09 -07:00
parent 0105b06fef
commit 5ae286d67e
13 changed files with 103 additions and 18 deletions
+3
View File
@@ -50,6 +50,9 @@ D_CmdTable: // | | | |
{SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" }
{SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" }
//- rjf: modules
{DownloadModuleDebugInfo 1 1 0 0 "query:modules" CtrlEntity null Nil Null 0 0 0 0 0 1 1 Module "download_module_debug_info" "Download Module Debug Info" "Tries to download a module's debug info from symbol server(s)." "" "" }
//- rjf: attaching
{Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" }
+22 -7
View File
@@ -379,6 +379,7 @@ d_serialized_string_from_msg_list(Arena *arena, D_MsgList *msgs)
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->exit_code);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_inherit);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->debug_subprocesses);
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->auto_download_debug_info);
str8_serial_push_array (scratch.arena, &msgs_srlzed, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
// rjf: write path string
@@ -479,6 +480,7 @@ d_msg_list_from_serialized_string(Arena *arena, String8 string)
read_off += str8_deserial_read_struct(string, read_off, &msg->exit_code);
read_off += str8_deserial_read_struct(string, read_off, &msg->env_inherit);
read_off += str8_deserial_read_struct(string, read_off, &msg->debug_subprocesses);
read_off += str8_deserial_read_struct(string, read_off, &msg->auto_download_debug_info);
read_off += str8_deserial_read_array (string, read_off, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
// rjf: read path string
@@ -2294,6 +2296,7 @@ d_ctrl_thread__entry_point(void *p)
MemoryZeroStruct(&d_ctrl_state->msg_user_bp_touched_files);
MemoryZeroStruct(&d_ctrl_state->msg_user_bp_touched_symbols);
MemoryCopyArray(d_ctrl_state->exception_code_filters, msg->exception_code_filters);
d_ctrl_state->auto_download_debug_info = msg->auto_download_debug_info;
}
//- rjf: gather all touched symbols by user breakpoints
@@ -2384,7 +2387,6 @@ d_ctrl_thread__entry_point(void *p)
}break;
case D_MsgKind_SetModuleDebugInfoPath:
{
D_EntityCtx *entity_ctx = &d_ctrl_state->ctrl_thread_entity_store->ctx;
String8 path = msg->path;
D_Entity *module = d_entity_from_handle(msg->entity);
D_Entity *debug_info_path = d_entity_child_from_kind(module, D_EntityKind_DebugInfoPath);
@@ -2433,7 +2435,6 @@ d_ctrl_thread__entry_point(void *p)
//- rjf: update thread register cache
ProfScope("update thread register cache")
{
D_EntityCtx *entity_ctx = &d_ctrl_state->ctrl_thread_entity_store->ctx;
D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread);
X64_RegBlock *blocks = push_array(scratch.arena, X64_RegBlock, threads.count);
{
@@ -2636,6 +2637,11 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
}
}
//////////////////////////////
//- rjf: compute local symbol server cache path for this debug info
//
String8 local_symbol_server_cache_path = smsv_local_path_from_key(scratch.arena, str8_skip_last_slash(module_info->debug_info_path), module_info->debug_info_guid, module_info->debug_info_age);
//////////////////////////////
//- rjf: pick default initial debug info path
//
@@ -2665,6 +2671,11 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
str8_list_pushf(scratch.arena, &candidates, "%S.rdi", exe_path);
}
// rjf: push local symbol server cache's path
{
str8_list_push(scratch.arena, &candidates, local_symbol_server_cache_path);
}
// rjf: pick first candidate that works
for EachNode(n, String8Node, candidates.first)
{
@@ -2679,14 +2690,15 @@ 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
//- rjf: no found debug info path -> try to fall back on symbol server cache path.
//
#if 1
if(initial_debug_info_path.size == 0)
// if it exists, we can just use it. if it doesn't, then we only want to pick it *if*
// automatic downloads are enabled.
//
if(initial_debug_info_path.size == 0 && d_ctrl_state->auto_download_debug_info)
{
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);
initial_debug_info_path = str8_copy(arena, local_symbol_server_cache_path);
}
#endif
//////////////////////////////
//- rjf: write 1 at attachment marker, to signify attachment
@@ -2706,6 +2718,9 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
info.unwinder = unwinder;
info.unwind_info = unwind_info_opaque;
info.local_debug_info_path = initial_debug_info_path;
info.dbg_name = str8_copy(arena, str8_skip_last_slash(module_info->debug_info_path));
info.dbg_guid = module_info->debug_info_guid;
info.dbg_age = module_info->debug_info_age;
info.raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
info.raddbg_data = raddbg_data;
}
+4
View File
@@ -169,6 +169,9 @@ struct D_ModuleInfo
UWND_Unwinder unwinder;
void *unwind_info;
String8 local_debug_info_path;
String8 dbg_name;
Guid dbg_guid;
U64 dbg_age;
U64 raddbg_attached_marker_voff;
String8 raddbg_data;
};
@@ -365,6 +368,7 @@ struct D_CtrlState
Arena *user_entry_point_arena;
String8List user_entry_points;
U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64];
B32 auto_download_debug_info;
U64 process_counter;
Arena *dbg_dir_arena;
D_DbgDirNode *dbg_dir_root;
+26 -1
View File
@@ -1582,7 +1582,7 @@ d_next_cmd(D_Cmd **cmd)
//~ rjf: Main Layer Top-Level Calls
internal D_EventList
d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64])
d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
@@ -1832,6 +1832,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->debug_subprocesses = target->debug_subprocesses;
msg->env_inherit = 1;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
str8_list_push(scratch.arena, &msg->entry_points, custom_entry_point_name);
msg->env_string_list = env;
}
@@ -1864,6 +1865,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->exit_code = 1;
msg->entity = process->handle;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}
}break;
case D_CmdKind_KillAll:
@@ -1872,6 +1874,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->kind = D_MsgKind_KillAll;
msg->exit_code = 1;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}break;
case D_CmdKind_Detach:
{
@@ -1886,6 +1889,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->kind = D_MsgKind_Detach;
msg->entity = process->handle;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}
}break;
case D_CmdKind_Continue:
@@ -2111,6 +2115,8 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
D_Msg *msg = d_msg_list_push(scratch.arena, &ctrl_msgs);
msg->kind = (should_freeze ? D_MsgKind_FreezeThread : D_MsgKind_ThawThread);
msg->entity = e->handle;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}
}
if(d_ctrl_targets_running())
@@ -2135,6 +2141,22 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
d_entity_equip_string(d_user_state->ctrl_entity_store, entity, params->string);
}break;
//- rjf: modules
case D_CmdKind_DownloadModuleDebugInfo:
{
Access *access = access_open();
D_ModuleInfo *info = d_info_from_module(access, params->entity);
String8 symbol_server_local_cache_path = smsv_local_path_from_key(scratch.arena, info->dbg_name, info->dbg_guid, info->dbg_age);
smsv_fill_local_path(symbol_server_local_cache_path);
D_Msg *msg = d_msg_list_push(scratch.arena, &ctrl_msgs);
msg->kind = D_MsgKind_SetModuleDebugInfoPath;
msg->entity = params->entity;
msg->path = symbol_server_local_cache_path;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
access_close(access);
}break;
//- rjf: attaching
case D_CmdKind_Attach:
{
@@ -2145,6 +2167,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->kind = D_MsgKind_Attach;
msg->entity_id = pid;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}
}break;
@@ -2156,6 +2179,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->kind = D_MsgKind_OpenCrashDump;
msg->path = str8_copy(scratch.arena, file_path);
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
}break;
}
@@ -2182,6 +2206,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
msg->entity = run_thread->handle;
msg->parent = process->handle;
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
msg->auto_download_debug_info = auto_download_debug_info;
MemoryCopyStruct(&msg->traps, &run_traps);
D_BreakpointArray *bp_batches[] =
{
+2 -1
View File
@@ -193,6 +193,7 @@ struct D_Msg
U32 exit_code;
B32 env_inherit;
B32 debug_subprocesses;
B32 auto_download_debug_info;
U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64];
String8 path;
String8List entry_points;
@@ -480,6 +481,6 @@ internal B32 d_next_cmd(D_Cmd **cmd);
////////////////////////////////
//~ rjf: Main Layer Top-Level Calls
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64]);
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info);
#endif // DBG_ENGINE_USER_H
@@ -42,6 +42,7 @@ D_CmdKind_FreezeEntity,
D_CmdKind_ThawEntity,
D_CmdKind_SetEntityColor,
D_CmdKind_SetEntityName,
D_CmdKind_DownloadModuleDebugInfo,
D_CmdKind_Attach,
D_CmdKind_OpenCrashDump,
D_CmdKind_COUNT,
+19 -3
View File
@@ -100,6 +100,15 @@ di_init(CmdLine *cmdline)
di_shared->event_arena = arena_alloc();
}
////////////////////////////////
//~ rjf: Settings Submission
internal void
di_set_auto_downloads(B32 auto_downloads)
{
ins_atomic_u32_eval_assign(&di_shared->auto_downloads, auto_downloads);
}
////////////////////////////////
//~ rjf: Path * Timestamp Cache Submission & Lookup
@@ -690,10 +699,17 @@ di_async_tick(void)
String8 symbol_cache_path = smsv_cache_path();
if(str8_match(symbol_cache_path, og_path, StringMatchFlag_RightSideSloppy|StringMatchFlag_SlashInsensitive))
{
og_is_downloading = 1;
smsv_fill_local_path(og_path);
if(di_shared->auto_downloads)
{
og_is_downloading = 1;
smsv_fill_local_path(og_path);
}
SMSV_Status status = smsv_status_from_local_path(og_path);
if(status == SMSV_Status_Null)
if(status == SMSV_Status_Pending)
{
og_is_downloading = 1;
}
else if(status == SMSV_Status_Null)
{
og_is_downloading = 0;
}
+8
View File
@@ -249,6 +249,9 @@ struct DI_Shared
U64 load_gen;
U64 load_count;
// rjf: settings
B32 auto_downloads;
// rjf: key -> path cache
U64 key2path_slots_count;
DI_KeySlot *key2path_slots;
@@ -315,6 +318,11 @@ internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
internal void di_init(CmdLine *cmdline);
////////////////////////////////
//~ rjf: Settings Submission
internal void di_set_auto_downloads(B32 auto_downloads);
////////////////////////////////
//~ rjf: Path * Timestamp Cache Submission & Lookup
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -98,6 +98,7 @@ RD_CmdKind_FreezeEntity,
RD_CmdKind_ThawEntity,
RD_CmdKind_SetEntityColor,
RD_CmdKind_SetEntityName,
RD_CmdKind_DownloadModuleDebugInfo,
RD_CmdKind_Attach,
RD_CmdKind_OpenCrashDump,
RD_CmdKind_Exit,
@@ -615,7 +616,7 @@ Z(getting_started)\
C_LINKAGE_BEGIN
extern String8 rd_tab_fast_path_view_name_table[25];
extern String8 rd_tab_fast_path_query_name_table[25];
extern RD_VocabInfo rd_vocab_info_table[367];
extern RD_VocabInfo rd_vocab_info_table[368];
extern RD_NameSchemaInfo rd_name_schema_info_table[39];
extern String8 rd_reg_slot_code_name_table[51];
extern Rng1U64 rd_reg_slot_range_table[51];
+4
View File
@@ -316,6 +316,10 @@ RD_VocabTable:
//- rjf: auto-load last project
@default(0) @display_name('Auto Load Last Project') @description("Enables loading the most recently opened project, if one is not specified from the command line.")
'auto_load_last_project': bool,
//- rjf: symbol server
@default(0) @display_name('Auto Download Debug Info') @Description("Automatically tries to download missing debug info from symbol server(s).")
'auto_download_debug_info': bool,
}
```
}
+4 -2
View File
@@ -11186,6 +11186,8 @@ rd_frame(void)
//////////////////////////////
//- rjf: apply debug info config trees -> loaded debug info cache
//
B32 auto_download_debug_info = rd_setting_b32_from_name(s("auto_download_debug_info"));
di_set_auto_downloads(auto_download_debug_info);
ProfScope("apply debug info config trees -> loaded debug info cache")
{
U64 current_update_tick_idx = update_tick_idx();
@@ -17319,7 +17321,7 @@ rd_frame(void)
}
////////////////////////////
//- rjf: gather exception code filters
//- rjf: gather debug engine settings
//
U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64] = {0};
{
@@ -17344,7 +17346,7 @@ rd_frame(void)
}
U64 cmd_count_pre_tick = rd_state->cmds[0].count;
B32 soft_halt_issued = d_user_state->ctrl_soft_halt_issued;
D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, exception_code_filters);
D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, exception_code_filters, auto_download_debug_info);
////////////////////////////
//- rjf: process debug engine events
+3
View File
@@ -4,6 +4,9 @@
////////////////////////////////
//~ rjf: post-0.9.26 TODO notes
//
// [ ] debug info loading retry mechanism, in cases where the load failed, but settings/filesystem state changes -
// e.g. turn on automatic downloads, already tried to load symbol server cache file that doesn't exist ->
// need to retry
// [ ] wassim memory bug
//
// [ ] symbol server