// Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef DEMON_OS_LINUX_H #define DEMON_OS_LINUX_H // TODO(allen): Potential Upgrades: // // memory fd upgrade - Right now for each process we hold open a file // descriptor for the process's memory (/proc/%d/mem) for the entire lifetime // of the process; it could be opened and closed with some kind of LRU cache // to put a finite cap on the number of handles the demon holds // //////////////////////////////// //~ NOTE(allen): Get The Linux Includes #include #include #include #include #include #include #include //////////////////////////////// //~ NOTE(allen): Linux Demon Types //- entities // Demon Linux Entity Extensions // Process: ext_u64 set to memory file descriptor // Thread : ext_u64 cast to DEMON_LNX_ThreadExt // Module : ext_u64 set to U64 (address of name) struct DEMON_LNX_ThreadExt{ B32 expecting_dummy_sigstop; }; StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext); //- helpers struct DEMON_LNX_AttachNode{ DEMON_LNX_AttachNode *next; pid_t pid; }; struct DEMON_LNX_ProcessAux{ B32 filled; U64 phnum; U64 phent; U64 phdr; U64 execfn; }; struct DEMON_LNX_PhdrInfo{ Rng1U64 range; U64 dynamic; }; struct DEMON_LNX_ModuleNode{ DEMON_LNX_ModuleNode *next; U64 vaddr; U64 size; U64 name; U64 already_known; }; struct DEMON_LNX_EntityNode{ DEMON_LNX_EntityNode *next; DEMON_Entity *entity; }; //////////////////////////////// //~ NOTE(allen): Linux Demon Register Layouts // these are defined in but only for one architecture at a time // (and we can't really trick it into giving us both in any obvious way) // we define them here so that we have them all "at once" struct DEMON_LNX_UserRegsX64{ 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; }; struct DEMON_LNX_UserX64{ DEMON_LNX_UserRegsX64 regs; S32 u_fpvalid, _pad0; SYMS_XSaveLegacy i387; U64 u_tsize, u_dsize, u_ssize, start_code, start_stack; U64 signal; S32 reserved, _pad1; U64 u_ar0, u_fpstate; U64 magic; U8 u_comm[32]; U64 u_debugreg[8]; }; struct DEMON_LNX_UserRegsX86{ U32 ebx; U32 ecx; U32 edx; U32 esi; U32 edi; U32 ebp; U32 eax; U32 ds; U32 es; U32 fs; U32 gs; U32 orig_eax; U32 eip; U32 cs; U32 eflags; U32 sp; U32 ss; }; struct DEMON_LNX_UserX86{ DEMON_LNX_UserRegsX86 regs; S32 u_fpvalid; SYMS_FSave i387; U32 u_tsize, u_dsize, u_ssize, start_code, start_stack; S32 signal, reserved; U32 u_ar0, u_fpstate; U32 magic; U8 u_comm[32]; U32 u_debugreg[8]; }; //////////////////////////////// enum { DEMON_LNX_PermFlags_Read = (1 << 0), DEMON_LNX_PermFlags_Write = (1 << 1), DEMON_LNX_PermFlags_Exec = (1 << 2), DEMON_LNX_PermFlags_Private = (1 << 3) }; typedef int DEMON_LNX_PermFlags; enum { DEMON_LNX_MapsEntryType_Null, DEMON_LNX_MapsEntryType_Path, DEMON_LNX_MapsEntryType_Heap, DEMON_LNX_MapsEntryType_Stack, DEMON_LNX_MapsEntryType_VDSO, }; typedef int DEMON_LNX_MapsEntryType; struct DEMON_LNX_MapsEntry { U64 address_lo; U64 address_hi; DEMON_LNX_PermFlags perms; U64 offset; U32 dev_major; U32 dev_minor; U64 inode; String8 pathname; DEMON_LNX_MapsEntryType type; pid_t stack_tid; }; //////////////////////////////// //~ rjf: Helpers internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity); internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node); internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid); internal int demon_lnx_open_memory_fd_for_pid(pid_t pid); internal Architecture demon_lnx_arch_from_pid(pid_t pid); internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Architecture arch); internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit, U64 phvaddr, U64 phstride, U64 phcount); internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process); internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size); internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size); internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address); internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src); internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src); internal String8 demon_lnx_read_int_string(int fd); internal B32 demon_lnx_read_expect(int fd, char expect); internal int demon_lnx_read_whitespace(int fd); internal String8 demon_lnx_read_string(Arena *arena, int fd); internal int demon_lnx_open_maps(pid_t pid); internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out); #endif //DEMON_OS_LINUX_H