aboutsummaryrefslogtreecommitdiff
path: root/gdbstub/gdbstub.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdbstub/gdbstub.c')
-rw-r--r--gdbstub/gdbstub.c115
1 files changed, 78 insertions, 37 deletions
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index be18568..6911b73 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -202,16 +202,19 @@ void gdb_memtox(GString *buf, const char *mem, int len)
static uint32_t gdb_get_cpu_pid(CPUState *cpu)
{
- /* TODO: In user mode, we should use the task state PID */
+#ifdef CONFIG_USER_ONLY
+ return getpid();
+#else
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
/* Return the default process' PID */
int index = gdbserver_state.process_num - 1;
return gdbserver_state.processes[index].pid;
}
return cpu->cluster_index + 1;
+#endif
}
-static GDBProcess *gdb_get_process(uint32_t pid)
+GDBProcess *gdb_get_process(uint32_t pid)
{
int i;
@@ -247,7 +250,7 @@ static CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
-static CPUState *get_first_cpu_in_process(GDBProcess *process)
+CPUState *gdb_get_first_cpu_in_process(GDBProcess *process)
{
CPUState *cpu;
@@ -325,7 +328,7 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
return NULL;
}
- return get_first_cpu_in_process(process);
+ return gdb_get_first_cpu_in_process(process);
} else {
/* a specific thread */
cpu = find_cpu(tid);
@@ -354,7 +357,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
size_t len;
int i;
const char *name;
- CPUState *cpu = get_first_cpu_in_process(process);
+ CPUState *cpu = gdb_get_first_cpu_in_process(process);
CPUClass *cc = CPU_GET_CLASS(cpu);
len = 0;
@@ -490,7 +493,7 @@ void gdb_register_coprocessor(CPUState *cpu,
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
{
- CPUState *cpu = get_first_cpu_in_process(p);
+ CPUState *cpu = gdb_get_first_cpu_in_process(p);
while (cpu) {
gdb_breakpoint_remove_all(cpu);
@@ -573,7 +576,6 @@ static int gdb_handle_vcont(const char *p)
{
int res, signal = 0;
char cur_action;
- char *newstates;
unsigned long tmp;
uint32_t pid, tid;
GDBProcess *process;
@@ -581,7 +583,7 @@ static int gdb_handle_vcont(const char *p)
GDBThreadIdKind kind;
unsigned int max_cpus = gdb_get_max_cpus();
/* uninitialised CPUs stay 0 */
- newstates = g_new0(char, max_cpus);
+ g_autofree char *newstates = g_new0(char, max_cpus);
/* mark valid CPUs with 1 */
CPU_FOREACH(cpu) {
@@ -597,8 +599,7 @@ static int gdb_handle_vcont(const char *p)
res = 0;
while (*p) {
if (*p++ != ';') {
- res = -ENOTSUP;
- goto out;
+ return -ENOTSUP;
}
cur_action = *p++;
@@ -606,13 +607,12 @@ static int gdb_handle_vcont(const char *p)
cur_action = qemu_tolower(cur_action);
res = qemu_strtoul(p, &p, 16, &tmp);
if (res) {
- goto out;
+ return res;
}
signal = gdb_signal_to_target(tmp);
} else if (cur_action != 'c' && cur_action != 's') {
/* unknown/invalid/unsupported command */
- res = -ENOTSUP;
- goto out;
+ return -ENOTSUP;
}
if (*p == '\0' || *p == ';') {
@@ -625,14 +625,12 @@ static int gdb_handle_vcont(const char *p)
} else if (*p++ == ':') {
kind = read_thread_id(p, &p, &pid, &tid);
} else {
- res = -ENOTSUP;
- goto out;
+ return -ENOTSUP;
}
switch (kind) {
case GDB_READ_THREAD_ERR:
- res = -EINVAL;
- goto out;
+ return -EINVAL;
case GDB_ALL_PROCESSES:
cpu = gdb_first_attached_cpu();
@@ -649,11 +647,10 @@ static int gdb_handle_vcont(const char *p)
process = gdb_get_process(pid);
if (!process->attached) {
- res = -EINVAL;
- goto out;
+ return -EINVAL;
}
- cpu = get_first_cpu_in_process(process);
+ cpu = gdb_get_first_cpu_in_process(process);
while (cpu) {
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
@@ -668,8 +665,7 @@ static int gdb_handle_vcont(const char *p)
/* invalid CPU/thread specified */
if (!cpu) {
- res = -EINVAL;
- goto out;
+ return -EINVAL;
}
/* only use if no previous match occourred */
@@ -679,12 +675,9 @@ static int gdb_handle_vcont(const char *p)
break;
}
}
+
gdbserver_state.signal = signal;
gdb_continue_partial(newstates);
-
-out:
- g_free(newstates);
-
return res;
}
@@ -1280,7 +1273,7 @@ static void handle_v_attach(GArray *params, void *user_ctx)
goto cleanup;
}
- cpu = get_first_cpu_in_process(process);
+ cpu = gdb_get_first_cpu_in_process(process);
if (!cpu) {
goto cleanup;
}
@@ -1334,6 +1327,36 @@ static const GdbCmdParseEntry gdb_v_commands_table[] = {
.cmd = "Kill;",
.cmd_startswith = 1
},
+#ifdef CONFIG_USER_ONLY
+ /*
+ * Host I/O Packets. See [1] for details.
+ * [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
+ */
+ {
+ .handler = gdb_handle_v_file_open,
+ .cmd = "File:open:",
+ .cmd_startswith = 1,
+ .schema = "s,L,L0"
+ },
+ {
+ .handler = gdb_handle_v_file_close,
+ .cmd = "File:close:",
+ .cmd_startswith = 1,
+ .schema = "l0"
+ },
+ {
+ .handler = gdb_handle_v_file_pread,
+ .cmd = "File:pread:",
+ .cmd_startswith = 1,
+ .schema = "l,L,L0"
+ },
+ {
+ .handler = gdb_handle_v_file_readlink,
+ .cmd = "File:readlink:",
+ .cmd_startswith = 1,
+ .schema = "s0"
+ },
+#endif
};
static void handle_v_commands(GArray *params, void *user_ctx)
@@ -1403,7 +1426,7 @@ static void handle_query_curr_tid(GArray *params, void *user_ctx)
* first thread).
*/
process = gdb_get_cpu_process(gdbserver_state.g_cpu);
- cpu = get_first_cpu_in_process(process);
+ cpu = gdb_get_first_cpu_in_process(process);
g_string_assign(gdbserver_state.str_buf, "QC");
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
gdb_put_strbuf();
@@ -1479,11 +1502,14 @@ static void handle_query_supported(GArray *params, void *user_ctx)
";ReverseStep+;ReverseContinue+");
}
-#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
+#if defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_LINUX)
if (gdbserver_state.c_cpu->opaque) {
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
}
#endif
+ g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
+#endif
if (params->len &&
strstr(get_param(params, 0)->data, "multiprocess+")) {
@@ -1622,7 +1648,8 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
.cmd_startswith = 1,
.schema = "s:l,l0"
},
-#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
+#if defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_LINUX)
{
.handler = gdb_handle_query_xfer_auxv,
.cmd = "Xfer:auxv:read::",
@@ -1631,6 +1658,13 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
},
#endif
{
+ .handler = gdb_handle_query_xfer_exec_file,
+ .cmd = "Xfer:exec-file:read:",
+ .cmd_startswith = 1,
+ .schema = "l:l,l0"
+ },
+#endif
+ {
.handler = gdb_handle_query_attached,
.cmd = "Attached:",
.cmd_startswith = 1
@@ -1814,6 +1848,7 @@ static int gdb_handle_packet(const char *line_buf)
.handler = handle_backward,
.cmd = "b",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "o0"
};
cmd_parser = &backward_cmd_desc;
@@ -2146,19 +2181,25 @@ void gdb_read_byte(uint8_t ch)
void gdb_create_default_process(GDBState *s)
{
GDBProcess *process;
- int max_pid = 0;
+ int pid;
+#ifdef CONFIG_USER_ONLY
+ assert(gdbserver_state.process_num == 0);
+ pid = getpid();
+#else
if (gdbserver_state.process_num) {
- max_pid = s->processes[s->process_num - 1].pid;
+ pid = s->processes[s->process_num - 1].pid;
+ } else {
+ pid = 0;
}
+ /* We need an available PID slot for this process */
+ assert(pid < UINT32_MAX);
+ pid++;
+#endif
s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
process = &s->processes[s->process_num - 1];
-
- /* We need an available PID slot for this process */
- assert(max_pid < UINT32_MAX);
-
- process->pid = max_pid + 1;
+ process->pid = pid;
process->attached = false;
process->target_xml[0] = '\0';
}