From 1602a9e6ea0cb51aa588d1a6e7b4557f1b9f2103 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 26 Nov 2025 16:27:43 -0800 Subject: [PATCH] runtime target OS handling --- src/ctrl/ctrl_core.c | 107 ++++++++++++++++++++++++------------------- src/ctrl/ctrl_core.h | 7 ++- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index f31cd624..58fd5c70 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -630,6 +630,7 @@ ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event, U64 max) str8_serial_push_struct(scratch.arena, &srl, &event->exception_code); str8_serial_push_struct(scratch.arena, &srl, &event->rgba); str8_serial_push_struct(scratch.arena, &srl, &event->bp_flags); + str8_serial_push_struct(scratch.arena, &srl, &event->target_os); str8_serial_push_struct(scratch.arena, &srl, &event->tls_model); str8_serial_push_struct(scratch.arena, &srl, &event->tls_index); str8_serial_push_struct(scratch.arena, &srl, &event->tls_offset); @@ -666,6 +667,7 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) read_off += str8_deserial_read_struct(string, read_off, &event.exception_code); read_off += str8_deserial_read_struct(string, read_off, &event.rgba); read_off += str8_deserial_read_struct(string, read_off, &event.bp_flags); + read_off += str8_deserial_read_struct(string, read_off, &event.target_os); read_off += str8_deserial_read_struct(string, read_off, &event.tls_model); read_off += str8_deserial_read_struct(string, read_off, &event.tls_index); read_off += str8_deserial_read_struct(string, read_off, &event.tls_offset); @@ -1270,6 +1272,7 @@ ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *lis CTRL_Entity *machine = ctrl_entity_from_handle(&store->ctx, ctrl_handle_make(event->entity.machine_id, dmn_handle_zero())); CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->arch, event->entity, (U64)event->entity_id); process->tls_model = event->tls_model; + process->target_os = event->target_os; }break; case CTRL_EventKind_EndProc: { @@ -2129,7 +2132,7 @@ ctrl_establish_frame_unwind_context__dwarf(Arena *arena, CTRL_Handle process_han } internal CTRL_UnwindStepResult -ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us) +ctrl_unwind_step__dwarf(CTRL_Handle process_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us) { Temp scratch = scratch_begin(0, 0); @@ -3032,47 +3035,6 @@ ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, return result; } -//- rjf: abstracted unwind step - -internal CTRL_UnwindStepResult -ctrl_establish_frame_unwind_context(Arena *arena, CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us, CTRL_FrameUnwindContext *ctx_out) -{ - CTRL_UnwindStepResult result = {0}; -#if OS_LINUX - result = ctrl_establish_frame_unwind_context__dwarf(arena, process_handle, module_handle, arch, regs, endt_us, ctx_out); -#elif OS_WINDOWS - // windows does not have a concept of frame context -#else -# error "unwinder is not defined for current OS" -#endif - return result; -} - -internal CTRL_UnwindStepResult -ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us) -{ - CTRL_UnwindStepResult result = {0}; -#if OS_LINUX - result = ctrl_unwind_step__dwarf(process, module, arch, reg_block, frame_ctx, endt_us); -#elif OS_WINDOWS - switch(arch) - { - case Arch_Null:{}break; - case Arch_x64:{result = ctrl_unwind_step__pe_x64(process, module, module_base_vaddr, reg_block, endt_us);}break; - case Arch_x86: - case Arch_arm32: - case Arch_arm64: - { - NotImplemented; - }break; - default:{InvalidPath;}break; - } -#else -# error "unwinder is not defined for current OS" -#endif - return result; -} - //- rjf: abstracted full unwind internal CTRL_Unwind @@ -3110,11 +3072,28 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U } // rip -> module - CTRL_Entity *module = ctrl_module_from_process_vaddr(process_entity, rip); + CTRL_Entity *module_entity = ctrl_module_from_process_vaddr(process_entity, rip); // establish frame context CTRL_FrameUnwindContext frame_ctx = {0}; - CTRL_UnwindStepResult frame_ctx_result = ctrl_establish_frame_unwind_context(scratch.arena, process_entity->handle, module->handle, arch, regs_block, endt_us, &frame_ctx); + CTRL_UnwindStepResult frame_ctx_result = {0}; + switch(process_entity->target_os) + { + case OperatingSystem_Null:{}break; + case OperatingSystem_Windows: + { + // no concept of frame unwind context + }break; + case OperatingSystem_Linux: + { + frame_ctx_result = ctrl_establish_frame_unwind_context__dwarf(arena, process_entity->handle, module_entity->handle, arch, regs_block, endt_us, &frame_ctx); + }break; + case OperatingSystem_Mac: + { + NotImplemented; + }break; + default: { InvalidPath; }break; + } unwind.flags |= frame_ctx_result.flags; if(unwind.flags & (CTRL_UnwindFlag_Stale|CTRL_UnwindFlag_Error)) { @@ -3131,10 +3110,41 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U frame_node_count += 1; // rjf: unwind one step - CTRL_UnwindStepResult step = ctrl_unwind_step(process_entity->handle, module->handle, module->vaddr_range.min, arch, regs_block, &frame_ctx, endt_us); - unwind.flags |= step.flags; + CTRL_UnwindStepResult step_result = {0}; + switch(process_entity->target_os) + { + case OperatingSystem_Null:{}break; + case OperatingSystem_Windows: + { + switch(arch) + { + case Arch_Null:{}break; + case Arch_x64: + { + step_result = ctrl_unwind_step__pe_x64(process_entity->handle, module_entity->handle, module_entity->vaddr_range.min, regs_block, endt_us); + }break; + case Arch_x86: + case Arch_arm32: + case Arch_arm64: + { + NotImplemented; + }break; + default: { InvalidPath; } break; + } + }break; + case OperatingSystem_Linux: + { + step_result = ctrl_unwind_step__dwarf(process_entity->handle, arch, regs_block, &frame_ctx, endt_us); + }break; + case OperatingSystem_Mac: + { + NotImplemented; + }break; + default: { InvalidPath; }break; + } // stop unwinding on errors or stale data + unwind.flags |= step_result.flags; if(unwind.flags & (CTRL_UnwindFlag_Stale|CTRL_UnwindFlag_Error) || (regs_rsp_from_arch_block(arch, regs_block) == rsp && regs_rip_from_arch_block(arch, regs_block) == rip)) { @@ -4524,6 +4534,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->arch = event->arch; out_evt->entity_id = event->code; out_evt->tls_model = ctrl_dynamic_linker_type_from_dmn(event->tls_model); + out_evt->target_os = OperatingSystem_CURRENT; // TODO: operating system of the remote target machine ctrl_state->process_counter += 1; }break; case DMN_EventKind_CreateThread: @@ -6945,6 +6956,10 @@ ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, dst_e->timestamp = src_e->timestamp; dst_e->bp_flags = src_e->bp_flags; dst_e->string = push_str8_copy(scratch.arena, src_e->string); + dst_e->tls_index = src_e->tls_index; + dst_e->tls_offset = src_e->tls_offset; + dst_e->target_os = src_e->target_os; + dst_e->tls_model = src_e->tls_model; } if(dst_parent == &ctrl_entity_nil) { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 650207d8..77870198 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -133,6 +133,7 @@ struct CTRL_Entity CTRL_TlsModel tls_model; U64 tls_index; U64 tls_offset; + OperatingSystem target_os; }; typedef struct CTRL_EntityNode CTRL_EntityNode; @@ -544,6 +545,7 @@ struct CTRL_Event U32 rgba; CTRL_UserBreakpointFlags bp_flags; String8 string; + OperatingSystem target_os; CTRL_TlsModel tls_model; }; @@ -960,15 +962,12 @@ internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Arch arch, CTRL_Unwind //- DWARF internal CTRL_UnwindStepResult ctrl_establish_frame_unwind_context__dwarf(Arena *arena, CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us, CTRL_FrameUnwindContext *ctx_out); -internal CTRL_UnwindStepResult ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step__dwarf(CTRL_Handle process_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us); //- rjf: [x64] internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, U64 module_base_vaddr, REGS_RegBlockX64 *regs, U64 endt_us); -//- rjf: abstracted unwind step -internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us); - //- rjf: abstracted full unwind internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U64 endt_us);