mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-11-14 02:03:27 -08:00
raddbg_server: checkpoint
This commit is contained in:
1 parent
bf000289db
commit
34a0ff4e80
6 files changed
+424
No files matched your search
@@ -195,6 +195,7 @@ pushd build
|
||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
||||
if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1
|
||||
if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1
|
||||
if "%raddbg_server%"=="1" set didbuild=1 && %compile% ..\src\raddbg_server\raddbg_server_main.c %compile_link% %out%raddbg_server.exe || exit /b 1
|
||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
||||
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
|
||||
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RADDBG_SERVER_H
|
||||
#define RADDBG_SERVER_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Messages (Client -> Server)
|
||||
|
||||
#define RDS_MSG_MAGIC 0x7273
|
||||
|
||||
typedef enum RDS_MsgKind
|
||||
{
|
||||
RDS_MsgKind_Null,
|
||||
|
||||
//- rjf: debuggee attaching/detaching ops
|
||||
RDS_MsgKind_Launch,
|
||||
RDS_MsgKind_Attach,
|
||||
RDS_MsgKind_Kill,
|
||||
RDS_MsgKind_Detach,
|
||||
|
||||
//- rjf: running ops
|
||||
RDS_MsgKind_Run,
|
||||
RDS_MsgKind_SingleStep,
|
||||
RDS_MsgKind_Halt,
|
||||
|
||||
//- rjf: memory ops
|
||||
RDS_MsgKind_MemoryReserve,
|
||||
RDS_MsgKind_MemoryCommit,
|
||||
RDS_MsgKind_MemoryDecommit,
|
||||
RDS_MsgKind_MemoryRelease,
|
||||
RDS_MsgKind_MemoryProtect,
|
||||
RDS_MsgKind_MemoryRead,
|
||||
RDS_MsgKind_MemoryWrite,
|
||||
|
||||
//- rjf: thread ops
|
||||
RDS_MsgKind_ThreadRegBlockRead,
|
||||
RDS_MsgKind_ThreadRegBlockWrite,
|
||||
RDS_MsgKind_ThreadGetModuleTLSVAddr,
|
||||
|
||||
//- rjf: system ops
|
||||
RDS_MsgKind_ListSystemProcesses,
|
||||
}
|
||||
RDS_MsgKind;
|
||||
|
||||
typedef U32 RDS_MsgFlags;
|
||||
enum
|
||||
{
|
||||
RDS_MsgFlag_InheritEnv = (1<<0),
|
||||
RDS_MsgFlag_DebugSubprocesses = (1<<1),
|
||||
RDS_MsgFlag_IgnorePreviousException = (1<<2),
|
||||
RDS_MsgFlag_RunEntitiesAreUnfrozen = (1<<3),
|
||||
RDS_MsgFlag_RunEntitiesAreProcesses = (1<<4),
|
||||
};
|
||||
|
||||
typedef struct RDS_Msg RDS_Msg;
|
||||
struct RDS_Msg
|
||||
{
|
||||
RDS_MsgKind kind;
|
||||
RDS_MsgFlags flags;
|
||||
U64 id;
|
||||
|
||||
//- rjf: general parameters
|
||||
Rng1U64 vaddr_range;
|
||||
AccessFlags access_flags;
|
||||
DMN_Handle entity;
|
||||
U64 pid;
|
||||
|
||||
//- rjf: process launching parameters
|
||||
String8List command_line;
|
||||
String8 path;
|
||||
String8List env;
|
||||
|
||||
//- rjf: running parameters
|
||||
DMN_TrapChunkList traps;
|
||||
DMN_HandleArray run_entities;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Responses (Server -> Client responses to messages)
|
||||
|
||||
typedef struct RDS_Response RDS_Response;
|
||||
struct RDS_Response
|
||||
{
|
||||
U64 id;
|
||||
String8 data;
|
||||
DMN_Handle entity;
|
||||
U64 pid;
|
||||
U64 demon_event_count;
|
||||
};
|
||||
|
||||
#endif // RADDBG_SERVER_H
|
||||
@@ -0,0 +1,300 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Options
|
||||
|
||||
#define BUILD_TITLE "The RAD Debugger Server"
|
||||
#define BUILD_CONSOLE_INTERFACE 1
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes
|
||||
|
||||
//- rjf: [h]
|
||||
#include "base/base_inc.h"
|
||||
#include "x64/x64_inc.h"
|
||||
#include "arch/arch_inc.h"
|
||||
#include "socket/socket_inc.h"
|
||||
#include "coff/coff.h"
|
||||
#include "coff/coff_parse.h"
|
||||
#include "pe/pe.h"
|
||||
#include "elf/elf.h"
|
||||
#include "gnu/gnu.h"
|
||||
#include "gnu/gnu_parse.h"
|
||||
#include "elf/elf_parse.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "raddbg_server/raddbg_server.h"
|
||||
|
||||
//- rjf: [c]
|
||||
#include "base/base_inc.c"
|
||||
#include "x64/x64_inc.c"
|
||||
#include "arch/arch_inc.c"
|
||||
#include "socket/socket_inc.c"
|
||||
#include "coff/coff.c"
|
||||
#include "coff/coff_parse.c"
|
||||
#include "pe/pe.c"
|
||||
#include "elf/elf.c"
|
||||
#include "gnu/gnu.c"
|
||||
#include "gnu/gnu_parse.c"
|
||||
#include "elf/elf_parse.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "raddbg_server/raddbg_server.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
typedef struct RDS_State RDS_State;
|
||||
struct RDS_State
|
||||
{
|
||||
Arena *arena;
|
||||
SOCK_Session sock_session;
|
||||
|
||||
//- rjf: client -> demon messages
|
||||
RWMutex c2d_rw_mutex;
|
||||
CondVar c2d_cv;
|
||||
Arena *c2d_arena;
|
||||
String8List c2d_msgs;
|
||||
|
||||
//- rjf: demon run state
|
||||
B32 demon_is_running;
|
||||
};
|
||||
|
||||
global RDS_State *rds_state = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Demon Thread
|
||||
|
||||
internal void
|
||||
dmn_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("dmn_thread");
|
||||
DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin();
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: get next messages
|
||||
//
|
||||
String8List msgs = {0};
|
||||
RWMutexScope(rds_state->c2d_rw_mutex, 1) for(;;)
|
||||
{
|
||||
if(rds_state->c2d_msgs.node_count != 0)
|
||||
{
|
||||
msgs = str8_list_copy(scratch.arena, &rds_state->c2d_msgs);
|
||||
MemoryZeroStruct(&rds_state->c2d_msgs);
|
||||
arena_clear(rds_state->c2d_arena);
|
||||
break;
|
||||
}
|
||||
cond_var_wait_rw_w(rds_state->c2d_cv, rds_state->c2d_rw_mutex, max_U64);
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: do messages
|
||||
//
|
||||
for(String8Node *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next)
|
||||
{
|
||||
//////////////////////////
|
||||
//- rjf: unpack message
|
||||
//
|
||||
String8 data = msg_n->string;
|
||||
U16 magic_maybe = 0;
|
||||
str8_deserial_read_struct(data, 0, &magic_maybe);
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: parse message
|
||||
//
|
||||
RDS_Msg msg = {0};
|
||||
if(magic_maybe == RDS_MSG_MAGIC)
|
||||
{
|
||||
U64 off = sizeof(magic_maybe);
|
||||
|
||||
// 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.vaddr_range);
|
||||
off += str8_deserial_read_struct(data, off, &msg.access_flags);
|
||||
off += str8_deserial_read_struct(data, off, &msg.entity);
|
||||
off += str8_deserial_read_struct(data, off, &msg.pid);
|
||||
|
||||
// rjf: read command line strings
|
||||
{
|
||||
U64 cmd_line_string_count = 0;
|
||||
off += str8_deserial_read_struct(data, off, &cmd_line_string_count);
|
||||
for EachIndex(idx, cmd_line_string_count)
|
||||
{
|
||||
String8 string = {0};
|
||||
off += str8_deserial_read_struct(data, off, &string.size);
|
||||
string = str8_substr(data, r1u64(off, off+string.size));
|
||||
str8_list_push(scratch.arena, &msg.command_line, string);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: read path
|
||||
{
|
||||
String8 string = {0};
|
||||
off += str8_deserial_read_struct(data, off, &string.size);
|
||||
string = str8_substr(data, r1u64(off, off+string.size));
|
||||
msg.path = string;
|
||||
}
|
||||
|
||||
// rjf: read environment strings
|
||||
{
|
||||
U64 env_string_count = 0;
|
||||
off += str8_deserial_read_struct(data, off, &env_string_count);
|
||||
for EachIndex(idx, env_string_count)
|
||||
{
|
||||
String8 string = {0};
|
||||
off += str8_deserial_read_struct(data, off, &string.size);
|
||||
string = str8_substr(data, r1u64(off, off+string.size));
|
||||
str8_list_push(scratch.arena, &msg.env, string);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: read traps
|
||||
{
|
||||
U64 trap_count = 0;
|
||||
off += str8_deserial_read_struct(data, off, &trap_count);
|
||||
for EachIndex(idx, trap_count)
|
||||
{
|
||||
DMN_Trap trap = {0};
|
||||
off += str8_deserial_read_struct(data, off, &trap.process);
|
||||
off += str8_deserial_read_struct(data, off, &trap.vaddr);
|
||||
off += str8_deserial_read_struct(data, off, &trap.id);
|
||||
off += str8_deserial_read_struct(data, off, &trap.flags);
|
||||
off += str8_deserial_read_struct(data, off, &trap.size);
|
||||
dmn_trap_chunk_list_push(scratch.arena, &msg.traps, trap_count, &trap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: do message
|
||||
//
|
||||
switch(msg.kind)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: debuggee attaching/detaching ops
|
||||
|
||||
case RDS_MsgKind_Launch:{}break;
|
||||
case RDS_MsgKind_Attach:{}break;
|
||||
case RDS_MsgKind_Kill:{}break;
|
||||
case RDS_MsgKind_Detach:{}break;
|
||||
|
||||
//- rjf: running ops
|
||||
|
||||
case RDS_MsgKind_Run:{}break;
|
||||
case RDS_MsgKind_SingleStep:{}break;
|
||||
case RDS_MsgKind_Halt:{}break;
|
||||
|
||||
//- rjf: memory ops
|
||||
|
||||
case RDS_MsgKind_MemoryReserve:{}break;
|
||||
case RDS_MsgKind_MemoryCommit:{}break;
|
||||
case RDS_MsgKind_MemoryDecommit:{}break;
|
||||
case RDS_MsgKind_MemoryRelease:{}break;
|
||||
case RDS_MsgKind_MemoryProtect:{}break;
|
||||
case RDS_MsgKind_MemoryRead:{}break;
|
||||
case RDS_MsgKind_MemoryWrite:{}break;
|
||||
|
||||
//- rjf: thread ops
|
||||
|
||||
case RDS_MsgKind_ThreadRegBlockRead:{}break;
|
||||
case RDS_MsgKind_ThreadRegBlockWrite:{}break;
|
||||
case RDS_MsgKind_ThreadGetModuleTLSVAddr:{}break;
|
||||
|
||||
//- rjf: system ops
|
||||
|
||||
case RDS_MsgKind_ListSystemProcesses:
|
||||
{
|
||||
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entry Point
|
||||
|
||||
internal void
|
||||
entry_point(CmdLine *cmd_line)
|
||||
{
|
||||
//- rjf: get port argument
|
||||
U64 port = 7273;
|
||||
{
|
||||
U64 port_maybe = 0;
|
||||
String8 port_arg_string = cmd_line_string(cmd_line, s("port"));
|
||||
if(try_u64_from_str8_c_rules(port_arg_string, &port_maybe))
|
||||
{
|
||||
port = port_maybe;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: set up shared state
|
||||
Arena *arena = arena_alloc();
|
||||
rds_state = push_array(arena, RDS_State, 1);
|
||||
rds_state->arena = arena;
|
||||
rds_state->sock_session = sock_session_open((U16)port, 0);
|
||||
rds_state->c2d_rw_mutex = rw_mutex_alloc();
|
||||
rds_state->c2d_cv = cond_var_alloc();
|
||||
rds_state->c2d_arena = arena_alloc();
|
||||
|
||||
//- rjf: launch demon thread
|
||||
thread_launch(dmn_thread__entry_point, 0);
|
||||
|
||||
//- rjf: loop: wait for messages, issue commands to demon
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next message from client
|
||||
fprintf(stderr, "[waiting for message]\n");
|
||||
SOCK_Protocol protocol = SOCK_Protocol_TCP;
|
||||
SOCK_Endpoint endpoint = {0};
|
||||
String8 data = {0};
|
||||
sock_recv(scratch.arena, rds_state->sock_session, &protocol, &endpoint, &data, max_U64);
|
||||
|
||||
//- rjf: parse magic prefix
|
||||
U16 magic_maybe = 0;
|
||||
str8_deserial_read_struct(data, 0, &magic_maybe);
|
||||
|
||||
//- rjf: log message info
|
||||
{
|
||||
String8 endpoint_string = sock_string_from_endpoint(scratch.arena, endpoint);
|
||||
fprintf(stderr, "[got message]\n");
|
||||
fprintf(stderr, " sender: %.*s\n", str8_varg(endpoint_string));
|
||||
fprintf(stderr, " magic: 0x%x\n", (int)magic_maybe);
|
||||
}
|
||||
|
||||
//- rjf: the only kind of message we handle on the main thread is halting,
|
||||
// since we need to interrupt the actual controller. just look for that one
|
||||
// code here, and handle it - otherwise, all we need to do is send the message
|
||||
// blob to the demon thread.
|
||||
RDS_MsgKind peek_kind = RDS_MsgKind_Null;
|
||||
if(magic_maybe == RDS_MSG_MAGIC)
|
||||
{
|
||||
str8_deserial_read_struct(data, 2, &peek_kind);
|
||||
if(peek_kind == RDS_MsgKind_Halt && rds_state->demon_is_running)
|
||||
{
|
||||
dmn_halt(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: not halt? -> okay, send to demon thread, if it's ready.
|
||||
if(magic_maybe == RDS_MSG_MAGIC && peek_kind != RDS_MsgKind_Halt && !rds_state->demon_is_running)
|
||||
{
|
||||
RWMutexScope(rds_state->c2d_rw_mutex, 1)
|
||||
{
|
||||
str8_list_push(rds_state->c2d_arena, &rds_state->c2d_msgs, data);
|
||||
}
|
||||
cond_var_broadcast(rds_state->c2d_cv);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
@@ -96,3 +96,31 @@ sock_endpoint_from_string(String8 address_and_port)
|
||||
SOCK_Endpoint ep = sock_endpoint_from_string_port(addr, port);
|
||||
return ep;
|
||||
}
|
||||
|
||||
internal String8
|
||||
sock_string_from_endpoint(Arena *arena, SOCK_Endpoint endpoint)
|
||||
{
|
||||
String8 result = {0};
|
||||
switch(endpoint.kind)
|
||||
{
|
||||
default:{}break;
|
||||
case SOCK_EndpointKind_IPv4:
|
||||
{
|
||||
result = str8f(arena, "%i.%i.%i.%i:%i", (int)endpoint.address_u8[0], (int)endpoint.address_u8[1], (int)endpoint.address_u8[2], (int)endpoint.address_u8[3], (int)endpoint.port);
|
||||
}break;
|
||||
case SOCK_EndpointKind_IPv6:
|
||||
{
|
||||
result = str8f(arena, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%i",
|
||||
(int)endpoint.address_u16[0],
|
||||
(int)endpoint.address_u16[1],
|
||||
(int)endpoint.address_u16[2],
|
||||
(int)endpoint.address_u16[3],
|
||||
(int)endpoint.address_u16[4],
|
||||
(int)endpoint.address_u16[5],
|
||||
(int)endpoint.address_u16[6],
|
||||
(int)endpoint.address_u16[7],
|
||||
(int)endpoint.port);
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -59,6 +59,7 @@ typedef SOCK_WAKEUP_FUNCTION_DEF(SOCK_WakeupFunctionType);
|
||||
|
||||
internal SOCK_Endpoint sock_endpoint_from_string_port(String8 address, U16 port);
|
||||
internal SOCK_Endpoint sock_endpoint_from_string(String8 address_and_port);
|
||||
internal String8 sock_string_from_endpoint(Arena *arena, SOCK_Endpoint endpoint);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @per_os_impl Top-Level Layer Calls
|
||||
|
||||
Reference in new issue
Block a user