mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
223 lines
5.2 KiB
C
223 lines
5.2 KiB
C
// 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 <sys/ptrace.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <elf.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
|
|
////////////////////////////////
|
|
//~ 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 <sys/user.h> 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
|