update logic for tracking new threads

This commit is contained in:
Nikita Smith
2025-12-20 14:41:01 -08:00
parent 13ce0cf020
commit f150662cc4
2 changed files with 80 additions and 42 deletions
+45 -11
View File
@@ -1430,11 +1430,9 @@ dmn_lnx_handle_not_attached(Arena *arena, DMN_EventList *events)
e->error_kind = DMN_ErrorKind_NotAttached; e->error_kind = DMN_ErrorKind_NotAttached;
} }
internal DMN_LNX_Entity * internal void
dmn_lnx_handle_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, pid_t tid) dmn_lnx_init_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, DMN_LNX_Entity *thread)
{ {
DMN_LNX_Entity *thread = dmn_lnx_entity_alloc(process, DMN_LNX_EntityKind_Thread);
thread->id = tid;
thread->arch = process->arch; thread->arch = process->arch;
thread->reg_block = push_array(process->arena, U8, regs_block_size_from_arch(process->arch)); thread->reg_block = push_array(process->arena, U8, regs_block_size_from_arch(process->arch));
thread->thread_state = DMN_LNX_ThreadState_Stopped; thread->thread_state = DMN_LNX_ThreadState_Stopped;
@@ -1462,7 +1460,14 @@ dmn_lnx_handle_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity
e->code = thread->id; e->code = thread->id;
process->thread_count += 1; process->thread_count += 1;
}
internal DMN_LNX_Entity *
dmn_lnx_handle_create_thread(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, pid_t tid)
{
DMN_LNX_Entity *thread = dmn_lnx_entity_alloc(process, DMN_LNX_EntityKind_Thread);
thread->id = tid;
dmn_lnx_init_create_thread(arena, events, process, thread);
return thread; return thread;
} }
@@ -1786,7 +1791,7 @@ dmn_lnx_handle_load_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *
} }
internal void internal void
dmn_lnx_hanlde_unload_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, U64 name_space_id, U64 rdebug_vaddr) dmn_lnx_handle_unload_module(Arena *arena, DMN_EventList *events, DMN_LNX_Entity *process, U64 name_space_id, U64 rdebug_vaddr)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
@@ -1917,7 +1922,7 @@ dmn_lnx_handle_breakpoint(Arena *arena, DMN_EventList *events, DMN_ActiveTrap *u
if(!stap_read_arg_u(probe->args.v[0], process->arch, thread->reg_block, dmn_lnx_stap_memory_read, process, &name_space_id)) { goto unmap_complete_exit; } if(!stap_read_arg_u(probe->args.v[0], process->arch, thread->reg_block, dmn_lnx_stap_memory_read, process, &name_space_id)) { goto unmap_complete_exit; }
if(!stap_read_arg_u(probe->args.v[1], process->arch, thread->reg_block, dmn_lnx_stap_memory_read, process, &rdebug_vaddr)) { goto unmap_complete_exit; } if(!stap_read_arg_u(probe->args.v[1], process->arch, thread->reg_block, dmn_lnx_stap_memory_read, process, &rdebug_vaddr)) { goto unmap_complete_exit; }
dmn_lnx_hanlde_unload_module(arena, events, process, name_space_id, rdebug_vaddr); dmn_lnx_handle_unload_module(arena, events, process, name_space_id, rdebug_vaddr);
is_unmap_completed = 1; is_unmap_completed = 1;
unmap_complete_exit:; unmap_complete_exit:;
@@ -2573,7 +2578,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
if(wifstopped || wifsignaled || wifexited) if(wifstopped || wifsignaled || wifexited)
{ {
DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id); DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id);
if(thread->thread_state != DMN_LNX_ThreadState_PendingCreation)
{
// kernel may send multiple stop signals for the same thread, // kernel may send multiple stop signals for the same thread,
// so count first stop signal and ignore subsequent signals // so count first stop signal and ignore subsequent signals
B32 is_first_thread_to_stop = 0; B32 is_first_thread_to_stop = 0;
@@ -2609,6 +2615,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
} }
} }
} }
}
// normal child exit via _exit or exit() // normal child exit via _exit or exit()
if(wifexited) if(wifexited)
@@ -2627,7 +2634,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
// read thread registers // read thread registers
{ {
DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id); DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id);
if(thread != dmn_lnx_nil_entity) if(thread != dmn_lnx_nil_entity && thread->thread_state != DMN_LNX_ThreadState_PendingCreation)
{ {
thread->is_reg_block_dirty = !dmn_lnx_thread_read_reg_block(thread); thread->is_reg_block_dirty = !dmn_lnx_thread_read_reg_block(thread);
Assert(!thread->is_reg_block_dirty); Assert(!thread->is_reg_block_dirty);
@@ -2729,12 +2736,26 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
}break; }break;
case PTRACE_EVENT_CLONE: case PTRACE_EVENT_CLONE:
{ {
// kernel stopped the parent just before scheduling the child to
// give us a chance to prepare to trace it; next event for the child
// will be a PTRACE_EVENT_STOP
pid_t new_pid; pid_t new_pid;
if(OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_GETEVENTMSG, wait_id, 0, &new_pid)) >= 0) if(OS_LNX_RETRY_ON_EINTR(ptrace(PTRACE_GETEVENTMSG, wait_id, 0, &new_pid)) >= 0)
{ {
DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id); DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id);
DMN_LNX_Entity *process = thread->parent; DMN_LNX_Entity *process = thread->parent;
dmn_lnx_handle_create_thread(arena, &events, process, new_pid);
// create a new partially inited thread
DMN_LNX_Entity *new_thread = dmn_lnx_entity_alloc(process, DMN_LNX_EntityKind_Thread);
new_thread->id = new_pid;
new_thread->thread_state = DMN_LNX_ThreadState_PendingCreation;
// create mapping from tid -> new thread
hash_table_push_u64_raw(dmn_lnx_state->arena, dmn_lnx_state->tid_ht, new_thread->id, new_thread);
// do not exit the wait loop before new threads are inited
dmn_lnx_state->threads_pending_creation += 1;
} }
else { Assert(0 && "failed to get new tid"); } else { Assert(0 && "failed to get new tid"); }
}break; }break;
@@ -2772,11 +2793,24 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
{ {
DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id); DMN_LNX_Entity *thread = dmn_lnx_thread_from_pid(wait_id);
DMN_LNX_Entity *process = thread->parent; DMN_LNX_Entity *process = thread->parent;
if(thread->thread_state == DMN_LNX_ThreadState_PendingCreation)
{
// finish thread init
dmn_lnx_init_create_thread(arena, &events, process, thread);
// update global thread counter
AssertAlways(dmn_lnx_state->threads_pending_creation > 0);
dmn_lnx_state->threads_pending_creation -= 1;
}
else
{
if(process->expect_user_interrupt) if(process->expect_user_interrupt)
{ {
process->expect_user_interrupt = 0; process->expect_user_interrupt = 0;
dmn_lnx_handle_halt(arena, &events); dmn_lnx_handle_halt(arena, &events);
} }
}
}break; }break;
default: { Assert(0 && "unexpected ptrace code"); } break; default: { Assert(0 && "unexpected ptrace code"); } break;
} }
@@ -2804,8 +2838,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
} }
else { Assert(0 && "unexpected stop code"); } else { Assert(0 && "unexpected stop code"); }
// do not wait if all threads are stopped and there are no launching processes // do not wait if all threads are stopped, there are no launching processes, and all threads were created
if(stopped_threads >= running_threads.count && dmn_lnx_state->pending_procs.count == 0) if(stopped_threads >= running_threads.count && dmn_lnx_state->pending_procs.count == 0 && dmn_lnx_state->threads_pending_creation == 0)
{ {
break; break;
} }
+6 -2
View File
@@ -63,12 +63,13 @@ StaticAssert(sizeof(DMN_LNX_UserX64) == 912, g_dmn_lnx_user_x64_size_check);
//////////////////////////////// ////////////////////////////////
typedef struct typedef struct DMN_LNX_DbDesc DMN_LNX_DbDesc;
struct DMN_LNX_DbDesc
{ {
U32 bit_size; U32 bit_size;
U32 count; U32 count;
U32 offset; U32 offset;
} DMN_LNX_DbDesc; };
//////////////////////////////// ////////////////////////////////
//~ SDT Probes //~ SDT Probes
@@ -173,6 +174,7 @@ typedef enum DMN_LNX_ThreadState
DMN_LNX_ThreadState_Running, DMN_LNX_ThreadState_Running,
DMN_LNX_ThreadState_Stopped, DMN_LNX_ThreadState_Stopped,
DMN_LNX_ThreadState_Exited, DMN_LNX_ThreadState_Exited,
DMN_LNX_ThreadState_PendingCreation,
} DMN_LNX_ThreadState; } DMN_LNX_ThreadState;
typedef struct DMN_LNX_Entity DMN_LNX_Entity; typedef struct DMN_LNX_Entity DMN_LNX_Entity;
@@ -309,6 +311,8 @@ struct DMN_LNX_State
DMN_LNX_ProcessLaunchList pending_procs; DMN_LNX_ProcessLaunchList pending_procs;
DMN_LNX_ProcessLaunchList free_pids; DMN_LNX_ProcessLaunchList free_pids;
U64 threads_pending_creation;
// halter // halter
Mutex halter_mutex; Mutex halter_mutex;
pid_t halter_tid; pid_t halter_tid;