gdbstub: Move GdbCmdParseEntry into a new header file
Move GdbCmdParseEntry and its associated types into a separate header file to allow the use of GdbCmdParseEntry and other gdbstub command functions outside of gdbstub.c. Since GdbCmdParseEntry and get_param are now public, kdoc GdbCmdParseEntry and rename get_param to gdb_get_cmd_param. This commit also makes gdb_put_packet public since is used in gdbstub command handling. Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20240628050850.536447-3-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20240705084047.857176-32-alex.bennee@linaro.org>
This commit is contained in:
parent
0ef6b12e58
commit
133f202b19
@ -30,6 +30,7 @@
|
|||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
#include "gdbstub/commands.h"
|
||||||
#include "gdbstub/syscalls.h"
|
#include "gdbstub/syscalls.h"
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
#include "accel/tcg/vcpu-state.h"
|
#include "accel/tcg/vcpu-state.h"
|
||||||
@ -920,43 +921,6 @@ static int cmd_parse_params(const char *data, const char *schema,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* cmd_startswith -> cmd is compared using startswith
|
|
||||||
*
|
|
||||||
* allow_stop_reply -> true iff the gdbstub can respond to this command with a
|
|
||||||
* "stop reply" packet. The list of commands that accept such response is
|
|
||||||
* defined at the GDB Remote Serial Protocol documentation. see:
|
|
||||||
* https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
|
|
||||||
*
|
|
||||||
* schema definitions:
|
|
||||||
* Each schema parameter entry consists of 2 chars,
|
|
||||||
* the first char represents the parameter type handling
|
|
||||||
* the second char represents the delimiter for the next parameter
|
|
||||||
*
|
|
||||||
* Currently supported schema types:
|
|
||||||
* 'l' -> unsigned long (stored in .val_ul)
|
|
||||||
* 'L' -> unsigned long long (stored in .val_ull)
|
|
||||||
* 's' -> string (stored in .data)
|
|
||||||
* 'o' -> single char (stored in .opcode)
|
|
||||||
* 't' -> thread id (stored in .thread_id)
|
|
||||||
* '?' -> skip according to delimiter
|
|
||||||
*
|
|
||||||
* Currently supported delimiters:
|
|
||||||
* '?' -> Stop at any delimiter (",;:=\0")
|
|
||||||
* '0' -> Stop at "\0"
|
|
||||||
* '.' -> Skip 1 char unless reached "\0"
|
|
||||||
* Any other value is treated as the delimiter value itself
|
|
||||||
*/
|
|
||||||
typedef struct GdbCmdParseEntry {
|
|
||||||
GdbCmdHandler handler;
|
|
||||||
const char *cmd;
|
|
||||||
bool cmd_startswith;
|
|
||||||
const char *schema;
|
|
||||||
bool allow_stop_reply;
|
|
||||||
} GdbCmdParseEntry;
|
|
||||||
|
|
||||||
static inline int startswith(const char *string, const char *pattern)
|
static inline int startswith(const char *string, const char *pattern)
|
||||||
{
|
{
|
||||||
return !strncmp(string, pattern, strlen(pattern));
|
return !strncmp(string, pattern, strlen(pattern));
|
||||||
@ -1023,7 +987,7 @@ static void handle_detach(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = get_param(params, 0)->val_ul;
|
pid = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
@ -1061,13 +1025,13 @@ static void handle_thread_alive(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
if (gdb_get_cmd_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid,
|
cpu = gdb_get_cpu(gdb_get_cmd_param(params, 0)->thread_id.pid,
|
||||||
get_param(params, 0)->thread_id.tid);
|
gdb_get_cmd_param(params, 0)->thread_id.tid);
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
@ -1079,7 +1043,7 @@ static void handle_thread_alive(GArray *params, void *user_ctx)
|
|||||||
static void handle_continue(GArray *params, void *user_ctx)
|
static void handle_continue(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
if (params->len) {
|
if (params->len) {
|
||||||
gdb_set_cpu_pc(get_param(params, 0)->val_ull);
|
gdb_set_cpu_pc(gdb_get_cmd_param(params, 0)->val_ull);
|
||||||
}
|
}
|
||||||
|
|
||||||
gdbserver_state.signal = 0;
|
gdbserver_state.signal = 0;
|
||||||
@ -1095,7 +1059,7 @@ static void handle_cont_with_sig(GArray *params, void *user_ctx)
|
|||||||
* omit the addr parameter
|
* omit the addr parameter
|
||||||
*/
|
*/
|
||||||
if (params->len) {
|
if (params->len) {
|
||||||
signal = get_param(params, 0)->val_ul;
|
signal = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdbserver_state.signal = gdb_signal_to_target(signal);
|
gdbserver_state.signal = gdb_signal_to_target(signal);
|
||||||
@ -1115,18 +1079,18 @@ static void handle_set_thread(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
if (gdb_get_cmd_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) {
|
if (gdb_get_cmd_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) {
|
||||||
gdb_put_packet("OK");
|
gdb_put_packet("OK");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = get_param(params, 1)->thread_id.pid;
|
pid = gdb_get_cmd_param(params, 1)->thread_id.pid;
|
||||||
tid = get_param(params, 1)->thread_id.tid;
|
tid = gdb_get_cmd_param(params, 1)->thread_id.tid;
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
if (gdb_handle_set_thread_user(pid, tid)) {
|
if (gdb_handle_set_thread_user(pid, tid)) {
|
||||||
return;
|
return;
|
||||||
@ -1142,7 +1106,7 @@ static void handle_set_thread(GArray *params, void *user_ctx)
|
|||||||
* Note: This command is deprecated and modern gdb's will be using the
|
* Note: This command is deprecated and modern gdb's will be using the
|
||||||
* vCont command instead.
|
* vCont command instead.
|
||||||
*/
|
*/
|
||||||
switch (get_param(params, 0)->opcode) {
|
switch (gdb_get_cmd_param(params, 0)->opcode) {
|
||||||
case 'c':
|
case 'c':
|
||||||
gdbserver_state.c_cpu = cpu;
|
gdbserver_state.c_cpu = cpu;
|
||||||
gdb_put_packet("OK");
|
gdb_put_packet("OK");
|
||||||
@ -1167,9 +1131,9 @@ static void handle_insert_bp(GArray *params, void *user_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = gdb_breakpoint_insert(gdbserver_state.c_cpu,
|
res = gdb_breakpoint_insert(gdbserver_state.c_cpu,
|
||||||
get_param(params, 0)->val_ul,
|
gdb_get_cmd_param(params, 0)->val_ul,
|
||||||
get_param(params, 1)->val_ull,
|
gdb_get_cmd_param(params, 1)->val_ull,
|
||||||
get_param(params, 2)->val_ull);
|
gdb_get_cmd_param(params, 2)->val_ull);
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
gdb_put_packet("OK");
|
gdb_put_packet("OK");
|
||||||
return;
|
return;
|
||||||
@ -1191,9 +1155,9 @@ static void handle_remove_bp(GArray *params, void *user_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = gdb_breakpoint_remove(gdbserver_state.c_cpu,
|
res = gdb_breakpoint_remove(gdbserver_state.c_cpu,
|
||||||
get_param(params, 0)->val_ul,
|
gdb_get_cmd_param(params, 0)->val_ul,
|
||||||
get_param(params, 1)->val_ull,
|
gdb_get_cmd_param(params, 1)->val_ull,
|
||||||
get_param(params, 2)->val_ull);
|
gdb_get_cmd_param(params, 2)->val_ull);
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
gdb_put_packet("OK");
|
gdb_put_packet("OK");
|
||||||
return;
|
return;
|
||||||
@ -1225,10 +1189,10 @@ static void handle_set_reg(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_size = strlen(get_param(params, 1)->data) / 2;
|
reg_size = strlen(gdb_get_cmd_param(params, 1)->data) / 2;
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 1)->data, reg_size);
|
gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 1)->data, reg_size);
|
||||||
gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
|
gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
|
||||||
get_param(params, 0)->val_ull);
|
gdb_get_cmd_param(params, 0)->val_ull);
|
||||||
gdb_put_packet("OK");
|
gdb_put_packet("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,7 +1207,7 @@ static void handle_get_reg(GArray *params, void *user_ctx)
|
|||||||
|
|
||||||
reg_size = gdb_read_register(gdbserver_state.g_cpu,
|
reg_size = gdb_read_register(gdbserver_state.g_cpu,
|
||||||
gdbserver_state.mem_buf,
|
gdbserver_state.mem_buf,
|
||||||
get_param(params, 0)->val_ull);
|
gdb_get_cmd_param(params, 0)->val_ull);
|
||||||
if (!reg_size) {
|
if (!reg_size) {
|
||||||
gdb_put_packet("E14");
|
gdb_put_packet("E14");
|
||||||
return;
|
return;
|
||||||
@ -1264,16 +1228,16 @@ static void handle_write_mem(GArray *params, void *user_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* gdb_hextomem() reads 2*len bytes */
|
/* gdb_hextomem() reads 2*len bytes */
|
||||||
if (get_param(params, 1)->val_ull >
|
if (gdb_get_cmd_param(params, 1)->val_ull >
|
||||||
strlen(get_param(params, 2)->data) / 2) {
|
strlen(gdb_get_cmd_param(params, 2)->data) / 2) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 2)->data,
|
gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 2)->data,
|
||||||
get_param(params, 1)->val_ull);
|
gdb_get_cmd_param(params, 1)->val_ull);
|
||||||
if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
|
if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
|
||||||
get_param(params, 0)->val_ull,
|
gdb_get_cmd_param(params, 0)->val_ull,
|
||||||
gdbserver_state.mem_buf->data,
|
gdbserver_state.mem_buf->data,
|
||||||
gdbserver_state.mem_buf->len, true)) {
|
gdbserver_state.mem_buf->len, true)) {
|
||||||
gdb_put_packet("E14");
|
gdb_put_packet("E14");
|
||||||
@ -1291,16 +1255,16 @@ static void handle_read_mem(GArray *params, void *user_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* gdb_memtohex() doubles the required space */
|
/* gdb_memtohex() doubles the required space */
|
||||||
if (get_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) {
|
if (gdb_get_cmd_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_byte_array_set_size(gdbserver_state.mem_buf,
|
g_byte_array_set_size(gdbserver_state.mem_buf,
|
||||||
get_param(params, 1)->val_ull);
|
gdb_get_cmd_param(params, 1)->val_ull);
|
||||||
|
|
||||||
if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
|
if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
|
||||||
get_param(params, 0)->val_ull,
|
gdb_get_cmd_param(params, 0)->val_ull,
|
||||||
gdbserver_state.mem_buf->data,
|
gdbserver_state.mem_buf->data,
|
||||||
gdbserver_state.mem_buf->len, false)) {
|
gdbserver_state.mem_buf->len, false)) {
|
||||||
gdb_put_packet("E14");
|
gdb_put_packet("E14");
|
||||||
@ -1324,8 +1288,8 @@ static void handle_write_all_regs(GArray *params, void *user_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu_synchronize_state(gdbserver_state.g_cpu);
|
cpu_synchronize_state(gdbserver_state.g_cpu);
|
||||||
len = strlen(get_param(params, 0)->data) / 2;
|
len = strlen(gdb_get_cmd_param(params, 0)->data) / 2;
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len);
|
gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 0)->data, len);
|
||||||
registers = gdbserver_state.mem_buf->data;
|
registers = gdbserver_state.mem_buf->data;
|
||||||
for (reg_id = 0;
|
for (reg_id = 0;
|
||||||
reg_id < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
|
reg_id < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
|
||||||
@ -1360,7 +1324,7 @@ static void handle_read_all_regs(GArray *params, void *user_ctx)
|
|||||||
static void handle_step(GArray *params, void *user_ctx)
|
static void handle_step(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
if (params->len) {
|
if (params->len) {
|
||||||
gdb_set_cpu_pc(get_param(params, 0)->val_ull);
|
gdb_set_cpu_pc(gdb_get_cmd_param(params, 0)->val_ull);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags);
|
cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags);
|
||||||
@ -1373,7 +1337,7 @@ static void handle_backward(GArray *params, void *user_ctx)
|
|||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
}
|
}
|
||||||
if (params->len == 1) {
|
if (params->len == 1) {
|
||||||
switch (get_param(params, 0)->opcode) {
|
switch (gdb_get_cmd_param(params, 0)->opcode) {
|
||||||
case 's':
|
case 's':
|
||||||
if (replay_reverse_step()) {
|
if (replay_reverse_step()) {
|
||||||
gdb_continue();
|
gdb_continue();
|
||||||
@ -1408,7 +1372,7 @@ static void handle_v_cont(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = gdb_handle_vcont(get_param(params, 0)->data);
|
res = gdb_handle_vcont(gdb_get_cmd_param(params, 0)->data);
|
||||||
if ((res == -EINVAL) || (res == -ERANGE)) {
|
if ((res == -EINVAL) || (res == -ERANGE)) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
} else if (res) {
|
} else if (res) {
|
||||||
@ -1426,7 +1390,7 @@ static void handle_v_attach(GArray *params, void *user_ctx)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
process = gdb_get_process(get_param(params, 0)->val_ul);
|
process = gdb_get_process(gdb_get_cmd_param(params, 0)->val_ul);
|
||||||
if (!process) {
|
if (!process) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -1523,7 +1487,7 @@ static void handle_v_commands(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process_string_cmd(get_param(params, 0)->data,
|
if (!process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
||||||
gdb_v_commands_table,
|
gdb_v_commands_table,
|
||||||
ARRAY_SIZE(gdb_v_commands_table))) {
|
ARRAY_SIZE(gdb_v_commands_table))) {
|
||||||
gdb_put_packet("");
|
gdb_put_packet("");
|
||||||
@ -1555,7 +1519,7 @@ static void handle_set_qemu_sstep(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_sstep_flags = get_param(params, 0)->val_ul;
|
new_sstep_flags = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
|
|
||||||
if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) {
|
if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
@ -1615,13 +1579,13 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx)
|
|||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
|
||||||
if (!params->len ||
|
if (!params->len ||
|
||||||
get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
gdb_get_cmd_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
|
||||||
gdb_put_packet("E22");
|
gdb_put_packet("E22");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid,
|
cpu = gdb_get_cpu(gdb_get_cmd_param(params, 0)->thread_id.pid,
|
||||||
get_param(params, 0)->thread_id.tid);
|
gdb_get_cmd_param(params, 0)->thread_id.tid);
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1673,7 +1637,7 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (params->len) {
|
if (params->len) {
|
||||||
const char *gdb_supported = get_param(params, 0)->data;
|
const char *gdb_supported = gdb_get_cmd_param(params, 0)->data;
|
||||||
|
|
||||||
if (strstr(gdb_supported, "multiprocess+")) {
|
if (strstr(gdb_supported, "multiprocess+")) {
|
||||||
gdbserver_state.multiprocess = true;
|
gdbserver_state.multiprocess = true;
|
||||||
@ -1707,15 +1671,15 @@ static void handle_query_xfer_features(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = get_param(params, 0)->data;
|
p = gdb_get_cmd_param(params, 0)->data;
|
||||||
xml = get_feature_xml(p, &p, process);
|
xml = get_feature_xml(p, &p, process);
|
||||||
if (!xml) {
|
if (!xml) {
|
||||||
gdb_put_packet("E00");
|
gdb_put_packet("E00");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = get_param(params, 1)->val_ul;
|
addr = gdb_get_cmd_param(params, 1)->val_ul;
|
||||||
len = get_param(params, 2)->val_ul;
|
len = gdb_get_cmd_param(params, 2)->val_ul;
|
||||||
total_len = strlen(xml);
|
total_len = strlen(xml);
|
||||||
if (addr > total_len) {
|
if (addr > total_len) {
|
||||||
gdb_put_packet("E00");
|
gdb_put_packet("E00");
|
||||||
@ -1889,13 +1853,13 @@ static void handle_gen_query(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(get_param(params, 0)->data,
|
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
||||||
gdb_gen_query_set_common_table,
|
gdb_gen_query_set_common_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process_string_cmd(get_param(params, 0)->data,
|
if (!process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
||||||
gdb_gen_query_table,
|
gdb_gen_query_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_table))) {
|
ARRAY_SIZE(gdb_gen_query_table))) {
|
||||||
gdb_put_packet("");
|
gdb_put_packet("");
|
||||||
@ -1908,13 +1872,13 @@ static void handle_gen_set(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(get_param(params, 0)->data,
|
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
||||||
gdb_gen_query_set_common_table,
|
gdb_gen_query_set_common_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process_string_cmd(get_param(params, 0)->data,
|
if (!process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
||||||
gdb_gen_set_table,
|
gdb_gen_set_table,
|
||||||
ARRAY_SIZE(gdb_gen_set_table))) {
|
ARRAY_SIZE(gdb_gen_set_table))) {
|
||||||
gdb_put_packet("");
|
gdb_put_packet("");
|
||||||
|
@ -106,7 +106,6 @@ static inline int tohex(int v)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void gdb_put_strbuf(void);
|
void gdb_put_strbuf(void);
|
||||||
int gdb_put_packet(const char *buf);
|
|
||||||
int gdb_put_packet_binary(const char *buf, int len, bool dump);
|
int gdb_put_packet_binary(const char *buf, int len, bool dump);
|
||||||
void gdb_hextomem(GByteArray *mem, const char *buf, int len);
|
void gdb_hextomem(GByteArray *mem, const char *buf, int len);
|
||||||
void gdb_memtohex(GString *buf, const uint8_t *mem, int len);
|
void gdb_memtohex(GString *buf, const uint8_t *mem, int len);
|
||||||
@ -166,27 +165,6 @@ void gdb_put_buffer(const uint8_t *buf, int len);
|
|||||||
*/
|
*/
|
||||||
void gdb_init_gdbserver_state(void);
|
void gdb_init_gdbserver_state(void);
|
||||||
|
|
||||||
typedef enum GDBThreadIdKind {
|
|
||||||
GDB_ONE_THREAD = 0,
|
|
||||||
GDB_ALL_THREADS, /* One process, all threads */
|
|
||||||
GDB_ALL_PROCESSES,
|
|
||||||
GDB_READ_THREAD_ERR
|
|
||||||
} GDBThreadIdKind;
|
|
||||||
|
|
||||||
typedef union GdbCmdVariant {
|
|
||||||
const char *data;
|
|
||||||
uint8_t opcode;
|
|
||||||
unsigned long val_ul;
|
|
||||||
unsigned long long val_ull;
|
|
||||||
struct {
|
|
||||||
GDBThreadIdKind kind;
|
|
||||||
uint32_t pid;
|
|
||||||
uint32_t tid;
|
|
||||||
} thread_id;
|
|
||||||
} GdbCmdVariant;
|
|
||||||
|
|
||||||
#define get_param(p, i) (&g_array_index(p, GdbCmdVariant, i))
|
|
||||||
|
|
||||||
void gdb_handle_query_rcmd(GArray *params, void *ctx); /* system */
|
void gdb_handle_query_rcmd(GArray *params, void *ctx); /* system */
|
||||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
||||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "gdbstub/user.h"
|
#include "gdbstub/user.h"
|
||||||
#include "gdbstub/syscalls.h"
|
#include "gdbstub/syscalls.h"
|
||||||
|
#include "gdbstub/commands.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
|
|
||||||
@ -154,9 +155,9 @@ void gdb_handle_file_io(GArray *params, void *user_ctx)
|
|||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ret = get_param(params, 0)->val_ull;
|
ret = gdb_get_cmd_param(params, 0)->val_ull;
|
||||||
if (params->len >= 2) {
|
if (params->len >= 2) {
|
||||||
err = get_param(params, 1)->val_ull;
|
err = gdb_get_cmd_param(params, 1)->val_ull;
|
||||||
} else {
|
} else {
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
@ -196,7 +197,7 @@ void gdb_handle_file_io(GArray *params, void *user_ctx)
|
|||||||
gdbserver_syscall_state.current_syscall_cb = NULL;
|
gdbserver_syscall_state.current_syscall_cb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') {
|
if (params->len >= 3 && gdb_get_cmd_param(params, 2)->opcode == (uint8_t)'C') {
|
||||||
gdb_put_packet("T02");
|
gdb_put_packet("T02");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "gdbstub/syscalls.h"
|
#include "gdbstub/syscalls.h"
|
||||||
|
#include "gdbstub/commands.h"
|
||||||
#include "exec/hwaddr.h"
|
#include "exec/hwaddr.h"
|
||||||
#include "exec/tb-flush.h"
|
#include "exec/tb-flush.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
@ -501,7 +502,7 @@ void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_param(params, 0)->val_ul) {
|
if (!gdb_get_cmd_param(params, 0)->val_ul) {
|
||||||
phy_memory_mode = 0;
|
phy_memory_mode = 0;
|
||||||
} else {
|
} else {
|
||||||
phy_memory_mode = 1;
|
phy_memory_mode = 1;
|
||||||
@ -519,7 +520,7 @@ void gdb_handle_query_rcmd(GArray *params, void *ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(get_param(params, 0)->data);
|
len = strlen(gdb_get_cmd_param(params, 0)->data);
|
||||||
if (len % 2) {
|
if (len % 2) {
|
||||||
gdb_put_packet("E01");
|
gdb_put_packet("E01");
|
||||||
return;
|
return;
|
||||||
@ -527,7 +528,7 @@ void gdb_handle_query_rcmd(GArray *params, void *ctx)
|
|||||||
|
|
||||||
g_assert(gdbserver_state.mem_buf->len == 0);
|
g_assert(gdbserver_state.mem_buf->len == 0);
|
||||||
len = len / 2;
|
len = len / 2;
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len);
|
gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 0)->data, len);
|
||||||
g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
|
g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
|
||||||
qemu_chr_be_write(gdbserver_system_state.mon_chr,
|
qemu_chr_be_write(gdbserver_system_state.mon_chr,
|
||||||
gdbserver_state.mem_buf->data,
|
gdbserver_state.mem_buf->data,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
#include "gdbstub/commands.h"
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
#ifdef CONFIG_LINUX
|
#ifdef CONFIG_LINUX
|
||||||
@ -250,8 +251,8 @@ void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = get_param(params, 0)->val_ul;
|
offset = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
len = get_param(params, 1)->val_ul;
|
len = gdb_get_cmd_param(params, 1)->val_ul;
|
||||||
ts = get_task_state(gdbserver_state.c_cpu);
|
ts = get_task_state(gdbserver_state.c_cpu);
|
||||||
saved_auxv = ts->info->saved_auxv;
|
saved_auxv = ts->info->saved_auxv;
|
||||||
auxv_len = ts->info->auxv_len;
|
auxv_len = ts->info->auxv_len;
|
||||||
@ -288,7 +289,7 @@ void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
|||||||
|
|
||||||
static const char *get_filename_param(GArray *params, int i)
|
static const char *get_filename_param(GArray *params, int i)
|
||||||
{
|
{
|
||||||
const char *hex_filename = get_param(params, i)->data;
|
const char *hex_filename = gdb_get_cmd_param(params, i)->data;
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
|
gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
|
||||||
strlen(hex_filename) / 2);
|
strlen(hex_filename) / 2);
|
||||||
g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
|
g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
|
||||||
@ -306,8 +307,8 @@ static void hostio_reply_with_data(const void *buf, size_t n)
|
|||||||
void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
const char *filename = get_filename_param(params, 0);
|
const char *filename = get_filename_param(params, 0);
|
||||||
uint64_t flags = get_param(params, 1)->val_ull;
|
uint64_t flags = gdb_get_cmd_param(params, 1)->val_ull;
|
||||||
uint64_t mode = get_param(params, 2)->val_ull;
|
uint64_t mode = gdb_get_cmd_param(params, 2)->val_ull;
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX
|
#ifdef CONFIG_LINUX
|
||||||
int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename,
|
int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename,
|
||||||
@ -325,7 +326,7 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
|||||||
|
|
||||||
void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
int fd = get_param(params, 0)->val_ul;
|
int fd = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
|
|
||||||
if (close(fd) == -1) {
|
if (close(fd) == -1) {
|
||||||
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||||
@ -338,9 +339,9 @@ void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
|||||||
|
|
||||||
void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
|
void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
int fd = get_param(params, 0)->val_ul;
|
int fd = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
size_t count = get_param(params, 1)->val_ull;
|
size_t count = gdb_get_cmd_param(params, 1)->val_ull;
|
||||||
off_t offset = get_param(params, 2)->val_ull;
|
off_t offset = gdb_get_cmd_param(params, 2)->val_ull;
|
||||||
|
|
||||||
size_t bufsiz = MIN(count, BUFSIZ);
|
size_t bufsiz = MIN(count, BUFSIZ);
|
||||||
g_autofree char *buf = g_try_malloc(bufsiz);
|
g_autofree char *buf = g_try_malloc(bufsiz);
|
||||||
@ -383,9 +384,9 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
|
|||||||
|
|
||||||
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
|
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
uint32_t pid = get_param(params, 0)->val_ul;
|
uint32_t pid = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
uint32_t offset = get_param(params, 1)->val_ul;
|
uint32_t offset = gdb_get_cmd_param(params, 1)->val_ul;
|
||||||
uint32_t length = get_param(params, 2)->val_ul;
|
uint32_t length = gdb_get_cmd_param(params, 2)->val_ul;
|
||||||
|
|
||||||
GDBProcess *process = gdb_get_process(pid);
|
GDBProcess *process = gdb_get_process(pid);
|
||||||
if (!process) {
|
if (!process) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "exec/hwaddr.h"
|
#include "exec/hwaddr.h"
|
||||||
#include "exec/tb-flush.h"
|
#include "exec/tb-flush.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
#include "gdbstub/commands.h"
|
||||||
#include "gdbstub/syscalls.h"
|
#include "gdbstub/syscalls.h"
|
||||||
#include "gdbstub/user.h"
|
#include "gdbstub/user.h"
|
||||||
#include "gdbstub/enums.h"
|
#include "gdbstub/enums.h"
|
||||||
@ -793,7 +794,7 @@ void gdb_syscall_return(CPUState *cs, int num)
|
|||||||
|
|
||||||
void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
|
void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
const char *param = get_param(params, 0)->data;
|
const char *param = gdb_get_cmd_param(params, 0)->data;
|
||||||
GDBSyscallsMask catch_syscalls_mask;
|
GDBSyscallsMask catch_syscalls_mask;
|
||||||
bool catch_all_syscalls;
|
bool catch_all_syscalls;
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
@ -858,8 +859,8 @@ void gdb_handle_query_xfer_siginfo(GArray *params, void *user_ctx)
|
|||||||
unsigned long offset, len;
|
unsigned long offset, len;
|
||||||
uint8_t *siginfo_offset;
|
uint8_t *siginfo_offset;
|
||||||
|
|
||||||
offset = get_param(params, 0)->val_ul;
|
offset = gdb_get_cmd_param(params, 0)->val_ul;
|
||||||
len = get_param(params, 1)->val_ul;
|
len = gdb_get_cmd_param(params, 1)->val_ul;
|
||||||
|
|
||||||
if (offset + len > gdbserver_user_state.siginfo_len) {
|
if (offset + len > gdbserver_user_state.siginfo_len) {
|
||||||
/* Invalid offset and/or requested length. */
|
/* Invalid offset and/or requested length. */
|
||||||
|
72
include/gdbstub/commands.h
Normal file
72
include/gdbstub/commands.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#ifndef GDBSTUB_COMMANDS_H
|
||||||
|
#define GDBSTUB
|
||||||
|
|
||||||
|
typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
|
||||||
|
|
||||||
|
typedef enum GDBThreadIdKind {
|
||||||
|
GDB_ONE_THREAD = 0,
|
||||||
|
GDB_ALL_THREADS, /* One process, all threads */
|
||||||
|
GDB_ALL_PROCESSES,
|
||||||
|
GDB_READ_THREAD_ERR
|
||||||
|
} GDBThreadIdKind;
|
||||||
|
|
||||||
|
typedef union GdbCmdVariant {
|
||||||
|
const char *data;
|
||||||
|
uint8_t opcode;
|
||||||
|
unsigned long val_ul;
|
||||||
|
unsigned long long val_ull;
|
||||||
|
struct {
|
||||||
|
GDBThreadIdKind kind;
|
||||||
|
uint32_t pid;
|
||||||
|
uint32_t tid;
|
||||||
|
} thread_id;
|
||||||
|
} GdbCmdVariant;
|
||||||
|
|
||||||
|
#define gdb_get_cmd_param(p, i) (&g_array_index(p, GdbCmdVariant, i))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* typedef GdbCmdParseEntry - gdb command parser
|
||||||
|
*
|
||||||
|
* This structure keeps the information necessary to match a gdb command,
|
||||||
|
* parse it (extract its parameters), and select the correct handler for it.
|
||||||
|
*
|
||||||
|
* @cmd: The command to be matched
|
||||||
|
* @cmd_startswith: If true, @cmd is compared using startswith
|
||||||
|
* @schema: Each schema for the command parameter entry consists of 2 chars,
|
||||||
|
* the first char represents the parameter type handling the second char
|
||||||
|
* represents the delimiter for the next parameter.
|
||||||
|
*
|
||||||
|
* Currently supported schema types:
|
||||||
|
* 'l' -> unsigned long (stored in .val_ul)
|
||||||
|
* 'L' -> unsigned long long (stored in .val_ull)
|
||||||
|
* 's' -> string (stored in .data)
|
||||||
|
* 'o' -> single char (stored in .opcode)
|
||||||
|
* 't' -> thread id (stored in .thread_id)
|
||||||
|
* '?' -> skip according to delimiter
|
||||||
|
*
|
||||||
|
* Currently supported delimiters:
|
||||||
|
* '?' -> Stop at any delimiter (",;:=\0")
|
||||||
|
* '0' -> Stop at "\0"
|
||||||
|
* '.' -> Skip 1 char unless reached "\0"
|
||||||
|
* Any other value is treated as the delimiter value itself
|
||||||
|
*
|
||||||
|
* @allow_stop_reply: True iff the gdbstub can respond to this command with a
|
||||||
|
* "stop reply" packet. The list of commands that accept such response is
|
||||||
|
* defined at the GDB Remote Serial Protocol documentation. See:
|
||||||
|
* https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
|
||||||
|
*/
|
||||||
|
typedef struct GdbCmdParseEntry {
|
||||||
|
GdbCmdHandler handler;
|
||||||
|
const char *cmd;
|
||||||
|
bool cmd_startswith;
|
||||||
|
const char *schema;
|
||||||
|
bool allow_stop_reply;
|
||||||
|
} GdbCmdParseEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_put_packet() - put string into gdb server's buffer so it is sent
|
||||||
|
* to the client
|
||||||
|
*/
|
||||||
|
int gdb_put_packet(const char *buf);
|
||||||
|
|
||||||
|
#endif /* GDBSTUB_COMMANDS_H */
|
Loading…
x
Reference in New Issue
Block a user