demon2 -> demon; eliminate original demon layer

This commit is contained in:
Ryan Fleury
2024-03-22 16:33:48 -07:00
parent c9df04ca60
commit 995804cc78
27 changed files with 219 additions and 7097 deletions
-3
View File
@@ -40,9 +40,6 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
txti_init();
#endif
#if defined(DEMON_CORE_H)
demon_init();
#endif
#if defined(DEMON2_CORE_H)
dmn_init();
#endif
#if defined(CTRL_CORE_H)
-198
View File
@@ -1,198 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//- allen: Acceleration Layer Functions
//- accel helpers
internal DEMON_AccelModule*
demon_accel_module_alloc(void){
DEMON_AccelModule *result = demon_free_module_accel;
if (result != 0){
SLLStackPop(demon_free_module_accel);
}
else{
result = push_array_no_zero(demon_ent_arena, DEMON_AccelModule, 1);
}
MemoryZeroStruct(result);
return(result);
}
internal void
demon_accel_module_free(DEMON_AccelModule *module){
SLLStackPush(demon_free_module_accel, module);
}
internal DEMON_AccelThread*
demon_accel_thread_alloc(void){
DEMON_AccelThread *result = demon_free_thread_accel;
if (result != 0){
SLLStackPop(demon_free_thread_accel);
}
else{
result = push_array_no_zero(demon_ent_arena, DEMON_AccelThread, 1);
}
MemoryZeroStruct(result);
return(result);
}
internal void
demon_accel_thread_free(DEMON_AccelThread *thread){
SLLStackPush(demon_free_thread_accel, thread);
}
internal DEMON_AccelThread*
demon_accel_from_thread(DEMON_Entity *thread){
DEMON_AccelThread *accel = (DEMON_AccelThread*)thread->accel;
if (accel == 0){
accel = demon_accel_thread_alloc();
thread->accel = accel;
}
return(accel);
}
//- operations on demon objects
internal String8
demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module){
DEMON_AccelModule *accel = (DEMON_AccelModule*)module->accel;
String8 result = {0};
// first time
if (accel == 0){
result = demon_os_full_path_from_module(arena, module);
// build chain
DEMON_AccelModule *last_accel = 0;
U8 *ptr = result.str;
U8 *opl = result.str + result.size;
for (;ptr < opl;){
U64 size = (U64)(ptr - opl);
U64 clamped_size = ClampTop(result.size, sizeof(Member(DEMON_AccelModule, buf)));
DEMON_AccelModule *node = demon_accel_module_alloc();
SLLQueuePush(accel, last_accel, node);
node->total_size = result.size;
MemoryCopy(node->buf, ptr, clamped_size);
ptr += clamped_size;
}
// store in module
module->accel = accel;
}
// read from accel
else{
U64 size = accel->total_size;
U8 *str = push_array_no_zero(arena, U8, size + 1);
// copy chain contents to buffer
U8 *ptr = str;
for (DEMON_AccelModule *node = accel;
node != 0;
node = node->next){
U64 total_size = node->total_size;
U64 clamped_size = ClampTop(total_size, sizeof(node->buf));
MemoryCopy(ptr, node->buf, clamped_size);
ptr += clamped_size;
}
*ptr = 0;
// fill result
result.str = str;
result.size = size;
}
return(result);
}
internal U64
demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread){
// get accel data
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
// fill stack base
if (!accel->has_stack_base){
accel->has_stack_base = 1;
accel->stack_base = demon_os_stack_base_vaddr_from_thread(thread);
}
return(accel->stack_base);
}
internal U64
demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread){
// get accel data
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
// fill tls root
if (!accel->has_tls_root){
accel->has_tls_root = 1;
accel->tls_root = demon_os_tls_root_vaddr_from_thread(thread);
}
return(accel->tls_root);
}
internal void*
demon_accel_read_regs(DEMON_Entity *thread){
// get accel data
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
// update reg cache
if (accel->reg_cache_time != demon_time){
accel->reg_cache_time = demon_time;
B32 success = demon_os_read_regs(thread, &accel->regs);
if (!success){
MemoryZeroStruct(&accel->regs);
}
}
return(&accel->regs);
}
internal void
demon_accel_write_regs(DEMON_Entity *thread, void *data){
// get accel data
DEMON_AccelThread *accel = demon_accel_from_thread(thread);
// write
U64 data_size = regs_block_size_from_architecture(thread->arch);
B32 success = demon_os_write_regs(thread, data);
// update cache
if(success)
{
accel->reg_cache_time = demon_time;
MemoryCopy(&accel->regs, data, data_size);
}
}
//- entity accel free
internal void
demon_accel_free(DEMON_Entity *entity){
switch (entity->kind){
default:{}break;
case DEMON_EntityKind_Module:
{
if (entity->accel != 0){
for (DEMON_AccelModule *node = (DEMON_AccelModule*)entity->accel, *next = 0;
node != 0;
node = next){
next = node->next;
demon_accel_module_free(node);
}
}
}break;
case DEMON_EntityKind_Thread:
{
if (entity->accel != 0){
demon_accel_thread_free((DEMON_AccelThread*)entity->accel);
}
}break;
}
}
-64
View File
@@ -1,64 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON_ACCEL_H
#define DEMON_ACCEL_H
////////////////////////////////
//~ allen: Acceleration Data
typedef struct DEMON_AccelModule DEMON_AccelModule;
struct DEMON_AccelModule
{
DEMON_AccelModule *next;
U64 total_size;
U8 buf[240];
};
typedef union DEMON_AccelThread DEMON_AccelThread;
union DEMON_AccelThread
{
DEMON_AccelThread *next;
struct{
B32 has_stack_base;
B32 has_tls_root;
U64 stack_base;
U64 tls_root;
U64 reg_cache_time;
union{
REGS_RegBlockX64 x64;
REGS_RegBlockX86 x86;
} regs;
};
};
////////////////////////////////
//~ allen: Acceleration Globals
global DEMON_AccelModule *demon_free_module_accel = 0;
global DEMON_AccelThread *demon_free_thread_accel = 0;
////////////////////////////////
//~ allen: Acceleration Layer Functions
//- accel helpers
internal DEMON_AccelModule *demon_accel_module_alloc(void);
internal void demon_accel_module_free(DEMON_AccelModule *module);
internal DEMON_AccelThread *demon_accel_thread_alloc(void);
internal void demon_accel_thread_free(DEMON_AccelThread *thread);
internal DEMON_AccelThread *demon_accel_from_thread(DEMON_Entity *thread);
//- operations on demon objects
internal String8 demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module);
internal U64 demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread);
internal U64 demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread);
internal void* demon_accel_read_regs(DEMON_Entity *thread);
internal void demon_accel_write_regs(DEMON_Entity *thread, void *data);
//- entity accel free
internal void demon_accel_free(DEMON_Entity *entity);
#endif //DEMON_ACCEL_H
-271
View File
@@ -1,271 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): State Safety Helper
internal B32
demon_access_begin(void){
B32 result = 0;
if (demon_primary_thread){
Assert(demon_run_state);
result = 1;
}
else{
os_mutex_take(demon_state_mutex);
if (demon_run_state){
os_mutex_drop(demon_state_mutex);
}
else{
result = 1;
}
}
return(result);
}
internal void
demon_access_end(void){
if (!demon_primary_thread){
os_mutex_drop(demon_state_mutex);
}
}
////////////////////////////////
// NOTE(allen): Entity System
internal void
demon_common_init(void){
// access control mechanism
demon_state_mutex = os_mutex_alloc();
// time
demon_time = 1;
// setup arena
demon_ent_arena = arena_alloc();
// setup map
demon_ent_map = push_array(demon_ent_arena, DEMON_Map, 1);
demon_ent_map->bucket_count = 4093;
demon_ent_map->buckets = push_array(demon_ent_arena, DEMON_MapSlot*, demon_ent_map->bucket_count);
// setup entity memory
U64 reserve_size_unaligned = (DEMON_ENTITY_CAP)*sizeof(DEMON_Entity);
U64 reserve_size = AlignPow2(reserve_size_unaligned, DEMON_ENTITY_CMT_SIZE);
demon_ent_cmt = demon_ent_pos = demon_ent_base = (DEMON_Entity*)os_reserve(reserve_size);
demon_ent_opl = demon_ent_base + (reserve_size/sizeof(DEMON_Entity));
Assert(demon_ent_base != 0);
// setup root
demon_ent_root = demon_ent_alloc();
demon_ent_root->kind = DEMON_EntityKind_Root;
}
internal DEMON_Entity*
demon_ent_alloc(void){
DEMON_Entity *result = demon_ent_free;
if (result != 0){
SLLStackPop(demon_ent_free);
}
else{
if (demon_ent_pos < demon_ent_opl){
if (ensure_commit(&demon_ent_cmt, demon_ent_pos + 1, DEMON_ENTITY_CMT_SIZE)){
result = demon_ent_pos;
demon_ent_pos += 1;
}
}
}
if (result != 0){
U32 gen = result->gen;
MemoryZeroStruct(result);
result->gen = gen;
}
return(result);
}
//- handle <-> entity pointer
internal DEMON_Entity*
demon_ent_ptr_from_handle(DEMON_Handle handle){
Assert(demon_ent_base != 0);
DEMON_Entity *result = 0;
U32 index = (U32)(handle & 0xFFFFFFFF);
U64 count = (U64)(demon_ent_pos - demon_ent_base);
if (0 < index && index < count){
DEMON_Entity *entity = demon_ent_base + index;
U32 gen = (U32)(handle >> 32);
if (gen == entity->gen){
result = entity;
}
}
return(result);
}
internal DEMON_Handle
demon_ent_handle_from_ptr(DEMON_Entity *entity){
Assert(demon_ent_base != 0);
DEMON_Handle result = {0};
if (demon_ent_base < entity && entity < demon_ent_pos){
U32 index = (U32)(entity - demon_ent_base);
U64 gen = entity->gen;
result = (gen << 32) | index;
}
return(result);
}
//- high level entity alloc,init,release
internal DEMON_Entity*
demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id){
Assert(demon_ent_base != 0);
DEMON_Entity *result = demon_ent_alloc();
if (result != 0){
result->kind = kind;
result->id = id;
result->arch = parent->arch;
result->parent = parent;
DLLPushBack(parent->first, parent->last, result);
demon_ent_map_save(kind, id, result);
}
return(result);
}
internal void
demon_ent_release_single(DEMON_Entity *entity){
switch (entity->kind){
default:{}break;
case DEMON_EntityKind_Process: demon_proc_count -= 1; break;
case DEMON_EntityKind_Thread: demon_thread_count -= 1; break;
case DEMON_EntityKind_Module: demon_module_count -= 1; break;
}
demon_accel_free(entity);
demon_os_entity_cleanup(entity);
DEMON_MapRef ref = demon_ent_map_find(entity->kind, entity->id);
demon_ent_map_erase(ref);
entity->gen += 1;
}
internal void
demon_ent_release_children(DEMON_Entity *root){
Assert(demon_ent_base != 0);
if (root->first != 0){
for (DEMON_Entity *node = root->first;
node != 0;
node = node->next){
demon_ent_release_children(node);
demon_ent_release_single(node);
}
root->last->next = demon_ent_free;
demon_ent_free = root->first;
root->first = 0;
root->last = 0;
}
}
internal void
demon_ent_release_root_and_children(DEMON_Entity *root){
Assert(demon_ent_base != 0);
Assert(root->parent != 0);
// release children
demon_ent_release_children(root);
// release root
DEMON_Entity *parent = root->parent;
demon_ent_release_single(root);
DLLRemove(parent->first, parent->last, root);
SLLStackPush(demon_ent_free, root);
}
//- entity map
internal U64
demon_ent_map_hash(U16 kind, U64 id){
U64 result = ((U64)kind << 32) ^ id;
return(result);
}
internal void
demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity){
Assert(demon_ent_base != 0);
DEMON_Map *map = demon_ent_map;
// allocate a new slot
DEMON_MapSlot *slot = map->free_slots;
if (slot != 0){
SLLStackPop(map->free_slots);
}
else{
slot = push_array_no_zero(demon_ent_arena, DEMON_MapSlot, 1);
}
// fill slot
slot->kind = kind;
slot->id = id;
slot->entity = entity;
// insert into bucket
U64 hash = demon_ent_map_hash(kind, id);
U64 bucket_index = hash%map->bucket_count;
SLLStackPush(map->buckets[bucket_index], slot);
}
internal DEMON_MapRef
demon_ent_map_find(U16 kind, U64 id){
Assert(demon_ent_base != 0);
DEMON_Map *map = demon_ent_map;
// scan bucket
DEMON_MapRef result = {0};
U64 hash = demon_ent_map_hash(kind, id);
U64 bucket_index = hash%map->bucket_count;
for (DEMON_MapSlot **ptr = &map->buckets[bucket_index], *slot = 0;
*ptr != 0;
ptr = &slot->next){
slot = *ptr;
if (slot->kind == kind && slot->id == id){
result.slot = slot;
result.ptr_to_slot = ptr;
break;
}
}
return(result);
}
internal DEMON_Entity*
demon_ent_map_entity_from_id(U16 kind, U64 id){
DEMON_Entity *result = 0;
DEMON_MapRef ref = demon_ent_map_find(kind, id);
if (ref.slot != 0){
result = ref.slot->entity;
}
return(result);
}
internal void
demon_ent_map_erase(DEMON_MapRef ref){
Assert(demon_ent_base != 0);
DEMON_Map *map = demon_ent_map;
// move slot to free list
if (ref.slot != 0){
*ref.ptr_to_slot = ref.slot->next;
SLLStackPush(map->free_slots, ref.slot);
}
}
////////////////////////////////
// NOTE(allen): Event Helpers
internal DEMON_Event*
demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind){
DEMON_EventNode *n = push_array(arena, DEMON_EventNode, 1);
DEMON_Event *result = &n->v;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
result->kind = kind;
return(result);
}
-150
View File
@@ -1,150 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON_COMMON_H
#define DEMON_COMMON_H
////////////////////////////////
//~ allen: DEMON Entity System
typedef enum DEMON_EntityKind
{
DEMON_EntityKind_NULL,
DEMON_EntityKind_Root,
DEMON_EntityKind_Process,
DEMON_EntityKind_Thread,
DEMON_EntityKind_Module,
DEMON_EntityKind_COUNT
}
DEMON_EntityKind;
typedef struct DEMON_Entity DEMON_Entity;
struct DEMON_Entity
{
// TODO(allen): these could be U32s
DEMON_Entity *next;
DEMON_Entity *prev;
DEMON_Entity *parent;
DEMON_Entity *first;
DEMON_Entity *last;
DEMON_EntityKind kind;
Architecture arch;
U32 gen;
U64 id;
U64 addr_range_dim;
// each OS backend decides how to use `ext` for each entity kind
union{
void *ext;
U64 ext_u64;
};
// the accel layer attaches some extra information to some entities
void *accel;
};
//- id -> entity map
typedef struct DEMON_MapSlot DEMON_MapSlot;
struct DEMON_MapSlot
{
DEMON_MapSlot *next;
U16 kind;
U64 id;
DEMON_Entity *entity;
};
typedef struct DEMON_Map DEMON_Map;
struct DEMON_Map
{
DEMON_MapSlot **buckets;
U64 bucket_count;
DEMON_MapSlot *free_slots;
};
typedef struct DEMON_MapRef DEMON_MapRef;
struct DEMON_MapRef
{
DEMON_MapSlot *slot;
DEMON_MapSlot **ptr_to_slot;
};
//- rjf: entity extrusive list
typedef struct DEMON_EntityNode DEMON_EntityNode;
struct DEMON_EntityNode
{
DEMON_EntityNode *next;
DEMON_Entity *entity;
};
////////////////////////////////
//~ allen: Demon Globals
thread_static B32 demon_primary_thread = 0;
global B32 demon_run_state = 0;
global OS_Handle demon_state_mutex = {0};
global U64 demon_time = 0;
global Arena *demon_ent_arena = 0;
global DEMON_Map *demon_ent_map = 0;
global DEMON_Entity *demon_ent_free = 0;
global DEMON_Entity *demon_ent_root = 0;
global DEMON_Entity *demon_ent_base = 0;
global DEMON_Entity *demon_ent_pos = 0;
global DEMON_Entity *demon_ent_opl = 0;
global void *demon_ent_cmt = 0;
global U64 demon_proc_count = 0;
global U64 demon_thread_count = 0;
global U64 demon_module_count = 0;
#if !defined(DEMON_ENTITY_CMT_SIZE)
# define DEMON_ENTITY_CMT_SIZE KB(64)
#endif
#if !defined(DEMON_ENTITY_CAP)
# define DEMON_ENTITY_CAP 65536
#endif
StaticAssert(IsPow2(DEMON_ENTITY_CMT_SIZE), check_demon_entity_cmt_size);
////////////////////////////////
//~ allen: State Safety Helper
internal B32 demon_access_begin(void);
internal void demon_access_end(void);
////////////////////////////////
//~ allen: Entity System
internal void demon_common_init(void);
internal DEMON_Entity* demon_ent_alloc(void);
//- handle <-> entity pointer
internal DEMON_Entity* demon_ent_ptr_from_handle(DEMON_Handle handle);
internal DEMON_Handle demon_ent_handle_from_ptr(DEMON_Entity *entity);
//- high level entity alloc,init,release
internal DEMON_Entity* demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id);
internal void demon_ent_release_single(DEMON_Entity *entity);
internal void demon_ent_release_children(DEMON_Entity *root);
internal void demon_ent_release_root_and_children(DEMON_Entity *root);
//- entity map
internal U64 demon_ent_map_hash(U16 kind, U64 id);
internal void demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity);
internal DEMON_MapRef demon_ent_map_find(U16 kind, U64 id);
internal DEMON_Entity* demon_ent_map_entity_from_id(U16 kind, U64 id);
internal void demon_ent_map_erase(DEMON_MapRef map_ref);
////////////////////////////////
//~ allen: Event Helpers
internal DEMON_Event* demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind);
#endif //DEMON_COMMON_H
+66 -784
View File
@@ -2,148 +2,34 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Main Layer Initialization
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
internal void
demon_init(void){
demon_common_init();
demon_os_init();
//- rjf: handles
internal DMN_Handle
dmn_handle_zero(void)
{
DMN_Handle h = {0};
return h;
}
////////////////////////////////
//~ rjf: Basic Type Functions
//- rjf: stringizing
internal String8
demon_string_from_event_kind(DEMON_EventKind kind){
String8 result = str8_lit("unknown");
switch (kind){
default: break;
case DEMON_EventKind_Error: result = str8_lit("Error"); break;
case DEMON_EventKind_HandshakeComplete: result = str8_lit("HandshakeComplete"); break;
case DEMON_EventKind_CreateProcess: result = str8_lit("CreateProcess"); break;
case DEMON_EventKind_ExitProcess: result = str8_lit("ExitProcess"); break;
case DEMON_EventKind_CreateThread: result = str8_lit("CreateThread"); break;
case DEMON_EventKind_ExitThread: result = str8_lit("ExitThread"); break;
case DEMON_EventKind_LoadModule: result = str8_lit("LoadModule"); break;
case DEMON_EventKind_UnloadModule: result = str8_lit("UnloadModule"); break;
case DEMON_EventKind_Breakpoint: result = str8_lit("Breakpoint"); break;
case DEMON_EventKind_Trap: result = str8_lit("Trap"); break;
case DEMON_EventKind_SingleStep: result = str8_lit("SingleStep"); break;
case DEMON_EventKind_Exception: result = str8_lit("Exception"); break;
case DEMON_EventKind_Halt: result = str8_lit("Halt"); break;
case DEMON_EventKind_Memory: result = str8_lit("Memory"); break;
case DEMON_EventKind_DebugString: result = str8_lit("DebugString"); break;
case DEMON_EventKind_SetThreadName: result = str8_lit("SetThreadName"); break;
}
return(result);
}
internal String8
demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind){
String8 result = str8_lit("unknown");
switch (kind){
default: break;
case DEMON_MemoryEventKind_Commit: result = str8_lit("Commit"); break;
case DEMON_MemoryEventKind_Reserve: result = str8_lit("Reserve"); break;
case DEMON_MemoryEventKind_Decommit: result = str8_lit("Decommit"); break;
case DEMON_MemoryEventKind_Release: result = str8_lit("Release"); break;
}
return(result);
}
internal String8
demon_string_from_exception_kind(DEMON_ExceptionKind kind){
String8 result = str8_lit("unknown");
switch (kind){
default: break;
case DEMON_ExceptionKind_MemoryRead: result = str8_lit("MemoryRead"); break;
case DEMON_ExceptionKind_MemoryWrite: result = str8_lit("MemoryWrite"); break;
case DEMON_ExceptionKind_MemoryExecute: result = str8_lit("MemoryExecute"); break;
case DEMON_ExceptionKind_CppThrow: result = str8_lit("CppThrow"); break;
}
return(result);
}
internal void
demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event){
B32 need_exception_info = (event->kind == DEMON_EventKind_Exception ||
event->kind == DEMON_EventKind_Breakpoint ||
event->kind == DEMON_EventKind_Halt ||
event->kind == DEMON_EventKind_SingleStep);
// allen: kind
String8 kind_string = demon_string_from_event_kind(event->kind);
str8_list_pushf(arena, out, "%S: { (%i)", kind_string, event->kind);
// rjf: basics
{
str8_list_pushf(arena, out, " process: (%I64x)", event->process);
str8_list_pushf(arena, out, " thread: (%I64x)", event->thread);
str8_list_pushf(arena, out, " module: (%I64x)", event->module);
str8_list_pushf(arena, out, " address: (%I64x)", event->address, event->address);
str8_list_pushf(arena, out, " size: (0x%I64x, %I64u)", event->size, event->size);
}
// rjf: string
if (event->string.size != 0){
str8_list_pushf(arena, out, " string: \"%S\"", event->string);
}
// rjf: exception info
if (need_exception_info){
str8_list_pushf(arena, out, " code: (0x%x, %i)", event->code, event->code);
str8_list_pushf(arena, out, " flags: (0x%x, %i)", event->flags, event->flags);
str8_list_pushf(arena, out, " signo: (0x%x, %i)", event->signo, event->signo);
str8_list_pushf(arena, out, " sigcode: (0x%x, %i)", event->sigcode, event->sigcode);
}
// rjf: need error info
if (event->kind == DEMON_EventKind_Error){
str8_list_pushf(arena, out, " error_kind: (0x%x, %i)", event->error_kind, event->error_kind);
}
// rjf: memory event kind info
if (event->memory_kind != DEMON_MemoryEventKind_Null){
String8 memory_kind_string = demon_string_from_memory_event_kind(event->memory_kind);
str8_list_pushf(arena, out, " memory_kind: (%S, %i)",
memory_kind_string, event->memory_kind);
}
// rjf: exception kind
if (need_exception_info){
String8 exception_kind_string = demon_string_from_exception_kind(event->exception_kind);
str8_list_pushf(arena, out, " exception_kind: (%S, %i)",
exception_kind_string, event->exception_kind);
}
// rjf: instruction ptr
if (event->instruction_pointer != 0){
str8_list_pushf(arena, out, " instruction_pointer: (%I64x)", event->instruction_pointer);
}
// rjf: stack ptr
if (event->stack_pointer != 0){
str8_list_pushf(arena, out, " stack_pointer: (%I64x)", event->stack_pointer);
}
str8_list_pushf(arena, out, " user_data: (0x%I64x, %I64u)",
event->user_data, event->user_data);
str8_list_pushf(arena, out, "}");
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
demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap)
dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap)
{
DEMON_TrapChunkNode *node = list->last;
DMN_TrapChunkNode *node = list->last;
if(node == 0 || node->count >= node->cap)
{
node = push_array(arena, DEMON_TrapChunkNode, 1);
node = push_array(arena, DMN_TrapChunkNode, 1);
node->cap = cap;
node->v = push_array_no_zero(arena, DEMON_Trap, node->cap);
node->v = push_array_no_zero(arena, DMN_Trap, node->cap);
SLLQueuePush(list->first, list->last, node);
list->node_count += 1;
}
@@ -153,7 +39,7 @@ demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEM
}
internal void
demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push)
dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
{
if(dst->last == 0)
{
@@ -170,11 +56,11 @@ demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkL
}
internal void
demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push)
dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push)
{
for(DEMON_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next)
{
DEMON_TrapChunkNode *dst_n = push_array(arena, DEMON_TrapChunkNode, 1);
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;
@@ -187,685 +73,81 @@ demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst
//- rjf: handle lists
internal void
demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle)
dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle)
{
DEMON_HandleNode *node = push_array(arena, DEMON_HandleNode, 1);
DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1);
SLLQueuePush(list->first, list->last, node);
node->v = handle;
list->count += 1;
}
internal DEMON_HandleArray
demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list)
internal DMN_HandleArray
dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list)
{
DEMON_HandleArray array = {0};
DMN_HandleArray array = {0};
array.count = list->count;
array.handles = push_array_no_zero(arena, DEMON_Handle, array.count);
array.handles = push_array_no_zero(arena, DMN_Handle, array.count);
U64 idx = 0;
for(DEMON_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
{
array.handles[idx] = n->v;
}
return array;
}
internal DEMON_HandleArray
demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src)
internal DMN_HandleArray
dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src)
{
DEMON_HandleArray dst = {0};
DMN_HandleArray dst = {0};
dst.count = src->count;
dst.handles = push_array_no_zero(arena, DEMON_Handle, dst.count);
MemoryCopy(dst.handles, src->handles, sizeof(DEMON_Handle)*dst.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: Primary Thread & Exclusive Mode Controls
//- rjf: event list building
internal void
demon_primary_thread_begin(void){
demon_primary_thread = 1;
}
internal void
demon_exclusive_mode_begin(void){
Assert(demon_primary_thread);
os_mutex_take(demon_state_mutex);
demon_run_state = 1;
os_mutex_drop(demon_state_mutex);
}
internal void
demon_exclusive_mode_end(void){
Assert(demon_primary_thread);
os_mutex_take(demon_state_mutex);
demon_run_state = 0;
os_mutex_drop(demon_state_mutex);
}
////////////////////////////////
//~ rjf: Running/Halting
internal DEMON_EventList
demon_run(Arena *arena, DEMON_RunCtrls *ctrls)
internal DMN_Event *
dmn_event_list_push(Arena *arena, DMN_EventList *list)
{
Assert(demon_primary_thread);
Temp scratch = scratch_begin(&arena, 1);
// convert controls to os controls
B32 full_conversion = 1;
DEMON_OS_RunCtrls os_ctrls = {0};
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);
{
// convert single_step_thread
if (ctrls->single_step_thread != 0){
DEMON_Entity *sst_entity = demon_ent_ptr_from_handle(ctrls->single_step_thread);
if (sst_entity != 0 &&
sst_entity->kind == DEMON_EntityKind_Thread){
os_ctrls.single_step_thread = sst_entity;
}
else{
full_conversion = 0;
goto finish_conversion;
}
}
// convert exception handling flag
os_ctrls.ignore_previous_exception = ctrls->ignore_previous_exception;
// convert fronzen threads
os_ctrls.run_entities_are_unfrozen = ctrls->run_entities_are_unfrozen;
os_ctrls.run_entities_are_processes = ctrls->run_entities_are_processes;
os_ctrls.run_entity_count = ctrls->run_entity_count;
os_ctrls.run_entities = push_array_no_zero(scratch.arena, DEMON_Entity*, ctrls->run_entity_count);
{
DEMON_EntityKind expected_entity_kind = DEMON_EntityKind_Thread;
if (os_ctrls.run_entities_are_processes){
expected_entity_kind = DEMON_EntityKind_Process;
}
DEMON_Handle *src = ctrls->run_entities;
DEMON_Entity **dst = os_ctrls.run_entities;
for (U64 i = 0; i < ctrls->run_entity_count; i += 1, src += 1, dst += 1){
DEMON_Entity *frozen_thread = demon_ent_ptr_from_handle(*src);
if (frozen_thread != 0 &&
frozen_thread->kind == expected_entity_kind){
*dst = frozen_thread;
}
else{
full_conversion = 0;
goto finish_conversion;
}
}
}
// convert traps
os_ctrls.traps = push_array_no_zero(scratch.arena, DEMON_OS_Trap, ctrls->traps.trap_count);
{
DEMON_OS_Trap *dst = os_ctrls.traps;
for (DEMON_TrapChunkNode *node = ctrls->traps.first;
node != 0;
node = node->next){
DEMON_Trap *src = node->v;
U64 node_trap_count = node->count;
for (U64 i = 0; i < node_trap_count; i += 1, src += 1){
if (src->process != 0){
DEMON_Entity *trap_process = demon_ent_ptr_from_handle(src->process);
if (trap_process != 0 &&
trap_process->kind == DEMON_EntityKind_Process){
dst->process = trap_process;
dst->address = src->address;
dst += 1;
}
else{
full_conversion = 0;
goto finish_conversion;
}
}
}
}
os_ctrls.trap_count = (U64)(dst - os_ctrls.traps);
}
finish_conversion:;
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);
}
// call the OS implementation of run
DEMON_EventList result = {0};
if (full_conversion){
result = demon_os_run(arena, &os_ctrls);
}
else{
DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error);
event->error_kind = DEMON_ErrorKind_InvalidHandle;
}
scratch_end(scratch);
return(result);
}
internal void
demon_halt(U64 code, U64 user_data){
demon_os_halt(code, user_data);
return result;
}
internal U64
demon_get_time_counter(void){
return(demon_time);
}
////////////////////////////////
//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting
internal U32
demon_launch_process(OS_LaunchOptions *options){
Assert(demon_primary_thread);
U32 result = demon_os_launch_process(options);
return(result);
}
internal B32
demon_attach_process(U32 pid){
Assert(demon_primary_thread);
B32 result = demon_os_attach_process(pid);
return(result);
}
internal B32
demon_kill_process(DEMON_Handle process, U32 exit_code){
Assert(demon_primary_thread);
B32 result = 0;
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
result = demon_os_kill_process(entity, exit_code);
}
return(result);
}
internal B32
demon_detach_process(DEMON_Handle process){
Assert(demon_primary_thread);
B32 result = 0;
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
result = demon_os_detach_process(entity);
}
return(result);
}
////////////////////////////////
//~ rjf: Entity Functions
//- rjf: basics
internal B32
demon_object_exists(DEMON_Handle object){
B32 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(object);
result = (entity != 0);
demon_access_end();
}
return(result);
}
//- rjf: introspection
internal Architecture
demon_arch_from_object(DEMON_Handle object){
Architecture result = Architecture_Null;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(object);
if (entity != 0){
result = (Architecture)entity->arch;
}
demon_access_end();
}
return(result);
}
internal U64
demon_base_vaddr_from_module(DEMON_Handle module){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
if (entity != 0 && entity->kind == DEMON_EntityKind_Module){
result = entity->id;
}
demon_access_end();
}
return(result);
}
internal Rng1U64
demon_vaddr_range_from_module(DEMON_Handle module)
dmn_rsp_from_thread(DMN_Handle thread)
{
Rng1U64 result = {0};
if(demon_access_begin())
U64 result = 0;
Temp scratch = scratch_begin(0, 0);
{
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
if(entity != 0 && entity->kind == DEMON_EntityKind_Module)
{
result = r1u64(entity->id, entity->id+entity->addr_range_dim);
}
demon_access_end();
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);
}
return(result);
}
internal String8
demon_full_path_from_module(Arena *arena, DEMON_Handle module){
String8 result = {0};
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(module);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Module){
result = demon_accel_full_path_from_module(arena, entity);
}
demon_access_end();
}
return(result);
}
internal U64
demon_stack_base_vaddr_from_thread(DEMON_Handle thread){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 && entity->kind == DEMON_EntityKind_Thread){
result = demon_accel_stack_base_vaddr_from_thread(entity);
}
demon_access_end();
}
return(result);
}
internal U64
demon_tls_root_vaddr_from_thread(DEMON_Handle handle){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(handle);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
result = demon_accel_tls_root_vaddr_from_thread(entity);
}
demon_access_end();
}
return(result);
}
internal DEMON_HandleArray
demon_all_processes(Arena *arena){
DEMON_HandleArray result = {0};
if (demon_access_begin()){
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_proc_count);
DEMON_Handle *handle_opl = handles + demon_proc_count;
DEMON_Handle *handle_ptr = handles;
for (DEMON_Entity *process = demon_ent_root->first;
process != 0 && handle_ptr < handle_opl;
process = process->next){
if (process->kind == DEMON_EntityKind_Process){
*handle_ptr = demon_ent_handle_from_ptr(process);
handle_ptr += 1;
}
}
result.handles = handles;
result.count = (U64)(handle_ptr - handles);
U64 unused_count = demon_proc_count - result.count;
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
demon_access_end();
}
return(result);
}
internal DEMON_HandleArray
demon_threads_from_process(Arena *arena, DEMON_Handle process){
DEMON_HandleArray result = {0};
if (demon_access_begin()){
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_thread_count);
DEMON_Handle *handle_opl = handles + demon_thread_count;
DEMON_Handle *handle_ptr = handles;
DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process);
if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){
for (DEMON_Entity *thread = process_ptr->first;
thread != 0 && handle_ptr < handle_opl;
thread = thread->next){
if (thread->kind == DEMON_EntityKind_Thread){
*handle_ptr = demon_ent_handle_from_ptr(thread);
handle_ptr += 1;
}
}
}
result.handles = handles;
result.count = (U64)(handle_ptr - handles);
U64 unused_count = demon_thread_count - result.count;
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
demon_access_end();
}
return(result);
}
internal DEMON_HandleArray
demon_modules_from_process(Arena *arena, DEMON_Handle process){
DEMON_HandleArray result = {0};
if (demon_access_begin()){
DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_module_count);
DEMON_Handle *handle_opl = handles + demon_module_count;
DEMON_Handle *handle_ptr = handles;
DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process);
if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){
for (DEMON_Entity *module = process_ptr->first;
module != 0 && handle_ptr < handle_opl;
module = module->next){
if (module->kind == DEMON_EntityKind_Module){
*handle_ptr = demon_ent_handle_from_ptr(module);
handle_ptr += 1;
}
}
}
result.handles = handles;
result.count = (U64)(handle_ptr - handles);
U64 unused_count = demon_module_count - result.count;
arena_put_back(arena, sizeof(DEMON_Handle)*unused_count);
demon_access_end();
}
return(result);
}
//- rjf: target process memory allocation/protection
internal U64
demon_reserve_memory(DEMON_Handle process, U64 size){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
result = demon_os_reserve_memory(entity, size);
}
demon_access_end();
}
return(result);
}
internal B32
demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){
B32 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
demon_os_set_memory_protect_flags(entity, page_vaddr, size, flags);
result = 1;
}
demon_access_end();
}
return(result);
}
internal B32
demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size){
B32 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
demon_os_release_memory(entity, vaddr, size);
result = 1;
}
demon_access_end();
}
return(result);
}
//- rjf: target process memory reading/writing
internal U64
demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size){
U64 bytes_read = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
bytes_read = demon_os_read_memory(entity, dst, src_address, size);
}
demon_access_end();
}
return(bytes_read);
}
internal B32
demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size){
B32 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(process);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Process){
result = demon_os_write_memory(entity, dst_address, src, size);
}
demon_access_end();
}
return(result);
}
#define READ_BLOCK_SIZE 4096
internal U64
demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size){
// Algorithm:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ^ ^ ^
// MIN MAX SMAX
// [MIN,MAX) - range attempting to read
// [MAX,SMAX) - range not yet proven to be impossible to read
Assert(src_address%READ_BLOCK_SIZE == 0);
Assert(size%READ_BLOCK_SIZE == 0);
U64 read_size = 0;
U64 min = 0;
U64 max = size;
U64 smax = max;
for (;;){
if (max <= min){
break;
}
// attempt to read range
U64 attempt_size = max - min;
B32 success = demon_read_memory(process, (U8*)dst + min, src_address + min, attempt_size);
if (success){
// increase successful read size
read_size += attempt_size;
// adjust range up
min = max;
max = smax;
}
else{
// mark this point as too far
smax = max - READ_BLOCK_SIZE;
// bisect the range for the next read attempt
U64 mid = (min + max)/2;
U64 aligned_mid = AlignDownPow2(mid, READ_BLOCK_SIZE);
max = aligned_mid;
}
}
U64 result = read_size;
return(result);
}
internal U64
demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size){
U64 read_size = 0;
if (demon_access_begin()){
B32 done = 0;
U64 read_opl = src_address + size;
// pre-aligned part -- [SRC,PRE_OPL)
U64 src_block_opl = AlignPow2(src_address, READ_BLOCK_SIZE);
U64 pre_opl = Min(src_block_opl, read_opl);
if(src_address < pre_opl)
{
U64 attempt_size = pre_opl - src_address;
if(!demon_read_memory(process, dst, src_address, attempt_size))
{
done = 1;
}
else
{
read_size += attempt_size;
}
}
// aligned part -- [PRE_OPL,POST_FIRST)
U64 read_opl_block_base = AlignDownPow2(read_opl, READ_BLOCK_SIZE);
U64 post_first = Max(read_opl_block_base, pre_opl);
if (!done && pre_opl < post_first){
U64 off = pre_opl - src_address;
U64 attempt_size = post_first - pre_opl;
U64 actual_size = demon_read_memory_amap_aligned(process, (U8*)dst + off,
pre_opl, attempt_size);
read_size += actual_size;
if (actual_size < attempt_size){
done = 1;
}
}
// post-aligned part -- [POST_FIRST,READ_OPL)
if (!done && post_first < read_opl){
U64 off = post_first - src_address;
U64 attempt_size = read_opl - post_first;
if (!demon_read_memory(process, (U8*)dst + off, post_first, attempt_size)){
done = 1;
}
else
{
read_size += attempt_size;
}
}
demon_access_end();
}
U64 result = read_size;
return(result);
}
#undef READ_BLOCK_SIZE
//- rjf: thread registers reading/writing
internal void*
demon_read_regs(DEMON_Handle thread){
void *result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
result = demon_accel_read_regs(entity);
}
demon_access_end();
}
return(result);
}
internal B32
demon_write_regs(DEMON_Handle thread, void *data){
B32 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
demon_accel_write_regs(entity, data);
result = 1;
}
demon_access_end();
}
return(result);
}
internal U64
demon_read_ip(DEMON_Handle thread){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
void *regs = demon_accel_read_regs(entity);
result = regs_rip_from_arch_block((Architecture)entity->arch, regs);
}
demon_access_end();
}
return(result);
}
internal U64
demon_read_sp(DEMON_Handle thread){
U64 result = 0;
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
void *regs = demon_accel_read_regs(entity);
result = regs_rsp_from_arch_block((Architecture)entity->arch, regs);
}
demon_access_end();
}
return(result);
}
internal void
demon_write_ip(DEMON_Handle thread, U64 ip){
if (demon_access_begin()){
DEMON_Entity *entity = demon_ent_ptr_from_handle(thread);
if (entity != 0 &&
entity->kind == DEMON_EntityKind_Thread){
void *regs = demon_accel_read_regs(entity);
regs_arch_block_write_rip((Architecture)entity->arch, regs, ip);
demon_accel_write_regs(entity, regs);
}
demon_access_end();
}
}
////////////////////////////////
//~ rjf: Process Listing
internal void
demon_proc_iter_begin(DEMON_ProcessIter *iter){
demon_os_proc_iter_begin(iter);
}
internal B32
demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){
return(demon_os_proc_iter_next(arena, iter, info_out));
}
internal void
demon_proc_iter_end(DEMON_ProcessIter *iter){
demon_os_proc_iter_end(iter);
scratch_end(scratch);
return result;
}
+136 -192
View File
@@ -5,111 +5,70 @@
#define DEMON_CORE_H
////////////////////////////////
//~ allen: Demon Low Level Entities
//~ rjf: Control-Thread-Only Context
//
// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only
// used by the thread which called it. All APIs which can ONLY run on the
// control thread, which blocks to control & receive events, will take this
// parameter. All other APIs can be called from any thread.
typedef U64 DEMON_Handle;
typedef struct DEMON_HandleNode DEMON_HandleNode;
struct DEMON_HandleNode
typedef struct DMN_CtrlCtx DMN_CtrlCtx;
struct DMN_CtrlCtx
{
DEMON_HandleNode *next;
DEMON_Handle v;
U64 u64 [1];
};
typedef struct DEMON_HandleList DEMON_HandleList;
struct DEMON_HandleList
////////////////////////////////
//~ rjf: Handle Types
typedef union DMN_Handle DMN_Handle;
union DMN_Handle
{
DEMON_HandleNode *first;
DEMON_HandleNode *last;
U32 u32[2];
U64 u64[1];
};
typedef struct DMN_HandleNode DMN_HandleNode;
struct DMN_HandleNode
{
DMN_HandleNode *next;
DMN_Handle v;
};
typedef struct DMN_HandleList DMN_HandleList;
struct DMN_HandleList
{
DMN_HandleNode *first;
DMN_HandleNode *last;
U64 count;
};
typedef struct DEMON_HandleArray DEMON_HandleArray;
struct DEMON_HandleArray
typedef struct DMN_HandleArray DMN_HandleArray;
struct DMN_HandleArray
{
DEMON_Handle *handles;
DMN_Handle *handles;
U64 count;
};
////////////////////////////////
//~ rjf: Memory Protection Flags
//~ rjf: Generated Code
typedef U32 DEMON_MemoryProtectFlags;
enum{
DEMON_MemoryProtectFlag_Read = (1<<0),
DEMON_MemoryProtectFlag_Write = (1<<1),
DEMON_MemoryProtectFlag_Execute = (1<<2),
};
#include "generated/demon.meta.h"
////////////////////////////////
//~ allen: Demon Event Types
//~ rjf: Event Types
typedef enum DEMON_EventKind
typedef struct DMN_Event DMN_Event;
struct DMN_Event
{
DEMON_EventKind_Null,
DEMON_EventKind_Error,
DEMON_EventKind_HandshakeComplete,
DEMON_EventKind_CreateProcess,
DEMON_EventKind_ExitProcess,
DEMON_EventKind_CreateThread,
DEMON_EventKind_ExitThread,
DEMON_EventKind_LoadModule,
DEMON_EventKind_UnloadModule,
DEMON_EventKind_Breakpoint,
DEMON_EventKind_Trap,
DEMON_EventKind_SingleStep,
DEMON_EventKind_Exception,
DEMON_EventKind_Halt,
DEMON_EventKind_Memory,
DEMON_EventKind_DebugString,
DEMON_EventKind_SetThreadName,
DEMON_EventKind_COUNT
}
DEMON_EventKind;
typedef enum DEMON_ErrorKind
{
DEMON_ErrorKind_Null,
DEMON_ErrorKind_NotInitialized,
DEMON_ErrorKind_NotAttached,
DEMON_ErrorKind_UnexpectedFailure,
DEMON_ErrorKind_InvalidHandle,
}
DEMON_ErrorKind;
typedef enum DEMON_MemoryEventKind
{
DEMON_MemoryEventKind_Null,
DEMON_MemoryEventKind_Commit,
DEMON_MemoryEventKind_Reserve,
DEMON_MemoryEventKind_Decommit,
DEMON_MemoryEventKind_Release,
DEMON_MemoryEventKind_COUNT
}
DEMON_MemoryEventKind;
typedef enum DEMON_ExceptionKind
{
DEMON_ExceptionKind_Null,
DEMON_ExceptionKind_MemoryRead,
DEMON_ExceptionKind_MemoryWrite,
DEMON_ExceptionKind_MemoryExecute,
DEMON_ExceptionKind_CppThrow,
DEMON_ExceptionKind_COUNT
}
DEMON_ExceptionKind;
typedef struct DEMON_Event DEMON_Event;
struct DEMON_Event
{
// TODO(allen): condense
DEMON_EventKind kind;
DEMON_ErrorKind error_kind;
DEMON_MemoryEventKind memory_kind;
DEMON_ExceptionKind exception_kind;
DEMON_Handle process;
DEMON_Handle thread;
DEMON_Handle module;
DMN_EventKind kind;
DMN_ErrorKind error_kind;
DMN_MemoryEventKind memory_kind;
DMN_ExceptionKind exception_kind;
DMN_Handle process;
DMN_Handle thread;
DMN_Handle module;
Architecture arch;
U64 address;
U64 size;
String8 string;
@@ -123,171 +82,156 @@ struct DEMON_Event
B32 exception_repeated;
};
typedef struct DEMON_EventNode DEMON_EventNode;
struct DEMON_EventNode
typedef struct DMN_EventNode DMN_EventNode;
struct DMN_EventNode
{
DEMON_EventNode *next;
DEMON_Event v;
DMN_EventNode *next;
DMN_Event v;
};
typedef struct DEMON_EventList DEMON_EventList;
struct DEMON_EventList
typedef struct DMN_EventList DMN_EventList;
struct DMN_EventList
{
DEMON_EventNode *first;
DEMON_EventNode *last;
DMN_EventNode *first;
DMN_EventNode *last;
U64 count;
};
////////////////////////////////
//~ allen: Demon Run Control Types
//~ rjf: Run Control Types
typedef struct DEMON_Trap DEMON_Trap;
struct DEMON_Trap
typedef struct DMN_Trap DMN_Trap;
struct DMN_Trap
{
DEMON_Handle process;
U64 address;
DMN_Handle process;
U64 vaddr;
U64 id;
};
typedef struct DEMON_TrapChunkNode DEMON_TrapChunkNode;
struct DEMON_TrapChunkNode
typedef struct DMN_TrapChunkNode DMN_TrapChunkNode;
struct DMN_TrapChunkNode
{
DEMON_TrapChunkNode *next;
DEMON_Trap *v;
DMN_TrapChunkNode *next;
DMN_Trap *v;
U64 cap;
U64 count;
};
typedef struct DEMON_TrapChunkList DEMON_TrapChunkList;
struct DEMON_TrapChunkList
typedef struct DMN_TrapChunkList DMN_TrapChunkList;
struct DMN_TrapChunkList
{
DEMON_TrapChunkNode *first;
DEMON_TrapChunkNode *last;
DMN_TrapChunkNode *first;
DMN_TrapChunkNode *last;
U64 node_count;
U64 trap_count;
};
typedef struct DEMON_RunCtrls DEMON_RunCtrls;
struct DEMON_RunCtrls
typedef struct DMN_RunCtrls DMN_RunCtrls;
struct DMN_RunCtrls
{
DEMON_Handle single_step_thread;
DMN_Handle single_step_thread;
B8 ignore_previous_exception;
B8 run_entities_are_unfrozen;
B8 run_entities_are_processes;
DEMON_Handle *run_entities;
DMN_Handle *run_entities;
U64 run_entity_count;
DEMON_TrapChunkList traps;
DMN_TrapChunkList traps;
};
////////////////////////////////
//~ allen: Demon Process Listing
//~ rjf: System Process Listing Types
typedef struct DEMON_ProcessIter DEMON_ProcessIter;
struct DEMON_ProcessIter
typedef struct DMN_ProcessIter DMN_ProcessIter;
struct DMN_ProcessIter
{
U64 v[2];
};
typedef struct DEMON_ProcessInfo DEMON_ProcessInfo;
struct DEMON_ProcessInfo
typedef struct DMN_ProcessInfo DMN_ProcessInfo;
struct DMN_ProcessInfo
{
String8 name;
U32 pid;
};
////////////////////////////////
//~ rjf: Main Layer Initialization
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
internal void demon_init(void);
////////////////////////////////
//~ rjf: Basic Type Functions
//- rjf: stringizing
internal String8 demon_string_from_event_kind(DEMON_EventKind kind);
internal String8 demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind);
internal String8 demon_string_from_exception_kind(DEMON_ExceptionKind kind);
internal void demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event);
//- rjf: handles
internal DMN_Handle dmn_handle_zero(void);
internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b);
//- rjf: trap chunk lists
internal void demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap);
internal void demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
internal void demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push);
internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap);
internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
//- rjf: handle lists
internal void demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle);
internal DEMON_HandleArray demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list);
internal DEMON_HandleArray demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src);
internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle);
internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list);
internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src);
//- rjf: event list building
internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list);
////////////////////////////////
//~ rjf: Primary Thread & Exclusive Mode Controls
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
internal void demon_primary_thread_begin(void);
internal void demon_exclusive_mode_begin(void);
internal void demon_exclusive_mode_end(void);
internal U64 dmn_rip_from_thread(DMN_Handle thread);
internal U64 dmn_rsp_from_thread(DMN_Handle thread);
////////////////////////////////
//~ rjf: Running/Halting
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
internal DEMON_EventList demon_run(Arena *arena, DEMON_RunCtrls *ctrls);
internal void demon_halt(U64 code, U64 user_data);
internal U64 demon_get_time_counter(void);
internal void dmn_init(void);
////////////////////////////////
//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
internal U32 demon_launch_process(OS_LaunchOptions *options);
internal B32 demon_attach_process(U32 pid);
internal B32 demon_kill_process(DEMON_Handle process, U32 exit_code);
internal B32 demon_detach_process(DEMON_Handle process);
internal DMN_CtrlCtx *dmn_ctrl_begin(void);
internal void dmn_ctrl_exclusive_access_begin(void);
internal void dmn_ctrl_exclusive_access_end(void);
#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end())
internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options);
internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid);
internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code);
internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process);
internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls);
////////////////////////////////
//~ rjf: Entity Functions
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
//- rjf: basics
internal B32 demon_object_exists(DEMON_Handle object);
//- rjf: introspection
internal Architecture demon_arch_from_object(DEMON_Handle object);
internal U64 demon_base_vaddr_from_module(DEMON_Handle module);
internal Rng1U64 demon_vaddr_range_from_module(DEMON_Handle module);
internal String8 demon_full_path_from_module(Arena *arena, DEMON_Handle module);
internal U64 demon_stack_base_vaddr_from_thread(DEMON_Handle thread);
internal U64 demon_tls_root_vaddr_from_thread(DEMON_Handle thread);
internal DEMON_HandleArray demon_all_processes(Arena *arena);
internal DEMON_HandleArray demon_threads_from_process(Arena *arena, DEMON_Handle process);
internal DEMON_HandleArray demon_modules_from_process(Arena *arena, DEMON_Handle process);
//- rjf: target process memory allocation/protection
internal U64 demon_reserve_memory(DEMON_Handle process, U64 size);
internal B32 demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags);
internal B32 demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size);
//- rjf: target process memory reading/writing
internal U64 demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size);
internal B32 demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size);
internal U64 demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size);
internal U64 demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size);
//- rjf: thread registers reading/writing
// IMPORTANT(allen): This API is _trusting_ you. You should never modify the data pointed
// at by that void pointer! It is pointing to the internal cache of the registers, so it
// will become invalid after a call to demon_write_regs, or demon_run. Use it to read
// what you need and be done ASAP and we can avoid an extra copy baked into the API.
internal void *demon_read_regs(DEMON_Handle thread);
internal B32 demon_write_regs(DEMON_Handle thread, void *data);
// TODO(allen): These might be a bad idea when we try to extend to ARM
// They make sense for x86/x64 abstraction, which often needs identical
// code paths except for these parts. Revisit this when ARM is integrated.
internal U64 demon_read_ip(DEMON_Handle thread);
internal U64 demon_read_sp(DEMON_Handle thread);
internal void demon_write_ip(DEMON_Handle thread, U64 ip);
internal void dmn_halt(U64 code, U64 user_data);
////////////////////////////////
//~ rjf: Process Listing
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
internal void demon_proc_iter_begin(DEMON_ProcessIter *iter);
internal B32 demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out);
internal void demon_proc_iter_end(DEMON_ProcessIter *iter);
//- rjf: run/memory/register counters
internal U64 dmn_run_gen(void);
internal U64 dmn_mem_gen(void);
internal U64 dmn_reg_gen(void);
#endif //DEMON_CORE_H
//- rjf: non-blocking-control-thread access barriers
internal B32 dmn_access_open(void);
internal void dmn_access_close(void);
#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close())
//- rjf: processes
internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
//- rjf: threads
internal Architecture dmn_arch_from_thread(DMN_Handle handle);
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
//- rjf: system process listing
internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out);
internal void dmn_process_iter_end(DMN_ProcessIter *iter);
#endif // DEMON_CORE_H
+2 -7
View File
@@ -2,14 +2,9 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "demon_core.c"
#include "demon_common.c"
#include "demon_accel.c"
#include "demon_os.c"
#if OS_WINDOWS
# include "win32/demon_os_win32.c"
#elif OS_LINUX
# include "linux/demon_os_linux.c"
# include "win32/demon_core_win32.c"
#else
# error No Demon Implementation for This OS
# error Demon layer backend not defined for this operating system.
#endif
+3 -8
View File
@@ -5,16 +5,11 @@
#define DEMON_INC_H
#include "demon_core.h"
#include "demon_common.h"
#include "demon_accel.h"
#include "demon_os.h"
#if OS_WINDOWS
# include "win32/demon_os_win32.h"
#elif OS_LINUX
# include "linux/demon_os_linux.h"
# include "win32/demon_core_win32.h"
#else
# error No Demon Implementation for This OS
# error Demon layer backend not defined for this operating system.
#endif
#endif //DEMON_INC_H
#endif // DEMON_INC_H
-28
View File
@@ -1,28 +0,0 @@
////////////////////////////////
//~ rjf: Helpers
internal B32
demon_os_read_regs(DEMON_Entity *thread, void *dst)
{
B32 result = 0;
switch(thread->arch)
{
default:{}break;
case Architecture_x86:{result = demon_os_read_regs_x86(thread, (REGS_RegBlockX86 *)dst);}break;
case Architecture_x64:{result = demon_os_read_regs_x64(thread, (REGS_RegBlockX64 *)dst);}break;
}
return result;
}
internal B32
demon_os_write_regs(DEMON_Entity *thread, void *src)
{
B32 result = 0;
switch(thread->arch)
{
default:{}break;
case Architecture_x86:{result = demon_os_write_regs_x86(thread, (REGS_RegBlockX86 *)src);}break;
case Architecture_x64:{result = demon_os_write_regs_x64(thread, (REGS_RegBlockX64 *)src);}break;
}
return result;
}
-98
View File
@@ -1,98 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON_OS_H
#define DEMON_OS_H
// NOTE(allen):
// These are the functions that the OS backends actually implement.
// Demon objects go through a handle validation layer but it is a lot more
// convenient in the OS backends to implement these versions which take the
// already validated DEMON_Entity*. These are also more convenient to call from
// the backend layer, which lets us avoid converting back and forth between
// handles and pointers a lot.
////////////////////////////////
//~ NOTE(allen): Demon OS Run Control Types
typedef struct DEMON_OS_Trap DEMON_OS_Trap;
struct DEMON_OS_Trap
{
DEMON_Entity *process;
U64 address;
};
typedef struct DEMON_OS_RunCtrls DEMON_OS_RunCtrls;
struct DEMON_OS_RunCtrls
{
DEMON_Entity *single_step_thread;
B8 ignore_previous_exception;
B8 run_entities_are_unfrozen;
B8 run_entities_are_processes;
DEMON_Entity **run_entities;
U64 run_entity_count;
DEMON_OS_Trap *traps;
U64 trap_count;
};
////////////////////////////////
//~ rjf: Helpers
internal B32 demon_os_read_regs(DEMON_Entity *thread, void *dst);
internal B32 demon_os_write_regs(DEMON_Entity *thread, void *src);
////////////////////////////////
//~ rjf: @demon_os_hooks Main Layer Initialization
internal void demon_os_init(void);
////////////////////////////////
//~ rjf: @demon_os_hooks Running/Halting
internal DEMON_EventList demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls);
internal void demon_os_halt(U64 code, U64 user_data);
////////////////////////////////
//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting
internal U32 demon_os_launch_process(OS_LaunchOptions *options);
internal B32 demon_os_attach_process(U32 pid);
internal B32 demon_os_kill_process(DEMON_Entity *process, U32 exit_code);
internal B32 demon_os_detach_process(DEMON_Entity *process);
////////////////////////////////
//~ rjf: @demon_os_hooks Entity Functions
//- rjf: cleanup
internal void demon_os_entity_cleanup(DEMON_Entity *entity);
//- rjf: introspection
internal String8 demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module);
internal U64 demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread);
internal U64 demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread);
//- rjf: target process memory allocation/protection
internal U64 demon_os_reserve_memory(DEMON_Entity *process, U64 size);
internal void demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags);
internal void demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size);
//- rjf: target process memory reading/writing
internal U64 demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size);
internal B32 demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size);
#define demon_os_read_struct(p,dst,src) demon_os_read_memory((p), (dst), (src), sizeof(*(dst)))
#define demon_os_write_struct(p,dst,src) demon_os_write_memory((p), (dst), (src), sizeof(*(src)))
//- rjf: thread registers reading/writing
internal B32 demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst);
internal B32 demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src);
internal B32 demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst);
internal B32 demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src);
////////////////////////////////
//~ rjf: @demon_os_hooks Process Listing
internal void demon_os_proc_iter_begin(DEMON_ProcessIter *iter);
internal B32 demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out);
internal void demon_os_proc_iter_end(DEMON_ProcessIter *iter);
#endif //DEMON_OS_H
@@ -3,8 +3,8 @@
//- GENERATED CODE
#ifndef DEMON2_META_H
#define DEMON2_META_H
#ifndef DEMON_META_H
#define DEMON_META_H
typedef enum DMN_EventKind
{
@@ -60,4 +60,4 @@ DMN_ExceptionKind_COUNT,
C_LINKAGE_BEGIN
C_LINKAGE_END
#endif // DEMON2_META_H
#endif // DEMON_META_H
File diff suppressed because it is too large Load Diff
-222
View File
@@ -1,222 +0,0 @@
// 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
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON2_CORE_WIN32_H
#define DEMON2_CORE_WIN32_H
#ifndef DEMON_CORE_WIN32_H
#define DEMON_CORE_WIN32_H
////////////////////////////////
//~ rjf: Windows Includes
@@ -284,4 +284,4 @@ internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, vo
//- rjf: remote thread injection
internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address);
#endif // DEMON2_CORE_WIN32_H
#endif // DEMON_CORE_WIN32_H
File diff suppressed because it is too large Load Diff
-385
View File
@@ -1,385 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON_OS_WIN32_H
#define DEMON_OS_WIN32_H
////////////////////////////////
//~ NOTE(allen): Win32 Demon Headers Negotation
// windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
////////////////////////////////
//~ NOTE(allen): Win32 Demon Types
//- entities
// Demon Win32 Entity Extensions
// Process: ext points to independently allocated DEMON_W32_Ext
// Thread : ext points to independently allocated DEMON_W32_Ext
// Module : ext set to HANDLE
typedef union DEMON_W32_Ext DEMON_W32_Ext;
union DEMON_W32_Ext
{
DEMON_W32_Ext *next;
struct{
HANDLE handle;
U64 injection_address;
B32 did_first_bp;
} proc;
struct{
HANDLE handle;
U64 thread_local_base;
U64 last_name_hash;
U64 name_gather_time_us;
B32 last_run_reported_trap;
U64 last_run_reported_trap_pre_rip;
U64 last_run_reported_trap_post_rip;
} thread;
struct{
HANDLE handle;
U64 address_of_name_pointer;
B32 is_main;
B32 name_is_unicode;
} module;
};
//- helpers
typedef struct DEMON_W32_InjectedBreak DEMON_W32_InjectedBreak;
struct DEMON_W32_InjectedBreak
{
U64 code;
U64 user_data;
};
#define DEMON_W32_INJECTED_CODE_SIZE 32
typedef struct DEMON_W32_ImageInfo DEMON_W32_ImageInfo;
struct DEMON_W32_ImageInfo
{
Architecture arch;
U32 size;
};
typedef struct DEMON_W32_EntityNode DEMON_W32_EntityNode;
struct DEMON_W32_EntityNode
{
DEMON_W32_EntityNode *next;
DEMON_Entity *entity;
};
typedef HRESULT GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription);
////////////////////////////////
//~ NOTE(allen): Win32 Demon Exceptions
#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u
#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u
#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u
#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u
#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu
#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u
#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u
#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u
#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u
#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u
#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u
#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u
#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u
#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u
#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u
#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u
#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u
#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u
#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u
#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u
#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u
#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u
#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u
#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u
#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u
#define DEMON_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u
////////////////////////////////
//~ NOTE(allen): Win32 Demon Register API Codes
#define DEMON_W32_CTX_X86 0x00010000
#define DEMON_W32_CTX_X64 0x00100000
#define DEMON_W32_CTX_INTEL_CONTROL 0x0001
#define DEMON_W32_CTX_INTEL_INTEGER 0x0002
#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004
#define DEMON_W32_CTX_INTEL_FLOATS 0x0008
#define DEMON_W32_CTX_INTEL_DEBUG 0x0010
#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020
#define DEMON_W32_CTX_INTEL_XSTATE 0x0040
#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \
DEMON_W32_CTX_INTEL_EXTENDED)
#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \
DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \
DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \
DEMON_W32_CTX_INTEL_DEBUG)
////////////////////////////////
//~ rjf: DOS Header Types
// this is the "MZ" as a 16-bit short
#define DEMON_DOS_MAGIC 0x5a4d
#pragma pack(push,1)
typedef struct DEMON_DosHeader DEMON_DosHeader;
struct DEMON_DosHeader
{
U16 magic;
U16 last_page_size;
U16 page_count;
U16 reloc_count;
U16 paragraph_header_size;
U16 min_paragraph;
U16 max_paragraph;
U16 init_ss;
U16 init_sp;
U16 checksum;
U16 init_ip;
U16 init_cs;
U16 reloc_table_file_off;
U16 overlay_number;
U16 reserved[4];
U16 oem_id;
U16 oem_info;
U16 reserved2[10];
U32 coff_file_offset;
};
#pragma pack(pop)
////////////////////////////////
//~ rjf: Coff Header Types
#define DEMON_PE_MAGIC 0x00004550u
typedef U16 DEMON_CoffMachineType;
enum{
DEMON_CoffMachineType_UNKNOWN = 0x0,
DEMON_CoffMachineType_X86 = 0x14c,
DEMON_CoffMachineType_X64 = 0x8664,
DEMON_CoffMachineType_ARM33 = 0x1d3,
DEMON_CoffMachineType_ARM = 0x1c0,
DEMON_CoffMachineType_ARM64 = 0xaa64,
DEMON_CoffMachineType_ARMNT = 0x1c4,
DEMON_CoffMachineType_EBC = 0xebc,
DEMON_CoffMachineType_IA64 = 0x200,
DEMON_CoffMachineType_M32R = 0x9041,
DEMON_CoffMachineType_MIPS16 = 0x266,
DEMON_CoffMachineType_MIPSFPU = 0x366,
DEMON_CoffMachineType_MIPSFPU16 = 0x466,
DEMON_CoffMachineType_POWERPC = 0x1f0,
DEMON_CoffMachineType_POWERPCFP = 0x1f1,
DEMON_CoffMachineType_R4000 = 0x166,
DEMON_CoffMachineType_RISCV32 = 0x5032,
DEMON_CoffMachineType_RISCV64 = 0x5064,
DEMON_CoffMachineType_RISCV128 = 0x5128,
DEMON_CoffMachineType_SH3 = 0x1a2,
DEMON_CoffMachineType_SH3DSP = 0x1a3,
DEMON_CoffMachineType_SH4 = 0x1a6,
DEMON_CoffMachineType_SH5 = 0x1a8,
DEMON_CoffMachineType_THUMB = 0x1c2,
DEMON_CoffMachineType_WCEMIPSV2 = 0x169,
DEMON_CoffMachineType_COUNT = 25
};
typedef U16 DEMON_CoffFlags;
enum{
DEMON_CoffFlag_RELOC_STRIPPED = (1 << 0),
DEMON_CoffFlag_EXECUTABLE_IMAGE = (1 << 1),
DEMON_CoffFlag_LINE_NUMS_STRIPPED = (1 << 2),
DEMON_CoffFlag_SYM_STRIPPED = (1 << 3),
DEMON_CoffFlag_RESERVED_0 = (1 << 4),
DEMON_CoffFlag_LARGE_ADDRESS_AWARE = (1 << 5),
DEMON_CoffFlag_RESERVED_1 = (1 << 6),
DEMON_CoffFlag_RESERVED_2 = (1 << 7),
DEMON_CoffFlag_32BIT_MACHINE = (1 << 8),
DEMON_CoffFlag_DEBUG_STRIPPED = (1 << 9),
DEMON_CoffFlag_REMOVABLE_RUN_FROM_SWAP = (1 << 10),
DEMON_CoffFlag_NET_RUN_FROM_SWAP = (1 << 11),
DEMON_CoffFlag_SYSTEM = (1 << 12),
DEMON_CoffFlag_DLL = (1 << 13),
DEMON_CoffFlag_UP_SYSTEM_ONLY = (1 << 14),
DEMON_CoffFlag_BYTES_RESERVED_HI = (1 << 15),
};
#pragma pack(push,1)
typedef struct DEMON_CoffHeader DEMON_CoffHeader;
struct DEMON_CoffHeader
{
DEMON_CoffMachineType machine;
U16 section_count;
U32 time_date_stamp;
// TODO: rename to "unix_timestamp"
U32 pointer_to_symbol_table;
U32 number_of_symbols;
// TODO: rename to "symbol_count"
U16 size_of_optional_header;
// TODO: rename to "optional_header_size"
DEMON_CoffFlags flags;
};
#pragma pack(pop)
////////////////////////////////
//~ rjf: PE Header Types
#pragma pack(push, 1)
typedef U16 DEMON_PeWindowsSubsystem;
enum{
DEMON_PeWindowsSubsystem_UNKNOWN = 0,
DEMON_PeWindowsSubsystem_NATIVE = 1,
DEMON_PeWindowsSubsystem_WINDOWS_GUI = 2,
DEMON_PeWindowsSubsystem_WINDOWS_CUI = 3,
DEMON_PeWindowsSubsystem_OS2_CUI = 5,
DEMON_PeWindowsSubsystem_POSIX_CUI = 7,
DEMON_PeWindowsSubsystem_NATIVE_WINDOWS = 8,
DEMON_PeWindowsSubsystem_WINDOWS_CE_GUI = 9,
DEMON_PeWindowsSubsystem_EFI_APPLICATION = 10,
DEMON_PeWindowsSubsystem_EFI_BOOT_SERVICE_DRIVER = 11,
DEMON_PeWindowsSubsystem_EFI_RUNTIME_DRIVER = 12,
DEMON_PeWindowsSubsystem_EFI_ROM = 13,
DEMON_PeWindowsSubsystem_XBOX = 14,
DEMON_PeWindowsSubsystem_WINDOWS_BOOT_APPLICATION = 16,
DEMON_PeWindowsSubsystem_COUNT = 14
};
typedef U16 DEMON_DllCharacteristics;
enum{
DEMON_DllCharacteristic_HIGH_ENTROPY_VA = (1 << 5),
DEMON_DllCharacteristic_DYNAMIC_BASE = (1 << 6),
DEMON_DllCharacteristic_FORCE_INTEGRITY = (1 << 7),
DEMON_DllCharacteristic_NX_COMPAT = (1 << 8),
DEMON_DllCharacteristic_NO_ISOLATION = (1 << 9),
DEMON_DllCharacteristic_NO_SEH = (1 << 10),
DEMON_DllCharacteristic_NO_BIND = (1 << 11),
DEMON_DllCharacteristic_APPCONTAINER = (1 << 12),
DEMON_DllCharacteristic_WDM_DRIVER = (1 << 13),
DEMON_DllCharacteristic_GUARD_CF = (1 << 14),
DEMON_DllCharacteristic_TERMINAL_SERVER_AWARE = (1 << 15),
};
typedef struct DEMON_PeOptionalHeader32 DEMON_PeOptionalHeader32;
struct DEMON_PeOptionalHeader32
{
U16 magic;
U8 major_linker_version;
U8 minor_linker_version;
U32 sizeof_code;
U32 sizeof_inited_data;
U32 sizeof_uninited_data;
U32 entry_point_va;
U32 code_base;
U32 data_base;
U32 image_base;
U32 section_alignment;
U32 file_alignment;
U16 major_os_ver;
U16 minor_os_ver;
U16 major_img_ver;
U16 minor_img_ver;
U16 major_subsystem_ver;
U16 minor_subsystem_ver;
U32 win32_version_value;
U32 sizeof_image;
U32 sizeof_headers;
U32 check_sum;
DEMON_PeWindowsSubsystem subsystem;
DEMON_DllCharacteristics dll_characteristics;
U32 sizeof_stack_reserve;
U32 sizeof_stack_commit;
U32 sizeof_heap_reserve;
U32 sizeof_heap_commit;
U32 loader_flags;
U32 data_dir_count;
};
typedef struct DEMON_PeOptionalHeader32Plus DEMON_PeOptionalHeader32Plus;
struct DEMON_PeOptionalHeader32Plus
{
U16 magic;
U8 major_linker_version;
U8 minor_linker_version;
U32 sizeof_code;
U32 sizeof_inited_data;
U32 sizeof_uninited_data;
U32 entry_point_va;
U32 code_base;
U64 image_base;
U32 section_alignment;
U32 file_alignment;
U16 major_os_ver;
U16 minor_os_ver;
U16 major_img_ver;
U16 minor_img_ver;
U16 major_subsystem_ver;
U16 minor_subsystem_ver;
U32 win32_version_value;
U32 sizeof_image;
U32 sizeof_headers;
U32 check_sum;
DEMON_PeWindowsSubsystem subsystem;
DEMON_DllCharacteristics dll_characteristics;
U64 sizeof_stack_reserve;
U64 sizeof_stack_commit;
U64 sizeof_heap_reserve;
U64 sizeof_heap_commit;
U32 loader_flags;
U32 data_dir_count;
};
#pragma pack(pop)
////////////////////////////////
//~ rjf: Helpers
internal U64 demon_w32_hash_from_string(String8 string);
internal DEMON_W32_Ext* demon_w32_ext_alloc(void);
internal DEMON_W32_Ext* demon_w32_ext(DEMON_Entity *entity);
internal U64 demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size);
internal B32 demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size);
internal String8 demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
internal String16 demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
#define demon_w32_read_struct(h,dst,src) demon_w32_read_memory((h), (dst), (src), sizeof(*(dst)))
internal DEMON_W32_ImageInfo demon_w32_image_info_from_base(HANDLE process_handle, U64 base);
internal DWORD demon_w32_inject_thread(DEMON_Entity *process, U64 start_address);
internal U16 demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave);
internal U16 demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw);
internal DWORD demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags);
////////////////////////////////
//~ rjf: Experiments
internal void demon_w32_peak_at_tls(DEMON_Handle handle);
#endif //DEMON_OS_WIN32_H
-153
View File
@@ -1,153 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ 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;
}
-237
View File
@@ -1,237 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON2_CORE_H
#define DEMON2_CORE_H
////////////////////////////////
//~ rjf: Control-Thread-Only Context
//
// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only
// used by the thread which called it. All APIs which can ONLY run on the
// control thread, which blocks to control & receive events, will take this
// parameter. All other APIs can be called from any thread.
typedef struct DMN_CtrlCtx DMN_CtrlCtx;
struct DMN_CtrlCtx
{
U64 u64 [1];
};
////////////////////////////////
//~ rjf: Handle Types
typedef union DMN_Handle DMN_Handle;
union DMN_Handle
{
U32 u32[2];
U64 u64[1];
};
typedef struct DMN_HandleNode DMN_HandleNode;
struct DMN_HandleNode
{
DMN_HandleNode *next;
DMN_Handle v;
};
typedef struct DMN_HandleList DMN_HandleList;
struct DMN_HandleList
{
DMN_HandleNode *first;
DMN_HandleNode *last;
U64 count;
};
typedef struct DMN_HandleArray DMN_HandleArray;
struct DMN_HandleArray
{
DMN_Handle *handles;
U64 count;
};
////////////////////////////////
//~ rjf: Generated Code
#include "generated/demon2.meta.h"
////////////////////////////////
//~ rjf: Event Types
typedef struct DMN_Event DMN_Event;
struct DMN_Event
{
DMN_EventKind kind;
DMN_ErrorKind error_kind;
DMN_MemoryEventKind memory_kind;
DMN_ExceptionKind exception_kind;
DMN_Handle process;
DMN_Handle thread;
DMN_Handle module;
Architecture arch;
U64 address;
U64 size;
String8 string;
U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully)
U32 flags;
S32 signo;
S32 sigcode;
U64 instruction_pointer;
U64 stack_pointer;
U64 user_data;
B32 exception_repeated;
};
typedef struct DMN_EventNode DMN_EventNode;
struct DMN_EventNode
{
DMN_EventNode *next;
DMN_Event v;
};
typedef struct DMN_EventList DMN_EventList;
struct DMN_EventList
{
DMN_EventNode *first;
DMN_EventNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Run Control Types
typedef struct DMN_Trap DMN_Trap;
struct DMN_Trap
{
DMN_Handle process;
U64 vaddr;
U64 id;
};
typedef struct DMN_TrapChunkNode DMN_TrapChunkNode;
struct DMN_TrapChunkNode
{
DMN_TrapChunkNode *next;
DMN_Trap *v;
U64 cap;
U64 count;
};
typedef struct DMN_TrapChunkList DMN_TrapChunkList;
struct DMN_TrapChunkList
{
DMN_TrapChunkNode *first;
DMN_TrapChunkNode *last;
U64 node_count;
U64 trap_count;
};
typedef struct DMN_RunCtrls DMN_RunCtrls;
struct DMN_RunCtrls
{
DMN_Handle single_step_thread;
B8 ignore_previous_exception;
B8 run_entities_are_unfrozen;
B8 run_entities_are_processes;
DMN_Handle *run_entities;
U64 run_entity_count;
DMN_TrapChunkList traps;
};
////////////////////////////////
//~ rjf: System Process Listing Types
typedef struct DMN_ProcessIter DMN_ProcessIter;
struct DMN_ProcessIter
{
U64 v[2];
};
typedef struct DMN_ProcessInfo DMN_ProcessInfo;
struct DMN_ProcessInfo
{
String8 name;
U32 pid;
};
////////////////////////////////
//~ rjf: Basic Type Functions (Helpers, Implemented Once)
//- rjf: handles
internal DMN_Handle dmn_handle_zero(void);
internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b);
//- rjf: trap chunk lists
internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap);
internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
//- rjf: handle lists
internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle);
internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list);
internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src);
//- rjf: event list building
internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list);
////////////////////////////////
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
internal U64 dmn_rip_from_thread(DMN_Handle thread);
internal U64 dmn_rsp_from_thread(DMN_Handle thread);
////////////////////////////////
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
internal void dmn_init(void);
////////////////////////////////
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
internal DMN_CtrlCtx *dmn_ctrl_begin(void);
internal void dmn_ctrl_exclusive_access_begin(void);
internal void dmn_ctrl_exclusive_access_end(void);
#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end())
internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options);
internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid);
internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code);
internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process);
internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls);
////////////////////////////////
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
internal void dmn_halt(U64 code, U64 user_data);
////////////////////////////////
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
//- rjf: run/memory/register counters
internal U64 dmn_run_gen(void);
internal U64 dmn_mem_gen(void);
internal U64 dmn_reg_gen(void);
//- rjf: non-blocking-control-thread access barriers
internal B32 dmn_access_open(void);
internal void dmn_access_close(void);
#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close())
//- rjf: processes
internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
//- rjf: threads
internal Architecture dmn_arch_from_thread(DMN_Handle handle);
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
//- rjf: system process listing
internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out);
internal void dmn_process_iter_end(DMN_ProcessIter *iter);
#endif // DEMON2_CORE_H
-10
View File
@@ -1,10 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "demon2_core.c"
#if OS_WINDOWS
# include "win32/demon2_core_win32.c"
#else
# error Demon layer backend not defined for this operating system.
#endif
-15
View File
@@ -1,15 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON2_INC_H
#define DEMON2_INC_H
#include "demon2_core.h"
#if OS_WINDOWS
# include "win32/demon2_core_win32.h"
#else
# error Demon layer backend not defined for this operating system.
#endif
#endif // DEMON2_INC_H
+2 -2
View File
@@ -2,11 +2,11 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Demon2 Pass Tasks
//~ rjf: Demon Pass Tasks
//
// [ ] TLS eval -> in-process-memory EXE info
// [ ] unwinding -> in-process-memory EXE info
// [x] solidify synchronization mechanisms for usage of demon2 layer
// [x] solidify synchronization mechanisms for usage of demon layer
// [x] TLS eval correctness
// [x] freezing thread while running -> soft-halt
+2 -2
View File
@@ -43,7 +43,7 @@
#include "regs/raddbgi/regs_raddbgi.h"
#include "type_graph/type_graph.h"
#include "dbgi/dbgi.h"
#include "demon2/demon2_inc.h"
#include "demon/demon_inc.h"
#include "eval/eval_inc.h"
#include "unwind/unwind.h"
#include "ctrl/ctrl_inc.h"
@@ -81,7 +81,7 @@
#include "regs/raddbgi/regs_raddbgi.c"
#include "type_graph/type_graph.c"
#include "dbgi/dbgi.c"
#include "demon2/demon2_inc.c"
#include "demon/demon_inc.c"
#include "eval/eval_inc.c"
#include "unwind/unwind.c"
#include "ctrl/ctrl_inc.c"
+2 -2
View File
@@ -43,7 +43,7 @@
#include "regs/raddbgi/regs_raddbgi.h"
#include "type_graph/type_graph.h"
#include "dbgi/dbgi.h"
#include "demon2/demon2_inc.h"
#include "demon/demon_inc.h"
#include "eval/eval_inc.h"
#include "unwind/unwind.h"
#include "ctrl/ctrl_inc.h"
@@ -71,7 +71,7 @@
#include "regs/raddbgi/regs_raddbgi.c"
#include "type_graph/type_graph.c"
#include "dbgi/dbgi.c"
#include "demon2/demon2_inc.c"
#include "demon/demon_inc.c"
#include "eval/eval_inc.c"
#include "unwind/unwind.c"
#include "ctrl/ctrl_inc.c"