mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-02 20:18:12 +00:00
git normalize all files
This commit is contained in:
+158
-158
@@ -1,158 +1,158 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/demon.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
||||
|
||||
//- rjf: handles
|
||||
|
||||
internal DMN_Handle
|
||||
dmn_handle_zero(void)
|
||||
{
|
||||
DMN_Handle h = {0};
|
||||
return h;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_handle_match(DMN_Handle a, DMN_Handle b)
|
||||
{
|
||||
return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1];
|
||||
}
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
|
||||
{
|
||||
DMN_TrapChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
node->cap = cap;
|
||||
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], trap);
|
||||
node->count += 1;
|
||||
list->trap_count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
if(dst->last == 0)
|
||||
{
|
||||
MemoryCopyStruct(dst, to_push);
|
||||
}
|
||||
else if(to_push->first != 0)
|
||||
{
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->node_count += to_push->node_count;
|
||||
dst->trap_count += to_push->trap_count;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
||||
{
|
||||
DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
dst_n->v = src_n->v;
|
||||
dst_n->cap = src_n->cap;
|
||||
dst_n->count = src_n->count;
|
||||
SLLQueuePush(dst->first, dst->last, dst_n);
|
||||
dst->node_count += 1;
|
||||
dst->trap_count += dst_n->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: handle lists
|
||||
|
||||
internal void
|
||||
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
|
||||
{
|
||||
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
node->v = handle;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
|
||||
{
|
||||
DMN_HandleArray array = {0};
|
||||
array.count = list->count;
|
||||
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
|
||||
U64 idx = 0;
|
||||
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
array.handles[idx] = n->v;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
|
||||
{
|
||||
DMN_HandleArray dst = {0};
|
||||
dst.count = src->count;
|
||||
dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count);
|
||||
MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- rjf: event list building
|
||||
|
||||
internal DMN_Event *
|
||||
dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
||||
{
|
||||
DMN_EventNode *n = push_array(arena, DMN_EventNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
DMN_Event *result = &n->v;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
||||
|
||||
internal U64
|
||||
dmn_rip_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rip_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_rsp_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rsp_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "generated/demon.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
|
||||
|
||||
//- rjf: handles
|
||||
|
||||
internal DMN_Handle
|
||||
dmn_handle_zero(void)
|
||||
{
|
||||
DMN_Handle h = {0};
|
||||
return h;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dmn_handle_match(DMN_Handle a, DMN_Handle b)
|
||||
{
|
||||
return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1];
|
||||
}
|
||||
|
||||
//- rjf: trap chunk lists
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
|
||||
{
|
||||
DMN_TrapChunkNode *node = list->last;
|
||||
if(node == 0 || node->count >= node->cap)
|
||||
{
|
||||
node = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
node->cap = cap;
|
||||
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->node_count += 1;
|
||||
}
|
||||
MemoryCopyStruct(&node->v[node->count], trap);
|
||||
node->count += 1;
|
||||
list->trap_count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
if(dst->last == 0)
|
||||
{
|
||||
MemoryCopyStruct(dst, to_push);
|
||||
}
|
||||
else if(to_push->first != 0)
|
||||
{
|
||||
dst->last->next = to_push->first;
|
||||
dst->last = to_push->last;
|
||||
dst->node_count += to_push->node_count;
|
||||
dst->trap_count += to_push->trap_count;
|
||||
}
|
||||
MemoryZeroStruct(to_push);
|
||||
}
|
||||
|
||||
internal void
|
||||
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
|
||||
{
|
||||
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
|
||||
{
|
||||
DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1);
|
||||
dst_n->v = src_n->v;
|
||||
dst_n->cap = src_n->cap;
|
||||
dst_n->count = src_n->count;
|
||||
SLLQueuePush(dst->first, dst->last, dst_n);
|
||||
dst->node_count += 1;
|
||||
dst->trap_count += dst_n->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: handle lists
|
||||
|
||||
internal void
|
||||
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
|
||||
{
|
||||
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
node->v = handle;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
|
||||
{
|
||||
DMN_HandleArray array = {0};
|
||||
array.count = list->count;
|
||||
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
|
||||
U64 idx = 0;
|
||||
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
array.handles[idx] = n->v;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal DMN_HandleArray
|
||||
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
|
||||
{
|
||||
DMN_HandleArray dst = {0};
|
||||
dst.count = src->count;
|
||||
dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count);
|
||||
MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- rjf: event list building
|
||||
|
||||
internal DMN_Event *
|
||||
dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
||||
{
|
||||
DMN_EventNode *n = push_array(arena, DMN_EventNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
DMN_Event *result = &n->v;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
|
||||
|
||||
internal U64
|
||||
dmn_rip_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rip_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_rsp_from_thread(DMN_Handle thread)
|
||||
{
|
||||
U64 result = 0;
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
{
|
||||
Architecture arch = dmn_arch_from_thread(thread);
|
||||
U64 reg_block_size = regs_block_size_from_architecture(arch);
|
||||
void *reg_block = push_array(scratch.arena, U8, reg_block_size);
|
||||
dmn_thread_read_reg_block(thread, reg_block);
|
||||
result = regs_rsp_from_arch_block(arch, reg_block);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
+90
-90
@@ -1,90 +1,90 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Kind Tables
|
||||
|
||||
@table(name)
|
||||
DMN_EventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Error}
|
||||
{HandshakeComplete}
|
||||
{CreateProcess}
|
||||
{ExitProcess}
|
||||
{CreateThread}
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
{Exception}
|
||||
{Halt}
|
||||
{Memory}
|
||||
{DebugString}
|
||||
{SetThreadName}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ErrorKindTable:
|
||||
{
|
||||
{Null}
|
||||
{NotAttached}
|
||||
{UnexpectedFailure}
|
||||
{InvalidHandle}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_MemoryEventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Commit}
|
||||
{Reserve}
|
||||
{Decommit}
|
||||
{Release}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ExceptionKindTable:
|
||||
{
|
||||
{Null}
|
||||
{MemoryRead}
|
||||
{MemoryWrite}
|
||||
{MemoryExecute}
|
||||
{CppThrow}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum DMN_EventKind:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_event_kind_string_table:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@enum DMN_ErrorKind:
|
||||
{
|
||||
@expand(DMN_ErrorKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_MemoryEventKind:
|
||||
{
|
||||
@expand(DMN_MemoryEventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_ExceptionKind:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_exception_kind_string_table:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Kind Tables
|
||||
|
||||
@table(name)
|
||||
DMN_EventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Error}
|
||||
{HandshakeComplete}
|
||||
{CreateProcess}
|
||||
{ExitProcess}
|
||||
{CreateThread}
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
{Exception}
|
||||
{Halt}
|
||||
{Memory}
|
||||
{DebugString}
|
||||
{SetThreadName}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ErrorKindTable:
|
||||
{
|
||||
{Null}
|
||||
{NotAttached}
|
||||
{UnexpectedFailure}
|
||||
{InvalidHandle}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_MemoryEventKindTable:
|
||||
{
|
||||
{Null}
|
||||
{Commit}
|
||||
{Reserve}
|
||||
{Decommit}
|
||||
{Release}
|
||||
}
|
||||
|
||||
@table(name)
|
||||
DMN_ExceptionKindTable:
|
||||
{
|
||||
{Null}
|
||||
{MemoryRead}
|
||||
{MemoryWrite}
|
||||
{MemoryExecute}
|
||||
{CppThrow}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generators
|
||||
|
||||
@enum DMN_EventKind:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_event_kind_string_table:
|
||||
{
|
||||
@expand(DMN_EventKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
@enum DMN_ErrorKind:
|
||||
{
|
||||
@expand(DMN_ErrorKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_MemoryEventKind:
|
||||
{
|
||||
@expand(DMN_MemoryEventKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@enum DMN_ExceptionKind:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) dmn_exception_kind_string_table:
|
||||
{
|
||||
@expand(DMN_ExceptionKindTable a) `str8_lit_comp("$(a.name)")`
|
||||
}
|
||||
|
||||
+222
-222
@@ -1,222 +1,222 @@
|
||||
// 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
|
||||
// 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
|
||||
|
||||
+286
-286
@@ -1,286 +1,286 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_WIN32_H
|
||||
#define DEMON_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Windows Includes
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Exception Codes
|
||||
|
||||
#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DMN_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u
|
||||
#define DMN_w32_EXCEPTION_CLR 0xE0434352u
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Register Codes
|
||||
|
||||
#define DMN_W32_CTX_X86 0x00010000
|
||||
#define DMN_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
|
||||
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
|
||||
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
|
||||
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
|
||||
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
|
||||
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DMN_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \
|
||||
DMN_W32_CTX_INTEL_EXTENDED)
|
||||
#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \
|
||||
DMN_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Entity State
|
||||
|
||||
typedef enum DMN_W32_EntityKind
|
||||
{
|
||||
DMN_W32_EntityKind_Null,
|
||||
DMN_W32_EntityKind_Root,
|
||||
DMN_W32_EntityKind_Process,
|
||||
DMN_W32_EntityKind_Thread,
|
||||
DMN_W32_EntityKind_Module,
|
||||
DMN_W32_EntityKind_COUNT
|
||||
}
|
||||
DMN_W32_EntityKind;
|
||||
|
||||
typedef struct DMN_W32_Entity DMN_W32_Entity;
|
||||
struct DMN_W32_Entity
|
||||
{
|
||||
DMN_W32_Entity *first;
|
||||
DMN_W32_Entity *last;
|
||||
DMN_W32_Entity *next;
|
||||
DMN_W32_Entity *prev;
|
||||
DMN_W32_Entity *parent;
|
||||
DMN_W32_EntityKind kind;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
HANDLE handle;
|
||||
Architecture arch;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
}
|
||||
proc;
|
||||
struct
|
||||
{
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
}
|
||||
thread;
|
||||
struct
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
}
|
||||
module;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityNode DMN_W32_EntityNode;
|
||||
struct DMN_W32_EntityNode
|
||||
{
|
||||
DMN_W32_EntityNode *next;
|
||||
DMN_W32_Entity *v;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode;
|
||||
struct DMN_W32_EntityIDHashNode
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *next;
|
||||
DMN_W32_EntityIDHashNode *prev;
|
||||
U64 id;
|
||||
DMN_W32_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot;
|
||||
struct DMN_W32_EntityIDHashSlot
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *first;
|
||||
DMN_W32_EntityIDHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Injection Types
|
||||
|
||||
typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak;
|
||||
struct DMN_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
|
||||
#define DMN_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Image Info Types
|
||||
|
||||
typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo;
|
||||
struct DMN_W32_ImageInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dynamically-Loaded Win32 Function Types
|
||||
|
||||
typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct DMN_W32_Shared DMN_W32_Shared;
|
||||
struct DMN_W32_Shared
|
||||
{
|
||||
// rjf: top-level info
|
||||
Arena *arena;
|
||||
String8List env_strings;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
// rjf: entity state
|
||||
Arena *entities_arena;
|
||||
DMN_W32_Entity *entities_base;
|
||||
DMN_W32_Entity *entities_first_free;
|
||||
U64 entities_count;
|
||||
DMN_W32_EntityIDHashSlot *entities_id_hash_slots;
|
||||
U64 entities_id_hash_slots_count;
|
||||
DMN_W32_EntityIDHashNode *entities_id_hash_node_free;
|
||||
|
||||
// rjf: launch state
|
||||
B32 new_process_pending;
|
||||
|
||||
// rjf: run results
|
||||
B32 resume_needed;
|
||||
U32 resume_pid;
|
||||
U32 resume_tid;
|
||||
B32 exception_not_handled;
|
||||
|
||||
// rjf: halting info
|
||||
DMN_Handle halter_process;
|
||||
U32 halter_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DMN_W32_Shared *dmn_w32_shared = 0;
|
||||
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
|
||||
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
|
||||
thread_static B32 dmn_w32_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dmn_w32_hash_from_string(String8 string);
|
||||
internal U64 dmn_w32_hash_from_id(U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Helpers
|
||||
|
||||
//- rjf: entity <-> handle
|
||||
internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity);
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle);
|
||||
|
||||
//- rjf: entity allocation/deallocation
|
||||
internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id);
|
||||
internal void dmn_w32_entity_release(DMN_W32_Entity *entity);
|
||||
|
||||
//- rjf: kind*id -> entity
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Info Extraction
|
||||
|
||||
internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32-Level Process/Thread Reads/Writes
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src);
|
||||
internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
|
||||
|
||||
//- rjf: threads
|
||||
internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
|
||||
//- rjf: remote thread injection
|
||||
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
|
||||
|
||||
#endif // DEMON_CORE_WIN32_H
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DEMON_CORE_WIN32_H
|
||||
#define DEMON_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Windows Includes
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Exception Codes
|
||||
|
||||
#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u
|
||||
#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
|
||||
#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
|
||||
#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
|
||||
#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
|
||||
#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
|
||||
#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
|
||||
#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
|
||||
#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
|
||||
#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
|
||||
#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
|
||||
#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
|
||||
#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
|
||||
#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
|
||||
#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
|
||||
#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
|
||||
#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
|
||||
#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
|
||||
#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
|
||||
#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u
|
||||
#define DMN_W32_EXCEPTION_THROW 0xE06D7363u
|
||||
#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
|
||||
#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u
|
||||
#define DMN_w32_EXCEPTION_CLR 0xE0434352u
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32 Register Codes
|
||||
|
||||
#define DMN_W32_CTX_X86 0x00010000
|
||||
#define DMN_W32_CTX_X64 0x00100000
|
||||
|
||||
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
|
||||
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
|
||||
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
|
||||
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
|
||||
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
|
||||
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
|
||||
#define DMN_W32_CTX_INTEL_XSTATE 0x0040
|
||||
|
||||
#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \
|
||||
DMN_W32_CTX_INTEL_EXTENDED)
|
||||
#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \
|
||||
DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \
|
||||
DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \
|
||||
DMN_W32_CTX_INTEL_DEBUG)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Entity State
|
||||
|
||||
typedef enum DMN_W32_EntityKind
|
||||
{
|
||||
DMN_W32_EntityKind_Null,
|
||||
DMN_W32_EntityKind_Root,
|
||||
DMN_W32_EntityKind_Process,
|
||||
DMN_W32_EntityKind_Thread,
|
||||
DMN_W32_EntityKind_Module,
|
||||
DMN_W32_EntityKind_COUNT
|
||||
}
|
||||
DMN_W32_EntityKind;
|
||||
|
||||
typedef struct DMN_W32_Entity DMN_W32_Entity;
|
||||
struct DMN_W32_Entity
|
||||
{
|
||||
DMN_W32_Entity *first;
|
||||
DMN_W32_Entity *last;
|
||||
DMN_W32_Entity *next;
|
||||
DMN_W32_Entity *prev;
|
||||
DMN_W32_Entity *parent;
|
||||
DMN_W32_EntityKind kind;
|
||||
U32 gen;
|
||||
U64 id;
|
||||
HANDLE handle;
|
||||
Architecture arch;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 injection_address;
|
||||
B32 did_first_bp;
|
||||
}
|
||||
proc;
|
||||
struct
|
||||
{
|
||||
U64 thread_local_base;
|
||||
U64 last_name_hash;
|
||||
U64 name_gather_time_us;
|
||||
}
|
||||
thread;
|
||||
struct
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 address_of_name_pointer;
|
||||
B32 is_main;
|
||||
B32 name_is_unicode;
|
||||
}
|
||||
module;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityNode DMN_W32_EntityNode;
|
||||
struct DMN_W32_EntityNode
|
||||
{
|
||||
DMN_W32_EntityNode *next;
|
||||
DMN_W32_Entity *v;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode;
|
||||
struct DMN_W32_EntityIDHashNode
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *next;
|
||||
DMN_W32_EntityIDHashNode *prev;
|
||||
U64 id;
|
||||
DMN_W32_Entity *entity;
|
||||
};
|
||||
|
||||
typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot;
|
||||
struct DMN_W32_EntityIDHashSlot
|
||||
{
|
||||
DMN_W32_EntityIDHashNode *first;
|
||||
DMN_W32_EntityIDHashNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Injection Types
|
||||
|
||||
typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak;
|
||||
struct DMN_W32_InjectedBreak
|
||||
{
|
||||
U64 code;
|
||||
U64 user_data;
|
||||
};
|
||||
|
||||
#define DMN_W32_INJECTED_CODE_SIZE 32
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Image Info Types
|
||||
|
||||
typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo;
|
||||
struct DMN_W32_ImageInfo
|
||||
{
|
||||
Architecture arch;
|
||||
U32 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dynamically-Loaded Win32 Function Types
|
||||
|
||||
typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct DMN_W32_Shared DMN_W32_Shared;
|
||||
struct DMN_W32_Shared
|
||||
{
|
||||
// rjf: top-level info
|
||||
Arena *arena;
|
||||
String8List env_strings;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
// rjf: entity state
|
||||
Arena *entities_arena;
|
||||
DMN_W32_Entity *entities_base;
|
||||
DMN_W32_Entity *entities_first_free;
|
||||
U64 entities_count;
|
||||
DMN_W32_EntityIDHashSlot *entities_id_hash_slots;
|
||||
U64 entities_id_hash_slots_count;
|
||||
DMN_W32_EntityIDHashNode *entities_id_hash_node_free;
|
||||
|
||||
// rjf: launch state
|
||||
B32 new_process_pending;
|
||||
|
||||
// rjf: run results
|
||||
B32 resume_needed;
|
||||
U32 resume_pid;
|
||||
U32 resume_tid;
|
||||
B32 exception_not_handled;
|
||||
|
||||
// rjf: halting info
|
||||
DMN_Handle halter_process;
|
||||
U32 halter_tid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DMN_W32_Shared *dmn_w32_shared = 0;
|
||||
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
|
||||
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
|
||||
thread_static B32 dmn_w32_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 dmn_w32_hash_from_string(String8 string);
|
||||
internal U64 dmn_w32_hash_from_id(U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Helpers
|
||||
|
||||
//- rjf: entity <-> handle
|
||||
internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity);
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle);
|
||||
|
||||
//- rjf: entity allocation/deallocation
|
||||
internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id);
|
||||
internal void dmn_w32_entity_release(DMN_W32_Entity *entity);
|
||||
|
||||
//- rjf: kind*id -> entity
|
||||
internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Info Extraction
|
||||
|
||||
internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Win32-Level Process/Thread Reads/Writes
|
||||
|
||||
//- rjf: processes
|
||||
internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src);
|
||||
internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
|
||||
internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
|
||||
#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
|
||||
|
||||
//- rjf: threads
|
||||
internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
|
||||
internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
|
||||
internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block);
|
||||
|
||||
//- rjf: remote thread injection
|
||||
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
|
||||
|
||||
#endif // DEMON_CORE_WIN32_H
|
||||
|
||||
Reference in New Issue
Block a user