Skip to content

Commit

Permalink
Initial GDB support
Browse files Browse the repository at this point in the history
Janky, crashy and still not fully implemented, but kinda works.
  • Loading branch information
hezi committed Jul 28, 2024
1 parent 7aa4f94 commit b726eaf
Show file tree
Hide file tree
Showing 5 changed files with 636 additions and 1 deletion.
11 changes: 11 additions & 0 deletions include/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ bool DEBUG_ExitLoop(void);
void DEBUG_RefreshPage(char scroll);
Bitu DEBUG_EnableDebugger(void);

// Exposed for GDB server
uint32_t DEBUG_GetRegister(int reg);
void DEBUG_SetRegister(int reg, uint32_t value);
uint8_t DEBUG_ReadMemory(uint32_t address);
void DEBUG_WriteMemory(uint32_t address, uint8_t value);
void DEBUG_Step();
void DEBUG_Continue();
bool DEBUG_SetBreakpoint(uint32_t address);
bool DEBUG_RemoveBreakpoint(uint32_t address);
void DEBUG_InitGDBStub(int port);

extern Bitu cycle_count;
extern Bitu debugCallback;

Expand Down
59 changes: 59 additions & 0 deletions include/gdbserver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "dosbox.h"
#include <string>
#include <vector>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include "debug.h"


static inline uint32_t swap32(uint32_t x);
static inline uint16_t swap16(uint16_t x);

class GDBServer {
public:
GDBServer(int port) : port(port), server_fd(-1), client_fd(-1) {}
~GDBServer() {
if (client_fd != -1) close(client_fd);
if (server_fd != -1) close(server_fd);
}
void run();
void signal_breakpoint();

private:
int port;
int server_fd, client_fd;
bool noack_mode = false;
bool processing = false;

void setup_socket();
void wait_for_client();
void handle_client();
bool perform_handshake();
std::string receive_packet();
void send_packet(const std::string& packet);
void process_command(const std::string& cmd);

// GDB command handlers
void handle_read_register(const std::string& cmd);
void handle_read_registers();
void handle_write_registers(const std::string& args);
void handle_read_memory(const std::string& args);
void handle_write_memory(const std::string& args);
void handle_step();
void handle_continue();
void handle_breakpoint(const std::string& args);
void handle_query(const std::string& args);
void handle_v_packets(const std::string& cmd);

// Helper functions
std::string hex_encode(const std::string& input);
std::string hex_decode(const std::string& input);
uint8_t hex_to_int(char c);
};

2 changes: 1 addition & 1 deletion src/debug/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AM_CPPFLAGS = -I$(top_srcdir)/include

noinst_LIBRARIES = libdebug.a
libdebug_a_SOURCES = debug.cpp debug_gui.cpp debug_disasm.cpp debug_inc.h disasm_tables.h debug_win32.cpp
libdebug_a_SOURCES = gdbserver.cpp debug.cpp debug_gui.cpp debug_disasm.cpp debug_inc.h disasm_tables.h debug_win32.cpp
109 changes: 109 additions & 0 deletions src/debug/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <iomanip>
#include <string>
#include <sstream>
#include <thread>
using namespace std;

#include "debug.h"
Expand All @@ -43,6 +44,7 @@ using namespace std;
#include "mapper.h"
#include "pc98_gdc.h"
#include "callback.h"
#include "gdbserver.h"
#include "inout.h"
#include "paging.h"
#include "shell.h"
Expand Down Expand Up @@ -5258,6 +5260,7 @@ void DEBUG_ReinitCallback(void) {

void DEBUG_Init() {
LOG(LOG_MISC, LOG_DEBUG)("Initializing debug system");
DEBUG_InitGDBStub(2159);

/* Reset code overview and input line */
memset((void*)&codeViewData,0,sizeof(codeViewData));
Expand Down Expand Up @@ -5650,6 +5653,112 @@ void DEBUG_StopLog(void) {

#endif // HEAVY DEBUG

uint32_t DEBUG_GetRegister(int reg) {
switch(reg) {
case 0: return reg_eax;
case 1: return reg_ecx;
case 2: return reg_edx;
case 3: return reg_ebx;
case 4: return reg_esp;
case 5: return reg_ebp;
case 6: return reg_esi;
case 7: return reg_edi;
case 8: return reg_eip;
case 9: return reg_flags;
case 10: return SegValue(cs);
case 11: return SegValue(ss);
case 12: return SegValue(ds);
case 13: return SegValue(es);
case 14: return SegValue(fs);
case 15: return SegValue(gs);
default: return 0;
}
}

void DEBUG_SetRegister(int reg, uint32_t value) {
switch(reg) {
case 0: reg_eax = value; break;
case 1: reg_ecx = value; break;
case 2: reg_edx = value; break;
case 3: reg_ebx = value; break;
case 4: reg_esp = value; break;
case 5: reg_ebp = value; break;
case 6: reg_esi = value; break;
case 7: reg_edi = value; break;
case 8: reg_eip = value; break;
case 9: reg_flags = value; break;
case 10: SegSet16(cs, value); break;
case 11: SegSet16(ss, value); break;
case 12: SegSet16(ds, value); break;
case 13: SegSet16(es, value); break;
case 14: SegSet16(fs, value); break;
case 15: SegSet16(gs, value); break;
}
}

uint8_t DEBUG_ReadMemory(uint32_t address) {
uint8_t value;
if (mem_readb_checked(address, &value)) {
// Memory read failed
return 0;
}
return value;
}

void DEBUG_WriteMemory(uint32_t address, uint8_t value) {
mem_writeb_checked(address, value);
}

void DEBUG_Step() {
StepOver();
return;

exitLoop = false;
debugging = true;
CBreakpoint::AddBreakpoint(SegValue(cs), reg_eip, true);
CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
debugging = false;

// Execute one instruction
DOSBOX_SetNormalLoop();
return;
}

void DEBUG_Continue() {
exitLoop = false;
debugging = false;
CBreakpoint::ActivateBreakpoints();
DOSBOX_SetNormalLoop();
return;
}

bool DEBUG_SetBreakpoint(uint32_t address) {
uint16_t seg = address >> 16;
uint16_t off = address & 0xFFFF;
DEBUG_ShowMsg("Adding Breakpoint %x:%x", seg, off);
return CBreakpoint::AddBreakpoint(seg, off, false);
}

bool DEBUG_RemoveBreakpoint(uint32_t address) {
uint16_t seg = address >> 16;
uint16_t off = address & 0xFFFF;
DEBUG_ShowMsg("Removing Breakpoint %x:%x", seg, off);
return CBreakpoint::DeleteBreakpoint(seg, off);
}

// Add this function to handle GDB server initialization
void DEBUG_InitGDBStub(int port) {
// This function should be called from dosbox.cpp when the -gdb option is used
GDBServer* gdbServer = new GDBServer(port);

// Run the GDB server in a separate thread
std::thread gdbThread([gdbServer]() {
gdbServer->run();
});

gdbThread.detach(); // Let the thread run independently
}


#endif // DEBUG

Expand Down
Loading

0 comments on commit b726eaf

Please sign in to comment.