This commit is contained in:
Ryan Fleury
2024-03-22 16:31:05 -07:00
23 changed files with 2274 additions and 1521 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ commands =
{
.rjf_f1 =
{
.win = "build ryan_scratch",
.win = "build raddbg telemetry",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
+1269 -909
View File
File diff suppressed because it is too large Load Diff
+218 -101
View File
@@ -10,16 +10,7 @@
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];
};
#define CTRL_MachineID_Local (1)
////////////////////////////////
//~ rjf: Machine/Handle Pair Types
@@ -28,7 +19,7 @@ typedef struct CTRL_MachineIDHandlePair CTRL_MachineIDHandlePair;
struct CTRL_MachineIDHandlePair
{
CTRL_MachineID machine_id;
CTRL_Handle handle;
DMN_Handle handle;
};
typedef struct CTRL_MachineIDHandlePairNode CTRL_MachineIDHandlePairNode;
@@ -46,6 +37,71 @@ struct CTRL_MachineIDHandlePairList
U64 count;
};
////////////////////////////////
//~ rjf: Entity Types
typedef enum CTRL_EntityKind
{
CTRL_EntityKind_Null,
CTRL_EntityKind_Root,
CTRL_EntityKind_Machine,
CTRL_EntityKind_Process,
CTRL_EntityKind_Thread,
CTRL_EntityKind_Module,
CTRL_EntityKind_COUNT
}
CTRL_EntityKind;
typedef struct CTRL_Entity CTRL_Entity;
struct CTRL_Entity
{
CTRL_Entity *first;
CTRL_Entity *last;
CTRL_Entity *next;
CTRL_Entity *prev;
CTRL_Entity *parent;
CTRL_EntityKind kind;
Architecture arch;
CTRL_MachineID machine_id;
DMN_Handle handle;
Rng1U64 vaddr_range;
String8 string;
};
typedef struct CTRL_EntityHashNode CTRL_EntityHashNode;
struct CTRL_EntityHashNode
{
CTRL_EntityHashNode *next;
CTRL_EntityHashNode *prev;
CTRL_Entity *entity;
};
typedef struct CTRL_EntityHashSlot CTRL_EntityHashSlot;
struct CTRL_EntityHashSlot
{
CTRL_EntityHashNode *first;
CTRL_EntityHashNode *last;
};
typedef struct CTRL_EntityStringChunkNode CTRL_EntityStringChunkNode;
struct CTRL_EntityStringChunkNode
{
CTRL_EntityStringChunkNode *next;
U64 size;
};
typedef struct CTRL_EntityStore CTRL_EntityStore;
struct CTRL_EntityStore
{
Arena *arena;
CTRL_Entity *root;
CTRL_Entity *free;
CTRL_EntityHashSlot *hash_slots;
CTRL_EntityHashNode *hash_node_free;
U64 hash_slots_count;
CTRL_EntityStringChunkNode *free_string_chunks[8];
};
////////////////////////////////
//~ rjf: Unwind Types
@@ -105,8 +161,8 @@ struct CTRL_TrapList
typedef struct CTRL_Spoof CTRL_Spoof;
struct CTRL_Spoof
{
CTRL_Handle process;
CTRL_Handle thread;
DMN_Handle process;
DMN_Handle thread;
U64 vaddr;
U64 new_ip_value;
};
@@ -177,8 +233,8 @@ struct CTRL_Msg
CTRL_MsgKind kind;
CTRL_MsgID msg_id;
CTRL_MachineID machine_id;
CTRL_Handle entity;
CTRL_Handle parent;
DMN_Handle entity;
DMN_Handle parent;
U32 entity_id;
U32 exit_code;
B32 env_inherit;
@@ -281,8 +337,8 @@ struct CTRL_Event
CTRL_ExceptionKind exception_kind;
CTRL_MsgID msg_id;
CTRL_MachineID machine_id;
CTRL_Handle entity;
CTRL_Handle parent;
DMN_Handle entity;
DMN_Handle parent;
Architecture arch;
U64 u64_code;
U32 entity_id;
@@ -320,7 +376,8 @@ struct CTRL_ProcessMemoryRangeHashNode
B32 zero_terminated;
Rng1U64 vaddr_range_clamped;
U128 hash;
U64 memgen_idx;
U64 mem_gen;
U64 last_time_requested_us;
B32 is_taken;
};
@@ -338,7 +395,7 @@ struct CTRL_ProcessMemoryCacheNode
CTRL_ProcessMemoryCacheNode *prev;
Arena *arena;
CTRL_MachineID machine_id;
CTRL_Handle process;
DMN_Handle process;
U64 range_hash_slots_count;
CTRL_ProcessMemoryRangeHashSlot *range_hash_slots;
};
@@ -372,6 +429,47 @@ struct CTRL_ProcessMemorySlice
String8 data;
U64 *byte_bad_flags;
U64 *byte_changed_flags;
B32 stale;
B32 any_byte_bad;
B32 any_byte_changed;
};
////////////////////////////////
//~ rjf: Thread Register Cache Types
typedef struct CTRL_ThreadRegCacheNode CTRL_ThreadRegCacheNode;
struct CTRL_ThreadRegCacheNode
{
CTRL_ThreadRegCacheNode *next;
CTRL_ThreadRegCacheNode *prev;
CTRL_MachineID machine_id;
DMN_Handle thread;
U64 block_size;
void *block;
U64 reg_gen;
};
typedef struct CTRL_ThreadRegCacheSlot CTRL_ThreadRegCacheSlot;
struct CTRL_ThreadRegCacheSlot
{
CTRL_ThreadRegCacheNode *first;
CTRL_ThreadRegCacheNode *last;
};
typedef struct CTRL_ThreadRegCacheStripe CTRL_ThreadRegCacheStripe;
struct CTRL_ThreadRegCacheStripe
{
Arena *arena;
OS_Handle rw_mutex;
};
typedef struct CTRL_ThreadRegCache CTRL_ThreadRegCache;
struct CTRL_ThreadRegCache
{
U64 slots_count;
CTRL_ThreadRegCacheSlot *slots;
U64 stripes_count;
CTRL_ThreadRegCacheStripe *stripes;
};
////////////////////////////////
@@ -388,16 +486,14 @@ struct CTRL_State
{
Arena *arena;
CTRL_WakeupFunctionType *wakeup_hook;
U64 run_idx;
U64 memgen_idx;
U64 reggen_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
// rjf: caches
CTRL_ProcessMemoryCache process_memory_cache;
CTRL_ThreadRegCache thread_reg_cache;
// rjf: user -> ctrl msg ring buffer
U64 u2c_ring_size;
@@ -417,10 +513,11 @@ struct CTRL_State
// 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;
CTRL_EntityStore *ctrl_thread_entity_store;
Arena *dmn_event_arena;
DMN_EventNode *first_dmn_event_node;
DMN_EventNode *last_dmn_event_node;
DMN_EventNode *free_dmn_event_node;
Arena *user_entry_point_arena;
String8List user_entry_points;
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
@@ -443,29 +540,21 @@ struct CTRL_State
//~ rjf: Globals
global CTRL_State *ctrl_state = 0;
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void ctrl_init(void);
////////////////////////////////
//~ rjf: Wakeup Callback Registration
internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook);
read_only global CTRL_Entity ctrl_entity_nil =
{
&ctrl_entity_nil,
&ctrl_entity_nil,
&ctrl_entity_nil,
&ctrl_entity_nil,
&ctrl_entity_nil,
};
////////////////////////////////
//~ 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);
internal U64 ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle);
internal CTRL_EventCause ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind);
////////////////////////////////
//~ rjf: Machine/Handle Pair Type Functions
@@ -484,8 +573,6 @@ internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src);
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
@@ -512,97 +599,127 @@ internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *eve
internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string);
////////////////////////////////
//~ rjf: Shared Functions
//~ rjf: Entity Type Functions
//- rjf: run index
internal U64 ctrl_run_idx(void);
internal U64 ctrl_memgen_idx(void);
internal U64 ctrl_reggen_idx(void);
//- rjf: cache creation/destruction
internal CTRL_EntityStore *ctrl_entity_store_alloc(void);
internal void ctrl_entity_store_release(CTRL_EntityStore *store);
//- rjf: halt everything
internal void ctrl_halt(void);
//- rjf: string allocation/deletion
internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string);
internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string);
//- 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: entity construction/deletion
internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Architecture arch, CTRL_MachineID machine_id, DMN_Handle handle);
internal void ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity);
//- rjf: handle -> arch
internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle);
//- rjf: entity equipment
internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string);
//- rjf: process memory reading/writing
internal U64 ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst);
internal B32 ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src);
//- rjf: entity store lookups
internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle);
//- rjf: applying events to entity caches
internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list);
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void ctrl_init(void);
////////////////////////////////
//~ rjf: Wakeup Callback Registration
internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook);
////////////////////////////////
//~ rjf: Process Memory Functions
//- rjf: process memory cache interaction
internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated);
internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us);
internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated);
internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us);
//- rjf: process memory cache reading helpers
internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, U64 endt_us);
internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us);
internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us);
internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 endt_us);
//- 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: process memory writing
internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src);
//- rjf: process * vaddr -> module
internal CTRL_Handle ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr);
////////////////////////////////
//~ rjf: Thread Register Functions
//- rjf: unwinding
internal CTRL_Unwind ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread);
//- rjf: thread register cache reading
internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread);
internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread);
internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread);
//- rjf: thread register writing
internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block);
////////////////////////////////
//~ rjf: Unwinding Functions
internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us);
////////////////////////////////
//~ rjf: Halting All Attached Processes
internal void ctrl_halt(void);
////////////////////////////////
//~ rjf: Shared Accessor Functions
//- rjf: generation counters
internal U64 ctrl_run_gen(void);
internal U64 ctrl_mem_gen(void);
internal U64 ctrl_reg_gen(void);
//- 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
//~ rjf: Control-Thread Functions
//- rjf: user -> control thread 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
//- rjf: control -> user thread 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: breakpoint resolution
internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out);
internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out);
//- 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);
internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_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);
internal void ctrl_thread__launch_and_handshake(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__launch_and_init(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
////////////////////////////////
//~ rjf: Memory-Stream-Thread-Only Functions
//~ rjf: Memory-Stream Thread Functions
//- rjf: user -> memory stream communication
internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us);
internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
//- rjf: entry point
internal void ctrl_mem_stream_thread__entry_point(void *p);
#endif //CTRL_CORE_H
#endif // CTRL_CORE_H
+1 -1
View File
@@ -74,4 +74,4 @@
#include "ctrl_core.h"
#endif //CTRL_INC_H
#endif // CTRL_INC_H
+8 -6
View File
@@ -179,7 +179,7 @@ dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_coun
//- rjf: opening handles & correllation with module
internal DASM_Handle
dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range)
dasm_handle_from_ctrl_process_range_arch(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range, Architecture arch)
{
DASM_Handle result = {0};
if(machine != 0 && process.u64[0] != 0)
@@ -195,8 +195,9 @@ dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process,
for(DASM_Entity *e = slot->first; e != 0; e = e->next)
{
if(e->machine_id == machine &&
ctrl_handle_match(e->process, process) &&
MemoryMatchStruct(&e->vaddr_range, &vaddr_range))
dmn_handle_match(e->process, process) &&
MemoryMatchStruct(&e->vaddr_range, &vaddr_range) &&
e->arch == arch)
{
entity = e;
break;
@@ -209,6 +210,7 @@ dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process,
entity->machine_id = machine;
entity->process = process;
entity->vaddr_range= vaddr_range;
entity->arch = arch;
entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen);
entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64));
entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64));
@@ -389,7 +391,7 @@ dasm_decode_thread_entry_point(void *p)
//- rjf: request -> ctrl info
B32 is_first_to_task = 0;
CTRL_MachineID ctrl_machine_id = 0;
CTRL_Handle ctrl_process = {0};
DMN_Handle ctrl_process = {0};
Rng1U64 vaddr_range = {0};
Architecture arch = Architecture_Null;
U64 *bytes_processed_counter = 0;
@@ -413,7 +415,7 @@ dasm_decode_thread_entry_point(void *p)
ctrl_machine_id = entity->machine_id;
ctrl_process = entity->process;
vaddr_range = entity->vaddr_range;
arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process);
arch = entity->arch;
bytes_processed_counter = &entity->bytes_processed;
U64 bytes_to_process = dim_1u64(vaddr_range);
ins_atomic_u64_eval_assign(&entity->bytes_processed, 0);
@@ -465,7 +467,7 @@ dasm_decode_thread_entry_point(void *p)
if(good_task)
{
data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range));
data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str);
data.size = dmn_process_read(ctrl_process, chunk_vaddr_range, data.str);
if(data.size != 0)
{
inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data);
+4 -3
View File
@@ -77,8 +77,9 @@ struct DASM_Entity
// rjf: key info
CTRL_MachineID machine_id;
CTRL_Handle process;
DMN_Handle process;
Rng1U64 vaddr_range;
Architecture arch;
U64 id;
// rjf: top-level info
@@ -114,7 +115,7 @@ typedef struct DASM_BinaryInfo DASM_BinaryInfo;
struct DASM_BinaryInfo
{
CTRL_MachineID machine_id;
CTRL_Handle process;
DMN_Handle process;
Rng1U64 vaddr_range;
U64 bytes_processed;
U64 bytes_to_process;
@@ -187,7 +188,7 @@ internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *aren
//~ rjf: Cache Lookups
//- rjf: opening handles & correllation with module
internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range);
internal DASM_Handle dasm_handle_from_ctrl_process_range_arch(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range, Architecture arch);
//- rjf: asking for top-level info of a handle
internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle);
+35
View File
@@ -116,3 +116,38 @@ dmn_event_list_push(Arena *arena, DMN_EventList *list)
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;
}
+52 -18
View File
@@ -4,6 +4,20 @@
#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
@@ -54,6 +68,7 @@ struct DMN_Event
DMN_Handle process;
DMN_Handle thread;
DMN_Handle module;
Architecture arch;
U64 address;
U64 size;
String8 string;
@@ -159,43 +174,62 @@ internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *sr
//- 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 Running/Halting (Implemented Per-OS)
//~ 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 DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls);
internal void dmn_halt(U64 code, U64 user_data);
////////////////////////////////
//~ rjf: @dmn_os_hooks Process Launching/Attaching/Killing/Detaching (Implemented Per-OS)
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
internal U32 dmn_launch_process(OS_LaunchOptions *options);
internal B32 dmn_attach_process(U32 pid);
internal B32 dmn_kill_process(DMN_Handle process, U32 exit_code);
internal B32 dmn_detach_process(DMN_Handle process);
//- rjf: run/memory/register counters
internal U64 dmn_run_gen(void);
internal U64 dmn_mem_gen(void);
internal U64 dmn_reg_gen(void);
////////////////////////////////
//~ rjf: @dmn_os_hooks Process/Thread Reads/Writes (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_read(DMN_Handle process, Rng1U64 range, void *dst);
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
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 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: @dmn_os_hooks System Process Listing (Implemented Per-OS)
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);
+371 -185
View File
@@ -40,7 +40,7 @@ dmn_w32_entity_from_handle(DMN_Handle handle)
{
U32 idx = handle.u32[0];
U32 gen = handle.u32[1];
DMN_W32_Entity *entity = dmn_w32_shared->entities_base;
DMN_W32_Entity *entity = dmn_w32_shared->entities_base + idx;
if(entity->gen != gen)
{
entity = &dmn_w32_entity_nil;
@@ -141,7 +141,7 @@ dmn_w32_entity_release(DMN_W32_Entity *entity)
Task *last_task = &start_task;
for(Task *t = first_task; t != 0; t = t->next)
{
for(DMN_W32_Entity *child = entity->first; child != &dmn_w32_entity_nil; child = child->next)
for(DMN_W32_Entity *child = t->e->first; child != &dmn_w32_entity_nil; child = child->next)
{
Task *t = push_array(scratch.arena, Task, 1);
t->e = child;
@@ -343,6 +343,7 @@ dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src)
ptr += actual_write;
cursor += actual_write;
}
ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen);
return result;
}
@@ -581,9 +582,10 @@ dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block)
//- rjf: unimplemented win32/arch combos
//
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
case Architecture_COUNT:
{NotImplemented;}break;
////////////////////////////
@@ -824,9 +826,10 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block
//- rjf: unimplemented win32/arch combos
//
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
case Architecture_COUNT:
{NotImplemented;}break;
////////////////////////////
@@ -951,6 +954,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block
//- rjf: bad context -> abort
if(ctx == 0)
{
DWORD error = GetLastError();
break;
}
@@ -1041,6 +1045,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block
scratch_end(scratch);
}break;
}
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
return result;
}
@@ -1068,6 +1073,7 @@ dmn_init(void)
Arena *arena = arena_alloc();
dmn_w32_shared = push_array(arena, DMN_W32_Shared, 1);
dmn_w32_shared->arena = arena;
dmn_w32_shared->access_mutex = os_mutex_alloc();
dmn_w32_shared->detach_arena = arena_alloc();
dmn_w32_shared->entities_arena = arena_alloc__sized(GB(8), KB(64));
dmn_w32_shared->entities_base = dmn_w32_entity_alloc(&dmn_w32_entity_nil, DMN_W32_EntityKind_Root, 0);
@@ -1103,18 +1109,203 @@ dmn_init(void)
}
////////////////////////////////
//~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS)
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
internal DMN_CtrlCtx *
dmn_ctrl_begin(void)
{
DMN_CtrlCtx *ctx = (DMN_CtrlCtx *)1;
dmn_w32_ctrl_thread = 1;
return ctx;
}
internal void
dmn_ctrl_exclusive_access_begin(void)
{
OS_MutexScope(dmn_w32_shared->access_mutex)
{
dmn_w32_shared->access_run_state = 1;
}
}
internal void
dmn_ctrl_exclusive_access_end(void)
{
OS_MutexScope(dmn_w32_shared->access_mutex)
{
dmn_w32_shared->access_run_state = 0;
}
}
internal U32
dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options)
{
Temp scratch = scratch_begin(0, 0);
U32 result = 0;
DMN_AccessScope
{
//- rjf: produce exe / arguments string
String8 cmd = {0};
if(options->cmd_line.first != 0)
{
String8List args = {0};
String8 exe_path = options->cmd_line.first->string;
str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path);
for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &args, n->string);
}
StringJoin join_params = {0};
join_params.sep = str8_lit(" ");
cmd = str8_list_join(scratch.arena, &args, &join_params);
}
//- rjf: produce environment strings
String8 env = {0};
{
String8List all_opts = options->env;
if(options->inherit_env != 0)
{
MemoryZeroStruct(&all_opts);
str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1"));
for(String8Node *n = options->env.first; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &all_opts, n->string);
}
for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &all_opts, n->string);
}
}
StringJoin join_params2 = {0};
join_params2.sep = str8_lit("\0");
join_params2.post = str8_lit("\0");
env = str8_list_join(scratch.arena, &all_opts, &join_params2);
}
//- rjf: produce utf-16 strings
String16 cmd16 = str16_from_8(scratch.arena, cmd);
String16 dir16 = str16_from_8(scratch.arena, options->path);
String16 env16 = str16_from_8(scratch.arena, env);
//- rjf: launch
DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS;
STARTUPINFOW startup_info = {sizeof(startup_info)};
PROCESS_INFORMATION process_info = {0};
AllocConsole();
if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info))
{
// check if we are 32-bit app, and just close it immediately
BOOL is_wow = 0;
IsWow64Process(process_info.hProcess, &is_wow);
if(is_wow)
{
MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP);
DebugActiveProcessStop(process_info.dwProcessId);
TerminateProcess(process_info.hProcess,0xffffffff);
}
else
{
result = process_info.dwProcessId;
dmn_w32_shared->new_process_pending = 1;
}
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
}
else
{
MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP);
}
FreeConsole();
//- rjf: eliminate all handles which have stuck around from the AllocConsole
{
SetStdHandle(STD_INPUT_HANDLE, 0);
SetStdHandle(STD_OUTPUT_HANDLE, 0);
SetStdHandle(STD_ERROR_HANDLE, 0);
}
}
scratch_end(scratch);
return result;
}
internal B32
dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid)
{
B32 result = 0;
DMN_AccessScope if(DebugActiveProcess((DWORD)pid))
{
result = 1;
dmn_w32_shared->new_process_pending = 1;
}
return result;
}
internal B32
dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code)
{
B32 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process);
if(TerminateProcess(process_entity->handle, exit_code))
{
result = 1;
}
}
return result;
}
internal B32
dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process)
{
B32 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process);
// rjf: resume threads
for(DMN_W32_Entity *child = process_entity->first;
child != &dmn_w32_entity_nil;
child = child->next)
{
if(child->kind == DMN_W32_EntityKind_Thread)
{
DWORD resume_result = ResumeThread(child->handle);
(void)resume_result;
}
}
// rjf: detach
{
DWORD pid = (DWORD)process_entity->id;
if(DebugActiveProcessStop(pid))
{
result = 1;
}
}
// rjf: push into list of processes to generate events for later
if(result != 0)
{
dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process);
}
}
return result;
}
internal DMN_EventList
dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
{
DMN_EventList events = {0};
dmn_access_open();
//////////////////////////////
//- rjf: determine event generation path
//
typedef enum DMN_W32_EventGenPath
{
DMN_W32_EventGenPath_NotAttached,
DMN_W32_EventGenPath_Run,
DMN_W32_EventGenPath_DetachProcesses,
}
@@ -1124,12 +1315,41 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
event_gen_path = DMN_W32_EventGenPath_DetachProcesses;
}
else
{
B32 any_processes_live = dmn_w32_shared->new_process_pending;
if(!any_processes_live)
{
for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; process != &dmn_w32_entity_nil; process = process->next)
{
if(process->kind == DMN_W32_EntityKind_Process)
{
any_processes_live = 1;
break;
}
}
}
if(!any_processes_live)
{
event_gen_path = DMN_W32_EventGenPath_NotAttached;
}
}
//////////////////////////////
//- rjf: produce debug events
//
switch(event_gen_path)
{
////////////////////////////
//- rjf: produce not-attached error events
//
case DMN_W32_EventGenPath_NotAttached:
{
DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_Error;
e->error_kind = DMN_ErrorKind_NotAttached;
}break;
////////////////////////////
//- rjf: produce debug events from regular running
//
@@ -1148,9 +1368,10 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
//- rjf: unimplemented win32/arch combos
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
case Architecture_COUNT:
{NotImplemented;}break;
//- rjf: x86/64
@@ -1198,7 +1419,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
//- rjf: scan all processes
for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first;
process != 0;
process != &dmn_w32_entity_nil;
process = process->next)
{
if(process->kind != DMN_W32_EntityKind_Process) {continue;}
@@ -1219,7 +1440,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
//- rjf: scan all threads in this process
for(DMN_W32_Entity *thread = process->first;
thread != 0;
thread != &dmn_w32_entity_nil;
thread = thread->next)
{
if(thread->kind != DMN_W32_EntityKind_Thread) {continue;}
@@ -1345,7 +1566,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
DEBUG_EVENT evt = {0};
B32 evt_good = 0;
{
B32 resume_good = 0;
B32 resume_good = 1;
if(dmn_w32_shared->resume_needed)
{
dmn_w32_shared->resume_needed = 0;
@@ -1363,6 +1584,9 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
dmn_w32_shared->resume_pid = evt.dwProcessId;
dmn_w32_shared->resume_tid = evt.dwThreadId;
}
ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen);
ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen);
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
}
}
@@ -1432,6 +1656,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
process->handle = process_handle;
process->arch = image_info.arch;
thread->handle = thread_handle;
thread->arch = image_info.arch;
thread->thread.thread_local_base = tls_base;
module->handle = module_handle;
module->module.vaddr_range = r1u64(module_base, image_info.size);
@@ -1462,6 +1687,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_CreateProcess;
e->process = dmn_w32_handle_from_entity(process);
e->arch = image_info.arch;
e->code = evt.dwProcessId;
}
@@ -1471,6 +1697,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
e->kind = DMN_EventKind_CreateThread;
e->process = dmn_w32_handle_from_entity(process);
e->thread = dmn_w32_handle_from_entity(thread);
e->arch = image_info.arch;
e->code = evt.dwThreadId;
}
@@ -1480,6 +1707,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
e->kind = DMN_EventKind_LoadModule;
e->process = dmn_w32_handle_from_entity(process);
e->module = dmn_w32_handle_from_entity(module);
e->arch = image_info.arch;
e->address = module_base;
e->size = image_info.size;
e->string = dmn_w32_full_path_from_module(arena, module);
@@ -1543,6 +1771,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
DMN_W32_Entity *thread = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Thread, evt.dwThreadId);
{
thread->handle = evt.u.CreateThread.hThread;
thread->arch = process->arch;
thread->thread.thread_local_base = (U64)evt.u.CreateThread.lpThreadLocalBase;
}
@@ -1573,6 +1802,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
e->kind = DMN_EventKind_CreateThread;
e->process = dmn_w32_handle_from_entity(process);
e->thread = dmn_w32_handle_from_entity(thread);
e->arch = thread->arch;
e->code = evt.dwThreadId;
e->string = thread_name;
}
@@ -1627,6 +1857,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
DMN_W32_Entity *module = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Module, module_base);
{
module->handle = evt.u.LoadDll.hFile;
module->arch = image_info.arch;
module->module.vaddr_range = r1u64(module_base, module_base+image_info.size);
module->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName;
module->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0);
@@ -1638,6 +1869,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
e->kind = DMN_EventKind_LoadModule;
e->process = dmn_w32_handle_from_entity(process);
e->module = dmn_w32_handle_from_entity(module);
e->arch = module->arch;
e->address = module_base;
e->size = image_info.size;
e->string = dmn_w32_full_path_from_module(arena, module);
@@ -1765,7 +1997,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
post_trap_rip = regs_rip_from_arch_block(thread->arch, regs_block);
regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer);
dmn_w32_thread_write_reg_block(thread->arch, thread, regs_block);
dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block);
}
temp_end(temp);
}
@@ -1980,7 +2212,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
if(process->kind != DMN_W32_EntityKind_Process) { continue; }
for(DMN_W32_Entity *thread = process->first;
thread != 0;
thread != &dmn_w32_entity_nil;
thread = thread->next)
{
if(thread->kind != DMN_W32_EntityKind_Thread) { continue; }
@@ -2043,9 +2275,10 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
{
//- rjf: unimplemented win32/arch combos
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
case Architecture_COUNT:
{NotImplemented;}break;
//- rjf: x86/64
@@ -2120,13 +2353,17 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls)
}break;
}
dmn_access_close();
return events;
}
////////////////////////////////
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
internal void
dmn_halt(U64 code, U64 user_data)
{
if(!dmn_handle_match(dmn_handle_zero(), dmn_w32_shared->halter_process))
if(dmn_handle_match(dmn_handle_zero(), dmn_w32_shared->halter_process))
{
DMN_W32_Entity *process = &dmn_w32_entity_nil;
for(DMN_W32_Entity *entity = dmn_w32_shared->entities_base->first;
@@ -2151,206 +2388,128 @@ dmn_halt(U64 code, U64 user_data)
}
////////////////////////////////
//~ rjf: @dmn_os_hooks Process Launching/Attaching/Killing/Detaching (Implemented Per-OS)
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
internal U32
dmn_launch_process(OS_LaunchOptions *options)
//- rjf: run/memory/register counters
internal U64
dmn_run_gen(void)
{
Temp scratch = scratch_begin(0, 0);
U32 result = 0;
//- rjf: produce exe / arguments string
String8 cmd = {0};
if(options->cmd_line.first != 0)
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen);
return result;
}
internal U64
dmn_mem_gen(void)
{
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen);
return result;
}
internal U64
dmn_reg_gen(void)
{
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen);
return result;
}
//- rjf: non-blocking-control-thread access barriers
internal B32
dmn_access_open(void)
{
B32 result = 0;
if(dmn_w32_ctrl_thread)
{
String8List args = {0};
String8 exe_path = options->cmd_line.first->string;
str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path);
for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &args, n->string);
}
StringJoin join_params = {0};
join_params.sep = str8_lit(" ");
cmd = str8_list_join(scratch.arena, &args, &join_params);
}
//- rjf: produce environment strings
String8 env = {0};
{
String8List all_opts = options->env;
if(options->inherit_env != 0)
{
MemoryZeroStruct(&all_opts);
for(String8Node *n = options->env.first; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &all_opts, n->string);
}
for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &all_opts, n->string);
}
}
StringJoin join_params2 = {0};
join_params2.sep = str8_lit("\0");
join_params2.post = str8_lit("\0");
env = str8_list_join(scratch.arena, &all_opts, &join_params2);
}
//- rjf: produce utf-16 strings
String16 cmd16 = str16_from_8(scratch.arena, cmd);
String16 dir16 = str16_from_8(scratch.arena, options->path);
String16 env16 = str16_from_8(scratch.arena, env);
//- rjf: launch
DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS;
STARTUPINFOW startup_info = {sizeof(startup_info)};
PROCESS_INFORMATION process_info = {0};
AllocConsole();
if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info))
{
// check if we are 32-bit app, and just close it immediately
BOOL is_wow = 0;
IsWow64Process(process_info.hProcess, &is_wow);
if(is_wow)
{
MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP);
DebugActiveProcessStop(process_info.dwProcessId);
TerminateProcess(process_info.hProcess,0xffffffff);
}
else
{
result = process_info.dwProcessId;
dmn_w32_shared->new_process_pending = 1;
}
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
result = 1;
}
else
{
MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP);
}
FreeConsole();
//- rjf: eliminate all handles which have stuck around from the AllocConsole
{
SetStdHandle(STD_INPUT_HANDLE, 0);
SetStdHandle(STD_OUTPUT_HANDLE, 0);
SetStdHandle(STD_ERROR_HANDLE, 0);
}
scratch_end(scratch);
return result;
}
internal B32
dmn_attach_process(U32 pid)
{
B32 result = 0;
if(DebugActiveProcess((DWORD)pid))
{
result = 1;
dmn_w32_shared->new_process_pending = 1;
os_mutex_take(dmn_w32_shared->access_mutex);
result = !dmn_w32_shared->access_run_state;
}
return result;
}
internal B32
dmn_kill_process(DMN_Handle process, U32 exit_code)
internal void
dmn_access_close(void)
{
B32 result = 0;
DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process);
if(TerminateProcess(process_entity->handle, exit_code))
if(!dmn_w32_ctrl_thread)
{
result = 1;
}
return result;
}
internal B32
dmn_detach_process(DMN_Handle process)
{
B32 result = 0;
DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process);
// rjf: resume threads
for(DMN_W32_Entity *child = process_entity->first;
child != &dmn_w32_entity_nil;
child = child->next)
{
if(child->kind == DMN_W32_EntityKind_Thread)
{
DWORD resume_result = ResumeThread(child->handle);
(void)resume_result;
}
}
// rjf: detach
{
DWORD pid = (DWORD)process_entity->id;
if(DebugActiveProcessStop(pid))
{
result = 1;
}
}
// rjf: push into list of processes to generate events for later
if(result != 0)
{
dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process);
os_mutex_drop(dmn_w32_shared->access_mutex);
}
}
////////////////////////////////
//~ rjf: @dmn_os_hooks Process/Thread Reads/Writes (Implemented Per-OS)
//- rjf: processes
internal U64
dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst)
{
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process);
U64 result = dmn_w32_process_read(entity->handle, range, dst);
U64 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process);
result = dmn_w32_process_read(entity->handle, range, dst);
}
return result;
}
internal B32
dmn_process_write(DMN_Handle process, Rng1U64 range, void *src)
{
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process);
B32 result = dmn_w32_process_write(entity->handle, range, src);
B32 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process);
result = dmn_w32_process_write(entity->handle, range, src);
}
return result;
}
//- rjf: threads
internal Architecture
dmn_arch_from_thread(DMN_Handle handle)
{
Architecture arch = Architecture_Null;
DMN_AccessScope
{
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle);
arch = entity->arch;
}
return arch;
}
internal U64
dmn_stack_base_vaddr_from_thread(DMN_Handle handle)
{
U64 result = 0;
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
if(thread->kind == DMN_W32_EntityKind_Thread)
DMN_AccessScope
{
DMN_W32_Entity *process = thread->parent;
U64 tlb = thread->thread.thread_local_base;
U64 result = 0;
switch(thread->arch)
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
if(thread->kind == DMN_W32_EntityKind_Thread)
{
case Architecture_Null:
case Architecture_arm64:
case Architecture_arm32:
case Architecture_COUNT:
{NotImplemented;}break;
case Architecture_x64:
DMN_W32_Entity *process = thread->parent;
U64 tlb = thread->thread.thread_local_base;
switch(thread->arch)
{
U64 stack_base_addr = tlb + 0x8;
dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result);
}break;
case Architecture_x86:
{
U64 stack_base_addr = tlb + 0x4;
dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result);
}break;
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
{NotImplemented;}break;
case Architecture_x64:
{
U64 stack_base_addr = tlb + 0x8;
dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result);
}break;
case Architecture_x86:
{
U64 stack_base_addr = tlb + 0x4;
dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result);
}break;
}
}
}
return result;
@@ -2360,10 +2519,30 @@ internal U64
dmn_tls_root_vaddr_from_thread(DMN_Handle handle)
{
U64 result = 0;
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle);
if(entity->kind == DMN_W32_EntityKind_Thread)
DMN_AccessScope
{
result = entity->thread.thread_local_base;
DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle);
if(entity->kind == DMN_W32_EntityKind_Thread)
{
result = entity->thread.thread_local_base;
switch(entity->arch)
{
case Architecture_Null:
case Architecture_COUNT:
{}break;
case Architecture_arm64:
case Architecture_arm32:
{NotImplemented;}break;
case Architecture_x64:
{
result += 88;
}break;
case Architecture_x86:
{
result += 44;
}break;
}
}
}
return result;
}
@@ -2371,21 +2550,28 @@ dmn_tls_root_vaddr_from_thread(DMN_Handle handle)
internal B32
dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block)
{
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
B32 result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block);
B32 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block);
}
return result;
}
internal B32
dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block)
{
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
B32 result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block);
B32 result = 0;
DMN_AccessScope
{
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle);
result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block);
}
return result;
}
////////////////////////////////
//~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS)
//- rjf: system process listing
internal void
dmn_process_iter_begin(DMN_ProcessIter *iter)
+10
View File
@@ -194,6 +194,15 @@ struct DMN_W32_Shared
Arena *arena;
String8List env_strings;
// rjf: access locking mechanism
OS_Handle access_mutex;
B32 access_run_state;
// rjf: run/mem/reg gens
U64 run_gen;
U64 mem_gen;
U64 reg_gen;
// rjf: detaching info
Arena *detach_arena;
DMN_HandleList detach_processes;
@@ -227,6 +236,7 @@ struct DMN_W32_Shared
global DMN_W32_Shared *dmn_w32_shared = 0;
global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil};
global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0;
thread_static B32 dmn_w32_ctrl_thread = 0;
////////////////////////////////
//~ rjf: Basic Helpers
+247 -248
View File
@@ -1404,7 +1404,7 @@ internal DASM_Handle
df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr)
{
Rng1U64 disasm_vaddr_rng = r1u64(AlignDownPow2(vaddr, KB(4)), AlignDownPow2(vaddr, KB(4)) + KB(16));
DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng);
DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range_arch(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng, process->arch);
return dasm_handle;
}
@@ -2025,7 +2025,7 @@ df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id)
}
internal void
df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle)
df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle)
{
df_require_entity_nonnil(entity, return);
entity->ctrl_handle = handle;
@@ -2419,7 +2419,7 @@ df_machine_entity_from_machine_id(CTRL_MachineID machine_id)
}
internal DF_Entity *
df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle)
df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle)
{
DF_Entity *result = &df_g_nil_entity;
if(handle.u64[0] != 0)
@@ -2520,11 +2520,13 @@ df_set_thread_freeze_state(DF_Entity *thread, B32 frozen)
}
node->handle = thread_handle;
df_handle_list_push_node(&df_state->frozen_threads, node);
df_state->entities_mut_soft_halt = 1;
}
// rjf: frozen => not frozen
if(is_frozen && !should_be_frozen)
{
df_state->entities_mut_soft_halt = 1;
df_handle_list_remove(&df_state->frozen_threads, already_frozen_node);
SLLStackPush(df_state->free_handle_node, already_frozen_node);
}
@@ -2710,11 +2712,9 @@ df_debug_info_path_from_module(Arena *arena, DF_Entity *module)
}
else
{
Temp scratch = scratch_begin(&arena, 1);
String8 exe_path = module->name;
String8 dbg_path = ctrl_og_dbg_path_from_exe_path(arena, exe_path);
String8 dbg_path = push_str8f(arena, "%S.pdb", str8_chop_last_dot(exe_path));
result = dbg_path;
scratch_end(scratch);
}
ProfEnd();
return result;
@@ -2824,14 +2824,14 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread)
// rjf: thread => unpacked info
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
Architecture arch = df_architecture_from_entity(thread);
U64 ip_vaddr = df_rip_from_thread(thread);
U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
// rjf: ip => machine code
String8 machine_code = {0};
{
Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch));
machine_code.str = push_array_no_zero(scratch.arena, U8, max_instruction_size_from_arch(arch));
machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, rng, machine_code.str);
CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, rng, os_now_microseconds()+5000);
machine_code = machine_code_slice.data;
}
// rjf: build traps if machine code was read successfully
@@ -2863,7 +2863,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread)
DF_Entity *module = df_module_from_thread(thread);
DF_Entity *binary = df_binary_file_from_module(module);
Architecture arch = df_architecture_from_entity(thread);
U64 ip_vaddr = df_rip_from_thread(thread);
U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
// rjf: ip => line vaddr range
Rng1U64 line_vaddr_rng = {0};
@@ -2897,8 +2897,8 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread)
String8 machine_code = {0};
if(good_line_info)
{
machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng));
machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str);
CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+50000);
machine_code = machine_code_slice.data;
}
// rjf: machine code => ctrl flow analysis
@@ -2988,7 +2988,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread)
DF_Entity *module = df_module_from_thread(thread);
DF_Entity *binary = df_binary_file_from_module(module);
Architecture arch = df_architecture_from_entity(thread);
U64 ip_vaddr = df_rip_from_thread(thread);
U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
// rjf: ip => line vaddr range
Rng1U64 line_vaddr_rng = {0};
@@ -3022,8 +3022,8 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread)
String8 machine_code = {0};
if(good_line_info)
{
machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng));
machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str);
CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+5000);
machine_code = machine_code_slice.data;
}
// rjf: machine code => ctrl flow analysis
@@ -3379,27 +3379,6 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff)
return result;
}
internal DF_TextLineDasm2SrcInfoList
df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff)
{
Temp scratch = scratch_begin(&arena, 1);
DF_TextLineDasm2SrcInfoList result = {0};
DF_EntityList binaries = df_push_active_binary_list(scratch.arena);
for(DF_EntityNode *n = binaries.first; n != 0; n = n->next)
{
DF_TextLineDasm2SrcInfo info = df_text_line_dasm2src_info_from_binary_voff(n->entity, voff);
if(!df_entity_is_nil(info.file))
{
DF_TextLineDasm2SrcInfoNode *dst_n = push_array(arena, DF_TextLineDasm2SrcInfoNode, 1);
dst_n->v = info;
SLLQueuePush(result.first, result.last, dst_n);
result.count += 1;
}
}
scratch_end(scratch);
return result;
}
//- rjf: symbol -> voff lookups
internal U64
@@ -3565,83 +3544,84 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64
U64 base_vaddr = 0;
Temp scratch = scratch_begin(0, 0);
DBGI_Scope *scope = dbgi_scope_open();
//- rjf: unpack thread info
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
DF_Entity *binary = df_binary_file_from_module(module);
DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary);
String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size);
PE_BinInfo *bin = &dbgi->pe;
B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF
U64 addr_size = bit_size_from_arch(bin->arch)/8;
//- rjf: grab tls range
Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module));
//- rjf: read module's TLS index
U64 tls_index = 0;
if(!df_ctrl_targets_running())
{
U64 bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, &tls_index);
if(bytes_read < sizeof(U64))
{
tls_index = 0;
}
}
//- rjf: PE path
if(bin_is_pe)
{
U64 thread_info_addr = root_vaddr;
U64 tls_addr_off = tls_index*addr_size;
U64 tls_addr_array = 0;
CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0);
String8 tls_addr_array_data = tls_addr_array_slice.data;
if(tls_addr_array_data.size >= 8)
{
MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64));
}
CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0);
String8 result_data = result_slice.data;
if(result_data.size >= 8)
{
MemoryCopy(&base_vaddr, result_data.str, sizeof(U64));
}
}
//- rjf: non-PE path (not implemented)
if(!bin_is_pe)
{
// TODO(rjf): not supported. old code from the prototype that Nick had sketched out:
#if 0
// TODO(nick): This code works only if the linked c runtime library is glibc.
// Implement CRT detection here.
//- rjf: unpack thread info
DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr);
DF_Entity *binary = df_binary_file_from_module(module);
DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary);
String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size);
PE_BinInfo *bin = &dbgi->pe;
B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF
U64 addr_size = bit_size_from_arch(bin->arch)/8;
U64 dtv_addr = UINT64_MAX;
demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size);
//- rjf: grab tls range
Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module));
/*
union delta_thread_vector
//- rjf: read module's TLS index
U64 tls_index = 0;
{
CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0);
if(tls_index_slice.data.size >= addr_size)
{
size_t counter;
struct
{
void *value;
void *to_free;
} pointer;
};
*/
U64 dtv_size = 16;
U64 dtv_count = 0;
demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size);
if (tls_index > 0 && tls_index < dtv_count)
{
demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size);
tls_index = *(U64 *)tls_index_slice.data.str;
}
}
//- rjf: PE path
if(bin_is_pe)
{
U64 thread_info_addr = root_vaddr;
U64 tls_addr_off = tls_index*addr_size;
U64 tls_addr_array = 0;
CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0);
String8 tls_addr_array_data = tls_addr_array_slice.data;
if(tls_addr_array_data.size >= 8)
{
MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64));
}
CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0);
String8 result_data = result_slice.data;
if(result_data.size >= 8)
{
MemoryCopy(&base_vaddr, result_data.str, sizeof(U64));
}
}
//- rjf: non-PE path (not implemented)
if(!bin_is_pe)
{
// TODO(rjf): not supported. old code from the prototype that Nick had sketched out:
#if 0
// TODO(nick): This code works only if the linked c runtime library is glibc.
// Implement CRT detection here.
U64 dtv_addr = UINT64_MAX;
demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size);
/*
union delta_thread_vector
{
size_t counter;
struct
{
void *value;
void *to_free;
} pointer;
};
*/
U64 dtv_size = 16;
U64 dtv_count = 0;
demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size);
if (tls_index > 0 && tls_index < dtv_count)
{
demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size);
}
#endif
}
}
dbgi_scope_close(scope);
scratch_end(scratch);
ProfEnd();
@@ -3654,43 +3634,6 @@ df_architecture_from_entity(DF_Entity *entity)
return entity->arch;
}
internal CTRL_Unwind
df_push_unwind_from_thread(Arena *arena, DF_Entity *thread)
{
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
CTRL_Unwind unwind = ctrl_unwind_from_process_thread(arena, thread->ctrl_machine_id, process->ctrl_handle, thread->ctrl_handle);
return unwind;
}
internal U64
df_rip_from_thread(DF_Entity *thread)
{
U64 result = ctrl_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle);
return result;
}
internal U64
df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count)
{
Temp scratch = scratch_begin(0, 0);
U64 result = df_rip_from_thread(thread);
if(unwind_count != 0)
{
CTRL_Unwind unwind = df_push_unwind_from_thread(scratch.arena, thread);
U64 unwind_idx = 0;
for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1)
{
if(unwind_count == unwind_idx)
{
result = frame->rip;
break;
}
}
}
scratch_end(scratch);
return result;
}
internal EVAL_String2NumMap *
df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff)
{
@@ -3718,26 +3661,33 @@ df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *
internal B32
df_set_thread_rip(DF_Entity *thread, U64 vaddr)
{
B32 result = ctrl_thread_write_rip(thread->ctrl_machine_id, thread->ctrl_handle, vaddr);
Temp scratch = scratch_begin(0, 0);
void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
regs_arch_block_write_rip(thread->arch, block, vaddr);
B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block);
// rjf: early mutation of unwind cache for immediate frontend effect
if(result)
{
DF_RunUnwindCache *unwind_cache = &df_state->unwind_cache;
DF_Handle thread_handle = df_handle_from_entity(thread);
U64 hash = df_hash_from_string(str8_struct(&thread_handle));
U64 slot_idx = hash % unwind_cache->table_size;
DF_RunUnwindCacheSlot *slot = &unwind_cache->table[slot_idx];
for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next)
DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)];
if(unwind_cache->slots_count != 0)
{
if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0)
DF_Handle thread_handle = df_handle_from_entity(thread);
U64 hash = df_hash_from_string(str8_struct(&thread_handle));
U64 slot_idx = hash % unwind_cache->slots_count;
DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx];
for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next)
{
n->unwind.first->rip = vaddr;
break;
if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0)
{
n->unwind.first->rip = vaddr;
break;
}
}
}
}
scratch_end(scratch);
return result;
}
@@ -4134,7 +4084,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_
//- rjf: unpack arguments
DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread);
U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle);
U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
DF_Entity *process = thread->parent;
U64 unwind_count = ctrl_ctx->unwind_count;
CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread);
@@ -6188,37 +6138,57 @@ df_push_active_target_list(Arena *arena)
internal CTRL_Unwind
df_query_cached_unwind_from_thread(DF_Entity *thread)
{
ProfBeginFunction();
CTRL_Unwind result = {0};
DF_RunUnwindCache *cache = &df_state->unwind_cache;
if(cache->table_size != 0)
DF_Handle handle = df_handle_from_entity(thread);
U64 hash = df_hash_from_string(str8_struct(&handle));
for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1)
{
DF_Handle handle = df_handle_from_entity(thread);
U64 hash = df_hash_from_string(str8_struct(&handle));
U64 slot_idx = hash % cache->table_size;
DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx];
DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)];
if(cache_idx == 0 && cache->slots_count == 0)
{
cache->slots_count = 1024;
cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count);
}
else if(cache->slots_count == 0)
{
break;
}
U64 slot_idx = hash%cache->slots_count;
DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx];
DF_RunUnwindCacheNode *node = 0;
for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next)
{
if(df_handle_match(n->thread, handle))
{
result = n->unwind;
node = n;
break;
}
}
if(node != 0)
{
result = node->unwind;
break;
}
else
{
result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0);
if(!result.error)
{
node = push_array(cache->arena, DF_RunUnwindCacheNode, 1);
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
node->thread = handle;
node->unwind = result;
break;
}
}
}
ProfEnd();
return result;
}
internal U64
df_query_cached_rip_from_thread(DF_Entity *thread)
{
U64 result = 0;
CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread);
if(unwind.first != 0)
{
result = unwind.first->rip;
}
U64 result = df_query_cached_rip_from_thread_unwind(thread, 0);
return result;
}
@@ -6226,14 +6196,21 @@ internal U64
df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count)
{
U64 result = 0;
CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread);
U64 unwind_idx = 0;
for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1)
if(unwind_count == 0)
{
if(unwind_idx == unwind_count)
result = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
}
else
{
CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread);
U64 unwind_idx = 0;
for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1)
{
result = frame->rip;
break;
if(unwind_idx == unwind_count)
{
result = frame->rip;
break;
}
}
}
return result;
@@ -6243,13 +6220,18 @@ internal U64
df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr)
{
U64 result = 0;
for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->tls_base_caches); cache_idx += 1)
{
DF_RunTLSBaseCache *cache = &df_state->tls_base_cache;
if(cache->slots_count == 0)
DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[(df_state->tls_base_cache_gen+cache_idx)%ArrayCount(df_state->tls_base_caches)];
if(cache_idx == 0 && cache->slots_count == 0)
{
cache->slots_count = 256;
cache->slots = push_array(cache->arena, DF_RunTLSBaseCacheSlot, cache->slots_count);
}
else if(cache->slots_count == 0)
{
break;
}
DF_Handle handle = df_handle_from_entity(process);
U64 hash = df_hash_from_seed_string(df_hash_from_string(str8_struct(&handle)), str8_struct(&rip_vaddr));
U64 slot_idx = hash%cache->slots_count;
@@ -6265,14 +6247,22 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo
}
if(node == 0)
{
node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1);
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
node->process = handle;
node->root_vaddr = root_vaddr;
node->rip_vaddr = rip_vaddr;
node->tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr);
U64 tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr);
if(tls_base_vaddr != 0)
{
node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1);
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
node->process = handle;
node->root_vaddr = root_vaddr;
node->rip_vaddr = rip_vaddr;
node->tls_base_vaddr = tls_base_vaddr;
}
}
if(node != 0 && node->tls_base_vaddr != 0)
{
result = node->tls_base_vaddr;
break;
}
result = node->tls_base_vaddr;
}
return result;
}
@@ -6282,13 +6272,18 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff)
{
ProfBeginFunction();
EVAL_String2NumMap *map = &eval_string2num_map_nil;
for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->locals_caches); cache_idx += 1)
{
DF_RunLocalsCache *cache = &df_state->locals_cache;
if(cache->table_size == 0)
DF_RunLocalsCache *cache = &df_state->locals_caches[(df_state->locals_cache_gen+cache_idx)%ArrayCount(df_state->locals_caches)];
if(cache_idx == 0 && cache->table_size == 0)
{
cache->table_size = 256;
cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size);
}
else if(cache->table_size == 0)
{
break;
}
DF_Handle handle = df_handle_from_entity(binary);
U64 hash = df_hash_from_string(str8_struct(&handle));
U64 slot_idx = hash % cache->table_size;
@@ -6316,9 +6311,10 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff)
}
dbgi_scope_close(scope);
}
if(node != 0)
if(node != 0 && node->locals_map->slots_count != 0)
{
map = node->locals_map;
break;
}
}
ProfEnd();
@@ -6330,13 +6326,18 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff)
{
ProfBeginFunction();
EVAL_String2NumMap *map = &eval_string2num_map_nil;
for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->member_caches); cache_idx += 1)
{
DF_RunLocalsCache *cache = &df_state->member_cache;
if(cache->table_size == 0)
DF_RunLocalsCache *cache = &df_state->member_caches[(df_state->member_cache_gen+cache_idx)%ArrayCount(df_state->member_caches)];
if(cache_idx == 0 && cache->table_size == 0)
{
cache->table_size = 256;
cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size);
}
else if(cache->table_size == 0)
{
break;
}
DF_Handle handle = df_handle_from_entity(binary);
U64 hash = df_hash_from_string(str8_struct(&handle));
U64 slot_idx = hash % cache->table_size;
@@ -6364,9 +6365,10 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff)
}
dbgi_scope_close(scope);
}
if(node != 0)
if(node != 0 && node->locals_map->slots_count != 0)
{
map = node->locals_map;
break;
}
}
ProfEnd();
@@ -6396,6 +6398,7 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist)
df_state->entities_base = push_array(df_state->entities_arena, DF_Entity, 0);
df_state->entities_count = 0;
df_state->ctrl_msg_arena = arena_alloc();
df_state->ctrl_entity_store = ctrl_entity_store_alloc();
df_state->ctrl_stop_arena = arena_alloc();
df_state->entities_root = df_entity_alloc(0, &df_g_nil_entity, DF_EntityKind_Root);
df_state->cmd_spec_table_size = 1024;
@@ -6417,7 +6420,7 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist)
// rjf: set up initial entities
{
DF_Entity *local_machine = df_entity_alloc(0, df_state->entities_root, DF_EntityKind_Machine);
df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Client);
df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Local);
df_entity_equip_name(0, local_machine, str8_lit("This PC"));
}
@@ -6434,10 +6437,22 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist)
}
// rjf: set up per-run caches
df_state->unwind_cache.arena = arena_alloc();
df_state->tls_base_cache.arena = arena_alloc();
df_state->locals_cache.arena = arena_alloc();
df_state->member_cache.arena = arena_alloc();
for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1)
{
df_state->unwind_caches[idx].arena = arena_alloc();
}
for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1)
{
df_state->tls_base_caches[idx].arena = arena_alloc();
}
for(U64 idx = 0; idx < ArrayCount(df_state->locals_caches); idx += 1)
{
df_state->locals_caches[idx].arena = arena_alloc();
}
for(U64 idx = 0; idx < ArrayCount(df_state->member_caches); idx += 1)
{
df_state->member_caches[idx].arena = arena_alloc();
}
// rjf: set up eval view cache
df_state->eval_view_cache.slots_count = 4096;
@@ -6542,11 +6557,12 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
Temp scratch = scratch_begin(&arena, 1);
//- rjf: grab next reggen/memgen
U64 new_memgen_idx = ctrl_memgen_idx();
U64 new_reggen_idx = ctrl_reggen_idx();
U64 new_mem_gen = ctrl_mem_gen();
U64 new_reg_gen = ctrl_reg_gen();
//- rjf: consume & process events
CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena);
ctrl_entity_store_apply_events(df_state->ctrl_entity_store, &events);
for(CTRL_EventNode *event_n = events.first; event_n != 0; event_n = event_n->next)
{
CTRL_Event *event = &event_n->v;
@@ -6586,7 +6602,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
// rjf: thread hit user breakpoint -> increment breakpoint hit count
if(event->cause == CTRL_EventCause_UserBreakpoint)
{
U64 stop_thread_vaddr = df_rip_from_thread(stop_thread);
U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle);
DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process);
DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr);
DF_Entity *binary = df_binary_file_from_module(module);
@@ -6895,7 +6911,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
}
}
// rjf: collect s top info
// rjf: collect stop info
arena_clear(df_state->ctrl_stop_arena);
MemoryCopyStruct(&df_state->ctrl_last_stop_event, event);
df_state->ctrl_last_stop_event.string = push_str8_copy(df_state->ctrl_stop_arena, df_state->ctrl_last_stop_event.string);
@@ -6903,72 +6919,55 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
}
}
//- rjf: refresh unwind cache
if((df_state->unwind_cache_memgen_idx != new_memgen_idx ||
df_state->unwind_cache_reggen_idx != new_reggen_idx) &&
//- rjf: clear unwind cache
if((df_state->unwind_cache_memgen_idx != new_mem_gen ||
df_state->unwind_cache_reggen_idx != new_reg_gen) &&
!df_ctrl_targets_running()) ProfScope("per-thread unwind gather")
{
B32 good = 1;
DF_EntityList all_threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread);
DF_RunUnwindCache *cache = &df_state->unwind_cache;
arena_clear(cache->arena);
cache->table_size = 1024;
cache->table = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->table_size);
for(DF_EntityNode *n = all_threads.first; n != 0; n = n->next)
{
DF_Entity *thread = n->entity;
DF_Handle thread_handle = df_handle_from_entity(thread);
U64 hash = df_hash_from_string(str8_struct(&thread_handle));
U64 slot_idx = hash % cache->table_size;
DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx];
DF_RunUnwindCacheNode *cache_node = push_array(cache->arena, DF_RunUnwindCacheNode, 1);
cache_node->thread = thread_handle;
cache_node->unwind = df_push_unwind_from_thread(cache->arena, thread);
SLLQueuePush_NZ(0, slot->first, slot->last, cache_node, hash_next);
if(cache_node->unwind.error != 0)
{
good = 0;
break;
}
}
if(good)
{
df_state->unwind_cache_memgen_idx = new_memgen_idx;
df_state->unwind_cache_reggen_idx = new_reggen_idx;
}
}
//- rjf: clear tls base cache
if((df_state->tls_base_cache_reggen_idx != new_reggen_idx ||
df_state->tls_base_cache_memgen_idx != new_memgen_idx) &&
!df_ctrl_targets_running())
{
DF_RunTLSBaseCache *cache = &df_state->tls_base_cache;
df_state->unwind_cache_gen += 1;
DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)];
arena_clear(cache->arena);
cache->slots_count = 0;
cache->slots = 0;
df_state->tls_base_cache_reggen_idx = new_reggen_idx;
df_state->tls_base_cache_memgen_idx = new_memgen_idx;
df_state->unwind_cache_memgen_idx = new_mem_gen;
df_state->unwind_cache_reggen_idx = new_reg_gen;
}
//- rjf: clear tls base cache
if((df_state->tls_base_cache_reggen_idx != new_reg_gen ||
df_state->tls_base_cache_memgen_idx != new_mem_gen) &&
!df_ctrl_targets_running())
{
df_state->tls_base_cache_gen += 1;
DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[df_state->tls_base_cache_gen%ArrayCount(df_state->tls_base_caches)];
arena_clear(cache->arena);
cache->slots_count = 0;
cache->slots = 0;
df_state->tls_base_cache_reggen_idx = new_reg_gen;
df_state->tls_base_cache_memgen_idx = new_mem_gen;
}
//- rjf: clear locals cache
if(df_state->locals_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running())
if(df_state->locals_cache_reggen_idx != new_reg_gen &&
!df_ctrl_targets_running())
{
DF_RunLocalsCache *cache = &df_state->locals_cache;
df_state->locals_cache_gen += 1;
DF_RunLocalsCache *cache = &df_state->locals_caches[df_state->locals_cache_gen%ArrayCount(df_state->locals_caches)];
arena_clear(cache->arena);
cache->table_size = 0;
cache->table = 0;
df_state->locals_cache_reggen_idx = new_reggen_idx;
df_state->locals_cache_reggen_idx = new_reg_gen;
}
//- rjf: clear members cache
if(df_state->member_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running())
if(df_state->member_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running())
{
DF_RunLocalsCache *cache = &df_state->member_cache;
df_state->member_cache_gen += 1;
DF_RunLocalsCache *cache = &df_state->member_caches[df_state->member_cache_gen%ArrayCount(df_state->member_caches)];
arena_clear(cache->arena);
cache->table_size = 0;
cache->table = 0;
df_state->member_cache_reggen_idx = new_reggen_idx;
df_state->member_cache_reggen_idx = new_reg_gen;
}
scratch_end(scratch);
@@ -7515,7 +7514,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
}break;
case DF_CoreCmdKind_FreezeLocalMachine:
{
CTRL_MachineID machine_id = CTRL_MachineID_Client;
CTRL_MachineID machine_id = CTRL_MachineID_Local;
DF_CmdParams params = df_cmd_params_zero();
params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id));
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_Entity);
@@ -7523,7 +7522,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
}break;
case DF_CoreCmdKind_ThawLocalMachine:
{
CTRL_MachineID machine_id = CTRL_MachineID_Client;
CTRL_MachineID machine_id = CTRL_MachineID_Local;
DF_CmdParams params = df_cmd_params_zero();
params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id));
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_Entity);
+14 -14
View File
@@ -447,7 +447,7 @@ struct DF_Entity
// rjf: ctrl entity equipment
CTRL_MachineID ctrl_machine_id;
CTRL_Handle ctrl_handle;
DMN_Handle ctrl_handle;
Architecture arch;
U32 ctrl_id;
U64 stack_base;
@@ -940,7 +940,6 @@ struct DF_RunUnwindCacheNode
DF_RunUnwindCacheNode *hash_next;
DF_Handle thread;
CTRL_Unwind unwind;
U64 tls_base_vaddr;
};
typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot;
@@ -954,8 +953,8 @@ typedef struct DF_RunUnwindCache DF_RunUnwindCache;
struct DF_RunUnwindCache
{
Arena *arena;
U64 table_size;
DF_RunUnwindCacheSlot *table;
U64 slots_count;
DF_RunUnwindCacheSlot *slots;
};
//- rjf: per-run tls-base-vaddr cache
@@ -1136,14 +1135,18 @@ struct DF_State
// rjf: per-run caches
U64 unwind_cache_reggen_idx;
U64 unwind_cache_memgen_idx;
DF_RunUnwindCache unwind_cache;
DF_RunUnwindCache unwind_caches[2];
U64 unwind_cache_gen;
U64 tls_base_cache_reggen_idx;
U64 tls_base_cache_memgen_idx;
DF_RunTLSBaseCache tls_base_cache;
DF_RunTLSBaseCache tls_base_caches[2];
U64 tls_base_cache_gen;
U64 locals_cache_reggen_idx;
DF_RunLocalsCache locals_cache;
DF_RunLocalsCache locals_caches[2];
U64 locals_cache_gen;
U64 member_cache_reggen_idx;
DF_RunLocalsCache member_cache;
DF_RunLocalsCache member_caches[2];
U64 member_cache_gen;
// rjf: eval view cache
DF_EvalViewCache eval_view_cache;
@@ -1179,6 +1182,7 @@ struct DF_State
B32 ctrl_solo_stepping_mode;
// rjf: control thread ctrl -> user reading state
CTRL_EntityStore *ctrl_entity_store;
Arena *ctrl_stop_arena;
CTRL_Event ctrl_last_stop_event;
@@ -1447,7 +1451,7 @@ internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src);
//- rjf: control layer correllation equipment
internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id);
internal void df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle);
internal void df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle);
internal void df_entity_equip_arch(DF_Entity *entity, Architecture arch);
internal void df_entity_equip_ctrl_id(DF_Entity *entity, U32 id);
internal void df_entity_equip_stack_base(DF_Entity *entity, U64 stack_base);
@@ -1468,7 +1472,7 @@ internal DF_Entity *df_entity_root(void);
internal DF_EntityList df_push_entity_list_with_kind(Arena *arena, DF_EntityKind kind);
internal DF_Entity *df_entity_from_id(DF_EntityID id);
internal DF_Entity *df_machine_entity_from_machine_id(CTRL_MachineID machine_id);
internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle);
internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle);
internal DF_Entity *df_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id);
internal DF_Entity *df_entity_from_name_and_kind(String8 string, DF_EntityKind kind);
internal DF_Entity *df_entity_from_u64_and_kind(U64 u64, DF_EntityKind kind);
@@ -1533,7 +1537,6 @@ internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_
//- rjf: voff -> src lookups
internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff);
internal DF_TextLineDasm2SrcInfoList df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff);
//- rjf: symbol -> voff lookups
internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name);
@@ -1547,9 +1550,6 @@ internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr);
internal DF_Entity *df_module_from_thread(DF_Entity *thread);
internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr);
internal Architecture df_architecture_from_entity(DF_Entity *entity);
internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread);
internal U64 df_rip_from_thread(DF_Entity *thread);
internal U64 df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count);
internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff);
internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff);
internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr);
+3 -3
View File
@@ -2131,7 +2131,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
if(thread->kind == DF_EntityKind_Thread)
{
// rjf: grab rip
U64 rip_vaddr = (unwind_count == 0 ? df_rip_from_thread(thread) : df_query_cached_rip_from_thread_unwind(thread, unwind_count));
U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count);
// rjf: extract thread/rip info
DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process);
@@ -3111,8 +3111,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
avg_ui_hash_chain_length = chain_length_sum / chain_count;
}
ui_labelf("Target Hz: %.2f", 1.f/df_dt());
ui_labelf("Ctrl Run Index: %I64u", ctrl_run_idx());
ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_memgen_idx());
ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen());
ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen());
ui_labelf("Window %p", window);
ui_set_next_pref_width(ui_children_sum(1));
ui_set_next_pref_height(ui_children_sum(1));
+7 -7
View File
@@ -565,7 +565,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba)
Vec4F32 rgba = {0};
Vec4F32 hsva = {0};
{
if(state->memgen_idx >= ctrl_memgen_idx())
if(state->memgen_idx >= ctrl_mem_gen())
{
hsva = state->hsva;
rgba = rgba_from_hsva(hsva);
@@ -575,7 +575,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba)
DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval);
rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdi, process);
state->hsva = hsva = hsva_from_rgba(rgba);
state->memgen_idx = ctrl_memgen_idx();
state->memgen_idx = ctrl_mem_gen();
}
}
Vec4F32 initial_hsva = hsva;
@@ -624,7 +624,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba)
{
Vec4F32 rgba = rgba_from_hsva(hsva);
df_view_rule_hooks__eval_commit_rgba(eval, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, rgba);
state->memgen_idx = ctrl_memgen_idx();
state->memgen_idx = ctrl_mem_gen();
}
//- rjf: commit possible edited value to state
@@ -700,7 +700,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text)
}
//- rjf: address range -> hash
U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1, 0);
U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1, 0, 0);
//- rjf: hash -> data
String8 data = hs_data_from_hash(hs_scope, hash);
@@ -891,7 +891,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap)
}
//- rjf: address range -> hash
U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0, 0);
U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0, 0, 0);
//- rjf: hash & topology -> texture
TEX_Topology topology = tex_topology_make(v2s32((S32)topology_info.width, (S32)topology_info.height), topology_info.fmt);
@@ -1151,8 +1151,8 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo)
}
//- rjf: address range -> hash
U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0, 0);
U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0, 0);
U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0, 0, 0);
U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0, 0, 0);
//- rjf: get gpu buffers
R_Handle index_buffer = geo_buffer_from_key_hash(geo_scope, index_buffer_key, index_buffer_hash);
+13 -8
View File
@@ -240,9 +240,9 @@ df_process_info_list_from_query(Arena *arena, String8 query)
//- rjf: build list
DF_ProcessInfoList list = {0};
{
DEMON_ProcessIter iter = {0};
demon_proc_iter_begin(&iter);
for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(scratch.arena, &iter, &info);)
DMN_ProcessIter iter = {0};
dmn_process_iter_begin(&iter);
for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &iter, &info);)
{
// rjf: skip root-level or otherwise 0-pid processes
if(info.pid == 0)
@@ -290,7 +290,7 @@ df_process_info_list_from_query(Arena *arena, String8 query)
list.count += 1;
}
}
demon_proc_iter_end(&iter);
dmn_process_iter_end(&iter);
}
scratch_end(scratch);
@@ -6235,6 +6235,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly)
}
// rjf: find live threads mapping to this disassembly
ProfScope("find live threads mapping to this disassembly")
{
DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread);
DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread);
@@ -6257,6 +6258,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly)
}
// rjf: find breakpoints mapping to this disassembly
ProfScope("find breakpoints mapping to this disassembly")
{
DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint);
for(DF_EntityNode *n = bps.first; n != 0; n = n->next)
@@ -6277,6 +6279,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly)
}
// rjf: find watch pins mapping to this disassembly
ProfScope("find watch pins mapping to this disassembly")
{
DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin);
for(DF_EntityNode *n = pins.first; n != 0; n = n->next)
@@ -7552,8 +7555,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Memory)
DF_VIEW_UI_FUNCTION_DEF(Memory)
{
Temp scratch = scratch_begin(0, 0);
ProfBeginFunction();
Temp scratch = scratch_begin(0, 0);
HS_Scope *hs_scope = hs_scope_open();
//////////////////////////////
//- rjf: unpack state
@@ -7755,7 +7759,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
U8 *visible_memory = 0;
{
Rng1U64 chunk_aligned_range_bytes = r1u64(AlignDownPow2(viz_range_bytes.min, KB(4)), AlignPow2(viz_range_bytes.max, KB(4)));
U64 current_memgen_idx = ctrl_memgen_idx();
U64 current_memgen_idx = ctrl_mem_gen();
B32 range_changed = (chunk_aligned_range_bytes.min != mv->last_viewed_memory_cache_range.min ||
chunk_aligned_range_bytes.max != mv->last_viewed_memory_cache_range.max);
B32 mem_changed = (current_memgen_idx != mv->last_viewed_memory_cache_memgen_idx);
@@ -7766,8 +7770,8 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
// rjf: try to read new memory for this range
U64 bytes_to_read = dim_1u64(chunk_aligned_range_bytes);
U8 *buffer = push_array_no_zero(scratch.arena, U8, bytes_to_read);
U64 half1_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0);
U64 half2_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2);
U64 half1_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0);
U64 half2_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2);
// rjf: worked? -> clear cache & store
if(half1_bytes_read+half2_bytes_read >= bytes_to_read)
@@ -8340,6 +8344,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
}
}
hs_scope_close(hs_scope);
scratch_end(scratch);
ProfEnd();
}
+1 -1
View File
@@ -144,7 +144,7 @@ struct DF_EntityListerItemArray
typedef struct DF_ProcessInfo DF_ProcessInfo;
struct DF_ProcessInfo
{
DEMON_ProcessInfo info;
DMN_ProcessInfo info;
B32 is_attached;
FuzzyMatchRangeList attached_match_ranges;
FuzzyMatchRangeList name_match_ranges;
+2 -2
View File
@@ -372,7 +372,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node
//- rjf: consume prefix operators
MG_StrExpr *leafmost_op = &mg_str_expr_nil;
for(;it < opl && !md_node_is_nil(it);)
for(;it != opl && !md_node_is_nil(it);)
{
MG_StrExprOp found_op = MG_StrExprOp_Null;
for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1);
@@ -431,7 +431,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node
}
//- rjf: parse binary operator extensions at this precedence level
for(;it < opl && !md_node_is_nil(it);)
for(;it != opl && !md_node_is_nil(it);)
{
// rjf: find binary op kind of `it`
MG_StrExprOp found_op = MG_StrExprOp_Null;
+9 -6
View File
@@ -1,13 +1,18 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Demon2 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] TLS eval correctness
// [x] freezing thread while running -> soft-halt
////////////////////////////////
//~ rjf: Frontend/UI Pass Tasks
//
// [x] hover-eval when window is not focused - maybe just start directly
// using mouse-move events here
// [x] CRT asserts - stepping over int 29 should work just like stepping over
// an int3
// [ ] committing needs to happen when navigating focus away for any reason
// [ ] better discoverability for view rules - have better help hover tooltip,
// info on arguments, and better autocomplete lister
@@ -79,8 +84,6 @@
// [ ] disasm animation & go-to-address
//
// [ ] visualize remapped files (via path map)
//
// [x] DBGI layer is case-sensitive even on case-insensitive systems
////////////////////////////////
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
+3 -3
View File
@@ -6,7 +6,7 @@
#define BUILD_VERSION_MAJOR 0
#define BUILD_VERSION_MINOR 9
#define BUILD_VERSION_PATCH 8
#define BUILD_VERSION_PATCH 9
#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#define BUILD_TITLE "The RAD Debugger"
#define OS_FEATURE_GRAPHICAL 1
@@ -43,7 +43,7 @@
#include "regs/raddbgi/regs_raddbgi.h"
#include "type_graph/type_graph.h"
#include "dbgi/dbgi.h"
#include "demon/demon_inc.h"
#include "demon2/demon2_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 "demon/demon_inc.c"
#include "demon2/demon2_inc.c"
#include "eval/eval_inc.c"
#include "unwind/unwind.c"
#include "ctrl/ctrl_inc.c"
+1 -1
View File
@@ -5,7 +5,7 @@
internal U64 regs_block_size_from_architecture(Architecture arch)
{
U64 result = 0;
U64 result = 8;
switch(arch)
{
default:{}break;
+1 -1
View File
@@ -421,7 +421,7 @@ regs_g_reg_code_x86_usage_kind_table:
{
`internal U64 regs_block_size_from_architecture(Architecture arch)`;
`{`;
`U64 result = 0;`;
`U64 result = 8;`;
`switch(arch)`;
`{`;
`default:{}break;`;
+2 -2
View File
@@ -46,7 +46,7 @@
#include "demon2/demon2_inc.h"
#include "eval/eval_inc.h"
#include "unwind/unwind.h"
#include "ctrl2/ctrl2_inc.h"
#include "ctrl/ctrl_inc.h"
//- rjf: [c]
#include "base/base_inc.c"
@@ -74,7 +74,7 @@
#include "demon2/demon2_inc.c"
#include "eval/eval_inc.c"
#include "unwind/unwind.c"
#include "ctrl2/ctrl2_inc.c"
#include "ctrl/ctrl_inc.c"
////////////////////////////////
//~ rjf: Entry Point
+2 -1
View File
@@ -2635,7 +2635,8 @@ ui_signal_from_box(UI_Box *box)
//- rjf: mouse is over this box's rect, no other hot key? -> set hot key, mark hovering
//
{
if(contains_2f32(rect, ui_state->mouse) &&
if(box->flags & UI_BoxFlag_MouseClickable &&
contains_2f32(rect, ui_state->mouse) &&
!contains_2f32(blacklist_rect, ui_state->mouse) &&
(ui_key_match(ui_state->hot_box_key, ui_key_zero()) || ui_key_match(ui_state->hot_box_key, box->key)) &&
(ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], ui_key_zero()) || ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], box->key)) &&