major clean-up pass over unwinding/module-info abstraction, + usage in the debug engine. simplified / cleaned up DWARF helpers for unwind info & expressions. decoupling unwinding / DWARF evaluation from memory read callbacks. light module info now prepared by demon layer - debug engine no longer duplicates per-backend parsing. unwind abstraction layer now does thin abstraction over unwinding backends, debug engine only calls abstraction. clean up demon to have fewer ad-hoc 'queries' on handles, and prefer sending info over debug events when possible / when it fits the usage pattern. move DWARF enum specifications to metacode, generate enums/xlists/tables/etc. decouple raddbg/radbin completely from old parsing helpers. replace portion of DWARF dumping; pull out some new parsing helpers from converter / dumper.

This commit is contained in:
Ryan Fleury
2026-06-02 12:11:13 -07:00
parent 541d3afefa
commit d73ce364b9
88 changed files with 9899 additions and 4723 deletions
+3 -9
View File
@@ -37,15 +37,9 @@ d_init(void)
d_ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc();
d_ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = rw_mutex_alloc();
}
d_ctrl_state->module_image_info_cache.slots_count = 1024;
d_ctrl_state->module_image_info_cache.slots = push_array(arena, D_ModuleImageInfoCacheSlot, d_ctrl_state->module_image_info_cache.slots_count);
d_ctrl_state->module_image_info_cache.stripes_count = get_system_info()->logical_processor_count;
d_ctrl_state->module_image_info_cache.stripes = push_array(arena, D_ModuleImageInfoCacheStripe, d_ctrl_state->module_image_info_cache.stripes_count);
for(U64 idx = 0; idx < d_ctrl_state->module_image_info_cache.stripes_count; idx += 1)
{
d_ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc();
d_ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = rw_mutex_alloc();
}
d_ctrl_state->module_info_cache.slots_count = 1024;
d_ctrl_state->module_info_cache.slots = push_array(arena, D_ModuleInfoCacheSlot, d_ctrl_state->module_info_cache.slots_count);
d_ctrl_state->module_info_cache.stripes = stripe_array_alloc(arena);
d_ctrl_state->u2c_ring_size = KB(64);
d_ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, d_ctrl_state->u2c_ring_size);
d_ctrl_state->u2c_ring_mutex = mutex_alloc();
+1
View File
@@ -139,6 +139,7 @@ struct D_Entity
D_TlsModel tls_model;
U64 tls_index;
U64 tls_offset;
U64 tls_root_vaddr;
OperatingSystem target_os;
D_MsgID src_msg_id;
};
+325 -121
View File
@@ -1358,6 +1358,7 @@ d_entity_store_apply_events(D_EntityCtxRWStore *store, D_EventList *list)
}
}
thread->stack_base = event->stack_base;
thread->tls_root_vaddr = event->tls_root;
}
//d_cached_ip_from_thread(&store->ctx, event->entity);
}break;
@@ -1633,6 +1634,25 @@ d_sp_from_thread(D_Handle handle)
return result;
}
internal B32
d_thread_get_module_tls_vaddr(D_Handle thread, D_Handle module, U64 *vaddr_out)
{
B32 result = 0;
// rjf: resolve to demon
DMN_Handle thread_dmn = d_dmn_from_handle(thread);
DMN_Handle module_dmn = d_dmn_from_handle(module);
// rjf: compute vaddr
if(!dmn_handle_match(thread_dmn, dmn_handle_zero()) &&
!dmn_handle_match(module_dmn, dmn_handle_zero()))
{
result = dmn_thread_get_module_tls_vaddr(thread_dmn, module_dmn, vaddr_out);
}
return result;
}
//- rjf: thread register cache reading
internal void *
@@ -1695,14 +1715,6 @@ d_cached_reg_block_from_thread(Arena *arena, D_Handle handle)
return result;
}
internal U64
d_cached_tls_root_vaddr_from_thread(D_Handle handle)
{
DMN_Handle handle_dmn = d_dmn_from_handle(handle);
U64 result = dmn_tls_root_vaddr_from_thread(handle_dmn);
return result;
}
internal U64
d_cached_ip_from_thread(D_Handle handle)
{
@@ -1734,17 +1746,18 @@ d_cached_sp_from_thread(D_Handle handle)
//- rjf: cache lookups
#if 0 // TODO(rjf): @unwind
internal PE_IntelPdata *
d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff)
{
PE_IntelPdata *first_pdata = 0;
{
U64 hash = d_hash_from_handle(module_handle);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
U64 slot_idx = hash%d_ctrl_state->module_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_info_cache.stripes_count;
D_ModuleInfoCacheSlot *slot = &d_ctrl_state->module_info_cache.slots[slot_idx];
D_ModuleInfoCacheStripe *stripe = &d_ctrl_state->module_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module_handle))
{
@@ -1800,70 +1813,54 @@ d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff)
}
return first_pdata;
}
#endif
internal D_ModuleInfo *
d_info_from_module(Access *access, D_Handle module)
{
D_ModuleInfo *result = &d_module_info_nil;
{
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
U64 hash = d_hash_from_handle(module);
U64 slot_idx = hash%cache->slots_count;
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
MutexScopeR(stripe->rw_mutex) for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module))
{
access_touch(access, &n->access_pt, stripe->cv);
result = &n->v;
break;
}
}
}
return result;
}
internal U64
d_entry_point_voff_from_module(D_Handle module_handle)
{
U64 result = 0;
U64 hash = d_hash_from_handle(module_handle);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module_handle))
{
result = n->entry_point_voff;
break;
}
}
Access *access = access_open();
U64 result = d_info_from_module(access, module_handle)->entry_point_voff;
access_close(access);
return result;
}
internal String8
d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle)
{
String8 result = {0};
U64 hash = d_hash_from_handle(module_handle);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module_handle))
{
result = str8_copy(arena, n->local_debug_info_path);
break;
}
}
return result;
}
internal String8
d_raddbg_data_from_module(Arena *arena, D_Handle module_handle)
{
String8 result = {0};
U64 hash = d_hash_from_handle(module_handle);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module_handle))
{
result = push_str8_copy(arena, n->raddbg_data);
break;
}
}
Access *access = access_open();
String8 result = str8_copy(arena, d_info_from_module(access, module_handle)->local_debug_info_path);
access_close(access);
return result;
}
////////////////////////////////
//~ rjf: Unwinding Functions
#if 0 // TODO(rjf): @unwind
//- rjf: [dwarf]
typedef struct D_MemoryReadContextDwarfX64 D_MemoryReadContextDwarfX64;
@@ -1930,11 +1927,11 @@ d_establish_frame_unwind_context__dwarf(Arena *arena, D_Handle process_handle, D
EH_PtrCtx eh_ptr_ctx = {0};
{
U64 hash = d_hash_from_handle(module_handle);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for EachNode(n, D_ModuleImageInfoCacheNode, slot->first)
U64 slot_idx = hash%d_ctrl_state->module_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_info_cache.stripes_count;
D_ModuleInfoCacheSlot *slot = &d_ctrl_state->module_info_cache.slots[slot_idx];
D_ModuleInfoCacheStripe *stripe = &d_ctrl_state->module_info_cache.stripes[stripe_idx];
MutexScopeR(stripe->rw_mutex) for EachNode(n, D_ModuleInfoCacheNode, slot->first)
{
if(d_handle_match(n->module, module_handle))
{
@@ -2998,6 +2995,7 @@ d_unwind_step__pe_x64(D_Handle process_handle, D_Handle module_handle, U64 modul
if(is_stale) {result.flags |= D_UnwindFlag_Stale;}
return result;
}
#endif
//- rjf: abstracted full unwind
@@ -3008,35 +3006,149 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
Temp scratch = scratch_begin(&arena, 1);
D_Unwind unwind = { .flags = D_UnwindFlag_Error };
//////////////////////////////
//- rjf: grab run state pre-unwind computing
//
U64 run_gen = d_run_gen();
//////////////////////////////
//- rjf: unpack args
//
D_Entity *thread_entity = d_entity_from_handle(thread);
D_Entity *process_entity = thread_entity->parent;
Arch arch = thread_entity->arch;
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 arch_reg_block_size = arch_info->reg_block_size;
//////////////////////////////
//- rjf: grab initial register block
//
void *regs_block = d_cached_reg_block_from_thread(scratch.arena, thread);
B32 regs_block_good = (arch != Arch_Null && regs_block != 0);
//- rjf: loop & unwind
//////////////////////////////
//- rjf: grab initial memory
//
MemoryMap memory_map = {0};
{
// NOTE(rjf): we can pre-fill memory that we can expect to load here -
// otherwise we will lazily evaluate it via the unwinding backends below
}
//////////////////////////////
//- rjf: push one frame for register block we already have
//
D_UnwindFrameNode *first_frame_node = 0;
D_UnwindFrameNode *last_frame_node = 0;
U64 frame_node_count = 0;
if(regs_block_good)
{
for(unwind.flags = 0;;)
D_UnwindFrameNode *frame_node = push_array(scratch.arena, D_UnwindFrameNode, 1);
D_UnwindFrame *f = &frame_node->v;
f->regs = push_array_no_zero(arena, U8, arch_reg_block_size);
MemoryCopy(f->regs, regs_block, arch_reg_block_size);
DLLPushBack(first_frame_node, last_frame_node, frame_node);
frame_node_count += 1;
}
//////////////////////////////
//- rjf: loop & unwind
//
if(regs_block_good)
{
unwind.flags = 0;
for(;!unwind.flags;)
{
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 rip = arch_ip_from_reg_block(arch_info, regs_block);
U64 rsp = arch_sp_from_reg_block(arch_info, regs_block);
U64 start_ip = arch_ip_from_reg_block(arch_info, regs_block);
U64 start_sp = arch_sp_from_reg_block(arch_info, regs_block);
// rjf: cancel on zero rip (except the top frame)
if(rip == 0 && frame_node_count > 0)
//- rjf: cancel on zero rip (except the top frame)
if(start_ip == 0 && frame_node_count > 0)
{
break;
}
//- rjf: open access for this step
Access *access = access_open();
//- rjf: ip -> module / unpack
D_Entity *module_entity = d_module_from_process_vaddr(process_entity, start_ip);
D_ModuleInfo *module_info = d_info_from_module(access, module_entity->handle);
UWND_Unwinder unwinder = module_info->unwinder;
UWND_ModuleInfo unwinder_module_info = {module_entity->vaddr_range.min, module_info->unwind_info};
//- rjf: thread * module -> tls vaddr
U64 tls_vaddr = 0;
d_thread_get_module_tls_vaddr(thread_entity->handle, module_entity->handle, &tls_vaddr);
//- rjf: do one unwind step
B32 step_is_good = 0;
for(;!unwind.flags;)
{
// rjf: try step
U64 cfa = 0;
UWND_StepResult step = uwnd_step(unwinder, arch, &memory_map, &unwinder_module_info, tls_vaddr, regs_block, &cfa);
// rjf: if we failed to read memory, try to read that memory, equip to memory map.
// if it is stale and we run out of time, we will need to mark the whole unwind as
// stale. if it can't be read, the unwind fails.
if(step.status == UWND_StepStatus_FailedMemoryRead)
{
D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process_entity->handle, step.missed_read_vaddr_range, 1, 0);
String8 data = slice.data;
if(slice.stale)
{
unwind.flags |= D_UnwindFlag_Stale;
}
else if(data.size < dim_1u64(step.missed_read_vaddr_range))
{
unwind.flags |= D_UnwindFlag_Error;
}
else
{
memory_map_push(scratch.arena, &memory_map, step.missed_read_vaddr_range, data.str);
}
}
// rjf: if the step itself failed, we just fail out.
else if(step.status == UWND_StepStatus_Error)
{
unwind.flags |= D_UnwindFlag_Error;
}
// rjf: if the step worked, we're good. equip this step's CFA to the previously added frame,
// then exit the step loop.
else if(step.status == UWND_StepStatus_Good)
{
last_frame_node->v.cfa = cfa;
step_is_good = 1;
break;
}
}
//- rjf: push successful steps to frame list
if(step_is_good && arch_ip_from_reg_block(arch_info, regs_block) != 0 && arch_ip_from_reg_block(arch_info, regs_block) != start_ip)
{
D_UnwindFrameNode *frame_node = push_array(scratch.arena, D_UnwindFrameNode, 1);
D_UnwindFrame *f = &frame_node->v;
f->regs = push_array_no_zero(arena, U8, arch_reg_block_size);
MemoryCopy(f->regs, regs_block, arch_reg_block_size);
DLLPushBack(first_frame_node, last_frame_node, frame_node);
frame_node_count += 1;
}
//- rjf: close access
access_close(access);
//- rjf: exit if we made no progress on the unwind
if(arch_ip_from_reg_block(arch_info, regs_block) == start_ip ||
arch_sp_from_reg_block(arch_info, regs_block) == start_sp)
{
break;
}
#if 0 // TODO(rjf): @unwind
// rip -> module
D_Entity *module_entity = d_module_from_process_vaddr(process_entity, rip);
@@ -3097,13 +3209,14 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
}break;
}
// stop unwinding on errors or stale data
// rjf: stop unwinding on errors or stale data
unwind.flags |= step_result.flags;
if(unwind.flags & (D_UnwindFlag_Stale|D_UnwindFlag_Error) ||
(arch_sp_from_reg_block(arch_info, regs_block) == rsp && arch_ip_from_reg_block(arch_info, regs_block) == rip))
{
break;
}
#endif
}
}
@@ -3758,23 +3871,47 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
{
Temp scratch = scratch_begin(0,0);
//- rjf: set up per-module info
//////////////////////////////
//- rjf: allocate / set up basic per-module info
//
Arena *arena = arena_alloc();
String8 raddbg_data = d_data_from_process_vaddr_range(arena, process, shift_1u64(module_info->raddbg_info_voff_range, base_vaddr), 0);
U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
EH_PtrCtx eh_ptr_ctx = {.pc_vaddr = max_U64, .text_vaddr = max_U64, .data_vaddr = max_U64, .func_vaddr = max_U64, .ptr_align = 0};
EH_FrameHdr eh_frame_hdr = {0};
B32 is_unwind_eh = 0;
if(module_info->eh_frame_header_vaddr_range.min != 0)
//////////////////////////////
//- rjf: prepare unwind info
//
UWND_Unwinder unwinder = UWND_Unwinder_Null;
void *unwind_info_opaque = 0;
{
String8 eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, module_info->eh_frame_header_vaddr_range, 0);
eh_ptr_ctx.pc_vaddr = module_info->eh_frame_header_vaddr_range.min;
eh_ptr_ctx.data_vaddr = module_info->eh_frame_header_vaddr_range.min;
eh_frame_hdr = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(module_info->arch), &eh_ptr_ctx);
is_unwind_eh = 1;
//- rjf: PE/x64 unwinder
if(dim_1u64(module_info->pe_intel_pdatas_vaddr_range) != 0)
{
unwinder = UWND_Unwinder_PEx64;
PE_X64_UWND_ModuleUnwindInfo *unwind_info = push_array(arena, PE_X64_UWND_ModuleUnwindInfo, 1);
{
U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
unwind_info->pdatas = pdatas;
unwind_info->pdatas_count = pdatas_count;
}
unwind_info_opaque = unwind_info;
}
//- rjf: .eh_frame unwinder
else if(dim_1u64(module_info->eh_frame_header_vaddr_range) != 0)
{
unwinder = UWND_Unwinder_EHFrame;
EH_UWND_ModuleUnwindInfo *unwind_info = push_array(arena, EH_UWND_ModuleUnwindInfo, 1);
{
String8 eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, module_info->eh_frame_header_vaddr_range, 0);
unwind_info->ptr_ctx.pc_vaddr = module_info->eh_frame_header_vaddr_range.min;
unwind_info->ptr_ctx.data_vaddr = module_info->eh_frame_header_vaddr_range.min;
unwind_info->header = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(module_info->arch), &unwind_info->ptr_ctx);
}
unwind_info_opaque = unwind_info;
}
}
//////////////////////////////
@@ -3853,19 +3990,33 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
d_process_write_struct(process, base_vaddr + module_info->raddbg_is_attached_marker_voff, &new_value);
}
//////////////////////////////
//- rjf: fill info
//
D_ModuleInfo info = {0};
{
info.entry_point_voff = module_info->entry_point_voff;
info.unwinder = unwinder;
info.unwind_info = unwind_info_opaque;
info.local_debug_info_path = initial_debug_info_path;
info.debug_info_unique_identifier = debug_info_unique_identifier;
info.raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
info.raddbg_data = raddbg_data;
}
//////////////////////////////
//- rjf: insert info into cache
//
{
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
U64 hash = d_hash_from_handle(module);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
U64 slot_idx = hash%cache->slots_count;
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
MutexScopeW(stripe->rw_mutex)
{
D_ModuleImageInfoCacheNode *node = 0;
for EachNode(n, D_ModuleImageInfoCacheNode, slot->first)
D_ModuleInfoCacheNode *node = 0;
for EachNode(n, D_ModuleInfoCacheNode, slot->first)
{
if(d_handle_match(n->module, module))
{
@@ -3875,21 +4026,11 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
}
if(!node)
{
node = push_array(arena, D_ModuleImageInfoCacheNode, 1);
node = push_array(arena, D_ModuleInfoCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->module = module;
node->arena = arena;
node->pdatas = pdatas;
node->pdatas_count = pdatas_count;
node->cfi_rebase = module_info->cfi_rebase;
node->is_unwind_eh = is_unwind_eh;
node->eh_frame_hdr = eh_frame_hdr;
node->eh_ptr_ctx = eh_ptr_ctx;
node->entry_point_voff = module_info->entry_point_voff;
node->local_debug_info_path = initial_debug_info_path;
node->debug_info_unique_identifier= debug_info_unique_identifier;
node->raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
node->raddbg_data = str8_copy(arena, raddbg_data);
node->module = module;
node->arena = arena;
node->v = info;
}
}
}
@@ -3903,19 +4044,19 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
DMN_Handle process_dmn = d_dmn_from_handle(process);
//////////////////////////////
//- rjf: evict module image info from cache
//- rjf: evict module info from cache
//
U64 raddbg_attached_marker_voff = 0;
{
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
U64 hash = d_hash_from_handle(module);
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
MutexScopeW(stripe->rw_mutex)
U64 slot_idx = hash%cache->slots_count;
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
MutexScopeW(stripe->rw_mutex) for(;;)
{
D_ModuleImageInfoCacheNode *node = 0;
for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
D_ModuleInfoCacheNode *node = 0;
for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
{
if(d_handle_match(n->module, module))
{
@@ -3923,12 +4064,14 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
break;
}
}
if(node)
if(node && access_pt_is_expired(&node->access_pt, .time = 0, .update_idxs = 0))
{
raddbg_attached_marker_voff = node->raddbg_attached_marker_voff;
raddbg_attached_marker_voff = node->v.raddbg_attached_marker_voff;
DLLRemove(slot->first, slot->last, node);
arena_release(node->arena);
break;
}
cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64);
}
}
@@ -4314,8 +4457,8 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
out_evt->parent = d_handle_from_dmn(D_MachineID_Local, event->process);
out_evt->arch = event->arch;
out_evt->entity_id = event->code;
out_evt->stack_base = dmn_stack_base_vaddr_from_thread(event->thread);
out_evt->tls_root = dmn_tls_root_vaddr_from_thread(event->thread);
out_evt->stack_base = event->stack_pointer;
out_evt->tls_root = event->tls_root_vaddr;
out_evt->rip_vaddr = event->instruction_pointer;
out_evt->string = event->string;
}break;
@@ -5902,7 +6045,9 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
//- rjf: add traps for module-baked entry points, if specified
if(!entries_found)
{
String8 raddbg_data = d_raddbg_data_from_module(scratch.arena, module->handle);
Access *access = access_open();
D_ModuleInfo *module_info = d_info_from_module(access, module->handle);
String8 raddbg_data = module_info->raddbg_data;
U8 split_char = 0;
String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0);
for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next)
@@ -5932,6 +6077,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
}
}
}
access_close(access);
}
//- rjf: add traps for PID-correllated entry points
@@ -7091,6 +7237,64 @@ d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *
return good;
}
////////////////////////////////
//~ rjf: TLS Address Artifact Cache Hooks / Lookups
internal AC_Artifact
d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
{
// rjf: unpack key
D_Handle thread = {0};
D_Handle module = {0};
{
U64 off = 0;
off += str8_deserial_read_struct(key, off, &thread);
off += str8_deserial_read_struct(key, off, &module);
}
// rjf: resolve to demon
DMN_Handle thread_dmn = d_dmn_from_handle(thread);
DMN_Handle module_dmn = d_dmn_from_handle(module);
// rjf: compute vaddr
U64 tls_vaddr = 0;
B32 success = 1;
if(!dmn_handle_match(thread_dmn, dmn_handle_zero()) &&
!dmn_handle_match(module_dmn, dmn_handle_zero()))
{
success = dmn_thread_get_module_tls_vaddr(thread_dmn, module_dmn, &tls_vaddr);
}
// rjf: if not successful -> retry
if(!success)
{
retry_out[0] = 1;
}
// rjf: package as artifact
AC_Artifact artifact = {0};
artifact.u64[0] = tls_vaddr;
return artifact;
}
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact)
{
// NOTE(rjf): no-op
}
internal U64
d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out)
{
U64 result = 0;
Access *access = access_open();
D_Handle key_data[] = {thread_handle, module_handle};
String8 key = str8((U8 *)&key_data[0], sizeof(key_data));
AC_Artifact artifact = ac_artifact_from_key(access, key, d_tls_vaddr_artifact_create, d_tls_vaddr_artifact_destroy, endt_us, .stale_out = stale_out);
result = artifact.u64[0];
access_close(access);
return result;
}
////////////////////////////////
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
@@ -7226,7 +7430,7 @@ d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U6
{
pre_reg_gen = d_reg_gen();
pre_mem_gen = d_mem_gen();
unwind = d_unwind_from_thread(arena, thread_handle, now_time_us()+5000);
unwind = d_unwind_from_thread(arena, thread_handle, 0);
if(!(unwind.flags & D_UnwindFlag_Stale))
{
good = 1;
+39 -31
View File
@@ -49,6 +49,7 @@ struct D_Unwind
D_UnwindFlags flags;
};
#if 0 // TODO(rjf): @unwind
typedef struct D_FrameUnwindContext D_FrameUnwindContext;
struct D_FrameUnwindContext
{
@@ -57,6 +58,7 @@ struct D_FrameUnwindContext
DW_CFI_Row *cfi_row;
U64 ret_addr_reg;
};
#endif
////////////////////////////////
//~ rjf: Call Stack Types
@@ -171,21 +173,12 @@ struct D_ThreadRegCache
////////////////////////////////
//~ rjf: Module Image Info Cache Types
typedef struct D_ModuleImageInfoCacheNode D_ModuleImageInfoCacheNode;
struct D_ModuleImageInfoCacheNode
typedef struct D_ModuleInfo D_ModuleInfo;
struct D_ModuleInfo
{
D_ModuleImageInfoCacheNode *next;
D_ModuleImageInfoCacheNode *prev;
D_Handle module;
Arena *arena;
PE_IntelPdata *pdatas;
U64 pdatas_count;
U64 cfi_rebase;
String8 dwarf_unwind_data;
B32 is_unwind_eh;
EH_FrameHdr eh_frame_hdr;
EH_PtrCtx eh_ptr_ctx;
U64 entry_point_voff;
UWND_Unwinder unwinder;
void *unwind_info;
String8 local_debug_info_path;
String8 local_server_cache_debug_info_path;
String8 debug_info_unique_identifier;
@@ -193,27 +186,30 @@ struct D_ModuleImageInfoCacheNode
String8 raddbg_data;
};
typedef struct D_ModuleImageInfoCacheSlot D_ModuleImageInfoCacheSlot;
struct D_ModuleImageInfoCacheSlot
{
D_ModuleImageInfoCacheNode *first;
D_ModuleImageInfoCacheNode *last;
};
typedef struct D_ModuleImageInfoCacheStripe D_ModuleImageInfoCacheStripe;
struct D_ModuleImageInfoCacheStripe
typedef struct D_ModuleInfoCacheNode D_ModuleInfoCacheNode;
struct D_ModuleInfoCacheNode
{
D_ModuleInfoCacheNode *next;
D_ModuleInfoCacheNode *prev;
AccessPt access_pt;
D_Handle module;
Arena *arena;
RWMutex rw_mutex;
D_ModuleInfo v;
};
typedef struct D_ModuleImageInfoCache D_ModuleImageInfoCache;
struct D_ModuleImageInfoCache
typedef struct D_ModuleInfoCacheSlot D_ModuleInfoCacheSlot;
struct D_ModuleInfoCacheSlot
{
D_ModuleInfoCacheNode *first;
D_ModuleInfoCacheNode *last;
};
typedef struct D_ModuleInfoCache D_ModuleInfoCache;
struct D_ModuleInfoCache
{
U64 slots_count;
D_ModuleImageInfoCacheSlot *slots;
U64 stripes_count;
D_ModuleImageInfoCacheStripe *stripes;
D_ModuleInfoCacheSlot *slots;
StripeArray stripes;
};
////////////////////////////////
@@ -340,7 +336,7 @@ struct D_CtrlState
// rjf: caches
D_ThreadRegCache thread_reg_cache;
D_ModuleImageInfoCache module_image_info_cache;
D_ModuleInfoCache module_info_cache;
D_DumpCache dump_cache;
// rjf: generations
@@ -413,6 +409,7 @@ read_only global D_CallStackTreeNode d_call_stack_tree_node_nil =
&d_call_stack_tree_node_nil,
};
thread_static D_EntityCtxLookupAccel *d_entity_ctx_lookup_accel = 0;
read_only global D_ModuleInfo d_module_info_nil = {0};
////////////////////////////////
//~ rjf: Basic Type Functions
@@ -550,10 +547,10 @@ internal B32 d_thread_read_reg_block(D_Handle handle, void *reg_block);
internal B32 d_thread_write_reg_block(D_Handle thread, void *reg_block);
internal U64 d_ip_from_thread(D_Handle handle);
internal U64 d_sp_from_thread(D_Handle handle);
internal B32 d_thread_get_module_tls_vaddr(D_Handle thread, D_Handle module, U64 *vaddr_out);
//- rjf: thread register cache reading
internal void *d_cached_reg_block_from_thread(Arena *arena, D_Handle handle);
internal U64 d_cached_tls_root_vaddr_from_thread(D_Handle handle);
internal U64 d_cached_ip_from_thread(D_Handle handle);
internal U64 d_cached_sp_from_thread(D_Handle handle);
@@ -561,14 +558,17 @@ internal U64 d_cached_sp_from_thread(D_Handle handle);
//~ rjf: Module Image Info Functions
//- rjf: cache lookups
#if 0 // TODO(rjf): @unwind
internal PE_IntelPdata *d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff);
#endif
internal D_ModuleInfo *d_info_from_module(Access *access, D_Handle module);
internal U64 d_entry_point_voff_from_module(D_Handle module_handle);
internal String8 d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle);
internal String8 d_raddbg_data_from_module(Arena *arena, D_Handle module_handle);
////////////////////////////////
//~ rjf: Unwinding Functions
#if 0 // TODO(rjf): @unwind
//- rjf: [dwarf]
internal D_UnwindStepResult d_unwind_step_result_from_machine_op_result(MachineOpResult s);
internal D_UnwindStepResult d_establish_frame_unwind_context__dwarf(Arena *arena, D_Handle process_handle, D_Handle module_handle, Arch arch, void *regs, U64 endt_us, D_FrameUnwindContext *ctx_out);
@@ -577,6 +577,7 @@ internal D_UnwindStepResult d_unwind_step__dwarf(D_Handle process_handle, Arch a
//- rjf: [x64]
internal U64 *d_unwind_reg_from_pe_gpr_reg__pe_x64(X64_RegBlock *regs, PE_UnwindGprRegX64 gpr_reg);
internal D_UnwindStepResult d_unwind_step__pe_x64(D_Handle process_handle, D_Handle module_handle, U64 module_base_vaddr, X64_RegBlock *regs, U64 endt_us);
#endif
//- rjf: abstracted full unwind
internal D_Unwind d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us);
@@ -673,6 +674,13 @@ internal D_ProcessMemorySlice d_process_memory_slice_from_vaddr_range(Arena *are
internal B32 d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us);
#define d_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) d_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us))
////////////////////////////////
//~ rjf: TLS Address Artifact Cache Hooks / Lookups
internal AC_Artifact d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact);
internal U64 d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out);
////////////////////////////////
//~ rjf: Call Stack Artifact Cache Hooks / Lookups