GDB Server: fix and cleanup

Move source files to Emu/GDB.cpp, GDB.h
Remove "WITH_GDB" option, enable GDB Server by default.
Change class name to gdb_thread.
Alias for external access gdb_server.
Change config option name to "GDB Server"
Bind on 127.0.0.1 by default.
This commit is contained in:
Nekotekina 2019-10-08 03:19:59 +03:00
parent 9d4de51cb6
commit a29d4150df
10 changed files with 192 additions and 208 deletions

View File

@ -12,7 +12,6 @@ elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
endif() endif()
endif() endif()
option(WITH_GDB "WITH_GDB" OFF)
option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON) option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON)
option(WITH_LLVM "Enable usage of LLVM library" ON) option(WITH_LLVM "Enable usage of LLVM library" ON)
option(BUILD_LLVM_SUBMODULE "Build LLVM from git submodule" ON) option(BUILD_LLVM_SUBMODULE "Build LLVM from git submodule" ON)
@ -28,10 +27,6 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/rpcs3/cmake_modules")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
if (WITH_GDB)
add_definitions(-DWITH_GDB_DEBUGGER)
endif()
if (NOT CMAKE_BUILD_TYPE) if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release") message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")

View File

@ -2,6 +2,7 @@
IdManager.cpp IdManager.cpp
System.cpp System.cpp
VFS.cpp VFS.cpp
GDB.cpp
) )
target_link_libraries(rpcs3_emu target_link_libraries(rpcs3_emu
@ -24,7 +25,6 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/Config.cpp ../../Utilities/Config.cpp
../../Utilities/dynamic_library.cpp ../../Utilities/dynamic_library.cpp
../../Utilities/File.cpp ../../Utilities/File.cpp
../../Utilities/GDBDebugServer.cpp
../../Utilities/JIT.cpp ../../Utilities/JIT.cpp
../../Utilities/Log.cpp ../../Utilities/Log.cpp
../../Utilities/LUrlParser.cpp ../../Utilities/LUrlParser.cpp

View File

@ -4,7 +4,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/vm_locking.h" #include "Emu/Memory/vm_locking.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Utilities/GDBDebugServer.h" #include "Emu/GDB.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
@ -194,12 +194,10 @@ cpu_thread::cpu_thread(u32 id)
bool cpu_thread::check_state() noexcept bool cpu_thread::check_state() noexcept
{ {
#ifdef WITH_GDB_DEBUGGER
if (state & cpu_flag::dbg_pause) if (state & cpu_flag::dbg_pause)
{ {
fxm::get<GDBDebugServer>()->pause_from(this); g_fxo->get<gdb_server>()->pause_from(this);
} }
#endif
bool cpu_sleep_called = false; bool cpu_sleep_called = false;
bool cpu_flag_memory = false; bool cpu_flag_memory = false;

View File

@ -13,7 +13,7 @@
#include "SPURecompiler.h" #include "SPURecompiler.h"
#include "lv2/sys_sync.h" #include "lv2/sys_sync.h"
#include "lv2/sys_prx.h" #include "lv2/sys_prx.h"
#include "Utilities/GDBDebugServer.h" #include "Emu/GDB.h"
#ifdef LLVM_AVAILABLE #ifdef LLVM_AVAILABLE
#include "restore_new.h" #include "restore_new.h"
@ -329,9 +329,9 @@ static bool ppu_break(ppu_thread& ppu, ppu_opcode_t op)
{ {
// Pause and wait if necessary // Pause and wait if necessary
bool status = ppu.state.test_and_set(cpu_flag::dbg_pause); bool status = ppu.state.test_and_set(cpu_flag::dbg_pause);
#ifdef WITH_GDB_DEBUGGER
fxm::get<GDBDebugServer>()->pause_from(&ppu); g_fxo->get<gdb_server>()->pause_from(&ppu);
#endif
if (!status && ppu.check_state()) if (!status && ppu.check_state())
{ {
return false; return false;

View File

@ -1,8 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#ifdef WITH_GDB_DEBUGGER
#include "GDBDebugServer.h" #include "GDB.h"
#include "Log.h" #include "Utilities/Log.h"
#include <algorithm> #include <algorithm>
#include "Emu/Memory/vm.h" #include "Emu/Memory/vm.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -12,8 +11,18 @@
#include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/RawSPUThread.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#ifndef _WIN32 #ifdef _WIN32
#include "fcntl.h" #include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#endif #endif
extern void ppu_set_breakpoint(u32 addr); extern void ppu_set_breakpoint(u32 addr);
@ -21,31 +30,12 @@ extern void ppu_remove_breakpoint(u32 addr);
LOG_CHANNEL(gdbDebugServer); LOG_CHANNEL(gdbDebugServer);
int sock_init(void)
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1, 1), &wsa_data);
#else
return 0;
#endif
}
int sock_quit(void)
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}
#ifndef _WIN32 #ifndef _WIN32
int closesocket(socket_t s) { int closesocket(int s)
{
return close(s); return close(s);
} }
const int SOCKET_ERROR = -1;
const socket_t INVALID_SOCKET = -1;
#define sscanf_s sscanf #define sscanf_s sscanf
#define HEX_U32 "x" #define HEX_U32 "x"
#define HEX_U64 "lx" #define HEX_U64 "lx"
@ -54,7 +44,24 @@ const socket_t INVALID_SOCKET = -1;
#define HEX_U64 "llx" #define HEX_U64 "llx"
#endif #endif
bool check_errno_again() { struct gdb_cmd
{
std::string cmd;
std::string data;
u8 checksum;
};
class wrong_checksum_exception : public std::runtime_error
{
public:
wrong_checksum_exception(char const* const message)
: runtime_error(message)
{
}
};
bool check_errno_again()
{
#ifdef _WIN32 #ifdef _WIN32
int err = GetLastError(); int err = GetLastError();
return (err == WSAEWOULDBLOCK); return (err == WSAEWOULDBLOCK);
@ -94,11 +101,12 @@ u64 hex_to_u64(std::string val) {
return result; return result;
} }
void GDBDebugServer::start_server() void gdb_thread::start_server()
{ {
server_socket = socket(AF_INET, SOCK_STREAM, 0); server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == INVALID_SOCKET) { if (server_socket == -1)
{
gdbDebugServer.error("Error creating server socket"); gdbDebugServer.error("Error creating server socket");
return; return;
} }
@ -116,33 +124,38 @@ void GDBDebugServer::start_server()
sockaddr_in server_saddr; sockaddr_in server_saddr;
server_saddr.sin_family = AF_INET; server_saddr.sin_family = AF_INET;
int port = g_cfg.misc.gdb_server_port; int port = 2345;
server_saddr.sin_port = htons(port); server_saddr.sin_port = htons(port);
server_saddr.sin_addr.s_addr = htonl(INADDR_ANY); server_saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
err = bind(server_socket, (struct sockaddr *) &server_saddr, sizeof(server_saddr)); err = bind(server_socket, (struct sockaddr *) &server_saddr, sizeof(server_saddr));
if (err == SOCKET_ERROR) { if (err == -1)
{
gdbDebugServer.error("Error binding to port %d", port); gdbDebugServer.error("Error binding to port %d", port);
return; return;
} }
err = listen(server_socket, 1); err = listen(server_socket, 1);
if (err == SOCKET_ERROR) { if (err == -1)
{
gdbDebugServer.error("Error listening on port %d", port); gdbDebugServer.error("Error listening on port %d", port);
return; return;
} }
gdbDebugServer.success("GDB Debug Server listening on port %d", port); gdbDebugServer.notice("GDB Debug Server listening on port %d", port);
} }
int GDBDebugServer::read(void * buf, int cnt) int gdb_thread::read(void* buf, int cnt)
{ {
while (!stop) { while (!Emu.IsStopped())
{
int result = recv(client_socket, reinterpret_cast<char*>(buf), cnt, 0); int result = recv(client_socket, reinterpret_cast<char*>(buf), cnt, 0);
if (result == SOCKET_ERROR) { if (result == -1)
if (check_errno_again()) { {
thread_ctrl::wait_for(50); if (check_errno_again())
{
thread_ctrl::wait_for(5000);
continue; continue;
} }
@ -154,7 +167,7 @@ int GDBDebugServer::read(void * buf, int cnt)
return 0; return 0;
} }
char GDBDebugServer::read_char() char gdb_thread::read_char()
{ {
char result; char result;
int cnt = read(&result, 1); int cnt = read(&result, 1);
@ -164,7 +177,7 @@ char GDBDebugServer::read_char()
return result; return result;
} }
u8 GDBDebugServer::read_hexbyte() u8 gdb_thread::read_hexbyte()
{ {
std::string s = ""; std::string s = "";
s += read_char(); s += read_char();
@ -172,7 +185,7 @@ u8 GDBDebugServer::read_hexbyte()
return hex_to_u8(s); return hex_to_u8(s);
} }
void GDBDebugServer::try_read_cmd(gdb_cmd & out_cmd) void gdb_thread::try_read_cmd(gdb_cmd& out_cmd)
{ {
char c = read_char(); char c = read_char();
//interrupt //interrupt
@ -228,32 +241,39 @@ void GDBDebugServer::try_read_cmd(gdb_cmd & out_cmd)
} }
} }
bool GDBDebugServer::read_cmd(gdb_cmd & out_cmd) bool gdb_thread::read_cmd(gdb_cmd& out_cmd)
{ {
while (true) { while (true)
try { {
try
{
try_read_cmd(out_cmd); try_read_cmd(out_cmd);
ack(true); ack(true);
return true; return true;
} }
catch (wrong_checksum_exception) { catch (const wrong_checksum_exception&)
{
ack(false); ack(false);
} }
catch (std::runtime_error e) { catch (const std::runtime_error& e)
{
gdbDebugServer.error(e.what()); gdbDebugServer.error(e.what());
return false; return false;
} }
} }
} }
void GDBDebugServer::send(const char * buf, int cnt) void gdb_thread::send(const char* buf, int cnt)
{ {
gdbDebugServer.trace("Sending %s (%d bytes)", buf, cnt); gdbDebugServer.trace("Sending %s (%d bytes)", buf, cnt);
while (!stop) { while (!Emu.IsStopped())
{
int res = ::send(client_socket, buf, cnt, 0); int res = ::send(client_socket, buf, cnt, 0);
if (res == SOCKET_ERROR) { if (res == -1)
if (check_errno_again()) { {
thread_ctrl::wait_for(50); if (check_errno_again())
{
thread_ctrl::wait_for(5000);
continue; continue;
} }
gdbDebugServer.error("Failed sending %d bytes", cnt); gdbDebugServer.error("Failed sending %d bytes", cnt);
@ -263,17 +283,17 @@ void GDBDebugServer::send(const char * buf, int cnt)
} }
} }
void GDBDebugServer::send_char(char c) void gdb_thread::send_char(char c)
{ {
send(&c, 1); send(&c, 1);
} }
void GDBDebugServer::ack(bool accepted) void gdb_thread::ack(bool accepted)
{ {
send_char(accepted ? '+' : '-'); send_char(accepted ? '+' : '-');
} }
void GDBDebugServer::send_cmd(const std::string & cmd) void gdb_thread::send_cmd(const std::string& cmd)
{ {
u8 checksum = 0; u8 checksum = 0;
std::string buf; std::string buf;
@ -287,7 +307,7 @@ void GDBDebugServer::send_cmd(const std::string & cmd)
send(buf.c_str(), static_cast<int>(buf.length())); send(buf.c_str(), static_cast<int>(buf.length()));
} }
bool GDBDebugServer::send_cmd_ack(const std::string & cmd) bool gdb_thread::send_cmd_ack(const std::string& cmd)
{ {
while (true) { while (true) {
send_cmd(cmd); send_cmd(cmd);
@ -303,7 +323,7 @@ bool GDBDebugServer::send_cmd_ack(const std::string & cmd)
} }
} }
u8 GDBDebugServer::append_encoded_char(char c, std::string & str) u8 gdb_thread::append_encoded_char(char c, std::string& str)
{ {
u8 checksum = 0; u8 checksum = 0;
if (UNLIKELY((c == '#') || (c == '$') || (c == '}'))) { if (UNLIKELY((c == '#') || (c == '$') || (c == '}'))) {
@ -316,7 +336,7 @@ u8 GDBDebugServer::append_encoded_char(char c, std::string & str)
return checksum; return checksum;
} }
std::string GDBDebugServer::to_hexbyte(u8 i) std::string gdb_thread::to_hexbyte(u8 i)
{ {
std::string result = "00"; std::string result = "00";
u8 i1 = i & 0xF; u8 i1 = i & 0xF;
@ -326,7 +346,7 @@ std::string GDBDebugServer::to_hexbyte(u8 i)
return result; return result;
} }
bool GDBDebugServer::select_thread(u64 id) bool gdb_thread::select_thread(u64 id)
{ {
//in case we have none at all //in case we have none at all
selected_thread.reset(); selected_thread.reset();
@ -342,7 +362,7 @@ bool GDBDebugServer::select_thread(u64 id)
return false; return false;
} }
std::string GDBDebugServer::get_reg(std::shared_ptr<ppu_thread> thread, u32 rid) std::string gdb_thread::get_reg(std::shared_ptr<ppu_thread> thread, u32 rid)
{ {
std::string result; std::string result;
//ids from gdb/features/rs6000/powerpc-64.c //ids from gdb/features/rs6000/powerpc-64.c
@ -373,7 +393,7 @@ std::string GDBDebugServer::get_reg(std::shared_ptr<ppu_thread> thread, u32 rid)
} }
} }
bool GDBDebugServer::set_reg(std::shared_ptr<ppu_thread> thread, u32 rid, std::string value) bool gdb_thread::set_reg(std::shared_ptr<ppu_thread> thread, u32 rid, std::string value)
{ {
switch (rid) { switch (rid) {
case 64: case 64:
@ -409,7 +429,7 @@ bool GDBDebugServer::set_reg(std::shared_ptr<ppu_thread> thread, u32 rid, std::s
} }
} }
u32 GDBDebugServer::get_reg_size(std::shared_ptr<ppu_thread> thread, u32 rid) u32 gdb_thread::get_reg_size(std::shared_ptr<ppu_thread> thread, u32 rid)
{ {
switch (rid) { switch (rid) {
case 66: case 66:
@ -424,19 +444,23 @@ u32 GDBDebugServer::get_reg_size(std::shared_ptr<ppu_thread> thread, u32 rid)
} }
} }
bool GDBDebugServer::send_reason() bool gdb_thread::send_reason()
{ {
return send_cmd_ack("S05"); return send_cmd_ack("S05");
} }
void GDBDebugServer::wait_with_interrupts() { void gdb_thread::wait_with_interrupts()
{
char c; char c;
while (!paused) { while (!paused)
{
int result = recv(client_socket, &c, 1, 0); int result = recv(client_socket, &c, 1, 0);
if (result == SOCKET_ERROR) { if (result == -1)
if (check_errno_again()) { {
thread_ctrl::wait_for(50); if (check_errno_again())
{
thread_ctrl::wait_for(5000);
continue; continue;
} }
@ -448,22 +472,22 @@ void GDBDebugServer::wait_with_interrupts() {
} }
} }
bool GDBDebugServer::cmd_extended_mode(gdb_cmd & cmd) bool gdb_thread::cmd_extended_mode(gdb_cmd& cmd)
{ {
return send_cmd_ack("OK"); return send_cmd_ack("OK");
} }
bool GDBDebugServer::cmd_reason(gdb_cmd & cmd) bool gdb_thread::cmd_reason(gdb_cmd& cmd)
{ {
return send_reason(); return send_reason();
} }
bool GDBDebugServer::cmd_supported(gdb_cmd & cmd) bool gdb_thread::cmd_supported(gdb_cmd& cmd)
{ {
return send_cmd_ack("PacketSize=1200"); return send_cmd_ack("PacketSize=1200");
} }
bool GDBDebugServer::cmd_thread_info(gdb_cmd & cmd) bool gdb_thread::cmd_thread_info(gdb_cmd& cmd)
{ {
std::string result = ""; std::string result = "";
const auto on_select = [&](u32, cpu_thread& cpu) const auto on_select = [&](u32, cpu_thread& cpu)
@ -483,12 +507,12 @@ bool GDBDebugServer::cmd_thread_info(gdb_cmd & cmd)
return send_cmd_ack(result);; return send_cmd_ack(result);;
} }
bool GDBDebugServer::cmd_current_thread(gdb_cmd & cmd) bool gdb_thread::cmd_current_thread(gdb_cmd& cmd)
{ {
return send_cmd_ack(selected_thread.expired() ? "" : ("QC" + u64_to_padded_hex(selected_thread.lock()->id))); return send_cmd_ack(selected_thread.expired() ? "" : ("QC" + u64_to_padded_hex(selected_thread.lock()->id)));
} }
bool GDBDebugServer::cmd_read_register(gdb_cmd & cmd) bool gdb_thread::cmd_read_register(gdb_cmd& cmd)
{ {
if (!select_thread(general_ops_thread_id)) { if (!select_thread(general_ops_thread_id)) {
return send_cmd_ack("E02"); return send_cmd_ack("E02");
@ -508,7 +532,7 @@ bool GDBDebugServer::cmd_read_register(gdb_cmd & cmd)
return send_cmd_ack(""); return send_cmd_ack("");
} }
bool GDBDebugServer::cmd_write_register(gdb_cmd & cmd) bool gdb_thread::cmd_write_register(gdb_cmd& cmd)
{ {
if (!select_thread(general_ops_thread_id)) { if (!select_thread(general_ops_thread_id)) {
return send_cmd_ack("E02"); return send_cmd_ack("E02");
@ -533,7 +557,7 @@ bool GDBDebugServer::cmd_write_register(gdb_cmd & cmd)
return send_cmd_ack(""); return send_cmd_ack("");
} }
bool GDBDebugServer::cmd_read_memory(gdb_cmd & cmd) bool gdb_thread::cmd_read_memory(gdb_cmd& cmd)
{ {
size_t s = cmd.data.find(','); size_t s = cmd.data.find(',');
u32 addr = hex_to_u32(cmd.data.substr(0, s)); u32 addr = hex_to_u32(cmd.data.substr(0, s));
@ -555,7 +579,7 @@ bool GDBDebugServer::cmd_read_memory(gdb_cmd & cmd)
return send_cmd_ack(result); return send_cmd_ack(result);
} }
bool GDBDebugServer::cmd_write_memory(gdb_cmd & cmd) bool gdb_thread::cmd_write_memory(gdb_cmd& cmd)
{ {
size_t s = cmd.data.find(','); size_t s = cmd.data.find(',');
size_t s2 = cmd.data.find(':'); size_t s2 = cmd.data.find(':');
@ -583,7 +607,7 @@ bool GDBDebugServer::cmd_write_memory(gdb_cmd & cmd)
return send_cmd_ack("OK"); return send_cmd_ack("OK");
} }
bool GDBDebugServer::cmd_read_all_registers(gdb_cmd & cmd) bool gdb_thread::cmd_read_all_registers(gdb_cmd& cmd)
{ {
std::string result; std::string result;
select_thread(general_ops_thread_id); select_thread(general_ops_thread_id);
@ -602,7 +626,7 @@ bool GDBDebugServer::cmd_read_all_registers(gdb_cmd & cmd)
return send_cmd_ack(""); return send_cmd_ack("");
} }
bool GDBDebugServer::cmd_write_all_registers(gdb_cmd & cmd) bool gdb_thread::cmd_write_all_registers(gdb_cmd& cmd)
{ {
select_thread(general_ops_thread_id); select_thread(general_ops_thread_id);
auto th = selected_thread.lock(); auto th = selected_thread.lock();
@ -620,7 +644,7 @@ bool GDBDebugServer::cmd_write_all_registers(gdb_cmd & cmd)
return send_cmd_ack("E01"); return send_cmd_ack("E01");
} }
bool GDBDebugServer::cmd_set_thread_ops(gdb_cmd & cmd) bool gdb_thread::cmd_set_thread_ops(gdb_cmd& cmd)
{ {
char type = cmd.data[0]; char type = cmd.data[0];
std::string thread = cmd.data.substr(1); std::string thread = cmd.data.substr(1);
@ -637,24 +661,24 @@ bool GDBDebugServer::cmd_set_thread_ops(gdb_cmd & cmd)
return send_cmd_ack("E01"); return send_cmd_ack("E01");
} }
bool GDBDebugServer::cmd_attached_to_what(gdb_cmd & cmd) bool gdb_thread::cmd_attached_to_what(gdb_cmd& cmd)
{ {
//creating processes from client is not available yet //creating processes from client is not available yet
return send_cmd_ack("1"); return send_cmd_ack("1");
} }
bool GDBDebugServer::cmd_kill(gdb_cmd & cmd) bool gdb_thread::cmd_kill(gdb_cmd& cmd)
{ {
Emu.Stop(); Emu.Stop();
return true; return true;
} }
bool GDBDebugServer::cmd_continue_support(gdb_cmd & cmd) bool gdb_thread::cmd_continue_support(gdb_cmd& cmd)
{ {
return send_cmd_ack("vCont;c;s;C;S"); return send_cmd_ack("vCont;c;s;C;S");
} }
bool GDBDebugServer::cmd_vcont(gdb_cmd & cmd) bool gdb_thread::cmd_vcont(gdb_cmd& cmd)
{ {
//todo: handle multiple actions and thread ids //todo: handle multiple actions and thread ids
this->from_breakpoint = false; this->from_breakpoint = false;
@ -690,7 +714,7 @@ bool GDBDebugServer::cmd_vcont(gdb_cmd & cmd)
static const u32 INVALID_PTR = 0xffffffff; static const u32 INVALID_PTR = 0xffffffff;
bool GDBDebugServer::cmd_set_breakpoint(gdb_cmd & cmd) bool gdb_thread::cmd_set_breakpoint(gdb_cmd& cmd)
{ {
char type = cmd.data[0]; char type = cmd.data[0];
//software breakpoint //software breakpoint
@ -712,7 +736,7 @@ bool GDBDebugServer::cmd_set_breakpoint(gdb_cmd & cmd)
return send_cmd_ack(""); return send_cmd_ack("");
} }
bool GDBDebugServer::cmd_remove_breakpoint(gdb_cmd & cmd) bool gdb_thread::cmd_remove_breakpoint(gdb_cmd& cmd)
{ {
char type = cmd.data[0]; char type = cmd.data[0];
//software breakpoint //software breakpoint
@ -733,20 +757,46 @@ bool GDBDebugServer::cmd_remove_breakpoint(gdb_cmd & cmd)
#define PROCESS_CMD(cmds,handler) if (cmd.cmd == cmds) { if (!handler(cmd)) break; else continue; } #define PROCESS_CMD(cmds,handler) if (cmd.cmd == cmds) { if (!handler(cmd)) break; else continue; }
void GDBDebugServer::on_task() gdb_thread::gdb_thread() noexcept
{ {
sock_init(); #ifdef _WIN32
WSADATA wsa_data;
WSAStartup(MAKEWORD(2, 2), &wsa_data);
#endif
}
gdb_thread::~gdb_thread()
{
if (server_socket != -1)
{
closesocket(server_socket);
}
if (client_socket != -1)
{
closesocket(client_socket);
}
#ifdef _WIN32
WSACleanup();
#endif
}
void gdb_thread::operator()()
{
start_server(); start_server();
while (!stop) { while (!Emu.IsStopped())
{
sockaddr_in client; sockaddr_in client;
socklen_t client_len = sizeof(client); socklen_t client_len = sizeof(client);
client_socket = accept(server_socket, (struct sockaddr *) &client, &client_len); client_socket = accept(server_socket, (struct sockaddr *) &client, &client_len);
if (client_socket == INVALID_SOCKET) { if (client_socket == -1)
if (check_errno_again()) { {
thread_ctrl::wait_for(50); if (check_errno_again())
{
thread_ctrl::wait_for(5000);
continue; continue;
} }
@ -765,8 +815,10 @@ void GDBDebugServer::on_task()
gdb_cmd cmd; gdb_cmd cmd;
while (!stop) { while (!Emu.IsStopped())
if (!read_cmd(cmd)) { {
if (!read_cmd(cmd))
{
break; break;
} }
gdbDebugServer.trace("Command %s with data %s received", cmd.cmd.c_str(), cmd.data.c_str()); gdbDebugServer.trace("Command %s with data %s received", cmd.cmd.c_str(), cmd.data.c_str());
@ -795,12 +847,14 @@ void GDBDebugServer::on_task()
} }
} }
} }
catch (std::runtime_error& e) catch (const std::runtime_error& e)
{ {
if (client_socket) { if (client_socket != -1)
{
closesocket(client_socket); closesocket(client_socket);
client_socket = 0; client_socket = -1;
} }
gdbDebugServer.error(e.what()); gdbDebugServer.error(e.what());
} }
} }
@ -808,46 +862,20 @@ void GDBDebugServer::on_task()
#undef PROCESS_CMD #undef PROCESS_CMD
void GDBDebugServer::on_exit() void gdb_thread::pause_from(cpu_thread* t)
{ {
if (server_socket) { if (paused)
closesocket(server_socket); {
}
if (client_socket) {
closesocket(client_socket);
}
sock_quit();
}
std::string GDBDebugServer::get_name() const
{
return "GDBDebugger";
}
void GDBDebugServer::on_stop()
{
this->stop = true;
//just in case we are waiting for breakpoint
this->notify();
old_thread::on_stop();
}
void GDBDebugServer::pause_from(cpu_thread* t) {
if (paused) {
return; return;
} }
paused = true; paused = true;
pausedBy = t->id; pausedBy = t->id;
notify(); thread_ctrl::notify(*static_cast<gdb_server*>(this));
} }
u32 g_gdb_debugger_id = 0;
#ifndef _WIN32 #ifndef _WIN32
#undef sscanf_s #undef sscanf_s
#endif #endif
#undef HEX_U32 #undef HEX_U32
#undef HEX_U64 #undef HEX_U64
#endif

View File

@ -1,49 +1,21 @@
#pragma once #pragma once
#ifdef WITH_GDB_DEBUGGER #include "Utilities/Thread.h"
#include <memory>
#include <string>
#include "Thread.h" struct gdb_cmd;
#include <Emu/IdManager.h>
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h"
#ifdef _WIN32 class cpu_thread;
#include <winsock2.h> class ppu_thread;
#include <WS2tcpip.h>
#else
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#ifdef _WIN32 class gdb_thread
using socket_t = SOCKET;
#else
using socket_t = int;
#endif
typedef struct gdb_cmd {
std::string cmd;
std::string data;
u8 checksum;
} gdb_cmd;
class wrong_checksum_exception : public std::runtime_error {
public:
wrong_checksum_exception(char const* const message) : runtime_error(message) {}
};
const u64 ALL_THREADS = 0xffffffffffffffff;
const u64 ANY_THREAD = 0;
class GDBDebugServer
{ {
socket_t server_socket; static const u64 ALL_THREADS = 0xffffffffffffffff;
socket_t client_socket; static const u64 ANY_THREAD = 0;
int server_socket = -1;
int client_socket = -1;
std::weak_ptr<cpu_thread> selected_thread; std::weak_ptr<cpu_thread> selected_thread;
u64 continue_ops_thread_id = ANY_THREAD; u64 continue_ops_thread_id = ANY_THREAD;
u64 general_ops_thread_id = ANY_THREAD; u64 general_ops_thread_id = ANY_THREAD;
@ -71,10 +43,10 @@ class GDBDebugServer
//acknowledge packet, either as accepted or declined //acknowledge packet, either as accepted or declined
void ack(bool accepted); void ack(bool accepted);
//sends command body cmd to client //sends command body cmd to client
void send_cmd(const std::string & cmd); void send_cmd(const std::string& cmd);
//sends command to client until receives positive acknowledgement //sends command to client until receives positive acknowledgement
//returns false in case some error happened, and command wasn't sent //returns false in case some error happened, and command wasn't sent
bool send_cmd_ack(const std::string & cmd); bool send_cmd_ack(const std::string& cmd);
//appends encoded char c to string str, and returns checksum. encoded byte can occupy 2 bytes //appends encoded char c to string str, and returns checksum. encoded byte can occupy 2 bytes
static u8 append_encoded_char(char c, std::string& str); static u8 append_encoded_char(char c, std::string& str);
//convert u8 to 2 byte hexademical representation //convert u8 to 2 byte hexademical representation
@ -114,14 +86,18 @@ class GDBDebugServer
public: public:
bool from_breakpoint = true; bool from_breakpoint = true;
bool stop = false;
bool paused = false; bool paused = false;
u64 pausedBy; u64 pausedBy;
gdb_thread() noexcept;
~gdb_thread();
gdb_thread(const gdb_thread&) = delete;
gdb_thread& operator=(const gdb_thread&) = delete;
void operator()(); void operator()();
void pause_from(cpu_thread* t); void pause_from(cpu_thread* t);
static constexpr auto thread_name = "GDB Server"sv;
}; };
extern u32 g_gdb_debugger_id; using gdb_server = named_thread<gdb_thread>;
#endif

View File

@ -38,8 +38,6 @@
#include <memory> #include <memory>
#include <regex> #include <regex>
#include "Utilities/GDBDebugServer.h"
#include "Utilities/JIT.h" #include "Utilities/JIT.h"
#if defined(_WIN32) || defined(HAVE_VULKAN) #if defined(_WIN32) || defined(HAVE_VULKAN)
@ -421,10 +419,6 @@ void Emulator::Init()
make_path_verbose(fs::get_cache_dir() + "shaderlog/"); make_path_verbose(fs::get_cache_dir() + "shaderlog/");
make_path_verbose(fs::get_config_dir() + "captures/"); make_path_verbose(fs::get_config_dir() + "captures/");
#ifdef WITH_GDB_DEBUGGER
LOG_SUCCESS(GENERAL, "GDB debug server will be started and listening on %d upon emulator boot", (int)g_cfg.misc.gdb_server_port);
#endif
// Initialize patch engine // Initialize patch engine
g_fxo->init<patch_engine>()->append(fs::get_config_dir() + "/patch.yml"); g_fxo->init<patch_engine>()->append(fs::get_config_dir() + "/patch.yml");
@ -1661,11 +1655,6 @@ void Emulator::Run()
idm::select<named_thread<ppu_thread>>(on_select); idm::select<named_thread<ppu_thread>>(on_select);
idm::select<named_thread<spu_thread>>(on_select); idm::select<named_thread<spu_thread>>(on_select);
#ifdef WITH_GDB_DEBUGGER
// Initialize debug server at the end of emu run sequence
fxm::make<GDBDebugServer>();
#endif
} }
bool Emulator::Pause() bool Emulator::Pause()

View File

@ -616,7 +616,7 @@ struct cfg_root : cfg::node
cfg::_bool show_trophy_popups{ this, "Show trophy popups", true}; cfg::_bool show_trophy_popups{ this, "Show trophy popups", true};
cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true }; cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true };
cfg::_bool use_native_interface{ this, "Use native user interface", true }; cfg::_bool use_native_interface{ this, "Use native user interface", true };
cfg::_int<1, 65535> gdb_server_port{this, "Port", 2345}; cfg::string gdb_server{this, "GDB Server", "127.0.0.1:2345"};
} misc{this}; } misc{this};

View File

@ -80,9 +80,6 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="..\Utilities\dynamic_library.cpp" /> <ClCompile Include="..\Utilities\dynamic_library.cpp" />
<ClCompile Include="..\Utilities\GDBDebugServer.cpp">
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\JIT.cpp"> <ClCompile Include="..\Utilities\JIT.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile> </ClCompile>
@ -369,6 +366,7 @@
<ClCompile Include="Emu\RSX\RSXThread.cpp" /> <ClCompile Include="Emu\RSX\RSXThread.cpp" />
<ClCompile Include="Emu\Memory\vm.cpp" /> <ClCompile Include="Emu\Memory\vm.cpp" />
<ClCompile Include="Emu\System.cpp" /> <ClCompile Include="Emu\System.cpp" />
<ClCompile Include="Emu\GDB.cpp" />
<ClCompile Include="Loader\ELF.cpp" /> <ClCompile Include="Loader\ELF.cpp" />
<ClCompile Include="Loader\PSF.cpp" /> <ClCompile Include="Loader\PSF.cpp" />
<ClCompile Include="Loader\PUP.cpp" /> <ClCompile Include="Loader\PUP.cpp" />
@ -397,7 +395,6 @@
<ClInclude Include="..\Utilities\date_time.h" /> <ClInclude Include="..\Utilities\date_time.h" />
<ClInclude Include="..\Utilities\dynamic_library.h" /> <ClInclude Include="..\Utilities\dynamic_library.h" />
<ClInclude Include="..\Utilities\event.h" /> <ClInclude Include="..\Utilities\event.h" />
<ClInclude Include="..\Utilities\GDBDebugServer.h" />
<ClInclude Include="..\Utilities\geometry.h" /> <ClInclude Include="..\Utilities\geometry.h" />
<ClInclude Include="..\Utilities\GSL.h" /> <ClInclude Include="..\Utilities\GSL.h" />
<ClInclude Include="..\Utilities\hash.h" /> <ClInclude Include="..\Utilities\hash.h" />
@ -618,6 +615,7 @@
<ClInclude Include="Emu\RSX\rsx_methods.h" /> <ClInclude Include="Emu\RSX\rsx_methods.h" />
<ClInclude Include="Emu\RSX\rsx_utils.h" /> <ClInclude Include="Emu\RSX\rsx_utils.h" />
<ClInclude Include="Emu\System.h" /> <ClInclude Include="Emu\System.h" />
<ClInclude Include="Emu\GDB.h" />
<ClInclude Include="Loader\ELF.h" /> <ClInclude Include="Loader\ELF.h" />
<ClInclude Include="Loader\PSF.h" /> <ClInclude Include="Loader\PSF.h" />
<ClInclude Include="Loader\PUP.h" /> <ClInclude Include="Loader\PUP.h" />

View File

@ -728,8 +728,8 @@
<ClCompile Include="Loader\TAR.cpp"> <ClCompile Include="Loader\TAR.cpp">
<Filter>Loader</Filter> <Filter>Loader</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Utilities\GDBDebugServer.cpp"> <ClCompile Include="Emu\GDB.cpp">
<Filter>Utilities</Filter> <Filter>Emu</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Utilities\bin_patch.cpp"> <ClCompile Include="..\Utilities\bin_patch.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
@ -1438,8 +1438,8 @@
<ClInclude Include="Loader\TAR.h"> <ClInclude Include="Loader\TAR.h">
<Filter>Loader</Filter> <Filter>Loader</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Utilities\GDBDebugServer.h"> <ClInclude Include="Emu\GDB.h">
<Filter>Utilities</Filter> <Filter>Emu</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Utilities\bin_patch.h"> <ClInclude Include="..\Utilities\bin_patch.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>