2017-04-02 20:10:06 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "util/Thread.h"
|
2019-10-08 02:19:59 +02:00
|
|
|
#include <string>
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
struct gdb_cmd;
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
class cpu_thread;
|
|
|
|
|
class ppu_thread;
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
class gdb_thread
|
2018-09-25 14:21:04 +02:00
|
|
|
{
|
2019-10-08 02:19:59 +02:00
|
|
|
static const u64 ALL_THREADS = 0xffffffffffffffff;
|
|
|
|
|
static const u64 ANY_THREAD = 0;
|
|
|
|
|
|
|
|
|
|
int server_socket = -1;
|
|
|
|
|
int client_socket = -1;
|
2024-12-22 19:59:48 +01:00
|
|
|
shared_ptr<cpu_thread> selected_thread{};
|
2017-04-02 20:10:06 +02:00
|
|
|
u64 continue_ops_thread_id = ANY_THREAD;
|
|
|
|
|
u64 general_ops_thread_id = ANY_THREAD;
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
// initialize server socket and start listening
|
2017-04-02 20:10:06 +02:00
|
|
|
void start_server();
|
2025-04-05 21:50:45 +02:00
|
|
|
// read at most cnt bytes to buf, returns number of bytes actually read
|
2021-04-09 21:12:47 +02:00
|
|
|
int read(void* buf, int cnt) const;
|
2025-04-05 21:50:45 +02:00
|
|
|
// reads one character
|
2017-04-02 20:10:06 +02:00
|
|
|
char read_char();
|
2025-04-05 21:50:45 +02:00
|
|
|
// reads pairs of hex characters and returns their integer value
|
2017-04-02 20:10:06 +02:00
|
|
|
u8 read_hexbyte();
|
2019-11-07 23:11:59 +01:00
|
|
|
|
|
|
|
|
// Tries to read command, returns false on error
|
|
|
|
|
bool try_read_cmd(gdb_cmd& out_cmd);
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
// reads commands until receiveing one with valid checksum
|
|
|
|
|
// in case of other exception (i.e. wrong first char of command)
|
|
|
|
|
// it will log exception text and return false
|
|
|
|
|
// in that case best for caller would be to stop reading, because
|
|
|
|
|
// chance of getting correct command is low
|
2017-04-02 20:10:06 +02:00
|
|
|
bool read_cmd(gdb_cmd& out_cmd);
|
2025-04-05 21:50:45 +02:00
|
|
|
// send cnt bytes from buf to client
|
2021-04-09 21:12:47 +02:00
|
|
|
void send(const char* buf, int cnt) const;
|
2025-04-05 21:50:45 +02:00
|
|
|
// send character to client
|
2017-04-02 20:10:06 +02:00
|
|
|
void send_char(char c);
|
2025-04-05 21:50:45 +02:00
|
|
|
// acknowledge packet, either as accepted or declined
|
2017-04-02 20:10:06 +02:00
|
|
|
void ack(bool accepted);
|
2025-04-05 21:50:45 +02:00
|
|
|
// sends command body cmd to client
|
2019-10-08 02:19:59 +02:00
|
|
|
void send_cmd(const std::string& cmd);
|
2025-04-05 21:50:45 +02:00
|
|
|
// sends command to client until receives positive acknowledgement
|
|
|
|
|
// returns false in case some error happened, and command wasn't sent
|
2019-10-08 02:19:59 +02:00
|
|
|
bool send_cmd_ack(const std::string& cmd);
|
2025-04-05 21:50:45 +02:00
|
|
|
// appends encoded char c to string str, and returns checksum. encoded byte can occupy 2 bytes
|
2017-04-02 20:10:06 +02:00
|
|
|
static u8 append_encoded_char(char c, std::string& str);
|
2025-04-05 21:50:45 +02:00
|
|
|
// convert u8 to 2 byte hexademical representation
|
2017-04-02 20:10:06 +02:00
|
|
|
static std::string to_hexbyte(u8 i);
|
2025-04-05 21:50:45 +02:00
|
|
|
// choose thread, support ALL_THREADS and ANY_THREAD values, returns true if some thread was selected
|
2017-04-02 20:10:06 +02:00
|
|
|
bool select_thread(u64 id);
|
2025-04-05 21:50:45 +02:00
|
|
|
// returns register value as hex string by register id (in gdb), in case of wrong id returns empty string
|
2019-10-09 02:12:45 +02:00
|
|
|
static std::string get_reg(ppu_thread* thread, u32 rid);
|
2025-04-05 21:50:45 +02:00
|
|
|
// sets register value to hex string by register id (in gdb), in case of wrong id returns false
|
2024-11-05 22:34:38 +01:00
|
|
|
static bool set_reg(ppu_thread* thread, u32 rid, const std::string& value);
|
2025-04-05 21:50:45 +02:00
|
|
|
// returns size of register with id rid in bytes, zero if invalid rid is provided
|
2019-10-09 02:12:45 +02:00
|
|
|
static u32 get_reg_size(ppu_thread* thread, u32 rid);
|
2025-04-05 21:50:45 +02:00
|
|
|
// send reason of stop, returns false if sending response failed
|
2017-04-02 20:10:06 +02:00
|
|
|
bool send_reason();
|
|
|
|
|
|
2018-02-28 16:31:39 +01:00
|
|
|
void wait_with_interrupts();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
// commands
|
2017-04-02 20:10:06 +02:00
|
|
|
bool cmd_extended_mode(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_reason(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_supported(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_thread_info(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_current_thread(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_read_register(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_write_register(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_read_memory(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_write_memory(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_read_all_registers(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_write_all_registers(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_set_thread_ops(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_attached_to_what(gdb_cmd& cmd);
|
2021-04-09 21:12:47 +02:00
|
|
|
static bool cmd_kill(gdb_cmd& cmd);
|
2017-04-02 20:10:06 +02:00
|
|
|
bool cmd_continue_support(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_vcont(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_set_breakpoint(gdb_cmd& cmd);
|
|
|
|
|
bool cmd_remove_breakpoint(gdb_cmd& cmd);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
bool from_breakpoint = true;
|
2018-02-28 16:31:39 +01:00
|
|
|
bool paused = false;
|
2021-04-09 21:12:47 +02:00
|
|
|
u64 pausedBy = 0;
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
gdb_thread() noexcept;
|
|
|
|
|
~gdb_thread();
|
|
|
|
|
gdb_thread(const gdb_thread&) = delete;
|
|
|
|
|
gdb_thread& operator=(const gdb_thread&) = delete;
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
void operator()();
|
2018-02-28 16:31:39 +01:00
|
|
|
void pause_from(cpu_thread* t);
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
static constexpr auto thread_name = "GDB Server"sv;
|
|
|
|
|
};
|
2017-04-02 20:10:06 +02:00
|
|
|
|
2019-10-08 02:19:59 +02:00
|
|
|
using gdb_server = named_thread<gdb_thread>;
|