debug server checkpoint

This commit is contained in:
Ryan Fleury committed 2026-10-09 07:49:24 -07:00
1 parent b6d8c3fd9e
commit c269823e15
12 files changed
+94 -220

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@ commands =
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry debug", .linux = "./build.sh raddbg debug meta", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg_server telemetry debug", .linux = "./build.sh raddbg debug meta", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
-27
View File
@@ -1,33 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Local Host Demon Interface
D_DemonInterface d_local_demon =
{
dmn_ctrl_exclusive_access_begin,
dmn_ctrl_exclusive_access_end,
dmn_ctrl_launch,
dmn_ctrl_attach,
dmn_ctrl_kill,
dmn_ctrl_detach,
dmn_ctrl_run,
dmn_halt,
dmn_access_open,
dmn_access_close,
dmn_process_memory_reserve,
dmn_process_memory_commit,
dmn_process_memory_decommit,
dmn_process_memory_release,
dmn_process_memory_protect,
dmn_process_read,
dmn_process_write,
dmn_thread_read_reg_block,
dmn_thread_write_reg_block,
dmn_thread_get_module_tls_vaddr,
};
////////////////////////////////
//~ rjf: Basic Type Functions
-62
View File
@@ -313,68 +313,6 @@ struct D_ModuleReqCacheNode
#define D_WAKEUP_FUNCTION_DEF(name) void name(void)
typedef D_WAKEUP_FUNCTION_DEF(D_WakeupFunctionType);
////////////////////////////////
//~ rjf: Demon Interface V-Table
typedef struct D_DemonInterface D_DemonInterface;
struct D_DemonInterface
{
//- rjf: control
void (*ctrl_exclusive_access_begin)(void);
void (*ctrl_exclusive_access_end)(void);
U32 (*launch)(DMN_CtrlCtx *ctx, ProcessLaunchParams *params);
B32 (*attach)(DMN_CtrlCtx *ctx, U32 pid);
B32 (*kill)(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code);
B32 (*detach)(DMN_CtrlCtx *ctx, DMN_Handle process);
DMN_EventList (*run)(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls);
//- rjf: halting
void (*halt)(U64 code, U64 user_data);
//- rjf: non-blocking-control-thread access barriers
B32 (*access_open)(void);
void (*access_close)(void);
//- rjf: process memory
U64 (*reserve_memory)(DMN_Handle process, U64 vaddr, U64 size);
void (*commit_memory)(DMN_Handle process, U64 vaddr, U64 size);
void (*decommit_memory)(DMN_Handle process, U64 vaddr, U64 size);
void (*release_memory)(DMN_Handle process, U64 vaddr, U64 size);
void (*protect_memory)(DMN_Handle process, U64 vaddr, U64 size, AccessFlags flags);
U64 (*read_memory)(DMN_Handle process, Rng1U64 range, void *dst);
B32 (*write_memory)(DMN_Handle process, Rng1U64 range, void *src);
//- rjf: threads
B32 (*thread_read_reg_block)(DMN_Handle thread, void *dst);
B32 (*thread_write_reg_block)(DMN_Handle thread, void *src);
B32 (*thread_get_module_tls_vaddr)(DMN_Handle thread, DMN_Handle module, U64 *vaddr_out);
};
typedef struct D_DemonState D_DemonState;
struct D_DemonState
{
D_DemonState *next;
D_DemonState *prev;
D_DemonID id;
D_DemonInterface *fn;
Arena *event_arena;
DMN_EventList events;
};
typedef struct D_DemonStateSlot D_DemonStateSlot;
struct D_DemonStateSlot
{
D_DemonState *first;
D_DemonState *last;
};
typedef struct D_DemonCache D_DemonCache;
struct D_DemonCache
{
U64 slots_count;
D_DemonStateSlot *slots;
};
////////////////////////////////
//~ rjf: Main State Types
+15 -1
View File
@@ -20,7 +20,7 @@ ds_msg_from_serialized(Arena *arena, String8 data)
// rjf: read flat parts
off += str8_deserial_read_struct(data, off, &msg.kind);
off += str8_deserial_read_struct(data, off, &msg.flags);
off += str8_deserial_read_struct(data, off, &msg.id);
off += str8_deserial_read_struct(data, off, &msg.msg_id);
off += str8_deserial_read_struct(data, off, &msg.vaddr_range);
off += str8_deserial_read_struct(data, off, &msg.access_flags);
off += str8_deserial_read_struct(data, off, &msg.entity);
@@ -92,3 +92,17 @@ ds_serialized_from_msg(Arena *arena, DS_Msg *msg)
String8 result = str8_list_join(arena, &srl, 0);
return result;
}
internal DS_Response
ds_response_from_serialized(Arena *arena, String8 data)
{
DS_Response result = {0};
return result;
}
internal String8
ds_serialized_from_response(Arena *arena, DS_Response *response)
{
String8 result = {0};
return result;
}
+15 -22
View File
@@ -60,13 +60,14 @@ struct DS_Msg
{
DS_MsgKind kind;
DS_MsgFlags flags;
U64 id;
U64 msg_id;
//- rjf: general parameters
Rng1U64 vaddr_range;
AccessFlags access_flags;
DMN_Handle entity;
U64 pid;
U64 code;
//- rjf: process launching parameters
String8List command_line;
@@ -78,41 +79,33 @@ struct DS_Msg
DMN_HandleArray run_entities;
};
////////////////////////////////
//~ rjf: Server Instance
typedef enum DS_InstKind
{
DS_InstKind_Host,
DS_InstKind_Remote,
}
DS_InstKind;
typedef struct DS_Inst DS_Inst;
struct DS_Inst
{
DS_InstKind kind;
U64 u64[1];
};
////////////////////////////////
//~ rjf: Responses (Server -> Client responses to messages)
typedef struct DS_Response DS_Response;
struct DS_Response
{
U64 id;
DS_Inst inst;
U64 msg_id;
String8 data;
DMN_Handle entity;
U64 pid;
B32 good;
DMN_EventList events;
};
typedef struct DS_ResponseNode DS_ResponseNode;
struct DS_ResponseNode
{
DS_ResponseNode *next;
DS_Response v;
};
////////////////////////////////
//~ rjf: Message Parsing
//~ rjf: Message/Response Parsing
internal DS_Msg ds_msg_from_serialized(Arena *arena, String8 data);
internal String8 ds_serialized_from_msg(Arena *arena, DS_Msg msg);
internal String8 ds_serialized_from_msg(Arena *arena, DS_Msg *msg);
internal DS_Response ds_response_from_serialized(Arena *arena, String8 data);
internal String8 ds_serialized_from_response(Arena *arena, DS_Response *response);
#endif // DBG_SERVER_H
-24
View File
@@ -1,24 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
ds_push_msg(GuardedRing *out_ring, DS_Inst inst, DS_Msg *msg, U64 endt_us)
{
B32 result = 0;
switch(inst.kind)
{
default:{}break;
case DS_InstKind_Host:
{
result = ds_push_msg__host(out_ring, msg, endt_us);
}break;
}
return result;
}
internal B32
ds_pop_response(Arena *arena, GuardedRing *out_ring, DS_Response *response_out, U64 endt_us)
{
B32 result = 0;
return result;
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DBG_SERVER_CLIENT_H
#define DBG_SERVER_CLIENT_H
////////////////////////////////
//~ rjf: Messages/Responses
internal B32 ds_push_msg(GuardedRing *out_ring, DS_Inst inst, DS_Msg *msg, U64 endt_us);
internal B32 ds_pop_response(Arena *arena, GuardedRing *out_ring, DS_Response *response_out, U64 endt_us);
#endif // DBG_SERVER_CLIENT_H
-28
View File
@@ -1,28 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
ds_push_msg__host(GuardedRing *out_ring, DS_Msg *msg, U64 endt_us)
{
B32 result = 1;
switch(msg->kind)
{
default:{}break;
//- rjf: launching
case DS_MsgKind_Launch:
{
ProcessLaunchParams params = {0};
{
params.cmd_line = msg->command_line;
params.path = msg->path;
params.env = msg->env;
params.inherit_env = !!(msg->flags & DS_MsgFlag_InheritEnv);
params.debug_subprocesses = !!(msg->flags & DS_MsgFlag_DebugSubprocesses);
}
U32 pid = dmn_ctrl_launch(0, &params);
}break;
}
return result;
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DBG_SERVER_HOST_H
#define DBG_SERVER_HOST_H
typedef struct DS_HostState DS_HostState;
struct DS_HostState
{
Arena *arena;
};
internal B32 ds_push_msg__host(GuardedRing *out_ring, DS_Msg *msg, U64 endt_us);
#endif // DBG_SERVER_HOST_H
-2
View File
@@ -1,2 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-7
View File
@@ -1,7 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DBG_SERVER_REMOTE_H
#define DBG_SERVER_REMOTE_H
#endif // DBG_SERVER_REMOTE_H
+63 -18
View File
@@ -23,7 +23,7 @@
#include "gnu/gnu_parse.h"
#include "elf/elf_parse.h"
#include "demon/demon_inc.h"
#include "raddbg_server/raddbg_server.h"
#include "dbg_server/dbg_server.h"
//- rjf: [c]
#include "base/base_inc.c"
@@ -38,7 +38,7 @@
#include "gnu/gnu_parse.c"
#include "elf/elf_parse.c"
#include "demon/demon_inc.c"
#include "raddbg_server/raddbg_server.c"
#include "dbg_server/dbg_server.c"
////////////////////////////////
//~ rjf: Globals
@@ -90,27 +90,72 @@ dmn_thread__entry_point(void *p)
}
////////////////////////////
//- rjf: do messages
//- rjf: do messages, push responses
//
for(String8Node *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next)
{
RDS_Msg msg = rds_msg_from_data(scratch.arena, msg_n->string);
//- rjf: unpack message
DS_Msg msg = ds_msg_from_serialized(scratch.arena, msg_n->string);
//- rjf: do action, get response
DS_Response response = {0};
switch(msg.kind)
{
default:{}break;
//- rjf: debuggee attaching/detaching ops
//- rjf: launching
case DS_MsgKind_Launch:
{
ProcessLaunchParams params = {0};
{
params.cmd_line = msg.command_line;
params.path = msg.path;
params.env = msg.env;
params.inherit_env = !!(msg.flags & DS_MsgFlag_InheritEnv);
params.debug_subprocesses = !!(msg.flags & DS_MsgFlag_DebugSubprocesses);
}
response.pid = dmn_ctrl_launch(ctrl_ctx, &params);
}break;
case RDS_MsgKind_Launch:{}break;
case RDS_MsgKind_Attach:{}break;
case RDS_MsgKind_Kill:{}break;
case RDS_MsgKind_Detach:{}break;
//- rjf: attaching
case DS_MsgKind_Attach:
{
response.good = dmn_ctrl_attach(ctrl_ctx, msg.pid);
}break;
//- rjf: killing
case DS_MsgKind_Kill:
{
response.good = dmn_ctrl_kill(ctrl_ctx, msg.entity, (U32)msg.code);
}break;
//- rjf: detaching
case DS_MsgKind_Detach:
{
response.good = dmn_ctrl_detach(ctrl_ctx, msg.entity);
}break;
//- rjf: running ops
case RDS_MsgKind_Run:{}break;
case RDS_MsgKind_SingleStep:{}break;
case DS_MsgKind_Run:
case DS_MsgKind_SingleStep:
{
DMN_RunCtrls ctrls = {0};
{
ctrls.priority_thread = msg.entity;
ctrls.single_step_thread = (msg.kind == DS_MsgKind_SingleStep) ? msg.entity : dmn_handle_zero();
ctrls.run_entities = msg.run_entities.handles;
ctrls.run_entity_count = msg.run_entities.count;
ctrls.traps = msg.traps;
ctrls.ignore_previous_exception = !!(msg.flags & DS_MsgFlag_IgnorePreviousException);
ctrls.run_entities_are_unfrozen = !!(msg.flags & DS_MsgFlag_RunEntitiesAreUnfrozen);
ctrls.run_entities_are_processes = !!(msg.flags & DS_MsgFlag_RunEntitiesAreProcesses);
};
response.events = dmn_ctrl_run(scratch.arena, ctrl_ctx, &ctrls);
}break;
}
//- rjf: pack response & push
String8 data = ds_serialized_from_response(scratch.arena, &response);
}
scratch_end(scratch);
@@ -176,17 +221,17 @@ entry_point(CmdLine *cmd_line)
// attaching, detaching, and so on. other operations, like reading/writing
// memory/registers, listing processes, and halting, we want to just do
// on the main thread without interrupting the demon at all.
RDS_MsgKind peek_kind = RDS_MsgKind_Null;
if(magic_maybe == RDS_MSG_MAGIC)
DS_MsgKind peek_kind = DS_MsgKind_Null;
if(magic_maybe == DS_MSG_MAGIC)
{
str8_deserial_read_struct(data, 2, &peek_kind);
if(peek_kind < RDS_MsgKind_DemonThreadHandledFirst || RDS_MsgKind_DemonThreadHandledLast < peek_kind)
if(peek_kind < DS_MsgKind_Launch || DS_MsgKind_SingleStep < peek_kind)
{
RDS_Msg msg = rds_msg_from_data(scratch.arena, data);
DS_Msg msg = ds_msg_from_serialized(scratch.arena, data);
switch(msg.kind)
{
default:{}break;
case RDS_MsgKind_Halt:
case DS_MsgKind_Halt:
{
dmn_halt(0, 0);
}break;
@@ -195,7 +240,7 @@ entry_point(CmdLine *cmd_line)
}
//- rjf: not handled by main thread? -> okay, send to demon thread, if it's ready.
if(magic_maybe == RDS_MSG_MAGIC && !rds_state->demon_is_running && (RDS_MsgKind_DemonThreadHandledFirst <= peek_kind && peek_kind <= RDS_MsgKind_DemonThreadHandledLast))
if(magic_maybe == DS_MSG_MAGIC && !rds_state->demon_is_running && (DS_MsgKind_Launch <= peek_kind && peek_kind <= DS_MsgKind_SingleStep))
{
RWMutexScope(rds_state->c2d_rw_mutex, 1)
{