diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 0e7ce246..9a3a4fed 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1534,6 +1534,46 @@ ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_H return first_pdata; } +internal U64 +ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + U64 result = 0; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->entry_point_voff; + break; + } + } + return result; +} + +internal Rng1U64 +ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + Rng1U64 result = {0}; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->tls_vaddr_range; + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Unwinding Functions @@ -2892,6 +2932,8 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand Arena *arena = arena_alloc(); PE_IntelPdata *pdatas = 0; U64 pdatas_count = 0; + U64 entry_point_voff = 0; + Rng1U64 tls_vaddr_range = {0}; ProfScope("unpack relevant PE info") { B32 is_valid = 1; @@ -2991,6 +3033,40 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand pdatas = push_array(arena, PE_IntelPdata, pdatas_count); dmn_process_read(process, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas); } + + // rjf: extract tls header + PE_TLSHeader64 tls_header = {0}; + if(data_dir_count > PE_DataDirectoryIndex_TLS) + { + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir); + Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + switch(coff_header.machine) + { + default:{}break; + case COFF_MachineType_X86: + { + PE_TLSHeader32 tls_header32 = {0}; + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header32); + tls_header.raw_data_start = (U64)tls_header32.raw_data_start; + tls_header.raw_data_end = (U64)tls_header32.raw_data_end; + tls_header.index_address = (U64)tls_header32.index_address; + tls_header.callbacks_address = (U64)tls_header32.callbacks_address; + tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; + tls_header.characteristics = (U64)tls_header32.characteristics; + }break; + case COFF_MachineType_X64: + { + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header); + }break; + } + } + + // rjf: grab entry point vaddr + entry_point_voff = entry_point; + + // rjf: calculate TLS vaddr range + tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32)); } } @@ -3023,6 +3099,7 @@ ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Hand node->arena = arena; node->pdatas = pdatas; node->pdatas_count = pdatas_count; + node->entry_point_voff = entry_point_voff; } } } @@ -4076,7 +4153,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: add trap for PE header entry if(!entries_found) { - U64 voff = dbgi->pe.entry_point; + U64 voff = ctrl_entry_point_voff_from_module(CTRL_MachineID_Local, module->handle); if(voff != 0) { DMN_Trap trap = {process->handle, module_base_vaddr + voff}; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b5d0d281..854dfc26 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -510,6 +510,8 @@ struct CTRL_ModuleImageInfoCacheNode Arena *arena; PE_IntelPdata *pdatas; U64 pdatas_count; + U64 entry_point_voff; + Rng1U64 tls_vaddr_range; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -738,6 +740,8 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //- rjf: cache lookups internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff); +internal U64 ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); +internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); //////////////////////////////// //~ rjf: Unwinding Functions diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index c9ed1bf1..412ad503 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3541,20 +3541,14 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 DBGI_Scope *scope = dbgi_scope_open(); if(!df_ctrl_targets_running()) { - //- rjf: unpack thread info + //- rjf: unpack module info DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - PE_BinInfo *bin = &dbgi->pe; - B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF - U64 addr_size = bit_size_from_arch(bin->arch)/8; - - //- rjf: grab tls range - Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); + Rng1U64 tls_vaddr_range = ctrl_tls_vaddr_range_from_module(module->ctrl_machine_id, module->ctrl_handle); + U64 addr_size = bit_size_from_arch(process->arch)/8; //- rjf: read module's TLS index U64 tls_index = 0; + if(addr_size != 0) { CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); if(tls_index_slice.data.size >= addr_size) @@ -3564,7 +3558,7 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: PE path - if(bin_is_pe) + if(addr_size != 0) { U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; @@ -3584,10 +3578,10 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: non-PE path (not implemented) +#if 0 if(!bin_is_pe) { // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: -#if 0 // TODO(nick): This code works only if the linked c runtime library is glibc. // Implement CRT detection here. @@ -3614,8 +3608,8 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 { demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); } -#endif } +#endif } dbgi_scope_close(scope); scratch_end(scratch); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 1e7a1ce1..f2c4511f 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -52,15 +52,10 @@ // since that's not normally how Windows fonts work. //////////////////////////////// -//~ rjf: Demon/Cleanup Pass Tasks +//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // -// [ ] TLS eval -> in-process-memory EXE info -// [ ] unwinding -> in-process-memory EXE info // [ ] "root" concept in hash store, which buckets keys & allows usage code to // jettison a collection of keys in retained mode fashion - -//////////////////////////////// -//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // // [ ] Jeff Notes // [ ] highlighted text & ctrl+f -> auto-fill search query @@ -379,6 +374,8 @@ // 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 #ifndef RADDBG_H #define RADDBG_H