Files
raddebugger/src/linux/demon/linux_demon.h
T

499 lines
13 KiB
C

// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef LINUX_DEMON_H
#define LINUX_DEMON_H
////////////////////////////////
//~ rjf: Linux Includes
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <elf.h>
////////////////////////////////
//~ rjf: Generated Code
#include "generated/linux_demon.meta.h"
////////////////////////////////
//~ rjf: Register Layouts
//
// These are defined in <sys/user.h>, but only for one architecture at a time
typedef struct LNX_DMN_GprsX64 LNX_DMN_GprsX64;
struct LNX_DMN_GprsX64
{
U64 r15;
U64 r14;
U64 r13;
U64 r12;
U64 rbp;
U64 rbx;
U64 r11;
U64 r10;
U64 r9;
U64 r8;
U64 rax;
U64 rcx;
U64 rdx;
U64 rsi;
U64 rdi;
U64 orig_rax;
U64 rip;
U64 cs;
U64 rflags;
U64 rsp;
U64 ss;
U64 fsbase;
U64 gsbase;
U64 ds;
U64 es;
U64 fs;
U64 gs;
};
typedef struct LNX_DMN_UserX64 LNX_DMN_UserX64;
struct LNX_DMN_UserX64
{
LNX_DMN_GprsX64 regs;
S32 u_fpvalid;
U32 _pad0;
X64_FXSave i387;
U64 u_tsize;
U64 u_dsize;
U64 u_ssize;
U64 start_code;
U64 start_stack;
U64 signal;
U32 reserved;
U32 _pad1;
U64 u_ar0;
U64 u_fpstate;
U64 magic;
U8 u_comm[32];
U64 u_debugreg[8];
};
StaticAssert(sizeof(LNX_DMN_UserX64) == 912, lnx_user_x64_size_check);
////////////////////////////////
//~ rjf: TLS Descriptions
typedef struct LNX_DMN_DbDesc LNX_DMN_DbDesc;
struct LNX_DMN_DbDesc
{
U32 bit_size;
U32 count;
U32 offset;
};
////////////////////////////////
//~ rjf: SDT (Statically-Defined Tracing) Probes
typedef struct LNX_DMN_Probe LNX_DMN_Probe;
struct LNX_DMN_Probe
{
String8 provider;
String8 name;
String8 args_string;
STAP_ArgArray args;
U64 pc;
U64 semaphore;
};
typedef struct LNX_DMN_ProbeNode LNX_DMN_ProbeNode;
struct LNX_DMN_ProbeNode
{
LNX_DMN_ProbeNode *next;
LNX_DMN_Probe v;
};
typedef struct LNX_DMN_ProbeList LNX_DMN_ProbeList;
struct LNX_DMN_ProbeList
{
LNX_DMN_ProbeNode *first;
LNX_DMN_ProbeNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Process Info
typedef struct LNX_DMN_Auxv LNX_DMN_Auxv;
struct LNX_DMN_Auxv
{
U64 base;
U64 phnum;
U64 phent;
U64 phdr;
U64 execfn;
U64 pagesz;
};
typedef struct LNX_DMN_DynamicInfo LNX_DMN_DynamicInfo;
struct LNX_DMN_DynamicInfo
{
U64 hash_vaddr;
U64 gnu_hash_vaddr;
U64 strtab_vaddr;
U64 strtab_size;
U64 symtab_vaddr;
U64 symtab_entry_size;
};
////////////////////////////////
//~ rjf: Entities
typedef enum LNX_DMN_EntityKind
{
LNX_DMN_EntityKind_Null,
LNX_DMN_EntityKind_Process,
LNX_DMN_EntityKind_ProcessCtx,
LNX_DMN_EntityKind_Thread,
LNX_DMN_EntityKind_Module,
}
LNX_DMN_EntityKind;
typedef enum LNX_DMN_ThreadState
{
LNX_DMN_ThreadState_Null,
LNX_DMN_ThreadState_Running,
LNX_DMN_ThreadState_Stopped,
LNX_DMN_ThreadState_Exited,
LNX_DMN_ThreadState_PendingCreation,
}
LNX_DMN_ThreadState;
typedef struct LNX_DMN_Thread LNX_DMN_Thread;
struct LNX_DMN_Thread
{
LNX_DMN_Thread *next;
LNX_DMN_Thread *prev;
pid_t tid;
LNX_DMN_ThreadState state;
struct LNX_DMN_Process *process;
void *reg_block;
B32 is_reg_block_dirty;
B32 pass_through_signal;
U64 pass_through_signo;
U64 orig_rax;
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
{
LNX_DMN_Module *next;
LNX_DMN_Module *prev;
U64 name_vaddr;
U64 base_vaddr;
U64 name_space_id;
U64 size;
U64 phvaddr;
U64 phentsize;
U64 phcount;
U64 tls_index;
U64 tls_offset;
B8 is_live;
B8 is_main;
};
typedef struct LNX_DMN_ModulePtrNode LNX_DMN_ModulePtrNode;
struct LNX_DMN_ModulePtrNode
{
LNX_DMN_ModulePtrNode *next;
LNX_DMN_Module *v;
};
typedef struct LNX_DMN_ModulePtrList LNX_DMN_ModulePtrList;
struct LNX_DMN_ModulePtrList
{
LNX_DMN_ModulePtrNode *first;
LNX_DMN_ModulePtrNode *last;
U64 count;
};
typedef enum LNX_DMN_ProcessState
{
LNX_DMN_ProcessState_Null,
LNX_DMN_ProcessState_Launch,
LNX_DMN_ProcessState_Attach,
LNX_DMN_ProcessState_WaitForExec,
LNX_DMN_ProcessState_ExecFailedDoExit,
LNX_DMN_ProcessState_Normal,
}
LNX_DMN_ProcessState;
typedef enum LNX_DMN_CreateProcessFlags
{
LNX_DMN_CreateProcessFlag_DebugSubprocesses = (1 << 0),
LNX_DMN_CreateProcessFlag_Rebased = (1 << 1),
LNX_DMN_CreateProcessFlag_Cow = (1 << 2),
LNX_DMN_CreateProcessFlag_ClonedMemory = (1 << 3),
}
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;
pid_t pid;
int fd;
LNX_DMN_ProcessState state;
B32 debug_subprocesses;
B32 is_cow;
B32 vfork_with_spoof;
U64 thread_count;
LNX_DMN_Thread *first_thread;
LNX_DMN_Thread *last_thread;
U64 main_thread_exit_code;
};
typedef struct LNX_DMN_ProcessPtrNode LNX_DMN_ProcessPtrNode;
struct LNX_DMN_ProcessPtrNode
{
LNX_DMN_ProcessPtrNode *next;
LNX_DMN_Process *v;
};
typedef struct LNX_DMN_ProcessPtrList LNX_DMN_ProcessPtrList;
struct LNX_DMN_ProcessPtrList
{
LNX_DMN_ProcessPtrNode *first;
LNX_DMN_ProcessPtrNode *last;
U64 count;
};
typedef struct LNX_DMN_ActiveTrap LNX_DMN_ActiveTrap;
struct LNX_DMN_ActiveTrap
{
LNX_DMN_ActiveTrap *next;
B32 good;
DMN_Trap *trap;
String8 swap_bytes;
};
typedef struct LNX_DMN_ProcessCtx LNX_DMN_ProcessCtx;
struct LNX_DMN_ProcessCtx
{
Arena *arena;
Arch arch;
U64 rdebug_vaddr;
ELF_Class dl_class;
HashTable *loaded_modules_ht;
LNX_DMN_Probe **probes;
LNX_DMN_ActiveTrap *first_probe_trap;
LNX_DMN_ActiveTrap *last_probe_trap;
LNX_DMN_Module *first_module;
LNX_DMN_Module *last_module;
U64 module_count;
U64 ref_count;
String8List free_reg_blocks;
String8List free_reg_block_nodes;
// x64
U64 xcr0;
U64 xsave_size;
X64_XSaveLayout xsave_layout;
};
typedef struct LNX_DMN_Entity LNX_DMN_Entity;
struct LNX_DMN_Entity
{
union
{
LNX_DMN_Process process;
LNX_DMN_ProcessCtx process_ctx;
LNX_DMN_Thread thread;
LNX_DMN_Module module;
LNX_DMN_Entity *next;
};
U32 gen;
LNX_DMN_EntityKind kind;
};
typedef struct LNX_DMN_EntityNode LNX_DMN_EntityNode;
struct LNX_DMN_EntityNode
{
LNX_DMN_EntityNode *next;
LNX_DMN_Entity *v;
};
typedef struct LNX_DMN_EntityList LNX_DMN_EntityList;
struct LNX_DMN_EntityList
{
LNX_DMN_EntityNode *first;
LNX_DMN_EntityNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Top-Level State Bundle
typedef struct LNX_DMN_State LNX_DMN_State;
struct LNX_DMN_State
{
Arena *arena;
// rjf: access locking mechanism
Mutex access_mutex;
B32 access_run_state;
// rjf: 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
// process tracking
U64 process_count;
LNX_DMN_Process *first_process;
LNX_DMN_Process *last_process;
// process/thread creation tracking
U64 process_pending_creation;
U64 threads_pending_creation;
// halter
Mutex halter_mutex;
pid_t halter_tid;
U64 halt_code;
U64 halt_user_data;
B32 is_halting;
// TLS
B32 is_tls_detected;
LNX_DMN_DbDesc tls_modid_desc;
LNX_DMN_DbDesc tls_offset_desc;
};
////////////////////////////////
//~ rjf: Globals
global LNX_DMN_State *lnx_dmn_state = 0;
thread_static B32 lnx_dmn_ctrl_thread = 0;
////////////////////////////////
//~ rjf: Memory R/W Helpers
internal U64 lnx_dmn_size_from_fd(int memory_fd, U64 cap);
internal U64 lnx_dmn_read(int memory_fd, Rng1U64 range, void *dst);
internal B32 lnx_dmn_write(int memory_fd, Rng1U64 range, void *src);
internal String8 lnx_dmn_read_string_capped(Arena *arena, int memory_fd, U64 base_vaddr, U64 cap_size);
internal String8 lnx_dmn_read_string(Arena *arena, int memory_fd, U64 base_vaddr);
#define lnx_dmn_read_struct(fd, vaddr, ptr) lnx_dmn_read((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
#define lnx_dmn_write_struct(fd, vaddr, ptr) lnx_dmn_write((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
////////////////////////////////
//~ rjf: Trap Setting
internal LNX_DMN_ActiveTrap *lnx_dmn_set_trap(Arena *arena, DMN_Trap *trap);
////////////////////////////////
//~ ELF/GNU info
internal Rng1U64 lnx_dmn_compute_image_vrange(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum);
////////////////////////////////
//~ rjf: Process Info Parsing Functions
internal String8 lnx_dmn_dl_path_from_pid(Arena *arena, pid_t pid, U64 auxv_base);
internal ELF_Hdr64 lnx_dmn_ehdr_from_pid(pid_t pid);
internal LNX_DMN_Auxv lnx_dmn_auxv_from_pid(pid_t pid, ELF_Class elf_class);
internal LNX_DMN_Thread * lnx_dmn_thread_from_pid(pid_t pid);
internal LNX_DMN_Process * lnx_dmn_process_from_pid(pid_t pid);
////////////////////////////////
//~ rjf: Module Info Parsing
internal DMN_ModuleInfo *lnx_dmn_module_info_from_process_module(Arena *arena, pid_t pid, int memory_fd, U64 base_vaddr, U64 link_map_vaddr, B32 is_main);
////////////////////////////////
//~ rjf: Entity Functions
// alloc
internal LNX_DMN_Entity * lnx_dmn_entity_alloc(LNX_DMN_EntityKind kind);
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);
// release
internal void lnx_dmn_entity_release(LNX_DMN_Entity *entity);
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);
// clone
internal LNX_DMN_ProcessCtx * lnx_dmn_process_ctx_clone(LNX_DMN_Process *process, LNX_DMN_ProcessCtx *ctx);
internal LNX_DMN_Module * lnx_dmn_module_clone(LNX_DMN_ProcessCtx *process_ctx, LNX_DMN_Module *module);
// entity -> handle
internal DMN_Handle lnx_dmn_handle_from_entity(LNX_DMN_Entity *entity);
internal DMN_Handle lnx_dmn_handle_from_process(LNX_DMN_Process *process);
internal DMN_Handle lnx_dmn_handle_from_thread(LNX_DMN_Thread *thread);
internal DMN_Handle lnx_dmn_handle_from_module(LNX_DMN_Module *module);
// handle -> entity
internal LNX_DMN_Entity * lnx_dmn_entity_from_handle(DMN_Handle handle, LNX_DMN_EntityKind expected_kind);
internal LNX_DMN_Process * lnx_dmn_process_from_handle(DMN_Handle process_handle);
internal LNX_DMN_Thread * lnx_dmn_thread_from_handle(DMN_Handle thread_handle);
internal LNX_DMN_Module * lnx_dmn_module_from_handle(DMN_Handle module_handle);
////////////////////////////////
//~ Thread Helpers
internal U64 lnx_dmn_thread_read_ip(LNX_DMN_Thread *thread);
internal void lnx_dmn_thread_write_ip(LNX_DMN_Thread *thread, U64 ip);
internal B32 lnx_dmn_thread_read_reg_block(LNX_DMN_Thread *thread);
internal B32 lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread);
internal B32 lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on);
internal U64 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);
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);
////////////////////////////////
//~ Debug Event Pushers
internal void lnx_dmn_push_event_create_thread(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread);
internal void lnx_dmn_push_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread, LNX_DMN_Module *module);
internal void lnx_dmn_push_event_unload_module(Arena *arena, DMN_EventList *events, LNX_DMN_Process *process, LNX_DMN_Module *module);
////////////////////////////////
//~ Debug Event
internal void lnx_dmn_event_exit_thread(Arena *arena, DMN_EventList *events, pid_t tid, U64 exit_code);
internal LNX_DMN_Process * lnx_dmn_event_create_process(Arena *arena, DMN_EventList *events, pid_t pid, LNX_DMN_Process *parent_process, LNX_DMN_CreateProcessFlags flags);
internal void lnx_dmn_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread, U64 name_space_id, U64 new_link_map_vaddr);
#endif // LINUX_DEMON_H