diff mbox series

[v2,25/38] gdbserver: initial thread support

Message ID 20220329154931.493851-26-npiggin@gmail.com
State New
Headers show
Series gdbserver multi-threaded debugging and POWER9/10 support | expand

Commit Message

Nicholas Piggin March 29, 2022, 3:49 p.m. UTC
Add a command-specific pointer to the struct thread that gdbserver
can use, so it doesn't have to build its own structure of threads.

Initially keep the PIR value in here, as a demonstration.

Later PIR will be used to identify threads to the gdb client, and
more data will be added to the gdb_thread structure to support
debugging multiple threads.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 libpdbg/hwunit.h |  1 +
 src/pdbgproxy.c  | 66 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 51 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h
index 2ce41db..563b581 100644
--- a/libpdbg/hwunit.h
+++ b/libpdbg/hwunit.h
@@ -139,6 +139,7 @@  struct core {
 struct thread {
 	struct pdbg_target target;
 	struct thread_state status;
+	void *gdbserver_priv;
 	int id;
 	struct thread_state (*state)(struct thread *);
 	int (*step)(struct thread *, int);
diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
index 6fa3c6d..c5e439d 100644
--- a/src/pdbgproxy.c
+++ b/src/pdbgproxy.c
@@ -51,6 +51,11 @@  static int fd = -1;
 enum client_state {IDLE, SIGNAL_WAIT};
 static enum client_state state = IDLE;
 
+/* Attached to thread->gdbserver_priv */
+struct gdb_thread {
+	uint64_t pir;
+};
+
 static void destroy_client(int dead_fd);
 
 static uint8_t gdbcrc(char *data)
@@ -666,7 +671,7 @@  static void SIGINT_handler(int sig)
 	gdbserver_running = false;
 }
 
-static int gdbserver_start(struct pdbg_target *thread, struct pdbg_target *adu, uint16_t port)
+static int gdbserver_start(struct pdbg_target *adu, uint16_t port)
 {
 	int sock, i;
 	struct sigaction sa;
@@ -682,7 +687,6 @@  static int gdbserver_start(struct pdbg_target *thread, struct pdbg_target *adu,
 	}
 
 	parser_init(callbacks);
-	thread_target = thread;
 	adu_target = adu;
 
 	sock = socket(PF_INET, SOCK_STREAM, 0);
@@ -767,33 +771,40 @@  static int gdbserver_start(struct pdbg_target *thread, struct pdbg_target *adu,
 
 static int gdbserver(uint16_t port)
 {
-	struct pdbg_target *target, *adu, *thread = NULL;
+	struct pdbg_target *target, *adu, *first_target = NULL;
 
 	for_each_path_target_class("thread", target) {
-		if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED)
+		struct thread *thread = target_to_thread(target);
+		struct gdb_thread *gdb_thread;
+
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
 			continue;
 
-		if (!thread) {
-			thread = target;
+		if (!pdbg_target_compatible(target, "ibm,power8-thread") &&
+		    !pdbg_target_compatible(target, "ibm,power9-thread") &&
+		    !pdbg_target_compatible(target, "ibm,power10-thread")) {
+			PR_ERROR("GDBSERVER is only available on POWER8,9,10\n");
+			return -1;
+		}
+
+		gdb_thread = malloc(sizeof(struct gdb_thread));
+		memset(gdb_thread, 0, sizeof(*gdb_thread));
+		thread->gdbserver_priv = gdb_thread;
+
+		if (!first_target) {
+			first_target = target;
 		} else {
 			fprintf(stderr, "GDB server cannot be run on multiple threads at once.\n");
 			return 0;
 		}
 	}
 
-	if (!thread) {
+	if (!first_target) {
 		fprintf(stderr, "No thread selected\n");
 		return 0;
 	}
 
-	if (!pdbg_target_compatible(thread, "ibm,power8-thread") &&
-	    !pdbg_target_compatible(thread, "ibm,power9-thread") &&
-	    !pdbg_target_compatible(thread, "ibm,power10-thread")) {
-		PR_ERROR("GDBSERVER is only available on POWER8,9,10\n");
-		return -1;
-	}
-
-	if (pdbg_target_compatible(thread, "ibm,power9-thread")) {
+	if (pdbg_target_compatible(first_target, "ibm,power9-thread")) {
 		/*
 		 * XXX: If we advertise no swbreak support on POWER9 does
 		 * that prevent the client using them?
@@ -801,6 +812,29 @@  static int gdbserver(uint16_t port)
 		PR_WARNING("Breakpoints may cause host crashes on POWER9 and should not be used\n");
 	}
 
+	thread_target = first_target;
+
+	for_each_path_target_class("thread", target) {
+		struct thread *thread = target_to_thread(target);
+		struct gdb_thread *gdb_thread;
+
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
+
+		gdb_thread = thread->gdbserver_priv;
+
+		if (thread_getspr(target, SPR_PIR, &gdb_thread->pir)) {
+			PR_ERROR("Error reading PIR. Are all thread in the target cores quiesced?\n");
+			return 0;
+		}
+
+		if (gdb_thread->pir & ~0xffffULL) {
+			/* This limit is just due to some string array sizes */
+			PR_ERROR("PIR exceeds 16-bits.");
+			return 0;
+		}
+	}
+
 	/* Select ADU target */
 	pdbg_for_each_class_target("mem", adu) {
 		if (pdbg_target_probe(adu) == PDBG_TARGET_ENABLED)
@@ -812,7 +846,7 @@  static int gdbserver(uint16_t port)
 		return 0;
 	}
 
-	gdbserver_start(thread, adu, port);
+	gdbserver_start(adu, port);
 
 	return 0;
 }