mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
fix line info voff baking; default selected inline frame depth to being shallowest; rework rich unwind to not lose concrete/inline frame structured info
This commit is contained in:
+50
-75
@@ -923,15 +923,15 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams
|
||||
params->index = u64;
|
||||
df_cmd_params_mark_slot(params, DF_CmdParamSlot_Index);
|
||||
}break;
|
||||
case DF_CmdParamSlot_BaseUnwindIndex:
|
||||
case DF_CmdParamSlot_UnwindIndex:
|
||||
{
|
||||
params->base_unwind_index = u64;
|
||||
df_cmd_params_mark_slot(params, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
params->unwind_index = u64;
|
||||
df_cmd_params_mark_slot(params, DF_CmdParamSlot_UnwindIndex);
|
||||
}break;
|
||||
case DF_CmdParamSlot_InlineUnwindIndex:
|
||||
case DF_CmdParamSlot_InlineDepth:
|
||||
{
|
||||
params->inline_unwind_index = u64;
|
||||
df_cmd_params_mark_slot(params, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
params->inline_depth = u64;
|
||||
df_cmd_params_mark_slot(params, DF_CmdParamSlot_InlineDepth);
|
||||
}break;
|
||||
case DF_CmdParamSlot_ID:
|
||||
{
|
||||
@@ -3241,7 +3241,7 @@ df_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
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);
|
||||
DF_LineNode *n = push_array(arena, DF_LineNode, 1);
|
||||
SLLQueuePush(result.first, result.last, n);
|
||||
SLLQueuePushFront(result.first, result.last, n);
|
||||
result.count += 1;
|
||||
if(line->file_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
@@ -3671,80 +3671,44 @@ df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates)
|
||||
internal DF_Unwind
|
||||
df_unwind_from_ctrl_unwind(Arena *arena, DI_Scope *di_scope, DF_Entity *process, CTRL_Unwind *base_unwind)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DF_UnwindFrameList rich_frames_list = {0};
|
||||
Architecture arch = df_architecture_from_entity(process);
|
||||
for(U64 base_frame_idx = 0; base_frame_idx < base_unwind->frames.count; base_frame_idx += 1)
|
||||
DF_Unwind result = {0};
|
||||
result.frames.concrete_frame_count = base_unwind->frames.count;
|
||||
result.frames.total_frame_count = result.frames.concrete_frame_count;
|
||||
result.frames.v = push_array(arena, DF_UnwindFrame, result.frames.concrete_frame_count);
|
||||
for(U64 idx = 0; idx < result.frames.concrete_frame_count; idx += 1)
|
||||
{
|
||||
CTRL_UnwindFrame *base_frame = &base_unwind->frames.v[base_frame_idx];
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(arch, base_frame->regs);
|
||||
CTRL_UnwindFrame *src = &base_unwind->frames.v[idx];
|
||||
DF_UnwindFrame *dst = &result.frames.v[idx];
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(arch, src->regs);
|
||||
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
|
||||
U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr);
|
||||
DI_Key dbgi_key = df_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0);
|
||||
RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff);
|
||||
|
||||
// rjf: add rich frames for inlines
|
||||
U64 inline_unwind_idx = 0;
|
||||
for(RDI_Scope *s = scope; s->inline_site_idx != 0; s = rdi_element_from_name_idx(rdi, Scopes, s->parent_scope_idx))
|
||||
// rjf: fill concrete frame info
|
||||
dst->regs = src->regs;
|
||||
dst->rdi = rdi;
|
||||
dst->procedure = rdi_element_from_name_idx(rdi, Procedures, scope->proc_idx);
|
||||
|
||||
// rjf: push inline frames
|
||||
for(RDI_Scope *s = scope;
|
||||
s->inline_site_idx != 0;
|
||||
s = rdi_element_from_name_idx(rdi, Scopes, s->parent_scope_idx))
|
||||
{
|
||||
RDI_InlineSite *site = rdi_element_from_name_idx(rdi, InlineSites, s->inline_site_idx);
|
||||
DF_UnwindFrameNode *n = push_array(scratch.arena, DF_UnwindFrameNode, 1);
|
||||
SLLQueuePush(rich_frames_list.first, rich_frames_list.last, n);
|
||||
rich_frames_list.count += 1;
|
||||
n->v.regs = base_frame->regs;
|
||||
n->v.rdi = rdi;
|
||||
n->v.procedure = 0;
|
||||
n->v.inline_site = site;
|
||||
n->v.base_unwind_idx = base_frame_idx;
|
||||
n->v.inline_unwind_idx = inline_unwind_idx;
|
||||
inline_unwind_idx += 1;
|
||||
}
|
||||
|
||||
// rjf: add frame for concrete frame
|
||||
DF_UnwindFrameNode *n = push_array(scratch.arena, DF_UnwindFrameNode, 1);
|
||||
SLLQueuePush(rich_frames_list.first, rich_frames_list.last, n);
|
||||
rich_frames_list.count += 1;
|
||||
n->v.regs = base_frame->regs;
|
||||
n->v.rdi = rdi;
|
||||
n->v.procedure = rdi_element_from_name_idx(rdi, Procedures, scope->proc_idx);
|
||||
n->v.inline_site = 0;
|
||||
n->v.base_unwind_idx = base_frame_idx;
|
||||
n->v.inline_unwind_idx = inline_unwind_idx;
|
||||
inline_unwind_idx = 0;
|
||||
}
|
||||
DF_Unwind result = {0};
|
||||
{
|
||||
result.frames.count = rich_frames_list.count;
|
||||
result.frames.v = push_array(arena, DF_UnwindFrame, result.frames.count);
|
||||
U64 idx = 0;
|
||||
for(DF_UnwindFrameNode *n = rich_frames_list.first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
MemoryCopyStruct(&result.frames.v[idx], &n->v);
|
||||
DF_UnwindInlineFrame *inline_frame = push_array(arena, DF_UnwindInlineFrame, 1);
|
||||
DLLPushFront(dst->first_inline_frame, dst->last_inline_frame, inline_frame);
|
||||
inline_frame->inline_site = site;
|
||||
dst->inline_frame_count += 1;
|
||||
result.frames.inline_frame_count += 1;
|
||||
result.frames.total_frame_count += 1;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal DF_UnwindFrame *
|
||||
df_frame_from_unwind_idxs(DF_Unwind *unwind, U64 base_unwind_idx, U64 inline_unwind_idx)
|
||||
{
|
||||
DF_UnwindFrame *f = 0;
|
||||
for(U64 idx = 0; idx < unwind->frames.count; idx += 1)
|
||||
{
|
||||
if(unwind->frames.v[idx].base_unwind_idx == base_unwind_idx)
|
||||
{
|
||||
f = &unwind->frames.v[idx];
|
||||
if(unwind->frames.v[idx].inline_unwind_idx == inline_unwind_idx)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Target Controls
|
||||
|
||||
@@ -3870,7 +3834,7 @@ df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_Tra
|
||||
|
||||
// rjf: set control context to top unwind
|
||||
df_state->ctrl_ctx.unwind_count = 0;
|
||||
df_state->ctrl_ctx.inline_unwind_count = 0;
|
||||
df_state->ctrl_ctx.inline_depth = 0;
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -5731,7 +5695,7 @@ df_ctrl_ctx_apply_overrides(DF_CtrlCtx *ctx, DF_CtrlCtx *overrides)
|
||||
{
|
||||
ctx->thread = overrides->thread;
|
||||
ctx->unwind_count = overrides->unwind_count;
|
||||
ctx->inline_unwind_count = overrides->inline_unwind_count;
|
||||
ctx->inline_depth = overrides->inline_depth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6531,8 +6495,8 @@ df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec)
|
||||
if(params->vaddr != 0) { log_infof("vaddr: 0x%I64x\n", params->vaddr); }
|
||||
if(params->voff != 0) { log_infof("voff: 0x%I64x\n", params->voff); }
|
||||
if(params->index != 0) { log_infof("index: 0x%I64x\n", params->index); }
|
||||
if(params->base_unwind_index != 0) { log_infof("base_unwind_index: 0x%I64x\n", params->base_unwind_index); }
|
||||
if(params->inline_unwind_index != 0){ log_infof("inline_unwind_index: 0x%I64x\n", params->inline_unwind_index); }
|
||||
if(params->unwind_index != 0) { log_infof("unwind_index: 0x%I64x\n", params->unwind_index); }
|
||||
if(params->inline_depth != 0) { log_infof("inline_depth: 0x%I64x\n", params->inline_depth); }
|
||||
if(params->id != 0) { log_infof("id: 0x%I64x\n", params->id); }
|
||||
if(params->os_event != 0)
|
||||
{
|
||||
@@ -7646,17 +7610,23 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
|
||||
CTRL_Unwind base_unwind = df_query_cached_unwind_from_thread(thread);
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
|
||||
DF_UnwindFrame *frame = df_frame_from_unwind_idxs(&rich_unwind, params.base_unwind_index, params.inline_unwind_index);
|
||||
if(frame != 0)
|
||||
if(params.unwind_index < rich_unwind.frames.concrete_frame_count)
|
||||
{
|
||||
df_state->ctrl_ctx.unwind_count = frame->base_unwind_idx;
|
||||
df_state->ctrl_ctx.inline_unwind_count = frame->inline_unwind_idx;
|
||||
DF_UnwindFrame *frame = &rich_unwind.frames.v[params.unwind_index];
|
||||
df_state->ctrl_ctx.unwind_count = params.unwind_index;
|
||||
df_state->ctrl_ctx.inline_depth = 0;
|
||||
if(params.inline_depth < frame->inline_frame_count)
|
||||
{
|
||||
df_state->ctrl_ctx.inline_depth = params.inline_depth;
|
||||
}
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
}break;
|
||||
case DF_CoreCmdKind_UpOneFrame:
|
||||
case DF_CoreCmdKind_DownOneFrame:
|
||||
{
|
||||
// TODO(rjf)
|
||||
#if 0
|
||||
DF_CtrlCtx ctrl_ctx = df_ctrl_ctx();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread);
|
||||
@@ -7664,6 +7634,10 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
CTRL_Unwind base_unwind = df_query_cached_unwind_from_thread(thread);
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
|
||||
DF_UnwindFrame *current_frame = 0;
|
||||
if(ctrl_ctx.unwind_count < rich_unwind.frames.concrete_frame_count)
|
||||
{
|
||||
current_frame = &rich_unwind.frames.v[ctrl_ctx.unwind_count];
|
||||
}
|
||||
for(U64 idx = 0; idx < rich_unwind.frames.count; idx += 1)
|
||||
{
|
||||
if(rich_unwind.frames.v[idx].base_unwind_idx == ctrl_ctx.unwind_count &&
|
||||
@@ -7702,6 +7676,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind));
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
#endif
|
||||
}break;
|
||||
case DF_CoreCmdKind_FreezeThread:
|
||||
case DF_CoreCmdKind_ThawThread:
|
||||
@@ -8999,7 +8974,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
df_interact_regs()->module = df_handle_from_entity(module);
|
||||
df_interact_regs()->process = df_handle_from_entity(process);
|
||||
df_interact_regs()->unwind_count = df_state->ctrl_ctx.unwind_count;
|
||||
df_interact_regs()->inline_unwind_count = df_state->ctrl_ctx.inline_unwind_count;
|
||||
df_interact_regs()->inline_depth = df_state->ctrl_ctx.inline_depth;
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
|
||||
+16
-22
@@ -77,7 +77,7 @@ struct DF_CtrlCtx
|
||||
{
|
||||
DF_Handle thread;
|
||||
U64 unwind_count;
|
||||
U64 inline_unwind_count;
|
||||
U64 inline_depth;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -452,37 +452,32 @@ struct DF_EntityFuzzyItemArray
|
||||
////////////////////////////////
|
||||
//~ rjf: Rich (Including Inline) Unwind Types
|
||||
|
||||
typedef struct DF_UnwindInlineFrame DF_UnwindInlineFrame;
|
||||
struct DF_UnwindInlineFrame
|
||||
{
|
||||
DF_UnwindInlineFrame *next;
|
||||
DF_UnwindInlineFrame *prev;
|
||||
RDI_InlineSite *inline_site;
|
||||
};
|
||||
|
||||
typedef struct DF_UnwindFrame DF_UnwindFrame;
|
||||
struct DF_UnwindFrame
|
||||
{
|
||||
DF_UnwindInlineFrame *first_inline_frame;
|
||||
DF_UnwindInlineFrame *last_inline_frame;
|
||||
U64 inline_frame_count;
|
||||
void *regs;
|
||||
RDI_Parsed *rdi;
|
||||
RDI_Procedure *procedure;
|
||||
RDI_InlineSite *inline_site;
|
||||
U64 base_unwind_idx;
|
||||
U64 inline_unwind_idx;
|
||||
};
|
||||
|
||||
typedef struct DF_UnwindFrameNode DF_UnwindFrameNode;
|
||||
struct DF_UnwindFrameNode
|
||||
{
|
||||
DF_UnwindFrameNode *next;
|
||||
DF_UnwindFrame v;
|
||||
};
|
||||
|
||||
typedef struct DF_UnwindFrameList DF_UnwindFrameList;
|
||||
struct DF_UnwindFrameList
|
||||
{
|
||||
DF_UnwindFrameNode *first;
|
||||
DF_UnwindFrameNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DF_UnwindFrameArray DF_UnwindFrameArray;
|
||||
struct DF_UnwindFrameArray
|
||||
{
|
||||
DF_UnwindFrame *v;
|
||||
U64 count;
|
||||
U64 concrete_frame_count;
|
||||
U64 inline_frame_count;
|
||||
U64 total_frame_count;
|
||||
};
|
||||
|
||||
typedef struct DF_Unwind DF_Unwind;
|
||||
@@ -598,7 +593,7 @@ struct DF_InteractRegs
|
||||
DF_Handle process;
|
||||
DF_Handle thread;
|
||||
U64 unwind_count;
|
||||
U64 inline_unwind_count;
|
||||
U64 inline_depth;
|
||||
DF_Handle window;
|
||||
DF_Handle panel;
|
||||
DF_Handle view;
|
||||
@@ -1609,7 +1604,6 @@ internal EVAL_String2NumMap *df_push_member_map_from_dbgi_key_voff(Arena *arena,
|
||||
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);
|
||||
internal DF_Unwind df_unwind_from_ctrl_unwind(Arena *arena, DI_Scope *di_scope, DF_Entity *process, CTRL_Unwind *base_unwind);
|
||||
internal DF_UnwindFrame *df_frame_from_unwind_idxs(DF_Unwind *unwind, U64 base_unwind_idx, U64 inline_unwind_idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Target Controls
|
||||
|
||||
+1870
-1870
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,8 @@ Rng1U64 df_g_cmd_param_slot_range_table[24] =
|
||||
{OffsetOf(DF_CmdParams, prefer_dasm), OffsetOf(DF_CmdParams, prefer_dasm) + sizeof(B32)},
|
||||
{OffsetOf(DF_CmdParams, force_confirm), OffsetOf(DF_CmdParams, force_confirm) + sizeof(B32)},
|
||||
{OffsetOf(DF_CmdParams, dir2), OffsetOf(DF_CmdParams, dir2) + sizeof(Dir2)},
|
||||
{OffsetOf(DF_CmdParams, base_unwind_index), OffsetOf(DF_CmdParams, base_unwind_index) + sizeof(U64)},
|
||||
{OffsetOf(DF_CmdParams, inline_unwind_index), OffsetOf(DF_CmdParams, inline_unwind_index) + sizeof(U64)},
|
||||
{OffsetOf(DF_CmdParams, unwind_index), OffsetOf(DF_CmdParams, unwind_index) + sizeof(U64)},
|
||||
{OffsetOf(DF_CmdParams, inline_depth), OffsetOf(DF_CmdParams, inline_depth) + sizeof(U64)},
|
||||
};
|
||||
|
||||
DF_IconKind df_g_entity_kind_icon_kind_table[25] =
|
||||
|
||||
@@ -392,8 +392,8 @@ DF_CmdParamSlot_ID,
|
||||
DF_CmdParamSlot_PreferDisassembly,
|
||||
DF_CmdParamSlot_ForceConfirm,
|
||||
DF_CmdParamSlot_Dir2,
|
||||
DF_CmdParamSlot_BaseUnwindIndex,
|
||||
DF_CmdParamSlot_InlineUnwindIndex,
|
||||
DF_CmdParamSlot_UnwindIndex,
|
||||
DF_CmdParamSlot_InlineDepth,
|
||||
DF_CmdParamSlot_COUNT,
|
||||
} DF_CmdParamSlot;
|
||||
|
||||
@@ -422,8 +422,8 @@ U64 id;
|
||||
B32 prefer_dasm;
|
||||
B32 force_confirm;
|
||||
Dir2 dir2;
|
||||
U64 base_unwind_index;
|
||||
U64 inline_unwind_index;
|
||||
U64 unwind_index;
|
||||
U64 inline_depth;
|
||||
};
|
||||
|
||||
DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array);
|
||||
|
||||
+93
-79
@@ -522,15 +522,15 @@ df_cmd_params_from_window(DF_Window *window)
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineDepth);
|
||||
p.window = df_handle_from_window(window);
|
||||
p.panel = df_handle_from_panel(window->focused_panel);
|
||||
p.view = df_handle_from_view(df_selected_tab_from_panel(window->focused_panel));
|
||||
p.prefer_dasm = df_prefer_dasm_from_window(window);
|
||||
p.entity = ctrl_ctx.thread;
|
||||
p.base_unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_unwind_index = ctrl_ctx.inline_unwind_count;
|
||||
p.unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_depth = ctrl_ctx.inline_depth;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -544,15 +544,15 @@ df_cmd_params_from_panel(DF_Window *window, DF_Panel *panel)
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineDepth);
|
||||
p.window = df_handle_from_window(window);
|
||||
p.panel = df_handle_from_panel(panel);
|
||||
p.view = df_handle_from_view(df_selected_tab_from_panel(panel));
|
||||
p.prefer_dasm = df_prefer_dasm_from_window(window);
|
||||
p.entity = ctrl_ctx.thread;
|
||||
p.base_unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_unwind_index = ctrl_ctx.inline_unwind_count;
|
||||
p.unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_depth = ctrl_ctx.inline_depth;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -566,15 +566,15 @@ df_cmd_params_from_view(DF_Window *window, DF_Panel *panel, DF_View *view)
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_InlineDepth);
|
||||
p.window = df_handle_from_window(window);
|
||||
p.panel = df_handle_from_panel(panel);
|
||||
p.view = df_handle_from_view(view);
|
||||
p.prefer_dasm = df_prefer_dasm_from_window(window);
|
||||
p.entity = ctrl_ctx.thread;
|
||||
p.base_unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_unwind_index = ctrl_ctx.inline_unwind_count;
|
||||
p.unwind_index = ctrl_ctx.unwind_count;
|
||||
p.inline_depth = ctrl_ctx.inline_depth;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2585,12 +2585,12 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
DF_Entity *thread = df_entity_from_handle(params.entity);
|
||||
U64 base_unwind_index = params.base_unwind_index;
|
||||
U64 inline_unwind_index = params.inline_unwind_index;
|
||||
U64 unwind_index = params.unwind_index;
|
||||
U64 inline_depth = params.inline_depth;
|
||||
if(thread->kind == DF_EntityKind_Thread)
|
||||
{
|
||||
// rjf: grab rip
|
||||
U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, base_unwind_index);
|
||||
U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_index);
|
||||
|
||||
// rjf: extract thread/rip info
|
||||
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
|
||||
@@ -2605,7 +2605,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
for(DF_LineNode *n = lines.first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
line = n->v;
|
||||
if(idx == inline_unwind_index)
|
||||
if(idx == inline_depth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2632,12 +2632,13 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
params.entity = df_handle_from_entity(thread);
|
||||
params.voff = rip_voff;
|
||||
params.vaddr = rip_vaddr;
|
||||
params.base_unwind_index = base_unwind_index;
|
||||
params.inline_unwind_index = inline_unwind_index;
|
||||
params.unwind_index = unwind_index;
|
||||
params.inline_depth = inline_depth;
|
||||
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_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation));
|
||||
}
|
||||
|
||||
@@ -2648,12 +2649,13 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
params.entity = df_handle_from_entity(thread);
|
||||
params.voff = rip_voff;
|
||||
params.vaddr = rip_vaddr;
|
||||
params.base_unwind_index = base_unwind_index;
|
||||
params.inline_unwind_index = inline_unwind_index;
|
||||
params.unwind_index = unwind_index;
|
||||
params.inline_depth = inline_depth;
|
||||
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_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation));
|
||||
}
|
||||
|
||||
@@ -2671,11 +2673,11 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread);
|
||||
DF_CmdParams params = df_cmd_params_from_window(ws);
|
||||
params.entity = df_handle_from_entity(selected_thread);
|
||||
params.base_unwind_index = ctrl_ctx.unwind_count;
|
||||
params.inline_unwind_index = ctrl_ctx.inline_unwind_count;
|
||||
params.unwind_index = ctrl_ctx.unwind_count;
|
||||
params.inline_depth = ctrl_ctx.inline_depth;
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread));
|
||||
}break;
|
||||
|
||||
@@ -3732,7 +3734,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
ui_labelf("cursor: (L:%I64d, C:%I64d)", regs->cursor.line, regs->cursor.column);
|
||||
ui_labelf("mark: (L:%I64d, C:%I64d)", regs->mark.line, regs->mark.column);
|
||||
ui_labelf("unwind_count: %I64u", regs->unwind_count);
|
||||
ui_labelf("inline_unwind_count: %I64u", regs->inline_unwind_count);
|
||||
ui_labelf("inline_depth: %I64u", regs->inline_depth);
|
||||
ui_labelf("text_key: [0x%I64x, 0x%I64x]", regs->text_key.u64[0], regs->text_key.u64[1]);
|
||||
ui_labelf("lang_kind: '%S'", txt_extension_from_lang_kind(regs->lang_kind));
|
||||
ui_labelf("vaddr_range: [0x%I64x, 0x%I64x)", regs->vaddr_range.min, regs->vaddr_range.max);
|
||||
@@ -4339,34 +4341,37 @@ 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 base_unwind = df_query_cached_unwind_from_thread(entity);
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
|
||||
String8List lines = {0};
|
||||
for(U64 frame_idx = 0; frame_idx < rich_unwind.frames.count; frame_idx += 1)
|
||||
{
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, rich_unwind.frames.v[frame_idx].regs);
|
||||
String8List lines = {0};
|
||||
for(U64 frame_idx = 0; frame_idx < rich_unwind.frames.concrete_frame_count; frame_idx += 1)
|
||||
{
|
||||
DF_UnwindFrame *concrete_frame = &rich_unwind.frames.v[frame_idx];
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, concrete_frame->regs);
|
||||
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
|
||||
RDI_Parsed *rdi = rich_unwind.frames.v[frame_idx].rdi;
|
||||
RDI_Procedure *procedure = rich_unwind.frames.v[frame_idx].procedure;
|
||||
RDI_InlineSite *inline_site = rich_unwind.frames.v[frame_idx].inline_site;
|
||||
if(procedure != 0)
|
||||
{
|
||||
String8 name = {0};
|
||||
name.str = rdi_name_from_procedure(rdi, procedure, &name.size);
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: \"%S\"%s%S", rip_vaddr, name, df_entity_is_nil(module) ? "" : " in ", module->name);
|
||||
}
|
||||
else if(inline_site != 0)
|
||||
{
|
||||
RDI_Parsed *rdi = concrete_frame->rdi;
|
||||
RDI_Procedure *procedure = concrete_frame->procedure;
|
||||
for(DF_UnwindInlineFrame *inline_frame = concrete_frame->last_inline_frame;
|
||||
inline_frame != 0;
|
||||
inline_frame = inline_frame->prev)
|
||||
{
|
||||
RDI_InlineSite *inline_site = inline_frame->inline_site;
|
||||
String8 name = {0};
|
||||
name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size);
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [inlined] \"%S\"%s%S", rip_vaddr, name, df_entity_is_nil(module) ? "" : " in ", module->name);
|
||||
}
|
||||
else if(!df_entity_is_nil(module))
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in %S]", rip_vaddr, module->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in ???]", rip_vaddr);
|
||||
}
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [inlined] \"%S\"%s%S", rip_vaddr, name, df_entity_is_nil(module) ? "" : " in ", module->name);
|
||||
}
|
||||
if(procedure != 0)
|
||||
{
|
||||
String8 name = {0};
|
||||
name.str = rdi_name_from_procedure(rdi, procedure, &name.size);
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: \"%S\"%s%S", rip_vaddr, name, df_entity_is_nil(module) ? "" : " in ", module->name);
|
||||
}
|
||||
else if(!df_entity_is_nil(module))
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in %S]", rip_vaddr, module->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in ???]", rip_vaddr);
|
||||
}
|
||||
}
|
||||
StringJoin join = {0};
|
||||
join.sep = join.post = str8_lit("\n");
|
||||
@@ -10623,34 +10628,24 @@ df_entity_tooltips(DF_Window *ws, DF_Entity *entity)
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process);
|
||||
CTRL_Unwind base_unwind = df_query_cached_unwind_from_thread(entity);
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
|
||||
for(U64 idx = 0; idx < rich_unwind.frames.count; idx += 1)
|
||||
{
|
||||
DF_UnwindFrame *f = &rich_unwind.frames.v[idx];
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
|
||||
for(U64 idx = 0; idx < rich_unwind.frames.concrete_frame_count; idx += 1)
|
||||
{
|
||||
DF_UnwindFrame *f = &rich_unwind.frames.v[idx];
|
||||
RDI_Parsed *rdi = f->rdi;
|
||||
RDI_Procedure *procedure = f->procedure;
|
||||
RDI_InlineSite *inline_site = f->inline_site;
|
||||
RDI_Procedure *procedure = f->procedure;
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs);
|
||||
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
|
||||
String8 module_name = df_entity_is_nil(module) ? str8_lit("???") : str8_skip_last_slash(module->name);
|
||||
String8 name = {0};
|
||||
String8 info = {0};
|
||||
if(procedure != 0)
|
||||
{
|
||||
name.str = rdi_name_from_procedure(rdi, procedure, &name.size);
|
||||
}
|
||||
else if(inline_site != 0)
|
||||
{
|
||||
name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size);
|
||||
info = str8_lit("[inlined]");
|
||||
}
|
||||
UI_PrefWidth(ui_children_sum(1)) UI_Row
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_PrefWidth(ui_em(18.f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_labelf("0x%I64x", rip_vaddr);
|
||||
if(info.size != 0)
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code)UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_label(info);
|
||||
}
|
||||
String8 module_name = df_entity_is_nil(module) ? str8_lit("???") : str8_skip_last_slash(module->name);
|
||||
|
||||
// rjf: inline frames
|
||||
for(DF_UnwindInlineFrame *fin = f->last_inline_frame; fin != 0; fin = fin->prev)
|
||||
UI_PrefWidth(ui_children_sum(1)) UI_Row
|
||||
{
|
||||
String8 name = {0};
|
||||
name.str = rdi_string_from_idx(rdi, fin->inline_site->name_string_idx, &name.size);
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_PrefWidth(ui_em(18.f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_labelf("0x%I64x", rip_vaddr);
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_label(str8_lit("[inlined]"));
|
||||
if(name.size != 0)
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1))
|
||||
@@ -10661,8 +10656,27 @@ df_entity_tooltips(DF_Window *ws, DF_Entity *entity)
|
||||
else
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: concrete frame
|
||||
UI_PrefWidth(ui_children_sum(1)) UI_Row
|
||||
{
|
||||
String8 name = {0};
|
||||
name.str = rdi_name_from_procedure(rdi, procedure, &name.size);
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_PrefWidth(ui_em(18.f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_labelf("0x%I64x", rip_vaddr);
|
||||
if(name.size != 0)
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1))
|
||||
{
|
||||
df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeSymbol), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DF_Font(ws, DF_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
}break;
|
||||
@@ -12513,7 +12527,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_
|
||||
{
|
||||
if((n->v.pt.line == line_num || df_entity_is_nil(df_entity_from_handle(df_interact_regs()->file))) &&
|
||||
((di_key_match(&n->v.dbgi_key, &rich_hover.dbgi_key) &&
|
||||
n->v.voff_range.min <= rich_hover_voff_range.min && rich_hover_voff_range.min <= n->v.voff_range.max) ||
|
||||
n->v.voff_range.min <= rich_hover_voff_range.min && rich_hover_voff_range.min < n->v.voff_range.max) ||
|
||||
(params->line_vaddrs[line_idx] == rich_hover.vaddr_range.min && rich_hover.vaddr_range.min != 0)))
|
||||
{
|
||||
matches = 1;
|
||||
|
||||
+88
-45
@@ -622,8 +622,8 @@ df_code_view_build(Arena *arena, DF_Window *ws, DF_Panel *panel, DF_View *view,
|
||||
{
|
||||
DF_Entity *thread = thread_n->entity;
|
||||
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
|
||||
U64 base_unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0;
|
||||
U64 inline_unwind_count = (thread == selected_thread) ? ctrl_ctx.inline_unwind_count : 0;
|
||||
U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0;
|
||||
U64 inline_depth = (thread == selected_thread) ? ctrl_ctx.inline_depth : 0;
|
||||
U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count);
|
||||
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);
|
||||
@@ -4230,7 +4230,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister)
|
||||
UI_BoxFlag_DrawHotEffects|
|
||||
UI_BoxFlag_DrawActiveEffects,
|
||||
"###procedure_%I64x", item->idx);
|
||||
UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 1))
|
||||
UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 1)) DF_Font(ws, DF_FontSlot_Code)
|
||||
{
|
||||
UI_Box *box = df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeSymbol), name);
|
||||
ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges);
|
||||
@@ -5684,6 +5684,49 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
CTRL_Unwind base_unwind = df_query_cached_unwind_from_thread(thread);
|
||||
DF_Unwind rich_unwind = df_unwind_from_ctrl_unwind(scratch.arena, scope, process, &base_unwind);
|
||||
|
||||
//- rjf: build per-row information
|
||||
typedef struct FrameRow FrameRow;
|
||||
struct FrameRow
|
||||
{
|
||||
void *regs;
|
||||
RDI_Parsed *rdi;
|
||||
RDI_Procedure *procedure;
|
||||
RDI_InlineSite *inline_site;
|
||||
U64 unwind_idx;
|
||||
U64 inline_depth;
|
||||
};
|
||||
U64 rows_count = rich_unwind.frames.total_frame_count;
|
||||
FrameRow *rows = push_array(scratch.arena, FrameRow, rows_count);
|
||||
{
|
||||
U64 concrete_frame_idx = 0;
|
||||
U64 row_idx = 0;
|
||||
for(;concrete_frame_idx < rich_unwind.frames.concrete_frame_count; concrete_frame_idx += 1, row_idx += 1)
|
||||
{
|
||||
DF_UnwindFrame *f = &rich_unwind.frames.v[concrete_frame_idx];
|
||||
|
||||
// rjf: fill rows for inline frames
|
||||
{
|
||||
U64 inline_unwind_idx = 0;
|
||||
for(DF_UnwindInlineFrame *fin = f->last_inline_frame; fin != 0; fin = fin->prev, row_idx += 1, inline_unwind_idx += 1)
|
||||
{
|
||||
rows[row_idx].regs = f->regs;
|
||||
rows[row_idx].rdi = f->rdi;
|
||||
rows[row_idx].inline_site = fin->inline_site;
|
||||
rows[row_idx].unwind_idx = concrete_frame_idx;
|
||||
rows[row_idx].inline_depth = f->inline_frame_count - inline_unwind_idx;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: fill row for concrete frame
|
||||
{
|
||||
rows[row_idx].regs = f->regs;
|
||||
rows[row_idx].rdi = f->rdi;
|
||||
rows[row_idx].procedure = f->procedure;
|
||||
rows[row_idx].unwind_idx= concrete_frame_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: grab state
|
||||
typedef struct DF_CallStackViewState DF_CallStackViewState;
|
||||
struct DF_CallStackViewState
|
||||
@@ -5713,8 +5756,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, rich_unwind.frames.count));
|
||||
scroll_list_params.item_range = r1s64(0, rich_unwind.frames.count+1);
|
||||
scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, rich_unwind.frames.total_frame_count));
|
||||
scroll_list_params.item_range = r1s64(0, rich_unwind.frames.total_frame_count+1);
|
||||
scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1;
|
||||
}
|
||||
UI_ScrollListSignal scroll_list_sig = {0};
|
||||
@@ -5754,7 +5797,7 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
|
||||
//- rjf: frame rows
|
||||
for(S64 row_num = visible_row_range.min;
|
||||
row_num <= visible_row_range.max && row_num <= rich_unwind.frames.count;
|
||||
row_num <= visible_row_range.max && row_num <= rows_count;
|
||||
row_num += 1)
|
||||
{
|
||||
if(row_num == 0)
|
||||
@@ -5764,29 +5807,29 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
B32 row_selected = (cs->cursor.y == row_num);
|
||||
|
||||
// rjf: unpack frame
|
||||
U64 frame_idx = row_num-1;
|
||||
DF_UnwindFrame *frame = &rich_unwind.frames.v[frame_idx];
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, frame->regs);
|
||||
U64 row_idx = row_num-1;
|
||||
FrameRow *row = &rows[row_idx];
|
||||
U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, row->regs);
|
||||
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
|
||||
B32 frame_valid = (rip_vaddr != 0);
|
||||
TG_Graph *graph = tg_graph_begin(bit_size_from_arch(thread->arch)/8, 256);
|
||||
String8 symbol_name = {0};
|
||||
String8 symbol_type_string = {0};
|
||||
if(frame->procedure != 0)
|
||||
if(row->procedure != 0)
|
||||
{
|
||||
symbol_name.str = rdi_name_from_procedure(frame->rdi, frame->procedure, &symbol_name.size);
|
||||
RDI_TypeNode *type = rdi_element_from_name_idx(frame->rdi, TypeNodes, frame->procedure->type_idx);
|
||||
symbol_type_string = tg_string_from_key(scratch.arena, graph, frame->rdi, tg_key_ext(tg_kind_from_rdi_type_kind(type->kind), frame->procedure->type_idx));
|
||||
symbol_name.str = rdi_name_from_procedure(row->rdi, row->procedure, &symbol_name.size);
|
||||
RDI_TypeNode *type = rdi_element_from_name_idx(row->rdi, TypeNodes, row->procedure->type_idx);
|
||||
symbol_type_string = tg_string_from_key(scratch.arena, graph, row->rdi, tg_key_ext(tg_kind_from_rdi_type_kind(type->kind), row->procedure->type_idx));
|
||||
}
|
||||
if(frame->inline_site != 0)
|
||||
if(row->inline_site != 0)
|
||||
{
|
||||
symbol_name.str = rdi_string_from_idx(frame->rdi, frame->inline_site->name_string_idx, &symbol_name.size);
|
||||
RDI_TypeNode *type = rdi_element_from_name_idx(frame->rdi, TypeNodes, frame->inline_site->type_idx);
|
||||
symbol_type_string = tg_string_from_key(scratch.arena, graph, frame->rdi, tg_key_ext(tg_kind_from_rdi_type_kind(type->kind), frame->inline_site->type_idx));
|
||||
symbol_name.str = rdi_string_from_idx(row->rdi, row->inline_site->name_string_idx, &symbol_name.size);
|
||||
RDI_TypeNode *type = rdi_element_from_name_idx(row->rdi, TypeNodes, row->inline_site->type_idx);
|
||||
symbol_type_string = tg_string_from_key(scratch.arena, graph, row->rdi, tg_key_ext(tg_kind_from_rdi_type_kind(type->kind), row->inline_site->type_idx));
|
||||
}
|
||||
|
||||
// rjf: build row
|
||||
if(frame_valid) UI_NamedTableVectorF("###callstack_%p_%I64x", view, frame_idx)
|
||||
if(frame_valid) UI_NamedTableVectorF("###callstack_%p_%I64x", view, row_idx)
|
||||
{
|
||||
// rjf: build cell for selection
|
||||
UI_TableCell
|
||||
@@ -5797,28 +5840,27 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
UI_FocusHot((row_selected && cs->cursor.x == 0) ? UI_FocusKind_On : UI_FocusKind_Off)
|
||||
{
|
||||
String8 selected_string = {0};
|
||||
if(ctrl_ctx.unwind_count == frame->base_unwind_idx &&
|
||||
ctrl_ctx.inline_unwind_count == frame->inline_unwind_idx)
|
||||
if(ctrl_ctx.unwind_count == row->unwind_idx &&
|
||||
ctrl_ctx.inline_depth == row->inline_depth)
|
||||
{
|
||||
selected_string = df_g_icon_kind_text_table[DF_IconKind_RightArrow];
|
||||
ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = thread_color));
|
||||
}
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###selection_%i", selected_string,
|
||||
(int)frame_idx);
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###selection_%I64u", selected_string, row_idx);
|
||||
UI_Signal sig = ui_signal_from_box(box);
|
||||
if(ui_pressed(sig))
|
||||
{
|
||||
next_cursor = v2s64(0, (S64)frame_idx+1);
|
||||
next_cursor = v2s64(0, row_num);
|
||||
DF_CmdParams p = df_cmd_params_from_panel(ws, panel);
|
||||
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel));
|
||||
}
|
||||
if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed)
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_from_view(ws, panel, view);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
params.base_unwind_index = frame->base_unwind_idx;
|
||||
params.inline_unwind_index = frame->inline_unwind_idx;
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
params.unwind_index = row->unwind_idx;
|
||||
params.inline_depth = row->inline_depth;
|
||||
df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind));
|
||||
}
|
||||
}
|
||||
@@ -5828,10 +5870,10 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
UI_FocusHot((row_selected && cs->cursor.x == 1) ? UI_FocusKind_On : UI_FocusKind_Off)
|
||||
{
|
||||
ui_set_next_child_layout_axis(Axis2_X);
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_Clip, "frame_%I64x", frame_idx);
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_Clip, "row_%I64x", row_idx);
|
||||
UI_Parent(box)
|
||||
{
|
||||
if(frame->inline_site != 0)
|
||||
if(row->inline_site != 0)
|
||||
{
|
||||
UI_PrefWidth(ui_text_dim(10, 1)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak)
|
||||
{
|
||||
@@ -5858,17 +5900,17 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
UI_Signal sig = ui_signal_from_box(box);
|
||||
if(ui_pressed(sig))
|
||||
{
|
||||
next_cursor = v2s64(1, (S64)frame_idx+1);
|
||||
next_cursor = v2s64(1, row_num);
|
||||
DF_CmdParams p = df_cmd_params_from_panel(ws, panel);
|
||||
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel));
|
||||
}
|
||||
if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed)
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_from_view(ws, panel, view);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
params.base_unwind_index = frame->base_unwind_idx;
|
||||
params.inline_unwind_index = frame->inline_unwind_idx;
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
params.unwind_index = row->unwind_idx;
|
||||
params.inline_depth = row->inline_depth;
|
||||
df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind));
|
||||
}
|
||||
}
|
||||
@@ -5881,17 +5923,17 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
UI_Signal sig = ui_signal_from_box(box);
|
||||
if(ui_pressed(sig))
|
||||
{
|
||||
next_cursor = v2s64(2, (S64)frame_idx+1);
|
||||
next_cursor = v2s64(2, row_num);
|
||||
DF_CmdParams p = df_cmd_params_from_panel(ws, panel);
|
||||
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel));
|
||||
}
|
||||
if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed)
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_from_view(ws, panel, view);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
params.base_unwind_index = frame->base_unwind_idx;
|
||||
params.inline_unwind_index = frame->inline_unwind_idx;
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
params.unwind_index = row->unwind_idx;
|
||||
params.inline_depth = row->inline_depth;
|
||||
df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind));
|
||||
}
|
||||
}
|
||||
@@ -5902,7 +5944,7 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
UI_Signal sig = {0};
|
||||
if(df_entity_is_nil(module)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak)
|
||||
{
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "(No Module)###moduleless_frame_%I64x", frame_idx);
|
||||
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "(No Module)###moduleless_frame_%I64x", row_idx);
|
||||
sig = ui_signal_from_box(box);
|
||||
}
|
||||
else
|
||||
@@ -5911,17 +5953,17 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack)
|
||||
}
|
||||
if(ui_pressed(sig))
|
||||
{
|
||||
next_cursor = v2s64(3, (S64)frame_idx+1);
|
||||
next_cursor = v2s64(3, row_num);
|
||||
DF_CmdParams p = df_cmd_params_from_panel(ws, panel);
|
||||
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel));
|
||||
}
|
||||
if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed)
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_from_view(ws, panel, view);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_BaseUnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineUnwindIndex);
|
||||
params.base_unwind_index = frame->base_unwind_idx;
|
||||
params.inline_unwind_index = frame->inline_unwind_idx;
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_UnwindIndex);
|
||||
df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_InlineDepth);
|
||||
params.unwind_index = row->unwind_idx;
|
||||
params.inline_depth = row->inline_depth;
|
||||
df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind));
|
||||
}
|
||||
}
|
||||
@@ -6525,6 +6567,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code)
|
||||
UI_PrefWidth(ui_text_dim(10, 1))
|
||||
UI_Focus(UI_FocusKind_On)
|
||||
DF_Palette(ws, DF_PaletteCode_NeutralPopButton)
|
||||
UI_TextAlignment(UI_TextAlign_Center)
|
||||
if(ui_clicked(ui_buttonf("Find alternative...")))
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_from_view(ws, panel, view);
|
||||
|
||||
+3680
-3680
File diff suppressed because it is too large
Load Diff
+476
-472
@@ -1,472 +1,476 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend/UI Pass Tasks
|
||||
//
|
||||
// [ ] auto-scroll output window
|
||||
// [ ] inline breakpoint hit_count
|
||||
// [ ] to count hit counts, resolve all bps to addresses, check addresses
|
||||
// against stopper thread's
|
||||
// [ ] theme lister -> fonts & font sizes
|
||||
// [ ] "Browse..." buttons should adopt a more relevant starting search path,
|
||||
// if possible
|
||||
// [ ] move breakpoints to being a global thing, not nested to particular files
|
||||
// [ ] visualize all breakpoints everywhere - source view should show up in
|
||||
// disasm, disasm should show up in source view, function should show up in
|
||||
// both, etc.
|
||||
// [ ] ** Function breakpoints should show up in the source listing. Without
|
||||
// them being visible, it is confusing when you run and you stop there,
|
||||
// because you're like "wait why did it stop" and then you later remember
|
||||
// that's because there was a function breakpoint there.
|
||||
//
|
||||
// [ ] n-row table selection, in watch window & other UIs, multi-selection
|
||||
// ctrl+C
|
||||
//
|
||||
// [ ] target/breakpoint/watch-pin reordering
|
||||
//
|
||||
// [ ] font lister
|
||||
// [ ] per-panel font size overrides
|
||||
//
|
||||
// [ ] For the Scheduler window, it would be nice if you could dim or
|
||||
// folderize threads that are not your threads - eg., if a thread doesn't
|
||||
// have any resolved stack pointers in your executable code, then you can
|
||||
// ignore it when you are focusing on your own code. I don't know what the
|
||||
// best way to detect this is, other than by walking the call stack... one
|
||||
// way might be to just have a way to separate threads you've named from
|
||||
// threads you haven't? Or, there could even be a debugger-specific API
|
||||
// that you use to tag them. Just some way that would make it easier to
|
||||
// focus on your own threads.
|
||||
//
|
||||
// [ ] "concept key stack"; basically, any point in UI builder path has a stack
|
||||
// of active "concept keys", which can be used to e.g. build context menus
|
||||
// automatically (could just be a per-box attachment; right-click any
|
||||
// point, search up the tree and see the concept keys)
|
||||
// [ ] ui_next_event(...), built-in focus filtering, no need to manually check
|
||||
// if(ui_is_focus_active())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy)
|
||||
//
|
||||
// [ ] PDB files distributed with the build are not found by DbgHelp!!!
|
||||
// [ ] Jai compiler debugging crash
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
|
||||
//
|
||||
// [ ] Setting the code_font/main_font values to a font name doesn't work.
|
||||
// Should probably make note that you have to set it to a path to a TTF,
|
||||
// since that's not normally how Windows fonts work.
|
||||
//
|
||||
// [ ] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// jettison a collection of keys in retained mode fashion
|
||||
//
|
||||
// [ ] Jeff Notes
|
||||
// [ ] sort locals by appearance in source code (or maybe just debug info)
|
||||
// [ ] sum view rule
|
||||
// [ ] plot view rule
|
||||
// [ ] histogram view rule
|
||||
// [ ] max view rule
|
||||
// [ ] min view rule
|
||||
//
|
||||
// [ ] filesystem drag/drop support
|
||||
// [ ] double-click vs. single-click for folder navigation, see if we can infer
|
||||
// [ ] use backslashes on windows by default, forward slashes elsewhere
|
||||
//
|
||||
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
|
||||
// support it?
|
||||
//
|
||||
// [ ] ** Converter performance & heuristics for asynchronously doing it early
|
||||
//
|
||||
// [ ] visualize conversion failures
|
||||
//
|
||||
// [ ] I was a little confused about what a profile file was. I understood
|
||||
// what the user file was, but the profile file sounded like it should
|
||||
// perhaps be per-project, yet it sounded like it was meant to be somewhat
|
||||
// global? I don't have any feedback here because it probably will make
|
||||
// sense once I use the debugger more, but I just thought I'd make a note
|
||||
// to say that I was confused about it after reading the manual, so
|
||||
// perhaps you could elaborate a little more on it in there.
|
||||
// [ ] It wasn't clear to me how you save a user or project file. I can see
|
||||
// how to load them, but not how you save them. Obviously I can just copy
|
||||
// the files myself in the shell, but it seemed weird that there was no
|
||||
// "save" option in the menus.
|
||||
//
|
||||
// [ ] Right-clicking on a thread in the Scheduler window pops up a context
|
||||
// menu, but you can't actually see it because the tooltip for the thread
|
||||
// draws on top of it, so you can't see the menu.
|
||||
//
|
||||
// [ ] In a "hover watch" (where you hover over a variable and it shows a pop-
|
||||
// up watch window), if you expand an item near the bottom of the listing,
|
||||
// it will be clipped to the bottom of the listing instead of showing the
|
||||
// actual items (ie., it doesn't resize the listing based on what's
|
||||
// actually visible)
|
||||
//
|
||||
// [ ] ** One very nice feature of RemedyBG that I use all the time is the
|
||||
// ability to put "$err, hr" into the watch window, which will just show
|
||||
// the value of GetLastError() as a string. This is super useful for
|
||||
// debugging, so you don't have to litter your own code with it.
|
||||
//
|
||||
// [ ] Tooltip Coverage:
|
||||
// [ ] lock icon
|
||||
// [ ] "rotation arrow" icon next to executables
|
||||
//
|
||||
// [ ] For theme editing, when you hove the mouse over a theme color entry and
|
||||
// it highlights that entry, it might help to temporarily change that
|
||||
// color to white (or the inverse of the background color, or whatever) so
|
||||
// that the user can see what things on the screen use that theme color.
|
||||
//
|
||||
// [ ] 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.
|
||||
// [ ] I had to go into the user file to change the font. That should probably
|
||||
// be in the theme window?
|
||||
//
|
||||
// [ ] It'd be nice to have a "goto byte" option for source views, for jumping
|
||||
// to error messages that are byte-based instead of line-based.
|
||||
//
|
||||
// [ ] @feature debug info overrides (both path-based AND module-based)
|
||||
//
|
||||
// [ ] C++ virtual inheritance member visualization in watch window
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup)
|
||||
//
|
||||
// [ ] The hex format for color values in the config file was a real
|
||||
// mindbender. It's prefixed with "0x", so I was assuming it was either
|
||||
// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To
|
||||
// my surprise, it was neither - it was actually web format (RRGGBBAA),
|
||||
// which I was not expecting because that is normally written with a
|
||||
// number sign (#AARRGGBB) not an 0x.
|
||||
//
|
||||
// [ ] Clicking on either side of a scroll bar is idiosyncratic. Normally,
|
||||
// that is "page up" / "page down", but here it is "smooth scroll upward"
|
||||
// / "smooth scroll downward" for some reason?
|
||||
//
|
||||
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
|
||||
// [ ] mouse back button should make view to go back after I double clicked
|
||||
// on function to open it
|
||||
// [ ] Alt+8 to switch to disassembly would be nice (regardless on which
|
||||
// panel was previous, don't want to use ctrl+, multiple times)
|
||||
// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use
|
||||
// in VS
|
||||
// [ ] default font size is too small for me - not only source code, but
|
||||
// menus/tab/watch names (which don't resize). Maybe you could query
|
||||
// Windows for initial font size?
|
||||
// [ ] icon fonts glyphs sometimes disappear for specific font size, but they
|
||||
// reappear if you go +1 higher or -1 lower. Mostly red triangle in watch
|
||||
// values for "unknown identifier". But also yellow arrow in call stack
|
||||
// disappears if font size gets too large.
|
||||
// [ ] undo close tab would be nice. If not for everything, then at least
|
||||
// just for source files
|
||||
// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Feature Tasks (Not really "low priority" but less urgent than fixes)
|
||||
//
|
||||
// [ ] @eval_upgrade
|
||||
// [ ] new eval system; support strings, many address spaces, many debug
|
||||
// infos, wide/async transforms (e.g. diff(blob1, blob2))
|
||||
// [ ] collapse frontend visualization systems - source view, disasm view,
|
||||
// callstack, modules, scheduler, should *all* be flavors of watch view
|
||||
//
|
||||
// [ ] Fancy View Rules
|
||||
// [ ] table column boundaries should be checked against *AFTER* table
|
||||
// contents, not before
|
||||
// [ ] `array:(x, y)` - multidimensional array
|
||||
// [ ] `text[:lang]` - interpret memory as text, in lang `lang`
|
||||
// [ ] `disasm:arch` - interpret memory as machine code for isa `arch`
|
||||
// [ ] `memory` - view memory in usual memory hex-editor view
|
||||
// NOTE(rjf): When the visualization system is solid, layers like dasm, txti,
|
||||
// and so on can be dispensed with, as things like the source view, disasm
|
||||
// view, or memory view will simply be specializations of the general purpose
|
||||
// viz system.
|
||||
// [ ] view rule hook for standalone visualization ui, granted its own
|
||||
// tab
|
||||
//
|
||||
// [ ] search-in-all-files
|
||||
//
|
||||
// [ ] Memory View
|
||||
// [ ] memory view mutation controls
|
||||
// [ ] memory view user-made annotations
|
||||
//
|
||||
// [ ] undo/redo
|
||||
// [ ] proper "go back" + "go forward" history navigations
|
||||
//
|
||||
// [ ] globally disable/configure default view rule-like things (string
|
||||
// viz for u8s in particular)
|
||||
// [ ] globally disable/configure bp/ip lines in source view
|
||||
//
|
||||
// [ ] @feature processor/data breakpoints
|
||||
// [ ] @feature automatically snap to search matches when searching source files
|
||||
// [ ] automatically start search query with selected text
|
||||
// [ ] @feature entity views: filtering & reordering
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Clean-up Tasks That Probably Only Ryan Notices
|
||||
// (E.G. Because They Are Code-Related Or Because Nobody Cares)
|
||||
//
|
||||
// [ ] @bug view-snapping in scroll-lists, accounting for mapping between
|
||||
// visual positions & logical positions (variably sized rows in watch,
|
||||
// table headers, etc.)
|
||||
// [ ] @cleanup collapse DF_CfgNodes into just being MD trees, find another way
|
||||
// to encode config source - don't need it at every node
|
||||
// [ ] @cleanup straighten out index/number space & types & terminology for
|
||||
// scroll lists
|
||||
// [ ] @cleanup simplification pass over eval visualization pipeline & types,
|
||||
// including view rule hooks
|
||||
// [ ] @cleanup naming pass over eval visualization part of the frontend,
|
||||
// "blocks" vs. "canvas" vs. "expansion" - etc.
|
||||
// [ ] @cleanup central worker thread pool - eliminate per-layer thread pools
|
||||
// [ ] @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.
|
||||
// [ ] @cleanup eliminate explicit font parameters in the various ui paths (e.g.
|
||||
// code slice params)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Unsorted Notes (Deferred Until Existing Lists Mostly Exhausted)
|
||||
//
|
||||
// [ ] @feature types -> auto view rules (don't statefully fill view rules
|
||||
// given types, just query if no other view rule is present, & autofill
|
||||
// when editing)
|
||||
// [ ] @feature eval system -> somehow evaluate breakpoint hit counts? "meta"
|
||||
// variables?
|
||||
//
|
||||
// [ ] @feature disasm view improvement features
|
||||
// [ ] visualize jump destinations in disasm
|
||||
//
|
||||
// [ ] @feature eval ui improvement features
|
||||
// [ ] serializing eval view maps
|
||||
// [ ] view rule editors in hover-eval
|
||||
// [ ] view rule hook coverage
|
||||
// [ ] `each:(expr addition)` - apply some additional expression to all
|
||||
// elements in an array/linked list would be useful to look at only a
|
||||
// subset of an array of complex structs
|
||||
// [ ] `slider:(min max)` view rule
|
||||
// [ ] `v2f32` view rule
|
||||
// [ ] `v3` view rule
|
||||
// [ ] `quat` view rule
|
||||
// [ ] `matrix` view rule
|
||||
// [ ] `audio` waveform view rule
|
||||
// [ ] smart scopes - expression operators for "grab me the first type X"
|
||||
// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx
|
||||
//
|
||||
// [ ] @feature header file for target -> debugger communication; printf, log,
|
||||
// etc.
|
||||
// [ ] @feature just-in-time debugging
|
||||
// [ ] @feature step-out-of-loop
|
||||
//
|
||||
//-[ ] long-term future notes from martins
|
||||
// [ ] core dump saving/loading
|
||||
// [ ] parallel call stacks view
|
||||
// [ ] parallel watch view
|
||||
// [ ] mixed native/interpreted/jit debugging
|
||||
// - it seems python has a top-level linked list of interpreter states,
|
||||
// which should allow the debugger to map native callstacks to python
|
||||
// code
|
||||
//
|
||||
// [ ] fancy string runs can include "weakness" information for text truncation
|
||||
// ... can prioritize certain parts of strings to be truncated before
|
||||
// others. would be good for e.g. the middle of a path
|
||||
// [ ] font cache eviction (both for font tags, closing fp handles, and
|
||||
// rasterizations)
|
||||
// [ ] frontend speedup opportunities
|
||||
// [ ] tables in UI -> currently building per-row, could probably cut down on
|
||||
// # of boxes and # of draws by doing per-column in some cases?
|
||||
// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too
|
||||
// (not just rasterization)... would save a *lot*, there is a ton of work
|
||||
// just in looking up & stitching stuff repeatedly
|
||||
// [ ] convert UI layout pass to not be naive recursive version
|
||||
// [ ] (big change) parallelize window ui build codepaths per-panel
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Recently Completed Task Log
|
||||
//
|
||||
// [x] UI_NavActions, OS_Event -> UI_Event (single event stream)
|
||||
// [x] better discoverability for view rules - have better help hover tooltip,
|
||||
// info on arguments, and better autocomplete lister
|
||||
// [x] source view -> floating margin/line-nums
|
||||
// [x] watch window reordering
|
||||
// [x] standard way to filter
|
||||
// [x] autocomplete lister should respect position in edited expression,
|
||||
// tabbing through should autocomplete but not exit, etc.
|
||||
// [x] pipe failure-to-launch errors back to frontend
|
||||
// [x] bit more padding on the tabs
|
||||
// [x] unified top-level cursor/typing/lister helper
|
||||
// [x] collapse text cells & command lister & etc. into same codepath (?)
|
||||
// [x] page-up & page-down correct handling in keyboard nav
|
||||
// [x] interleaved src/dasm view
|
||||
// [x] in watch window when I enter some new expression and then click mouse
|
||||
// away from cell, then it should behave the same as if I pressed enter.
|
||||
// Currently it does the same as if I have pressed esc and I have lost my
|
||||
// expression
|
||||
// [x] pressing random keyboard keys in source code advances text cursor like
|
||||
// you were inputting text, very strange.
|
||||
// [x] It's confusing that ENTER is the way you expand and collapse things in
|
||||
// the watch window, but then also how you edit them if they are not
|
||||
// expandable? It seems like this should be consistent (one way to edit,
|
||||
// one way to expand/collapse, that are distinct)
|
||||
// [x] Dragging a window tab (like Locals or Registers or whatnot) and
|
||||
// canceling with ESC should revert the window tab to where it was.
|
||||
// Currently, it leaves the window tab reordered if you dragged over its
|
||||
// window and shuffled its position.
|
||||
// [x] ** I couldn't figure out how to really view threads in the debugger.
|
||||
// The only place I found a thread list was in "The Scheduler", but it
|
||||
// only lists threads by ID, which is hard to use. I can hover over them
|
||||
// to get the stack, which helps, but it would be much nicer if the top
|
||||
// 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
|
||||
// [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] rdi file regeneration too strict
|
||||
// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly
|
||||
// [x] mouse-driven way to complete file/folder selection, or more generally
|
||||
// query completion
|
||||
// [x] it would be nice to have "show in explorer" for right click on source
|
||||
// file tab (opens explorer & selects the file)
|
||||
// [x] asan stepping breakage
|
||||
// [x] what's up with decimal number coloring where every group of 3 are in
|
||||
// different color? can I turn it off? And why sometimes digits in number
|
||||
// start with brighter color, but sometimes with darker - shouldn't it
|
||||
// always have the same color ordering?
|
||||
// [x] fix tabs-on-bottom positioning
|
||||
// [x] colors: consistent tooltip styles (colors, font flags, etc.)
|
||||
// [x] colors: scroll bars
|
||||
// [x] colors: watch window navigation visuals
|
||||
// [x] floating source view margin background/placement
|
||||
// [x] "interaction root", or "group" ui_key, or something; used for menu bar interactions
|
||||
// [x] theme colors -> more explicit about e.g. opaque backgrounds vs. floating
|
||||
// & scrollbars etc.
|
||||
// [x] Pressing the left mouse button on the menu bar and dragging does not
|
||||
// move through the menus as expected - instead, it opens the one you
|
||||
// clicked down on, then does nothing until you release, at which point it
|
||||
// opens the menu you released on.
|
||||
// [x] Similarly, pressing the left mouse button on a menu and dragging to an
|
||||
// item, then releasing, does not trigger that item as expected. Instead,
|
||||
// it is a nop, and it waits for you to click again on the item.
|
||||
// [x] Using the word "symbol" in "Code (Symbol)" seems like a bad idea, since
|
||||
// you're referring to non-identifier characters, but in a debugger
|
||||
// "symbol" usually means something defined in the debug information.
|
||||
// [x] I couldn't figure out how to affect the "dim" color in constants that
|
||||
// have alternating bright/dim letters to show sections of a number. Is
|
||||
// this in the theme colors somewhere?
|
||||
//
|
||||
// [x] ** Scrollbars are barely visible for me, for some reason. I could not
|
||||
// find anything in the theme that would fill them with a solid, bright
|
||||
// color. Instead they are just a thin outline and the same color as the
|
||||
// scroll bar background.
|
||||
//
|
||||
// [x] Many of the UI elements, like the menus, would like better if they had
|
||||
// a little bit of margin. Having the text right next to the edges, and
|
||||
// with no line spacing, makes it harder to read things quickly.
|
||||
// [x] colors: memory view
|
||||
// [x] Hitting ESC during a color picker drag should abort the color picking
|
||||
// and revert to the previous color. Currently, it just accepts the last
|
||||
// drag result as the new color.
|
||||
// [x] It was not clear to me why a small "tab picker" appeared when I got to
|
||||
// a certain number of tabs. It seemed to appear even if the tabs were
|
||||
// quite large, and there was no need to a drop-down menu to pick them. It
|
||||
// feels like either it should always be there, or it should only show up
|
||||
// if at least one tab gets small enough to have its name cut off?
|
||||
// [x] I found the "context menu" convention to be confusing. For example, if
|
||||
// I left-click on a tab, it selects the tab. If I right-click on a tab,
|
||||
// it opens the context menu. However, if I left-click on a module, it
|
||||
// opens the context window. It seems like maybe menus should be right,
|
||||
// and left should do the default action, more consistently?
|
||||
//
|
||||
// [x] double click on procedure in procedures tab to jump to source
|
||||
// [x] highlighted text & ctrl+f -> auto-fill search query
|
||||
// [x] double-click any part of frame in callstack view -> snap to function
|
||||
// [x] Menus take too long to show up. I would prefer it if they were instant.
|
||||
// The animation doesn't really provide any useful cues, since I know
|
||||
// where the menu came from.
|
||||
// [x] user settings (ui & functionality - generally need a story for it)
|
||||
// [x] hover animations
|
||||
// [x] press animations
|
||||
// [x] focus animations
|
||||
// [x] tooltip animations
|
||||
// [x] context menu animations
|
||||
// [x] scrolling animations
|
||||
// [x] background blur
|
||||
// [x] tab width
|
||||
// [x] ** In the call stack, I would like to be able to click quickly and move
|
||||
// around the stack. Right now, you can do that with the first and third
|
||||
// column, but the second column drops down a context menu. Since right
|
||||
// click is already for context menus, can it not just be that double-
|
||||
// clicking any column jumps to that stack frame?
|
||||
//
|
||||
// [x] ** I find it really hard to read the code with the heavyweight lines
|
||||
// running through it for breakpoints and stepping and things. Is there a
|
||||
// way to turn the lines off? AFAICT they are based on thread and
|
||||
// breakpoint color, so you can't really control the line drawing? I might
|
||||
// be fine with them, but they would have to be much more light (like
|
||||
// alpha 0.1 or something)
|
||||
// [x] zooming behaves very strangely - sometimes it zooms source code,
|
||||
// sometimes both source code and menu/tab/watch font size, sometimes
|
||||
// just menu/tab/watch font size not source size.
|
||||
// [x] colors: fill out rest of theme presets for new theme setup
|
||||
// [x] I LOVE ALT-W to add watch under cursor, but I would prefer to have it
|
||||
// add what's under the MOUSE cursor instead of the keyboard cursor. Can
|
||||
// we get a command for that so I can bind ALT-W to that instead?
|
||||
// [x] editing multiple bindings for commands
|
||||
|
||||
#ifndef RADDBG_H
|
||||
#define RADDBG_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Execution Types
|
||||
|
||||
typedef enum ExecMode
|
||||
{
|
||||
ExecMode_Normal,
|
||||
ExecMode_IPCSender,
|
||||
ExecMode_Converter,
|
||||
ExecMode_Help,
|
||||
}
|
||||
ExecMode;
|
||||
|
||||
typedef struct IPCInfo IPCInfo;
|
||||
struct IPCInfo
|
||||
{
|
||||
U64 msg_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
//- rjf: IPC resources
|
||||
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4)
|
||||
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
|
||||
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: last focused window
|
||||
global DF_Handle last_focused_window = {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};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend Entry Points
|
||||
|
||||
internal void update_and_render(OS_Handle repaint_window_handle, void *user_data);
|
||||
|
||||
#endif // RADDBG_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend/UI Pass Tasks
|
||||
//
|
||||
// [ ] file overrides -> always pick most specific one! found with conflicting
|
||||
// overrides, e.g. C:/devel/ -> D:/devel/, but also C:/devel/foo ->
|
||||
// C:/devel/bar, etc.
|
||||
//
|
||||
// [ ] auto-scroll output window
|
||||
// [ ] inline breakpoint hit_count
|
||||
// [ ] to count hit counts, resolve all bps to addresses, check addresses
|
||||
// against stopper thread's
|
||||
// [ ] theme lister -> fonts & font sizes
|
||||
// [ ] "Browse..." buttons should adopt a more relevant starting search path,
|
||||
// if possible
|
||||
// [ ] move breakpoints to being a global thing, not nested to particular files
|
||||
// [ ] visualize all breakpoints everywhere - source view should show up in
|
||||
// disasm, disasm should show up in source view, function should show up in
|
||||
// both, etc.
|
||||
// [ ] ** Function breakpoints should show up in the source listing. Without
|
||||
// them being visible, it is confusing when you run and you stop there,
|
||||
// because you're like "wait why did it stop" and then you later remember
|
||||
// that's because there was a function breakpoint there.
|
||||
//
|
||||
// [ ] n-row table selection, in watch window & other UIs, multi-selection
|
||||
// ctrl+C
|
||||
//
|
||||
// [ ] target/breakpoint/watch-pin reordering
|
||||
//
|
||||
// [ ] font lister
|
||||
// [ ] per-panel font size overrides
|
||||
//
|
||||
// [ ] For the Scheduler window, it would be nice if you could dim or
|
||||
// folderize threads that are not your threads - eg., if a thread doesn't
|
||||
// have any resolved stack pointers in your executable code, then you can
|
||||
// ignore it when you are focusing on your own code. I don't know what the
|
||||
// best way to detect this is, other than by walking the call stack... one
|
||||
// way might be to just have a way to separate threads you've named from
|
||||
// threads you haven't? Or, there could even be a debugger-specific API
|
||||
// that you use to tag them. Just some way that would make it easier to
|
||||
// focus on your own threads.
|
||||
//
|
||||
// [ ] "concept key stack"; basically, any point in UI builder path has a stack
|
||||
// of active "concept keys", which can be used to e.g. build context menus
|
||||
// automatically (could just be a per-box attachment; right-click any
|
||||
// point, search up the tree and see the concept keys)
|
||||
// [ ] ui_next_event(...), built-in focus filtering, no need to manually check
|
||||
// if(ui_is_focus_active())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy)
|
||||
//
|
||||
// [ ] PDB files distributed with the build are not found by DbgHelp!!!
|
||||
// [ ] Jai compiler debugging crash
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
|
||||
//
|
||||
// [ ] Setting the code_font/main_font values to a font name doesn't work.
|
||||
// Should probably make note that you have to set it to a path to a TTF,
|
||||
// since that's not normally how Windows fonts work.
|
||||
//
|
||||
// [ ] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// jettison a collection of keys in retained mode fashion
|
||||
//
|
||||
// [ ] Jeff Notes
|
||||
// [ ] sort locals by appearance in source code (or maybe just debug info)
|
||||
// [ ] sum view rule
|
||||
// [ ] plot view rule
|
||||
// [ ] histogram view rule
|
||||
// [ ] max view rule
|
||||
// [ ] min view rule
|
||||
//
|
||||
// [ ] filesystem drag/drop support
|
||||
// [ ] double-click vs. single-click for folder navigation, see if we can infer
|
||||
// [ ] use backslashes on windows by default, forward slashes elsewhere
|
||||
//
|
||||
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
|
||||
// support it?
|
||||
//
|
||||
// [ ] ** Converter performance & heuristics for asynchronously doing it early
|
||||
//
|
||||
// [ ] visualize conversion failures
|
||||
//
|
||||
// [ ] I was a little confused about what a profile file was. I understood
|
||||
// what the user file was, but the profile file sounded like it should
|
||||
// perhaps be per-project, yet it sounded like it was meant to be somewhat
|
||||
// global? I don't have any feedback here because it probably will make
|
||||
// sense once I use the debugger more, but I just thought I'd make a note
|
||||
// to say that I was confused about it after reading the manual, so
|
||||
// perhaps you could elaborate a little more on it in there.
|
||||
// [ ] It wasn't clear to me how you save a user or project file. I can see
|
||||
// how to load them, but not how you save them. Obviously I can just copy
|
||||
// the files myself in the shell, but it seemed weird that there was no
|
||||
// "save" option in the menus.
|
||||
//
|
||||
// [ ] Right-clicking on a thread in the Scheduler window pops up a context
|
||||
// menu, but you can't actually see it because the tooltip for the thread
|
||||
// draws on top of it, so you can't see the menu.
|
||||
//
|
||||
// [ ] In a "hover watch" (where you hover over a variable and it shows a pop-
|
||||
// up watch window), if you expand an item near the bottom of the listing,
|
||||
// it will be clipped to the bottom of the listing instead of showing the
|
||||
// actual items (ie., it doesn't resize the listing based on what's
|
||||
// actually visible)
|
||||
//
|
||||
// [ ] ** One very nice feature of RemedyBG that I use all the time is the
|
||||
// ability to put "$err, hr" into the watch window, which will just show
|
||||
// the value of GetLastError() as a string. This is super useful for
|
||||
// debugging, so you don't have to litter your own code with it.
|
||||
//
|
||||
// [ ] Tooltip Coverage:
|
||||
// [ ] lock icon
|
||||
// [ ] "rotation arrow" icon next to executables
|
||||
//
|
||||
// [ ] For theme editing, when you hove the mouse over a theme color entry and
|
||||
// it highlights that entry, it might help to temporarily change that
|
||||
// color to white (or the inverse of the background color, or whatever) so
|
||||
// that the user can see what things on the screen use that theme color.
|
||||
//
|
||||
// [ ] 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.
|
||||
// [ ] I had to go into the user file to change the font. That should probably
|
||||
// be in the theme window?
|
||||
//
|
||||
// [ ] It'd be nice to have a "goto byte" option for source views, for jumping
|
||||
// to error messages that are byte-based instead of line-based.
|
||||
//
|
||||
// [ ] @feature debug info overrides (both path-based AND module-based)
|
||||
//
|
||||
// [ ] C++ virtual inheritance member visualization in watch window
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup)
|
||||
//
|
||||
// [ ] The hex format for color values in the config file was a real
|
||||
// mindbender. It's prefixed with "0x", so I was assuming it was either
|
||||
// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To
|
||||
// my surprise, it was neither - it was actually web format (RRGGBBAA),
|
||||
// which I was not expecting because that is normally written with a
|
||||
// number sign (#AARRGGBB) not an 0x.
|
||||
//
|
||||
// [ ] Clicking on either side of a scroll bar is idiosyncratic. Normally,
|
||||
// that is "page up" / "page down", but here it is "smooth scroll upward"
|
||||
// / "smooth scroll downward" for some reason?
|
||||
//
|
||||
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
|
||||
// [ ] mouse back button should make view to go back after I double clicked
|
||||
// on function to open it
|
||||
// [ ] Alt+8 to switch to disassembly would be nice (regardless on which
|
||||
// panel was previous, don't want to use ctrl+, multiple times)
|
||||
// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use
|
||||
// in VS
|
||||
// [ ] default font size is too small for me - not only source code, but
|
||||
// menus/tab/watch names (which don't resize). Maybe you could query
|
||||
// Windows for initial font size?
|
||||
// [ ] icon fonts glyphs sometimes disappear for specific font size, but they
|
||||
// reappear if you go +1 higher or -1 lower. Mostly red triangle in watch
|
||||
// values for "unknown identifier". But also yellow arrow in call stack
|
||||
// disappears if font size gets too large.
|
||||
// [ ] undo close tab would be nice. If not for everything, then at least
|
||||
// just for source files
|
||||
// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Feature Tasks (Not really "low priority" but less urgent than fixes)
|
||||
//
|
||||
// [ ] @eval_upgrade
|
||||
// [ ] new eval system; support strings, many address spaces, many debug
|
||||
// infos, wide/async transforms (e.g. diff(blob1, blob2))
|
||||
// [ ] collapse frontend visualization systems - source view, disasm view,
|
||||
// callstack, modules, scheduler, should *all* be flavors of watch view
|
||||
//
|
||||
// [ ] Fancy View Rules
|
||||
// [ ] table column boundaries should be checked against *AFTER* table
|
||||
// contents, not before
|
||||
// [ ] `array:(x, y)` - multidimensional array
|
||||
// [ ] `text[:lang]` - interpret memory as text, in lang `lang`
|
||||
// [ ] `disasm:arch` - interpret memory as machine code for isa `arch`
|
||||
// [ ] `memory` - view memory in usual memory hex-editor view
|
||||
// NOTE(rjf): When the visualization system is solid, layers like dasm, txti,
|
||||
// and so on can be dispensed with, as things like the source view, disasm
|
||||
// view, or memory view will simply be specializations of the general purpose
|
||||
// viz system.
|
||||
// [ ] view rule hook for standalone visualization ui, granted its own
|
||||
// tab
|
||||
//
|
||||
// [ ] search-in-all-files
|
||||
//
|
||||
// [ ] Memory View
|
||||
// [ ] memory view mutation controls
|
||||
// [ ] memory view user-made annotations
|
||||
//
|
||||
// [ ] undo/redo
|
||||
// [ ] proper "go back" + "go forward" history navigations
|
||||
//
|
||||
// [ ] globally disable/configure default view rule-like things (string
|
||||
// viz for u8s in particular)
|
||||
// [ ] globally disable/configure bp/ip lines in source view
|
||||
//
|
||||
// [ ] @feature processor/data breakpoints
|
||||
// [ ] @feature automatically snap to search matches when searching source files
|
||||
// [ ] automatically start search query with selected text
|
||||
// [ ] @feature entity views: filtering & reordering
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Clean-up Tasks That Probably Only Ryan Notices
|
||||
// (E.G. Because They Are Code-Related Or Because Nobody Cares)
|
||||
//
|
||||
// [ ] @bug view-snapping in scroll-lists, accounting for mapping between
|
||||
// visual positions & logical positions (variably sized rows in watch,
|
||||
// table headers, etc.)
|
||||
// [ ] @cleanup collapse DF_CfgNodes into just being MD trees, find another way
|
||||
// to encode config source - don't need it at every node
|
||||
// [ ] @cleanup straighten out index/number space & types & terminology for
|
||||
// scroll lists
|
||||
// [ ] @cleanup simplification pass over eval visualization pipeline & types,
|
||||
// including view rule hooks
|
||||
// [ ] @cleanup naming pass over eval visualization part of the frontend,
|
||||
// "blocks" vs. "canvas" vs. "expansion" - etc.
|
||||
// [ ] @cleanup central worker thread pool - eliminate per-layer thread pools
|
||||
// [ ] @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.
|
||||
// [ ] @cleanup eliminate explicit font parameters in the various ui paths (e.g.
|
||||
// code slice params)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Unsorted Notes (Deferred Until Existing Lists Mostly Exhausted)
|
||||
//
|
||||
// [ ] @feature types -> auto view rules (don't statefully fill view rules
|
||||
// given types, just query if no other view rule is present, & autofill
|
||||
// when editing)
|
||||
// [ ] @feature eval system -> somehow evaluate breakpoint hit counts? "meta"
|
||||
// variables?
|
||||
//
|
||||
// [ ] @feature disasm view improvement features
|
||||
// [ ] visualize jump destinations in disasm
|
||||
//
|
||||
// [ ] @feature eval ui improvement features
|
||||
// [ ] serializing eval view maps
|
||||
// [ ] view rule editors in hover-eval
|
||||
// [ ] view rule hook coverage
|
||||
// [ ] `each:(expr addition)` - apply some additional expression to all
|
||||
// elements in an array/linked list would be useful to look at only a
|
||||
// subset of an array of complex structs
|
||||
// [ ] `slider:(min max)` view rule
|
||||
// [ ] `v2f32` view rule
|
||||
// [ ] `v3` view rule
|
||||
// [ ] `quat` view rule
|
||||
// [ ] `matrix` view rule
|
||||
// [ ] `audio` waveform view rule
|
||||
// [ ] smart scopes - expression operators for "grab me the first type X"
|
||||
// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx
|
||||
//
|
||||
// [ ] @feature header file for target -> debugger communication; printf, log,
|
||||
// etc.
|
||||
// [ ] @feature just-in-time debugging
|
||||
// [ ] @feature step-out-of-loop
|
||||
//
|
||||
//-[ ] long-term future notes from martins
|
||||
// [ ] core dump saving/loading
|
||||
// [ ] parallel call stacks view
|
||||
// [ ] parallel watch view
|
||||
// [ ] mixed native/interpreted/jit debugging
|
||||
// - it seems python has a top-level linked list of interpreter states,
|
||||
// which should allow the debugger to map native callstacks to python
|
||||
// code
|
||||
//
|
||||
// [ ] fancy string runs can include "weakness" information for text truncation
|
||||
// ... can prioritize certain parts of strings to be truncated before
|
||||
// others. would be good for e.g. the middle of a path
|
||||
// [ ] font cache eviction (both for font tags, closing fp handles, and
|
||||
// rasterizations)
|
||||
// [ ] frontend speedup opportunities
|
||||
// [ ] tables in UI -> currently building per-row, could probably cut down on
|
||||
// # of boxes and # of draws by doing per-column in some cases?
|
||||
// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too
|
||||
// (not just rasterization)... would save a *lot*, there is a ton of work
|
||||
// just in looking up & stitching stuff repeatedly
|
||||
// [ ] convert UI layout pass to not be naive recursive version
|
||||
// [ ] (big change) parallelize window ui build codepaths per-panel
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Recently Completed Task Log
|
||||
//
|
||||
// [x] UI_NavActions, OS_Event -> UI_Event (single event stream)
|
||||
// [x] better discoverability for view rules - have better help hover tooltip,
|
||||
// info on arguments, and better autocomplete lister
|
||||
// [x] source view -> floating margin/line-nums
|
||||
// [x] watch window reordering
|
||||
// [x] standard way to filter
|
||||
// [x] autocomplete lister should respect position in edited expression,
|
||||
// tabbing through should autocomplete but not exit, etc.
|
||||
// [x] pipe failure-to-launch errors back to frontend
|
||||
// [x] bit more padding on the tabs
|
||||
// [x] unified top-level cursor/typing/lister helper
|
||||
// [x] collapse text cells & command lister & etc. into same codepath (?)
|
||||
// [x] page-up & page-down correct handling in keyboard nav
|
||||
// [x] interleaved src/dasm view
|
||||
// [x] in watch window when I enter some new expression and then click mouse
|
||||
// away from cell, then it should behave the same as if I pressed enter.
|
||||
// Currently it does the same as if I have pressed esc and I have lost my
|
||||
// expression
|
||||
// [x] pressing random keyboard keys in source code advances text cursor like
|
||||
// you were inputting text, very strange.
|
||||
// [x] It's confusing that ENTER is the way you expand and collapse things in
|
||||
// the watch window, but then also how you edit them if they are not
|
||||
// expandable? It seems like this should be consistent (one way to edit,
|
||||
// one way to expand/collapse, that are distinct)
|
||||
// [x] Dragging a window tab (like Locals or Registers or whatnot) and
|
||||
// canceling with ESC should revert the window tab to where it was.
|
||||
// Currently, it leaves the window tab reordered if you dragged over its
|
||||
// window and shuffled its position.
|
||||
// [x] ** I couldn't figure out how to really view threads in the debugger.
|
||||
// The only place I found a thread list was in "The Scheduler", but it
|
||||
// only lists threads by ID, which is hard to use. I can hover over them
|
||||
// to get the stack, which helps, but it would be much nicer if the top
|
||||
// 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
|
||||
// [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] rdi file regeneration too strict
|
||||
// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly
|
||||
// [x] mouse-driven way to complete file/folder selection, or more generally
|
||||
// query completion
|
||||
// [x] it would be nice to have "show in explorer" for right click on source
|
||||
// file tab (opens explorer & selects the file)
|
||||
// [x] asan stepping breakage
|
||||
// [x] what's up with decimal number coloring where every group of 3 are in
|
||||
// different color? can I turn it off? And why sometimes digits in number
|
||||
// start with brighter color, but sometimes with darker - shouldn't it
|
||||
// always have the same color ordering?
|
||||
// [x] fix tabs-on-bottom positioning
|
||||
// [x] colors: consistent tooltip styles (colors, font flags, etc.)
|
||||
// [x] colors: scroll bars
|
||||
// [x] colors: watch window navigation visuals
|
||||
// [x] floating source view margin background/placement
|
||||
// [x] "interaction root", or "group" ui_key, or something; used for menu bar interactions
|
||||
// [x] theme colors -> more explicit about e.g. opaque backgrounds vs. floating
|
||||
// & scrollbars etc.
|
||||
// [x] Pressing the left mouse button on the menu bar and dragging does not
|
||||
// move through the menus as expected - instead, it opens the one you
|
||||
// clicked down on, then does nothing until you release, at which point it
|
||||
// opens the menu you released on.
|
||||
// [x] Similarly, pressing the left mouse button on a menu and dragging to an
|
||||
// item, then releasing, does not trigger that item as expected. Instead,
|
||||
// it is a nop, and it waits for you to click again on the item.
|
||||
// [x] Using the word "symbol" in "Code (Symbol)" seems like a bad idea, since
|
||||
// you're referring to non-identifier characters, but in a debugger
|
||||
// "symbol" usually means something defined in the debug information.
|
||||
// [x] I couldn't figure out how to affect the "dim" color in constants that
|
||||
// have alternating bright/dim letters to show sections of a number. Is
|
||||
// this in the theme colors somewhere?
|
||||
//
|
||||
// [x] ** Scrollbars are barely visible for me, for some reason. I could not
|
||||
// find anything in the theme that would fill them with a solid, bright
|
||||
// color. Instead they are just a thin outline and the same color as the
|
||||
// scroll bar background.
|
||||
//
|
||||
// [x] Many of the UI elements, like the menus, would like better if they had
|
||||
// a little bit of margin. Having the text right next to the edges, and
|
||||
// with no line spacing, makes it harder to read things quickly.
|
||||
// [x] colors: memory view
|
||||
// [x] Hitting ESC during a color picker drag should abort the color picking
|
||||
// and revert to the previous color. Currently, it just accepts the last
|
||||
// drag result as the new color.
|
||||
// [x] It was not clear to me why a small "tab picker" appeared when I got to
|
||||
// a certain number of tabs. It seemed to appear even if the tabs were
|
||||
// quite large, and there was no need to a drop-down menu to pick them. It
|
||||
// feels like either it should always be there, or it should only show up
|
||||
// if at least one tab gets small enough to have its name cut off?
|
||||
// [x] I found the "context menu" convention to be confusing. For example, if
|
||||
// I left-click on a tab, it selects the tab. If I right-click on a tab,
|
||||
// it opens the context menu. However, if I left-click on a module, it
|
||||
// opens the context window. It seems like maybe menus should be right,
|
||||
// and left should do the default action, more consistently?
|
||||
//
|
||||
// [x] double click on procedure in procedures tab to jump to source
|
||||
// [x] highlighted text & ctrl+f -> auto-fill search query
|
||||
// [x] double-click any part of frame in callstack view -> snap to function
|
||||
// [x] Menus take too long to show up. I would prefer it if they were instant.
|
||||
// The animation doesn't really provide any useful cues, since I know
|
||||
// where the menu came from.
|
||||
// [x] user settings (ui & functionality - generally need a story for it)
|
||||
// [x] hover animations
|
||||
// [x] press animations
|
||||
// [x] focus animations
|
||||
// [x] tooltip animations
|
||||
// [x] context menu animations
|
||||
// [x] scrolling animations
|
||||
// [x] background blur
|
||||
// [x] tab width
|
||||
// [x] ** In the call stack, I would like to be able to click quickly and move
|
||||
// around the stack. Right now, you can do that with the first and third
|
||||
// column, but the second column drops down a context menu. Since right
|
||||
// click is already for context menus, can it not just be that double-
|
||||
// clicking any column jumps to that stack frame?
|
||||
//
|
||||
// [x] ** I find it really hard to read the code with the heavyweight lines
|
||||
// running through it for breakpoints and stepping and things. Is there a
|
||||
// way to turn the lines off? AFAICT they are based on thread and
|
||||
// breakpoint color, so you can't really control the line drawing? I might
|
||||
// be fine with them, but they would have to be much more light (like
|
||||
// alpha 0.1 or something)
|
||||
// [x] zooming behaves very strangely - sometimes it zooms source code,
|
||||
// sometimes both source code and menu/tab/watch font size, sometimes
|
||||
// just menu/tab/watch font size not source size.
|
||||
// [x] colors: fill out rest of theme presets for new theme setup
|
||||
// [x] I LOVE ALT-W to add watch under cursor, but I would prefer to have it
|
||||
// add what's under the MOUSE cursor instead of the keyboard cursor. Can
|
||||
// we get a command for that so I can bind ALT-W to that instead?
|
||||
// [x] editing multiple bindings for commands
|
||||
|
||||
#ifndef RADDBG_H
|
||||
#define RADDBG_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Execution Types
|
||||
|
||||
typedef enum ExecMode
|
||||
{
|
||||
ExecMode_Normal,
|
||||
ExecMode_IPCSender,
|
||||
ExecMode_Converter,
|
||||
ExecMode_Help,
|
||||
}
|
||||
ExecMode;
|
||||
|
||||
typedef struct IPCInfo IPCInfo;
|
||||
struct IPCInfo
|
||||
{
|
||||
U64 msg_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
//- rjf: IPC resources
|
||||
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4)
|
||||
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
|
||||
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: last focused window
|
||||
global DF_Handle last_focused_window = {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};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend Entry Points
|
||||
|
||||
internal void update_and_render(OS_Handle repaint_window_handle, void *user_data);
|
||||
|
||||
#endif // RADDBG_H
|
||||
|
||||
Reference in New Issue
Block a user