linux_demon: intrinsic links in threads/processes for pid mapping

This commit is contained in:
Ryan Fleury committed 2026-08-10 14:40:43 -06:00
1 parent 6b30c395d7
commit 45aeca0bf9
2 files changed
+121 -58

No files matched your search

+90 -47
View File
@@ -425,8 +425,13 @@ lnx_dmn_process_alloc(pid_t pid, LNX_DMN_ProcessState state, LNX_DMN_Process *pa
DLLPushBack(lnx_dmn_state->first_process, lnx_dmn_state->last_process, process);
lnx_dmn_state->process_count += 1;
// push pid -> LNX_DMN_Process mapping
hash_table_push_u64_raw(lnx_dmn_state->arena, lnx_dmn_state->pid_ht, pid, process);
// rjf: record in id -> process table
{
U64 key = (U64)pid;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->process_from_pid_slots_count;
DLLPushBack_NP(lnx_dmn_state->process_from_pid_slots[slot_idx].first, lnx_dmn_state->process_from_pid_slots[slot_idx].last, process, pid_next, pid_prev);
}
scratch_end(scratch);
return process;
@@ -488,42 +493,6 @@ lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64
return module;
}
internal void
lnx_dmn_thread_release(LNX_DMN_Thread *thread)
{
LNX_DMN_Process *process = thread->process;
// purge tid mapping
hash_table_purge_u64(lnx_dmn_state->tid_ht, thread->tid);
// update global thread counter
if(thread->state == LNX_DMN_ThreadState_PendingCreation)
{
AssertAlways(lnx_dmn_state->threads_pending_creation > 0);
lnx_dmn_state->threads_pending_creation -= 1;
}
// remove thread from the list
Assert(process->thread_count > 0);
DLLRemove(process->first_thread, process->last_thread, thread);
process->thread_count -= 1;
// push reg block to the free list
String8Node *reg_block_node;
if(process->ctx->free_reg_block_nodes.node_count)
{
reg_block_node = str8_list_pop_front(&process->ctx->free_reg_block_nodes);
}
else
{
reg_block_node = push_array(process->ctx->arena, String8Node, 1);
}
reg_block_node->string = str8(thread->reg_block, 0);
str8_list_push_node(&process->ctx->free_reg_blocks, reg_block_node);
lnx_dmn_entity_release((LNX_DMN_Entity *)thread);
}
internal void
lnx_dmn_module_release(LNX_DMN_ProcessCtx *ctx, LNX_DMN_Module *module)
{
@@ -676,13 +645,37 @@ lnx_dmn_module_from_handle(DMN_Handle module_handle)
internal LNX_DMN_Thread *
lnx_dmn_thread_from_pid(pid_t tid)
{
return hash_table_search_u64_raw(lnx_dmn_state->tid_ht, tid);
LNX_DMN_Thread *result = 0;
U64 key = (U64)tid;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->thread_from_tid_slots_count;
for(LNX_DMN_Thread *t = lnx_dmn_state->thread_from_tid_slots[slot_idx].first; t != 0; t = t->tid_next)
{
if(t->tid == tid)
{
result = t;
break;
}
}
return result;
}
internal LNX_DMN_Process *
lnx_dmn_process_from_pid(pid_t pid)
{
return hash_table_search_u64_raw(lnx_dmn_state->pid_ht, pid);
LNX_DMN_Process *result = 0;
U64 key = (U64)pid;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->process_from_pid_slots_count;
for(LNX_DMN_Process *p = lnx_dmn_state->process_from_pid_slots[slot_idx].first; p != 0; p = p->pid_next)
{
if(p->pid == pid)
{
result = p;
break;
}
}
return result;
}
////////////////////////////////
@@ -1229,14 +1222,21 @@ dmn_init(void)
lnx_dmn_state->access_mutex = mutex_alloc();
lnx_dmn_state->entities_arena = arena_alloc(.reserve_size = GB(32), .commit_size = KB(64), .flags = ArenaFlag_NoChain);
lnx_dmn_state->entities_base = push_array(lnx_dmn_state->entities_arena, LNX_DMN_Entity, 0);
lnx_dmn_state->tid_ht = hash_table_init(lnx_dmn_state->arena, 0x2000);
lnx_dmn_state->pid_ht = hash_table_init(lnx_dmn_state->arena, 0x400);
lnx_dmn_state->halter_mutex = mutex_alloc();
lnx_dmn_entity_alloc(LNX_DMN_EntityKind_Null);
// rjf: set up id <-> entity tables
{
lnx_dmn_state->process_from_pid_slots_count = 4096;
lnx_dmn_state->process_from_pid_slots = push_array(arena, LNX_DMN_ProcessSlot, lnx_dmn_state->process_from_pid_slots_count);
lnx_dmn_state->thread_from_tid_slots_count = 16384;
lnx_dmn_state->thread_from_tid_slots = push_array(arena, LNX_DMN_ThreadSlot, lnx_dmn_state->thread_from_tid_slots_count);
}
// find offsets of TLS index and TLS offset in the link_map struct
//
// TODO: assuming that target is using same libc version as debugger
//
{
LNX_DMN_DbDesc *tls_modid_desc = dlsym(RTLD_DEFAULT, "_thread_db_link_map_l_tls_modid");
LNX_DMN_DbDesc *tls_offset_desc = dlsym(RTLD_DEFAULT, "_thread_db_link_map_l_tls_offset");
@@ -1248,7 +1248,6 @@ dmn_init(void)
lnx_dmn_state->tls_offset_desc = *tls_offset_desc;
lnx_dmn_state->is_tls_detected = 1;
}
else { Assert(0 && "invalid TLS desc"); }
}
}
}
@@ -2252,7 +2251,41 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
}
// rjf: release thread storage
lnx_dmn_thread_release(thread);
{
// update global thread counter
if(thread->state == LNX_DMN_ThreadState_PendingCreation)
{
lnx_dmn_state->threads_pending_creation -= 1;
}
// rjf: remove thread from per-process thread list
DLLRemove(thread_process->first_thread, thread_process->last_thread, thread);
thread_process->thread_count -= 1;
// rjf: remove thread from id -> thread table
{
U64 key = (U64)thread->tid;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->thread_from_tid_slots_count;
DLLRemove_NP(lnx_dmn_state->thread_from_tid_slots[slot_idx].first, lnx_dmn_state->thread_from_tid_slots[slot_idx].last, thread, tid_next, tid_prev);
}
// rjf: release reg block
String8Node *reg_block_node;
if(thread_process->ctx->free_reg_block_nodes.node_count)
{
reg_block_node = str8_list_pop_front(&thread_process->ctx->free_reg_block_nodes);
}
else
{
reg_block_node = push_array(thread_process->ctx->arena, String8Node, 1);
}
reg_block_node->string = str8(thread->reg_block, 0);
str8_list_push_node(&thread_process->ctx->free_reg_blocks, reg_block_node);
// rjf: release entity record
lnx_dmn_entity_release((LNX_DMN_Entity *)thread);
}
// rjf: last thread in process? -> exit process too
if(thread_process->thread_count == 0)
@@ -2293,7 +2326,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
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);
{
U64 key = (U64)process->pid;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->process_from_pid_slots_count;
DLLRemove_NP(lnx_dmn_state->process_from_pid_slots[slot_idx].first, lnx_dmn_state->process_from_pid_slots[slot_idx].last, process, pid_next, pid_prev);
}
if(process->ctx)
{
process->ctx->ref_count -= 1;
@@ -2954,8 +2992,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
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: map id -> thread
{
U64 key = (U64)wait_id;
U64 hash = u64_hash_from_str8(str8_struct(&key));
U64 slot_idx = hash%lnx_dmn_state->thread_from_tid_slots_count;
DLLPushBack_NP(lnx_dmn_state->thread_from_tid_slots[slot_idx].first, lnx_dmn_state->thread_from_tid_slots[slot_idx].last, new_thread, tid_next, tid_prev);
}
}
// rjf: report
+31 -11
View File
@@ -170,6 +170,8 @@ struct LNX_DMN_Thread
{
LNX_DMN_Thread *next;
LNX_DMN_Thread *prev;
LNX_DMN_Thread *tid_next;
LNX_DMN_Thread *tid_prev;
pid_t tid;
LNX_DMN_ThreadState state;
struct LNX_DMN_Process *process;
@@ -181,6 +183,13 @@ struct LNX_DMN_Thread
U64 dtv_base_vaddr;
};
typedef struct LNX_DMN_ThreadSlot LNX_DMN_ThreadSlot;
struct LNX_DMN_ThreadSlot
{
LNX_DMN_Thread *first;
LNX_DMN_Thread *last;
};
typedef struct LNX_DMN_Module LNX_DMN_Module;
struct LNX_DMN_Module
{
@@ -234,10 +243,12 @@ LNX_DMN_CreateProcessFlags;
typedef struct LNX_DMN_Process LNX_DMN_Process;
struct LNX_DMN_Process
{
LNX_DMN_Process *parent_process;
struct LNX_DMN_ProcessCtx *ctx;
LNX_DMN_Process *next;
LNX_DMN_Process *prev;
LNX_DMN_Process *pid_next;
LNX_DMN_Process *pid_prev;
LNX_DMN_Process *parent_process;
struct LNX_DMN_ProcessCtx *ctx;
pid_t pid;
int fd;
LNX_DMN_ProcessState state;
@@ -250,6 +261,13 @@ struct LNX_DMN_Process
U64 main_thread_exit_code;
};
typedef struct LNX_DMN_ProcessSlot LNX_DMN_ProcessSlot;
struct LNX_DMN_ProcessSlot
{
LNX_DMN_Process *first;
LNX_DMN_Process *last;
};
typedef struct LNX_DMN_ProcessPtrNode LNX_DMN_ProcessPtrNode;
struct LNX_DMN_ProcessPtrNode
{
@@ -340,32 +358,35 @@ struct LNX_DMN_State
Mutex access_mutex;
B32 access_run_state;
// rjf: entity storage
// rjf: main entity storage
Arena *entities_arena;
LNX_DMN_Entity *entities_base;
LNX_DMN_Entity *free_entity;
U64 entities_count;
HashTable *tid_ht; // thread id -> thread entity
HashTable *pid_ht; // process id -> process entity
// rjf: id -> entity tables
LNX_DMN_ProcessSlot *process_from_pid_slots;
U64 process_from_pid_slots_count;
LNX_DMN_ThreadSlot *thread_from_tid_slots;
U64 thread_from_tid_slots_count;
// process tracking
U64 process_count;
// rjf: process entity list
LNX_DMN_Process *first_process;
LNX_DMN_Process *last_process;
U64 process_count;
// process/thread creation tracking
// rjf: pending process/thread counts
U64 process_pending_creation;
U64 threads_pending_creation;
// halter
// rjf: halting state
Mutex halter_mutex;
pid_t halter_tid;
U64 halt_code;
U64 halt_user_data;
B32 is_halting;
// TLS
// rjf: TLS
B32 is_tls_detected;
LNX_DMN_DbDesc tls_modid_desc;
LNX_DMN_DbDesc tls_offset_desc;
@@ -412,7 +433,6 @@ 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_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_thread_release(LNX_DMN_Thread *thread);
internal void lnx_dmn_module_release(LNX_DMN_ProcessCtx *ctx, LNX_DMN_Module *module);
//- rjf: context cloning