linux_demon: more reading, flattening, elimination of unnecessary helpers / layers

This commit is contained in:
Ryan Fleury committed 2026-08-10 11:56:42 -06:00
1 parent 980a9908d1
commit 9f83e388d2
2 files changed
+223 -221

No files matched your search

+222 -199
View File
@@ -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;
+1 -22
View File
@@ -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