diff --git a/src/dbg_engine/dbg_engine.mdesk b/src/dbg_engine/dbg_engine.mdesk index b9672b36..2c054da3 100644 --- a/src/dbg_engine/dbg_engine.mdesk +++ b/src/dbg_engine/dbg_engine.mdesk @@ -88,6 +88,62 @@ D_EntityKindTable: {EndedProcess ended_process ended_processes 1 0 0 1 0 0 0 0 0 0 0 "Label" Null "EndedProcess" } } +//////////////////////////////// +//~ rjf: Registers Type Table + +@table(c_type name_lower name) +D_RegTable: +{ + // rjf: entity slots + {D_Handle module Module } + {D_Handle process Process } + {D_Handle thread Thread } + {D_Handle window Window } + {D_Handle panel Panel } + {D_Handle view View } + {D_Handle prev_view PrevView } + {D_Handle dst_panel DstPanel } + {D_Handle entity Entity } + {D_HandleList entity_list EntityList } + + // rjf: frame selection + {U64 unwind_count UnwindCount } + {U64 inline_depth InlineDepth } + + // rjf: code / address location info + {String8 file_path FilePath } + {TxtPt cursor Cursor } + {TxtPt mark Mark } + {U128 text_key TextKey } + {TXT_LangKind lang_kind LangKind } + {D_LineList lines Lines } + {DI_Key dbgi_key DbgiKey } + {Rng1U64 vaddr_range VaddrRange } + {Rng1U64 voff_range VoffRange } + + // rjf: general parameters + {B32 force_confirm ForceConfirm } + {B32 prefer_disasm PreferDisasm } + {Dir2 dir2 Dir2 } + {String8 string String } + {`MD_Node *` params_tree ParamsTree } +} + +@enum D_RegSlot: +{ + @expand(D_RegTable a) `$(a.name)` +} + +@struct D_Regs: +{ + @expand(D_RegTable a) `$(a.c_type) $(a.name_lower)` +} + +@data(Rng1U64) d_reg_slot_range_table: +{ + @expand(D_RegTable a) `{OffsetOf(D_Regs, $(a.name_lower)), OffsetOf(D_Regs, $(a.name_lower)) + sizeof($(a.c_type))}` +} + //////////////////////////////// //~ rjf: Built-In Command Tables @@ -613,7 +669,6 @@ DF_DevToggleTable: @data(Rng1U64) d_cmd_param_slot_range_table: { - `{0}`, @expand(D_CmdParamSlotTable a) `{OffsetOf(D_CmdParams, $(a.name_lower)), OffsetOf(D_CmdParams, $(a.name_lower)) + sizeof($(a.c_type))}`, } diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 24ecbbab..dac37e07 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -100,7 +100,7 @@ d_handle_list_find(D_HandleList *list, D_Handle handle) } internal D_HandleList -d_push_handle_list_copy(Arena *arena, D_HandleList list) +d_handle_list_copy(Arena *arena, D_HandleList list) { D_HandleList result = {0}; for(D_HandleNode *n = list.first; n != 0; n = n->next) @@ -110,6 +110,29 @@ d_push_handle_list_copy(Arena *arena, D_HandleList list) return result; } +//////////////////////////////// +//~ rjf: Registers Type Pure Functions + +internal void +d_regs_copy_contents(Arena *arena, D_Regs *dst, D_Regs *src) +{ + MemoryCopyStruct(dst, src); + dst->entity_list = d_handle_list_copy(arena, src->entity_list); + dst->file_path = push_str8_copy(arena, src->file_path); + dst->lines = d_line_list_copy(arena, &src->lines); + dst->dbgi_key = di_key_copy(arena, &src->dbgi_key); + dst->string = push_str8_copy(arena, src->string); + dst->params_tree = md_tree_copy(arena, src->params_tree); +} + +internal D_Regs * +d_regs_copy(Arena *arena, D_Regs *src) +{ + D_Regs *dst = push_array(arena, D_Regs, 1); + d_regs_copy_contents(arena, dst, src); + return dst; +} + //////////////////////////////// //~ rjf: State History Data Structure @@ -6351,9 +6374,7 @@ d_begin_frame(Arena *arena, D_CmdList *cmds, F32 dt) d_state->dt = dt; d_state->time_in_seconds += dt; d_state->top_regs = &d_state->base_regs; - d_state->top_regs->v.file_path = push_str8_copy(d_frame_arena(), d_state->top_regs->v.file_path); - d_state->top_regs->v.lines = d_line_list_copy(d_frame_arena(), &d_state->top_regs->v.lines); - d_state->top_regs->v.dbgi_key = di_key_copy(d_frame_arena(), &d_state->top_regs->v.dbgi_key); + d_regs_copy_contents(d_frame_arena(), &d_state->top_regs->v, &d_state->top_regs->v); //- rjf: sync with ctrl thread ProfScope("sync with ctrl thread") diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index b3b9cc61..42cf1b6c 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -29,6 +29,41 @@ struct D_HandleList U64 count; }; +//////////////////////////////// +//~ rjf: Line Info Types + +typedef struct D_Line D_Line; +struct D_Line +{ + String8 file_path; + TxtPt pt; + Rng1U64 voff_range; + DI_Key dbgi_key; +}; + +typedef struct D_LineNode D_LineNode; +struct D_LineNode +{ + D_LineNode *next; + D_Line v; +}; + +typedef struct D_LineList D_LineList; +struct D_LineList +{ + D_LineNode *first; + D_LineNode *last; + U64 count; +}; + +typedef struct D_LineListArray D_LineListArray; +struct D_LineListArray +{ + D_LineList *v; + U64 count; + DI_KeyList dbgi_keys; +}; + //////////////////////////////// //~ rjf: Sparse Tree Expansion State Data Structure @@ -401,64 +436,7 @@ struct D_Unwind }; //////////////////////////////// -//~ rjf: Line Info Types - -typedef struct D_Line D_Line; -struct D_Line -{ - String8 file_path; - TxtPt pt; - Rng1U64 voff_range; - DI_Key dbgi_key; -}; - -typedef struct D_LineNode D_LineNode; -struct D_LineNode -{ - D_LineNode *next; - D_Line v; -}; - -typedef struct D_LineList D_LineList; -struct D_LineList -{ - D_LineNode *first; - D_LineNode *last; - U64 count; -}; - -typedef struct D_LineListArray D_LineListArray; -struct D_LineListArray -{ - D_LineList *v; - U64 count; - DI_KeyList dbgi_keys; -}; - -//////////////////////////////// -//~ rjf: Interaction Context Register Types - -typedef struct D_Regs D_Regs; -struct D_Regs -{ - D_Handle module; - D_Handle process; - D_Handle thread; - U64 unwind_count; - U64 inline_depth; - D_Handle window; - D_Handle panel; - D_Handle view; - String8 file_path; - TxtPt cursor; - TxtPt mark; - U128 text_key; - TXT_LangKind lang_kind; - Rng1U64 vaddr_range; - Rng1U64 voff_range; - D_LineList lines; - DI_Key dbgi_key; -}; +//~ rjf: Context Register Types typedef struct D_RegsNode D_RegsNode; struct D_RegsNode @@ -1110,7 +1088,13 @@ internal void d_handle_list_push_node(D_HandleList *list, D_HandleNode *node); internal void d_handle_list_push(Arena *arena, D_HandleList *list, D_Handle handle); internal void d_handle_list_remove(D_HandleList *list, D_HandleNode *node); internal D_HandleNode *d_handle_list_find(D_HandleList *list, D_Handle handle); -internal D_HandleList d_push_handle_list_copy(Arena *arena, D_HandleList list); +internal D_HandleList d_handle_list_copy(Arena *arena, D_HandleList list); + +//////////////////////////////// +//~ rjf: Registers Type Pure Functions + +internal void d_regs_copy_contents(Arena *arena, D_Regs *dst, D_Regs *src); +internal D_Regs *d_regs_copy(Arena *arena, D_Regs *src); //////////////////////////////// //~ rjf: State History Data Structure diff --git a/src/dbg_engine/generated/dbg_engine.meta.c b/src/dbg_engine/generated/dbg_engine.meta.c index 6b81b010..d82a7f5c 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.c +++ b/src/dbg_engine/generated/dbg_engine.meta.c @@ -4,9 +4,38 @@ //- GENERATED CODE C_LINKAGE_BEGIN -Rng1U64 d_cmd_param_slot_range_table[24] = +Rng1U64 d_reg_slot_range_table[26] = +{ +{OffsetOf(D_Regs, module), OffsetOf(D_Regs, module) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, process), OffsetOf(D_Regs, process) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, thread), OffsetOf(D_Regs, thread) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, window), OffsetOf(D_Regs, window) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, panel), OffsetOf(D_Regs, panel) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, view), OffsetOf(D_Regs, view) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, prev_view), OffsetOf(D_Regs, prev_view) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, dst_panel), OffsetOf(D_Regs, dst_panel) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, entity), OffsetOf(D_Regs, entity) + sizeof(D_Handle)}, +{OffsetOf(D_Regs, entity_list), OffsetOf(D_Regs, entity_list) + sizeof(D_HandleList)}, +{OffsetOf(D_Regs, unwind_count), OffsetOf(D_Regs, unwind_count) + sizeof(U64)}, +{OffsetOf(D_Regs, inline_depth), OffsetOf(D_Regs, inline_depth) + sizeof(U64)}, +{OffsetOf(D_Regs, file_path), OffsetOf(D_Regs, file_path) + sizeof(String8)}, +{OffsetOf(D_Regs, cursor), OffsetOf(D_Regs, cursor) + sizeof(TxtPt)}, +{OffsetOf(D_Regs, mark), OffsetOf(D_Regs, mark) + sizeof(TxtPt)}, +{OffsetOf(D_Regs, text_key), OffsetOf(D_Regs, text_key) + sizeof(U128)}, +{OffsetOf(D_Regs, lang_kind), OffsetOf(D_Regs, lang_kind) + sizeof(TXT_LangKind)}, +{OffsetOf(D_Regs, lines), OffsetOf(D_Regs, lines) + sizeof(D_LineList)}, +{OffsetOf(D_Regs, dbgi_key), OffsetOf(D_Regs, dbgi_key) + sizeof(DI_Key)}, +{OffsetOf(D_Regs, vaddr_range), OffsetOf(D_Regs, vaddr_range) + sizeof(Rng1U64)}, +{OffsetOf(D_Regs, voff_range), OffsetOf(D_Regs, voff_range) + sizeof(Rng1U64)}, +{OffsetOf(D_Regs, force_confirm), OffsetOf(D_Regs, force_confirm) + sizeof(B32)}, +{OffsetOf(D_Regs, prefer_disasm), OffsetOf(D_Regs, prefer_disasm) + sizeof(B32)}, +{OffsetOf(D_Regs, dir2), OffsetOf(D_Regs, dir2) + sizeof(Dir2)}, +{OffsetOf(D_Regs, string), OffsetOf(D_Regs, string) + sizeof(String8)}, +{OffsetOf(D_Regs, params_tree), OffsetOf(D_Regs, params_tree) + sizeof(MD_Node *)}, +}; + +Rng1U64 d_cmd_param_slot_range_table[23] = { -{0}, {OffsetOf(D_CmdParams, window), OffsetOf(D_CmdParams, window) + sizeof(D_Handle)}, {OffsetOf(D_CmdParams, panel), OffsetOf(D_CmdParams, panel) + sizeof(D_Handle)}, {OffsetOf(D_CmdParams, dest_panel), OffsetOf(D_CmdParams, dest_panel) + sizeof(D_Handle)}, diff --git a/src/dbg_engine/generated/dbg_engine.meta.h b/src/dbg_engine/generated/dbg_engine.meta.h index 25a37882..91bf2a52 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.h +++ b/src/dbg_engine/generated/dbg_engine.meta.h @@ -6,6 +6,36 @@ #ifndef DBG_ENGINE_META_H #define DBG_ENGINE_META_H +typedef enum D_RegSlot +{ +D_RegSlot_Module, +D_RegSlot_Process, +D_RegSlot_Thread, +D_RegSlot_Window, +D_RegSlot_Panel, +D_RegSlot_View, +D_RegSlot_PrevView, +D_RegSlot_DstPanel, +D_RegSlot_Entity, +D_RegSlot_EntityList, +D_RegSlot_UnwindCount, +D_RegSlot_InlineDepth, +D_RegSlot_FilePath, +D_RegSlot_Cursor, +D_RegSlot_Mark, +D_RegSlot_TextKey, +D_RegSlot_LangKind, +D_RegSlot_Lines, +D_RegSlot_DbgiKey, +D_RegSlot_VaddrRange, +D_RegSlot_VoffRange, +D_RegSlot_ForceConfirm, +D_RegSlot_PreferDisasm, +D_RegSlot_Dir2, +D_RegSlot_String, +D_RegSlot_ParamsTree, +} D_RegSlot; + typedef enum D_CfgSrc { D_CfgSrc_User, @@ -332,6 +362,37 @@ D_CmdParamSlot_InlineDepth, D_CmdParamSlot_COUNT, } D_CmdParamSlot; +typedef struct D_Regs D_Regs; +struct D_Regs +{ +D_Handle module; +D_Handle process; +D_Handle thread; +D_Handle window; +D_Handle panel; +D_Handle view; +D_Handle prev_view; +D_Handle dst_panel; +D_Handle entity; +D_HandleList entity_list; +U64 unwind_count; +U64 inline_depth; +String8 file_path; +TxtPt cursor; +TxtPt mark; +U128 text_key; +TXT_LangKind lang_kind; +D_LineList lines; +DI_Key dbgi_key; +Rng1U64 vaddr_range; +Rng1U64 voff_range; +B32 force_confirm; +B32 prefer_disasm; +Dir2 dir2; +String8 string; +MD_Node * params_tree; +}; + typedef struct D_CmdParams D_CmdParams; struct D_CmdParams { @@ -399,7 +460,8 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = {&DEV_updating_indicator, str8_lit_comp("updating_indicator")}, }; C_LINKAGE_BEGIN -extern Rng1U64 d_cmd_param_slot_range_table[24]; +extern Rng1U64 d_reg_slot_range_table[26]; +extern Rng1U64 d_cmd_param_slot_range_table[23]; extern String8 d_entity_kind_display_string_table[31]; extern String8 d_entity_kind_name_lower_table[31]; extern String8 d_entity_kind_name_lower_plural_table[31]; diff --git a/src/dbg_frontend/dbg_frontend_core.c b/src/dbg_frontend/dbg_frontend_core.c index a566aad9..f9662aa5 100644 --- a/src/dbg_frontend/dbg_frontend_core.c +++ b/src/dbg_frontend/dbg_frontend_core.c @@ -488,7 +488,7 @@ df_cmd_params_copy(Arena *arena, D_CmdParams *src) { D_CmdParams dst = {0}; MemoryCopyStruct(&dst, src); - dst.entity_list = d_push_handle_list_copy(arena, src->entity_list); + dst.entity_list = d_handle_list_copy(arena, src->entity_list); if(dst.entity_list.count == 0 && !d_handle_match(src->entity, d_handle_zero())) { d_handle_list_push(arena, &dst.entity_list, dst.entity); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index d131f933..1e961e87 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -3,47 +3,49 @@ //////////////////////////////// //~ rjf: Frontend/UI Pass Tasks -// -// [ ] engine/frontend commands situation -// - currently, there is an interesting bifurcation of commands in the -// frontend; you can either push a command *at a root level*, or push a -// command to a locally-accessible list if you want that command to run -// on the same frame (root level commands are deferred by a frame, since -// the engine must see them first). -// - things would be simpler if there was only a single "push command" -// mechanism, and codepaths only ever saw these commands at most once. -// this would require an alternate strategy of the initial "gather" of -// commands, and instead it would just be a global queue, or something... -// it is a little weird since commands are not just consumed in order... -// - this will clean up the various different ways that codepaths -// parameterize commands. -// [ ] frontend entities vs. engine entities -// - currently, the engine has entities like "watch", and the frontend -// has entities like "windows", "panels", and "views". -// - because "watch" entities ideally have a hierarchical relationship -// with windows, panels, and views (enabling things like drag/drop -// from watch window -> tab, or tab -> watch window, trivially), it -// would be much better if all entities could collapse into engine -// entities. -// - now, the frontend requires various specialized resources for things -// like windows, so what I am thinking is that the engine just controls -// all of the stateful windows/panel/view/watch mechanisms, and then -// the frontend pure-functionally queries stuff like os/r handles -// on-demand, and then prunes them, immediate-mode cache style. -// [ ] command params -> d_regs -// - currently there are two almost-identical concepts relating to commands: -// the parameters struct, and D_Regs. D_Regs is a registers struct which -// is used to manage a stack of contextual information in various debugger -// codepaths. it is used so that codepaths can register information they -// know about, without passing it down to everyone explicitly - but those -// later codepaths can still pass that information along. e.g. a window -// calls into a watch window, watch window calls into visualizer, visualizer -// pushes command, which needs to pass which window it occurred on along. -// - i think D_Regs needs to expand a bit in order to encompass all of the -// things that the command parameters were being used for, but at that point -// commands can just be a spec * regs, and then the push-command API can -// just have ways of overriding regs values explicitly, when the codepath -// needs to be opinionated about which things are affected by which commands +// +// [ ] empty user file causing failure to launch +// +// [ ] engine/frontend commands situation +// - currently, there is an interesting bifurcation of commands in the +// frontend; you can either push a command *at a root level*, or push a +// command to a locally-accessible list if you want that command to run +// on the same frame (root level commands are deferred by a frame, since +// the engine must see them first). +// - things would be simpler if there was only a single "push command" +// mechanism, and codepaths only ever saw these commands at most once. +// this would require an alternate strategy of the initial "gather" of +// commands, and instead it would just be a global queue, or something... +// it is a little weird since commands are not just consumed in order... +// - this will clean up the various different ways that codepaths +// parameterize commands. +// [ ] frontend entities vs. engine entities +// - currently, the engine has entities like "watch", and the frontend +// has entities like "windows", "panels", and "views". +// - because "watch" entities ideally have a hierarchical relationship +// with windows, panels, and views (enabling things like drag/drop +// from watch window -> tab, or tab -> watch window, trivially), it +// would be much better if all entities could collapse into engine +// entities. +// - now, the frontend requires various specialized resources for things +// like windows, so what I am thinking is that the engine just controls +// all of the stateful windows/panel/view/watch mechanisms, and then +// the frontend pure-functionally queries stuff like os/r handles +// on-demand, and then prunes them, immediate-mode cache style. +// [ ] command params -> d_regs +// - currently there are two almost-identical concepts relating to commands: +// the parameters struct, and D_Regs. D_Regs is a registers struct which +// is used to manage a stack of contextual information in various debugger +// codepaths. it is used so that codepaths can register information they +// know about, without passing it down to everyone explicitly - but those +// later codepaths can still pass that information along. e.g. a window +// calls into a watch window, watch window calls into visualizer, visualizer +// pushes command, which needs to pass which window it occurred on along. +// - i think D_Regs needs to expand a bit in order to encompass all of the +// things that the command parameters were being used for, but at that point +// commands can just be a spec * regs, and then the push-command API can +// just have ways of overriding regs values explicitly, when the codepath +// needs to be opinionated about which things are affected by which commands // // [ ] transient view timeout releasing // @@ -431,28 +433,28 @@ // against stopper thread's // // [x] PDB files distributed with the build are not found by DbgHelp!!! -// [x] Jai compiler debugging crash -// -//- 2024/8/29 +// [x] Jai compiler debugging crash +// +//- 2024/8/29 // // [x] fix HRESULTs // [x] fix escape char literals // [x] eval: indexing into string literals // [x] fix incorrectly consuming keyboard inputs, preventing fallback-to-filtering, when -// selecting null selection in watch views +// selecting null selection in watch views // [x] ui_next_event(...), built-in focus filtering, no need to manually check -// if(ui_is_focus_active()) +// if(ui_is_focus_active()) // [x] Theme window should include font scaling. I was able to find the // command for increasing the font scale, but I imagine most people -// wouldn't think to look there. +// wouldn't think to look there. // [x] n-row table selection, in watch window & other UIs, multi-selection // ctrl+C -// [x] target/breakpoint/watch-pin reordering -// [x] move breakpoints to being a global thing, not nested to particular files +// [x] target/breakpoint/watch-pin reordering +// [x] move breakpoints to being a global thing, not nested to particular files // [x] EVAL SPACES - each rdi gets an rdi space, rdi space is passed to -// memory reads & so on, used to resolve to value space; REPLACES "mode" +// memory reads & so on, used to resolve to value space; REPLACES "mode" // [x] fix selecting hover eval, then hover eval disappearing, causing -// busted focus, until a new hover eval is opened +// busted focus, until a new hover eval is opened // [x] `text[:lang]` - interpret memory as text, in lang `lang` // [x] `disasm:arch` - interpret memory as machine code for isa `arch` // [x] `memory` - view memory in usual memory hex-editor view @@ -461,21 +463,21 @@ // view, or memory view will simply be specializations of the general purpose // viz system. // [x] view rule hook for standalone visualization ui, granted its own -// tab +// tab // [x] collapse frontend visualization systems - source view, disasm view, -// callstack, modules, scheduler, should *all* be flavors of watch view -// [x] globally disable/configure bp/ip lines in source view +// callstack, modules, scheduler, should *all* be flavors of watch view +// [x] globally disable/configure bp/ip lines in source view // [x] @cleanup naming pass over eval visualization part of the frontend, -// "blocks" vs. "canvas" vs. "expansion" - etc. +// "blocks" vs. "canvas" vs. "expansion" - etc. // [x] @cleanup collapse DF_CfgNodes into just being MD trees, find another way -// to encode config source - don't need it at every node +// to encode config source - don't need it at every node // [x] @cleanup in the frontend, we are starting to have to pass down "DF_Window" // everywhere, because of per-window parameters (e.g. font rendering settings). // this is really better solved by implicit thread-local parameters, similar to // interaction registers, so that one window can "pick" all of the implicit -// parameters, and then 99% of the UI code does not have to care. +// parameters, and then 99% of the UI code does not have to care. // [x] @cleanup simplification pass over eval visualization pipeline & types, -// including view rule hooks +// including view rule hooks #ifndef RADDBG_H #define RADDBG_H