[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v8 02/16] gdbstub: introduce GDB processes
From: |
Luc Michel |
Subject: |
[Qemu-devel] [PATCH v8 02/16] gdbstub: introduce GDB processes |
Date: |
Fri, 7 Dec 2018 10:01:20 +0100 |
Add a structure GDBProcess that represents processes from the GDB
semantic point of view.
CPUs can be split into different processes, by grouping them under
different cpu-cluster objects. Each occurrence of a cpu-cluster object
implies the existence of the corresponding process in the GDB stub. The
GDB process ID is derived from the corresponding cluster ID as follows:
GDB PID = cluster ID + 1
This is because PIDs -1 and 0 are reserved in GDB and cannot be used by
processes.
A default process is created to handle CPUs that are not in a cluster.
This process gets the PID of the last process PID + 1.
Signed-off-by: Luc Michel <address@hidden>
Acked-by: Alistair Francis <address@hidden>
Reviewed-by: Edgar E. Iglesias <address@hidden>
Reviewed-by: Philippe Mathieu-Daudé <address@hidden>
---
gdbstub.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/gdbstub.c b/gdbstub.c
index c4e4f9f082..2a3aa0f07e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -27,10 +27,11 @@
#include "monitor/monitor.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "exec/gdbstub.h"
+#include "hw/cpu/cluster.h"
#endif
#define MAX_PACKET_LENGTH 4096
#include "qemu/sockets.h"
@@ -294,10 +295,15 @@ typedef struct GDBRegisterState {
gdb_reg_cb set_reg;
const char *xml;
struct GDBRegisterState *next;
} GDBRegisterState;
+typedef struct GDBProcess {
+ uint32_t pid;
+ bool attached;
+} GDBProcess;
+
enum RSState {
RS_INACTIVE,
RS_IDLE,
RS_GETLINE,
RS_GETLINE_ESC,
@@ -322,10 +328,13 @@ typedef struct GDBState {
int running_state;
#else
CharBackend chr;
Chardev *mon_chr;
#endif
+ bool multiprocess;
+ GDBProcess *processes;
+ int process_num;
char syscall_buf[256];
gdb_syscall_complete_cb current_syscall_cb;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
@@ -1749,10 +1758,34 @@ void gdb_exit(CPUArchState *env, int code)
#ifndef CONFIG_USER_ONLY
qemu_chr_fe_deinit(&s->chr, true);
#endif
}
+/*
+ * Create the process that will contain all the "orphan" CPUs (that are not
+ * part of a CPU cluster). Note that if this process contains no CPUs, it won't
+ * be attachable and thus will be invisible to the user.
+ */
+static void create_default_process(GDBState *s)
+{
+ GDBProcess *process;
+ int max_pid = 0;
+
+ if (s->process_num) {
+ max_pid = s->processes[s->process_num - 1].pid;
+ }
+
+ 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->attached = false;
+}
+
#ifdef CONFIG_USER_ONLY
int
gdb_handlesig(CPUState *cpu, int sig)
{
GDBState *s;
@@ -1846,10 +1879,11 @@ static bool gdb_accept(void)
}
s = g_malloc0(sizeof(GDBState));
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
+ create_default_process(s);
s->fd = fd;
gdb_has_xml = false;
gdbserver_state = s;
return true;
@@ -2002,10 +2036,68 @@ static const TypeInfo char_gdb_type_info = {
.name = TYPE_CHARDEV_GDB,
.parent = TYPE_CHARDEV,
.class_init = char_gdb_class_init,
};
+static int find_cpu_clusters(Object *child, void *opaque)
+{
+ if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
+ GDBState *s = (GDBState *) opaque;
+ CPUClusterState *cluster = CPU_CLUSTER(child);
+ GDBProcess *process;
+
+ s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
+
+ process = &s->processes[s->process_num - 1];
+
+ /*
+ * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
+ * runtime, we enforce here that the machine does not use a cluster ID
+ * that would lead to PID 0. */
+ assert(cluster->cluster_id != UINT32_MAX);
+ process->pid = cluster->cluster_id + 1;
+ process->attached = false;
+
+ return 0;
+ }
+
+ return object_child_foreach(child, find_cpu_clusters, opaque);
+}
+
+static int pid_order(const void *a, const void *b)
+{
+ GDBProcess *pa = (GDBProcess *) a;
+ GDBProcess *pb = (GDBProcess *) b;
+
+ if (pa->pid < pb->pid) {
+ return -1;
+ } else if (pa->pid > pb->pid) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void create_processes(GDBState *s)
+{
+ object_child_foreach(object_get_root(), find_cpu_clusters, s);
+
+ if (s->processes) {
+ /* Sort by PID */
+ qsort(s->processes, s->process_num, sizeof(s->processes[0]),
pid_order);
+ }
+
+ create_default_process(s);
+}
+
+static void cleanup_processes(GDBState *s)
+{
+ g_free(s->processes);
+ s->process_num = 0;
+ s->processes = NULL;
+}
+
int gdbserver_start(const char *device)
{
trace_gdbstub_op_start(device);
GDBState *s;
@@ -2058,15 +2150,19 @@ int gdbserver_start(const char *device)
NULL, &error_abort);
monitor_init(mon_chr, 0);
} else {
qemu_chr_fe_deinit(&s->chr, true);
mon_chr = s->mon_chr;
+ cleanup_processes(s);
memset(s, 0, sizeof(GDBState));
s->mon_chr = mon_chr;
}
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
+
+ create_processes(s);
+
if (chr) {
qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
gdb_chr_event, NULL, NULL, NULL, true);
}
--
2.19.2
- [Qemu-devel] [PATCH v8 00/16] gdbstub: support for the multiprocess extension, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 09/16] gdbstub: add multiprocess support to gdb_vm_state_change(), Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 07/16] gdbstub: add multiprocess support to (f|s)ThreadInfo and ThreadExtraInfo, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 03/16] gdbstub: add multiprocess support to '?' packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 06/16] gdbstub: add multiprocess support to 'sC' packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 02/16] gdbstub: introduce GDB processes,
Luc Michel <=
- [Qemu-devel] [PATCH v8 08/16] gdbstub: add multiprocess support to Xfer:features:read:, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 04/16] gdbstub: add multiprocess support to 'H' and 'T' packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 05/16] gdbstub: add multiprocess support to vCont packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 12/16] gdbstub: add support for vAttach packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 13/16] gdbstub: processes initialization on new peer connection, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 16/16] arm/xlnx-zynqmp: put APUs and RPUs in separate CPU clusters, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 01/16] hw/cpu: introduce CPU clusters, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 10/16] gdbstub: add multiprocess support to 'D' packets, Luc Michel, 2018/12/07
- [Qemu-devel] [PATCH v8 14/16] gdbstub: gdb_set_stop_cpu: ignore request when process is not attached, Luc Michel, 2018/12/07