mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-11-14 10:10:11 -08:00
linux_demon: more reading, flattening, elimination of unnecessary helpers / layers
This commit is contained in:
1 parent
980a9908d1
commit
9f83e388d2
2 files changed
+223
-221
No files matched your search
+222
-199
@@ -432,50 +432,6 @@ lnx_dmn_process_alloc(pid_t pid, LNX_DMN_ProcessState state, LNX_DMN_Process *pa
|
||||
return process;
|
||||
}
|
||||
|
||||
internal LNX_DMN_Thread *
|
||||
lnx_dmn_thread_alloc(LNX_DMN_Process *process, LNX_DMN_ThreadState thread_state, pid_t tid)
|
||||
{
|
||||
void *reg_block;
|
||||
if(process->ctx->free_reg_blocks.node_count)
|
||||
{
|
||||
String8Node *n = str8_list_pop_front(&process->ctx->free_reg_blocks);
|
||||
reg_block = n->string.str;
|
||||
str8_list_push_node(&process->ctx->free_reg_block_nodes, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
ARCH_Info *arch_info = arch_info_from_arch(process->ctx->arch);
|
||||
U64 reg_block_size = arch_info->reg_block_size;
|
||||
reg_block = push_array(process->ctx->arena, U8, reg_block_size);
|
||||
}
|
||||
|
||||
LNX_DMN_Thread *thread = &lnx_dmn_entity_alloc(LNX_DMN_EntityKind_Thread)->thread;
|
||||
thread->tid = tid;
|
||||
thread->state = thread_state;
|
||||
thread->process = process;
|
||||
thread->reg_block = reg_block;
|
||||
thread->dtv_base_vaddr = lnx_dmn_tls_root_vaddr_from_reg_block(process->fd, process->ctx->arch, reg_block);
|
||||
if(thread_state == LNX_DMN_ThreadState_Stopped)
|
||||
{
|
||||
thread->is_reg_block_dirty = !lnx_dmn_thread_read_reg_block(thread);
|
||||
}
|
||||
|
||||
// add thread to the list
|
||||
DLLPushBack(process->first_thread, process->last_thread, thread);
|
||||
process->thread_count += 1;
|
||||
|
||||
// push tid -> thread mapping
|
||||
hash_table_push_u64_raw(lnx_dmn_state->arena, lnx_dmn_state->tid_ht, thread->tid, thread);
|
||||
|
||||
// update global thread counter
|
||||
if(thread_state == LNX_DMN_ThreadState_PendingCreation)
|
||||
{
|
||||
lnx_dmn_state->threads_pending_creation += 1;
|
||||
}
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
internal LNX_DMN_Module *
|
||||
lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64 name_vaddr, U64 name_space_id, B32 is_main)
|
||||
{
|
||||
@@ -532,42 +488,6 @@ lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64
|
||||
return module;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnx_dmn_process_release(LNX_DMN_Process *process)
|
||||
{
|
||||
// update global state
|
||||
AssertAlways(lnx_dmn_state->process_count > 0);
|
||||
DLLRemove(lnx_dmn_state->first_process, lnx_dmn_state->last_process, process);
|
||||
lnx_dmn_state->process_count -= 1;
|
||||
|
||||
// update pending process tracker
|
||||
if(process->state != LNX_DMN_ProcessState_Normal)
|
||||
{
|
||||
Assert(lnx_dmn_state->process_pending_creation > 0);
|
||||
lnx_dmn_state->process_pending_creation -= 1;
|
||||
}
|
||||
|
||||
// close memory handle
|
||||
if(LNX_RETRY_ON_EINTR(close(process->fd)) < 0) { Assert(0 && "failed to close memory descriptor"); }
|
||||
|
||||
// remove pid mapping
|
||||
hash_table_purge_u64(lnx_dmn_state->pid_ht, process->pid);
|
||||
|
||||
// release the context
|
||||
if(process->ctx)
|
||||
{
|
||||
process->ctx->ref_count -= 1;
|
||||
if(process->ctx->ref_count == 0)
|
||||
{
|
||||
Arena *arena = process->ctx->arena;
|
||||
lnx_dmn_entity_release((LNX_DMN_Entity *)process->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// release process entity
|
||||
lnx_dmn_entity_release((LNX_DMN_Entity *)process);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnx_dmn_thread_release(LNX_DMN_Thread *thread)
|
||||
{
|
||||
@@ -1221,29 +1141,6 @@ lnx_dmn_tls_root_vaddr_from_reg_block(int fd, Arch arch, void *reg_block)
|
||||
////////////////////////////////
|
||||
//~ List Helpers
|
||||
|
||||
internal void
|
||||
lnx_dmn_thread_ptr_list_push_node(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n)
|
||||
{
|
||||
DLLPushBack(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal LNX_DMN_ThreadPtrNode *
|
||||
lnx_dmn_thread_ptr_list_push(Arena *arena, LNX_DMN_ThreadPtrList *list, LNX_DMN_Thread *v)
|
||||
{
|
||||
LNX_DMN_ThreadPtrNode *n = push_array(arena, LNX_DMN_ThreadPtrNode, 1);
|
||||
n->v = v;
|
||||
lnx_dmn_thread_ptr_list_push_node(list, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnx_dmn_thread_ptr_list_remove(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n)
|
||||
{
|
||||
DLLRemove(list->first, list->last, n);
|
||||
list->count -= 1;
|
||||
}
|
||||
|
||||
internal LNX_DMN_ModulePtrNode *
|
||||
lnx_dmn_module_ptr_list_push(Arena *arena, LNX_DMN_ModulePtrList *list, LNX_DMN_Module *v)
|
||||
{
|
||||
@@ -1605,7 +1502,16 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
////////////////////////////
|
||||
//- rjf: schedule threads to run
|
||||
//
|
||||
LNX_DMN_ThreadPtrList running_threads = {0};
|
||||
typedef struct ThreadNode ThreadNode;
|
||||
struct ThreadNode
|
||||
{
|
||||
ThreadNode *next;
|
||||
LNX_DMN_Thread *v;
|
||||
};
|
||||
ThreadNode *first_scheduled_thread = 0;
|
||||
ThreadNode *last_scheduled_thread = 0;
|
||||
U64 scheduled_thread_count = 0;
|
||||
U64 running_thread_count = 0;
|
||||
{
|
||||
for EachNode(process, LNX_DMN_Process, lnx_dmn_state->first_process)
|
||||
{
|
||||
@@ -1684,9 +1590,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
// resume thread
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_CONT, thread->tid, 0, sig_code)) >= 0)
|
||||
{
|
||||
thread->state = LNX_DMN_ThreadState_Running;
|
||||
thread->state = LNX_DMN_ThreadState_Running;
|
||||
thread->is_reg_block_dirty = 1;
|
||||
lnx_dmn_thread_ptr_list_push(scratch.arena, &running_threads, thread);
|
||||
ThreadNode *n = push_array(scratch.arena, ThreadNode, 1);
|
||||
SLLQueuePush(first_scheduled_thread, last_scheduled_thread, n);
|
||||
n->v = thread;
|
||||
scheduled_thread_count += 1;
|
||||
running_thread_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1710,20 +1620,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: hash running threads tids
|
||||
//
|
||||
HashTable *running_threads_ht = hash_table_init(scratch.arena, running_threads.count * 2);
|
||||
for EachNode(n, LNX_DMN_ThreadPtrNode, running_threads.first)
|
||||
{
|
||||
hash_table_push_u64_raw(scratch.arena, running_threads_ht, n->v->tid, n);
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: wait the next signal & generate events
|
||||
//
|
||||
B32 is_halt_done = 0;
|
||||
LNX_DMN_ThreadPtrList stopped_threads = {0};
|
||||
for(;;)
|
||||
{
|
||||
//////////////////////////
|
||||
@@ -1738,14 +1638,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: unpack wait_id
|
||||
//- rjf: unpack signal
|
||||
//
|
||||
LNX_DMN_Process *process = lnx_dmn_process_from_pid(wait_id);
|
||||
LNX_DMN_Thread *thread = lnx_dmn_thread_from_pid(wait_id);
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: unpack signal's status
|
||||
//
|
||||
int wifexited = WIFEXITED(status);
|
||||
int wifsignaled = WIFSIGNALED(status);
|
||||
int wifstopped = WIFSTOPPED(status);
|
||||
@@ -1753,15 +1649,33 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
int event_code = (status >> 16);
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: handle signals from initializing processes
|
||||
//- rjf: set up signal handling outputs (top-level handling bit)
|
||||
//
|
||||
B32 signal_handled = 0;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: set up signal handling outputs (process exits / creation)
|
||||
//
|
||||
B32 process_done = 0;
|
||||
B32 process_new = 0;
|
||||
LNX_DMN_CreateProcessFlags process_new_flags = 0;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: set up signal handling outputs (thread exits / creation / stops)
|
||||
//
|
||||
B32 thread_done = 0;
|
||||
B32 thread_done_report_events = 0;
|
||||
U64 thread_done_exit_code = 0;
|
||||
B32 thread_new = 0;
|
||||
LNX_DMN_ThreadState thread_new_state = LNX_DMN_ThreadState_Null;
|
||||
B32 thread_new_report_events = 0;
|
||||
LNX_DMN_Process *thread_new_parent = process;
|
||||
B32 thread_stop = 0;
|
||||
B32 thread_initial_stop = 0;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: handle signals from initializing processes
|
||||
//
|
||||
if(process && process->state != LNX_DMN_ProcessState_Normal)
|
||||
{
|
||||
//- rjf: advance process initialization state
|
||||
@@ -1824,23 +1738,15 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: any thread stop -> interrupt all threads
|
||||
//- rjf: any thread stop -> update thread state, halt other threads if needed
|
||||
//
|
||||
if(!signal_handled && (wifexited || wifsignaled || wifstopped))
|
||||
{
|
||||
LNX_DMN_ThreadPtrNode *thread_n = hash_table_search_u64_raw(running_threads_ht, wait_id);
|
||||
if(thread_n)
|
||||
B32 thread_running = (thread && thread->state == LNX_DMN_ThreadState_Running);
|
||||
|
||||
// rjf: update thread running state
|
||||
if(thread)
|
||||
{
|
||||
LNX_DMN_Thread *thread = thread_n->v;
|
||||
|
||||
// remove mapping
|
||||
hash_table_purge_u64(running_threads_ht, thread->tid);
|
||||
|
||||
// move thread to the stopped list
|
||||
lnx_dmn_thread_ptr_list_remove(&running_threads, thread_n);
|
||||
lnx_dmn_thread_ptr_list_push_node(&stopped_threads, thread_n);
|
||||
|
||||
// update thread state
|
||||
if(wifstopped && !wifsignaled && !wifexited)
|
||||
{
|
||||
thread->state = LNX_DMN_ThreadState_Stopped;
|
||||
@@ -1849,17 +1755,29 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
thread->state = LNX_DMN_ThreadState_Exited;
|
||||
}
|
||||
else { InvalidPath; }
|
||||
|
||||
// stop all other threads
|
||||
if(stopped_threads.count == 1)
|
||||
}
|
||||
|
||||
// rjf: if this is the first thread to stop out of all we scheduled -> interrupt
|
||||
// all other scheduled threads
|
||||
if(scheduled_thread_count != 0 && running_thread_count == scheduled_thread_count)
|
||||
{
|
||||
for EachNode(n, ThreadNode, first_scheduled_thread)
|
||||
{
|
||||
for EachNode(n, LNX_DMN_ThreadPtrNode, running_threads.first)
|
||||
if(n->v != thread && n->v->state == LNX_DMN_ThreadState_Running)
|
||||
{
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_INTERRUPT, n->v->tid, 0, 0)) < 0) { Assert(0 && "failed to interrupt process"); }
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_INTERRUPT, n->v->tid, 0, 0)) < 0)
|
||||
{
|
||||
log_infof("ptrace error: Couldn't send PTRACE_INTERRUPT to TID %I64u.", n->v->tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: decrement running thread count
|
||||
if(thread_running)
|
||||
{
|
||||
running_thread_count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
@@ -1872,6 +1790,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
thread_done = 1;
|
||||
thread_done_exit_code = wifexited ? WEXITSTATUS(status) : WTERMSIG(status);
|
||||
thread_done_report_events = 1;
|
||||
signal_handled = 1;
|
||||
}
|
||||
|
||||
@@ -1897,6 +1816,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
switch(event_code)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
////////////////////
|
||||
//- rjf: 0 -> general trap path
|
||||
//
|
||||
@@ -2148,19 +2069,22 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
//
|
||||
case PTRACE_EVENT_CLONE:
|
||||
{
|
||||
// kernel stopped the parent just before scheduling the child to
|
||||
// NOTE: 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_tid;
|
||||
pid_t new_tid = 0;
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_GETEVENTMSG, wait_id, 0, &new_tid)) >= 0)
|
||||
{
|
||||
LNX_DMN_Thread *thread = lnx_dmn_thread_from_pid(wait_id);
|
||||
|
||||
// create a new partially inited thread
|
||||
lnx_dmn_thread_alloc(thread->process, LNX_DMN_ThreadState_PendingCreation, new_tid);
|
||||
thread_new = 1;
|
||||
thread_new_report_events = 0;
|
||||
thread_new_state = LNX_DMN_ThreadState_PendingCreation;
|
||||
thread_new_parent = thread->process;
|
||||
lnx_dmn_state->threads_pending_creation += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_infof("ptrace error: PTRACE_EVENT_CLONE reported, but ptrace did not successfully report the new TID.");
|
||||
}
|
||||
else { Assert(0 && "failed to get new tid"); }
|
||||
}break;
|
||||
|
||||
////////////////////
|
||||
@@ -2172,6 +2096,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
if(process->debug_subprocesses)
|
||||
{
|
||||
thread_done = 1;
|
||||
thread_done_report_events = 1;
|
||||
thread_done_exit_code = 0;
|
||||
process_new = 1;
|
||||
process_new_flags = LNX_DMN_CreateProcessFlag_DebugSubprocesses;
|
||||
@@ -2181,42 +2106,35 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_DETACH, wait_id, 0, 0)) >= 0)
|
||||
{
|
||||
thread_done = 1;
|
||||
thread_done_report_events = 1;
|
||||
thread_done_exit_code = 0;
|
||||
}
|
||||
else { Assert(0 && "failed to detach"); }
|
||||
}
|
||||
}break;
|
||||
|
||||
////////////////////
|
||||
//- rjf: exit event -> exit tracing not enabled, so we don't really have anything to do here.
|
||||
//
|
||||
case PTRACE_EVENT_EXIT:
|
||||
{
|
||||
}break;
|
||||
|
||||
////////////////////
|
||||
//- TODO(rjf): seccomp?
|
||||
//
|
||||
case PTRACE_EVENT_SECCOMP:
|
||||
{
|
||||
NotImplemented;
|
||||
}break;
|
||||
|
||||
////////////////////
|
||||
//- rjf: thread stops
|
||||
//
|
||||
case PTRACE_EVENT_STOP:
|
||||
{
|
||||
// rjf: stop event for pending threads -> thread is created & stopped
|
||||
if(thread->state == LNX_DMN_ThreadState_PendingCreation)
|
||||
{
|
||||
LNX_DMN_Process *process = thread->process;
|
||||
lnx_dmn_thread_release(thread);
|
||||
thread = lnx_dmn_thread_alloc(process, LNX_DMN_ThreadState_Stopped, wait_id);
|
||||
lnx_dmn_push_event_create_thread(arena, &events, thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertAlways(thread->state == LNX_DMN_ThreadState_Stopped);
|
||||
thread->state = LNX_DMN_ThreadState_Stopped;
|
||||
lnx_dmn_state->threads_pending_creation -= 1;
|
||||
thread_stop = 1;
|
||||
thread_initial_stop = 1;
|
||||
|
||||
// rjf: report new thread
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_CreateThread;
|
||||
e->process = lnx_dmn_handle_from_process(thread->process);
|
||||
e->thread = lnx_dmn_handle_from_thread(thread);
|
||||
e->arch = thread->process->ctx->arch;
|
||||
e->code = thread->tid;
|
||||
// TODO(rjf): e->stack_pointer = ???;
|
||||
e->tls_root_vaddr = thread->dtv_base_vaddr;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -2249,7 +2167,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
LNX_DMN_Thread *thread = lnx_dmn_thread_from_pid(wait_id);
|
||||
thread->pass_through_signal = 1;
|
||||
thread->pass_through_signo = wstopsig;
|
||||
thread->pass_through_signo = wstopsig;
|
||||
local_persist B8 is_repeatable[] =
|
||||
{
|
||||
0, // null
|
||||
@@ -2325,6 +2243,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
|
||||
// rjf: push exit event
|
||||
if(thread_done_report_events)
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_ExitThread;
|
||||
@@ -2340,12 +2259,16 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
if(thread_process->thread_count == 0)
|
||||
{
|
||||
// rjf: push module events
|
||||
for EachNode(module, LNX_DMN_Module, thread_process->ctx->first_module)
|
||||
if(thread_done_report_events)
|
||||
{
|
||||
lnx_dmn_push_event_unload_module(arena, &events, thread_process, module);
|
||||
for EachNode(module, LNX_DMN_Module, thread_process->ctx->first_module)
|
||||
{
|
||||
lnx_dmn_push_event_unload_module(arena, &events, thread_process, module);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push process exit event
|
||||
if(thread_done_report_events)
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_ExitProcess;
|
||||
@@ -2353,8 +2276,9 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
e->code = thread_process->main_thread_exit_code;
|
||||
}
|
||||
|
||||
// rjf: release process storage
|
||||
lnx_dmn_process_release(thread_process);
|
||||
// rjf: turn on process-end path
|
||||
process = thread_process;
|
||||
process_done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2363,16 +2287,34 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
//
|
||||
if(process_done && process)
|
||||
{
|
||||
lnx_dmn_process_release(process);
|
||||
DLLRemove(lnx_dmn_state->first_process, lnx_dmn_state->last_process, process);
|
||||
lnx_dmn_state->process_count -= 1;
|
||||
if(process->state != LNX_DMN_ProcessState_Normal)
|
||||
{
|
||||
lnx_dmn_state->process_pending_creation -= 1;
|
||||
}
|
||||
LNX_RETRY_ON_EINTR(close(process->fd));
|
||||
hash_table_purge_u64(lnx_dmn_state->pid_ht, process->pid);
|
||||
if(process->ctx)
|
||||
{
|
||||
process->ctx->ref_count -= 1;
|
||||
if(process->ctx->ref_count == 0)
|
||||
{
|
||||
Arena *arena = process->ctx->arena;
|
||||
lnx_dmn_entity_release((LNX_DMN_Entity *)process->ctx);
|
||||
}
|
||||
}
|
||||
lnx_dmn_entity_release((LNX_DMN_Entity *)process);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: new process -> create
|
||||
//
|
||||
LNX_DMN_Process *new_process = 0;
|
||||
if(process_new)
|
||||
{
|
||||
LNX_DMN_Process *parent_process = 0;
|
||||
LNX_DMN_Process *new_process = lnx_dmn_process_alloc(wait_id, LNX_DMN_ProcessState_Normal, 0, !!(process_new_flags & LNX_DMN_CreateProcessFlag_DebugSubprocesses), !!(process_new_flags & LNX_DMN_CreateProcessFlag_Cow));
|
||||
new_process = lnx_dmn_process_alloc(wait_id, LNX_DMN_ProcessState_Normal, 0, !!(process_new_flags & LNX_DMN_CreateProcessFlag_DebugSubprocesses), !!(process_new_flags & LNX_DMN_CreateProcessFlag_Cow));
|
||||
|
||||
////////////////////////
|
||||
//- rjf: get process context - create if this isn't cloning parent process
|
||||
@@ -2958,12 +2900,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
//- rjf: create main thread
|
||||
//
|
||||
lnx_dmn_thread_alloc(new_process, LNX_DMN_ThreadState_Stopped, wait_id);
|
||||
|
||||
////////////////////////
|
||||
//- rjf: push events
|
||||
//- rjf: report process creation
|
||||
//
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
@@ -2972,42 +2909,128 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
e->arch = new_process->ctx->arch;
|
||||
e->code = new_process->pid;
|
||||
}
|
||||
for EachNode(thread, LNX_DMN_Thread, new_process->first_thread)
|
||||
|
||||
////////////////////////
|
||||
//- rjf: create main thread
|
||||
//
|
||||
{
|
||||
lnx_dmn_push_event_create_thread(arena, &events, thread);
|
||||
thread_new = 1;
|
||||
thread_new_state = LNX_DMN_ThreadState_Stopped;
|
||||
thread_new_parent = new_process;
|
||||
thread_new_report_events = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: new thread -> create
|
||||
//
|
||||
if(thread_new)
|
||||
{
|
||||
// rjf: allocate
|
||||
LNX_DMN_Thread *new_thread = 0;
|
||||
{
|
||||
// rjf: allocate reg block
|
||||
void *reg_block = 0;
|
||||
if(process->ctx->free_reg_blocks.node_count)
|
||||
{
|
||||
String8Node *n = str8_list_pop_front(&process->ctx->free_reg_blocks);
|
||||
reg_block = n->string.str;
|
||||
str8_list_push_node(&process->ctx->free_reg_block_nodes, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
ARCH_Info *arch_info = arch_info_from_arch(process->ctx->arch);
|
||||
U64 reg_block_size = arch_info->reg_block_size;
|
||||
reg_block = push_array(process->ctx->arena, U8, reg_block_size);
|
||||
}
|
||||
|
||||
// rjf: allocate thread
|
||||
new_thread = &lnx_dmn_entity_alloc(LNX_DMN_EntityKind_Thread)->thread;
|
||||
new_thread->tid = wait_id;
|
||||
new_thread->state = thread_new_state;
|
||||
new_thread->process = thread_new_parent;
|
||||
new_thread->reg_block = reg_block;
|
||||
|
||||
// rjf: hook thread to process
|
||||
DLLPushBack(thread_new_parent->first_thread, thread_new_parent->last_thread, new_thread);
|
||||
thread_new_parent->thread_count += 1;
|
||||
|
||||
// rjf: map tid -> thread mapping
|
||||
hash_table_push_u64_raw(lnx_dmn_state->arena, lnx_dmn_state->tid_ht, new_thread->tid, new_thread);
|
||||
}
|
||||
|
||||
// rjf: report
|
||||
if(thread_new_report_events)
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_CreateThread;
|
||||
e->process = lnx_dmn_handle_from_process(new_thread->process);
|
||||
e->thread = lnx_dmn_handle_from_thread(new_thread);
|
||||
e->arch = new_thread->process->ctx->arch;
|
||||
e->code = new_thread->tid;
|
||||
// TODO(rjf): e->stack_pointer = ???;
|
||||
e->tls_root_vaddr = new_thread->dtv_base_vaddr;
|
||||
}
|
||||
|
||||
// rjf: if thread is stopped -> turn on initial stop path
|
||||
if(thread_new_state == LNX_DMN_ThreadState_Stopped)
|
||||
{
|
||||
thread = new_thread;
|
||||
thread_stop = 1;
|
||||
thread_initial_stop = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: thread stop -> read registers. if initial stop, form base addr to DTV (TLS)
|
||||
//
|
||||
if(thread_stop)
|
||||
{
|
||||
thread->is_reg_block_dirty = !lnx_dmn_thread_read_reg_block(thread);
|
||||
if(thread_initial_stop)
|
||||
{
|
||||
thread->dtv_base_vaddr = lnx_dmn_tls_root_vaddr_from_reg_block(thread->process->fd, thread->process->ctx->arch, thread->reg_block);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: process was created -> report events for module loads
|
||||
//
|
||||
if(new_process)
|
||||
{
|
||||
for EachNode(module, LNX_DMN_Module, new_process->ctx->first_module)
|
||||
{
|
||||
lnx_dmn_push_event_load_module(arena, &events, new_process->first_thread, module);
|
||||
}
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_HandshakeComplete;
|
||||
e->process = lnx_dmn_handle_from_process(new_process);
|
||||
e->thread = lnx_dmn_handle_from_thread(new_process->first_thread);
|
||||
e->arch = new_process->ctx->arch;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: process was created -> report event for handshake completion
|
||||
//
|
||||
if(new_process)
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_HandshakeComplete;
|
||||
e->process = lnx_dmn_handle_from_process(new_process);
|
||||
e->thread = lnx_dmn_handle_from_thread(new_process->first_thread);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: break if all threads are stopped, no pending processes, no pending threads
|
||||
//
|
||||
if(running_threads.count == 0 && lnx_dmn_state->process_pending_creation == 0 && lnx_dmn_state->threads_pending_creation == 0)
|
||||
if(running_thread_count == 0 && lnx_dmn_state->process_pending_creation == 0 && lnx_dmn_state->threads_pending_creation == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: do halt
|
||||
//- rjf: halted -> push halt event, reset halter state
|
||||
//
|
||||
if(is_halt_done)
|
||||
{
|
||||
// push event
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_Halt;
|
||||
|
||||
// reset state
|
||||
lnx_dmn_state->halter_tid = 0;
|
||||
lnx_dmn_state->halt_code = 0;
|
||||
lnx_dmn_state->halt_user_data = 0;
|
||||
|
||||
@@ -181,22 +181,6 @@ struct LNX_DMN_Thread
|
||||
U64 dtv_base_vaddr;
|
||||
};
|
||||
|
||||
typedef struct LNX_DMN_ThreadPtrNode LNX_DMN_ThreadPtrNode;
|
||||
struct LNX_DMN_ThreadPtrNode
|
||||
{
|
||||
LNX_DMN_ThreadPtrNode *next;
|
||||
LNX_DMN_ThreadPtrNode *prev;
|
||||
LNX_DMN_Thread *v;
|
||||
};
|
||||
|
||||
typedef struct LNX_DMN_ThreadPtrList LNX_DMN_ThreadPtrList;
|
||||
struct LNX_DMN_ThreadPtrList
|
||||
{
|
||||
LNX_DMN_ThreadPtrNode *first;
|
||||
LNX_DMN_ThreadPtrNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct LNX_DMN_Module LNX_DMN_Module;
|
||||
struct LNX_DMN_Module
|
||||
{
|
||||
@@ -427,9 +411,7 @@ internal void lnx_dmn_entity_release(LNX_DMN_Entity *entity);
|
||||
|
||||
//- rjf: specialized allocation / deallocation helpers
|
||||
internal LNX_DMN_Process *lnx_dmn_process_alloc(pid_t pid, LNX_DMN_ProcessState state, LNX_DMN_Process *parent_process, B32 debug_subprocess, B32 is_cow);
|
||||
internal LNX_DMN_Thread *lnx_dmn_thread_alloc(LNX_DMN_Process *process, LNX_DMN_ThreadState thread_state, pid_t tid);
|
||||
internal LNX_DMN_Module *lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64 name_vaddr, U64 name_space_id, B32 is_main);
|
||||
internal void lnx_dmn_process_release(LNX_DMN_Process *process);
|
||||
internal void lnx_dmn_thread_release(LNX_DMN_Thread *thread);
|
||||
internal void lnx_dmn_module_release(LNX_DMN_ProcessCtx *ctx, LNX_DMN_Module *module);
|
||||
|
||||
@@ -463,10 +445,7 @@ internal U64 lnx_dmn_tls_root_vaddr_from_reg_block(int fd, Arch arch, void *reg
|
||||
////////////////////////////////
|
||||
//~ List Helpers
|
||||
|
||||
internal void lnx_dmn_thread_ptr_list_push_node(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n);
|
||||
internal LNX_DMN_ThreadPtrNode * lnx_dmn_thread_ptr_list_push(Arena *arena, LNX_DMN_ThreadPtrList *list, LNX_DMN_Thread *v);
|
||||
internal void lnx_dmn_thread_ptr_list_remove(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n);
|
||||
internal LNX_DMN_ModulePtrNode * lnx_dmn_module_ptr_list_push(Arena *arena, LNX_DMN_ModulePtrList *list, LNX_DMN_Module *v);
|
||||
internal LNX_DMN_ModulePtrNode *lnx_dmn_module_ptr_list_push(Arena *arena, LNX_DMN_ModulePtrList *list, LNX_DMN_Module *v);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Debug Event Pushers
|
||||
|
||||
Reference in new issue
Block a user