diff mbox series

[v2,26/39] gdbserver: initial thread support

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

Commit Message

Nicholas Piggin April 20, 2022, 6:50 a.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(-)

Comments

Joel Stanley May 3, 2022, 7:22 a.m. UTC | #1
On Wed, 20 Apr 2022 at 06:51, Nicholas Piggin <npiggin@gmail.com> wrote:
>
> 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>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  libpdbg/hwunit.h |  1 +
>  src/pdbgproxy.c  | 66 ++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 51 insertions(+), 16 deletions(-)
>
> diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h
> index 2ce41db8..563b5812 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 393b37bf..b8ee2a06 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;
>  }
> --
> 2.35.1
>
> --
> Pdbg mailing list
> Pdbg@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg
diff mbox series

Patch

diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h
index 2ce41db8..563b5812 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 393b37bf..b8ee2a06 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;
 }