// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef DEMON_CORE_H #define DEMON_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]; }; //////////////////////////////// //~ Dynamic Linker Types typedef U32 DMN_TlsModel; enum { DMN_TlsModel_Null, DMN_TlsModel_WinodwsNt, DMN_TlsModel_Gnu }; //////////////////////////////// //~ 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/demon.meta.h" //////////////////////////////// //~ rjf: Event Types typedef struct DMN_ModuleInfo DMN_ModuleInfo; struct DMN_ModuleInfo { // rjf: image architecture Arch arch; // rjf: image virtual size U64 vsize; // rjf: entry point U64 entry_point_voff; // rjf: module path String8 module_path; // rjf: debug info key String8 debug_info_path; Guid debug_info_guid; U64 debug_info_timestamp; U64 debug_info_age; // rjf: thread-local storage info U64 tls_index; U64 tls_offset; // rjf: unwinding info Rng1U64 pe_intel_pdatas_vaddr_range; Rng1U64 eh_frame_header_vaddr_range; // rjf: special raddbg data Rng1U64 raddbg_info_voff_range; U64 raddbg_is_attached_marker_voff; }; typedef struct DMN_Event DMN_Event; struct DMN_Event { // rjf: categories DMN_EventKind kind; DMN_ErrorKind error_kind; DMN_MemoryEventKind memory_kind; DMN_ExceptionKind exception_kind; // rjf: entities DMN_Handle process; DMN_Handle thread; DMN_Handle module; // rjf: general event properties Arch arch; U64 address; U64 size; String8 string; U32 code; // code -> exception code (signo on Linux), pid/tid U32 flags; // DMN_TrapFlags, if `DMN_EventKind_SetBreakpoint` U64 instruction_pointer; U64 stack_pointer; U64 user_data; B32 exception_repeated; // rjf: process info DMN_TlsModel tls_model; // rjf: module info DMN_ModuleInfo *module_info; // rjf: thread info U64 tls_root_vaddr; }; 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 U32 DMN_TrapFlags; enum { DMN_TrapFlag_BreakOnWrite = (1<<0), DMN_TrapFlag_BreakOnRead = (1<<1), DMN_TrapFlag_BreakOnExecute = (1<<2), }; typedef struct DMN_Trap DMN_Trap; struct DMN_Trap { DMN_Handle process; U64 vaddr; U64 id; DMN_TrapFlags flags; U32 size; }; 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 priority_thread; DMN_Handle single_step_thread; DMN_Handle *run_entities; U64 run_entity_count; DMN_TrapChunkList traps; B8 ignore_previous_exception; B8 run_entities_are_unfrozen; B8 run_entities_are_processes; }; //////////////////////////////// //~ 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: Globals read_only global DMN_ModuleInfo dmn_module_info_nil = {0}; //////////////////////////////// //~ 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: Process Reading Helper Functions (Helpers, Implemented Once) internal String8 dmn_data_from_process_vaddr_range(Arena *arena, DMN_Handle process, Rng1U64 vrange); //////////////////////////////// //~ 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, ProcessLaunchParams *params); 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: 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_memory_reserve(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, AccessFlags flags); internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); //- rjf: threads 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); internal B32 dmn_thread_get_module_tls_vaddr(DMN_Handle thread, DMN_Handle module, U64 *vaddr_out); //- 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