mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-10-09 17:35:41 +00:00
sketch out first pass of autos evaluation
This commit is contained in:
@@ -11782,15 +11782,19 @@ rd_frame(void)
|
||||
struct
|
||||
{
|
||||
String8 name;
|
||||
E_TypeIRExtFunctionType *irext;
|
||||
E_TypeExpandInfoFunctionType *info;
|
||||
E_TypeExpandRangeFunctionType *range;
|
||||
}
|
||||
collection_infos[] =
|
||||
{
|
||||
#define Collection(name) {str8_lit_comp(#name), E_TYPE_EXPAND_INFO_FUNCTION_NAME(name), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)}
|
||||
Collection(locals),
|
||||
Collection(registers),
|
||||
#undef Collection
|
||||
#define Collection1(name) {str8_lit_comp(#name), 0, E_TYPE_EXPAND_INFO_FUNCTION_NAME(name), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)}
|
||||
#define Collection2(name) {str8_lit_comp(#name), E_TYPE_IREXT_FUNCTION_NAME(name), E_TYPE_EXPAND_INFO_FUNCTION_NAME(name), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)}
|
||||
Collection1(locals),
|
||||
Collection1(registers),
|
||||
Collection2(autos),
|
||||
#undef Collection1
|
||||
#undef Collection2
|
||||
};
|
||||
for EachElement(idx, collection_infos)
|
||||
{
|
||||
@@ -11798,6 +11802,7 @@ rd_frame(void)
|
||||
E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0));
|
||||
expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set,
|
||||
.name = collection_name,
|
||||
.irext = collection_infos[idx].irext,
|
||||
.expand =
|
||||
{
|
||||
.info = collection_infos[idx].info,
|
||||
@@ -16539,6 +16544,28 @@ rd_frame(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: update the autos-determining code range
|
||||
{
|
||||
D_Handle new_thread_handle = thread->handle;
|
||||
U64 new_sp = d_rsp_from_thread(&d_user_state->ctrl_entity_store->ctx, new_thread_handle);
|
||||
if(thread == &d_entity_nil)
|
||||
{
|
||||
new_thread_handle = selected_thread->handle;
|
||||
}
|
||||
if(d_handle_match(new_thread_handle, rd_state->last_stop_selected_thread) &&
|
||||
new_sp == rd_state->last_stop_selected_thread_sp)
|
||||
{
|
||||
rd_state->autos_determining_vaddr_range = r1u64(rd_state->last_stop_selected_thread_ip, vaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryZeroStruct(&rd_state->autos_determining_vaddr_range);
|
||||
}
|
||||
rd_state->last_stop_selected_thread = new_thread_handle;
|
||||
rd_state->last_stop_selected_thread_ip = vaddr;
|
||||
rd_state->last_stop_selected_thread_sp = new_sp;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +495,19 @@ struct RD_State
|
||||
RD_Regs *next_hover_regs;
|
||||
RD_RegSlot next_hover_regs_slot;
|
||||
|
||||
// rjf: autos-determining code range
|
||||
//
|
||||
// NOTE(rjf): this includes only instructions that we've observed the
|
||||
// selected thread passed. autos are *also* computed from disassembling
|
||||
// the line at which any thread sits, but we only want to collect autos
|
||||
// from larger ranges of instructions when we directly observer this
|
||||
// on a particular selected thread within a single function.
|
||||
//
|
||||
D_Handle last_stop_selected_thread;
|
||||
U64 last_stop_selected_thread_ip;
|
||||
U64 last_stop_selected_thread_sp;
|
||||
Rng1U64 autos_determining_vaddr_range;
|
||||
|
||||
// rjf: icon texture
|
||||
R_Handle icon_texture;
|
||||
|
||||
|
||||
@@ -306,6 +306,222 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: `autos` Type Hooks
|
||||
|
||||
typedef struct RD_AutosAccel RD_AutosAccel;
|
||||
struct RD_AutosAccel
|
||||
{
|
||||
String8Array exprs;
|
||||
};
|
||||
|
||||
E_TYPE_IREXT_FUNCTION_DEF(autos)
|
||||
{
|
||||
E_IRExt irext = {0};
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
//- rjf: compute all autos
|
||||
String8List auto_exprs = {0};
|
||||
ProfScope("compute all autos")
|
||||
{
|
||||
Access *access = access_open();
|
||||
U64 seen_expr_slots_count = 16;
|
||||
String8Node **seen_expr_slots = push_array(scratch.arena, String8Node *, seen_expr_slots_count);
|
||||
D_Handle thread_handle = rd_regs()->thread;
|
||||
D_Entity *thread = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, thread_handle);
|
||||
D_CallStack call_stack = d_call_stack_from_thread(access, thread->handle, 0, 0);
|
||||
if(call_stack.frames_count != 0)
|
||||
{
|
||||
//- rjf: unpack thread / module / debug info / lines
|
||||
ARCH_Info *arch_info = arch_info_from_arch(thread->arch);
|
||||
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
|
||||
U64 thread_ip_vaddr = d_rip_from_thread(&d_user_state->ctrl_entity_store->ctx, thread_handle);
|
||||
D_Entity *module = d_module_from_process_vaddr(process, thread_ip_vaddr);
|
||||
DI_Key dbgi_key = d_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
U64 thread_ip_voff = d_voff_from_vaddr(module, thread_ip_vaddr);
|
||||
D_LineList thread_ip_lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, thread_ip_voff);
|
||||
|
||||
//- rjf: gather all relevant code vaddr ranges
|
||||
Rng1U64List code_vaddr_ranges = {0};
|
||||
{
|
||||
U64 line_range_limit = 0;
|
||||
for EachNode(n, D_LineNode, thread_ip_lines.first)
|
||||
{
|
||||
Rng1U64 line_voff_range = n->v.voff_range;
|
||||
Rng1U64 line_vaddr_range = d_vaddr_range_from_voff_range(module, line_voff_range);
|
||||
rng1u64_list_push(scratch.arena, &code_vaddr_ranges, line_vaddr_range);
|
||||
line_range_limit += 1;
|
||||
if(line_range_limit >= 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
rng1u64_list_push(scratch.arena, &code_vaddr_ranges, rd_state->autos_determining_vaddr_range);
|
||||
}
|
||||
|
||||
//- rjf: for each code vaddr range -> disassemble, look at src/dest of instructions,
|
||||
// map back to location info, & gather expressions for affected symbols
|
||||
for EachNode(n, Rng1U64Node, code_vaddr_ranges.first)
|
||||
{
|
||||
Rng1U64 vaddr_range = n->v;
|
||||
vaddr_range.max = Min(vaddr_range.min+64, vaddr_range.max);
|
||||
D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, vaddr_range, 0, 0);
|
||||
for(U64 off = 0, next_off = 0; off < slice.data.size; off = next_off)
|
||||
{
|
||||
next_off = slice.data.size;
|
||||
|
||||
// rjf: disassemble next instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, thread->arch, vaddr_range.min + off, str8_skip(slice.data, off), DASM_Syntax_Intel);
|
||||
next_off = off + inst.size;
|
||||
|
||||
// rjf: gather locations from instruction
|
||||
struct
|
||||
{
|
||||
ARCH_RegCode reg_code;
|
||||
U64 reg_off;
|
||||
}
|
||||
inst_locations[] =
|
||||
{
|
||||
{inst.dst_reg_code, inst.dst_reg_off},
|
||||
{inst.src_reg_code, inst.src_reg_off},
|
||||
};
|
||||
|
||||
// rjf: for each location -> map to symbols, gather
|
||||
for EachElement(location_idx, inst_locations)
|
||||
{
|
||||
if(inst_locations[location_idx].reg_code != 0)
|
||||
{
|
||||
U64 reg_value = 0;
|
||||
void *regs = call_stack.frames[0].regs;
|
||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[inst_locations[location_idx].reg_code];
|
||||
reg_rng.max = Min(reg_rng.max, reg_rng.min + sizeof(reg_value));
|
||||
if(arch_reg_block_read_range(arch_info, regs, reg_rng, ®_value))
|
||||
{
|
||||
U64 affected_vaddr = reg_value + inst_locations[location_idx].reg_off;
|
||||
|
||||
// rjf: compare against locals
|
||||
{
|
||||
E_String2NumMap *locals_map = e_ir_ctx->locals_map;
|
||||
for(E_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next)
|
||||
{
|
||||
U64 local_num = n->num;
|
||||
if(local_num != 0)
|
||||
{
|
||||
U64 local_idx = local_num-1;
|
||||
RDI_Symbol *local = rdi_element_from_name_idx(rdi, LocalVariables, local_idx);
|
||||
if(rdi_kind_from_location(local->location) == RDI_LocationKind_AddrBytecodeStream ||
|
||||
rdi_kind_from_location(local->location) == RDI_LocationKind_AddrRegPlusOff ||
|
||||
rdi_kind_from_location(local->location) == RDI_LocationKind_AddrAddrRegPlusOff)
|
||||
{
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local->type_idx);
|
||||
E_OpList local_ops = e_oplist_from_location(scratch.arena, rdi, local->location);
|
||||
String8 local_bytecode = e_bytecode_from_oplist(scratch.arena, &local_ops);
|
||||
E_Interpretation local_addr_interpret = e_interpret(local_bytecode);
|
||||
U64 local_vaddr = local_addr_interpret.value.u64;
|
||||
Rng1U64 local_vaddr_range = r1u64(local_vaddr, local_vaddr+type_node->byte_size);
|
||||
if(contains_1u64(local_vaddr_range, affected_vaddr))
|
||||
{
|
||||
String8 local_name = str8_from_rdi_string_idx(rdi, local->name_string_idx);
|
||||
U64 hash = u64_hash_from_str8(local_name);
|
||||
U64 slot_idx = hash%seen_expr_slots_count;
|
||||
B32 already_seen = 0;
|
||||
for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->string, local_name, 0))
|
||||
{
|
||||
already_seen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!already_seen)
|
||||
{
|
||||
str8_list_push(scratch.arena, &auto_exprs, local_name);
|
||||
String8Node *n = push_array(scratch.arena, String8Node, 1);
|
||||
SLLStackPush(seen_expr_slots[slot_idx], n);
|
||||
n->string = local_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: compare against global variables
|
||||
{
|
||||
D_Entity *affected_module = d_module_from_process_vaddr(process, affected_vaddr);
|
||||
U64 affected_voff = d_voff_from_vaddr(affected_module, affected_vaddr);
|
||||
DI_Key affected_dbgi_key = d_dbgi_key_from_module(affected_module);
|
||||
RDI_Parsed *affected_rdi = di_rdi_from_key(access, affected_dbgi_key, 0, 0);
|
||||
RDI_Symbol *affected_gvar = rdi_global_variable_from_voff(affected_rdi, affected_voff);
|
||||
if(affected_gvar->name_string_idx != 0)
|
||||
{
|
||||
String8 gvar_name = fully_qualified_str8_from_rdi_symbol(arena, affected_rdi, affected_gvar);
|
||||
U64 hash = u64_hash_from_str8(gvar_name);
|
||||
U64 slot_idx = hash%seen_expr_slots_count;
|
||||
B32 already_seen = 0;
|
||||
for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->string, gvar_name, 0))
|
||||
{
|
||||
already_seen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!already_seen)
|
||||
{
|
||||
str8_list_push(scratch.arena, &auto_exprs, gvar_name);
|
||||
String8Node *n = push_array(scratch.arena, String8Node, 1);
|
||||
SLLStackPush(seen_expr_slots[slot_idx], n);
|
||||
n->string = gvar_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
access_close(access);
|
||||
}
|
||||
|
||||
//- rjf: gather
|
||||
RD_AutosAccel *accel = push_array(arena, RD_AutosAccel, 1);
|
||||
{
|
||||
accel->exprs = str8_array_from_list(arena, &auto_exprs);
|
||||
}
|
||||
irext.user_data = accel;
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return irext;
|
||||
}
|
||||
|
||||
E_TYPE_EXPAND_INFO_FUNCTION_DEF(autos)
|
||||
{
|
||||
E_TypeExpandInfo info = {0};
|
||||
RD_AutosAccel *accel = (RD_AutosAccel *)eval.irtree.user_data;
|
||||
if(accel != 0)
|
||||
{
|
||||
info.expr_count = accel->exprs.count;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(autos)
|
||||
{
|
||||
RD_AutosAccel *accel = (RD_AutosAccel *)eval.irtree.user_data;
|
||||
if(accel != 0)
|
||||
{
|
||||
for EachInRange(idx, idx_range)
|
||||
{
|
||||
evals_out[idx - idx_range.min] = e_eval_from_string(accel->exprs.v[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Type Hooks
|
||||
|
||||
|
||||
@@ -37,6 +37,13 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(locals);
|
||||
E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers);
|
||||
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: `autos` Type Hooks
|
||||
|
||||
E_TYPE_IREXT_FUNCTION_DEF(autos);
|
||||
E_TYPE_EXPAND_INFO_FUNCTION_DEF(autos);
|
||||
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(autos);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Type Hooks
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: post-0.9.26 TODO notes
|
||||
//
|
||||
// [ ] symbol server
|
||||
// [ ] core dump saving/loading
|
||||
//
|
||||
// [ ] "autos" collection, which can be evaluated
|
||||
// [ ] show "autos" inline in source code near thread?
|
||||
// [ ] memory_size(...) view for quickly evaluating memory sizes
|
||||
@@ -173,7 +176,6 @@
|
||||
//
|
||||
//- control improvements
|
||||
// [ ] debug info overrides (both path-based AND module-based)
|
||||
// [ ] symbol server
|
||||
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
|
||||
// [ ] jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
|
||||
@@ -195,7 +197,6 @@
|
||||
//
|
||||
//- longer-term future features
|
||||
// [ ] long-term future notes from martins
|
||||
// [ ] core dump saving/loading
|
||||
// [ ] parallel call stacks view
|
||||
// [ ] parallel watch view
|
||||
// [ ] mixed native/interpreted/jit debugging
|
||||
@@ -328,7 +329,7 @@
|
||||
#include "radbin/radbin.h"
|
||||
#include "arch/arch_inc.h"
|
||||
#include "dbg_info/dbg_info.h"
|
||||
#include "disasm/disasm.h"
|
||||
#include "disasm/disasm_inc.h"
|
||||
#include "stap/stap_parse.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "eval/eval_inc.h"
|
||||
@@ -381,7 +382,7 @@
|
||||
#include "radbin/radbin.c"
|
||||
#include "arch/arch_inc.c"
|
||||
#include "dbg_info/dbg_info.c"
|
||||
#include "disasm/disasm.c"
|
||||
#include "disasm/disasm_inc.c"
|
||||
#include "stap/stap_parse.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "eval/eval_inc.c"
|
||||
|
||||
Reference in New Issue
Block a user