initial upload

This commit is contained in:
Ryan Fleury
2024-01-10 19:53:18 -08:00
commit a42ec6aeff
308 changed files with 162362 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Tables
@table(name lower_name code default display_string)
CTRL_ExceptionCodeKindTable:
{
{Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" }
{Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" }
{Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" }
{Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" }
{Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" }
{Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" }
{Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" }
{Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" }
{Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" }
{Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" }
{Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" }
{Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" }
{Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" }
{Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" }
{Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" }
{Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" }
{Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" }
{Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" }
{Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" }
{Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" }
{Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" }
{Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" }
{Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" }
{Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" }
{Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" }
{Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" }
{Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" }
{Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" }
{Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" }
{Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" }
{Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" }
{Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" }
{Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" }
{Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" }
{Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" }
{Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" }
}
////////////////////////////////
//~ rjf: Generators
@table_gen_enum CTRL_ExceptionCodeKind:
{
`CTRL_ExceptionCodeKind_Null,`;
@expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`;
`CTRL_ExceptionCodeKind_COUNT`;
}
@table_gen_data(type:U32, fallback:0)
ctrl_exception_code_kind_code_table:
{
`0,`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`;
}
@table_gen_data(type:String8, fallback:`{0}`)
ctrl_exception_code_kind_display_string_table:
{
`{0},`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`;
}
@table_gen_data(type:String8, fallback:`{0}`)
ctrl_exception_code_kind_lowercase_code_string_table:
{
`{0},`;
@expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`;
}
@table_gen_data(type:B8, fallback:0)
ctrl_exception_code_kind_default_enable_table:
{
`0,`;
@expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`;
}
+3020
View File
File diff suppressed because it is too large Load Diff
+601
View File
@@ -0,0 +1,601 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CTRL_CORE_H
#define CTRL_CORE_H
////////////////////////////////
//~ rjf: ID Types
typedef U64 CTRL_MsgID;
typedef U64 CTRL_MachineID;
#define CTRL_MachineID_Client (1)
////////////////////////////////
//~ rjf: Handle Type
typedef struct CTRL_Handle CTRL_Handle;
struct CTRL_Handle
{
U64 u64[1];
};
////////////////////////////////
//~ rjf: Machine/Handle Pair Types
typedef struct CTRL_MachineIDHandlePair CTRL_MachineIDHandlePair;
struct CTRL_MachineIDHandlePair
{
CTRL_MachineID machine_id;
CTRL_Handle handle;
};
typedef struct CTRL_MachineIDHandlePairNode CTRL_MachineIDHandlePairNode;
struct CTRL_MachineIDHandlePairNode
{
CTRL_MachineIDHandlePairNode *next;
CTRL_MachineIDHandlePair v;
};
typedef struct CTRL_MachineIDHandlePairList CTRL_MachineIDHandlePairList;
struct CTRL_MachineIDHandlePairList
{
CTRL_MachineIDHandlePairNode *first;
CTRL_MachineIDHandlePairNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Trap Types
typedef U32 CTRL_TrapFlags;
enum
{
CTRL_TrapFlag_IgnoreStackPointerCheck = (1<<0),
CTRL_TrapFlag_SingleStepAfterHit = (1<<1),
CTRL_TrapFlag_SaveStackPointer = (1<<2),
CTRL_TrapFlag_BeginSpoofMode = (1<<3),
CTRL_TrapFlag_EndStepping = (1<<4),
};
typedef struct CTRL_Trap CTRL_Trap;
struct CTRL_Trap
{
CTRL_TrapFlags flags;
U64 vaddr;
};
typedef struct CTRL_TrapNode CTRL_TrapNode;
struct CTRL_TrapNode
{
CTRL_TrapNode *next;
CTRL_Trap v;
};
typedef struct CTRL_TrapList CTRL_TrapList;
struct CTRL_TrapList
{
CTRL_TrapNode *first;
CTRL_TrapNode *last;
U64 count;
};
typedef struct CTRL_Spoof CTRL_Spoof;
struct CTRL_Spoof
{
CTRL_Handle process;
U64 vaddr;
U64 new_ip_value;
};
////////////////////////////////
//~ rjf: User Breakpoint Types
typedef enum CTRL_UserBreakpointKind
{
CTRL_UserBreakpointKind_FileNameAndLineColNumber,
CTRL_UserBreakpointKind_SymbolNameAndOffset,
CTRL_UserBreakpointKind_VirtualAddress,
CTRL_UserBreakpointKind_COUNT
}
CTRL_UserBreakpointKind;
typedef struct CTRL_UserBreakpoint CTRL_UserBreakpoint;
struct CTRL_UserBreakpoint
{
CTRL_UserBreakpointKind kind;
String8 string;
TxtPt pt;
U64 u64;
String8 condition;
};
typedef struct CTRL_UserBreakpointNode CTRL_UserBreakpointNode;
struct CTRL_UserBreakpointNode
{
CTRL_UserBreakpointNode *next;
CTRL_UserBreakpoint v;
};
typedef struct CTRL_UserBreakpointList CTRL_UserBreakpointList;
struct CTRL_UserBreakpointList
{
CTRL_UserBreakpointNode *first;
CTRL_UserBreakpointNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Generated Code
#include "generated/ctrl.meta.h"
////////////////////////////////
//~ rjf: Message Types
typedef enum CTRL_MsgKind
{
CTRL_MsgKind_Null,
CTRL_MsgKind_LaunchAndHandshake,
CTRL_MsgKind_LaunchAndInit,
CTRL_MsgKind_Attach,
CTRL_MsgKind_Kill,
CTRL_MsgKind_Detach,
CTRL_MsgKind_Run,
CTRL_MsgKind_SingleStep,
CTRL_MsgKind_SetUserEntryPoints,
CTRL_MsgKind_COUNT,
}
CTRL_MsgKind;
typedef struct CTRL_Msg CTRL_Msg;
struct CTRL_Msg
{
CTRL_MsgKind kind;
CTRL_MsgID msg_id;
CTRL_MachineID machine_id;
CTRL_Handle entity;
CTRL_Handle parent;
U32 entity_id;
U32 exit_code;
B32 env_inherit;
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
String8 path;
String8List strings;
String8List cmd_line_string_list;
String8List env_string_list;
CTRL_TrapList traps;
CTRL_UserBreakpointList user_bps;
CTRL_MachineIDHandlePairList freeze_state_threads; // NOTE(rjf): can be frozen or unfrozen, depending on `freeze_state_is_frozen`
B32 freeze_state_is_frozen;
};
typedef struct CTRL_MsgNode CTRL_MsgNode;
struct CTRL_MsgNode
{
CTRL_MsgNode *next;
CTRL_Msg v;
};
typedef struct CTRL_MsgList CTRL_MsgList;
struct CTRL_MsgList
{
CTRL_MsgNode *first;
CTRL_MsgNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Event Types
typedef enum CTRL_EventKind
{
CTRL_EventKind_Null,
CTRL_EventKind_Error,
//- rjf: starts/stops
CTRL_EventKind_Started,
CTRL_EventKind_Stopped,
//- rjf: entity creation/deletion
CTRL_EventKind_NewProc,
CTRL_EventKind_NewThread,
CTRL_EventKind_NewModule,
CTRL_EventKind_EndProc,
CTRL_EventKind_EndThread,
CTRL_EventKind_EndModule,
//- rjf: debug strings
CTRL_EventKind_DebugString,
CTRL_EventKind_ThreadName,
//- rjf: memory
CTRL_EventKind_MemReserve,
CTRL_EventKind_MemCommit,
CTRL_EventKind_MemDecommit,
CTRL_EventKind_MemRelease,
//- rjf: ctrl requests
CTRL_EventKind_LaunchAndHandshakeDone,
CTRL_EventKind_LaunchAndInitDone,
CTRL_EventKind_AttachDone,
CTRL_EventKind_KillDone,
CTRL_EventKind_DetachDone,
CTRL_EventKind_COUNT
}
CTRL_EventKind;
typedef enum CTRL_EventCause
{
CTRL_EventCause_Null,
CTRL_EventCause_Error,
CTRL_EventCause_Finished,
CTRL_EventCause_UserBreakpoint,
CTRL_EventCause_InterruptedByTrap,
CTRL_EventCause_InterruptedByException,
CTRL_EventCause_InterruptedByHalt,
CTRL_EventCause_COUNT
}
CTRL_EventCause;
typedef enum CTRL_ExceptionKind
{
CTRL_ExceptionKind_Null,
CTRL_ExceptionKind_MemoryRead,
CTRL_ExceptionKind_MemoryWrite,
CTRL_ExceptionKind_MemoryExecute,
CTRL_ExceptionKind_CppThrow,
CTRL_ExceptionKind_COUNT
}
CTRL_ExceptionKind;
typedef struct CTRL_Event CTRL_Event;
struct CTRL_Event
{
CTRL_EventKind kind;
CTRL_EventCause cause;
CTRL_ExceptionKind exception_kind;
CTRL_MsgID msg_id;
CTRL_MachineID machine_id;
CTRL_Handle entity;
CTRL_Handle parent;
Architecture arch;
U64 u64_code;
U32 entity_id;
Rng1U64 vaddr_rng;
U64 rip_vaddr;
U64 stack_base;
U64 tls_root;
U32 exception_code;
String8 string;
};
typedef struct CTRL_EventNode CTRL_EventNode;
struct CTRL_EventNode
{
CTRL_EventNode *next;
CTRL_Event v;
};
typedef struct CTRL_EventList CTRL_EventList;
struct CTRL_EventList
{
CTRL_EventNode *first;
CTRL_EventNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Process Memory Cache Types
// NOTE(rjf):
//
// Process memory is cached with a 5-level page table. Each level has 256
// slots, and is indexed into with 8 bits. Each index is extracted from a
// virtual address in the following manner:
//
// |1------||2------||3------||4------||5------||byte-n-page|
// xxxxxxxx xxxx0000 00000000 00000000 00000000 00000000 0000xxxx xxxxxxxx
//
// The top 12 bits are not used (a 52-bit address space is supported at most).
// The next 8 most-significant-bits are used to index into the level 1 table.
// The next 8 are used to index into the level 2. Then the level 3. Then the
// level 4. At the level 4 table, instead of pointing to other tables, each
// slot points at the base address of a cached 4KB page. The next 8 bits are
// used to index into that table. The final 12 bits in the address are used
// to refer to unique bytes within each page.
typedef struct CTRL_ProcessMemoryCacheNode4 CTRL_ProcessMemoryCacheNode4;
struct CTRL_ProcessMemoryCacheNode4
{
U64 page_memgen_idxs[256];
U128 page_hashes[256];
};
typedef struct CTRL_ProcessMemoryCacheNode3 CTRL_ProcessMemoryCacheNode3;
struct CTRL_ProcessMemoryCacheNode3
{
CTRL_ProcessMemoryCacheNode4 *children[256];
};
typedef struct CTRL_ProcessMemoryCacheNode2 CTRL_ProcessMemoryCacheNode2;
struct CTRL_ProcessMemoryCacheNode2
{
CTRL_ProcessMemoryCacheNode3 *children[256];
};
typedef struct CTRL_ProcessMemoryCacheNode1 CTRL_ProcessMemoryCacheNode1;
struct CTRL_ProcessMemoryCacheNode1
{
CTRL_ProcessMemoryCacheNode2 *children[256];
};
typedef struct CTRL_ProcessMemoryRangeHashNode CTRL_ProcessMemoryRangeHashNode;
struct CTRL_ProcessMemoryRangeHashNode
{
CTRL_ProcessMemoryRangeHashNode *next;
Rng1U64 vaddr_range;
B32 zero_terminated;
U128 hash;
U64 memgen_idx;
B32 is_taken;
};
typedef struct CTRL_ProcessMemoryRangeHashSlot CTRL_ProcessMemoryRangeHashSlot;
struct CTRL_ProcessMemoryRangeHashSlot
{
CTRL_ProcessMemoryRangeHashNode *first;
CTRL_ProcessMemoryRangeHashNode *last;
};
typedef struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode;
struct CTRL_ProcessMemoryCacheNode
{
CTRL_ProcessMemoryCacheNode *next;
CTRL_ProcessMemoryCacheNode *prev;
Arena *arena;
CTRL_MachineID machine_id;
CTRL_Handle process;
CTRL_ProcessMemoryCacheNode1 *children[256];
U64 range_hash_slots_count;
CTRL_ProcessMemoryRangeHashSlot *range_hash_slots;
};
typedef struct CTRL_ProcessMemoryCacheSlot CTRL_ProcessMemoryCacheSlot;
struct CTRL_ProcessMemoryCacheSlot
{
CTRL_ProcessMemoryCacheNode *first;
CTRL_ProcessMemoryCacheNode *last;
};
typedef struct CTRL_ProcessMemoryCacheStripe CTRL_ProcessMemoryCacheStripe;
struct CTRL_ProcessMemoryCacheStripe
{
OS_Handle rw_mutex;
};
typedef struct CTRL_ProcessMemoryCache CTRL_ProcessMemoryCache;
struct CTRL_ProcessMemoryCache
{
U64 slots_count;
CTRL_ProcessMemoryCacheSlot *slots;
U64 stripes_count;
CTRL_ProcessMemoryCacheStripe *stripes;
};
////////////////////////////////
//~ rjf: Wakeup Hook Function Types
#define CTRL_WAKEUP_FUNCTION_DEF(name) void name(void)
typedef CTRL_WAKEUP_FUNCTION_DEF(CTRL_WakeupFunctionType);
////////////////////////////////
//~ rjf: Main State Types
typedef struct CTRL_State CTRL_State;
struct CTRL_State
{
Arena *arena;
CTRL_WakeupFunctionType *wakeup_hook;
U64 run_idx;
U64 memgen_idx;
// rjf: name -> register/alias hash tables for eval
EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT];
EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT];
// rjf: process memory cache
CTRL_ProcessMemoryCache process_memory_cache;
// rjf: user -> ctrl msg ring buffer
U64 u2c_ring_size;
U8 *u2c_ring_base;
U64 u2c_ring_write_pos;
U64 u2c_ring_read_pos;
OS_Handle u2c_ring_mutex;
OS_Handle u2c_ring_cv;
// rjf: ctrl -> user event ring buffer
U64 c2u_ring_size;
U8 *c2u_ring_base;
U64 c2u_ring_write_pos;
U64 c2u_ring_read_pos;
OS_Handle c2u_ring_mutex;
OS_Handle c2u_ring_cv;
// rjf: ctrl thread state
OS_Handle ctrl_thread;
Arena *demon_event_arena;
DEMON_EventNode *first_demon_event_node;
DEMON_EventNode *last_demon_event_node;
DEMON_EventNode *free_demon_event_node;
Arena *user_entry_point_arena;
String8List user_entry_points;
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
U64 process_counter;
// rjf: user -> memstream ring buffer
U64 u2ms_ring_size;
U8 *u2ms_ring_base;
U64 u2ms_ring_write_pos;
U64 u2ms_ring_read_pos;
OS_Handle u2ms_ring_mutex;
OS_Handle u2ms_ring_cv;
// rjf: memory stream threads
U64 ms_thread_count;
OS_Handle *ms_threads;
};
////////////////////////////////
//~ rjf: Globals
global CTRL_State *ctrl_state = 0;
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void ctrl_init(CTRL_WakeupFunctionType *wakeup_hook);
////////////////////////////////
//~ rjf: Basic Type Functions
internal U64 ctrl_hash_from_string(String8 string);
internal CTRL_EventCause ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind);
internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b);
////////////////////////////////
//~ rjf: Ctrl <-> Demon Handle Translation Functions
internal DEMON_Handle ctrl_demon_handle_from_ctrl(CTRL_Handle h);
internal CTRL_Handle ctrl_handle_from_demon(DEMON_Handle h);
////////////////////////////////
//~ rjf: Machine/Handle Pair Type Functions
internal void ctrl_machine_id_handle_pair_list_push(Arena *arena, CTRL_MachineIDHandlePairList *list, CTRL_MachineIDHandlePair *pair);
internal CTRL_MachineIDHandlePairList ctrl_machine_id_handle_pair_list_copy(Arena *arena, CTRL_MachineIDHandlePairList *src);
////////////////////////////////
//~ rjf: Trap Type Functions
internal void ctrl_trap_list_push(Arena *arena, CTRL_TrapList *list, CTRL_Trap *trap);
internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src);
////////////////////////////////
//~ rjf: User Breakpoint Type Functions
internal void ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp);
internal CTRL_UserBreakpointList ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src);
internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out);
internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out);
////////////////////////////////
//~ rjf: Message Type Functions
//- rjf: deep copying
internal void ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src);
//- rjf: list building
internal CTRL_Msg *ctrl_msg_list_push(Arena *arena, CTRL_MsgList *list);
//- rjf: serialization
internal String8 ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs);
internal CTRL_MsgList ctrl_msg_list_from_serialized_string(Arena *arena, String8 string);
////////////////////////////////
//~ rjf: Event Type Functions
//- rjf: list building
internal CTRL_Event *ctrl_event_list_push(Arena *arena, CTRL_EventList *list);
internal void ctrl_event_list_concat_in_place(CTRL_EventList *dst, CTRL_EventList *to_push);
//- rjf: serialization
internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event);
internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string);
////////////////////////////////
//~ rjf: Shared Functions
//- rjf: run index
internal U64 ctrl_run_idx(void);
internal U64 ctrl_memgen_idx(void);
//- rjf: halt everything
internal void ctrl_halt(void);
//- rjf: exe -> dbg path mapping
internal String8 ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path);
internal String8 ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path);
internal String8 ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path);
internal String8 ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path);
//- rjf: handle -> arch
internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle);
//- rjf: process memory reading/writing
internal U64 ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst);
internal String8 ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range);
internal String8 ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit);
internal B32 ctrl_process_write_data(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, String8 data);
internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated);
//- rjf: register reading/writing
internal void *ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread);
internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block);
internal U64 ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread);
internal B32 ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip);
internal U64 ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread);
//- rjf: name -> register/alias hash tables, for eval
internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch);
internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch);
////////////////////////////////
//~ rjf: User -> Ctrl Communication
internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us);
internal CTRL_MsgList ctrl_u2c_pop_msgs(Arena *arena);
////////////////////////////////
//~ rjf: Ctrl -> User Communication
internal void ctrl_c2u_push_events(CTRL_EventList *events);
internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena);
////////////////////////////////
//~ rjf: User -> Memory Stream Communication
internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us);
internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
////////////////////////////////
//~ rjf: Control-Thread-Only Functions
//- rjf: entry point
internal void ctrl_thread__entry_point(void *p);
//- rjf: attached process running/event gathering
internal DEMON_Event *ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof);
//- rjf: eval helpers
internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size);
//- rjf: msg kind implementations
internal void ctrl_thread__launch_and_handshake(CTRL_Msg *msg);
internal void ctrl_thread__launch_and_init(CTRL_Msg *msg);
internal void ctrl_thread__attach(CTRL_Msg *msg);
internal void ctrl_thread__kill(CTRL_Msg *msg);
internal void ctrl_thread__detach(CTRL_Msg *msg);
internal void ctrl_thread__run(CTRL_Msg *msg);
internal void ctrl_thread__single_step(CTRL_Msg *msg);
////////////////////////////////
//~ rjf: Memory-Stream-Thread-Only Functions
//- rjf: entry point
internal void ctrl_mem_stream_thread__entry_point(void *p);
#endif //CTRL_CORE_H
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "ctrl_core.c"
+77
View File
@@ -0,0 +1,77 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CTRL_INC_H
#define CTRL_INC_H
////////////////////////////////
//~ NOTE(rjf): Control Layer Overview (2023/8/29)
//
// This layer's purpose is to provide access to the asynchronously-running, low
// level parts of a debugger, running on the debugger client. This primarily
// consists of process control, using the Demon layer (the lower level
// abstraction layer for process control, across multiple OSes), but including
// higher-level concepts, like stepping, breakpoint resolution, conditional
// breakpoint evaluation, and so on. Right now, this just includes process
// control *local to the debugger client machine*. But in the future, this can
// also include communication to multiple target machines, all running their
// own process controller, using the Demon layer.
//
// This part of a debugger must run asynchronously to prevent blocking the UI -
// ideally our debugger is designed such that, if targets are running, the
// debugger frontend is still usable for a variety of purposes. So, in short,
// the asynchronously-running "control thread", implemented by this layer, is
// tasked with communicating with a separately executing "user thread". This
// communication happens in two directions - `user -> ctrl`, and the reverse,
// `ctrl -> user`.
//
// In the case of `user -> ctrl` communication, this is done with a ring buffer
// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages
// include commands like: launching targets, attaching to targets, killing
// targets, detaching from targets, stepping/running, or single stepping.
//
// In the case of `ctrl -> user` communication, this is done with a ring buffer
// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events
// include information about what happened during the execution of targets -
// including: process/module/thread creation, process/module/thread deletion,
// debug strings, thread name events, memory allocation events, and stop events
// (where stops can be caused by: user breakpoints, traps set for stepping,
// exceptions, halts, or errors).
//
// The various stepping algorithms are implemented with two concepts: (a) the
// "trap net", and (b) "spoofs".
//
// A "trap net" is a term which refers to a set of addresses paired with a set
// of behavioral flags. Before targets run, trap instructions are written to
// these addresses. After targets stop, these addresses are reset to their
// original bytes. These trap instructions cause the debugger's targets to
// stop executing, and based on which behavioral flags are associated with
// the instruction causing the stop, the control thread may adjust parameters
// used for running, then continue execution, or it will not resume target
// execution, and will report stopped events. These behavioral flags can
// include: single-stepping the stopped thread to execute the instruction at
// the trap location, saving a stack pointer "check value" (where this check
// value is compared against when making decisions about whether to continue
// running or not), and so on. It's complicated to unpack why exactly these
// behaviors are useful, but the TL;DR of it is that they are used for a
// variety of stepping behaviors. For example, when doing a "step into" step,
// a `call` instruction can have a trap set at it, and will be marked with
// a "single-step-after" trap flag, as well as the "end stepping" trap flag,
// such that the step operation will complete after the `call` has executed.
//
// A "spoof" is a feature the control layer uses to detect when some thread
// returns from a particular sub-callstack. This is useful when implementing
// "step over" in functions that may be recursive. In short, unlike a trap,
// which writes a trap instruction (like `int3`) into an instruction stream,
// a spoof overwrites a *return address* on some thread's *stack*. This return
// address is not a valid address for executing code -- it is simply a value
// that the debugger can recognize, such that it is notified when the thread
// returns from some level in a callstack. When the thread exits some function,
// it will return to the "spoofed" address, and it will immediately hit an
// exception, because the spoofed address will not be a valid address for
// code execution. At that point, the debugger can move the thread back to
// the pre-spoof return address, and resume execution.
#include "ctrl_core.h"
#endif //CTRL_INC_H
+5
View File
@@ -0,0 +1,5 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
+216
View File
@@ -0,0 +1,216 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
#ifndef CTRL_META_H
#define CTRL_META_H
typedef enum CTRL_ExceptionCodeKind
{
CTRL_ExceptionCodeKind_Null,
CTRL_ExceptionCodeKind_Win32CtrlC,
CTRL_ExceptionCodeKind_Win32CtrlBreak,
CTRL_ExceptionCodeKind_Win32WinRTOriginateError,
CTRL_ExceptionCodeKind_Win32WinRTTransformError,
CTRL_ExceptionCodeKind_Win32RPCCallCancelled,
CTRL_ExceptionCodeKind_Win32DatatypeMisalignment,
CTRL_ExceptionCodeKind_Win32AccessViolation,
CTRL_ExceptionCodeKind_Win32InPageError,
CTRL_ExceptionCodeKind_Win32InvalidHandle,
CTRL_ExceptionCodeKind_Win32NotEnoughQuota,
CTRL_ExceptionCodeKind_Win32IllegalInstruction,
CTRL_ExceptionCodeKind_Win32CannotContinueException,
CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition,
CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded,
CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand,
CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero,
CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult,
CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation,
CTRL_ExceptionCodeKind_Win32FloatingPointOverflow,
CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck,
CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow,
CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero,
CTRL_ExceptionCodeKind_Win32IntegerOverflow,
CTRL_ExceptionCodeKind_Win32PrivilegedInstruction,
CTRL_ExceptionCodeKind_Win32StackOverflow,
CTRL_ExceptionCodeKind_Win32UnableToLocateDLL,
CTRL_ExceptionCodeKind_Win32OrdinalNotFound,
CTRL_ExceptionCodeKind_Win32EntryPointNotFound,
CTRL_ExceptionCodeKind_Win32DLLInitializationFailed,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults,
CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps,
CTRL_ExceptionCodeKind_Win32AssertionFailed,
CTRL_ExceptionCodeKind_Win32ModuleNotFound,
CTRL_ExceptionCodeKind_Win32ProcedureNotFound,
CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected,
CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation,
CTRL_ExceptionCodeKind_COUNT
} CTRL_ExceptionCodeKind;
U32 ctrl_exception_code_kind_code_table[] =
{
0,
0x40010005,
0x40010008,
0x40080201,
0x40080202,
0x0000071a,
0x80000002,
0xc0000005,
0xc0000006,
0xc0000008,
0xc0000017,
0xc000001d,
0xc0000025,
0xc0000026,
0xc000008c,
0xc000008d,
0xc000008e,
0xc000008f,
0xc0000090,
0xc0000091,
0xc0000092,
0xc0000093,
0xc0000094,
0xc0000095,
0xc0000096,
0xc00000fd,
0xc0000135,
0xc0000138,
0xc0000139,
0xc0000142,
0xc00002b4,
0xc00002b5,
0xc0000420,
0xc06d007e,
0xc06d007f,
0xe073616e,
0xe0736171,
};
String8 ctrl_exception_code_kind_display_string_table[] =
{
{0},
str8_lit_comp("(Win32) Control-C"),
str8_lit_comp("(Win32) Control-Break"),
str8_lit_comp("(Win32) WinRT Originate Error"),
str8_lit_comp("(Win32) WinRT Transform Error"),
str8_lit_comp("(Win32) RPC Call Cancelled"),
str8_lit_comp("(Win32) Data Type Misalignment"),
str8_lit_comp("(Win32) Access Violation"),
str8_lit_comp("(Win32) In Page Error"),
str8_lit_comp("(Win32) Invalid Handle Specified"),
str8_lit_comp("(Win32) Not Enough Quota"),
str8_lit_comp("(Win32) Illegal Instruction"),
str8_lit_comp("(Win32) Cannot Continue From Exception"),
str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"),
str8_lit_comp("(Win32) Array Bounds Exceeded"),
str8_lit_comp("(Win32) Floating-Point Denormal Operand"),
str8_lit_comp("(Win32) Floating-Point Division By Zero"),
str8_lit_comp("(Win32) Floating-Point Inexact Result"),
str8_lit_comp("(Win32) Floating-Point Invalid Operation"),
str8_lit_comp("(Win32) Floating-Point Overflow"),
str8_lit_comp("(Win32) Floating-Point Stack Check"),
str8_lit_comp("(Win32) Floating-Point Underflow"),
str8_lit_comp("(Win32) Integer Division By Zero"),
str8_lit_comp("(Win32) Integer Overflow"),
str8_lit_comp("(Win32) Privileged Instruction"),
str8_lit_comp("(Win32) Stack Overflow"),
str8_lit_comp("(Win32) Unable To Locate DLL"),
str8_lit_comp("(Win32) Ordinal Not Found"),
str8_lit_comp("(Win32) Entry Point Not Found"),
str8_lit_comp("(Win32) DLL Initialization Failed"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"),
str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"),
str8_lit_comp("(Win32) Assertion Failed"),
str8_lit_comp("(Win32) Module Not Found"),
str8_lit_comp("(Win32) Procedure Not Found"),
str8_lit_comp("(Win32) Sanitizer Error Detected"),
str8_lit_comp("(Win32) Sanitizer Raw Access Violation"),
};
String8 ctrl_exception_code_kind_lowercase_code_string_table[] =
{
{0},
str8_lit_comp("win32_ctrl_c"),
str8_lit_comp("win32_ctrl_break"),
str8_lit_comp("win32_win_rt_originate_error"),
str8_lit_comp("win32_win_rt_transform_error"),
str8_lit_comp("win32_rpc_call_cancelled"),
str8_lit_comp("win32_datatype_misalignment"),
str8_lit_comp("win32_access_violation"),
str8_lit_comp("win32_in_page_error"),
str8_lit_comp("win32_invalid_handle"),
str8_lit_comp("win32_not_enough_quota"),
str8_lit_comp("win32_illegal_instruction"),
str8_lit_comp("win32_cannot_continue_exception"),
str8_lit_comp("win32_invalid_exception_disposition"),
str8_lit_comp("win32_array_bounds_exceeded"),
str8_lit_comp("win32_floating_point_denormal_operand"),
str8_lit_comp("win32_floating_point_division_by_zero"),
str8_lit_comp("win32_floating_point_inexact_result"),
str8_lit_comp("win32_floating_point_invalid_operation"),
str8_lit_comp("win32_floating_point_overflow"),
str8_lit_comp("win32_floating_point_stack_check"),
str8_lit_comp("win32_floating_point_underflow"),
str8_lit_comp("win32_integer_division_by_zero"),
str8_lit_comp("win32_integer_overflow"),
str8_lit_comp("win32_privileged_instruction"),
str8_lit_comp("win32_stack_overflow"),
str8_lit_comp("win32_unable_to_locate_dll"),
str8_lit_comp("win32_ordinal_not_found"),
str8_lit_comp("win32_entry_point_not_found"),
str8_lit_comp("win32_dll_initialization_failed"),
str8_lit_comp("win32_floating_point_sse_multiple_faults"),
str8_lit_comp("win32_floating_point_sse_multiple_traps"),
str8_lit_comp("win32_assertion_failed"),
str8_lit_comp("win32_module_not_found"),
str8_lit_comp("win32_procedure_not_found"),
str8_lit_comp("win32_sanitizer_error_detected"),
str8_lit_comp("win32_sanitizer_raw_access_violation"),
};
B8 ctrl_exception_code_kind_default_enable_table[] =
{
0,
1,
1,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
};
#endif // CTRL_META_H