From 45aeca0bf99081a5259d74572338139d74c44735 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 10 Aug 2026 14:40:43 -0600 Subject: [PATCH] linux_demon: intrinsic links in threads/processes for pid mapping --- src/linux/demon/linux_demon.c | 137 ++++++++++++++++++++++------------ src/linux/demon/linux_demon.h | 42 ++++++++--- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/src/linux/demon/linux_demon.c b/src/linux/demon/linux_demon.c index e505b482..5d574fd1 100644 --- a/src/linux/demon/linux_demon.c +++ b/src/linux/demon/linux_demon.c @@ -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 diff --git a/src/linux/demon/linux_demon.h b/src/linux/demon/linux_demon.h index 3f699bf4..a13187e6 100644 --- a/src/linux/demon/linux_demon.h +++ b/src/linux/demon/linux_demon.h @@ -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