public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support
@ 2023-01-30  4:45 Thiago Jung Bauermann
  2023-01-30  4:45 ` [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number Thiago Jung Bauermann
                   ` (8 more replies)
  0 siblings, 9 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann

Hello,

This is version 3 of the patch series adding support to gdbserver for
inferiors that change the SVE vector length at runtime. This is already
supported by GDB, but not by gdbserver. Version 2 was posted here:

https://inbox.sourceware.org/gdb-patches/20221126020452.1686509-1-thiago.bauermann@linaro.org/

This version incorporates the review comments from v2 (thanks!). The
biggest change is that it implements Simon's idea¹:

> If it's the case, that we need to extend the RSP to allow fetching
> per-thread tdesc, here's the idea I had in mind for a while, to avoid
> adding too much overhead.  Stop replies and the qXfer:threads:read reply
> could include a per-thread tdesc identifier.  That tdesc identifier
> would be something short, either an incrementing number, or some kind of
> hash of the tdesc.  It would be something opaque chosen by the stub.  A
> new packet would be introduced to allow GDB to request the XML given
> that ID.  On the GDB side, GDB would request the XML when encountering a
> tdesc ID it doesn't know about, and then cache the result.

The only difference from the above in this series is that instead of
creating a new packet to allow GDB to request the XML given the ID, I'm
extending the qXfer:features:read request: GDB can send "target-id-%u.xml"
as the annex, where %u is the target description ID. Please let me know if
you think a separate packet would be better. The remote protocol changes
are documented in patch 5.

I had to drop the Reviewed-by tags from some patches because they have some
significant changes from the version that was reviewed.

There's also a new testcase exercising the case of an inferior's thread
changing its SVE vector length. The previous version of this series failed
the testcase, but this one passes it.

With this series applied, gdb.arch/aarch64-sve.exp passes all tests on
extended-remote aarch64-linux. Without them, it fails tests after the
testcase changes the vector length.

Tested on native and extended-remote aarch64-linux, x86_64-linux and
armv7l-linux-gnueabihf (the last one on QEMU TCG).

¹ https://inbox.sourceware.org/gdb-patches/559069a3-f3ce-2059-bf4a-44add43979f7@simark.ca/

Changes since v2:

- Patch “gdbserver: Add assert in find_register_by_number”
  - Rewritten to follow Simon's suggestion of putting the assert in another
    function.
- Patch “gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap”
  - As suggested by Simon, directly access thread_info::id rather than use
    pid_of.
  - Also as suggested by Simon, updated doc comment of
    process_stratum_target::read_auxv.
- Patch “gdbserver/linux-aarch64: Factor out function to get aarch64_features”
  - As suggested by Simon, directly access thread_info::id rather than use
    lwpid_of.
  - Also as suggested by Simon, added doc comment for
    aarch64_get_arch_features.
- Patch “gdbserver/linux-aarch64: When thread stops, update its target description”
  - As suggested by Luis, added doc comments to thread_info::tdesc and
    arch_process_info::has_sve.
  - As suggested by Simon, renamed arch_update_tdesc to get_thread_tdesc,
    and return a target_desc pointer (or nullptr) instead of one wrapped in
    gdb::optional.  The code was changed a bit as well.
  - As suggested by Luis, expanded doc comment of get_thread_tdesc.
  - As suggested by Luis, abstracted away trying to fetch a tdesc from a
    thread and then from a process to a new function
    "get_thread_target_desc".
  - Export free_register_cache_thread in gdbserver/regcache.h.
  - Use free_register_cache_thread in linux_process_target::filter_event to
    implement Simon's suggestion of only freeing the regcache for the
    thread with a different tdesc.
- “gdb/aarch64: Factor out most of the thread_architecture method”
  - Dropped this patch. It's not needed anymore.
- “gdbserver: Transmit target description ID in thread list and stop reply”
  - New patch.
- “gdb/remote: Parse and use tdesc field in stop reply and threads list XML”
  - New patch.
- “gdb/aarch64: Detect vector length changes when debugging remotely”
  - As suggested by Luis, clarified in the patch description that this patch improves
    debugging programs remotely. Also, reworded description somewhat.
  - As suggested by Luis, changed VL references in comments to VG. Also reworded a bit the
    description of the update_architecture gdbarch method.
  - Changed the update_architecture gdbarch method (and consequently also
    aarch64_update_architecture) to take a target description instead of a vector of
    cached_reg_t.
  - Changed remote_target::update_thread_list to get the thread target description from
    the remote target.
  - Changed remote_target::process_stop_reply to get the thread target description from
    the remote target.
  - Renamed remote_thread_info::expedited_arch to arch.
  - Changed code of remote_target::thread_architecture to be a little bit clearer, and
    added doc comment.
- “gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors”
  - New patch.

Thiago Jung Bauermann (8):
  gdbserver: Add assert in find_register_by_number
  gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  gdbserver/linux-aarch64: Factor out function to get aarch64_features
  gdbserver/linux-aarch64: When thread stops, update its target
    description
  gdbserver: Transmit target description ID in thread list and stop
    reply
  gdb/remote: Parse tdesc field in stop reply and threads list XML
  gdb/aarch64: Detect vector length changes when debugging remotely
  gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE
    inferiors

 gdb/aarch64-tdep.c                            |  20 +++
 gdb/arch-utils.c                              |   8 +
 gdb/arch-utils.h                              |   4 +
 gdb/doc/gdb.texinfo                           |  27 ++-
 gdb/features/threads.dtd                      |   1 +
 gdb/gdbarch-components.py                     |  15 ++
 gdb/gdbarch-gen.h                             |  10 ++
 gdb/gdbarch.c                                 |  22 +++
 gdb/remote.c                                  | 169 +++++++++++++++++-
 gdb/testsuite/gdb.arch/aarch64-sve-threads.c  | 125 +++++++++++++
 .../gdb.arch/aarch64-sve-threads.exp          |  70 ++++++++
 gdb/xml-tdesc.c                               |  27 ++-
 gdb/xml-tdesc.h                               |   6 +
 gdbserver/gdbthread.h                         |   4 +
 gdbserver/linux-aarch64-low.cc                |  68 +++++--
 gdbserver/linux-arm-low.cc                    |   2 +-
 gdbserver/linux-low.cc                        |  35 +++-
 gdbserver/linux-low.h                         |  15 +-
 gdbserver/linux-ppc-low.cc                    |   6 +-
 gdbserver/linux-s390-low.cc                   |   2 +-
 gdbserver/netbsd-low.cc                       |   4 +-
 gdbserver/netbsd-low.h                        |   2 +-
 gdbserver/regcache.cc                         |  14 +-
 gdbserver/regcache.h                          |   4 +
 gdbserver/remote-utils.cc                     |  57 ++++++
 gdbserver/remote-utils.h                      |   9 +
 gdbserver/server.cc                           |  20 ++-
 gdbserver/server.h                            |   4 +
 gdbserver/target.cc                           |   4 +-
 gdbserver/target.h                            |   4 +-
 gdbserver/tdesc.cc                            |  13 +-
 gdbserver/tdesc.h                             |   5 +
 32 files changed, 717 insertions(+), 59 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.exp


base-commit: 6c76a6beade05f8b2ca93e939cf73da2917d379b

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-01-31 17:05   ` Simon Marchi
  2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann, Simon Marchi

It helped me during development, catching bugs closer to when they actually
happened.

Also remove the equivalent gdb_assert in regcache_raw_read_unsigned, since
it's checking the same condition a few frames above.

Suggested-By: Simon Marchi <simon.marchi@efficios.com>
---
 gdbserver/regcache.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index 3aeefcc79a37..7b896a19767d 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -199,6 +199,8 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
 static const struct gdb::reg &
 find_register_by_number (const struct target_desc *tdesc, int n)
 {
+  gdb_assert (n >= 0 && n < tdesc->reg_defs.size ());
+
   return tdesc->reg_defs[n];
 }
 
@@ -440,8 +442,6 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
   int size;
 
   gdb_assert (regcache != NULL);
-  gdb_assert (regnum >= 0
-	      && regnum < regcache->tdesc->reg_defs.size ());
 
   size = register_size (regcache->tdesc, regnum);
 

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
  2023-01-30  4:45 ` [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01  9:07   ` Luis Machado
                     ` (2 more replies)
  2023-01-30  4:45 ` [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features Thiago Jung Bauermann
                   ` (6 subsequent siblings)
  8 siblings, 3 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann, Simon Marchi

This patch doesn't change gdbserver behaviour, but after later changes are
made it avoids a null pointer dereference when HWCAP needs to be obtained
for a specific process while current_thread is nullptr.

Fixing linux_read_auxv, linux_get_hwcap and linux_get_hwcap2 to take a PID
parameter seems more correct than setting current_thread in one particular
code path.

Changes are propagated to allow passing the new parameter through the call
chain.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
---
 gdbserver/linux-aarch64-low.cc |  7 ++++---
 gdbserver/linux-arm-low.cc     |  2 +-
 gdbserver/linux-low.cc         | 18 +++++++++---------
 gdbserver/linux-low.h          |  9 ++++-----
 gdbserver/linux-ppc-low.cc     |  6 +++---
 gdbserver/linux-s390-low.cc    |  2 +-
 gdbserver/netbsd-low.cc        |  4 +---
 gdbserver/netbsd-low.h         |  2 +-
 gdbserver/server.cc            |  3 ++-
 gdbserver/target.cc            |  4 ++--
 gdbserver/target.h             |  4 ++--
 11 files changed, 30 insertions(+), 31 deletions(-)

diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 3c09e086afee..2ed6e95562c5 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -846,12 +846,13 @@ aarch64_target::low_arch_setup ()
   if (is_elf64)
     {
       struct aarch64_features features;
+      int pid = current_thread->id.pid ();
 
       features.vq = aarch64_sve_get_vq (tid);
       /* A-profile PAC is 64-bit only.  */
-      features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
+      features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
       /* A-profile MTE is 64-bit only.  */
-      features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
+      features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
       features.tls = aarch64_tls_register_count (tid);
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
@@ -3322,7 +3323,7 @@ aarch64_target::supports_memory_tagging ()
 #endif
     }
 
-  return (linux_get_hwcap2 (8) & HWCAP2_MTE) != 0;
+  return (linux_get_hwcap2 (current_thread->id.pid (), 8) & HWCAP2_MTE) != 0;
 }
 
 bool
diff --git a/gdbserver/linux-arm-low.cc b/gdbserver/linux-arm-low.cc
index 98ba0e02524b..5975b44af0ae 100644
--- a/gdbserver/linux-arm-low.cc
+++ b/gdbserver/linux-arm-low.cc
@@ -958,7 +958,7 @@ get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
 static const struct target_desc *
 arm_read_description (void)
 {
-  unsigned long arm_hwcap = linux_get_hwcap (4);
+  unsigned long arm_hwcap = linux_get_hwcap (current_thread->id.pid (), 4);
 
   if (arm_hwcap & HWCAP_IWMMXT)
     return arm_linux_read_description (ARM_FP_TYPE_IWMMXT);
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 7e1de3978933..5cd22824e470 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -5483,12 +5483,11 @@ linux_process_target::supports_read_auxv ()
    to debugger memory starting at MYADDR.  */
 
 int
-linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
-				 unsigned int len)
+linux_process_target::read_auxv (int pid, CORE_ADDR offset,
+				 unsigned char *myaddr, unsigned int len)
 {
   char filename[PATH_MAX];
   int fd, n;
-  int pid = lwpid_of (current_thread);
 
   xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
 
@@ -6982,14 +6981,15 @@ linux_get_pc_64bit (struct regcache *regcache)
 /* See linux-low.h.  */
 
 int
-linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
+linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp)
 {
   gdb_byte *data = (gdb_byte *) alloca (2 * wordsize);
   int offset = 0;
 
   gdb_assert (wordsize == 4 || wordsize == 8);
 
-  while (the_target->read_auxv (offset, data, 2 * wordsize) == 2 * wordsize)
+  while (the_target->read_auxv (pid, offset, data, 2 * wordsize)
+	 == 2 * wordsize)
     {
       if (wordsize == 4)
 	{
@@ -7019,20 +7019,20 @@ linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
 /* See linux-low.h.  */
 
 CORE_ADDR
-linux_get_hwcap (int wordsize)
+linux_get_hwcap (int pid, int wordsize)
 {
   CORE_ADDR hwcap = 0;
-  linux_get_auxv (wordsize, AT_HWCAP, &hwcap);
+  linux_get_auxv (pid, wordsize, AT_HWCAP, &hwcap);
   return hwcap;
 }
 
 /* See linux-low.h.  */
 
 CORE_ADDR
-linux_get_hwcap2 (int wordsize)
+linux_get_hwcap2 (int pid, int wordsize)
 {
   CORE_ADDR hwcap2 = 0;
-  linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2);
+  linux_get_auxv (pid, wordsize, AT_HWCAP2, &hwcap2);
   return hwcap2;
 }
 
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index aebfe05707e5..221de85aa2ee 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -178,7 +178,7 @@ class linux_process_target : public process_stratum_target
 
   bool supports_read_auxv () override;
 
-  int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
+  int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
 		 unsigned int len) override;
 
   int insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
@@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
    *VALP and return 1.  If not found or if there is an error, return
    0.  */
 
-int linux_get_auxv (int wordsize, CORE_ADDR match,
-		    CORE_ADDR *valp);
+int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
 
 /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
    WORDSIZE.  If no entry was found, return zero.  */
 
-CORE_ADDR linux_get_hwcap (int wordsize);
+CORE_ADDR linux_get_hwcap (int pid, int wordsize);
 
 /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
    WORDSIZE.  If no entry was found, return zero.  */
 
-CORE_ADDR linux_get_hwcap2 (int wordsize);
+CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
 
 #endif /* GDBSERVER_LINUX_LOW_H */
diff --git a/gdbserver/linux-ppc-low.cc b/gdbserver/linux-ppc-low.cc
index fdf74727e392..f8dd770b8eb3 100644
--- a/gdbserver/linux-ppc-low.cc
+++ b/gdbserver/linux-ppc-low.cc
@@ -894,8 +894,8 @@ ppc_target::low_arch_setup ()
 
   /* The value of current_process ()->tdesc needs to be set for this
      call.  */
-  ppc_hwcap = linux_get_hwcap (features.wordsize);
-  ppc_hwcap2 = linux_get_hwcap2 (features.wordsize);
+  ppc_hwcap = linux_get_hwcap (current_thread->id.pid (), features.wordsize);
+  ppc_hwcap2 = linux_get_hwcap2 (current_thread->id.pid (), features.wordsize);
 
   features.isa205 = ppc_linux_has_isa205 (ppc_hwcap);
 
@@ -1097,7 +1097,7 @@ is_elfv2_inferior (void)
   const struct target_desc *tdesc = current_process ()->tdesc;
   int wordsize = register_size (tdesc, 0);
 
-  if (!linux_get_auxv (wordsize, AT_PHDR, &phdr))
+  if (!linux_get_auxv (current_thread->id.pid (), wordsize, AT_PHDR, &phdr))
     return def_res;
 
   /* Assume ELF header is at the beginning of the page where program headers
diff --git a/gdbserver/linux-s390-low.cc b/gdbserver/linux-s390-low.cc
index b3ccdff3e57f..48f64ef7bb3b 100644
--- a/gdbserver/linux-s390-low.cc
+++ b/gdbserver/linux-s390-low.cc
@@ -592,7 +592,7 @@ s390_target::low_arch_setup ()
   /* Determine word size and HWCAP.  */
   int pid = pid_of (current_thread);
   int wordsize = s390_get_wordsize (pid);
-  unsigned long hwcap = linux_get_hwcap (wordsize);
+  unsigned long hwcap = linux_get_hwcap (pid, wordsize);
 
   /* Check whether the kernel supports extra register sets.  */
   int have_regset_last_break
diff --git a/gdbserver/netbsd-low.cc b/gdbserver/netbsd-low.cc
index 15afa36d1152..4defd79eee47 100644
--- a/gdbserver/netbsd-low.cc
+++ b/gdbserver/netbsd-low.cc
@@ -581,11 +581,9 @@ netbsd_read_auxv(pid_t pid, void *offs, void *addr, size_t len)
    to debugger memory starting at MYADDR.  */
 
 int
-netbsd_process_target::read_auxv (CORE_ADDR offset,
+netbsd_process_target::read_auxv (int pid, CORE_ADDR offset,
 				  unsigned char *myaddr, unsigned int len)
 {
-  pid_t pid = pid_of (current_thread);
-
   return netbsd_read_auxv (pid, (void *) (intptr_t) offset, myaddr, len);
 }
 
diff --git a/gdbserver/netbsd-low.h b/gdbserver/netbsd-low.h
index daefc302785e..050b43fc54f4 100644
--- a/gdbserver/netbsd-low.h
+++ b/gdbserver/netbsd-low.h
@@ -77,7 +77,7 @@ class netbsd_process_target : public process_stratum_target
 
   bool supports_read_auxv () override;
 
-  int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
+  int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
 		 unsigned int len) override;
 
   bool supports_hardware_single_step () override;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index d802e8b4a341..21fb51a45d16 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -1443,7 +1443,8 @@ handle_qxfer_auxv (const char *annex,
   if (annex[0] != '\0' || current_thread == NULL)
     return -1;
 
-  return the_target->read_auxv (offset, readbuf, len);
+  return the_target->read_auxv (current_thread->id.pid (), offset, readbuf,
+				len);
 }
 
 /* Handle qXfer:exec-file:read.  */
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index 24b8e2160138..b4f8e9f1efb6 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -344,8 +344,8 @@ process_stratum_target::supports_read_auxv ()
 }
 
 int
-process_stratum_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
-				   unsigned int len)
+process_stratum_target::read_auxv (int pid, CORE_ADDR offset,
+				   unsigned char *myaddr, unsigned int len)
 {
   gdb_assert_not_reached ("target op read_auxv not supported");
 }
diff --git a/gdbserver/target.h b/gdbserver/target.h
index eea651c30b4b..1b0caa98c56a 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -172,10 +172,10 @@ class process_stratum_target
   /* Return true if the read_auxv target op is supported.  */
   virtual bool supports_read_auxv ();
 
-  /* Read auxiliary vector data from the inferior process.
+  /* Read auxiliary vector data from the process with pid PID.
 
      Read LEN bytes at OFFSET into a buffer at MYADDR.  */
-  virtual int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
+  virtual int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
 			 unsigned int len);
 
   /* Returns true if GDB Z breakpoint type TYPE is supported, false

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
  2023-01-30  4:45 ` [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number Thiago Jung Bauermann
  2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01  8:59   ` Luis Machado
  2023-01-30  4:45 ` [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description Thiago Jung Bauermann
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann, Luis Machado, Simon Marchi

It will be used in a subsequent commit.  There's no functional change.

Reviewed-by: Luis Machado <luis.machado@arm.com>
Approved-By: Simon Marchi <simon.marchi@efficios.com>
---
 gdbserver/linux-aarch64-low.cc | 36 ++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 2ed6e95562c5..92c621e5548c 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -675,6 +675,28 @@ aarch64_target::low_delete_process (arch_process_info *info)
   xfree (info);
 }
 
+/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
+#define AARCH64_HWCAP_PACA (1 << 30)
+
+/* Obtain the architectural features available in the given THREAD.  */
+
+static struct aarch64_features
+aarch64_get_arch_features (const thread_info *thread)
+{
+  struct aarch64_features features;
+  int pid = thread->id.pid ();
+  int tid = thread->id.lwp ();
+
+  features.vq = aarch64_sve_get_vq (tid);
+  /* A-profile PAC is 64-bit only.  */
+  features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
+  /* A-profile MTE is 64-bit only.  */
+  features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
+  features.tls = aarch64_tls_register_count (tid);
+
+  return features;
+}
+
 void
 aarch64_target::low_new_thread (lwp_info *lwp)
 {
@@ -827,9 +849,6 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
     }
 }
 
-/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
-#define AARCH64_HWCAP_PACA (1 << 30)
-
 /* Implementation of linux target ops method "low_arch_setup".  */
 
 void
@@ -845,15 +864,8 @@ aarch64_target::low_arch_setup ()
 
   if (is_elf64)
     {
-      struct aarch64_features features;
-      int pid = current_thread->id.pid ();
-
-      features.vq = aarch64_sve_get_vq (tid);
-      /* A-profile PAC is 64-bit only.  */
-      features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
-      /* A-profile MTE is 64-bit only.  */
-      features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
-      features.tls = aarch64_tls_register_count (tid);
+      struct aarch64_features features
+	  = aarch64_get_arch_features (current_thread);
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
 

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (2 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01  9:05   ` Luis Machado
  2023-02-01 11:06   ` Andrew Burgess
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann, Luis Machado

This change prepares gdbserver to support remotely debugging programs in
aarch64-linux where different threads have different SVE vector lengths.
It allows gdbserver to support different inferior threads having different
target descriptions.

To that end, a tdesc field is added to struct thread_info.  If it's
nullptr (the default) it means that the thread uses the target description
stored in struct process_info and thus gdbserver behaviour is unchanged.
The get_thread_tdesc method is added to the linux_process_target class to
allow aarch64-linux code to probe the inferior's vq register and provide a
thread-specific target description reflecting the new vector length.

After this change, all targets except SVE-supporting aarch64-linux will
still use per-process target descriptions.

Reviewed-by: Luis Machado <luis.machado@arm.com>
---
 gdbserver/gdbthread.h          |  4 ++++
 gdbserver/linux-aarch64-low.cc | 31 +++++++++++++++++++++++++++++++
 gdbserver/linux-low.cc         | 17 +++++++++++++++++
 gdbserver/linux-low.h          |  6 ++++++
 gdbserver/regcache.cc          | 10 ++++++----
 gdbserver/regcache.h           |  4 ++++
 gdbserver/tdesc.cc             | 13 ++++++++++++-
 gdbserver/tdesc.h              |  5 +++++
 8 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
index 493e1dbf6cb6..5b5ba6f8e521 100644
--- a/gdbserver/gdbthread.h
+++ b/gdbserver/gdbthread.h
@@ -80,6 +80,10 @@ struct thread_info
 
   /* Branch trace target information for this thread.  */
   struct btrace_target_info *btrace = nullptr;
+
+  /* Target description for this thread.  Only present if it's different
+     from the one in process_info.  */
+  const struct target_desc *tdesc = nullptr;
 };
 
 extern std::list<thread_info *> all_threads;
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 92c621e5548c..69765ee90db3 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -99,6 +99,9 @@ protected:
 
   void low_arch_setup () override;
 
+  const struct target_desc *
+    get_thread_tdesc (const thread_info *thread) override;
+
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
@@ -184,6 +187,9 @@ struct arch_process_info
      same for each thread, it is reasonable for the data to live here.
      */
   struct aarch64_debug_reg_state debug_reg_state;
+
+  /* Whether this process has the Scalable Vector Extension available.  */
+  bool has_sve;
 };
 
 /* Return true if the size of register 0 is 8 byte.  */
@@ -869,6 +875,9 @@ aarch64_target::low_arch_setup ()
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
 
+      if (features.vq > 0)
+	current_process ()->priv->arch_private->has_sve = true;
+
       /* Adjust the register sets we should use for this particular set of
 	 features.  */
       aarch64_adjust_register_sets (features);
@@ -879,6 +888,28 @@ aarch64_target::low_arch_setup ()
   aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
 }
 
+/* Implementation of linux target ops method "get_thread_tdesc".  */
+
+const struct target_desc *
+aarch64_target::get_thread_tdesc (const thread_info *thread)
+{
+  const struct process_info *process = get_thread_process (thread);
+
+  /* Only inferiors with SVE need a thread-specific target description.  */
+  if (!process->priv->arch_private->has_sve)
+    return nullptr;
+
+  const struct aarch64_features features = aarch64_get_arch_features (thread);
+  const struct target_desc *tdesc = aarch64_linux_read_description (features);
+
+  /* If the target description we just found is the same as the process-wide
+     one, there's no need to set a thread-specific one.  */
+  if (tdesc == process->tdesc)
+    return nullptr;
+
+  return tdesc;
+}
+
 /* Implementation of linux target ops method "get_regs_info".  */
 
 const regs_info *
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 5cd22824e470..47916009ebaf 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -483,6 +483,12 @@ linux_process_target::arch_setup_thread (thread_info *thread)
   low_arch_setup ();
 }
 
+const struct target_desc *
+linux_process_target::get_thread_tdesc (const thread_info *thread)
+{
+  return nullptr;
+}
+
 int
 linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
 					    int wstat)
@@ -2348,6 +2354,17 @@ linux_process_target::filter_event (int lwpid, int wstat)
 	      return;
 	    }
 	}
+      else
+	{
+	  /* Give the arch code an opportunity to set the thread's target
+	     description.  */
+	  const struct target_desc *new_tdesc = get_thread_tdesc (thread);
+	  if (new_tdesc != thread->tdesc)
+	    {
+	      free_register_cache_thread (thread);
+	      thread->tdesc = new_tdesc;
+	    }
+	}
     }
 
   if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags)
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 221de85aa2ee..b52eb23cc444 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
   /* Architecture-specific setup for the current thread.  */
   virtual void low_arch_setup () = 0;
 
+  /* Allows arch-specific code to set the thread's target description when the
+     inferior stops.  Returns nullptr if no thread-specific target description
+     is necessary.  */
+  virtual const struct target_desc *
+    get_thread_tdesc (const thread_info *thread);
+
   /* Return false if we can fetch/store the register, true if we cannot
      fetch/store the register.  */
   virtual bool low_cannot_fetch_register (int regno) = 0;
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index 7b896a19767d..fb60e2c9c399 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -39,11 +39,11 @@ get_thread_regcache (struct thread_info *thread, int fetch)
      have.  */
   if (regcache == NULL)
     {
-      struct process_info *proc = get_thread_process (thread);
+      const target_desc *tdesc = get_thread_target_desc (thread);
 
-      gdb_assert (proc->tdesc != NULL);
+      gdb_assert (tdesc != nullptr);
 
-      regcache = new_register_cache (proc->tdesc);
+      regcache = new_register_cache (tdesc);
       set_thread_regcache_data (thread, regcache);
     }
 
@@ -270,7 +270,9 @@ find_regno (const struct target_desc *tdesc, const char *name)
   internal_error ("Unknown register %s requested", name);
 }
 
-static void
+/* See regcache.h.  */
+
+void
 free_register_cache_thread (struct thread_info *thread)
 {
   struct regcache *regcache = thread_regcache_data (thread);
diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
index 7248bcf5808a..4beea0139cd6 100644
--- a/gdbserver/regcache.h
+++ b/gdbserver/regcache.h
@@ -79,6 +79,10 @@ void free_register_cache (struct regcache *regcache);
 
 void regcache_invalidate_thread (struct thread_info *);
 
+/* Invalidate and release the register cache of the given THREAD.  */
+
+void free_register_cache_thread (struct thread_info *thread);
+
 /* Invalidate cached registers for all threads of the given process.  */
 
 void regcache_invalidate_pid (int pid);
diff --git a/gdbserver/tdesc.cc b/gdbserver/tdesc.cc
index 2c7257c458f4..e3339dde4d6c 100644
--- a/gdbserver/tdesc.cc
+++ b/gdbserver/tdesc.cc
@@ -123,13 +123,24 @@ copy_target_description (struct target_desc *dest,
   dest->xmltarget = src->xmltarget;
 }
 
+/* See tdesc.h.  */
+
+const struct target_desc *
+get_thread_target_desc (const struct thread_info *thread)
+{
+  if (thread->tdesc != nullptr)
+    return thread->tdesc;
+
+  return get_thread_process (thread)->tdesc;
+}
+
 const struct target_desc *
 current_target_desc (void)
 {
   if (current_thread == NULL)
     return &default_description;
 
-  return current_process ()->tdesc;
+  return get_thread_target_desc (current_thread);
 }
 
 /* An empty structure.  */
diff --git a/gdbserver/tdesc.h b/gdbserver/tdesc.h
index 7fe7d0d8eb30..71cc5b51c84e 100644
--- a/gdbserver/tdesc.h
+++ b/gdbserver/tdesc.h
@@ -88,6 +88,11 @@ void copy_target_description (struct target_desc *dest,
 void init_target_desc (struct target_desc *tdesc,
 		       const char **expedite_regs);
 
+/* Return the target description corresponding to the given THREAD.  */
+
+const struct target_desc *
+  get_thread_target_desc (const struct thread_info *thread);
+
 /* Return the current inferior's target description.  Never returns
    NULL.  */
 

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (3 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-01-30 12:52   ` Eli Zaretskii
                     ` (3 more replies)
  2023-01-30  4:45 ` [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML Thiago Jung Bauermann
                   ` (3 subsequent siblings)
  8 siblings, 4 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann, Simon Marchi

Now that an inferior thread can have a different target description than
its process, there needs to be a way to communicate this target
description to GDB.  So add the concept of a target description ID to the
remote protocol, which is used to reference them and allows them to be
transferred only once over the wire.

The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
unsigned integer containing the ID.

It is also sent in the threads list XML in the response of a
qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
the <thread> node.

To request the target description XML of a given ID, GDB sends the
qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
is the target description ID.

Suggested-By: Simon Marchi <simon.marchi@efficios.com>
---
 gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
 gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
 gdbserver/remote-utils.h  |  9 +++++++
 gdbserver/server.cc       | 17 ++++++++++--
 gdbserver/server.h        |  4 +++
 5 files changed, 109 insertions(+), 5 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9c0018ea5c14..fbf7e59853b5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -42030,6 +42030,10 @@ the stopped thread, as specified in @ref{thread-id syntax}.
 If @var{n} is @samp{core}, then @var{r} is the hexadecimal number of
 the core on which the stop event was detected.
 
+@item
+If @var{n} is @samp{tdesc}, then @var{r} is the hexadecimal number of
+the target description ID (@pxref{Target Description ID}).
+
 @item
 If @var{n} is a recognized @dfn{stop reason}, it describes a more
 specific event that stopped the target.  The currently defined stop
@@ -46546,7 +46550,7 @@ the following structure:
 @smallexample
 <?xml version="1.0"?>
 <threads>
-    <thread id="id" core="0" name="name">
+    <thread id="id" core="0" name="name" tdesc="0">
     ... description ...
     </thread>
 </threads>
@@ -46556,8 +46560,10 @@ Each @samp{thread} element must have the @samp{id} attribute that
 identifies the thread (@pxref{thread-id syntax}).  The
 @samp{core} attribute, if present, specifies which processor core
 the thread was last executing on.  The @samp{name} attribute, if
-present, specifies the human-readable name of the thread.  The content
-of the of @samp{thread} element is interpreted as human-readable
+present, specifies the human-readable name of the thread.  The
+@samp{tdesc} attribute, if present, specifies the target description
+ID of the thread (@pxref{Target Description ID}).  The content of
+the @samp{thread} element is interpreted as human-readable
 auxiliary information.  The @samp{handle} attribute, if present,
 is a hex encoded representation of the thread handle.
 
@@ -46767,6 +46773,8 @@ descriptions are accurate, and that @value{GDBN} understands them.
 target descriptions.  @xref{Expat}.
 
 @menu
+* Target Description ID::           Referencing different descriptions in the
+                                    remote protocol.
 * Retrieving Descriptions::         How descriptions are fetched from a target.
 * Target Description Format::       The contents of a target description.
 * Predefined Target Types::         Standard types available for target
@@ -46775,6 +46783,14 @@ target descriptions.  @xref{Expat}.
 * Standard Target Features::        Features @value{GDBN} knows about.
 @end menu
 
+@node Target Description ID
+@section Target Description ID
+
+In cases where a remote target supports threads having different
+target descriptions than their parent process, the remote protocol
+assigns a non-negative integer to each target description to reference
+it in the communication between the host and the target.
+
 @node Retrieving Descriptions
 @section Retrieving Descriptions
 
@@ -46787,6 +46803,11 @@ qXfer}).  The @var{annex} in the @samp{qXfer} packet will be
 XML document, of the form described in @ref{Target Description
 Format}.
 
+If target description IDs are being used (@pxref{Target Description ID}),
+@value{GDBN} can retrieve a target description with a given ID by using
+@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
+non-negative integer identifier of the desired target description.
+
 Alternatively, you can specify a file to read for the target description.
 If a file is set, the target will not be queried.  The commands to
 specify a file are:
diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
index 80310bc2c709..baff899307cc 100644
--- a/gdbserver/remote-utils.cc
+++ b/gdbserver/remote-utils.cc
@@ -1049,6 +1049,53 @@ outreg (struct regcache *regcache, int regno, char *buf)
   return buf;
 }
 
+/* See remote-utils.h.  */
+
+unsigned int
+get_tdesc_rsp_id (const target_desc *tdesc)
+{
+  client_state &cs = get_client_state ();
+  unsigned int i;
+
+  for (i = 0; i < cs.tdescs.size (); i++)
+    if (cs.tdescs[i] == tdesc)
+      return i;
+
+  cs.tdescs.push_back (tdesc);
+
+  return i;
+}
+
+/* See remote-utils.h.  */
+
+const target_desc *
+get_tdesc_from_rsp_id (unsigned int id)
+{
+  client_state &cs = get_client_state ();
+
+  if (id >= cs.tdescs.size ())
+    return nullptr;
+
+  return cs.tdescs[id];
+}
+
+/* Return the ID as used in the remote protocol for the target descriptor of the
+   given PTID.  */
+
+static unsigned int
+get_tdesc_rsp_id (ptid_t ptid)
+{
+  const thread_info *thread = find_thread_ptid (ptid);
+  const target_desc *tdesc;
+
+  if (thread == nullptr)
+    tdesc = find_process_pid (ptid.pid ())->tdesc;
+  else
+    tdesc = get_thread_target_desc (thread);
+
+  return get_tdesc_rsp_id (tdesc);
+}
+
 void
 prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
 {
@@ -1241,6 +1288,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
 	    buf += strlen (buf);
 	    current_process ()->dlls_changed = false;
 	  }
+
+	if (current_thread->tdesc != nullptr
+	    && current_thread->tdesc != current_process ()->tdesc)
+	  {
+	    sprintf (buf, "tdesc:");
+	    buf += strlen (buf);
+	    sprintf (buf, "%x", get_tdesc_rsp_id (ptid));
+	    strcat (buf, ";");
+	    buf += strlen (buf);
+	  }
       }
       break;
     case TARGET_WAITKIND_EXITED:
diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h
index cb2d6c346c99..61ef80b4dad7 100644
--- a/gdbserver/remote-utils.h
+++ b/gdbserver/remote-utils.h
@@ -75,4 +75,13 @@ int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc);
 
 void monitor_output (const char *msg);
 
+/* Return the ID as used in the remote protocol for the given target
+   descriptor.  */
+
+unsigned int get_tdesc_rsp_id (const target_desc *tdesc);
+
+/* Return the target description corresponding to the remote protocol ID.  */
+
+const target_desc *get_tdesc_from_rsp_id (unsigned int id);
+
 #endif /* GDBSERVER_REMOTE_UTILS_H */
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 21fb51a45d16..2d1062f98468 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -976,7 +976,15 @@ handle_general_set (char *own_buf)
 static const char *
 get_features_xml (const char *annex)
 {
-  const struct target_desc *desc = current_target_desc ();
+  const struct target_desc *desc;
+  unsigned int id;
+
+  if (strcmp (annex, "target.xml") == 0)
+    desc = current_target_desc ();
+  else if (sscanf (annex, "target-id-%u.xml", &id) == 1)
+    desc = get_tdesc_from_rsp_id (id);
+  else
+    desc = nullptr;
 
   /* `desc->xmltarget' defines what to return when looking for the
      "target.xml" file.  Its contents can either be verbatim XML code
@@ -986,7 +994,7 @@ get_features_xml (const char *annex)
      This variable is set up from the auto-generated
      init_registers_... routine for the current target.  */
 
-  if (strcmp (annex, "target.xml") == 0)
+  if (desc != nullptr)
     {
       const char *ret = tdesc_get_features_xml (desc);
 
@@ -1664,6 +1672,11 @@ handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
   if (name != NULL)
     buffer_xml_printf (buffer, " name=\"%s\"", name);
 
+  if (thread->tdesc != nullptr
+      && thread->tdesc != get_thread_process (thread)->tdesc)
+    buffer_xml_printf (buffer, " tdesc=\"%u\"",
+		       get_tdesc_rsp_id (thread->tdesc));
+
   if (handle_status)
     {
       char *handle_s = (char *) alloca (handle_len * 2 + 1);
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 7997d1a32e6e..58be5027795b 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -193,6 +193,10 @@ struct client_state
   /* If true, memory tagging features are supported.  */
   bool memory_tagging_feature = false;
 
+  /* The target descriptions that have been communicated to the client.  The
+     index of a target description in this vector is the ID used to reference it
+     in the remote protocol.  */
+  std::vector<const target_desc *> tdescs;
 };
 
 client_state &get_client_state ();

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (4 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01  9:52   ` Luis Machado
  2023-02-01 14:32   ` Andrew Burgess
  2023-01-30  4:45 ` [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely Thiago Jung Bauermann
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann

gdbserver added the concept of target description IDs to the remote
protocol and uses them in the threads list XML and in the 'T AA' stop
reply packet.  It also allows fetching a target description with a given
ID.  This patch is for the GDB-side support.  The target descriptions
obtained this way aren't yet used but will be in the next patch.

In the DTD for the threads list XML, add a "tdesc" attribute to the
<thread> node.  A tdesc_id field is added to the stop_reply and
thread_item structs.  An m_remote member is added to the
threads_listing_context struct, and to simplify its initialisation a
constructor is added as well.  This is to provide access to the remote
state in start_thread.

Finally, the remote_state object keeps a map of the target descriptions
that have been received from the target, keyed by their ID.  There are
also methods to get a target description given its ID, and to fetch target
descriptions for IDs that were mentioned by gdbserver but not yet
retrieved by GDB.  The latter gets called after parsing the response of
qXfer:threads:read and of the stop reply packet.
---
 gdb/features/threads.dtd |  1 +
 gdb/remote.c             | 85 +++++++++++++++++++++++++++++++++++++++-
 gdb/xml-tdesc.c          | 27 ++++++++++---
 gdb/xml-tdesc.h          |  6 +++
 4 files changed, 112 insertions(+), 7 deletions(-)

diff --git a/gdb/features/threads.dtd b/gdb/features/threads.dtd
index 036b2ce58837..3102d1352978 100644
--- a/gdb/features/threads.dtd
+++ b/gdb/features/threads.dtd
@@ -11,3 +11,4 @@
 
 <!ATTLIST thread id CDATA #REQUIRED>
 <!ATTLIST thread core CDATA #IMPLIED>
+<!ATTLIST thread tdesc CDATA #IMPLIED>
diff --git a/gdb/remote.c b/gdb/remote.c
index 218bca30d047..f1d1944414c3 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -80,6 +80,7 @@
 #include <unordered_map>
 #include "async-event.h"
 #include "gdbsupport/selftest.h"
+#include "xml-tdesc.h"
 
 /* The remote target.  */
 
@@ -238,6 +239,16 @@ class remote_state
   /* Get the remote arch state for GDBARCH.  */
   struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
 
+  /* Add new ID to the target description list.  The corresponding XML will be
+     requested soon.  */
+  void add_tdesc_id (ULONGEST id);
+
+  /* Get the target description corresponding to remote protocol ID.  */
+  const target_desc *get_tdesc (ULONGEST id) const;
+
+  /* Get the target descriptions we don't know about from the target.  */
+  void fetch_unknown_tdescs (remote_target *remote);
+
 public: /* data */
 
   /* A buffer to use for incoming packets, and its current size.  The
@@ -387,6 +398,10 @@ class remote_state
      support multi-process.  */
   std::unordered_map<struct gdbarch *, remote_arch_state>
     m_arch_states;
+
+  /* The target descriptions that have been received from the target.  The key
+     is the ID used to reference it in the remote protocol.  */
+  std::unordered_map<ULONGEST, const target_desc *> m_tdescs;
 };
 
 static const target_info remote_target_info = {
@@ -1009,6 +1024,9 @@ struct stop_reply : public notif_event
      fetch them is avoided).  */
   std::vector<cached_reg_t> regcache;
 
+  /* The target description ID communicated in the stop reply packet.  */
+  gdb::optional<ULONGEST> tdesc_id;
+
   enum target_stop_reason stop_reason;
 
   CORE_ADDR watch_data_address;
@@ -3689,6 +3707,9 @@ struct thread_item
 
   /* The thread handle associated with the thread.  */
   gdb::byte_vector thread_handle;
+
+  /* The ID of the thread's target description, if provided.  */
+  gdb::optional<ULONGEST> tdesc_id;
 };
 
 /* Context passed around to the various methods listing remote
@@ -3697,6 +3718,12 @@ struct thread_item
 
 struct threads_listing_context
 {
+  threads_listing_context (remote_target *remote)
+    : m_remote (remote)
+  {}
+
+  DISABLE_COPY_AND_ASSIGN (threads_listing_context);
+
   /* Return true if this object contains an entry for a thread with ptid
      PTID.  */
 
@@ -3733,6 +3760,9 @@ struct threads_listing_context
 
   /* The threads found on the remote target.  */
   std::vector<thread_item> items;
+
+  /* The remote target associated with this context.  */
+  remote_target *m_remote;
 };
 
 static int
@@ -3814,6 +3844,13 @@ start_thread (struct gdb_xml_parser *parser,
   attr = xml_find_attribute (attributes, "handle");
   if (attr != NULL)
     item.thread_handle = hex2bin ((const char *) attr->value.get ());
+
+  attr = xml_find_attribute (attributes, "tdesc");
+  if (attr != NULL)
+    {
+      item.tdesc_id = *(ULONGEST *) attr->value.get ();
+      data->m_remote->get_remote_state ()->add_tdesc_id (*item.tdesc_id);
+    }
 }
 
 static void
@@ -3833,6 +3870,7 @@ const struct gdb_xml_attribute thread_attributes[] = {
   { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
   { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL },
+  { "tdesc", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
@@ -3870,6 +3908,7 @@ remote_target::remote_get_threads_with_qxfer (threads_listing_context *context)
 	{
 	  gdb_xml_parse_quick (_("threads"), "threads.dtd",
 			       threads_elements, xml->data (), context);
+	  get_remote_state ()->fetch_unknown_tdescs (this);
 	}
 
       return 1;
@@ -3937,7 +3976,7 @@ has_single_non_exited_thread (inferior *inf)
 void
 remote_target::update_thread_list ()
 {
-  struct threads_listing_context context;
+  struct threads_listing_context context (this);
   int got_list = 0;
 
   /* We have a few different mechanisms to fetch the thread list.  Try
@@ -7223,7 +7262,11 @@ remote_notif_stop_parse (remote_target *remote,
 			 struct notif_client *self, const char *buf,
 			 struct notif_event *event)
 {
-  remote->remote_parse_stop_reply (buf, (struct stop_reply *) event);
+  struct stop_reply *stop_reply = (struct stop_reply *) event;
+
+  remote->remote_parse_stop_reply (buf, stop_reply);
+
+  stop_reply->rs->fetch_unknown_tdescs (remote);
 }
 
 static void
@@ -7516,6 +7559,36 @@ strprefix (const char *p, const char *pend, const char *prefix)
   return *prefix == '\0';
 }
 
+void
+remote_state::add_tdesc_id (ULONGEST id)
+{
+  /* Check whether the ID was already added.  */
+  if (m_tdescs.find (id) != m_tdescs.cend ())
+    return;
+
+  m_tdescs[id] = nullptr;
+}
+
+const target_desc *
+remote_state::get_tdesc (ULONGEST id) const
+{
+  auto found = m_tdescs.find (id);
+
+  /* Check if the given ID was already provided.  */
+  if (found == m_tdescs.cend ())
+    return nullptr;
+
+  return found->second;
+}
+
+void
+remote_state::fetch_unknown_tdescs (remote_target *remote)
+{
+  for (auto &pair : m_tdescs)
+    if (pair.second == nullptr)
+      m_tdescs[pair.first] = target_read_description_xml (remote, pair.first);
+}
+
 /* Parse the stop reply in BUF.  Either the function succeeds, and the
    result is stored in EVENT, or throws an error.  */
 
@@ -7674,6 +7747,14 @@ Packet: '%s'\n"),
 	      event->ws.set_thread_created ();
 	      p = strchrnul (p1 + 1, ';');
 	    }
+	  else if (strprefix (p, p1, "tdesc"))
+	    {
+	      ULONGEST tdesc_id;
+
+	      p = unpack_varlen_hex (++p1, &tdesc_id);
+	      event->rs->add_tdesc_id (tdesc_id);
+	      event->tdesc_id = tdesc_id;
+	    }
 	  else
 	    {
 	      ULONGEST pnum;
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index ba7154c5d56f..302863e12365 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -698,14 +698,13 @@ fetch_available_features_from_target (const char *name, target_ops *ops)
 }
 \f
 
-/* Read an XML target description using OPS.  Parse it, and return the
-   parsed description.  */
+/* Actual implementation of the target_read_description_xml variants.  */
 
-const struct target_desc *
-target_read_description_xml (struct target_ops *ops)
+static const struct target_desc *
+target_read_description_xml (struct target_ops *ops, const char *desc_name)
 {
   gdb::optional<gdb::char_vector> tdesc_str
-    = fetch_available_features_from_target ("target.xml", ops);
+    = fetch_available_features_from_target (desc_name, ops);
   if (!tdesc_str)
     return NULL;
 
@@ -717,6 +716,24 @@ target_read_description_xml (struct target_ops *ops)
   return tdesc_parse_xml (tdesc_str->data (), fetch_another);
 }
 
+/* See xml-tdesc.h.  */
+
+const struct target_desc *
+target_read_description_xml (struct target_ops *ops)
+{
+  return target_read_description_xml (ops, "target.xml");
+}
+
+/* See xml-tdesc.h.  */
+
+const struct target_desc *
+target_read_description_xml (struct target_ops *ops, ULONGEST id)
+{
+  std::string desc_name = string_printf ("target-id-%" PRIu64 ".xml", id);
+
+  return target_read_description_xml (ops, desc_name.c_str ());
+}
+
 /* Fetches an XML target description using OPS,  processing
    includes, but not parsing it.  Used to dump whole tdesc
    as a single XML file.  */
diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h
index 0fbfc7e043e9..c7cc97c5dfc0 100644
--- a/gdb/xml-tdesc.h
+++ b/gdb/xml-tdesc.h
@@ -38,6 +38,12 @@ const struct target_desc *file_read_description_xml (const char *filename);
 
 const struct target_desc *target_read_description_xml (struct target_ops *);
 
+/* Read an XML target description with the given ID using OPS.  Parse it, and
+   return the parsed description.  */
+
+const struct target_desc *target_read_description_xml (struct target_ops *ops,
+						       ULONGEST id);
+
 /* Fetches an XML target description using OPS, processing includes,
    but not parsing it.  Used to dump whole tdesc as a single XML file.
    Returns the description on success, and a disengaged optional

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (5 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01  9:58   ` Luis Machado
  2023-02-01 15:26   ` Andrew Burgess
  2023-01-30  4:45 ` [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors Thiago Jung Bauermann
  2023-02-06 19:11 ` [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Pedro Alves
  8 siblings, 2 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann

If the remote target provides target description IDs in their threads
list and stop reply packets, use them to update the thread's gdbarch.
This allows debugging programs remotely that change their SVE vector
length during runtime.

GDB already supports different vector lengths in native debugging by
calling target_ops::thread_architecture, and aarch64_linux_nat_target
provides an implementation of that method.

So to provide the same feature in remote debugging, implement the
thread_architecture method in remote_target, so that the same
mechanism can be used for both the native and remote cases.  This
method returns the gdbarch corresponding to the target description
provided by the last threads list or stop reply packet.

To allow changing the architecture based on the target description,
add a new gdbarch method to allow arch-specific code to make the
adjustment.
---
 gdb/aarch64-tdep.c        | 20 ++++++++++
 gdb/arch-utils.c          |  8 ++++
 gdb/arch-utils.h          |  4 ++
 gdb/gdbarch-components.py | 15 +++++++
 gdb/gdbarch-gen.h         | 10 +++++
 gdb/gdbarch.c             | 22 ++++++++++
 gdb/remote.c              | 84 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 163 insertions(+)

diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index b576d3b9d99f..1e6e7116ed8a 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -3502,6 +3502,25 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
 	  || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
 }
 
+/* Implement the "update_architecture" gdbarch method.  */
+
+static struct gdbarch *
+aarch64_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
+{
+  /* If this is a 32-bit architecture, then this is ARM, not AArch64.
+     There are no SVE registers here, so just return the inferior
+     architecture.  */
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    return gdbarch;
+
+  struct gdbarch_info info;
+
+  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
+  info.target_desc = tdesc;
+
+  return gdbarch_find_by_info (info);
+}
+
 /* Implement the stack_frame_destroyed_p gdbarch method.  */
 
 static int
@@ -3748,6 +3767,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_tdesc_pseudo_register_reggroup_p (gdbarch,
 					aarch64_pseudo_register_reggroup_p);
   set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
+  set_gdbarch_update_architecture (gdbarch, aarch64_update_architecture);
 
   /* ABI */
   set_gdbarch_short_bit (gdbarch, 16);
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index 67968126488e..e8ad0aed6eb4 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -1098,6 +1098,14 @@ default_get_return_buf_addr (struct type *val_type, frame_info_ptr cur_frame)
   return 0;
 }
 
+/* See arch-utils.h.  */
+
+struct gdbarch *
+default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
+{
+  return gdbarch;
+}
+
 /* Non-zero if we want to trace architecture code.  */
 
 #ifndef GDBARCH_DEBUG
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 56690f0fd435..aeee7f51ad49 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -314,4 +314,8 @@ extern enum return_value_convention default_gdbarch_return_value
       struct regcache *regcache, struct value **read_value,
       const gdb_byte *writebuf);
 
+/* Default implementation of gdbarch update_architecture method.  */
+extern struct gdbarch *
+default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);
+
 #endif /* ARCH_UTILS_H */
diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py
index 76ad2832d8a2..68b7521c9966 100644
--- a/gdb/gdbarch-components.py
+++ b/gdb/gdbarch-components.py
@@ -2744,3 +2744,18 @@ Read core file mappings
     predefault="default_read_core_file_mappings",
     invalid=False,
 )
+
+Method(
+    comment="""
+An architecture may change while the inferior is running.  For instance, the
+length of the vector registers in AArch64's Scalable Vector Extension is given
+by the contents of the VG pseudo-register.
+
+Return a gdbarch corresponding to the given target description.
+""",
+    type="struct gdbarch *",
+    name="update_architecture",
+    params=[("const target_desc *", "tdesc")],
+    predefault="default_update_architecture",
+    invalid=False,
+)
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 32b2d96fbe01..d6068c2bc24f 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -1672,3 +1672,13 @@ extern void set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, gdbarch_g
 typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
+
+/* An architecture may change while the inferior is running.  For instance, the
+   length of the vector registers in AArch64's Scalable Vector Extension is given
+   by the contents of the VG pseudo-register.
+
+   Return a gdbarch corresponding to the given target description. */
+
+typedef struct gdbarch * (gdbarch_update_architecture_ftype) (struct gdbarch *gdbarch, const target_desc *tdesc);
+extern struct gdbarch * gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);
+extern void set_gdbarch_update_architecture (struct gdbarch *gdbarch, gdbarch_update_architecture_ftype *update_architecture);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 46baca9c4793..07d3e060fe1f 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -256,6 +256,7 @@ struct gdbarch
   gdbarch_type_align_ftype *type_align = default_type_align;
   gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags;
   gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
+  gdbarch_update_architecture_ftype *update_architecture = default_update_architecture;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -517,6 +518,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of type_align, invalid_p == 0 */
   /* Skip verify of get_pc_address_flags, invalid_p == 0 */
   /* Skip verify of read_core_file_mappings, invalid_p == 0 */
+  /* Skip verify of update_architecture, invalid_p == 0 */
   if (!log.empty ())
     internal_error (_("verify_gdbarch: the following are invalid ...%s"),
 		    log.c_str ());
@@ -1355,6 +1357,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   gdb_printf (file,
 	      "gdbarch_dump: read_core_file_mappings = <%s>\n",
 	      host_address_to_string (gdbarch->read_core_file_mappings));
+  gdb_printf (file,
+	      "gdbarch_dump: update_architecture = <%s>\n",
+	      host_address_to_string (gdbarch->update_architecture));
   if (gdbarch->dump_tdep != NULL)
     gdbarch->dump_tdep (gdbarch, file);
 }
@@ -5317,3 +5322,20 @@ set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch,
 {
   gdbarch->read_core_file_mappings = read_core_file_mappings;
 }
+
+struct gdbarch *
+gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->update_architecture != NULL);
+  if (gdbarch_debug >= 2)
+    gdb_printf (gdb_stdlog, "gdbarch_update_architecture called\n");
+  return gdbarch->update_architecture (gdbarch, tdesc);
+}
+
+void
+set_gdbarch_update_architecture (struct gdbarch *gdbarch,
+				 gdbarch_update_architecture_ftype update_architecture)
+{
+  gdbarch->update_architecture = update_architecture;
+}
diff --git a/gdb/remote.c b/gdb/remote.c
index f1d1944414c3..a17d65220408 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -506,6 +506,8 @@ class remote_target : public process_stratum_target
   gdb::byte_vector thread_info_to_thread_handle (struct thread_info *tp)
 						 override;
 
+  struct gdbarch *thread_architecture (ptid_t ptid) override;
+
   void stop (ptid_t) override;
 
   void interrupt () override;
@@ -1168,6 +1170,10 @@ struct remote_thread_info : public private_thread_info
      to stop for a watchpoint.  */
   CORE_ADDR watch_data_address = 0;
 
+  /* The architecture corresponding to the target description returned
+     in the last stop reply or threads list.  */
+  struct gdbarch *arch = nullptr;
+
   /* Get the thread's resume state.  */
   enum resume_state get_resume_state () const
   {
@@ -1186,6 +1192,8 @@ struct remote_thread_info : public private_thread_info
     m_resume_state = resume_state::RESUMED_PENDING_VCONT;
     m_resumed_pending_vcont_info.step = step;
     m_resumed_pending_vcont_info.sig = sig;
+
+    arch = nullptr;
   }
 
   /* Get the information this thread's pending vCont-resumption.
@@ -1203,6 +1211,8 @@ struct remote_thread_info : public private_thread_info
   void set_resumed ()
   {
     m_resume_state = resume_state::RESUMED;
+
+    arch = nullptr;
   }
 
 private:
@@ -4046,6 +4056,29 @@ remote_target::update_thread_list ()
 	      info->extra = std::move (item.extra);
 	      info->name = std::move (item.name);
 	      info->thread_handle = std::move (item.thread_handle);
+
+	      /* If the threads list indicated a target description for this
+		 thread, add it to the thread information.  */
+	      if (item.tdesc_id)
+		{
+		  const target_desc *tdesc
+		      = get_remote_state ()->get_tdesc (*item.tdesc_id);
+
+		  gdb_assert (tdesc != nullptr);
+
+		  /* If there's no thread-specific gdbarch, use the one from the
+		     whole inferior.  */
+		  if (info->arch == nullptr)
+		    info->arch = tp->inf->gdbarch;
+
+		  gdbarch *new_arch = gdbarch_update_architecture (info->arch,
+								   tdesc);
+		  if (new_arch != info->arch)
+		    {
+		      registers_changed_thread (tp);
+		      info->arch = new_arch;
+		    }
+		}
 	    }
 	}
     }
@@ -8152,6 +8185,36 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
       && status->kind () != TARGET_WAITKIND_SIGNALLED
       && status->kind () != TARGET_WAITKIND_NO_RESUMED)
     {
+      thread_info *thr = find_thread_ptid (this, ptid);
+
+      /* If GDB already knows about this thread, we can give the
+	 architecture-specific code a chance to update the gdbarch based on the
+	 provided target description.  */
+      if (stop_reply->tdesc_id && thr != nullptr)
+	{
+	  const target_desc *tdesc
+	      = stop_reply->rs->get_tdesc (*stop_reply->tdesc_id);
+
+	  gdb_assert (tdesc != nullptr);
+
+	  /* If there's no gdbarch associated with the stop reply, use the one
+	     from the whole inferior.  */
+	  if (stop_reply->arch == nullptr)
+	    stop_reply->arch = thr->inf->gdbarch;
+
+	  stop_reply->arch = gdbarch_update_architecture (stop_reply->arch,
+							  tdesc);
+
+	  /* Save stop_reply->arch so that it can be returned by the
+	     thread_architecture method.  */
+	  remote_thread_info *remote_thr = get_remote_thread_info (thr);
+	  if (remote_thr->arch != stop_reply->arch)
+	    {
+	      registers_changed_thread (thr);
+	      remote_thr->arch = stop_reply->arch;
+	    }
+	}
+
       /* Expedited registers.  */
       if (!stop_reply->regcache.empty ())
 	{
@@ -14469,6 +14532,27 @@ remote_target::thread_info_to_thread_handle (struct thread_info *tp)
   return priv->thread_handle;
 }
 
+/* Implementation of the thread_architecture method for the remote target.  */
+
+struct gdbarch *
+remote_target::thread_architecture (ptid_t ptid)
+{
+  thread_info *thr = find_thread_ptid (this, ptid);
+  remote_thread_info *remote_thr;
+
+  if (thr == nullptr)
+    remote_thr = nullptr;
+  else
+    remote_thr = get_remote_thread_info (thr);
+
+  if (remote_thr == nullptr || remote_thr->arch == nullptr)
+    /* The default thread_architecture implementation is the one from
+       process_stratum_target.  */
+    return process_stratum_target::thread_architecture (ptid);
+
+  return remote_thr->arch;
+}
+
 bool
 remote_target::can_async_p ()
 {

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (6 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely Thiago Jung Bauermann
@ 2023-01-30  4:45 ` Thiago Jung Bauermann
  2023-02-01 10:10   ` Luis Machado
  2023-02-06 19:11 ` [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Pedro Alves
  8 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30  4:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Thiago Jung Bauermann

This testcase exercises two scenarios with a multi-threaded inferior, one
proposed by Luis and another one proposed by Simon.

In the first scenario, one of the inferior threads changes its vector
length and then hits a breakpoint.  In the second one, the main thread hits
a breakpoint and then GDB switches to another thread.
---
 gdb/testsuite/gdb.arch/aarch64-sve-threads.c  | 125 ++++++++++++++++++
 .../gdb.arch/aarch64-sve-threads.exp          |  70 ++++++++++
 2 files changed, 195 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.exp

diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.c b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c
new file mode 100644
index 000000000000..7fad77008da3
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c
@@ -0,0 +1,125 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Exercise AArch64's Scalable Vector Extension in a multi-threaded program.  */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+/* For one of the tests, the thread needs to sleep after setting the vector
+   length.  This variable is set by GDB.  */
+volatile bool should_sleep = false;
+
+/* Used to signal to the main thread that the additional thread's vector length
+   was changed.  */
+sem_t vl_changed;
+
+/* Start routine for the additional thread.  Sets a new vector length, sleeps if
+   requested then restores the original vector length.  */
+
+static void *
+thread_function (void *unused)
+{
+  unsigned int vl;
+  int rc;
+
+  rc = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (rc < 0)
+    {
+      perror ("FAILED to PR_SVE_GET_VL");
+      sem_post (&vl_changed);
+      return NULL;
+    }
+
+  vl = rc & PR_SVE_VL_LEN_MASK;
+
+  /* Decrease vector length by 16 bytes.  */
+  vl -= 16;
+
+  rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0, 0);
+  if (rc < 0)
+    {
+      perror ("FAILED to PR_SVE_SET_VL");
+      sem_post (&vl_changed);
+      return NULL;
+    }
+
+  /* Let the main thread continue.  */
+  rc = sem_post (&vl_changed);
+  if (rc != 0)
+    {
+      perror ("sem_post");
+      return NULL;
+    }
+
+  if (should_sleep)
+    sleep (10);
+
+  /* Restore original vector length.  */
+  vl += 16; /* break here 1 */
+
+  rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0, 0);
+  if (rc < 0)
+    {
+      perror ("FAILED to PR_SVE_SET_VL");
+      return NULL;
+    }
+
+  return NULL; /* break here 2 */
+}
+
+int
+main (int argc, char **argv)
+{
+  pthread_t thread;
+  int rc;
+
+  rc = sem_init (&vl_changed, 0, 0);
+  if (rc != 0)
+    {
+      perror ("sem_init");
+      return 1;
+    }
+
+  rc = pthread_create (&thread, NULL, thread_function, NULL);
+  if (rc != 0)
+    {
+      perror ("pthread_create");
+      return 1;
+    }
+
+  /* Wait until the additional thread changes it's vector length.  */
+  rc = sem_wait (&vl_changed);
+  if (rc != 0)
+    {
+      perror ("sem_wait");
+      return 1;
+    }
+
+  rc = pthread_join (thread, NULL); /* break here 3 */
+  if (rc != 0)
+    {
+      perror ("pthread_join");
+      return 1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
new file mode 100644
index 000000000000..48197650e1de
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
@@ -0,0 +1,70 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test a multi-threaded binary that uses SVE and changes the SVE vector length
+# in the additional thread.
+
+if {[skip_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	 {debug pthreads}] == -1} {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Stop after the additional thread has changed its vector length.
+gdb_breakpoint [gdb_get_line_number "break here 1"]
+gdb_continue_to_breakpoint "break here 1"
+
+# If GDB and gdbserver don't agree on the thread's vector length, this command
+# will fail.
+gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register"
+
+# Stop after the additional thread has restored its original vector length.
+gdb_breakpoint [gdb_get_line_number "break here 2"]
+gdb_continue_to_breakpoint "break here 2"
+
+# Test that going back to the original vector length doesn't confuse GDB or
+# gdbserver.
+gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register again"
+
+# Restart GDB to test a scenario where GDB switches to a thread that changed its
+# vector length but hasn't hit any breakpoints yet.
+clean_restart ${binfile}
+
+if ![runto_main] {
+    return -1
+}
+
+# Make the thread sleep after changing its vector length.
+gdb_test_no_output -nopass "set var should_sleep = 1" "make thread sleep"
+
+# Stop after the additional thread has been created.
+gdb_breakpoint [gdb_get_line_number "break here 3"]
+gdb_continue_to_breakpoint "break here 3"
+
+# The regexp accounts for two lines of output after the "Switching to thread" message.
+gdb_test_lines "thread 2" "switch to another thread" \
+    {\[Switching to thread 2 \(.*\)\]\r\n#0  [[:print:]]+}
+
+# Make sure everything is still fine.
+gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register in thread 2"

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
@ 2023-01-30 12:52   ` Eli Zaretskii
  2023-01-30 14:05     ` Thiago Jung Bauermann
  2023-02-01  9:39   ` Luis Machado
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 94+ messages in thread
From: Eli Zaretskii @ 2023-01-30 12:52 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches, simon.marchi

> Cc: Thiago Jung Bauermann <thiago.bauermann@linaro.org>,
>  Simon Marchi <simon.marchi@efficios.com>
> Date: Mon, 30 Jan 2023 04:45:15 +0000
> From: Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
> 
> Now that an inferior thread can have a different target description than
> its process, there needs to be a way to communicate this target
> description to GDB.  So add the concept of a target description ID to the
> remote protocol, which is used to reference them and allows them to be
> transferred only once over the wire.
> 
> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
> unsigned integer containing the ID.
> 
> It is also sent in the threads list XML in the response of a
> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
> the <thread> node.
> 
> To request the target description XML of a given ID, GDB sends the
> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
> is the target description ID.
> 
> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
>  gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
>  gdbserver/remote-utils.h  |  9 +++++++
>  gdbserver/server.cc       | 17 ++++++++++--
>  gdbserver/server.h        |  4 +++
>  5 files changed, 109 insertions(+), 5 deletions(-)

Thanks.

> +If target description IDs are being used (@pxref{Target Description ID}),
> +@value{GDBN} can retrieve a target description with a given ID by using
> +@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
   ^^^^^^^^^^^^^^^^^^^^^^^                           ^^^^^^^^
@file{target-id-@var{id}.xml}                        @var{id}

The arguments of @var should be in lower-case, as that looks better in
the printed and HTML versions of the manual.

The documentation part is OK with these problems fixed.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30 12:52   ` Eli Zaretskii
@ 2023-01-30 14:05     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-30 14:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, simon.marchi


Hello Eli,

Eli Zaretskii <eliz@gnu.org> writes:

>> Now that an inferior thread can have a different target description than
>> its process, there needs to be a way to communicate this target
>> description to GDB.  So add the concept of a target description ID to the
>> remote protocol, which is used to reference them and allows them to be
>> transferred only once over the wire.
>> 
>> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
>> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
>> unsigned integer containing the ID.
>> 
>> It is also sent in the threads list XML in the response of a
>> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
>> the <thread> node.
>> 
>> To request the target description XML of a given ID, GDB sends the
>> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
>> is the target description ID.
>> 
>> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
>> ---
>>  gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
>>  gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
>>  gdbserver/remote-utils.h  |  9 +++++++
>>  gdbserver/server.cc       | 17 ++++++++++--
>>  gdbserver/server.h        |  4 +++
>>  5 files changed, 109 insertions(+), 5 deletions(-)
>
> Thanks.

Thank you for the quick review!

>> +If target description IDs are being used (@pxref{Target Description ID}),
>> +@value{GDBN} can retrieve a target description with a given ID by using
>> +@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
>    ^^^^^^^^^^^^^^^^^^^^^^^                           ^^^^^^^^
> @file{target-id-@var{id}.xml}                        @var{id}
>
> The arguments of @var should be in lower-case, as that looks better in
> the printed and HTML versions of the manual.

Ah, nice to know that I can nest tags like that. Thank you for the
explanation as well.

> The documentation part is OK with these problems fixed.

Fixed locally.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number
  2023-01-30  4:45 ` [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number Thiago Jung Bauermann
@ 2023-01-31 17:05   ` Simon Marchi
  2023-01-31 19:49     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-01-31 17:05 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

On 1/29/23 23:45, Thiago Jung Bauermann wrote:
> It helped me during development, catching bugs closer to when they actually
> happened.
> 
> Also remove the equivalent gdb_assert in regcache_raw_read_unsigned, since
> it's checking the same condition a few frames above.
> 
> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdbserver/regcache.cc | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 3aeefcc79a37..7b896a19767d 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -199,6 +199,8 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
>  static const struct gdb::reg &
>  find_register_by_number (const struct target_desc *tdesc, int n)
>  {
> +  gdb_assert (n >= 0 && n < tdesc->reg_defs.size ());

Since you're moving this assertion, I would suggest breaking it up in
two.  I general, I suggest avoiding multiple checks in a single
gdb_assert.  It makes it a little less obvious from the crash report
which condition failed exactly.  So:

  gdb_assert (n >= 0);
  gdb_assert (n < tdesc->reg_defs.size ());

The patch is fine to push right away in any case, it's good
independently from the rest of the series:

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number
  2023-01-31 17:05   ` Simon Marchi
@ 2023-01-31 19:49     ` Thiago Jung Bauermann
  2023-02-01 15:43       ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-01-31 19:49 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches


Hello Simon,

Simon Marchi <simon.marchi@efficios.com> writes:

> On 1/29/23 23:45, Thiago Jung Bauermann wrote:
>> It helped me during development, catching bugs closer to when they actually
>> happened.
>> 
>> Also remove the equivalent gdb_assert in regcache_raw_read_unsigned, since
>> it's checking the same condition a few frames above.
>> 
>> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
>> ---
>>  gdbserver/regcache.cc | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>> 
>> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
>> index 3aeefcc79a37..7b896a19767d 100644
>> --- a/gdbserver/regcache.cc
>> +++ b/gdbserver/regcache.cc
>> @@ -199,6 +199,8 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
>>  static const struct gdb::reg &
>>  find_register_by_number (const struct target_desc *tdesc, int n)
>>  {
>> +  gdb_assert (n >= 0 && n < tdesc->reg_defs.size ());
>
> Since you're moving this assertion, I would suggest breaking it up in
> two.  I general, I suggest avoiding multiple checks in a single
> gdb_assert.  It makes it a little less obvious from the crash report
> which condition failed exactly.  So:
>
>   gdb_assert (n >= 0);
>   gdb_assert (n < tdesc->reg_defs.size ());

Good point. I made this change.

> The patch is fine to push right away in any case, it's good
> independently from the rest of the series:

Indeed. I will do that. Is it OK if I push patch 2 as well? You approved
it in v2, and the only changes in v3 are to implement your review
comments.

> Approved-By: Simon Marchi <simon.marchi@efficios.com>

Thanks for your review!

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features
  2023-01-30  4:45 ` [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features Thiago Jung Bauermann
@ 2023-02-01  8:59   ` Luis Machado
  2023-02-01 16:04     ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-01  8:59 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches; +Cc: Simon Marchi

On 1/30/23 04:45, Thiago Jung Bauermann wrote:
> It will be used in a subsequent commit.  There's no functional change.
> 
> Reviewed-by: Luis Machado <luis.machado@arm.com>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>   gdbserver/linux-aarch64-low.cc | 36 ++++++++++++++++++++++------------
>   1 file changed, 24 insertions(+), 12 deletions(-)
> 
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 2ed6e95562c5..92c621e5548c 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -675,6 +675,28 @@ aarch64_target::low_delete_process (arch_process_info *info)
>     xfree (info);
>   }
>   
> +/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
> +#define AARCH64_HWCAP_PACA (1 << 30)
> +
> +/* Obtain the architectural features available in the given THREAD.  */
> +
> +static struct aarch64_features
> +aarch64_get_arch_features (const thread_info *thread)
> +{
> +  struct aarch64_features features;
> +  int pid = thread->id.pid ();
> +  int tid = thread->id.lwp ();
> +
> +  features.vq = aarch64_sve_get_vq (tid);
> +  /* A-profile PAC is 64-bit only.  */
> +  features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
> +  /* A-profile MTE is 64-bit only.  */
> +  features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
> +  features.tls = aarch64_tls_register_count (tid);
> +
> +  return features;
> +}
> +
>   void
>   aarch64_target::low_new_thread (lwp_info *lwp)
>   {
> @@ -827,9 +849,6 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>       }
>   }
>   
> -/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
> -#define AARCH64_HWCAP_PACA (1 << 30)
> -
>   /* Implementation of linux target ops method "low_arch_setup".  */
>   
>   void
> @@ -845,15 +864,8 @@ aarch64_target::low_arch_setup ()
>   
>     if (is_elf64)
>       {
> -      struct aarch64_features features;
> -      int pid = current_thread->id.pid ();
> -
> -      features.vq = aarch64_sve_get_vq (tid);
> -      /* A-profile PAC is 64-bit only.  */
> -      features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
> -      /* A-profile MTE is 64-bit only.  */
> -      features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
> -      features.tls = aarch64_tls_register_count (tid);
> +      struct aarch64_features features
> +	  = aarch64_get_arch_features (current_thread);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   

Still LGTM.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-01-30  4:45 ` [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description Thiago Jung Bauermann
@ 2023-02-01  9:05   ` Luis Machado
  2023-02-01 11:06   ` Andrew Burgess
  1 sibling, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-01  9:05 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

On 1/30/23 04:45, Thiago Jung Bauermann wrote:
> This change prepares gdbserver to support remotely debugging programs in
> aarch64-linux where different threads have different SVE vector lengths.
> It allows gdbserver to support different inferior threads having different
> target descriptions.
> 
> To that end, a tdesc field is added to struct thread_info.  If it's
> nullptr (the default) it means that the thread uses the target description
> stored in struct process_info and thus gdbserver behaviour is unchanged.
> The get_thread_tdesc method is added to the linux_process_target class to
> allow aarch64-linux code to probe the inferior's vq register and provide a
> thread-specific target description reflecting the new vector length.
> 
> After this change, all targets except SVE-supporting aarch64-linux will
> still use per-process target descriptions.
> 
> Reviewed-by: Luis Machado <luis.machado@arm.com>
> ---
>   gdbserver/gdbthread.h          |  4 ++++
>   gdbserver/linux-aarch64-low.cc | 31 +++++++++++++++++++++++++++++++
>   gdbserver/linux-low.cc         | 17 +++++++++++++++++
>   gdbserver/linux-low.h          |  6 ++++++
>   gdbserver/regcache.cc          | 10 ++++++----
>   gdbserver/regcache.h           |  4 ++++
>   gdbserver/tdesc.cc             | 13 ++++++++++++-
>   gdbserver/tdesc.h              |  5 +++++
>   8 files changed, 85 insertions(+), 5 deletions(-)
> 
> diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
> index 493e1dbf6cb6..5b5ba6f8e521 100644
> --- a/gdbserver/gdbthread.h
> +++ b/gdbserver/gdbthread.h
> @@ -80,6 +80,10 @@ struct thread_info
>   
>     /* Branch trace target information for this thread.  */
>     struct btrace_target_info *btrace = nullptr;
> +
> +  /* Target description for this thread.  Only present if it's different
> +     from the one in process_info.  */
> +  const struct target_desc *tdesc = nullptr;
>   };
>   
>   extern std::list<thread_info *> all_threads;
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 92c621e5548c..69765ee90db3 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -99,6 +99,9 @@ protected:
>   
>     void low_arch_setup () override;
>   
> +  const struct target_desc *
> +    get_thread_tdesc (const thread_info *thread) override;
> +
>     bool low_cannot_fetch_register (int regno) override;
>   
>     bool low_cannot_store_register (int regno) override;
> @@ -184,6 +187,9 @@ struct arch_process_info
>        same for each thread, it is reasonable for the data to live here.
>        */
>     struct aarch64_debug_reg_state debug_reg_state;
> +
> +  /* Whether this process has the Scalable Vector Extension available.  */
> +  bool has_sve;
>   };
>   
>   /* Return true if the size of register 0 is 8 byte.  */
> @@ -869,6 +875,9 @@ aarch64_target::low_arch_setup ()
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> +      if (features.vq > 0)
> +	current_process ()->priv->arch_private->has_sve = true;
> +
>         /* Adjust the register sets we should use for this particular set of
>   	 features.  */
>         aarch64_adjust_register_sets (features);
> @@ -879,6 +888,28 @@ aarch64_target::low_arch_setup ()
>     aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
>   }
>   
> +/* Implementation of linux target ops method "get_thread_tdesc".  */
> +
> +const struct target_desc *
> +aarch64_target::get_thread_tdesc (const thread_info *thread)
> +{
> +  const struct process_info *process = get_thread_process (thread);
> +
> +  /* Only inferiors with SVE need a thread-specific target description.  */
> +  if (!process->priv->arch_private->has_sve)
> +    return nullptr;
> +
> +  const struct aarch64_features features = aarch64_get_arch_features (thread);
> +  const struct target_desc *tdesc = aarch64_linux_read_description (features);
> +
> +  /* If the target description we just found is the same as the process-wide
> +     one, there's no need to set a thread-specific one.  */
> +  if (tdesc == process->tdesc)
> +    return nullptr;
> +
> +  return tdesc;
> +}
> +
>   /* Implementation of linux target ops method "get_regs_info".  */
>   
>   const regs_info *
> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
> index 5cd22824e470..47916009ebaf 100644
> --- a/gdbserver/linux-low.cc
> +++ b/gdbserver/linux-low.cc
> @@ -483,6 +483,12 @@ linux_process_target::arch_setup_thread (thread_info *thread)
>     low_arch_setup ();
>   }
>   
> +const struct target_desc *
> +linux_process_target::get_thread_tdesc (const thread_info *thread)
> +{
> +  return nullptr;
> +}
> +
>   int
>   linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
>   					    int wstat)
> @@ -2348,6 +2354,17 @@ linux_process_target::filter_event (int lwpid, int wstat)
>   	      return;
>   	    }
>   	}
> +      else
> +	{
> +	  /* Give the arch code an opportunity to set the thread's target
> +	     description.  */
> +	  const struct target_desc *new_tdesc = get_thread_tdesc (thread);
> +	  if (new_tdesc != thread->tdesc)
> +	    {
> +	      free_register_cache_thread (thread);
> +	      thread->tdesc = new_tdesc;
> +	    }
> +	}
>       }
>   
>     if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags)
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index 221de85aa2ee..b52eb23cc444 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>     /* Architecture-specific setup for the current thread.  */
>     virtual void low_arch_setup () = 0;
>   
> +  /* Allows arch-specific code to set the thread's target description when the
> +     inferior stops.  Returns nullptr if no thread-specific target description
> +     is necessary.  */
> +  virtual const struct target_desc *
> +    get_thread_tdesc (const thread_info *thread);
> +
>     /* Return false if we can fetch/store the register, true if we cannot
>        fetch/store the register.  */
>     virtual bool low_cannot_fetch_register (int regno) = 0;
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 7b896a19767d..fb60e2c9c399 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -39,11 +39,11 @@ get_thread_regcache (struct thread_info *thread, int fetch)
>        have.  */
>     if (regcache == NULL)
>       {
> -      struct process_info *proc = get_thread_process (thread);
> +      const target_desc *tdesc = get_thread_target_desc (thread);
>   
> -      gdb_assert (proc->tdesc != NULL);
> +      gdb_assert (tdesc != nullptr);
>   
> -      regcache = new_register_cache (proc->tdesc);
> +      regcache = new_register_cache (tdesc);
>         set_thread_regcache_data (thread, regcache);
>       }
>   
> @@ -270,7 +270,9 @@ find_regno (const struct target_desc *tdesc, const char *name)
>     internal_error ("Unknown register %s requested", name);
>   }
>   
> -static void
> +/* See regcache.h.  */
> +
> +void
>   free_register_cache_thread (struct thread_info *thread)
>   {
>     struct regcache *regcache = thread_regcache_data (thread);
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 7248bcf5808a..4beea0139cd6 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -79,6 +79,10 @@ void free_register_cache (struct regcache *regcache);
>   
>   void regcache_invalidate_thread (struct thread_info *);
>   
> +/* Invalidate and release the register cache of the given THREAD.  */
> +
> +void free_register_cache_thread (struct thread_info *thread);
> +
>   /* Invalidate cached registers for all threads of the given process.  */
>   
>   void regcache_invalidate_pid (int pid);
> diff --git a/gdbserver/tdesc.cc b/gdbserver/tdesc.cc
> index 2c7257c458f4..e3339dde4d6c 100644
> --- a/gdbserver/tdesc.cc
> +++ b/gdbserver/tdesc.cc
> @@ -123,13 +123,24 @@ copy_target_description (struct target_desc *dest,
>     dest->xmltarget = src->xmltarget;
>   }
>   
> +/* See tdesc.h.  */
> +
> +const struct target_desc *
> +get_thread_target_desc (const struct thread_info *thread)
> +{
> +  if (thread->tdesc != nullptr)
> +    return thread->tdesc;
> +
> +  return get_thread_process (thread)->tdesc;
> +}
> +
>   const struct target_desc *
>   current_target_desc (void)
>   {
>     if (current_thread == NULL)
>       return &default_description;
>   
> -  return current_process ()->tdesc;
> +  return get_thread_target_desc (current_thread);
>   }
>   
>   /* An empty structure.  */
> diff --git a/gdbserver/tdesc.h b/gdbserver/tdesc.h
> index 7fe7d0d8eb30..71cc5b51c84e 100644
> --- a/gdbserver/tdesc.h
> +++ b/gdbserver/tdesc.h
> @@ -88,6 +88,11 @@ void copy_target_description (struct target_desc *dest,
>   void init_target_desc (struct target_desc *tdesc,
>   		       const char **expedite_regs);
>   
> +/* Return the target description corresponding to the given THREAD.  */
> +
> +const struct target_desc *
> +  get_thread_target_desc (const struct thread_info *thread);
> +
>   /* Return the current inferior's target description.  Never returns
>      NULL.  */
>   

I don't have any comments on this code. It looks good to me.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
@ 2023-02-01  9:07   ` Luis Machado
  2023-02-01 10:54   ` Andrew Burgess
  2023-02-06 19:54   ` Pedro Alves
  2 siblings, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-01  9:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches; +Cc: Simon Marchi

On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
> This patch doesn't change gdbserver behaviour, but after later changes are
> made it avoids a null pointer dereference when HWCAP needs to be obtained
> for a specific process while current_thread is nullptr.
> 
> Fixing linux_read_auxv, linux_get_hwcap and linux_get_hwcap2 to take a PID
> parameter seems more correct than setting current_thread in one particular
> code path.
> 
> Changes are propagated to allow passing the new parameter through the call
> chain.
> 
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>   gdbserver/linux-aarch64-low.cc |  7 ++++---
>   gdbserver/linux-arm-low.cc     |  2 +-
>   gdbserver/linux-low.cc         | 18 +++++++++---------
>   gdbserver/linux-low.h          |  9 ++++-----
>   gdbserver/linux-ppc-low.cc     |  6 +++---
>   gdbserver/linux-s390-low.cc    |  2 +-
>   gdbserver/netbsd-low.cc        |  4 +---
>   gdbserver/netbsd-low.h         |  2 +-
>   gdbserver/server.cc            |  3 ++-
>   gdbserver/target.cc            |  4 ++--
>   gdbserver/target.h             |  4 ++--
>   11 files changed, 30 insertions(+), 31 deletions(-)
> 
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 3c09e086afee..2ed6e95562c5 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -846,12 +846,13 @@ aarch64_target::low_arch_setup ()
>     if (is_elf64)
>       {
>         struct aarch64_features features;
> +      int pid = current_thread->id.pid ();
>   
>         features.vq = aarch64_sve_get_vq (tid);
>         /* A-profile PAC is 64-bit only.  */
> -      features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
> +      features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
> -      features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> +      features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
>         features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
> @@ -3322,7 +3323,7 @@ aarch64_target::supports_memory_tagging ()
>   #endif
>       }
>   
> -  return (linux_get_hwcap2 (8) & HWCAP2_MTE) != 0;
> +  return (linux_get_hwcap2 (current_thread->id.pid (), 8) & HWCAP2_MTE) != 0;
>   }
>   
>   bool
> diff --git a/gdbserver/linux-arm-low.cc b/gdbserver/linux-arm-low.cc
> index 98ba0e02524b..5975b44af0ae 100644
> --- a/gdbserver/linux-arm-low.cc
> +++ b/gdbserver/linux-arm-low.cc
> @@ -958,7 +958,7 @@ get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
>   static const struct target_desc *
>   arm_read_description (void)
>   {
> -  unsigned long arm_hwcap = linux_get_hwcap (4);
> +  unsigned long arm_hwcap = linux_get_hwcap (current_thread->id.pid (), 4);
>   
>     if (arm_hwcap & HWCAP_IWMMXT)
>       return arm_linux_read_description (ARM_FP_TYPE_IWMMXT);
> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
> index 7e1de3978933..5cd22824e470 100644
> --- a/gdbserver/linux-low.cc
> +++ b/gdbserver/linux-low.cc
> @@ -5483,12 +5483,11 @@ linux_process_target::supports_read_auxv ()
>      to debugger memory starting at MYADDR.  */
>   
>   int
> -linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> -				 unsigned int len)
> +linux_process_target::read_auxv (int pid, CORE_ADDR offset,
> +				 unsigned char *myaddr, unsigned int len)
>   {
>     char filename[PATH_MAX];
>     int fd, n;
> -  int pid = lwpid_of (current_thread);
>   
>     xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
>   
> @@ -6982,14 +6981,15 @@ linux_get_pc_64bit (struct regcache *regcache)
>   /* See linux-low.h.  */
>   
>   int
> -linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
> +linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp)
>   {
>     gdb_byte *data = (gdb_byte *) alloca (2 * wordsize);
>     int offset = 0;
>   
>     gdb_assert (wordsize == 4 || wordsize == 8);
>   
> -  while (the_target->read_auxv (offset, data, 2 * wordsize) == 2 * wordsize)
> +  while (the_target->read_auxv (pid, offset, data, 2 * wordsize)
> +	 == 2 * wordsize)
>       {
>         if (wordsize == 4)
>   	{
> @@ -7019,20 +7019,20 @@ linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
>   /* See linux-low.h.  */
>   
>   CORE_ADDR
> -linux_get_hwcap (int wordsize)
> +linux_get_hwcap (int pid, int wordsize)
>   {
>     CORE_ADDR hwcap = 0;
> -  linux_get_auxv (wordsize, AT_HWCAP, &hwcap);
> +  linux_get_auxv (pid, wordsize, AT_HWCAP, &hwcap);
>     return hwcap;
>   }
>   
>   /* See linux-low.h.  */
>   
>   CORE_ADDR
> -linux_get_hwcap2 (int wordsize)
> +linux_get_hwcap2 (int pid, int wordsize)
>   {
>     CORE_ADDR hwcap2 = 0;
> -  linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2);
> +  linux_get_auxv (pid, wordsize, AT_HWCAP2, &hwcap2);
>     return hwcap2;
>   }
>   
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index aebfe05707e5..221de85aa2ee 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -178,7 +178,7 @@ class linux_process_target : public process_stratum_target
>   
>     bool supports_read_auxv () override;
>   
> -  int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> +  int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
>   		 unsigned int len) override;
>   
>     int insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>      *VALP and return 1.  If not found or if there is an error, return
>      0.  */
>   
> -int linux_get_auxv (int wordsize, CORE_ADDR match,
> -		    CORE_ADDR *valp);
> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>   
>   /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>      WORDSIZE.  If no entry was found, return zero.  */
>   
> -CORE_ADDR linux_get_hwcap (int wordsize);
> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>   
>   /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>      WORDSIZE.  If no entry was found, return zero.  */
>   
> -CORE_ADDR linux_get_hwcap2 (int wordsize);
> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
>   
>   #endif /* GDBSERVER_LINUX_LOW_H */
> diff --git a/gdbserver/linux-ppc-low.cc b/gdbserver/linux-ppc-low.cc
> index fdf74727e392..f8dd770b8eb3 100644
> --- a/gdbserver/linux-ppc-low.cc
> +++ b/gdbserver/linux-ppc-low.cc
> @@ -894,8 +894,8 @@ ppc_target::low_arch_setup ()
>   
>     /* The value of current_process ()->tdesc needs to be set for this
>        call.  */
> -  ppc_hwcap = linux_get_hwcap (features.wordsize);
> -  ppc_hwcap2 = linux_get_hwcap2 (features.wordsize);
> +  ppc_hwcap = linux_get_hwcap (current_thread->id.pid (), features.wordsize);
> +  ppc_hwcap2 = linux_get_hwcap2 (current_thread->id.pid (), features.wordsize);
>   
>     features.isa205 = ppc_linux_has_isa205 (ppc_hwcap);
>   
> @@ -1097,7 +1097,7 @@ is_elfv2_inferior (void)
>     const struct target_desc *tdesc = current_process ()->tdesc;
>     int wordsize = register_size (tdesc, 0);
>   
> -  if (!linux_get_auxv (wordsize, AT_PHDR, &phdr))
> +  if (!linux_get_auxv (current_thread->id.pid (), wordsize, AT_PHDR, &phdr))
>       return def_res;
>   
>     /* Assume ELF header is at the beginning of the page where program headers
> diff --git a/gdbserver/linux-s390-low.cc b/gdbserver/linux-s390-low.cc
> index b3ccdff3e57f..48f64ef7bb3b 100644
> --- a/gdbserver/linux-s390-low.cc
> +++ b/gdbserver/linux-s390-low.cc
> @@ -592,7 +592,7 @@ s390_target::low_arch_setup ()
>     /* Determine word size and HWCAP.  */
>     int pid = pid_of (current_thread);
>     int wordsize = s390_get_wordsize (pid);
> -  unsigned long hwcap = linux_get_hwcap (wordsize);
> +  unsigned long hwcap = linux_get_hwcap (pid, wordsize);
>   
>     /* Check whether the kernel supports extra register sets.  */
>     int have_regset_last_break
> diff --git a/gdbserver/netbsd-low.cc b/gdbserver/netbsd-low.cc
> index 15afa36d1152..4defd79eee47 100644
> --- a/gdbserver/netbsd-low.cc
> +++ b/gdbserver/netbsd-low.cc
> @@ -581,11 +581,9 @@ netbsd_read_auxv(pid_t pid, void *offs, void *addr, size_t len)
>      to debugger memory starting at MYADDR.  */
>   
>   int
> -netbsd_process_target::read_auxv (CORE_ADDR offset,
> +netbsd_process_target::read_auxv (int pid, CORE_ADDR offset,
>   				  unsigned char *myaddr, unsigned int len)
>   {
> -  pid_t pid = pid_of (current_thread);
> -
>     return netbsd_read_auxv (pid, (void *) (intptr_t) offset, myaddr, len);
>   }
>   
> diff --git a/gdbserver/netbsd-low.h b/gdbserver/netbsd-low.h
> index daefc302785e..050b43fc54f4 100644
> --- a/gdbserver/netbsd-low.h
> +++ b/gdbserver/netbsd-low.h
> @@ -77,7 +77,7 @@ class netbsd_process_target : public process_stratum_target
>   
>     bool supports_read_auxv () override;
>   
> -  int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> +  int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
>   		 unsigned int len) override;
>   
>     bool supports_hardware_single_step () override;
> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index d802e8b4a341..21fb51a45d16 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -1443,7 +1443,8 @@ handle_qxfer_auxv (const char *annex,
>     if (annex[0] != '\0' || current_thread == NULL)
>       return -1;
>   
> -  return the_target->read_auxv (offset, readbuf, len);
> +  return the_target->read_auxv (current_thread->id.pid (), offset, readbuf,
> +				len);
>   }
>   
>   /* Handle qXfer:exec-file:read.  */
> diff --git a/gdbserver/target.cc b/gdbserver/target.cc
> index 24b8e2160138..b4f8e9f1efb6 100644
> --- a/gdbserver/target.cc
> +++ b/gdbserver/target.cc
> @@ -344,8 +344,8 @@ process_stratum_target::supports_read_auxv ()
>   }
>   
>   int
> -process_stratum_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> -				   unsigned int len)
> +process_stratum_target::read_auxv (int pid, CORE_ADDR offset,
> +				   unsigned char *myaddr, unsigned int len)
>   {
>     gdb_assert_not_reached ("target op read_auxv not supported");
>   }
> diff --git a/gdbserver/target.h b/gdbserver/target.h
> index eea651c30b4b..1b0caa98c56a 100644
> --- a/gdbserver/target.h
> +++ b/gdbserver/target.h
> @@ -172,10 +172,10 @@ class process_stratum_target
>     /* Return true if the read_auxv target op is supported.  */
>     virtual bool supports_read_auxv ();
>   
> -  /* Read auxiliary vector data from the inferior process.
> +  /* Read auxiliary vector data from the process with pid PID.
>   
>        Read LEN bytes at OFFSET into a buffer at MYADDR.  */
> -  virtual int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> +  virtual int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
>   			 unsigned int len);
>   
>     /* Returns true if GDB Z breakpoint type TYPE is supported, false

I don't have comments on this patch. Look sane to me.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
  2023-01-30 12:52   ` Eli Zaretskii
@ 2023-02-01  9:39   ` Luis Machado
  2023-02-01 12:07   ` Andrew Burgess
  2023-02-01 14:51   ` Andrew Burgess
  3 siblings, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-01  9:39 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches; +Cc: Simon Marchi

This looks good. Thanks. Just a nit below.

On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
> Now that an inferior thread can have a different target description than
> its process, there needs to be a way to communicate this target
> description to GDB.  So add the concept of a target description ID to the
> remote protocol, which is used to reference them and allows them to be
> transferred only once over the wire.
> 
> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
> unsigned integer containing the ID.
> 
> It is also sent in the threads list XML in the response of a
> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
> the <thread> node.
> 
> To request the target description XML of a given ID, GDB sends the
> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
> is the target description ID.
> 
> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>   gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
>   gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
>   gdbserver/remote-utils.h  |  9 +++++++
>   gdbserver/server.cc       | 17 ++++++++++--
>   gdbserver/server.h        |  4 +++
>   5 files changed, 109 insertions(+), 5 deletions(-)
> 
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 9c0018ea5c14..fbf7e59853b5 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -42030,6 +42030,10 @@ the stopped thread, as specified in @ref{thread-id syntax}.
>   If @var{n} is @samp{core}, then @var{r} is the hexadecimal number of
>   the core on which the stop event was detected.
>   
> +@item
> +If @var{n} is @samp{tdesc}, then @var{r} is the hexadecimal number of
> +the target description ID (@pxref{Target Description ID}).
> +

Above we mention that it is hexadecimal, but ...

>   @item
>   If @var{n} is a recognized @dfn{stop reason}, it describes a more
>   specific event that stopped the target.  The currently defined stop
> @@ -46546,7 +46550,7 @@ the following structure:
>   @smallexample
>   <?xml version="1.0"?>
>   <threads>
> -    <thread id="id" core="0" name="name">
> +    <thread id="id" core="0" name="name" tdesc="0">
>       ... description ...
>       </thread>
>   </threads>
> @@ -46556,8 +46560,10 @@ Each @samp{thread} element must have the @samp{id} attribute that
>   identifies the thread (@pxref{thread-id syntax}).  The
>   @samp{core} attribute, if present, specifies which processor core
>   the thread was last executing on.  The @samp{name} attribute, if
> -present, specifies the human-readable name of the thread.  The content
> -of the of @samp{thread} element is interpreted as human-readable
> +present, specifies the human-readable name of the thread.  The
> +@samp{tdesc} attribute, if present, specifies the target description
> +ID of the thread (@pxref{Target Description ID}).  The content of
> +the @samp{thread} element is interpreted as human-readable
>   auxiliary information.  The @samp{handle} attribute, if present,
>   is a hex encoded representation of the thread handle.

... what about the id being passed via the qXfer:threads:read? Should it be hex or decimal?

Might be nice to clarify so implementors have a clear understanding.

>   
> @@ -46767,6 +46773,8 @@ descriptions are accurate, and that @value{GDBN} understands them.
>   target descriptions.  @xref{Expat}.
>   
>   @menu
> +* Target Description ID::           Referencing different descriptions in the
> +                                    remote protocol.
>   * Retrieving Descriptions::         How descriptions are fetched from a target.
>   * Target Description Format::       The contents of a target description.
>   * Predefined Target Types::         Standard types available for target
> @@ -46775,6 +46783,14 @@ target descriptions.  @xref{Expat}.
>   * Standard Target Features::        Features @value{GDBN} knows about.
>   @end menu
>   
> +@node Target Description ID
> +@section Target Description ID
> +
> +In cases where a remote target supports threads having different
> +target descriptions than their parent process, the remote protocol
> +assigns a non-negative integer to each target description to reference
> +it in the communication between the host and the target.
> +
>   @node Retrieving Descriptions
>   @section Retrieving Descriptions
>   
> @@ -46787,6 +46803,11 @@ qXfer}).  The @var{annex} in the @samp{qXfer} packet will be
>   XML document, of the form described in @ref{Target Description
>   Format}.
>   
> +If target description IDs are being used (@pxref{Target Description ID}),
> +@value{GDBN} can retrieve a target description with a given ID by using
> +@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
> +non-negative integer identifier of the desired target description.
> +

Same case in here. Should id be a regular integer or its hex representation?

 From reading the code, it seems the two cases above should really be integers, so the text
is fine. But we want to make sure whoever is implementing the changes gets it right.

>   Alternatively, you can specify a file to read for the target description.
>   If a file is set, the target will not be queried.  The commands to
>   specify a file are:
> diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
> index 80310bc2c709..baff899307cc 100644
> --- a/gdbserver/remote-utils.cc
> +++ b/gdbserver/remote-utils.cc
> @@ -1049,6 +1049,53 @@ outreg (struct regcache *regcache, int regno, char *buf)
>     return buf;
>   }
>   
> +/* See remote-utils.h.  */
> +
> +unsigned int
> +get_tdesc_rsp_id (const target_desc *tdesc)
> +{
> +  client_state &cs = get_client_state ();
> +  unsigned int i;
> +
> +  for (i = 0; i < cs.tdescs.size (); i++)
> +    if (cs.tdescs[i] == tdesc)
> +      return i;
> +
> +  cs.tdescs.push_back (tdesc);
> +
> +  return i;
> +}
> +
> +/* See remote-utils.h.  */
> +
> +const target_desc *
> +get_tdesc_from_rsp_id (unsigned int id)
> +{
> +  client_state &cs = get_client_state ();
> +
> +  if (id >= cs.tdescs.size ())
> +    return nullptr;
> +
> +  return cs.tdescs[id];
> +}
> +
> +/* Return the ID as used in the remote protocol for the target descriptor of the
> +   given PTID.  */
> +
> +static unsigned int
> +get_tdesc_rsp_id (ptid_t ptid)
> +{
> +  const thread_info *thread = find_thread_ptid (ptid);
> +  const target_desc *tdesc;
> +
> +  if (thread == nullptr)
> +    tdesc = find_process_pid (ptid.pid ())->tdesc;
> +  else
> +    tdesc = get_thread_target_desc (thread);
> +
> +  return get_tdesc_rsp_id (tdesc);
> +}
> +
>   void
>   prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>   {
> @@ -1241,6 +1288,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>   	    buf += strlen (buf);
>   	    current_process ()->dlls_changed = false;
>   	  }
> +
> +	if (current_thread->tdesc != nullptr
> +	    && current_thread->tdesc != current_process ()->tdesc)
> +	  {
> +	    sprintf (buf, "tdesc:");
> +	    buf += strlen (buf);
> +	    sprintf (buf, "%x", get_tdesc_rsp_id (ptid));
> +	    strcat (buf, ";");
> +	    buf += strlen (buf);
> +	  }
>         }
>         break;
>       case TARGET_WAITKIND_EXITED:
> diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h
> index cb2d6c346c99..61ef80b4dad7 100644
> --- a/gdbserver/remote-utils.h
> +++ b/gdbserver/remote-utils.h
> @@ -75,4 +75,13 @@ int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc);
>   
>   void monitor_output (const char *msg);
>   
> +/* Return the ID as used in the remote protocol for the given target
> +   descriptor.  */
> +
> +unsigned int get_tdesc_rsp_id (const target_desc *tdesc);
> +
> +/* Return the target description corresponding to the remote protocol ID.  */
> +
> +const target_desc *get_tdesc_from_rsp_id (unsigned int id);
> +
>   #endif /* GDBSERVER_REMOTE_UTILS_H */
> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index 21fb51a45d16..2d1062f98468 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -976,7 +976,15 @@ handle_general_set (char *own_buf)
>   static const char *
>   get_features_xml (const char *annex)
>   {
> -  const struct target_desc *desc = current_target_desc ();
> +  const struct target_desc *desc;
> +  unsigned int id;
> +
> +  if (strcmp (annex, "target.xml") == 0)
> +    desc = current_target_desc ();
> +  else if (sscanf (annex, "target-id-%u.xml", &id) == 1)
> +    desc = get_tdesc_from_rsp_id (id);
> +  else
> +    desc = nullptr;
>   
>     /* `desc->xmltarget' defines what to return when looking for the
>        "target.xml" file.  Its contents can either be verbatim XML code
> @@ -986,7 +994,7 @@ get_features_xml (const char *annex)
>        This variable is set up from the auto-generated
>        init_registers_... routine for the current target.  */
>   
> -  if (strcmp (annex, "target.xml") == 0)
> +  if (desc != nullptr)
>       {
>         const char *ret = tdesc_get_features_xml (desc);
>   
> @@ -1664,6 +1672,11 @@ handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
>     if (name != NULL)
>       buffer_xml_printf (buffer, " name=\"%s\"", name);
>   
> +  if (thread->tdesc != nullptr
> +      && thread->tdesc != get_thread_process (thread)->tdesc)
> +    buffer_xml_printf (buffer, " tdesc=\"%u\"",
> +		       get_tdesc_rsp_id (thread->tdesc));
> +
>     if (handle_status)
>       {
>         char *handle_s = (char *) alloca (handle_len * 2 + 1);
> diff --git a/gdbserver/server.h b/gdbserver/server.h
> index 7997d1a32e6e..58be5027795b 100644
> --- a/gdbserver/server.h
> +++ b/gdbserver/server.h
> @@ -193,6 +193,10 @@ struct client_state
>     /* If true, memory tagging features are supported.  */
>     bool memory_tagging_feature = false;
>   
> +  /* The target descriptions that have been communicated to the client.  The
> +     index of a target description in this vector is the ID used to reference it
> +     in the remote protocol.  */
> +  std::vector<const target_desc *> tdescs;
>   };
>   
>   client_state &get_client_state ();

Otherwise LGTM.

Reviewed-by: Luis Machado <luis.machado@arm.com>

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-01-30  4:45 ` [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML Thiago Jung Bauermann
@ 2023-02-01  9:52   ` Luis Machado
  2023-02-05  0:06     ` Thiago Jung Bauermann
  2023-02-01 14:32   ` Andrew Burgess
  1 sibling, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-01  9:52 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
> gdbserver added the concept of target description IDs to the remote
> protocol and uses them in the threads list XML and in the 'T AA' stop
> reply packet.  It also allows fetching a target description with a given
> ID.  This patch is for the GDB-side support.  The target descriptions
> obtained this way aren't yet used but will be in the next patch.
> 
> In the DTD for the threads list XML, add a "tdesc" attribute to the
> <thread> node.  A tdesc_id field is added to the stop_reply and
> thread_item structs.  An m_remote member is added to the
> threads_listing_context struct, and to simplify its initialisation a
> constructor is added as well.  This is to provide access to the remote
> state in start_thread.
> 
> Finally, the remote_state object keeps a map of the target descriptions
> that have been received from the target, keyed by their ID.  There are
> also methods to get a target description given its ID, and to fetch target
> descriptions for IDs that were mentioned by gdbserver but not yet
> retrieved by GDB.  The latter gets called after parsing the response of
> qXfer:threads:read and of the stop reply packet.
> ---
>   gdb/features/threads.dtd |  1 +
>   gdb/remote.c             | 85 +++++++++++++++++++++++++++++++++++++++-
>   gdb/xml-tdesc.c          | 27 ++++++++++---
>   gdb/xml-tdesc.h          |  6 +++
>   4 files changed, 112 insertions(+), 7 deletions(-)
> 
> diff --git a/gdb/features/threads.dtd b/gdb/features/threads.dtd
> index 036b2ce58837..3102d1352978 100644
> --- a/gdb/features/threads.dtd
> +++ b/gdb/features/threads.dtd
> @@ -11,3 +11,4 @@
>   
>   <!ATTLIST thread id CDATA #REQUIRED>
>   <!ATTLIST thread core CDATA #IMPLIED>
> +<!ATTLIST thread tdesc CDATA #IMPLIED>
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 218bca30d047..f1d1944414c3 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -80,6 +80,7 @@
>   #include <unordered_map>
>   #include "async-event.h"
>   #include "gdbsupport/selftest.h"
> +#include "xml-tdesc.h"
>   
>   /* The remote target.  */
>   
> @@ -238,6 +239,16 @@ class remote_state
>     /* Get the remote arch state for GDBARCH.  */
>     struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
>   
> +  /* Add new ID to the target description list.  The corresponding XML will be
> +     requested soon.  */

Will it be requested soon or can gdb just ignore it if the user doesn't switch to that thread?

If gdb can ignore it, then it might be nice to mention it here that gdb can chose to request it
at any point in time, but may opt not to do it at all.

> +  void add_tdesc_id (ULONGEST id);
> +
> +  /* Get the target description corresponding to remote protocol ID.  */

s/remote protocol/remote target description?

> +  const target_desc *get_tdesc (ULONGEST id) const;
> +
> +  /* Get the target descriptions we don't know about from the target.  */
> +  void fetch_unknown_tdescs (remote_target *remote);
> +
>   public: /* data */
>   
>     /* A buffer to use for incoming packets, and its current size.  The
> @@ -387,6 +398,10 @@ class remote_state
>        support multi-process.  */
>     std::unordered_map<struct gdbarch *, remote_arch_state>
>       m_arch_states;
> +
> +  /* The target descriptions that have been received from the target.  The key
> +     is the ID used to reference it in the remote protocol.  */
> +  std::unordered_map<ULONGEST, const target_desc *> m_tdescs;
>   };
>   
>   static const target_info remote_target_info = {
> @@ -1009,6 +1024,9 @@ struct stop_reply : public notif_event
>        fetch them is avoided).  */
>     std::vector<cached_reg_t> regcache;
>   
> +  /* The target description ID communicated in the stop reply packet.  */
> +  gdb::optional<ULONGEST> tdesc_id;
> +
>     enum target_stop_reason stop_reason;
>   
>     CORE_ADDR watch_data_address;
> @@ -3689,6 +3707,9 @@ struct thread_item
>   
>     /* The thread handle associated with the thread.  */
>     gdb::byte_vector thread_handle;
> +
> +  /* The ID of the thread's target description, if provided.  */
> +  gdb::optional<ULONGEST> tdesc_id;
>   };
>   
>   /* Context passed around to the various methods listing remote
> @@ -3697,6 +3718,12 @@ struct thread_item
>   
>   struct threads_listing_context
>   {
> +  threads_listing_context (remote_target *remote)
> +    : m_remote (remote)
> +  {}
> +
> +  DISABLE_COPY_AND_ASSIGN (threads_listing_context);
> +
>     /* Return true if this object contains an entry for a thread with ptid
>        PTID.  */
>   
> @@ -3733,6 +3760,9 @@ struct threads_listing_context
>   
>     /* The threads found on the remote target.  */
>     std::vector<thread_item> items;
> +
> +  /* The remote target associated with this context.  */
> +  remote_target *m_remote;
>   };
>   
>   static int
> @@ -3814,6 +3844,13 @@ start_thread (struct gdb_xml_parser *parser,
>     attr = xml_find_attribute (attributes, "handle");
>     if (attr != NULL)
>       item.thread_handle = hex2bin ((const char *) attr->value.get ());
> +
> +  attr = xml_find_attribute (attributes, "tdesc");
> +  if (attr != NULL)

s/NULL/nullptr

> +    {
> +      item.tdesc_id = *(ULONGEST *) attr->value.get ();
> +      data->m_remote->get_remote_state ()->add_tdesc_id (*item.tdesc_id);
> +    }
>   }
>   
>   static void
> @@ -3833,6 +3870,7 @@ const struct gdb_xml_attribute thread_attributes[] = {
>     { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
>     { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
>     { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL },
> +  { "tdesc", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
>     { NULL, GDB_XML_AF_NONE, NULL, NULL }
>   };
>   
> @@ -3870,6 +3908,7 @@ remote_target::remote_get_threads_with_qxfer (threads_listing_context *context)
>   	{
>   	  gdb_xml_parse_quick (_("threads"), "threads.dtd",
>   			       threads_elements, xml->data (), context);
> +	  get_remote_state ()->fetch_unknown_tdescs (this);
>   	}
>   
>         return 1;
> @@ -3937,7 +3976,7 @@ has_single_non_exited_thread (inferior *inf)
>   void
>   remote_target::update_thread_list ()
>   {
> -  struct threads_listing_context context;
> +  struct threads_listing_context context (this);
>     int got_list = 0;
>   
>     /* We have a few different mechanisms to fetch the thread list.  Try
> @@ -7223,7 +7262,11 @@ remote_notif_stop_parse (remote_target *remote,
>   			 struct notif_client *self, const char *buf,
>   			 struct notif_event *event)
>   {
> -  remote->remote_parse_stop_reply (buf, (struct stop_reply *) event);
> +  struct stop_reply *stop_reply = (struct stop_reply *) event;
> +
> +  remote->remote_parse_stop_reply (buf, stop_reply);
> +
> +  stop_reply->rs->fetch_unknown_tdescs (remote);
>   }
>   
>   static void
> @@ -7516,6 +7559,36 @@ strprefix (const char *p, const char *pend, const char *prefix)
>     return *prefix == '\0';
>   }
>   
> +void
> +remote_state::add_tdesc_id (ULONGEST id)
> +{
> +  /* Check whether the ID was already added.  */
> +  if (m_tdescs.find (id) != m_tdescs.cend ())
> +    return;
> +
> +  m_tdescs[id] = nullptr;
> +}
> +
> +const target_desc *
> +remote_state::get_tdesc (ULONGEST id) const
> +{
> +  auto found = m_tdescs.find (id);
> +
> +  /* Check if the given ID was already provided.  */
> +  if (found == m_tdescs.cend ())
> +    return nullptr;
> +
> +  return found->second;
> +}
> +
> +void
> +remote_state::fetch_unknown_tdescs (remote_target *remote)
> +{
> +  for (auto &pair : m_tdescs)
> +    if (pair.second == nullptr)
> +      m_tdescs[pair.first] = target_read_description_xml (remote, pair.first);
> +}
> +
>   /* Parse the stop reply in BUF.  Either the function succeeds, and the
>      result is stored in EVENT, or throws an error.  */
>   
> @@ -7674,6 +7747,14 @@ Packet: '%s'\n"),
>   	      event->ws.set_thread_created ();
>   	      p = strchrnul (p1 + 1, ';');
>   	    }
> +	  else if (strprefix (p, p1, "tdesc"))
> +	    {
> +	      ULONGEST tdesc_id;
> +
> +	      p = unpack_varlen_hex (++p1, &tdesc_id);
> +	      event->rs->add_tdesc_id (tdesc_id);
> +	      event->tdesc_id = tdesc_id;
> +	    }
>   	  else
>   	    {
>   	      ULONGEST pnum;
> diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
> index ba7154c5d56f..302863e12365 100644
> --- a/gdb/xml-tdesc.c
> +++ b/gdb/xml-tdesc.c
> @@ -698,14 +698,13 @@ fetch_available_features_from_target (const char *name, target_ops *ops)
>   }
>   \f
>   
> -/* Read an XML target description using OPS.  Parse it, and return the
> -   parsed description.  */
> +/* Actual implementation of the target_read_description_xml variants.  */
>   
> -const struct target_desc *
> -target_read_description_xml (struct target_ops *ops)
> +static const struct target_desc *
> +target_read_description_xml (struct target_ops *ops, const char *desc_name)
>   {
>     gdb::optional<gdb::char_vector> tdesc_str
> -    = fetch_available_features_from_target ("target.xml", ops);
> +    = fetch_available_features_from_target (desc_name, ops);
>     if (!tdesc_str)
>       return NULL;
>   
> @@ -717,6 +716,24 @@ target_read_description_xml (struct target_ops *ops)
>     return tdesc_parse_xml (tdesc_str->data (), fetch_another);
>   }
>   
> +/* See xml-tdesc.h.  */
> +
> +const struct target_desc *
> +target_read_description_xml (struct target_ops *ops)
> +{
> +  return target_read_description_xml (ops, "target.xml");
> +}
> +
> +/* See xml-tdesc.h.  */
> +
> +const struct target_desc *
> +target_read_description_xml (struct target_ops *ops, ULONGEST id)
> +{
> +  std::string desc_name = string_printf ("target-id-%" PRIu64 ".xml", id);
> +
> +  return target_read_description_xml (ops, desc_name.c_str ());
> +}
> +
>   /* Fetches an XML target description using OPS,  processing
>      includes, but not parsing it.  Used to dump whole tdesc
>      as a single XML file.  */
> diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h
> index 0fbfc7e043e9..c7cc97c5dfc0 100644
> --- a/gdb/xml-tdesc.h
> +++ b/gdb/xml-tdesc.h
> @@ -38,6 +38,12 @@ const struct target_desc *file_read_description_xml (const char *filename);
>   
>   const struct target_desc *target_read_description_xml (struct target_ops *);
>   
> +/* Read an XML target description with the given ID using OPS.  Parse it, and
> +   return the parsed description.  */
> +
> +const struct target_desc *target_read_description_xml (struct target_ops *ops,
> +						       ULONGEST id);
> +
>   /* Fetches an XML target description using OPS, processing includes,
>      but not parsing it.  Used to dump whole tdesc as a single XML file.
>      Returns the description on success, and a disengaged optional

I noticed we're dealing with the target description id as ULONGEST on gdb's side, but as unsigned int on gdbserver's side.

Should we make them the same, if possible?

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-01-30  4:45 ` [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely Thiago Jung Bauermann
@ 2023-02-01  9:58   ` Luis Machado
  2023-02-01 15:26   ` Andrew Burgess
  1 sibling, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-01  9:58 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
> If the remote target provides target description IDs in their threads
> list and stop reply packets, use them to update the thread's gdbarch.
> This allows debugging programs remotely that change their SVE vector
> length during runtime.
> 
> GDB already supports different vector lengths in native debugging by
> calling target_ops::thread_architecture, and aarch64_linux_nat_target
> provides an implementation of that method.
> 
> So to provide the same feature in remote debugging, implement the
> thread_architecture method in remote_target, so that the same
> mechanism can be used for both the native and remote cases.  This
> method returns the gdbarch corresponding to the target description
> provided by the last threads list or stop reply packet.
> 
> To allow changing the architecture based on the target description,
> add a new gdbarch method to allow arch-specific code to make the
> adjustment.
> ---
>   gdb/aarch64-tdep.c        | 20 ++++++++++
>   gdb/arch-utils.c          |  8 ++++
>   gdb/arch-utils.h          |  4 ++
>   gdb/gdbarch-components.py | 15 +++++++
>   gdb/gdbarch-gen.h         | 10 +++++
>   gdb/gdbarch.c             | 22 ++++++++++
>   gdb/remote.c              | 84 +++++++++++++++++++++++++++++++++++++++
>   7 files changed, 163 insertions(+)
> 
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index b576d3b9d99f..1e6e7116ed8a 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3502,6 +3502,25 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
>   	  || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
>   }
>   
> +/* Implement the "update_architecture" gdbarch method.  */
> +
> +static struct gdbarch *
> +aarch64_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  /* If this is a 32-bit architecture, then this is ARM, not AArch64.
> +     There are no SVE registers here, so just return the inferior
> +     architecture.  */
> +  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
> +    return gdbarch;
> +
> +  struct gdbarch_info info;
> +
> +  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
> +  info.target_desc = tdesc;
> +
> +  return gdbarch_find_by_info (info);
> +}
> +
>   /* Implement the stack_frame_destroyed_p gdbarch method.  */
>   
>   static int
> @@ -3748,6 +3767,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     set_tdesc_pseudo_register_reggroup_p (gdbarch,
>   					aarch64_pseudo_register_reggroup_p);
>     set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
> +  set_gdbarch_update_architecture (gdbarch, aarch64_update_architecture);
>   
>     /* ABI */
>     set_gdbarch_short_bit (gdbarch, 16);
> diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
> index 67968126488e..e8ad0aed6eb4 100644
> --- a/gdb/arch-utils.c
> +++ b/gdb/arch-utils.c
> @@ -1098,6 +1098,14 @@ default_get_return_buf_addr (struct type *val_type, frame_info_ptr cur_frame)
>     return 0;
>   }
>   
> +/* See arch-utils.h.  */
> +
> +struct gdbarch *
> +default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  return gdbarch;
> +}
> +
>   /* Non-zero if we want to trace architecture code.  */
>   
>   #ifndef GDBARCH_DEBUG
> diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
> index 56690f0fd435..aeee7f51ad49 100644
> --- a/gdb/arch-utils.h
> +++ b/gdb/arch-utils.h
> @@ -314,4 +314,8 @@ extern enum return_value_convention default_gdbarch_return_value
>         struct regcache *regcache, struct value **read_value,
>         const gdb_byte *writebuf);
>   
> +/* Default implementation of gdbarch update_architecture method.  */
> +extern struct gdbarch *
> +default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);
> +
>   #endif /* ARCH_UTILS_H */
> diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py
> index 76ad2832d8a2..68b7521c9966 100644
> --- a/gdb/gdbarch-components.py
> +++ b/gdb/gdbarch-components.py
> @@ -2744,3 +2744,18 @@ Read core file mappings
>       predefault="default_read_core_file_mappings",
>       invalid=False,
>   )
> +
> +Method(
> +    comment="""
> +An architecture may change while the inferior is running.  For instance, the
> +length of the vector registers in AArch64's Scalable Vector Extension is given
> +by the contents of the VG pseudo-register.
> +
> +Return a gdbarch corresponding to the given target description.
> +""",
> +    type="struct gdbarch *",
> +    name="update_architecture",
> +    params=[("const target_desc *", "tdesc")],
> +    predefault="default_update_architecture",
> +    invalid=False,
> +)
> diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
> index 32b2d96fbe01..d6068c2bc24f 100644
> --- a/gdb/gdbarch-gen.h
> +++ b/gdb/gdbarch-gen.h
> @@ -1672,3 +1672,13 @@ extern void set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, gdbarch_g
>   typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
>   extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
>   extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
> +
> +/* An architecture may change while the inferior is running.  For instance, the
> +   length of the vector registers in AArch64's Scalable Vector Extension is given
> +   by the contents of the VG pseudo-register.
> +
> +   Return a gdbarch corresponding to the given target description. */
> +
> +typedef struct gdbarch * (gdbarch_update_architecture_ftype) (struct gdbarch *gdbarch, const target_desc *tdesc);
> +extern struct gdbarch * gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);
> +extern void set_gdbarch_update_architecture (struct gdbarch *gdbarch, gdbarch_update_architecture_ftype *update_architecture);
> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
> index 46baca9c4793..07d3e060fe1f 100644
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -256,6 +256,7 @@ struct gdbarch
>     gdbarch_type_align_ftype *type_align = default_type_align;
>     gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags;
>     gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
> +  gdbarch_update_architecture_ftype *update_architecture = default_update_architecture;
>   };
>   
>   /* Create a new ``struct gdbarch'' based on information provided by
> @@ -517,6 +518,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
>     /* Skip verify of type_align, invalid_p == 0 */
>     /* Skip verify of get_pc_address_flags, invalid_p == 0 */
>     /* Skip verify of read_core_file_mappings, invalid_p == 0 */
> +  /* Skip verify of update_architecture, invalid_p == 0 */
>     if (!log.empty ())
>       internal_error (_("verify_gdbarch: the following are invalid ...%s"),
>   		    log.c_str ());
> @@ -1355,6 +1357,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
>     gdb_printf (file,
>   	      "gdbarch_dump: read_core_file_mappings = <%s>\n",
>   	      host_address_to_string (gdbarch->read_core_file_mappings));
> +  gdb_printf (file,
> +	      "gdbarch_dump: update_architecture = <%s>\n",
> +	      host_address_to_string (gdbarch->update_architecture));
>     if (gdbarch->dump_tdep != NULL)
>       gdbarch->dump_tdep (gdbarch, file);
>   }
> @@ -5317,3 +5322,20 @@ set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch,
>   {
>     gdbarch->read_core_file_mappings = read_core_file_mappings;
>   }
> +
> +struct gdbarch *
> +gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->update_architecture != NULL);
> +  if (gdbarch_debug >= 2)
> +    gdb_printf (gdb_stdlog, "gdbarch_update_architecture called\n");
> +  return gdbarch->update_architecture (gdbarch, tdesc);
> +}
> +
> +void
> +set_gdbarch_update_architecture (struct gdbarch *gdbarch,
> +				 gdbarch_update_architecture_ftype update_architecture)
> +{
> +  gdbarch->update_architecture = update_architecture;
> +}
> diff --git a/gdb/remote.c b/gdb/remote.c
> index f1d1944414c3..a17d65220408 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -506,6 +506,8 @@ class remote_target : public process_stratum_target
>     gdb::byte_vector thread_info_to_thread_handle (struct thread_info *tp)
>   						 override;
>   
> +  struct gdbarch *thread_architecture (ptid_t ptid) override;
> +
>     void stop (ptid_t) override;
>   
>     void interrupt () override;
> @@ -1168,6 +1170,10 @@ struct remote_thread_info : public private_thread_info
>        to stop for a watchpoint.  */
>     CORE_ADDR watch_data_address = 0;
>   
> +  /* The architecture corresponding to the target description returned
> +     in the last stop reply or threads list.  */
> +  struct gdbarch *arch = nullptr;
> +
>     /* Get the thread's resume state.  */
>     enum resume_state get_resume_state () const
>     {
> @@ -1186,6 +1192,8 @@ struct remote_thread_info : public private_thread_info
>       m_resume_state = resume_state::RESUMED_PENDING_VCONT;
>       m_resumed_pending_vcont_info.step = step;
>       m_resumed_pending_vcont_info.sig = sig;
> +
> +    arch = nullptr;
>     }
>   
>     /* Get the information this thread's pending vCont-resumption.
> @@ -1203,6 +1211,8 @@ struct remote_thread_info : public private_thread_info
>     void set_resumed ()
>     {
>       m_resume_state = resume_state::RESUMED;
> +
> +    arch = nullptr;
>     }
>   
>   private:
> @@ -4046,6 +4056,29 @@ remote_target::update_thread_list ()
>   	      info->extra = std::move (item.extra);
>   	      info->name = std::move (item.name);
>   	      info->thread_handle = std::move (item.thread_handle);
> +
> +	      /* If the threads list indicated a target description for this
> +		 thread, add it to the thread information.  */
> +	      if (item.tdesc_id)
> +		{
> +		  const target_desc *tdesc
> +		      = get_remote_state ()->get_tdesc (*item.tdesc_id);
> +
> +		  gdb_assert (tdesc != nullptr);
> +
> +		  /* If there's no thread-specific gdbarch, use the one from the
> +		     whole inferior.  */
> +		  if (info->arch == nullptr)
> +		    info->arch = tp->inf->gdbarch;
> +
> +		  gdbarch *new_arch = gdbarch_update_architecture (info->arch,
> +								   tdesc);
> +		  if (new_arch != info->arch)
> +		    {
> +		      registers_changed_thread (tp);
> +		      info->arch = new_arch;
> +		    }
> +		}
>   	    }
>   	}
>       }
> @@ -8152,6 +8185,36 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
>         && status->kind () != TARGET_WAITKIND_SIGNALLED
>         && status->kind () != TARGET_WAITKIND_NO_RESUMED)
>       {
> +      thread_info *thr = find_thread_ptid (this, ptid);
> +
> +      /* If GDB already knows about this thread, we can give the
> +	 architecture-specific code a chance to update the gdbarch based on the
> +	 provided target description.  */
> +      if (stop_reply->tdesc_id && thr != nullptr)
> +	{
> +	  const target_desc *tdesc
> +	      = stop_reply->rs->get_tdesc (*stop_reply->tdesc_id);
> +
> +	  gdb_assert (tdesc != nullptr);
> +
> +	  /* If there's no gdbarch associated with the stop reply, use the one
> +	     from the whole inferior.  */
> +	  if (stop_reply->arch == nullptr)
> +	    stop_reply->arch = thr->inf->gdbarch;
> +
> +	  stop_reply->arch = gdbarch_update_architecture (stop_reply->arch,
> +							  tdesc);
> +
> +	  /* Save stop_reply->arch so that it can be returned by the
> +	     thread_architecture method.  */
> +	  remote_thread_info *remote_thr = get_remote_thread_info (thr);
> +	  if (remote_thr->arch != stop_reply->arch)
> +	    {
> +	      registers_changed_thread (thr);
> +	      remote_thr->arch = stop_reply->arch;
> +	    }
> +	}
> +
>         /* Expedited registers.  */
>         if (!stop_reply->regcache.empty ())
>   	{
> @@ -14469,6 +14532,27 @@ remote_target::thread_info_to_thread_handle (struct thread_info *tp)
>     return priv->thread_handle;
>   }
>   
> +/* Implementation of the thread_architecture method for the remote target.  */
> +
> +struct gdbarch *
> +remote_target::thread_architecture (ptid_t ptid)
> +{
> +  thread_info *thr = find_thread_ptid (this, ptid);
> +  remote_thread_info *remote_thr;
> +
> +  if (thr == nullptr)
> +    remote_thr = nullptr;
> +  else
> +    remote_thr = get_remote_thread_info (thr);
> +
> +  if (remote_thr == nullptr || remote_thr->arch == nullptr)
> +    /* The default thread_architecture implementation is the one from
> +       process_stratum_target.  */
> +    return process_stratum_target::thread_architecture (ptid);
> +
> +  return remote_thr->arch;
> +}
> +
>   bool
>   remote_target::can_async_p ()
>   {

I have no comments on this patch. It looks sane to me.

Reviewed-by: Luis Machado <luis.machado@arm.com>

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors
  2023-01-30  4:45 ` [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors Thiago Jung Bauermann
@ 2023-02-01 10:10   ` Luis Machado
  0 siblings, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-01 10:10 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

Just a nit.

On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
> This testcase exercises two scenarios with a multi-threaded inferior, one
> proposed by Luis and another one proposed by Simon.
> 
> In the first scenario, one of the inferior threads changes its vector
> length and then hits a breakpoint.  In the second one, the main thread hits
> a breakpoint and then GDB switches to another thread.
> ---
>   gdb/testsuite/gdb.arch/aarch64-sve-threads.c  | 125 ++++++++++++++++++
>   .../gdb.arch/aarch64-sve-threads.exp          |  70 ++++++++++
>   2 files changed, 195 insertions(+)
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.c
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
> 
> diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.c b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c
> new file mode 100644
> index 000000000000..7fad77008da3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c
> @@ -0,0 +1,125 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2023 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* Exercise AArch64's Scalable Vector Extension in a multi-threaded program.  */
> +
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <pthread.h>
> +#include <semaphore.h>
> +#include <sys/prctl.h>
> +#include <unistd.h>
> +
> +/* For one of the tests, the thread needs to sleep after setting the vector
> +   length.  This variable is set by GDB.  */
> +volatile bool should_sleep = false;
> +
> +/* Used to signal to the main thread that the additional thread's vector length
> +   was changed.  */
> +sem_t vl_changed;
> +
> +/* Start routine for the additional thread.  Sets a new vector length, sleeps if
> +   requested then restores the original vector length.  */
> +
> +static void *
> +thread_function (void *unused)
> +{
> +  unsigned int vl;
> +  int rc;
> +
> +  rc = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
> +  if (rc < 0)
> +    {
> +      perror ("FAILED to PR_SVE_GET_VL");
> +      sem_post (&vl_changed);
> +      return NULL;
> +    }
> +
> +  vl = rc & PR_SVE_VL_LEN_MASK;
> +
> +  /* Decrease vector length by 16 bytes.  */
> +  vl -= 16;

Is there an initial vector length set before we decrement it by 16? I'm wondering about a case where we already start with 16, and then we'd decrement the vector length to an invalid value.

> +
> +  rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0, 0);
> +  if (rc < 0)
> +    {
> +      perror ("FAILED to PR_SVE_SET_VL");
> +      sem_post (&vl_changed);
> +      return NULL;
> +    }
> +
> +  /* Let the main thread continue.  */
> +  rc = sem_post (&vl_changed);
> +  if (rc != 0)
> +    {
> +      perror ("sem_post");
> +      return NULL;
> +    }
> +
> +  if (should_sleep)
> +    sleep (10);
> +
> +  /* Restore original vector length.  */
> +  vl += 16; /* break here 1 */
> +
> +  rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0, 0);
> +  if (rc < 0)
> +    {
> +      perror ("FAILED to PR_SVE_SET_VL");
> +      return NULL;
> +    }
> +
> +  return NULL; /* break here 2 */
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> +  pthread_t thread;
> +  int rc;
> +
> +  rc = sem_init (&vl_changed, 0, 0);
> +  if (rc != 0)
> +    {
> +      perror ("sem_init");
> +      return 1;
> +    }
> +
> +  rc = pthread_create (&thread, NULL, thread_function, NULL);
> +  if (rc != 0)
> +    {
> +      perror ("pthread_create");
> +      return 1;
> +    }
> +
> +  /* Wait until the additional thread changes it's vector length.  */
> +  rc = sem_wait (&vl_changed);
> +  if (rc != 0)
> +    {
> +      perror ("sem_wait");
> +      return 1;
> +    }
> +
> +  rc = pthread_join (thread, NULL); /* break here 3 */
> +  if (rc != 0)
> +    {
> +      perror ("pthread_join");
> +      return 1;
> +    }
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
> new file mode 100644
> index 000000000000..48197650e1de
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
> @@ -0,0 +1,70 @@
> +# Copyright 2023 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test a multi-threaded binary that uses SVE and changes the SVE vector length
> +# in the additional thread.
> +
> +if {[skip_aarch64_sve_tests]} {
> +    verbose "Skipping ${gdb_test_file_name}."
> +    return
> +}
> +
> +standard_testfile
> +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
> +	 {debug pthreads}] == -1} {
> +    return -1
> +}
> +
> +if ![runto_main] {
> +    return -1
> +}
> +
> +# Stop after the additional thread has changed its vector length.
> +gdb_breakpoint [gdb_get_line_number "break here 1"]
> +gdb_continue_to_breakpoint "break here 1"
> +
> +# If GDB and gdbserver don't agree on the thread's vector length, this command
> +# will fail.
> +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register"
> +

Out of curiosity, what is the failure mode when gdbserver doesn't do the right thing.

> +# Stop after the additional thread has restored its original vector length.
> +gdb_breakpoint [gdb_get_line_number "break here 2"]
> +gdb_continue_to_breakpoint "break here 2"
> +
> +# Test that going back to the original vector length doesn't confuse GDB or
> +# gdbserver.
> +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register again"
> +
> +# Restart GDB to test a scenario where GDB switches to a thread that changed its
> +# vector length but hasn't hit any breakpoints yet.
> +clean_restart ${binfile}
> +
> +if ![runto_main] {
> +    return -1
> +}
> +
> +# Make the thread sleep after changing its vector length.
> +gdb_test_no_output -nopass "set var should_sleep = 1" "make thread sleep"
> +
> +# Stop after the additional thread has been created.
> +gdb_breakpoint [gdb_get_line_number "break here 3"]
> +gdb_continue_to_breakpoint "break here 3"
> +
> +# The regexp accounts for two lines of output after the "Switching to thread" message.
> +gdb_test_lines "thread 2" "switch to another thread" \
> +    {\[Switching to thread 2 \(.*\)\]\r\n#0  [[:print:]]+}
> +
> +# Make sure everything is still fine.
> +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register in thread 2

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
  2023-02-01  9:07   ` Luis Machado
@ 2023-02-01 10:54   ` Andrew Burgess
  2023-02-01 16:01     ` Simon Marchi
  2023-02-06 19:54   ` Pedro Alves
  2 siblings, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 10:54 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> This patch doesn't change gdbserver behaviour, but after later changes are
> made it avoids a null pointer dereference when HWCAP needs to be obtained
> for a specific process while current_thread is nullptr.
>
> Fixing linux_read_auxv, linux_get_hwcap and linux_get_hwcap2 to take a PID
> parameter seems more correct than setting current_thread in one particular
> code path.
>
> Changes are propagated to allow passing the new parameter through the call
> chain.
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdbserver/linux-aarch64-low.cc |  7 ++++---
>  gdbserver/linux-arm-low.cc     |  2 +-
>  gdbserver/linux-low.cc         | 18 +++++++++---------
>  gdbserver/linux-low.h          |  9 ++++-----
>  gdbserver/linux-ppc-low.cc     |  6 +++---
>  gdbserver/linux-s390-low.cc    |  2 +-
>  gdbserver/netbsd-low.cc        |  4 +---
>  gdbserver/netbsd-low.h         |  2 +-
>  gdbserver/server.cc            |  3 ++-
>  gdbserver/target.cc            |  4 ++--
>  gdbserver/target.h             |  4 ++--
>  11 files changed, 30 insertions(+), 31 deletions(-)
>
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 3c09e086afee..2ed6e95562c5 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -846,12 +846,13 @@ aarch64_target::low_arch_setup ()
>    if (is_elf64)
>      {
>        struct aarch64_features features;
> +      int pid = current_thread->id.pid ();
>  
>        features.vq = aarch64_sve_get_vq (tid);
>        /* A-profile PAC is 64-bit only.  */
> -      features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
> +      features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
>        /* A-profile MTE is 64-bit only.  */
> -      features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> +      features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
>        features.tls = aarch64_tls_register_count (tid);
>  
>        current_process ()->tdesc = aarch64_linux_read_description (features);
> @@ -3322,7 +3323,7 @@ aarch64_target::supports_memory_tagging ()
>  #endif
>      }
>  
> -  return (linux_get_hwcap2 (8) & HWCAP2_MTE) != 0;
> +  return (linux_get_hwcap2 (current_thread->id.pid (), 8) & HWCAP2_MTE) != 0;
>  }
>  
>  bool
> diff --git a/gdbserver/linux-arm-low.cc b/gdbserver/linux-arm-low.cc
> index 98ba0e02524b..5975b44af0ae 100644
> --- a/gdbserver/linux-arm-low.cc
> +++ b/gdbserver/linux-arm-low.cc
> @@ -958,7 +958,7 @@ get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
>  static const struct target_desc *
>  arm_read_description (void)
>  {
> -  unsigned long arm_hwcap = linux_get_hwcap (4);
> +  unsigned long arm_hwcap = linux_get_hwcap (current_thread->id.pid (), 4);
>  
>    if (arm_hwcap & HWCAP_IWMMXT)
>      return arm_linux_read_description (ARM_FP_TYPE_IWMMXT);
> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
> index 7e1de3978933..5cd22824e470 100644
> --- a/gdbserver/linux-low.cc
> +++ b/gdbserver/linux-low.cc
> @@ -5483,12 +5483,11 @@ linux_process_target::supports_read_auxv ()
>     to debugger memory starting at MYADDR.  */
>  
>  int
> -linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> -				 unsigned int len)
> +linux_process_target::read_auxv (int pid, CORE_ADDR offset,
> +				 unsigned char *myaddr, unsigned int len)
>  {
>    char filename[PATH_MAX];
>    int fd, n;
> -  int pid = lwpid_of (current_thread);
>  
>    xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
>  
> @@ -6982,14 +6981,15 @@ linux_get_pc_64bit (struct regcache *regcache)
>  /* See linux-low.h.  */
>  
>  int
> -linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
> +linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp)
>  {
>    gdb_byte *data = (gdb_byte *) alloca (2 * wordsize);
>    int offset = 0;
>  
>    gdb_assert (wordsize == 4 || wordsize == 8);
>  
> -  while (the_target->read_auxv (offset, data, 2 * wordsize) == 2 * wordsize)
> +  while (the_target->read_auxv (pid, offset, data, 2 * wordsize)
> +	 == 2 * wordsize)
>      {
>        if (wordsize == 4)
>  	{
> @@ -7019,20 +7019,20 @@ linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
>  /* See linux-low.h.  */
>  
>  CORE_ADDR
> -linux_get_hwcap (int wordsize)
> +linux_get_hwcap (int pid, int wordsize)
>  {
>    CORE_ADDR hwcap = 0;
> -  linux_get_auxv (wordsize, AT_HWCAP, &hwcap);
> +  linux_get_auxv (pid, wordsize, AT_HWCAP, &hwcap);
>    return hwcap;
>  }
>  
>  /* See linux-low.h.  */
>  
>  CORE_ADDR
> -linux_get_hwcap2 (int wordsize)
> +linux_get_hwcap2 (int pid, int wordsize)
>  {
>    CORE_ADDR hwcap2 = 0;
> -  linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2);
> +  linux_get_auxv (pid, wordsize, AT_HWCAP2, &hwcap2);
>    return hwcap2;
>  }
>  
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index aebfe05707e5..221de85aa2ee 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -178,7 +178,7 @@ class linux_process_target : public process_stratum_target
>  
>    bool supports_read_auxv () override;
>  
> -  int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> +  int read_auxv (int pid, CORE_ADDR offset, unsigned char *myaddr,
>  		 unsigned int len) override;
>  
>    int insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>     *VALP and return 1.  If not found or if there is an error, return
>     0.  */
>  
> -int linux_get_auxv (int wordsize, CORE_ADDR match,
> -		    CORE_ADDR *valp);
> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>  
>  /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>     WORDSIZE.  If no entry was found, return zero.  */
>  
> -CORE_ADDR linux_get_hwcap (int wordsize);
> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>  
>  /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>     WORDSIZE.  If no entry was found, return zero.  */
>  
> -CORE_ADDR linux_get_hwcap2 (int wordsize);
> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);

Ideally the comment for these three functions would be updated to
mention the PID argument.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-01-30  4:45 ` [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description Thiago Jung Bauermann
  2023-02-01  9:05   ` Luis Machado
@ 2023-02-01 11:06   ` Andrew Burgess
  2023-02-01 16:21     ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 11:06 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches
  Cc: Thiago Jung Bauermann, Luis Machado

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> This change prepares gdbserver to support remotely debugging programs in
> aarch64-linux where different threads have different SVE vector lengths.
> It allows gdbserver to support different inferior threads having different
> target descriptions.
>
> To that end, a tdesc field is added to struct thread_info.  If it's
> nullptr (the default) it means that the thread uses the target description
> stored in struct process_info and thus gdbserver behaviour is unchanged.
> The get_thread_tdesc method is added to the linux_process_target class to
> allow aarch64-linux code to probe the inferior's vq register and provide a
> thread-specific target description reflecting the new vector length.
>
> After this change, all targets except SVE-supporting aarch64-linux will
> still use per-process target descriptions.
>
> Reviewed-by: Luis Machado <luis.machado@arm.com>
> ---
>  gdbserver/gdbthread.h          |  4 ++++
>  gdbserver/linux-aarch64-low.cc | 31 +++++++++++++++++++++++++++++++
>  gdbserver/linux-low.cc         | 17 +++++++++++++++++
>  gdbserver/linux-low.h          |  6 ++++++
>  gdbserver/regcache.cc          | 10 ++++++----
>  gdbserver/regcache.h           |  4 ++++
>  gdbserver/tdesc.cc             | 13 ++++++++++++-
>  gdbserver/tdesc.h              |  5 +++++
>  8 files changed, 85 insertions(+), 5 deletions(-)
>
> diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
> index 493e1dbf6cb6..5b5ba6f8e521 100644
> --- a/gdbserver/gdbthread.h
> +++ b/gdbserver/gdbthread.h
> @@ -80,6 +80,10 @@ struct thread_info
>  
>    /* Branch trace target information for this thread.  */
>    struct btrace_target_info *btrace = nullptr;
> +
> +  /* Target description for this thread.  Only present if it's different
> +     from the one in process_info.  */
> +  const struct target_desc *tdesc = nullptr;
>  };
>  
>  extern std::list<thread_info *> all_threads;
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 92c621e5548c..69765ee90db3 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -99,6 +99,9 @@ protected:
>  
>    void low_arch_setup () override;
>  
> +  const struct target_desc *
> +    get_thread_tdesc (const thread_info *thread) override;
> +
>    bool low_cannot_fetch_register (int regno) override;
>  
>    bool low_cannot_store_register (int regno) override;
> @@ -184,6 +187,9 @@ struct arch_process_info
>       same for each thread, it is reasonable for the data to live here.
>       */
>    struct aarch64_debug_reg_state debug_reg_state;
> +
> +  /* Whether this process has the Scalable Vector Extension available.  */
> +  bool has_sve;
>  };
>  
>  /* Return true if the size of register 0 is 8 byte.  */
> @@ -869,6 +875,9 @@ aarch64_target::low_arch_setup ()
>  
>        current_process ()->tdesc = aarch64_linux_read_description (features);
>  
> +      if (features.vq > 0)
> +	current_process ()->priv->arch_private->has_sve = true;
> +
>        /* Adjust the register sets we should use for this particular set of
>  	 features.  */
>        aarch64_adjust_register_sets (features);
> @@ -879,6 +888,28 @@ aarch64_target::low_arch_setup ()
>    aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
>  }
>  
> +/* Implementation of linux target ops method "get_thread_tdesc".  */
> +
> +const struct target_desc *
> +aarch64_target::get_thread_tdesc (const thread_info *thread)
> +{
> +  const struct process_info *process = get_thread_process (thread);
> +
> +  /* Only inferiors with SVE need a thread-specific target description.  */
> +  if (!process->priv->arch_private->has_sve)
> +    return nullptr;
> +
> +  const struct aarch64_features features = aarch64_get_arch_features (thread);
> +  const struct target_desc *tdesc = aarch64_linux_read_description (features);
> +
> +  /* If the target description we just found is the same as the process-wide
> +     one, there's no need to set a thread-specific one.  */
> +  if (tdesc == process->tdesc)
> +    return nullptr;
> +
> +  return tdesc;
> +}
> +
>  /* Implementation of linux target ops method "get_regs_info".  */
>  
>  const regs_info *
> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
> index 5cd22824e470..47916009ebaf 100644
> --- a/gdbserver/linux-low.cc
> +++ b/gdbserver/linux-low.cc
> @@ -483,6 +483,12 @@ linux_process_target::arch_setup_thread (thread_info *thread)
>    low_arch_setup ();
>  }
>  
> +const struct target_desc *
> +linux_process_target::get_thread_tdesc (const thread_info *thread)
> +{
> +  return nullptr;
> +}
> +
>  int
>  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
>  					    int wstat)
> @@ -2348,6 +2354,17 @@ linux_process_target::filter_event (int lwpid, int wstat)
>  	      return;
>  	    }
>  	}
> +      else
> +	{
> +	  /* Give the arch code an opportunity to set the thread's target
> +	     description.  */
> +	  const struct target_desc *new_tdesc = get_thread_tdesc (thread);
> +	  if (new_tdesc != thread->tdesc)
> +	    {
> +	      free_register_cache_thread (thread);
> +	      thread->tdesc = new_tdesc;
> +	    }
> +	}
>      }
>  
>    if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags)
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index 221de85aa2ee..b52eb23cc444 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>    /* Architecture-specific setup for the current thread.  */
>    virtual void low_arch_setup () = 0;
>  
> +  /* Allows arch-specific code to set the thread's target description when the
> +     inferior stops.  Returns nullptr if no thread-specific target description
> +     is necessary.  */
> +  virtual const struct target_desc *
> +    get_thread_tdesc (const thread_info *thread);

I think the comment for this function is not correct.  The function does
not SET the thread's target description, but just GETS a target
description suitable for `thread`.  It's the caller's job to do the
setting.

Thanks,
Andrew

> +
>    /* Return false if we can fetch/store the register, true if we cannot
>       fetch/store the register.  */
>    virtual bool low_cannot_fetch_register (int regno) = 0;
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 7b896a19767d..fb60e2c9c399 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -39,11 +39,11 @@ get_thread_regcache (struct thread_info *thread, int fetch)
>       have.  */
>    if (regcache == NULL)
>      {
> -      struct process_info *proc = get_thread_process (thread);
> +      const target_desc *tdesc = get_thread_target_desc (thread);
>  
> -      gdb_assert (proc->tdesc != NULL);
> +      gdb_assert (tdesc != nullptr);
>  
> -      regcache = new_register_cache (proc->tdesc);
> +      regcache = new_register_cache (tdesc);
>        set_thread_regcache_data (thread, regcache);
>      }
>  
> @@ -270,7 +270,9 @@ find_regno (const struct target_desc *tdesc, const char *name)
>    internal_error ("Unknown register %s requested", name);
>  }
>  
> -static void
> +/* See regcache.h.  */
> +
> +void
>  free_register_cache_thread (struct thread_info *thread)
>  {
>    struct regcache *regcache = thread_regcache_data (thread);
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 7248bcf5808a..4beea0139cd6 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -79,6 +79,10 @@ void free_register_cache (struct regcache *regcache);
>  
>  void regcache_invalidate_thread (struct thread_info *);
>  
> +/* Invalidate and release the register cache of the given THREAD.  */
> +
> +void free_register_cache_thread (struct thread_info *thread);
> +
>  /* Invalidate cached registers for all threads of the given process.  */
>  
>  void regcache_invalidate_pid (int pid);
> diff --git a/gdbserver/tdesc.cc b/gdbserver/tdesc.cc
> index 2c7257c458f4..e3339dde4d6c 100644
> --- a/gdbserver/tdesc.cc
> +++ b/gdbserver/tdesc.cc
> @@ -123,13 +123,24 @@ copy_target_description (struct target_desc *dest,
>    dest->xmltarget = src->xmltarget;
>  }
>  
> +/* See tdesc.h.  */
> +
> +const struct target_desc *
> +get_thread_target_desc (const struct thread_info *thread)
> +{
> +  if (thread->tdesc != nullptr)
> +    return thread->tdesc;
> +
> +  return get_thread_process (thread)->tdesc;
> +}
> +
>  const struct target_desc *
>  current_target_desc (void)
>  {
>    if (current_thread == NULL)
>      return &default_description;
>  
> -  return current_process ()->tdesc;
> +  return get_thread_target_desc (current_thread);
>  }
>  
>  /* An empty structure.  */
> diff --git a/gdbserver/tdesc.h b/gdbserver/tdesc.h
> index 7fe7d0d8eb30..71cc5b51c84e 100644
> --- a/gdbserver/tdesc.h
> +++ b/gdbserver/tdesc.h
> @@ -88,6 +88,11 @@ void copy_target_description (struct target_desc *dest,
>  void init_target_desc (struct target_desc *tdesc,
>  		       const char **expedite_regs);
>  
> +/* Return the target description corresponding to the given THREAD.  */
> +
> +const struct target_desc *
> +  get_thread_target_desc (const struct thread_info *thread);
> +
>  /* Return the current inferior's target description.  Never returns
>     NULL.  */
>  


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
  2023-01-30 12:52   ` Eli Zaretskii
  2023-02-01  9:39   ` Luis Machado
@ 2023-02-01 12:07   ` Andrew Burgess
  2023-02-01 13:03     ` Eli Zaretskii
                       ` (2 more replies)
  2023-02-01 14:51   ` Andrew Burgess
  3 siblings, 3 replies; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 12:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> Now that an inferior thread can have a different target description than
> its process, there needs to be a way to communicate this target
> description to GDB.  So add the concept of a target description ID to the
> remote protocol, which is used to reference them and allows them to be
> transferred only once over the wire.
>
> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
> unsigned integer containing the ID.
>
> It is also sent in the threads list XML in the response of a
> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
> the <thread> node.
>
> To request the target description XML of a given ID, GDB sends the
> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
> is the target description ID.

Luis already commented that in some locations the ID is hex, while in
others it is not explicitly stated if the value is hex or decimal.  I'd
like to second that feedback, and suggest that we pick one, and use that
consistently throughout.

My thinking is that it will be easier to understand remote packet traces
if target descriptions are requested using an ID in the safe format as
was sent to GDB, and if IDs in different packets match up.

Thus, I would suggest we switch to using 'target-id-%x.xml' here, and
send the ID as hex in the threads reply packet.

Additionally, I think it would be worth adding a new feature to the
qSupported packet, maybe 'per-thread-tdesc'.  With this added, GDB would
be able to tell gdbserver that it supports this feature, and gdbserver
will be able to confirm that the feature is supported.

I'm not 100% sure what we'd want to do if it turns out GDB doesn't
support the feature?  Is it better to push on with GDB using the wrong
target description?  Or would it be better if gdbserver exits with an
error suggesting the GDB needs updating?  In some ways, _what_ we do
doesn't really matter to me, but I think having the feature will allow
us to pick a suitable error handling solution later if needed.

I'd be happy if adding the feature was done as a separate patch in this
series, but I do think it should be part of this series.

>
> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
>  gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
>  gdbserver/remote-utils.h  |  9 +++++++
>  gdbserver/server.cc       | 17 ++++++++++--
>  gdbserver/server.h        |  4 +++
>  5 files changed, 109 insertions(+), 5 deletions(-)
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 9c0018ea5c14..fbf7e59853b5 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -42030,6 +42030,10 @@ the stopped thread, as specified in @ref{thread-id syntax}.
>  If @var{n} is @samp{core}, then @var{r} is the hexadecimal number of
>  the core on which the stop event was detected.
>  
> +@item
> +If @var{n} is @samp{tdesc}, then @var{r} is the hexadecimal number of
> +the target description ID (@pxref{Target Description ID}).
> +
>  @item
>  If @var{n} is a recognized @dfn{stop reason}, it describes a more
>  specific event that stopped the target.  The currently defined stop
> @@ -46546,7 +46550,7 @@ the following structure:
>  @smallexample
>  <?xml version="1.0"?>
>  <threads>
> -    <thread id="id" core="0" name="name">
> +    <thread id="id" core="0" name="name" tdesc="0">
>      ... description ...
>      </thread>
>  </threads>
> @@ -46556,8 +46560,10 @@ Each @samp{thread} element must have the @samp{id} attribute that
>  identifies the thread (@pxref{thread-id syntax}).  The
>  @samp{core} attribute, if present, specifies which processor core
>  the thread was last executing on.  The @samp{name} attribute, if
> -present, specifies the human-readable name of the thread.  The content
> -of the of @samp{thread} element is interpreted as human-readable
> +present, specifies the human-readable name of the thread.  The
> +@samp{tdesc} attribute, if present, specifies the target description
> +ID of the thread (@pxref{Target Description ID}).  The content of
> +the @samp{thread} element is interpreted as human-readable
>  auxiliary information.  The @samp{handle} attribute, if present,
>  is a hex encoded representation of the thread handle.
>  
> @@ -46767,6 +46773,8 @@ descriptions are accurate, and that @value{GDBN} understands them.
>  target descriptions.  @xref{Expat}.
>  
>  @menu
> +* Target Description ID::           Referencing different descriptions in the
> +                                    remote protocol.
>  * Retrieving Descriptions::         How descriptions are fetched from a target.
>  * Target Description Format::       The contents of a target description.
>  * Predefined Target Types::         Standard types available for target
> @@ -46775,6 +46783,14 @@ target descriptions.  @xref{Expat}.
>  * Standard Target Features::        Features @value{GDBN} knows about.
>  @end menu
>  
> +@node Target Description ID
> +@section Target Description ID
> +
> +In cases where a remote target supports threads having different
> +target descriptions than their parent process, the remote protocol
> +assigns a non-negative integer to each target description to reference
> +it in the communication between the host and the target.

I think this should be reworded slightly.  I would prefer that it be
made clear that it is the remote target that is responsible for
assigning the ID numbers for target descriptions.

It would also be nice if there were some cross references from this
section to the other places in the manual where we discuss
sending/receiving the ID number.

Finally, I wonder if it might make sense to add something like:

  @cindex Target Description IDs

to every place where we discuss these ID's, then there will be an index
entry that links all the places together?

> +
>  @node Retrieving Descriptions
>  @section Retrieving Descriptions
>  
> @@ -46787,6 +46803,11 @@ qXfer}).  The @var{annex} in the @samp{qXfer} packet will be
>  XML document, of the form described in @ref{Target Description
>  Format}.
>  
> +If target description IDs are being used (@pxref{Target Description ID}),
> +@value{GDBN} can retrieve a target description with a given ID by using
> +@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
> +non-negative integer identifier of the desired target description.
> +
>  Alternatively, you can specify a file to read for the target description.
>  If a file is set, the target will not be queried.  The commands to
>  specify a file are:
> diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
> index 80310bc2c709..baff899307cc 100644
> --- a/gdbserver/remote-utils.cc
> +++ b/gdbserver/remote-utils.cc
> @@ -1049,6 +1049,53 @@ outreg (struct regcache *regcache, int regno, char *buf)
>    return buf;
>  }
>  
> +/* See remote-utils.h.  */
> +
> +unsigned int
> +get_tdesc_rsp_id (const target_desc *tdesc)
> +{
> +  client_state &cs = get_client_state ();
> +  unsigned int i;
> +
> +  for (i = 0; i < cs.tdescs.size (); i++)
> +    if (cs.tdescs[i] == tdesc)
> +      return i;
> +
> +  cs.tdescs.push_back (tdesc);
> +
> +  return i;
> +}
> +
> +/* See remote-utils.h.  */
> +
> +const target_desc *
> +get_tdesc_from_rsp_id (unsigned int id)
> +{
> +  client_state &cs = get_client_state ();
> +
> +  if (id >= cs.tdescs.size ())
> +    return nullptr;
> +
> +  return cs.tdescs[id];
> +}
> +
> +/* Return the ID as used in the remote protocol for the target descriptor of the
> +   given PTID.  */
> +
> +static unsigned int
> +get_tdesc_rsp_id (ptid_t ptid)
> +{
> +  const thread_info *thread = find_thread_ptid (ptid);
> +  const target_desc *tdesc;
> +
> +  if (thread == nullptr)
> +    tdesc = find_process_pid (ptid.pid ())->tdesc;
> +  else
> +    tdesc = get_thread_target_desc (thread);
> +
> +  return get_tdesc_rsp_id (tdesc);
> +}
> +
>  void
>  prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>  {
> @@ -1241,6 +1288,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>  	    buf += strlen (buf);
>  	    current_process ()->dlls_changed = false;
>  	  }
> +
> +	if (current_thread->tdesc != nullptr
> +	    && current_thread->tdesc != current_process ()->tdesc)
> +	  {
> +	    sprintf (buf, "tdesc:");
> +	    buf += strlen (buf);
> +	    sprintf (buf, "%x", get_tdesc_rsp_id (ptid));
> +	    strcat (buf, ";");
> +	    buf += strlen (buf);
> +	  }
>        }
>        break;
>      case TARGET_WAITKIND_EXITED:
> diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h
> index cb2d6c346c99..61ef80b4dad7 100644
> --- a/gdbserver/remote-utils.h
> +++ b/gdbserver/remote-utils.h
> @@ -75,4 +75,13 @@ int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc);
>  
>  void monitor_output (const char *msg);
>  
> +/* Return the ID as used in the remote protocol for the given target
> +   descriptor.  */
> +
> +unsigned int get_tdesc_rsp_id (const target_desc *tdesc);
> +
> +/* Return the target description corresponding to the remote protocol ID.  */

This comment should explain what happens if the ID is invalid
(i.e. returns nullptr).

> +
> +const target_desc *get_tdesc_from_rsp_id (unsigned int id);
> +
>  #endif /* GDBSERVER_REMOTE_UTILS_H */
> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index 21fb51a45d16..2d1062f98468 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -976,7 +976,15 @@ handle_general_set (char *own_buf)
>  static const char *
>  get_features_xml (const char *annex)
>  {
> -  const struct target_desc *desc = current_target_desc ();
> +  const struct target_desc *desc;
> +  unsigned int id;
> +
> +  if (strcmp (annex, "target.xml") == 0)
> +    desc = current_target_desc ();
> +  else if (sscanf (annex, "target-id-%u.xml", &id) == 1)
> +    desc = get_tdesc_from_rsp_id (id);
> +  else
> +    desc = nullptr;
>  
>    /* `desc->xmltarget' defines what to return when looking for the
>       "target.xml" file.  Its contents can either be verbatim XML code

This comment could be updated to replace '"target.xml"' with 'target
description' now that we handle multiple annex names.

There's a second reference toe "target.xml" at the end of the comment,
which can also be removed with a little rewording.

Thanks,
Andrew

> @@ -986,7 +994,7 @@ get_features_xml (const char *annex)
>       This variable is set up from the auto-generated
>       init_registers_... routine for the current target.  */
>  
> -  if (strcmp (annex, "target.xml") == 0)
> +  if (desc != nullptr)
>      {
>        const char *ret = tdesc_get_features_xml (desc);
>  
> @@ -1664,6 +1672,11 @@ handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
>    if (name != NULL)
>      buffer_xml_printf (buffer, " name=\"%s\"", name);
>  
> +  if (thread->tdesc != nullptr
> +      && thread->tdesc != get_thread_process (thread)->tdesc)
> +    buffer_xml_printf (buffer, " tdesc=\"%u\"",
> +		       get_tdesc_rsp_id (thread->tdesc));
> +
>    if (handle_status)
>      {
>        char *handle_s = (char *) alloca (handle_len * 2 + 1);
> diff --git a/gdbserver/server.h b/gdbserver/server.h
> index 7997d1a32e6e..58be5027795b 100644
> --- a/gdbserver/server.h
> +++ b/gdbserver/server.h
> @@ -193,6 +193,10 @@ struct client_state
>    /* If true, memory tagging features are supported.  */
>    bool memory_tagging_feature = false;
>  
> +  /* The target descriptions that have been communicated to the client.  The
> +     index of a target description in this vector is the ID used to reference it
> +     in the remote protocol.  */
> +  std::vector<const target_desc *> tdescs;
>  };
>  
>  client_state &get_client_state ();


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 12:07   ` Andrew Burgess
@ 2023-02-01 13:03     ` Eli Zaretskii
  2023-02-01 17:37     ` Simon Marchi
  2023-02-01 20:46     ` Simon Marchi
  2 siblings, 0 replies; 94+ messages in thread
From: Eli Zaretskii @ 2023-02-01 13:03 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, gdb-patches, thiago.bauermann, simon.marchi

> Cc: Thiago Jung Bauermann <thiago.bauermann@linaro.org>, Simon Marchi
>  <simon.marchi@efficios.com>
> Date: Wed, 01 Feb 2023 12:07:20 +0000
> From: Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org>
> 
> Finally, I wonder if it might make sense to add something like:
> 
>   @cindex Target Description IDs
> 
> to every place where we discuss these ID's, then there will be an index
> entry that links all the places together?

Adding index entries is always welcome, as those help finding subjects
quickly and efficiently.  However:

  . we prefer index entries to use only lower-case letters, to avoid
    having their sorting order (which eventually affects whet you see
    in the Info reader when you use completion) depend on the locale
    where the manual is produced from Texinfo;
  . more importantly, it is not a good idea to have multiple
    identical index entries, since makeinfo then disambiguates them as
    foo<1>, foo<2>, etc., and when you see those in the list of
    completions, you have no idea which one is the one you want.  So
    it is preferable to qualify each such index entry in a way that
    will convey enough information to the reader to know which one
    he/she wants.  For example:

     @cindex target description id, and remote packets
     @cindex target description id, in python programs

    etc., you get the idea.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-01-30  4:45 ` [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML Thiago Jung Bauermann
  2023-02-01  9:52   ` Luis Machado
@ 2023-02-01 14:32   ` Andrew Burgess
  2023-02-01 19:50     ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 14:32 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches; +Cc: Thiago Jung Bauermann

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> gdbserver added the concept of target description IDs to the remote
> protocol and uses them in the threads list XML and in the 'T AA' stop
> reply packet.  It also allows fetching a target description with a given
> ID.  This patch is for the GDB-side support.  The target descriptions
> obtained this way aren't yet used but will be in the next patch.
>
> In the DTD for the threads list XML, add a "tdesc" attribute to the
> <thread> node.  A tdesc_id field is added to the stop_reply and
> thread_item structs.  An m_remote member is added to the
> threads_listing_context struct, and to simplify its initialisation a
> constructor is added as well.  This is to provide access to the remote
> state in start_thread.
>
> Finally, the remote_state object keeps a map of the target descriptions
> that have been received from the target, keyed by their ID.  There are
> also methods to get a target description given its ID, and to fetch target
> descriptions for IDs that were mentioned by gdbserver but not yet
> retrieved by GDB.  The latter gets called after parsing the response of
> qXfer:threads:read and of the stop reply packet.
> ---
>  gdb/features/threads.dtd |  1 +
>  gdb/remote.c             | 85 +++++++++++++++++++++++++++++++++++++++-
>  gdb/xml-tdesc.c          | 27 ++++++++++---
>  gdb/xml-tdesc.h          |  6 +++
>  4 files changed, 112 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/features/threads.dtd b/gdb/features/threads.dtd
> index 036b2ce58837..3102d1352978 100644
> --- a/gdb/features/threads.dtd
> +++ b/gdb/features/threads.dtd
> @@ -11,3 +11,4 @@
>  
>  <!ATTLIST thread id CDATA #REQUIRED>
>  <!ATTLIST thread core CDATA #IMPLIED>
> +<!ATTLIST thread tdesc CDATA #IMPLIED>
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 218bca30d047..f1d1944414c3 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -80,6 +80,7 @@
>  #include <unordered_map>
>  #include "async-event.h"
>  #include "gdbsupport/selftest.h"
> +#include "xml-tdesc.h"
>  
>  /* The remote target.  */
>  
> @@ -238,6 +239,16 @@ class remote_state
>    /* Get the remote arch state for GDBARCH.  */
>    struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
>  
> +  /* Add new ID to the target description list.  The corresponding XML will be
> +     requested soon.  */
> +  void add_tdesc_id (ULONGEST id);

I'm wondering why this function is needed?  Could we not just have
get_tdesc take a remote_target* argument, and fetch the descriptions on
demand?  This would also allow fetch_unknown_tdescs to be removed I
think, as well as the remote_target* inside threads_listing_context.

> +
> +  /* Get the target description corresponding to remote protocol ID.  */
> +  const target_desc *get_tdesc (ULONGEST id) const;
> +
> +  /* Get the target descriptions we don't know about from the target.  */
> +  void fetch_unknown_tdescs (remote_target *remote);
> +
>  public: /* data */
>  
>    /* A buffer to use for incoming packets, and its current size.  The
> @@ -387,6 +398,10 @@ class remote_state
>       support multi-process.  */
>    std::unordered_map<struct gdbarch *, remote_arch_state>
>      m_arch_states;
> +
> +  /* The target descriptions that have been received from the target.  The key
> +     is the ID used to reference it in the remote protocol.  */
> +  std::unordered_map<ULONGEST, const target_desc *> m_tdescs;

Who owns the objects pointed too by this data structure?  From my
reading of the code I suspect they are owned by the remote_state, in
which case we should possibly be deleting the objects in
remote_state::~remote_state.

The only problem with this would be, what happens to any threads that
reference a target description within a remote connection that is close,
and thus the referenced target description is deleted....

... having just run a test it appears that when we disconnect from a
remote target, the remote target itself (and the associated
remote_state) is deleted first, and then we delete the threads of
inferiors running on that target.  That means that if we did delete the
target descriptions in ~remote_state, then we would, for a time, be in a
situation where the thread_info referenced a deleted target description.

I'm not sure how easy that would be to fix, maybe we can just add some
code in remote_unpush_target before the call to
inferior::pop_all_targets_at_and_above?

Anyway, I think the first attempt should be to make the m_tdescs data
structure be:

  std::unordered_map<ULONGEST, std::unique_ptr<const target_desc>> m_tdescs;

>  };
>  
>  static const target_info remote_target_info = {
> @@ -1009,6 +1024,9 @@ struct stop_reply : public notif_event
>       fetch them is avoided).  */
>    std::vector<cached_reg_t> regcache;
>  
> +  /* The target description ID communicated in the stop reply packet.  */
> +  gdb::optional<ULONGEST> tdesc_id;
> +
>    enum target_stop_reason stop_reason;
>  
>    CORE_ADDR watch_data_address;
> @@ -3689,6 +3707,9 @@ struct thread_item
>  
>    /* The thread handle associated with the thread.  */
>    gdb::byte_vector thread_handle;
> +
> +  /* The ID of the thread's target description, if provided.  */
> +  gdb::optional<ULONGEST> tdesc_id;
>  };
>  
>  /* Context passed around to the various methods listing remote
> @@ -3697,6 +3718,12 @@ struct thread_item
>  
>  struct threads_listing_context
>  {
> +  threads_listing_context (remote_target *remote)
> +    : m_remote (remote)
> +  {}
> +
> +  DISABLE_COPY_AND_ASSIGN (threads_listing_context);
> +
>    /* Return true if this object contains an entry for a thread with ptid
>       PTID.  */
>  
> @@ -3733,6 +3760,9 @@ struct threads_listing_context
>  
>    /* The threads found on the remote target.  */
>    std::vector<thread_item> items;
> +
> +  /* The remote target associated with this context.  */
> +  remote_target *m_remote;

The GDB style reserves the 'm_' prefix for private member variables.
Ideally I'd prefer m_remote be made private, and then add a 'remote()'
member function to return the pointer.  Though if my comment above is
correct then I think this new field could be dropped.

>  };
>  
>  static int
> @@ -3814,6 +3844,13 @@ start_thread (struct gdb_xml_parser *parser,
>    attr = xml_find_attribute (attributes, "handle");
>    if (attr != NULL)
>      item.thread_handle = hex2bin ((const char *) attr->value.get ());
> +
> +  attr = xml_find_attribute (attributes, "tdesc");
> +  if (attr != NULL)

s/NULL/nullptr/

> +    {
> +      item.tdesc_id = *(ULONGEST *) attr->value.get ();
> +      data->m_remote->get_remote_state ()->add_tdesc_id (*item.tdesc_id);
> +    }
>  }
>  
>  static void
> @@ -3833,6 +3870,7 @@ const struct gdb_xml_attribute thread_attributes[] = {
>    { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
>    { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
>    { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL },
> +  { "tdesc", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },

Ideally s/NULL/nullptr/ here too, but this one's clearly a bit odd as
we're in a table surrounded by legacy code.  But I think I'd still use
nullptr in preference.

Thanks,
Andrew

>    { NULL, GDB_XML_AF_NONE, NULL, NULL }
>  };
>  
> @@ -3870,6 +3908,7 @@ remote_target::remote_get_threads_with_qxfer (threads_listing_context *context)
>  	{
>  	  gdb_xml_parse_quick (_("threads"), "threads.dtd",
>  			       threads_elements, xml->data (), context);
> +	  get_remote_state ()->fetch_unknown_tdescs (this);
>  	}
>  
>        return 1;
> @@ -3937,7 +3976,7 @@ has_single_non_exited_thread (inferior *inf)
>  void
>  remote_target::update_thread_list ()
>  {
> -  struct threads_listing_context context;
> +  struct threads_listing_context context (this);
>    int got_list = 0;
>  
>    /* We have a few different mechanisms to fetch the thread list.  Try
> @@ -7223,7 +7262,11 @@ remote_notif_stop_parse (remote_target *remote,
>  			 struct notif_client *self, const char *buf,
>  			 struct notif_event *event)
>  {
> -  remote->remote_parse_stop_reply (buf, (struct stop_reply *) event);
> +  struct stop_reply *stop_reply = (struct stop_reply *) event;
> +
> +  remote->remote_parse_stop_reply (buf, stop_reply);
> +
> +  stop_reply->rs->fetch_unknown_tdescs (remote);
>  }
>  
>  static void
> @@ -7516,6 +7559,36 @@ strprefix (const char *p, const char *pend, const char *prefix)
>    return *prefix == '\0';
>  }
>  
> +void
> +remote_state::add_tdesc_id (ULONGEST id)
> +{
> +  /* Check whether the ID was already added.  */
> +  if (m_tdescs.find (id) != m_tdescs.cend ())
> +    return;
> +
> +  m_tdescs[id] = nullptr;
> +}
> +
> +const target_desc *
> +remote_state::get_tdesc (ULONGEST id) const
> +{
> +  auto found = m_tdescs.find (id);
> +
> +  /* Check if the given ID was already provided.  */
> +  if (found == m_tdescs.cend ())
> +    return nullptr;
> +
> +  return found->second;
> +}
> +
> +void
> +remote_state::fetch_unknown_tdescs (remote_target *remote)
> +{
> +  for (auto &pair : m_tdescs)
> +    if (pair.second == nullptr)
> +      m_tdescs[pair.first] = target_read_description_xml (remote, pair.first);
> +}
> +
>  /* Parse the stop reply in BUF.  Either the function succeeds, and the
>     result is stored in EVENT, or throws an error.  */
>  
> @@ -7674,6 +7747,14 @@ Packet: '%s'\n"),
>  	      event->ws.set_thread_created ();
>  	      p = strchrnul (p1 + 1, ';');
>  	    }
> +	  else if (strprefix (p, p1, "tdesc"))
> +	    {
> +	      ULONGEST tdesc_id;
> +
> +	      p = unpack_varlen_hex (++p1, &tdesc_id);
> +	      event->rs->add_tdesc_id (tdesc_id);
> +	      event->tdesc_id = tdesc_id;
> +	    }
>  	  else
>  	    {
>  	      ULONGEST pnum;
> diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
> index ba7154c5d56f..302863e12365 100644
> --- a/gdb/xml-tdesc.c
> +++ b/gdb/xml-tdesc.c
> @@ -698,14 +698,13 @@ fetch_available_features_from_target (const char *name, target_ops *ops)
>  }
>  \f
>  
> -/* Read an XML target description using OPS.  Parse it, and return the
> -   parsed description.  */
> +/* Actual implementation of the target_read_description_xml variants.  */
>  
> -const struct target_desc *
> -target_read_description_xml (struct target_ops *ops)
> +static const struct target_desc *
> +target_read_description_xml (struct target_ops *ops, const char *desc_name)
>  {
>    gdb::optional<gdb::char_vector> tdesc_str
> -    = fetch_available_features_from_target ("target.xml", ops);
> +    = fetch_available_features_from_target (desc_name, ops);
>    if (!tdesc_str)
>      return NULL;
>  
> @@ -717,6 +716,24 @@ target_read_description_xml (struct target_ops *ops)
>    return tdesc_parse_xml (tdesc_str->data (), fetch_another);
>  }
>  
> +/* See xml-tdesc.h.  */
> +
> +const struct target_desc *
> +target_read_description_xml (struct target_ops *ops)
> +{
> +  return target_read_description_xml (ops, "target.xml");
> +}
> +
> +/* See xml-tdesc.h.  */
> +
> +const struct target_desc *
> +target_read_description_xml (struct target_ops *ops, ULONGEST id)
> +{
> +  std::string desc_name = string_printf ("target-id-%" PRIu64 ".xml", id);
> +
> +  return target_read_description_xml (ops, desc_name.c_str ());
> +}
> +
>  /* Fetches an XML target description using OPS,  processing
>     includes, but not parsing it.  Used to dump whole tdesc
>     as a single XML file.  */
> diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h
> index 0fbfc7e043e9..c7cc97c5dfc0 100644
> --- a/gdb/xml-tdesc.h
> +++ b/gdb/xml-tdesc.h
> @@ -38,6 +38,12 @@ const struct target_desc *file_read_description_xml (const char *filename);
>  
>  const struct target_desc *target_read_description_xml (struct target_ops *);
>  
> +/* Read an XML target description with the given ID using OPS.  Parse it, and
> +   return the parsed description.  */
> +
> +const struct target_desc *target_read_description_xml (struct target_ops *ops,
> +						       ULONGEST id);
> +
>  /* Fetches an XML target description using OPS, processing includes,
>     but not parsing it.  Used to dump whole tdesc as a single XML file.
>     Returns the description on success, and a disengaged optional


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
                     ` (2 preceding siblings ...)
  2023-02-01 12:07   ` Andrew Burgess
@ 2023-02-01 14:51   ` Andrew Burgess
  2023-02-01 17:03     ` Simon Marchi
  3 siblings, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 14:51 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> Now that an inferior thread can have a different target description than
> its process, there needs to be a way to communicate this target
> description to GDB.  So add the concept of a target description ID to the
> remote protocol, which is used to reference them and allows them to be
> transferred only once over the wire.
>
> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
> unsigned integer containing the ID.
>
> It is also sent in the threads list XML in the response of a
> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
> the <thread> node.
>
> To request the target description XML of a given ID, GDB sends the
> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
> is the target description ID.
>
> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdb/doc/gdb.texinfo       | 27 ++++++++++++++++---
>  gdbserver/remote-utils.cc | 57 +++++++++++++++++++++++++++++++++++++++
>  gdbserver/remote-utils.h  |  9 +++++++
>  gdbserver/server.cc       | 17 ++++++++++--
>  gdbserver/server.h        |  4 +++
>  5 files changed, 109 insertions(+), 5 deletions(-)
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 9c0018ea5c14..fbf7e59853b5 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -42030,6 +42030,10 @@ the stopped thread, as specified in @ref{thread-id syntax}.
>  If @var{n} is @samp{core}, then @var{r} is the hexadecimal number of
>  the core on which the stop event was detected.
>  
> +@item
> +If @var{n} is @samp{tdesc}, then @var{r} is the hexadecimal number of
> +the target description ID (@pxref{Target Description ID}).
> +
>  @item
>  If @var{n} is a recognized @dfn{stop reason}, it describes a more
>  specific event that stopped the target.  The currently defined stop
> @@ -46546,7 +46550,7 @@ the following structure:
>  @smallexample
>  <?xml version="1.0"?>
>  <threads>
> -    <thread id="id" core="0" name="name">
> +    <thread id="id" core="0" name="name" tdesc="0">
>      ... description ...
>      </thread>
>  </threads>
> @@ -46556,8 +46560,10 @@ Each @samp{thread} element must have the @samp{id} attribute that
>  identifies the thread (@pxref{thread-id syntax}).  The
>  @samp{core} attribute, if present, specifies which processor core
>  the thread was last executing on.  The @samp{name} attribute, if
> -present, specifies the human-readable name of the thread.  The content
> -of the of @samp{thread} element is interpreted as human-readable
> +present, specifies the human-readable name of the thread.  The
> +@samp{tdesc} attribute, if present, specifies the target description
> +ID of the thread (@pxref{Target Description ID}).  The content of
> +the @samp{thread} element is interpreted as human-readable
>  auxiliary information.  The @samp{handle} attribute, if present,
>  is a hex encoded representation of the thread handle.
>  
> @@ -46767,6 +46773,8 @@ descriptions are accurate, and that @value{GDBN} understands them.
>  target descriptions.  @xref{Expat}.
>  
>  @menu
> +* Target Description ID::           Referencing different descriptions in the
> +                                    remote protocol.
>  * Retrieving Descriptions::         How descriptions are fetched from a target.
>  * Target Description Format::       The contents of a target description.
>  * Predefined Target Types::         Standard types available for target
> @@ -46775,6 +46783,14 @@ target descriptions.  @xref{Expat}.
>  * Standard Target Features::        Features @value{GDBN} knows about.
>  @end menu
>  
> +@node Target Description ID
> +@section Target Description ID
> +
> +In cases where a remote target supports threads having different
> +target descriptions than their parent process, the remote protocol
> +assigns a non-negative integer to each target description to reference
> +it in the communication between the host and the target.

Having read some of the later patches, I have some additional thoughts
here:

I think we should make it explicit here that IDs are connection wide,
not per-process.  We should also make it clear that GDB might[1] cache
target descriptions per remote connection, and so a remote target should
not reuse a target description ID except where the target description is
identical.

[1] I say "GDB might" here because if we say "GDB will" then this would
imply each target description will only be asked for once.  And I
figure, why be overly restrictive.


Thanks,
Andrew


> +
>  @node Retrieving Descriptions
>  @section Retrieving Descriptions
>  
> @@ -46787,6 +46803,11 @@ qXfer}).  The @var{annex} in the @samp{qXfer} packet will be
>  XML document, of the form described in @ref{Target Description
>  Format}.
>  
> +If target description IDs are being used (@pxref{Target Description ID}),
> +@value{GDBN} can retrieve a target description with a given ID by using
> +@samp{target-id-ID.xml} as the @var{annex}, where @var{ID} is the
> +non-negative integer identifier of the desired target description.
> +
>  Alternatively, you can specify a file to read for the target description.
>  If a file is set, the target will not be queried.  The commands to
>  specify a file are:
> diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
> index 80310bc2c709..baff899307cc 100644
> --- a/gdbserver/remote-utils.cc
> +++ b/gdbserver/remote-utils.cc
> @@ -1049,6 +1049,53 @@ outreg (struct regcache *regcache, int regno, char *buf)
>    return buf;
>  }
>  
> +/* See remote-utils.h.  */
> +
> +unsigned int
> +get_tdesc_rsp_id (const target_desc *tdesc)
> +{
> +  client_state &cs = get_client_state ();
> +  unsigned int i;
> +
> +  for (i = 0; i < cs.tdescs.size (); i++)
> +    if (cs.tdescs[i] == tdesc)
> +      return i;
> +
> +  cs.tdescs.push_back (tdesc);
> +
> +  return i;
> +}
> +
> +/* See remote-utils.h.  */
> +
> +const target_desc *
> +get_tdesc_from_rsp_id (unsigned int id)
> +{
> +  client_state &cs = get_client_state ();
> +
> +  if (id >= cs.tdescs.size ())
> +    return nullptr;
> +
> +  return cs.tdescs[id];
> +}
> +
> +/* Return the ID as used in the remote protocol for the target descriptor of the
> +   given PTID.  */
> +
> +static unsigned int
> +get_tdesc_rsp_id (ptid_t ptid)
> +{
> +  const thread_info *thread = find_thread_ptid (ptid);
> +  const target_desc *tdesc;
> +
> +  if (thread == nullptr)
> +    tdesc = find_process_pid (ptid.pid ())->tdesc;
> +  else
> +    tdesc = get_thread_target_desc (thread);
> +
> +  return get_tdesc_rsp_id (tdesc);
> +}
> +
>  void
>  prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>  {
> @@ -1241,6 +1288,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
>  	    buf += strlen (buf);
>  	    current_process ()->dlls_changed = false;
>  	  }
> +
> +	if (current_thread->tdesc != nullptr
> +	    && current_thread->tdesc != current_process ()->tdesc)
> +	  {
> +	    sprintf (buf, "tdesc:");
> +	    buf += strlen (buf);
> +	    sprintf (buf, "%x", get_tdesc_rsp_id (ptid));
> +	    strcat (buf, ";");
> +	    buf += strlen (buf);
> +	  }
>        }
>        break;
>      case TARGET_WAITKIND_EXITED:
> diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h
> index cb2d6c346c99..61ef80b4dad7 100644
> --- a/gdbserver/remote-utils.h
> +++ b/gdbserver/remote-utils.h
> @@ -75,4 +75,13 @@ int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc);
>  
>  void monitor_output (const char *msg);
>  
> +/* Return the ID as used in the remote protocol for the given target
> +   descriptor.  */
> +
> +unsigned int get_tdesc_rsp_id (const target_desc *tdesc);
> +
> +/* Return the target description corresponding to the remote protocol ID.  */
> +
> +const target_desc *get_tdesc_from_rsp_id (unsigned int id);
> +
>  #endif /* GDBSERVER_REMOTE_UTILS_H */
> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index 21fb51a45d16..2d1062f98468 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -976,7 +976,15 @@ handle_general_set (char *own_buf)
>  static const char *
>  get_features_xml (const char *annex)
>  {
> -  const struct target_desc *desc = current_target_desc ();
> +  const struct target_desc *desc;
> +  unsigned int id;
> +
> +  if (strcmp (annex, "target.xml") == 0)
> +    desc = current_target_desc ();
> +  else if (sscanf (annex, "target-id-%u.xml", &id) == 1)
> +    desc = get_tdesc_from_rsp_id (id);
> +  else
> +    desc = nullptr;
>  
>    /* `desc->xmltarget' defines what to return when looking for the
>       "target.xml" file.  Its contents can either be verbatim XML code
> @@ -986,7 +994,7 @@ get_features_xml (const char *annex)
>       This variable is set up from the auto-generated
>       init_registers_... routine for the current target.  */
>  
> -  if (strcmp (annex, "target.xml") == 0)
> +  if (desc != nullptr)
>      {
>        const char *ret = tdesc_get_features_xml (desc);
>  
> @@ -1664,6 +1672,11 @@ handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
>    if (name != NULL)
>      buffer_xml_printf (buffer, " name=\"%s\"", name);
>  
> +  if (thread->tdesc != nullptr
> +      && thread->tdesc != get_thread_process (thread)->tdesc)
> +    buffer_xml_printf (buffer, " tdesc=\"%u\"",
> +		       get_tdesc_rsp_id (thread->tdesc));
> +
>    if (handle_status)
>      {
>        char *handle_s = (char *) alloca (handle_len * 2 + 1);
> diff --git a/gdbserver/server.h b/gdbserver/server.h
> index 7997d1a32e6e..58be5027795b 100644
> --- a/gdbserver/server.h
> +++ b/gdbserver/server.h
> @@ -193,6 +193,10 @@ struct client_state
>    /* If true, memory tagging features are supported.  */
>    bool memory_tagging_feature = false;
>  
> +  /* The target descriptions that have been communicated to the client.  The
> +     index of a target description in this vector is the ID used to reference it
> +     in the remote protocol.  */
> +  std::vector<const target_desc *> tdescs;
>  };
>  
>  client_state &get_client_state ();


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-01-30  4:45 ` [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely Thiago Jung Bauermann
  2023-02-01  9:58   ` Luis Machado
@ 2023-02-01 15:26   ` Andrew Burgess
  2023-02-01 20:20     ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-01 15:26 UTC (permalink / raw)
  To: Thiago Jung Bauermann via Gdb-patches, gdb-patches; +Cc: Thiago Jung Bauermann

Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
writes:

> If the remote target provides target description IDs in their threads
> list and stop reply packets, use them to update the thread's gdbarch.
> This allows debugging programs remotely that change their SVE vector
> length during runtime.
>
> GDB already supports different vector lengths in native debugging by
> calling target_ops::thread_architecture, and aarch64_linux_nat_target
> provides an implementation of that method.
>
> So to provide the same feature in remote debugging, implement the
> thread_architecture method in remote_target, so that the same
> mechanism can be used for both the native and remote cases.  This
> method returns the gdbarch corresponding to the target description
> provided by the last threads list or stop reply packet.
>
> To allow changing the architecture based on the target description,
> add a new gdbarch method to allow arch-specific code to make the
> adjustment.

It doesn't seem right to me that the method to lookup a new gdbarch is
itself, a member function of gdbarch.   Looking at the implementation,
I'm still puzzled, I'll expand on this inline below...

> ---
>  gdb/aarch64-tdep.c        | 20 ++++++++++
>  gdb/arch-utils.c          |  8 ++++
>  gdb/arch-utils.h          |  4 ++
>  gdb/gdbarch-components.py | 15 +++++++
>  gdb/gdbarch-gen.h         | 10 +++++
>  gdb/gdbarch.c             | 22 ++++++++++
>  gdb/remote.c              | 84 +++++++++++++++++++++++++++++++++++++++
>  7 files changed, 163 insertions(+)
>
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index b576d3b9d99f..1e6e7116ed8a 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3502,6 +3502,25 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
>  	  || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
>  }
>  
> +/* Implement the "update_architecture" gdbarch method.  */
> +
> +static struct gdbarch *
> +aarch64_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  /* If this is a 32-bit architecture, then this is ARM, not AArch64.
> +     There are no SVE registers here, so just return the inferior
> +     architecture.  */
> +  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
> +    return gdbarch;

OK, this bit is AArch64 specific.  But do we actually expect this case
to trigger?  If the remote is running ARM (so bit_per_word == 32), the
surely we wouldn't be sending different target description ids, and so
we wouldn't end up in here?

And if, in some future (imaginary?) world there is some reason why we
want different architecture for different ARM threads, then does the
lookup below actually hurt?

> +
> +  struct gdbarch_info info;
> +
> +  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);

Instead of hard-coding bfd_arch_aarch64 and bfd_mach_aarch64, could you
not use tdesc_architecture to get a bfd_arch_info?

I guess the point I'm driving towards is that maybe instead of a new
gdbarch method we should add something like gdbarch_from_tdesc into
arch-utils.c (like we have gdbarch_from_bfd and gdbarch_find_by_info),
which just does a lookup from tdesc.

Thanks,
Andrew


> +  info.target_desc = tdesc;
> +
> +  return gdbarch_find_by_info (info);
> +}
> +
>  /* Implement the stack_frame_destroyed_p gdbarch method.  */
>  
>  static int
> @@ -3748,6 +3767,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>    set_tdesc_pseudo_register_reggroup_p (gdbarch,
>  					aarch64_pseudo_register_reggroup_p);
>    set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
> +  set_gdbarch_update_architecture (gdbarch, aarch64_update_architecture);
>  
>    /* ABI */
>    set_gdbarch_short_bit (gdbarch, 16);
> diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
> index 67968126488e..e8ad0aed6eb4 100644
> --- a/gdb/arch-utils.c
> +++ b/gdb/arch-utils.c
> @@ -1098,6 +1098,14 @@ default_get_return_buf_addr (struct type *val_type, frame_info_ptr cur_frame)
>    return 0;
>  }
>  
> +/* See arch-utils.h.  */
> +
> +struct gdbarch *
> +default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  return gdbarch;
> +}
> +
>  /* Non-zero if we want to trace architecture code.  */
>  
>  #ifndef GDBARCH_DEBUG
> diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
> index 56690f0fd435..aeee7f51ad49 100644
> --- a/gdb/arch-utils.h
> +++ b/gdb/arch-utils.h
> @@ -314,4 +314,8 @@ extern enum return_value_convention default_gdbarch_return_value
>        struct regcache *regcache, struct value **read_value,
>        const gdb_byte *writebuf);
>  
> +/* Default implementation of gdbarch update_architecture method.  */

I think we could give a better comment here; say what the default
behaviour actually is.

> +extern struct gdbarch *
> +default_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);

The GDB style here is to place the function name on the same line as the
return value, and then place the parameter list on the second line.
Check out default_gdbarch_return_value just above for an example.

> +
>  #endif /* ARCH_UTILS_H */
> diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py
> index 76ad2832d8a2..68b7521c9966 100644
> --- a/gdb/gdbarch-components.py
> +++ b/gdb/gdbarch-components.py
> @@ -2744,3 +2744,18 @@ Read core file mappings
>      predefault="default_read_core_file_mappings",
>      invalid=False,
>  )
> +
> +Method(
> +    comment="""
> +An architecture may change while the inferior is running.  For instance, the
> +length of the vector registers in AArch64's Scalable Vector Extension is given
> +by the contents of the VG pseudo-register.
> +
> +Return a gdbarch corresponding to the given target description.
> +""",
> +    type="struct gdbarch *",
> +    name="update_architecture",
> +    params=[("const target_desc *", "tdesc")],
> +    predefault="default_update_architecture",
> +    invalid=False,
> +)
> diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
> index 32b2d96fbe01..d6068c2bc24f 100644
> --- a/gdb/gdbarch-gen.h
> +++ b/gdb/gdbarch-gen.h
> @@ -1672,3 +1672,13 @@ extern void set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, gdbarch_g
>  typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
>  extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
>  extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
> +
> +/* An architecture may change while the inferior is running.  For instance, the
> +   length of the vector registers in AArch64's Scalable Vector Extension is given
> +   by the contents of the VG pseudo-register.
> +
> +   Return a gdbarch corresponding to the given target description. */
> +
> +typedef struct gdbarch * (gdbarch_update_architecture_ftype) (struct gdbarch *gdbarch, const target_desc *tdesc);
> +extern struct gdbarch * gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc);
> +extern void set_gdbarch_update_architecture (struct gdbarch *gdbarch, gdbarch_update_architecture_ftype *update_architecture);
> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
> index 46baca9c4793..07d3e060fe1f 100644
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -256,6 +256,7 @@ struct gdbarch
>    gdbarch_type_align_ftype *type_align = default_type_align;
>    gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags;
>    gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
> +  gdbarch_update_architecture_ftype *update_architecture = default_update_architecture;
>  };
>  
>  /* Create a new ``struct gdbarch'' based on information provided by
> @@ -517,6 +518,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of type_align, invalid_p == 0 */
>    /* Skip verify of get_pc_address_flags, invalid_p == 0 */
>    /* Skip verify of read_core_file_mappings, invalid_p == 0 */
> +  /* Skip verify of update_architecture, invalid_p == 0 */
>    if (!log.empty ())
>      internal_error (_("verify_gdbarch: the following are invalid ...%s"),
>  		    log.c_str ());
> @@ -1355,6 +1357,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
>    gdb_printf (file,
>  	      "gdbarch_dump: read_core_file_mappings = <%s>\n",
>  	      host_address_to_string (gdbarch->read_core_file_mappings));
> +  gdb_printf (file,
> +	      "gdbarch_dump: update_architecture = <%s>\n",
> +	      host_address_to_string (gdbarch->update_architecture));
>    if (gdbarch->dump_tdep != NULL)
>      gdbarch->dump_tdep (gdbarch, file);
>  }
> @@ -5317,3 +5322,20 @@ set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch,
>  {
>    gdbarch->read_core_file_mappings = read_core_file_mappings;
>  }
> +
> +struct gdbarch *
> +gdbarch_update_architecture (struct gdbarch *gdbarch, const target_desc *tdesc)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->update_architecture != NULL);
> +  if (gdbarch_debug >= 2)
> +    gdb_printf (gdb_stdlog, "gdbarch_update_architecture called\n");
> +  return gdbarch->update_architecture (gdbarch, tdesc);
> +}
> +
> +void
> +set_gdbarch_update_architecture (struct gdbarch *gdbarch,
> +				 gdbarch_update_architecture_ftype update_architecture)
> +{
> +  gdbarch->update_architecture = update_architecture;
> +}
> diff --git a/gdb/remote.c b/gdb/remote.c
> index f1d1944414c3..a17d65220408 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -506,6 +506,8 @@ class remote_target : public process_stratum_target
>    gdb::byte_vector thread_info_to_thread_handle (struct thread_info *tp)
>  						 override;
>  
> +  struct gdbarch *thread_architecture (ptid_t ptid) override;
> +
>    void stop (ptid_t) override;
>  
>    void interrupt () override;
> @@ -1168,6 +1170,10 @@ struct remote_thread_info : public private_thread_info
>       to stop for a watchpoint.  */
>    CORE_ADDR watch_data_address = 0;
>  
> +  /* The architecture corresponding to the target description returned
> +     in the last stop reply or threads list.  */
> +  struct gdbarch *arch = nullptr;
> +
>    /* Get the thread's resume state.  */
>    enum resume_state get_resume_state () const
>    {
> @@ -1186,6 +1192,8 @@ struct remote_thread_info : public private_thread_info
>      m_resume_state = resume_state::RESUMED_PENDING_VCONT;
>      m_resumed_pending_vcont_info.step = step;
>      m_resumed_pending_vcont_info.sig = sig;
> +
> +    arch = nullptr;
>    }
>  
>    /* Get the information this thread's pending vCont-resumption.
> @@ -1203,6 +1211,8 @@ struct remote_thread_info : public private_thread_info
>    void set_resumed ()
>    {
>      m_resume_state = resume_state::RESUMED;
> +
> +    arch = nullptr;
>    }
>  
>  private:
> @@ -4046,6 +4056,29 @@ remote_target::update_thread_list ()
>  	      info->extra = std::move (item.extra);
>  	      info->name = std::move (item.name);
>  	      info->thread_handle = std::move (item.thread_handle);
> +
> +	      /* If the threads list indicated a target description for this
> +		 thread, add it to the thread information.  */
> +	      if (item.tdesc_id)
> +		{
> +		  const target_desc *tdesc
> +		      = get_remote_state ()->get_tdesc (*item.tdesc_id);
> +
> +		  gdb_assert (tdesc != nullptr);
> +
> +		  /* If there's no thread-specific gdbarch, use the one from the
> +		     whole inferior.  */
> +		  if (info->arch == nullptr)
> +		    info->arch = tp->inf->gdbarch;
> +
> +		  gdbarch *new_arch = gdbarch_update_architecture (info->arch,
> +								   tdesc);
> +		  if (new_arch != info->arch)
> +		    {
> +		      registers_changed_thread (tp);
> +		      info->arch = new_arch;
> +		    }
> +		}
>  	    }
>  	}
>      }
> @@ -8152,6 +8185,36 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
>        && status->kind () != TARGET_WAITKIND_SIGNALLED
>        && status->kind () != TARGET_WAITKIND_NO_RESUMED)
>      {
> +      thread_info *thr = find_thread_ptid (this, ptid);
> +
> +      /* If GDB already knows about this thread, we can give the
> +	 architecture-specific code a chance to update the gdbarch based on the
> +	 provided target description.  */
> +      if (stop_reply->tdesc_id && thr != nullptr)
> +	{
> +	  const target_desc *tdesc
> +	      = stop_reply->rs->get_tdesc (*stop_reply->tdesc_id);
> +
> +	  gdb_assert (tdesc != nullptr);
> +
> +	  /* If there's no gdbarch associated with the stop reply, use the one
> +	     from the whole inferior.  */
> +	  if (stop_reply->arch == nullptr)
> +	    stop_reply->arch = thr->inf->gdbarch;
> +
> +	  stop_reply->arch = gdbarch_update_architecture (stop_reply->arch,
> +							  tdesc);
> +
> +	  /* Save stop_reply->arch so that it can be returned by the
> +	     thread_architecture method.  */
> +	  remote_thread_info *remote_thr = get_remote_thread_info (thr);
> +	  if (remote_thr->arch != stop_reply->arch)
> +	    {
> +	      registers_changed_thread (thr);
> +	      remote_thr->arch = stop_reply->arch;
> +	    }
> +	}
> +
>        /* Expedited registers.  */
>        if (!stop_reply->regcache.empty ())
>  	{
> @@ -14469,6 +14532,27 @@ remote_target::thread_info_to_thread_handle (struct thread_info *tp)
>    return priv->thread_handle;
>  }
>  
> +/* Implementation of the thread_architecture method for the remote target.  */
> +
> +struct gdbarch *
> +remote_target::thread_architecture (ptid_t ptid)
> +{
> +  thread_info *thr = find_thread_ptid (this, ptid);
> +  remote_thread_info *remote_thr;
> +
> +  if (thr == nullptr)
> +    remote_thr = nullptr;
> +  else
> +    remote_thr = get_remote_thread_info (thr);
> +
> +  if (remote_thr == nullptr || remote_thr->arch == nullptr)
> +    /* The default thread_architecture implementation is the one from
> +       process_stratum_target.  */
> +    return process_stratum_target::thread_architecture (ptid);
> +
> +  return remote_thr->arch;
> +}
> +
>  bool
>  remote_target::can_async_p ()
>  {


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number
  2023-01-31 19:49     ` Thiago Jung Bauermann
@ 2023-02-01 15:43       ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 15:43 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Simon Marchi; +Cc: gdb-patches



On 1/31/23 14:49, Thiago Jung Bauermann via Gdb-patches wrote:
> 
> Hello Simon,
> 
> Simon Marchi <simon.marchi@efficios.com> writes:
> 
>> On 1/29/23 23:45, Thiago Jung Bauermann wrote:
>>> It helped me during development, catching bugs closer to when they actually
>>> happened.
>>>
>>> Also remove the equivalent gdb_assert in regcache_raw_read_unsigned, since
>>> it's checking the same condition a few frames above.
>>>
>>> Suggested-By: Simon Marchi <simon.marchi@efficios.com>
>>> ---
>>>  gdbserver/regcache.cc | 4 ++--
>>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
>>> index 3aeefcc79a37..7b896a19767d 100644
>>> --- a/gdbserver/regcache.cc
>>> +++ b/gdbserver/regcache.cc
>>> @@ -199,6 +199,8 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
>>>  static const struct gdb::reg &
>>>  find_register_by_number (const struct target_desc *tdesc, int n)
>>>  {
>>> +  gdb_assert (n >= 0 && n < tdesc->reg_defs.size ());
>>
>> Since you're moving this assertion, I would suggest breaking it up in
>> two.  I general, I suggest avoiding multiple checks in a single
>> gdb_assert.  It makes it a little less obvious from the crash report
>> which condition failed exactly.  So:
>>
>>   gdb_assert (n >= 0);
>>   gdb_assert (n < tdesc->reg_defs.size ());
> 
> Good point. I made this change.
> 
>> The patch is fine to push right away in any case, it's good
>> independently from the rest of the series:
> 
> Indeed. I will do that. Is it OK if I push patch 2 as well? You approved
> it in v2, and the only changes in v3 are to implement your review
> comments.

Probably, I will take a look (Andrew has left a comment already though).

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-01 10:54   ` Andrew Burgess
@ 2023-02-01 16:01     ` Simon Marchi
  2023-02-01 19:33       ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 16:01 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

>> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>>     *VALP and return 1.  If not found or if there is an error, return
>>     0.  */
>>  
>> -int linux_get_auxv (int wordsize, CORE_ADDR match,
>> -		    CORE_ADDR *valp);
>> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>>  
>>  /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>>     WORDSIZE.  If no entry was found, return zero.  */
>>  
>> -CORE_ADDR linux_get_hwcap (int wordsize);
>> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>>  
>>  /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>>     WORDSIZE.  If no entry was found, return zero.  */
>>  
>> -CORE_ADDR linux_get_hwcap2 (int wordsize);
>> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
> 
> Ideally the comment for these three functions would be updated to
> mention the PID argument.
I think the patch is OK to push after addressing this comment.

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features
  2023-02-01  8:59   ` Luis Machado
@ 2023-02-01 16:04     ` Simon Marchi
  2023-02-01 22:13       ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 16:04 UTC (permalink / raw)
  To: Luis Machado, Thiago Jung Bauermann, gdb-patches; +Cc: Simon Marchi

> Still LGTM.
Still LGTM too.

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-01 11:06   ` Andrew Burgess
@ 2023-02-01 16:21     ` Simon Marchi
  2023-02-01 16:32       ` Luis Machado
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 16:21 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann, Luis Machado


>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>> index 221de85aa2ee..b52eb23cc444 100644
>> --- a/gdbserver/linux-low.h
>> +++ b/gdbserver/linux-low.h
>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>    /* Architecture-specific setup for the current thread.  */
>>    virtual void low_arch_setup () = 0;
>>  
>> +  /* Allows arch-specific code to set the thread's target description when the
>> +     inferior stops.  Returns nullptr if no thread-specific target description
>> +     is necessary.  */
>> +  virtual const struct target_desc *
>> +    get_thread_tdesc (const thread_info *thread);
> 
> I think the comment for this function is not correct.  The function does
> not SET the thread's target description, but just GETS a target
> description suitable for `thread`.  It's the caller's job to do the
> setting.

This comment also gave me pause.  How does a getter set something.  I
then understood that it allowed the arch-specific code to provide a
thread-specific tdesc.  I would suggest just:

  /* Return a target description for THREAD.

     Return nullptr if no thread-specific description is necessary.  */

The other thought I had while re-reading the patch is why do we need to
return and store nullptr if the thread target description is the same as
the main one for the process.  get_thread_tdesc could just return
process_info->tdesc if we don't need a separate tdesc, and we would
store that same pointer in thread_info->tdesc.  And get_thread_tdesc
would just return that (in fact, get_thread_tdesc might not be necessary
then).  Perhaps it makes some things more complicated down the road, but
I can't think of anything.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-01 16:21     ` Simon Marchi
@ 2023-02-01 16:32       ` Luis Machado
  2023-02-02  2:54         ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-01 16:32 UTC (permalink / raw)
  To: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

On 2/1/23 16:21, Simon Marchi wrote:
> 
>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>> index 221de85aa2ee..b52eb23cc444 100644
>>> --- a/gdbserver/linux-low.h
>>> +++ b/gdbserver/linux-low.h
>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>     /* Architecture-specific setup for the current thread.  */
>>>     virtual void low_arch_setup () = 0;
>>>   
>>> +  /* Allows arch-specific code to set the thread's target description when the
>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>> +     is necessary.  */
>>> +  virtual const struct target_desc *
>>> +    get_thread_tdesc (const thread_info *thread);
>>
>> I think the comment for this function is not correct.  The function does
>> not SET the thread's target description, but just GETS a target
>> description suitable for `thread`.  It's the caller's job to do the
>> setting.
> 
> This comment also gave me pause.  How does a getter set something.  I
> then understood that it allowed the arch-specific code to provide a
> thread-specific tdesc.  I would suggest just:

FWIW, I read it as "the functions *allows* arch-specific code to set". So it doesn't set on its own, but it does allow something else to do it.

> 
>    /* Return a target description for THREAD.
> 
>       Return nullptr if no thread-specific description is necessary.  */
> 
> The other thought I had while re-reading the patch is why do we need to
> return and store nullptr if the thread target description is the same as
> the main one for the process.  get_thread_tdesc could just return
> process_info->tdesc if we don't need a separate tdesc, and we would
> store that same pointer in thread_info->tdesc.  And get_thread_tdesc
> would just return that (in fact, get_thread_tdesc might not be necessary
> then).  Perhaps it makes some things more complicated down the road, but
> I can't think of anything.

Sounds reasonable.

Moving towards thread-specific target descriptions/gdbarch would be a positive thing given the SVE precedent. The process-wide target description/gdbarch no
longer reflects the correct settings for each thread on AArch64's with SVE support.

> 
> Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 14:51   ` Andrew Burgess
@ 2023-02-01 17:03     ` Simon Marchi
  2023-02-02 19:52       ` Thiago Jung Bauermann
  2023-02-03 11:22       ` Luis Machado
  0 siblings, 2 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 17:03 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi


> Having read some of the later patches, I have some additional thoughts
> here:
> 
> I think we should make it explicit here that IDs are connection wide,
> not per-process.  We should also make it clear that GDB might[1] cache
> target descriptions per remote connection, and so a remote target should
> not reuse a target description ID except where the target description is
> identical.
> 
> [1] I say "GDB might" here because if we say "GDB will" then this would
> imply each target description will only be asked for once.  And I
> figure, why be overly restrictive.

Thanks for pointing this out, I had the same thought while reading the
patch.

In my original idea, I imagined that target description IDs could be
some hashes computed from the XML content (a bit like git hashes or ELF
build IDs), such that a given target description would always have the
same ID.  This would give clients the possibility to cache target
descriptions locally, a bit like the index cache.  It did sound nice,
but perhaps it's not really important.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 12:07   ` Andrew Burgess
  2023-02-01 13:03     ` Eli Zaretskii
@ 2023-02-01 17:37     ` Simon Marchi
  2023-02-02 20:36       ` Thiago Jung Bauermann
  2023-02-01 20:46     ` Simon Marchi
  2 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 17:37 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi



On 2/1/23 07:07, Andrew Burgess via Gdb-patches wrote:
> Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
> writes:
> 
>> Now that an inferior thread can have a different target description than
>> its process, there needs to be a way to communicate this target
>> description to GDB.  So add the concept of a target description ID to the
>> remote protocol, which is used to reference them and allows them to be
>> transferred only once over the wire.
>>
>> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
>> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
>> unsigned integer containing the ID.
>>
>> It is also sent in the threads list XML in the response of a
>> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
>> the <thread> node.
>>
>> To request the target description XML of a given ID, GDB sends the
>> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
>> is the target description ID.
> 
> Luis already commented that in some locations the ID is hex, while in
> others it is not explicitly stated if the value is hex or decimal.  I'd
> like to second that feedback, and suggest that we pick one, and use that
> consistently throughout.
> 
> My thinking is that it will be easier to understand remote packet traces
> if target descriptions are requested using an ID in the safe format as
> was sent to GDB, and if IDs in different packets match up.
> 
> Thus, I would suggest we switch to using 'target-id-%x.xml' here, and
> send the ID as hex in the threads reply packet.

Not that I disagree with you, but I just wanted to note that this
decimal / hexadecimal mismatch already exists for the core field.  It's
hex in stop replies, decimal in XML.  The thread id, however, is always
hex (the special thread-id syntax).

Regardless how this new field is formatted, it would be nice to be
explicit about the core field too.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-01 16:01     ` Simon Marchi
@ 2023-02-01 19:33       ` Thiago Jung Bauermann
  2023-02-01 19:53         ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-01 19:33 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Simon Marchi <simon.marchi@efficios.com> writes:

>>> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>>>     *VALP and return 1.  If not found or if there is an error, return
>>>     0.  */
>>>  
>>> -int linux_get_auxv (int wordsize, CORE_ADDR match,
>>> -		    CORE_ADDR *valp);
>>> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>>>  
>>>  /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>  
>>> -CORE_ADDR linux_get_hwcap (int wordsize);
>>> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>>>  
>>>  /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>  
>>> -CORE_ADDR linux_get_hwcap2 (int wordsize);
>>> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
>> 
>> Ideally the comment for these three functions would be updated to
>> mention the PID argument.

This is how I changed the comments. What do you think?

diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 221de85aa2ee..4f95a27808ba 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -941,20 +941,19 @@ bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len);
 
 extern int have_ptrace_getregset;
 
-/* Search for the value with type MATCH in the auxv vector with
-   entries of length WORDSIZE bytes.  If found, store the value in
-   *VALP and return 1.  If not found or if there is an error, return
-   0.  */
+/* Search for the value with type MATCH in the auxv vector, with entries of
+   length WORDSIZE bytes, of process with PID.  If found, store the value
+   in *VALP and return 1.  If not found or if there is an error, return 0.  */
 
 int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
 
 /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
-   WORDSIZE.  If no entry was found, return zero.  */
+   WORDSIZE, of process with PID.  If no entry was found, return zero.  */
 
 CORE_ADDR linux_get_hwcap (int pid, int wordsize);
 
 /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
-   WORDSIZE.  If no entry was found, return zero.  */
+   WORDSIZE, of process with PID.  If no entry was found, return zero.  */
 
 CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
 

> I think the patch is OK to push after addressing this comment.

Thanks!

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-01 14:32   ` Andrew Burgess
@ 2023-02-01 19:50     ` Simon Marchi
  2023-02-01 20:16       ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 19:50 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann



On 2/1/23 09:32, Andrew Burgess via Gdb-patches wrote:
> Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
> writes:
> 
>> gdbserver added the concept of target description IDs to the remote
>> protocol and uses them in the threads list XML and in the 'T AA' stop
>> reply packet.  It also allows fetching a target description with a given
>> ID.  This patch is for the GDB-side support.  The target descriptions
>> obtained this way aren't yet used but will be in the next patch.
>>
>> In the DTD for the threads list XML, add a "tdesc" attribute to the
>> <thread> node.  A tdesc_id field is added to the stop_reply and
>> thread_item structs.  An m_remote member is added to the
>> threads_listing_context struct, and to simplify its initialisation a
>> constructor is added as well.  This is to provide access to the remote
>> state in start_thread.
>>
>> Finally, the remote_state object keeps a map of the target descriptions
>> that have been received from the target, keyed by their ID.  There are
>> also methods to get a target description given its ID, and to fetch target
>> descriptions for IDs that were mentioned by gdbserver but not yet
>> retrieved by GDB.  The latter gets called after parsing the response of
>> qXfer:threads:read and of the stop reply packet.
>> ---
>>  gdb/features/threads.dtd |  1 +
>>  gdb/remote.c             | 85 +++++++++++++++++++++++++++++++++++++++-
>>  gdb/xml-tdesc.c          | 27 ++++++++++---
>>  gdb/xml-tdesc.h          |  6 +++
>>  4 files changed, 112 insertions(+), 7 deletions(-)
>>
>> diff --git a/gdb/features/threads.dtd b/gdb/features/threads.dtd
>> index 036b2ce58837..3102d1352978 100644
>> --- a/gdb/features/threads.dtd
>> +++ b/gdb/features/threads.dtd
>> @@ -11,3 +11,4 @@
>>  
>>  <!ATTLIST thread id CDATA #REQUIRED>
>>  <!ATTLIST thread core CDATA #IMPLIED>
>> +<!ATTLIST thread tdesc CDATA #IMPLIED>
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index 218bca30d047..f1d1944414c3 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -80,6 +80,7 @@
>>  #include <unordered_map>
>>  #include "async-event.h"
>>  #include "gdbsupport/selftest.h"
>> +#include "xml-tdesc.h"
>>  
>>  /* The remote target.  */
>>  
>> @@ -238,6 +239,16 @@ class remote_state
>>    /* Get the remote arch state for GDBARCH.  */
>>    struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
>>  
>> +  /* Add new ID to the target description list.  The corresponding XML will be
>> +     requested soon.  */
>> +  void add_tdesc_id (ULONGEST id);
> 
> I'm wondering why this function is needed?  Could we not just have
> get_tdesc take a remote_target* argument, and fetch the descriptions on
> demand?  This would also allow fetch_unknown_tdescs to be removed I
> think, as well as the remote_target* inside threads_listing_context.

Piggybacking on Andrew's review again, because he said most of what I
noticed.

I had a comment going in a similar direction.  I think the intent of
threads_listing_context to be a "parsed" version of the XML document,
that can then be used by the caller that implements the logic.  So I
would just store the target description id in the thread_item, and
that's it.  update_thread_list can then fetch the missing target
descriptions, probably as Andrew suggested.

> Who owns the objects pointed too by this data structure?  From my
> reading of the code I suspect they are owned by the remote_state, in
> which case we should possibly be deleting the objects in
> remote_state::~remote_state.
> 
> The only problem with this would be, what happens to any threads that
> reference a target description within a remote connection that is close,
> and thus the referenced target description is deleted....
> 
> ... having just run a test it appears that when we disconnect from a
> remote target, the remote target itself (and the associated
> remote_state) is deleted first, and then we delete the threads of
> inferiors running on that target.  That means that if we did delete the
> target descriptions in ~remote_state, then we would, for a time, be in a
> situation where the thread_info referenced a deleted target description.
> 
> I'm not sure how easy that would be to fix, maybe we can just add some
> code in remote_unpush_target before the call to
> inferior::pop_all_targets_at_and_above?

IIUC, the tdescs would be deleted during the
pop_all_targets_at_and_above, when the refcount of the remote_target
gets to 0 and it gets deleted.  And the threads would be removed in
generic_mourn_inferior just after.

An idea could be to call generic_mourn_inferior before
remote_unpush_target (no idea if it works).  Another one would be to
get a temporary reference to the remote_target object in
remote_unpush_target, just so that it outlives the threads.
Or maybe we should say that it's a process target's responsibility to
delete any thread it "owns" before getting deleted itself.

> Anyway, I think the first attempt should be to make the m_tdescs data
> structure be:
> 
>   std::unordered_map<ULONGEST, std::unique_ptr<const target_desc>> m_tdescs;

Note that we have target_desc_up, with a custom deleter.  It's necessary
because struct target_desc is in target-description.c, not the header.
Although I wouldn't mind if we moved the struct to the header and got
rid of the custom deleter.

>> @@ -3833,6 +3870,7 @@ const struct gdb_xml_attribute thread_attributes[] = {
>>    { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
>>    { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
>>    { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL },
>> +  { "tdesc", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
> 
> Ideally s/NULL/nullptr/ here too, but this one's clearly a bit odd as
> we're in a table surrounded by legacy code.  But I think I'd still use
> nullptr in preference.

Also, feel free to submit a patch to change NULL for nullptr in this
whole array.  Or heck, the whole file.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-01 19:33       ` Thiago Jung Bauermann
@ 2023-02-01 19:53         ` Simon Marchi
  2023-02-01 21:55           ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 19:53 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches



On 2/1/23 14:33, Thiago Jung Bauermann via Gdb-patches wrote:
> 
> Simon Marchi <simon.marchi@efficios.com> writes:
> 
>>>> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>>>>     *VALP and return 1.  If not found or if there is an error, return
>>>>     0.  */
>>>>  
>>>> -int linux_get_auxv (int wordsize, CORE_ADDR match,
>>>> -		    CORE_ADDR *valp);
>>>> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>>>>  
>>>>  /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>>  
>>>> -CORE_ADDR linux_get_hwcap (int wordsize);
>>>> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>>>>  
>>>>  /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>>  
>>>> -CORE_ADDR linux_get_hwcap2 (int wordsize);
>>>> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
>>>
>>> Ideally the comment for these three functions would be updated to
>>> mention the PID argument.
> 
> This is how I changed the comments. What do you think?
> 
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index 221de85aa2ee..4f95a27808ba 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -941,20 +941,19 @@ bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len);
>  
>  extern int have_ptrace_getregset;
>  
> -/* Search for the value with type MATCH in the auxv vector with
> -   entries of length WORDSIZE bytes.  If found, store the value in
> -   *VALP and return 1.  If not found or if there is an error, return
> -   0.  */
> +/* Search for the value with type MATCH in the auxv vector, with entries of
> +   length WORDSIZE bytes, of process with PID.  If found, store the value

"of process with PID" sounds weird, syntactically.  I would say "of process with pid
PID" (same in the other comments).  Otherwise, this is OK.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-01 19:50     ` Simon Marchi
@ 2023-02-01 20:16       ` Simon Marchi
  2023-02-03 11:27         ` Luis Machado
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 20:16 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

> IIUC, the tdescs would be deleted during the
> pop_all_targets_at_and_above, when the refcount of the remote_target
> gets to 0 and it gets deleted.  And the threads would be removed in
> generic_mourn_inferior just after.
> 
> An idea could be to call generic_mourn_inferior before
> remote_unpush_target (no idea if it works).  Another one would be to
> get a temporary reference to the remote_target object in
> remote_unpush_target, just so that it outlives the threads.
> Or maybe we should say that it's a process target's responsibility to
> delete any thread it "owns" before getting deleted itself.

Another question related to this popped while reading the following
patch.  When creating a gdbarch from a tdesc, the gdbarch keeps a
pointer to that tdesc (accessible through gdbarch_target_desc).  And
AFAIK, we never delete gdbarches.  So I suppose the gdbarch will refer a
stale target desc.  At first I thought it wouldn't be a problem in
practice, because while that gdbarch object still exists, nothing
references it (it is effectively leaked).  But then I remember that we
cache gdbarches to avoid creating arches with duplicate features.  So
later (let's say if you connect again to a remote), we might want to
create a gdbarch with the same features as before, and we'll dig up the
old gdbarch, that points to the now deleted tdesc.

Perhaps it's possible to generate a crash with the current
implementation by connecting, disconnecting, connecting again, and then
doing something that uses the thread-specific gdbarch.

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-02-01 15:26   ` Andrew Burgess
@ 2023-02-01 20:20     ` Simon Marchi
  2023-02-03 11:31       ` Luis Machado
  2023-02-03 16:38       ` Andrew Burgess
  0 siblings, 2 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 20:20 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

> I guess the point I'm driving towards is that maybe instead of a new
> gdbarch method we should add something like gdbarch_from_tdesc into
> arch-utils.c (like we have gdbarch_from_bfd and gdbarch_find_by_info),
> which just does a lookup from tdesc.

One thing I would like to add: I presume that this process
(gdbarch_find_by_info) is somewhat expensive.  Is there an easy way to
short-circuit things earlier?  Maybe if we detect that a thread has the
same target desc id as before, we can avoid recomputing the gdbarch?
Or, we can cache the gdbarch in the remote_target.  The
remote_target::m_tdescs would hold both the target desc and
corresponding gdbarch as values, instead of just the target desc.
Actually, maybe the remote target wouldn't need to hold the target_desc
at all, once it has the gdbarch.  Other than maybe for lifetime reasons,
which are discussed with the previous patch.

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 12:07   ` Andrew Burgess
  2023-02-01 13:03     ` Eli Zaretskii
  2023-02-01 17:37     ` Simon Marchi
@ 2023-02-01 20:46     ` Simon Marchi
  2023-02-02 21:43       ` Thiago Jung Bauermann
  2 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-01 20:46 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi



On 2/1/23 07:07, Andrew Burgess via Gdb-patches wrote:
> Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
> writes:
> 
>> Now that an inferior thread can have a different target description than
>> its process, there needs to be a way to communicate this target
>> description to GDB.  So add the concept of a target description ID to the
>> remote protocol, which is used to reference them and allows them to be
>> transferred only once over the wire.
>>
>> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
>> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
>> unsigned integer containing the ID.
>>
>> It is also sent in the threads list XML in the response of a
>> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
>> the <thread> node.
>>
>> To request the target description XML of a given ID, GDB sends the
>> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
>> is the target description ID.
> 
> Luis already commented that in some locations the ID is hex, while in
> others it is not explicitly stated if the value is hex or decimal.  I'd
> like to second that feedback, and suggest that we pick one, and use that
> consistently throughout.
> 
> My thinking is that it will be easier to understand remote packet traces
> if target descriptions are requested using an ID in the safe format as
> was sent to GDB, and if IDs in different packets match up.
> 
> Thus, I would suggest we switch to using 'target-id-%x.xml' here, and
> send the ID as hex in the threads reply packet.
> 
> Additionally, I think it would be worth adding a new feature to the
> qSupported packet, maybe 'per-thread-tdesc'.  With this added, GDB would
> be able to tell gdbserver that it supports this feature, and gdbserver
> will be able to confirm that the feature is supported.
> 
> I'm not 100% sure what we'd want to do if it turns out GDB doesn't
> support the feature?  Is it better to push on with GDB using the wrong
> target description?  Or would it be better if gdbserver exits with an
> error suggesting the GDB needs updating?  In some ways, _what_ we do
> doesn't really matter to me, but I think having the feature will allow
> us to pick a suitable error handling solution later if needed.
> 
> I'd be happy if adding the feature was done as a separate patch in this
> series, but I do think it should be part of this series.

I forgot to comment on that part.  Just to think out loud:

- If GDB supports the new feature but GDBserver doesn't, I guess that
  debugging works exactly like today?  What happens today if a remote
  thread changes its SVE vector size, the registers that GDB shows will
  simply not reflect the reality, they might have bogus values, but
  debugging will otherwise work?

- If GDB does not support the new feature but GDBserver does, I guess it
  is problematic, because GDBserver will assume that GDB will have
  adjusted its expectations about the length (and layout) of the g
  packet response, since it told GDB about the thread-specific tdesc.
  But since GDB doesn't know about thread-specific tdescs, it will try
  to interpret the g packet response with the register layout of the
  process-wide tdesc, possibly leading to the infamous "Remote 'g'
  packet reply is too long", if the received response is longer than
  expected.

So, I agree that we need some feature flag for this.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-01 19:53         ` Simon Marchi
@ 2023-02-01 21:55           ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-01 21:55 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Simon Marchi <simark@simark.ca> writes:

> On 2/1/23 14:33, Thiago Jung Bauermann via Gdb-patches wrote:
>> 
>> Simon Marchi <simon.marchi@efficios.com> writes:
>> 
>>>>> @@ -946,17 +946,16 @@ extern int have_ptrace_getregset;
>>>>>     *VALP and return 1.  If not found or if there is an error, return
>>>>>     0.  */
>>>>>  
>>>>> -int linux_get_auxv (int wordsize, CORE_ADDR match,
>>>>> -		    CORE_ADDR *valp);
>>>>> +int linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp);
>>>>>  
>>>>>  /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
>>>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>>>  
>>>>> -CORE_ADDR linux_get_hwcap (int wordsize);
>>>>> +CORE_ADDR linux_get_hwcap (int pid, int wordsize);
>>>>>  
>>>>>  /* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length
>>>>>     WORDSIZE.  If no entry was found, return zero.  */
>>>>>  
>>>>> -CORE_ADDR linux_get_hwcap2 (int wordsize);
>>>>> +CORE_ADDR linux_get_hwcap2 (int pid, int wordsize);
>>>>
>>>> Ideally the comment for these three functions would be updated to
>>>> mention the PID argument.
>> 
>> This is how I changed the comments. What do you think?
>> 
>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>> index 221de85aa2ee..4f95a27808ba 100644
>> --- a/gdbserver/linux-low.h
>> +++ b/gdbserver/linux-low.h
>> @@ -941,20 +941,19 @@ bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int
>> *handle_len);
>>  
>>  extern int have_ptrace_getregset;
>>  
>> -/* Search for the value with type MATCH in the auxv vector with
>> -   entries of length WORDSIZE bytes.  If found, store the value in
>> -   *VALP and return 1.  If not found or if there is an error, return
>> -   0.  */
>> +/* Search for the value with type MATCH in the auxv vector, with entries of
>> +   length WORDSIZE bytes, of process with PID.  If found, store the value
>
> "of process with PID" sounds weird, syntactically.  I would say "of process with pid
> PID" (same in the other comments).  Otherwise, this is OK.

I adopted this wording and pushed this patch as well as patch 1 in this
series.

Thank you again for your, Andrew's and Luis' reviews on these patches.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features
  2023-02-01 16:04     ` Simon Marchi
@ 2023-02-01 22:13       ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-01 22:13 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Luis Machado, gdb-patches, Simon Marchi


Simon Marchi <simark@simark.ca> writes:

>> Still LGTM.
> Still LGTM too.

Thank you for your review!

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-01 16:32       ` Luis Machado
@ 2023-02-02  2:54         ` Thiago Jung Bauermann
  2023-02-02  3:47           ` Simon Marchi
                             ` (2 more replies)
  0 siblings, 3 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-02  2:54 UTC (permalink / raw)
  To: Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/1/23 16:21, Simon Marchi wrote:
>> 
>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>> --- a/gdbserver/linux-low.h
>>>> +++ b/gdbserver/linux-low.h
>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>     /* Architecture-specific setup for the current thread.  */
>>>>     virtual void low_arch_setup () = 0;
>>>>   +  /* Allows arch-specific code to set the thread's target description when the
>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>> +     is necessary.  */
>>>> +  virtual const struct target_desc *
>>>> +    get_thread_tdesc (const thread_info *thread);
>>>
>>> I think the comment for this function is not correct.  The function does
>>> not SET the thread's target description, but just GETS a target
>>> description suitable for `thread`.  It's the caller's job to do the
>>> setting.
>> This comment also gave me pause.  How does a getter set something.  I
>> then understood that it allowed the arch-specific code to provide a
>> thread-specific tdesc.  I would suggest just:
>
> FWIW, I read it as "the functions *allows* arch-specific code to set".
> So it doesn't set on its own, but it does allow something else to do
> it.

Yes, that's what was in my mind when I wrote the comment. But I agree
it's unclear, and I adopted Simon's suggested version.

>> The other thought I had while re-reading the patch is why do we need to
>> return and store nullptr if the thread target description is the same as
>> the main one for the process.  get_thread_tdesc could just return
>> process_info->tdesc if we don't need a separate tdesc, and we would
>> store that same pointer in thread_info->tdesc.

We don't need to return and store nullptr if the thread target
description is the same as the main one for the process. Things will
work fine if we do as you suggest. IIRC my private branch worked liked
that for a while, before I changed it to the current version.

I changed it because I thought it was a clearer mental model if
thread_info->tdesc is nullptr when there's not thread-specific target
description. I can make the get_thread_tdesc method always return a
valid target description if you think it's better that way.

>> And get_thread_tdesc would just return that (in fact,
>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>> things more complicated down the road, but I can't think of anything.

Sorry, I don't understand this part. get_thread_tdesc is necessary
because it's the hook that allows arch-specific code to provide a target
description for the thread. I don't see how it can become unnecessary.

Perhaps you mean the get_thread_target_desc function? Sorry about the
names being so similar, I spent some time trying to think of a better
name for either the method or the function but failed.

In any case, it wouldn't be possible to make get_thread_target_desc just
return thread_info->tdesc because at least the way these patches are
currently written, when the inferior starts or a new thread of the
inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
call get_thread_tdesc after the first stop (in get_thread_regcache, in
the process of obtaining the pc register), so we will need to cope with
that situation.

> Sounds reasonable.
>
> Moving towards thread-specific target descriptions/gdbarch would be a positive thing given
> the SVE precedent. The process-wide target description/gdbarch no
> longer reflects the correct settings for each thread on AArch64's with SVE support.

In the first version of these patches I removed the process-wide target
description and moved it to thread_info, but it was a big patch that
touched many targets. I can bring it back if you think it's worth it.


-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-02  2:54         ` Thiago Jung Bauermann
@ 2023-02-02  3:47           ` Simon Marchi
  2023-02-03  3:47             ` Thiago Jung Bauermann
  2023-02-03 11:11             ` Luis Machado
  2023-02-03 10:57           ` Luis Machado
  2023-02-06 20:26           ` Pedro Alves
  2 siblings, 2 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-02  3:47 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Luis Machado
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches



On 2/1/23 21:54, Thiago Jung Bauermann wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 2/1/23 16:21, Simon Marchi wrote:
>>>
>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>> --- a/gdbserver/linux-low.h
>>>>> +++ b/gdbserver/linux-low.h
>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>     /* Architecture-specific setup for the current thread.  */
>>>>>     virtual void low_arch_setup () = 0;
>>>>>   +  /* Allows arch-specific code to set the thread's target description when the
>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>> +     is necessary.  */
>>>>> +  virtual const struct target_desc *
>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>
>>>> I think the comment for this function is not correct.  The function does
>>>> not SET the thread's target description, but just GETS a target
>>>> description suitable for `thread`.  It's the caller's job to do the
>>>> setting.
>>> This comment also gave me pause.  How does a getter set something.  I
>>> then understood that it allowed the arch-specific code to provide a
>>> thread-specific tdesc.  I would suggest just:
>>
>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>> So it doesn't set on its own, but it does allow something else to do
>> it.
> 
> Yes, that's what was in my mind when I wrote the comment. But I agree
> it's unclear, and I adopted Simon's suggested version.
> 
>>> The other thought I had while re-reading the patch is why do we need to
>>> return and store nullptr if the thread target description is the same as
>>> the main one for the process.  get_thread_tdesc could just return
>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>> store that same pointer in thread_info->tdesc.
> 
> We don't need to return and store nullptr if the thread target
> description is the same as the main one for the process. Things will
> work fine if we do as you suggest. IIRC my private branch worked liked
> that for a while, before I changed it to the current version.
> 
> I changed it because I thought it was a clearer mental model if
> thread_info->tdesc is nullptr when there's not thread-specific target
> description. I can make the get_thread_tdesc method always return a
> valid target description if you think it's better that way.

Either way works.

>>> And get_thread_tdesc would just return that (in fact,
>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>> things more complicated down the road, but I can't think of anything.
> 
> Sorry, I don't understand this part. get_thread_tdesc is necessary
> because it's the hook that allows arch-specific code to provide a target
> description for the thread. I don't see how it can become unnecessary.
> 
> Perhaps you mean the get_thread_target_desc function? Sorry about the
> names being so similar, I spent some time trying to think of a better
> name for either the method or the function but failed.

Err yeah, I meant the free function that returns the process' tdesc if
the thread doesn't have one.

> In any case, it wouldn't be possible to make get_thread_target_desc just
> return thread_info->tdesc because at least the way these patches are
> currently written, when the inferior starts or a new thread of the
> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
> call get_thread_tdesc after the first stop (in get_thread_regcache, in
> the process of obtaining the pc register), so we will need to cope with
> that situation.

Ok.  Would it work if a new thread initially inherited the tdesc from
its process?

>> Sounds reasonable.
>>
>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing given
>> the SVE precedent. The process-wide target description/gdbarch no
>> longer reflects the correct settings for each thread on AArch64's with SVE support.
> 
> In the first version of these patches I removed the process-wide target
> description and moved it to thread_info, but it was a big patch that
> touched many targets. I can bring it back if you think it's worth it.

At least for the register description, if we decide it's now a
per-thread thing, what does it mean to have a process-wide description
anyway?  I think it would make sense to get rid of it, that could help
confirm our model works (and it would remove the chance of  using the
wrong tdesc by mistake for a thread that has its own tdesc).  It's
probably something that can be done incrementally though.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 17:03     ` Simon Marchi
@ 2023-02-02 19:52       ` Thiago Jung Bauermann
  2023-02-02 20:51         ` Simon Marchi
  2023-02-03 11:22       ` Luis Machado
  1 sibling, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-02 19:52 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi


Simon Marchi <simark@simark.ca> writes:

>> Having read some of the later patches, I have some additional thoughts
>> here:
>> 
>> I think we should make it explicit here that IDs are connection wide,
>> not per-process.  We should also make it clear that GDB might[1] cache
>> target descriptions per remote connection, and so a remote target should
>> not reuse a target description ID except where the target description is
>> identical.

Ah, good point. I will make that clarification.

>> [1] I say "GDB might" here because if we say "GDB will" then this would
>> imply each target description will only be asked for once.  And I
>> figure, why be overly restrictive.
>
> Thanks for pointing this out, I had the same thought while reading the
> patch.
>
> In my original idea, I imagined that target description IDs could be
> some hashes computed from the XML content (a bit like git hashes or ELF
> build IDs), such that a given target description would always have the
> same ID.  This would give clients the possibility to cache target
> descriptions locally, a bit like the index cache.  It did sound nice,
> but perhaps it's not really important.

Ah, sorry I misunderstood this part of your suggestion. I thought that
the caching was supposed to be limited to the duration of the connection,
and thus the m_tdescs map in struct remote state would be enough to
provide that functionality. Do you mean that the cache should be on
disk, so that it survives GDB quitting? I can look into that if you want
and implement it, if not complicated.

In this case, I think the tdesc ID should be of the format
<prefix>:<hex number>, so that <prefix> can be “sha1”, “sha256” etc to
indicate that <hex number> is a hash with the given algo, or even
“number” to indicate that it's a simple integer like it is today.

Perhaps we can do the prefix thing even if not implementing the cache,
to leave the possibility of adding it in the future?

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 17:37     ` Simon Marchi
@ 2023-02-02 20:36       ` Thiago Jung Bauermann
  2023-02-02 20:56         ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-02 20:36 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi


Simon Marchi <simark@simark.ca> writes:

> On 2/1/23 07:07, Andrew Burgess via Gdb-patches wrote:
>> Thiago Jung Bauermann via Gdb-patches <gdb-patches@sourceware.org>
>> writes:
>> 
>>> Now that an inferior thread can have a different target description than
>>> its process, there needs to be a way to communicate this target
>>> description to GDB.  So add the concept of a target description ID to the
>>> remote protocol, which is used to reference them and allows them to be
>>> transferred only once over the wire.
>>>
>>> The ID is an unsigned integer, and is sent in the 'T AA n1:r1;n2:r2;...'
>>> stop reply packet as a new 'n:r' pair, where n is "tdesc" and "r" is an
>>> unsigned integer containing the ID.
>>>
>>> It is also sent in the threads list XML in the response of a
>>> qXfer:threads:read request.  The ID is sent as a new "tdesc" attribute of
>>> the <thread> node.
>>>
>>> To request the target description XML of a given ID, GDB sends the
>>> qXfer:features:read request with "target-id-%u.xml" as the annex, where %u
>>> is the target description ID.
>> 
>> Luis already commented that in some locations the ID is hex, while in
>> others it is not explicitly stated if the value is hex or decimal.  I'd
>> like to second that feedback, and suggest that we pick one, and use that
>> consistently throughout.
>> 
>> My thinking is that it will be easier to understand remote packet traces
>> if target descriptions are requested using an ID in the safe format as
>> was sent to GDB, and if IDs in different packets match up.
>> 
>> Thus, I would suggest we switch to using 'target-id-%x.xml' here, and
>> send the ID as hex in the threads reply packet.
>
> Not that I disagree with you, but I just wanted to note that this
> decimal / hexadecimal mismatch already exists for the core field.  It's
> hex in stop replies, decimal in XML.  The thread id, however, is always
> hex (the special thread-id syntax).
>
> Regardless how this new field is formatted, it would be nice to be
> explicit about the core field too.

I agree it makes more sense to use hex everywhere.

In the case of XML attribute fields, enforcing hex would mean adding a
base parameter to xml_parse_unsigned_integer (which currently accepts
decimal, octal and hex). I'll do that.

In the case of the core field, to avoid breaking existing stubs it's
probably better to document that it can accept any of the three bases.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-02 19:52       ` Thiago Jung Bauermann
@ 2023-02-02 20:51         ` Simon Marchi
  2023-02-03  2:44           ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-02 20:51 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi



On 2/2/23 14:52, Thiago Jung Bauermann wrote:
> 
> Simon Marchi <simark@simark.ca> writes:
> 
>>> Having read some of the later patches, I have some additional thoughts
>>> here:
>>>
>>> I think we should make it explicit here that IDs are connection wide,
>>> not per-process.  We should also make it clear that GDB might[1] cache
>>> target descriptions per remote connection, and so a remote target should
>>> not reuse a target description ID except where the target description is
>>> identical.
> 
> Ah, good point. I will make that clarification.
> 
>>> [1] I say "GDB might" here because if we say "GDB will" then this would
>>> imply each target description will only be asked for once.  And I
>>> figure, why be overly restrictive.
>>
>> Thanks for pointing this out, I had the same thought while reading the
>> patch.
>>
>> In my original idea, I imagined that target description IDs could be
>> some hashes computed from the XML content (a bit like git hashes or ELF
>> build IDs), such that a given target description would always have the
>> same ID.  This would give clients the possibility to cache target
>> descriptions locally, a bit like the index cache.  It did sound nice,
>> but perhaps it's not really important.
> 
> Ah, sorry I misunderstood this part of your suggestion. I thought that
> the caching was supposed to be limited to the duration of the connection,
> and thus the m_tdescs map in struct remote state would be enough to
> provide that functionality. Do you mean that the cache should be on
> disk, so that it survives GDB quitting? I can look into that if you want
> and implement it, if not complicated.

To be clear, I'm not asking you to implement an on-disk cache, I'm just
trying to think about what the limitations of the proposed solution are.
Because mistakes or shortcomings introduced in the remote protocol (like
any API / ABI meant to be stable) are difficult to fix afterwards.  If
there is a chance we want to do an on-disk cache (or share a cache
between multiple concurrent connections), we should think about that
now.

On one hand, perhaps we consider that target descriptions are small
enough that there's no point in having a persistent cache like that.
The time to fetch each target description once per connection is
probably insignificant.

On the other hand, perhaps doing the hash approach is easy enough that
we might as well do it, and that just leaves more doors open.  In my
mind, as a start, we could just pass the XML of the tdesc through a
sha256 function, possibly doing something more sophisticated later (this
means the hash of a given tdesc could change over time, but still two
identical hashes mean identical tdescs).  However, I don't think there
are sha256 functions built in on the OSes we want to support, so we'd
have to depend on some external library.  And that complicates things
quite a bit...  We already have a CRC32 function in gdbserver, but I
don't know if that's good enough to be confident there won't be
collisions.

> In this case, I think the tdesc ID should be of the format
> <prefix>:<hex number>, so that <prefix> can be “sha1”, “sha256” etc to
> indicate that <hex number> is a hash with the given algo, or even
> “number” to indicate that it's a simple integer like it is today.
> 
> Perhaps we can do the prefix thing even if not implementing the cache,
> to leave the possibility of adding it in the future?

I think I would choose between hash and number, but not do both, I don't
see the need to have both.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-02 20:36       ` Thiago Jung Bauermann
@ 2023-02-02 20:56         ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-02 20:56 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi


> I agree it makes more sense to use hex everywhere.
> 
> In the case of XML attribute fields, enforcing hex would mean adding a
> base parameter to xml_parse_unsigned_integer (which currently accepts
> decimal, octal and hex). I'll do that.
> 
> In the case of the core field, to avoid breaking existing stubs it's
> probably better to document that it can accept any of the three bases.

The "core" field is parsed using gdb_xml_parse_attr_ulongest, which uses
strtoulst with a base of 0.  So I suppose that an hex value with the 0x
prefix would work.  So bases other than 10 can work, but they need to
have the appropriate prefix.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 20:46     ` Simon Marchi
@ 2023-02-02 21:43       ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-02 21:43 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi


Simon Marchi <simark@simark.ca> writes:

> On 2/1/23 07:07, Andrew Burgess via Gdb-patches wrote:
>> Additionally, I think it would be worth adding a new feature to the
>> qSupported packet, maybe 'per-thread-tdesc'.  With this added, GDB would
>> be able to tell gdbserver that it supports this feature, and gdbserver
>> will be able to confirm that the feature is supported.
>> 
>> I'm not 100% sure what we'd want to do if it turns out GDB doesn't
>> support the feature?  Is it better to push on with GDB using the wrong
>> target description?  Or would it be better if gdbserver exits with an
>> error suggesting the GDB needs updating?  In some ways, _what_ we do
>> doesn't really matter to me, but I think having the feature will allow
>> us to pick a suitable error handling solution later if needed.
>> 
>> I'd be happy if adding the feature was done as a separate patch in this
>> series, but I do think it should be part of this series.
>
> I forgot to comment on that part.  Just to think out loud:

I tested the two cases you mentioned below.

> - If GDB supports the new feature but GDBserver doesn't, I guess that
>   debugging works exactly like today?  What happens today if a remote
>   thread changes its SVE vector size, the registers that GDB shows will
>   simply not reflect the reality, they might have bogus values, but
>   debugging will otherwise work?

Yes, that's exactly what happens.

> - If GDB does not support the new feature but GDBserver does, I guess it
>   is problematic, because GDBserver will assume that GDB will have
>   adjusted its expectations about the length (and layout) of the g
>   packet response, since it told GDB about the thread-specific tdesc.
>   But since GDB doesn't know about thread-specific tdescs, it will try
>   to interpret the g packet response with the register layout of the
>   process-wide tdesc, possibly leading to the infamous "Remote 'g'
>   packet reply is too long", if the received response is longer than
>   expected.

This too.

> So, I agree that we need some feature flag for this.

Ok, I will add it for the next version of the patches.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-02 20:51         ` Simon Marchi
@ 2023-02-03  2:44           ` Thiago Jung Bauermann
  2023-02-03 16:29             ` Andrew Burgess
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-03  2:44 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches, Simon Marchi


Simon Marchi <simark@simark.ca> writes:

> On 2/2/23 14:52, Thiago Jung Bauermann wrote:
>> 
>> Simon Marchi <simark@simark.ca> writes:
>> 
>>>> Having read some of the later patches, I have some additional thoughts
>>>> here:
>>>>
>>>> I think we should make it explicit here that IDs are connection wide,
>>>> not per-process.  We should also make it clear that GDB might[1] cache
>>>> target descriptions per remote connection, and so a remote target should
>>>> not reuse a target description ID except where the target description is
>>>> identical.
>> 
>> Ah, good point. I will make that clarification.
>> 
>>>> [1] I say "GDB might" here because if we say "GDB will" then this would
>>>> imply each target description will only be asked for once.  And I
>>>> figure, why be overly restrictive.
>>>
>>> Thanks for pointing this out, I had the same thought while reading the
>>> patch.
>>>
>>> In my original idea, I imagined that target description IDs could be
>>> some hashes computed from the XML content (a bit like git hashes or ELF
>>> build IDs), such that a given target description would always have the
>>> same ID.  This would give clients the possibility to cache target
>>> descriptions locally, a bit like the index cache.  It did sound nice,
>>> but perhaps it's not really important.
>> 
>> Ah, sorry I misunderstood this part of your suggestion. I thought that
>> the caching was supposed to be limited to the duration of the connection,
>> and thus the m_tdescs map in struct remote state would be enough to
>> provide that functionality. Do you mean that the cache should be on
>> disk, so that it survives GDB quitting? I can look into that if you want
>> and implement it, if not complicated.
>
> To be clear, I'm not asking you to implement an on-disk cache, I'm just
> trying to think about what the limitations of the proposed solution are.
> Because mistakes or shortcomings introduced in the remote protocol (like
> any API / ABI meant to be stable) are difficult to fix afterwards.  If
> there is a chance we want to do an on-disk cache (or share a cache
> between multiple concurrent connections), we should think about that
> now.

Indeed, that's a good idea.

> On one hand, perhaps we consider that target descriptions are small
> enough that there's no point in having a persistent cache like that.
> The time to fetch each target description once per connection is
> probably insignificant.

I don't have a good intuition about that. My uneducated guess is that
it's not worth it, but as you say I think it's a good idea to leave the
door open if we can.

> On the other hand, perhaps doing the hash approach is easy enough that
> we might as well do it, and that just leaves more doors open.  In my
> mind, as a start, we could just pass the XML of the tdesc through a
> sha256 function, possibly doing something more sophisticated later (this
> means the hash of a given tdesc could change over time, but still two
> identical hashes mean identical tdescs).  However, I don't think there
> are sha256 functions built in on the OSes we want to support, so we'd
> have to depend on some external library.  And that complicates things
> quite a bit...  We already have a CRC32 function in gdbserver, but I
> don't know if that's good enough to be confident there won't be
> collisions.

I tried to research this a bit, but I'm not confident enough in my
knowledge of the subject to reach a conclusion. I only know enough about
hashes to be dangerous. I did find a hash testsuite called SMhasher
which seems to be well regarded, and its website¹ has
reports for CRC32², which shows that it fails many collision and
distribution bias tests. So it doesn't look like it is very reliable for
using as a hash.

We do support libxxhash as an optional dependency, so we could use that
if gdbserver is linked with it. Its SMhasher report³ looks good, IUUC
(but not the 32 bits version though⁴).

We could also vendor coreutils's lib/sha256.[ch] files. They're 660
lines in total.

>> In this case, I think the tdesc ID should be of the format
>> <prefix>:<hex number>, so that <prefix> can be “sha1”, “sha256” etc to
>> indicate that <hex number> is a hash with the given algo, or even
>> “number” to indicate that it's a simple integer like it is today.
>> 
>> Perhaps we can do the prefix thing even if not implementing the cache,
>> to leave the possibility of adding it in the future?
>
> I think I would choose between hash and number, but not do both, I don't
> see the need to have both.

I suggested a prefix to designate an integer ID as a way to implement
only this possibility for now, but which would allow implementing hash
IDs later, as additional prefixes. Or another possibility is that if we
later decide to support hashes, we could add a separate protocol feature
to signal that.

-- 
Thiago

¹ https://rurban.github.io/smhasher/
² https://rurban.github.io/smhasher/doc/crc32.txt
³ https://rurban.github.io/smhasher/doc/xxHash64.txthttps://rurban.github.io/smhasher/doc/xxHash32.txt

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-02  3:47           ` Simon Marchi
@ 2023-02-03  3:47             ` Thiago Jung Bauermann
  2023-02-03 11:13               ` Luis Machado
  2023-02-03 11:11             ` Luis Machado
  1 sibling, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-03  3:47 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Luis Machado, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Simon Marchi <simark@simark.ca> writes:

> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>> 
>> Luis Machado <luis.machado@arm.com> writes:
>> 
>>> On 2/1/23 16:21, Simon Marchi wrote:
>>>>
>>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>>> --- a/gdbserver/linux-low.h
>>>>>> +++ b/gdbserver/linux-low.h
>>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>>     /* Architecture-specific setup for the current thread.  */
>>>>>>     virtual void low_arch_setup () = 0;
>>>>>>   +  /* Allows arch-specific code to set the thread's target description when the
>>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>>> +     is necessary.  */
>>>>>> +  virtual const struct target_desc *
>>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>>
>>>>> I think the comment for this function is not correct.  The function does
>>>>> not SET the thread's target description, but just GETS a target
>>>>> description suitable for `thread`.  It's the caller's job to do the
>>>>> setting.
>>>> This comment also gave me pause.  How does a getter set something.  I
>>>> then understood that it allowed the arch-specific code to provide a
>>>> thread-specific tdesc.  I would suggest just:
>>>
>>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>>> So it doesn't set on its own, but it does allow something else to do
>>> it.
>> 
>> Yes, that's what was in my mind when I wrote the comment. But I agree
>> it's unclear, and I adopted Simon's suggested version.
>> 
>>>> The other thought I had while re-reading the patch is why do we need to
>>>> return and store nullptr if the thread target description is the same as
>>>> the main one for the process.  get_thread_tdesc could just return
>>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>>> store that same pointer in thread_info->tdesc.
>> 
>> We don't need to return and store nullptr if the thread target
>> description is the same as the main one for the process. Things will
>> work fine if we do as you suggest. IIRC my private branch worked liked
>> that for a while, before I changed it to the current version.
>> 
>> I changed it because I thought it was a clearer mental model if
>> thread_info->tdesc is nullptr when there's not thread-specific target
>> description. I can make the get_thread_tdesc method always return a
>> valid target description if you think it's better that way.
>
> Either way works.

Ok, if there's no preference I suggest leaving it as it is now (unless
we decide moving away from process_info->tdesc).

>>>> And get_thread_tdesc would just return that (in fact,
>>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>>> things more complicated down the road, but I can't think of anything.
>> 
>> Sorry, I don't understand this part. get_thread_tdesc is necessary
>> because it's the hook that allows arch-specific code to provide a target
>> description for the thread. I don't see how it can become unnecessary.
>> 
>> Perhaps you mean the get_thread_target_desc function? Sorry about the
>> names being so similar, I spent some time trying to think of a better
>> name for either the method or the function but failed.
>
> Err yeah, I meant the free function that returns the process' tdesc if
> the thread doesn't have one.
>
>> In any case, it wouldn't be possible to make get_thread_target_desc just
>> return thread_info->tdesc because at least the way these patches are
>> currently written, when the inferior starts or a new thread of the
>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>> the process of obtaining the pc register), so we will need to cope with
>> that situation.
>
> Ok.  Would it work if a new thread initially inherited the tdesc from
> its process?

Yes, it would. Version 1 of these patches didn't work exactly like that
because I removed process_info->tdesc, but the new thread inherited from
the parent thread's tdesc. This happened in
linux_process_target::handle_extended_wait where the clone and fork
events are handled.

>>> Sounds reasonable.
>>>
>>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing
>>> given
>>> the SVE precedent. The process-wide target description/gdbarch no
>>> longer reflects the correct settings for each thread on AArch64's with SVE support.
>> 
>> In the first version of these patches I removed the process-wide target
>> description and moved it to thread_info, but it was a big patch that
>> touched many targets. I can bring it back if you think it's worth it.
>
> At least for the register description, if we decide it's now a
> per-thread thing, what does it mean to have a process-wide description
> anyway?  I think it would make sense to get rid of it, that could help
> confirm our model works (and it would remove the chance of  using the
> wrong tdesc by mistake for a thread that has its own tdesc).  It's
> probably something that can be done incrementally though.

Would it be done incrementally by keeping process_info->tdesc but
changing each target in turn to use thread_info->tdesc and ignore the
process_info one?

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-02  2:54         ` Thiago Jung Bauermann
  2023-02-02  3:47           ` Simon Marchi
@ 2023-02-03 10:57           ` Luis Machado
  2023-02-04  6:18             ` Thiago Jung Bauermann
  2023-02-06 20:26           ` Pedro Alves
  2 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-03 10:57 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/2/23 02:54, Thiago Jung Bauermann wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 2/1/23 16:21, Simon Marchi wrote:
>>>
>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>> --- a/gdbserver/linux-low.h
>>>>> +++ b/gdbserver/linux-low.h
>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>      /* Architecture-specific setup for the current thread.  */
>>>>>      virtual void low_arch_setup () = 0;
>>>>>    +  /* Allows arch-specific code to set the thread's target description when the
>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>> +     is necessary.  */
>>>>> +  virtual const struct target_desc *
>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>
>>>> I think the comment for this function is not correct.  The function does
>>>> not SET the thread's target description, but just GETS a target
>>>> description suitable for `thread`.  It's the caller's job to do the
>>>> setting.
>>> This comment also gave me pause.  How does a getter set something.  I
>>> then understood that it allowed the arch-specific code to provide a
>>> thread-specific tdesc.  I would suggest just:
>>
>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>> So it doesn't set on its own, but it does allow something else to do
>> it.
> 
> Yes, that's what was in my mind when I wrote the comment. But I agree
> it's unclear, and I adopted Simon's suggested version.
> 
>>> The other thought I had while re-reading the patch is why do we need to
>>> return and store nullptr if the thread target description is the same as
>>> the main one for the process.  get_thread_tdesc could just return
>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>> store that same pointer in thread_info->tdesc.
> 
> We don't need to return and store nullptr if the thread target
> description is the same as the main one for the process. Things will
> work fine if we do as you suggest. IIRC my private branch worked liked
> that for a while, before I changed it to the current version.
> 
> I changed it because I thought it was a clearer mental model if
> thread_info->tdesc is nullptr when there's not thread-specific target
> description. I can make the get_thread_tdesc method always return a
> valid target description if you think it's better that way.
> 
>>> And get_thread_tdesc would just return that (in fact,
>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>> things more complicated down the road, but I can't think of anything.
> 
> Sorry, I don't understand this part. get_thread_tdesc is necessary
> because it's the hook that allows arch-specific code to provide a target
> description for the thread. I don't see how it can become unnecessary.
> 
> Perhaps you mean the get_thread_target_desc function? Sorry about the
> names being so similar, I spent some time trying to think of a better
> name for either the method or the function but failed.
> 
> In any case, it wouldn't be possible to make get_thread_target_desc just
> return thread_info->tdesc because at least the way these patches are
> currently written, when the inferior starts or a new thread of the
> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
> call get_thread_tdesc after the first stop (in get_thread_regcache, in
> the process of obtaining the pc register), so we will need to cope with
> that situation.
> 
>> Sounds reasonable.
>>
>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing given
>> the SVE precedent. The process-wide target description/gdbarch no
>> longer reflects the correct settings for each thread on AArch64's with SVE support.
> 
> In the first version of these patches I removed the process-wide target
> description and moved it to thread_info, but it was a big patch that
> touched many targets. I can bring it back if you think it's worth it

No need. As Simon suggested, we can do this incrementally. I don't think we should hold off on
this series' particular improvements so we can get the more general case sorted.


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-02  3:47           ` Simon Marchi
  2023-02-03  3:47             ` Thiago Jung Bauermann
@ 2023-02-03 11:11             ` Luis Machado
  2023-02-04 15:21               ` Thiago Jung Bauermann
  1 sibling, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-03 11:11 UTC (permalink / raw)
  To: Simon Marchi, Thiago Jung Bauermann
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/2/23 03:47, Simon Marchi wrote:
> 
> 
> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>
>> Luis Machado <luis.machado@arm.com> writes:
>>
>>> On 2/1/23 16:21, Simon Marchi wrote:
>>>>
>>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>>> --- a/gdbserver/linux-low.h
>>>>>> +++ b/gdbserver/linux-low.h
>>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>>      /* Architecture-specific setup for the current thread.  */
>>>>>>      virtual void low_arch_setup () = 0;
>>>>>>    +  /* Allows arch-specific code to set the thread's target description when the
>>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>>> +     is necessary.  */
>>>>>> +  virtual const struct target_desc *
>>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>>
>>>>> I think the comment for this function is not correct.  The function does
>>>>> not SET the thread's target description, but just GETS a target
>>>>> description suitable for `thread`.  It's the caller's job to do the
>>>>> setting.
>>>> This comment also gave me pause.  How does a getter set something.  I
>>>> then understood that it allowed the arch-specific code to provide a
>>>> thread-specific tdesc.  I would suggest just:
>>>
>>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>>> So it doesn't set on its own, but it does allow something else to do
>>> it.
>>
>> Yes, that's what was in my mind when I wrote the comment. But I agree
>> it's unclear, and I adopted Simon's suggested version.
>>
>>>> The other thought I had while re-reading the patch is why do we need to
>>>> return and store nullptr if the thread target description is the same as
>>>> the main one for the process.  get_thread_tdesc could just return
>>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>>> store that same pointer in thread_info->tdesc.
>>
>> We don't need to return and store nullptr if the thread target
>> description is the same as the main one for the process. Things will
>> work fine if we do as you suggest. IIRC my private branch worked liked
>> that for a while, before I changed it to the current version.
>>
>> I changed it because I thought it was a clearer mental model if
>> thread_info->tdesc is nullptr when there's not thread-specific target
>> description. I can make the get_thread_tdesc method always return a
>> valid target description if you think it's better that way.
> 
> Either way works.
> 
>>>> And get_thread_tdesc would just return that (in fact,
>>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>>> things more complicated down the road, but I can't think of anything.
>>
>> Sorry, I don't understand this part. get_thread_tdesc is necessary
>> because it's the hook that allows arch-specific code to provide a target
>> description for the thread. I don't see how it can become unnecessary.
>>
>> Perhaps you mean the get_thread_target_desc function? Sorry about the
>> names being so similar, I spent some time trying to think of a better
>> name for either the method or the function but failed.
> 
> Err yeah, I meant the free function that returns the process' tdesc if
> the thread doesn't have one.
> 
>> In any case, it wouldn't be possible to make get_thread_target_desc just
>> return thread_info->tdesc because at least the way these patches are
>> currently written, when the inferior starts or a new thread of the
>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>> the process of obtaining the pc register), so we will need to cope with
>> that situation.
> 
> Ok.  Would it work if a new thread initially inherited the tdesc from
> its process?
> 

It should be fine because the first time we fetch a process target description, it is eventually obtained from the first and only thread. So the SVE vector length should be correct.

Any subsequent attempts to use the process' target description (the first one we obtained), after further stops, may end up using an incorrect description.

I think this is handled correctly by the target architecture target hook though. But there are other places where this is potentially incorrect.

For example...

- When using gcore to dump a core file, GDB only dumps a single target description. While this might be correct for a target with a fixed target description or a AArch64 target that doesn't support SVE, it likely won't be correctly for one
AArch64 target supporting SVE if its threads changed vector length mid-execution. Either we emit target description notes by thread, or we don't emit a target description note for those cases.

- When loading the above/older gcore core files back, GDB will use a potentially incorrect target description. If we decide to emit per-thread target descriptions, it should be fine. Otherwise we may need to have a "thread architecture" hook for core files as well.

- The remote has no concept of a thread architecture (Thiago is addressing this with this patch series).

- AArch64 frames may have slightly different vg values, which means their gdbarches are different as well.

Given the differences between two gdbarches are small, we mostly get away with it. But if there are further differences (different hooks, for example), I fear we may run into a situation where we use an incorrect gdbarch to call a particular hook.

>>> Sounds reasonable.
>>>
>>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing given
>>> the SVE precedent. The process-wide target description/gdbarch no
>>> longer reflects the correct settings for each thread on AArch64's with SVE support.
>>
>> In the first version of these patches I removed the process-wide target
>> description and moved it to thread_info, but it was a big patch that
>> touched many targets. I can bring it back if you think it's worth it.
> 
> At least for the register description, if we decide it's now a
> per-thread thing, what does it mean to have a process-wide description
> anyway?  I think it would make sense to get rid of it, that could help

For AArch64 SVE, process-wide target descriptions mean it is the initial state. But it can't be trusted for further stops/events, in which case we need to trust the thread architecture hook.

> confirm our model works (and it would remove the chance of  using the
> wrong tdesc by mistake for a thread that has its own tdesc).  It's
> probably something that can be done incrementally though.
> 
> Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-03  3:47             ` Thiago Jung Bauermann
@ 2023-02-03 11:13               ` Luis Machado
  2023-02-04 15:26                 ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-03 11:13 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Simon Marchi
  Cc: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/3/23 03:47, Thiago Jung Bauermann wrote:
> 
> Simon Marchi <simark@simark.ca> writes:
> 
>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>>
>>> Luis Machado <luis.machado@arm.com> writes:
>>>
>>>> On 2/1/23 16:21, Simon Marchi wrote:
>>>>>
>>>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>>>> --- a/gdbserver/linux-low.h
>>>>>>> +++ b/gdbserver/linux-low.h
>>>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>>>      /* Architecture-specific setup for the current thread.  */
>>>>>>>      virtual void low_arch_setup () = 0;
>>>>>>>    +  /* Allows arch-specific code to set the thread's target description when the
>>>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>>>> +     is necessary.  */
>>>>>>> +  virtual const struct target_desc *
>>>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>>>
>>>>>> I think the comment for this function is not correct.  The function does
>>>>>> not SET the thread's target description, but just GETS a target
>>>>>> description suitable for `thread`.  It's the caller's job to do the
>>>>>> setting.
>>>>> This comment also gave me pause.  How does a getter set something.  I
>>>>> then understood that it allowed the arch-specific code to provide a
>>>>> thread-specific tdesc.  I would suggest just:
>>>>
>>>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>>>> So it doesn't set on its own, but it does allow something else to do
>>>> it.
>>>
>>> Yes, that's what was in my mind when I wrote the comment. But I agree
>>> it's unclear, and I adopted Simon's suggested version.
>>>
>>>>> The other thought I had while re-reading the patch is why do we need to
>>>>> return and store nullptr if the thread target description is the same as
>>>>> the main one for the process.  get_thread_tdesc could just return
>>>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>>>> store that same pointer in thread_info->tdesc.
>>>
>>> We don't need to return and store nullptr if the thread target
>>> description is the same as the main one for the process. Things will
>>> work fine if we do as you suggest. IIRC my private branch worked liked
>>> that for a while, before I changed it to the current version.
>>>
>>> I changed it because I thought it was a clearer mental model if
>>> thread_info->tdesc is nullptr when there's not thread-specific target
>>> description. I can make the get_thread_tdesc method always return a
>>> valid target description if you think it's better that way.
>>
>> Either way works.
> 
> Ok, if there's no preference I suggest leaving it as it is now (unless
> we decide moving away from process_info->tdesc).
> 
>>>>> And get_thread_tdesc would just return that (in fact,
>>>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>>>> things more complicated down the road, but I can't think of anything.
>>>
>>> Sorry, I don't understand this part. get_thread_tdesc is necessary
>>> because it's the hook that allows arch-specific code to provide a target
>>> description for the thread. I don't see how it can become unnecessary.
>>>
>>> Perhaps you mean the get_thread_target_desc function? Sorry about the
>>> names being so similar, I spent some time trying to think of a better
>>> name for either the method or the function but failed.
>>
>> Err yeah, I meant the free function that returns the process' tdesc if
>> the thread doesn't have one.
>>
>>> In any case, it wouldn't be possible to make get_thread_target_desc just
>>> return thread_info->tdesc because at least the way these patches are
>>> currently written, when the inferior starts or a new thread of the
>>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>>> the process of obtaining the pc register), so we will need to cope with
>>> that situation.
>>
>> Ok.  Would it work if a new thread initially inherited the tdesc from
>> its process?
> 
> Yes, it would. Version 1 of these patches didn't work exactly like that
> because I removed process_info->tdesc, but the new thread inherited from
> the parent thread's tdesc. This happened in
> linux_process_target::handle_extended_wait where the clone and fork
> events are handled.
> 
>>>> Sounds reasonable.
>>>>
>>>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing
>>>> given
>>>> the SVE precedent. The process-wide target description/gdbarch no
>>>> longer reflects the correct settings for each thread on AArch64's with SVE support.
>>>
>>> In the first version of these patches I removed the process-wide target
>>> description and moved it to thread_info, but it was a big patch that
>>> touched many targets. I can bring it back if you think it's worth it.
>>
>> At least for the register description, if we decide it's now a
>> per-thread thing, what does it mean to have a process-wide description
>> anyway?  I think it would make sense to get rid of it, that could help
>> confirm our model works (and it would remove the chance of  using the
>> wrong tdesc by mistake for a thread that has its own tdesc).  It's
>> probably something that can be done incrementally though.
> 
> Would it be done incrementally by keeping process_info->tdesc but
> changing each target in turn to use thread_info->tdesc and ignore the
> process_info one?
> 

Given only AArch64 has this requirement at the moment, it may be easier to leave the process-wide tdesc up until the point we can safely/easily switch to thread-specific ones.

After that, AArch64 will have potentially distinct thread tdescs while other architectures will have threads sharing the same tdesc.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-01 17:03     ` Simon Marchi
  2023-02-02 19:52       ` Thiago Jung Bauermann
@ 2023-02-03 11:22       ` Luis Machado
  2023-02-03 12:50         ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-03 11:22 UTC (permalink / raw)
  To: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi

On 2/1/23 17:03, Simon Marchi via Gdb-patches wrote:
> 
>> Having read some of the later patches, I have some additional thoughts
>> here:
>>
>> I think we should make it explicit here that IDs are connection wide,
>> not per-process.  We should also make it clear that GDB might[1] cache
>> target descriptions per remote connection, and so a remote target should
>> not reuse a target description ID except where the target description is
>> identical.
>>
>> [1] I say "GDB might" here because if we say "GDB will" then this would
>> imply each target description will only be asked for once.  And I
>> figure, why be overly restrictive.
> 
> Thanks for pointing this out, I had the same thought while reading the
> patch.
> 
> In my original idea, I imagined that target description IDs could be
> some hashes computed from the XML content (a bit like git hashes or ELF
> build IDs), such that a given target description would always have the
> same ID.  This would give clients the possibility to cache target
> descriptions locally, a bit like the index cache.  It did sound nice,
> but perhaps it's not really important.

Are you considering an encoded block of data that gdbserver sends to gdb, which in turn unpacks it on its end and use it to compute a target description?

Something along the lines of gdb/arch/aarch64.h:"struct aarch64_features" and how we encode features through bits?

> 
> Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-01 20:16       ` Simon Marchi
@ 2023-02-03 11:27         ` Luis Machado
  2023-02-03 13:19           ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-03 11:27 UTC (permalink / raw)
  To: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

On 2/1/23 20:16, Simon Marchi via Gdb-patches wrote:
>> IIUC, the tdescs would be deleted during the
>> pop_all_targets_at_and_above, when the refcount of the remote_target
>> gets to 0 and it gets deleted.  And the threads would be removed in
>> generic_mourn_inferior just after.
>>
>> An idea could be to call generic_mourn_inferior before
>> remote_unpush_target (no idea if it works).  Another one would be to
>> get a temporary reference to the remote_target object in
>> remote_unpush_target, just so that it outlives the threads.
>> Or maybe we should say that it's a process target's responsibility to
>> delete any thread it "owns" before getting deleted itself.
> 
> Another question related to this popped while reading the following
> patch.  When creating a gdbarch from a tdesc, the gdbarch keeps a
> pointer to that tdesc (accessible through gdbarch_target_desc).  And
> AFAIK, we never delete gdbarches.  So I suppose the gdbarch will refer a
> stale target desc.  At first I thought it wouldn't be a problem in
> practice, because while that gdbarch object still exists, nothing
> references it (it is effectively leaked).  But then I remember that we
> cache gdbarches to avoid creating arches with duplicate features.  So
> later (let's say if you connect again to a remote), we might want to
> create a gdbarch with the same features as before, and we'll dig up the
> old gdbarch, that points to the now deleted tdesc.

The target descriptions for aarch64 are all cached using a map in gdb/aarch64-tdep.c:

/* All possible aarch64 target descriptors.  */
static std::unordered_map <aarch64_features, target_desc *> tdesc_aarch64_map;

I don't think we should try to delete those, and they should live throughout the life of gdb (unless things get large, then we might consider cleanups).

> 
> Perhaps it's possible to generate a crash with the current
> implementation by connecting, disconnecting, connecting again, and then
> doing something that uses the thread-specific gdbarch.
> 
> Simon
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-02-01 20:20     ` Simon Marchi
@ 2023-02-03 11:31       ` Luis Machado
  2023-02-03 16:38       ` Andrew Burgess
  1 sibling, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-03 11:31 UTC (permalink / raw)
  To: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

On 2/1/23 20:20, Simon Marchi via Gdb-patches wrote:
>> I guess the point I'm driving towards is that maybe instead of a new
>> gdbarch method we should add something like gdbarch_from_tdesc into
>> arch-utils.c (like we have gdbarch_from_bfd and gdbarch_find_by_info),
>> which just does a lookup from tdesc.
> 
> One thing I would like to add: I presume that this process
> (gdbarch_find_by_info) is somewhat expensive.  Is there an easy way to
> short-circuit things earlier?  Maybe if we detect that a thread has the

We already do it in gdb/aarch64-tdep.c:aarch64_gdbarch_init by checking if we have something that can be reused:

   /* If there is already a candidate, use it.  */
   for (gdbarch_list *best_arch = gdbarch_list_lookup_by_info (arches, &info);
        best_arch != nullptr;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
       aarch64_gdbarch_tdep *tdep
         = gdbarch_tdep<aarch64_gdbarch_tdep> (best_arch->gdbarch);
       if (tdep && tdep->vq == vq)
         return best_arch->gdbarch;
     }

It is indeed an expensive process.

> same target desc id as before, we can avoid recomputing the gdbarch?
> Or, we can cache the gdbarch in the remote_target.  The
> remote_target::m_tdescs would hold both the target desc and
> corresponding gdbarch as values, instead of just the target desc.
> Actually, maybe the remote target wouldn't need to hold the target_desc
> at all, once it has the gdbarch.  Other than maybe for lifetime reasons,
> which are discussed with the previous patch.
> 
> Simon
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-03 11:22       ` Luis Machado
@ 2023-02-03 12:50         ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-03 12:50 UTC (permalink / raw)
  To: Luis Machado, Simon Marchi, Andrew Burgess,
	Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

> Are you considering an encoded block of data that gdbserver sends to gdb, which in turn unpacks it on its end and use it to compute a target description?
> 
> Something along the lines of gdb/arch/aarch64.h:"struct aarch64_features" and how we encode features through bits?

No, I imagine a hash being transmitted as a hex string, much like git
commit sha1s or build-ids.  Imagine passing the XML file through
sha256sum and sending that as a fingerprint for the tdesc.  Except that
an actual implementation could be smarter and hash the contents of the
XML in some way so that the particular (meaningless) formatting of the
XML doesn't change the hash (but that's an implementation detail).

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-03 11:27         ` Luis Machado
@ 2023-02-03 13:19           ` Simon Marchi
  2023-02-03 16:33             ` Andrew Burgess
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-03 13:19 UTC (permalink / raw)
  To: Luis Machado, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann



On 2/3/23 06:27, Luis Machado wrote:
> On 2/1/23 20:16, Simon Marchi via Gdb-patches wrote:
>>> IIUC, the tdescs would be deleted during the
>>> pop_all_targets_at_and_above, when the refcount of the remote_target
>>> gets to 0 and it gets deleted.  And the threads would be removed in
>>> generic_mourn_inferior just after.
>>>
>>> An idea could be to call generic_mourn_inferior before
>>> remote_unpush_target (no idea if it works).  Another one would be to
>>> get a temporary reference to the remote_target object in
>>> remote_unpush_target, just so that it outlives the threads.
>>> Or maybe we should say that it's a process target's responsibility to
>>> delete any thread it "owns" before getting deleted itself.
>>
>> Another question related to this popped while reading the following
>> patch.  When creating a gdbarch from a tdesc, the gdbarch keeps a
>> pointer to that tdesc (accessible through gdbarch_target_desc).  And
>> AFAIK, we never delete gdbarches.  So I suppose the gdbarch will refer a
>> stale target desc.  At first I thought it wouldn't be a problem in
>> practice, because while that gdbarch object still exists, nothing
>> references it (it is effectively leaked).  But then I remember that we
>> cache gdbarches to avoid creating arches with duplicate features.  So
>> later (let's say if you connect again to a remote), we might want to
>> create a gdbarch with the same features as before, and we'll dig up the
>> old gdbarch, that points to the now deleted tdesc.
> 
> The target descriptions for aarch64 are all cached using a map in gdb/aarch64-tdep.c:
> 
> /* All possible aarch64 target descriptors.  */
> static std::unordered_map <aarch64_features, target_desc *> tdesc_aarch64_map;
> 
> I don't think we should try to delete those, and they should live throughout the life of gdb (unless things get large, then we might consider cleanups).

When debugging natively with GDB, that's true.  When debugging remotely,
on GDBserver-side, that's true too.  But when debugging remotely, on
GDB-side, don't we create a new target_desc object for each read target
description?

Ok, I just saw in xml-tdesc.c:

  /* A record of every XML description we have parsed.  We never discard
     old descriptions, because we never discard gdbarches.  As long as we
     have a gdbarch referencing this description, we want to have a copy
     of it here, so that if we parse the same XML document again we can
     return the same "struct target_desc *"; if they are not singletons,
     then we will create unnecessary duplicate gdbarches.  See
     gdbarch_list_lookup_by_info.  */

  static std::unordered_map<std::string, target_desc_up> xml_cache;

So, at least, a remote sending the same exact XML over and over will
lead to the same target_desc object being reused.  And there won't be
lifetime issues, since the target_desc created from XML also live
forever.  So I guess we're good.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-03  2:44           ` Thiago Jung Bauermann
@ 2023-02-03 16:29             ` Andrew Burgess
  2023-02-04  6:08               ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-03 16:29 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Simon Marchi
  Cc: Thiago Jung Bauermann via Gdb-patches, Simon Marchi

Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:

> Simon Marchi <simark@simark.ca> writes:
>
>> On 2/2/23 14:52, Thiago Jung Bauermann wrote:
>>> 
>>> Simon Marchi <simark@simark.ca> writes:
>>> 
>>>>> Having read some of the later patches, I have some additional thoughts
>>>>> here:
>>>>>
>>>>> I think we should make it explicit here that IDs are connection wide,
>>>>> not per-process.  We should also make it clear that GDB might[1] cache
>>>>> target descriptions per remote connection, and so a remote target should
>>>>> not reuse a target description ID except where the target description is
>>>>> identical.
>>> 
>>> Ah, good point. I will make that clarification.
>>> 
>>>>> [1] I say "GDB might" here because if we say "GDB will" then this would
>>>>> imply each target description will only be asked for once.  And I
>>>>> figure, why be overly restrictive.
>>>>
>>>> Thanks for pointing this out, I had the same thought while reading the
>>>> patch.
>>>>
>>>> In my original idea, I imagined that target description IDs could be
>>>> some hashes computed from the XML content (a bit like git hashes or ELF
>>>> build IDs), such that a given target description would always have the
>>>> same ID.  This would give clients the possibility to cache target
>>>> descriptions locally, a bit like the index cache.  It did sound nice,
>>>> but perhaps it's not really important.
>>> 
>>> Ah, sorry I misunderstood this part of your suggestion. I thought that
>>> the caching was supposed to be limited to the duration of the connection,
>>> and thus the m_tdescs map in struct remote state would be enough to
>>> provide that functionality. Do you mean that the cache should be on
>>> disk, so that it survives GDB quitting? I can look into that if you want
>>> and implement it, if not complicated.
>>
>> To be clear, I'm not asking you to implement an on-disk cache, I'm just
>> trying to think about what the limitations of the proposed solution are.
>> Because mistakes or shortcomings introduced in the remote protocol (like
>> any API / ABI meant to be stable) are difficult to fix afterwards.  If
>> there is a chance we want to do an on-disk cache (or share a cache
>> between multiple concurrent connections), we should think about that
>> now.
>
> Indeed, that's a good idea.
>
>> On one hand, perhaps we consider that target descriptions are small
>> enough that there's no point in having a persistent cache like that.
>> The time to fetch each target description once per connection is
>> probably insignificant.
>
> I don't have a good intuition about that. My uneducated guess is that
> it's not worth it, but as you say I think it's a good idea to leave the
> door open if we can.
>
>> On the other hand, perhaps doing the hash approach is easy enough that
>> we might as well do it, and that just leaves more doors open.  In my
>> mind, as a start, we could just pass the XML of the tdesc through a
>> sha256 function, possibly doing something more sophisticated later (this
>> means the hash of a given tdesc could change over time, but still two
>> identical hashes mean identical tdescs).  However, I don't think there
>> are sha256 functions built in on the OSes we want to support, so we'd
>> have to depend on some external library.  And that complicates things
>> quite a bit...  We already have a CRC32 function in gdbserver, but I
>> don't know if that's good enough to be confident there won't be
>> collisions.
>
> I tried to research this a bit, but I'm not confident enough in my
> knowledge of the subject to reach a conclusion. I only know enough about
> hashes to be dangerous. I did find a hash testsuite called SMhasher
> which seems to be well regarded, and its website¹ has
> reports for CRC32², which shows that it fails many collision and
> distribution bias tests. So it doesn't look like it is very reliable for
> using as a hash.
>
> We do support libxxhash as an optional dependency, so we could use that
> if gdbserver is linked with it. Its SMhasher report³ looks good, IUUC
> (but not the 32 bits version though⁴).
>
> We could also vendor coreutils's lib/sha256.[ch] files. They're 660
> lines in total.
>
>>> In this case, I think the tdesc ID should be of the format
>>> <prefix>:<hex number>, so that <prefix> can be “sha1”, “sha256” etc to
>>> indicate that <hex number> is a hash with the given algo, or even
>>> “number” to indicate that it's a simple integer like it is today.
>>> 
>>> Perhaps we can do the prefix thing even if not implementing the cache,
>>> to leave the possibility of adding it in the future?
>>
>> I think I would choose between hash and number, but not do both, I don't
>> see the need to have both.
>
> I suggested a prefix to designate an integer ID as a way to implement
> only this possibility for now, but which would allow implementing hash
> IDs later, as additional prefixes. Or another possibility is that if we
> later decide to support hashes, we could add a separate protocol feature
> to signal that.

So, I'd also be in favour of supporting the simple "just a number"
scheme.  Not everything that talks to GDB is our GDBServer, and not
every target might have the right hashing library.  I'd hate to force
folk to have to implement some hashing code, just to use this feature of
the remote protocol.

I have a proposal for how to negotiate different ID types without
adding a prefix to every ID sent from gdbserver...

We don't need to use a prefix in the actual ID.  I believe you're
already adding a qSupported feature for per-thread-tdesc.  The
qSupported mechanism already supports value passing.

So, we could pass a value back and forth in the qSupported negotiation
where GDB and GDBServer can agree on a numbering scheme.

If GDB sends out:

  per-thread-tdesc=value

Where `value` is a comma separated list of letters, each letter
representing a scheme that GDB understands:

  N: Each ID is a number,

  H: Each ID is a hash of the target description contents.

Then GDBServer replies with:

  per-thread-tdesc=value

Where `value` is a single letter drawn from the set of letters that GDB
sent out, this is the scheme that GDBServer will be using.  Thus,
GDBServer might reply with _one_ of the following:

  per-thread-tdesc=N
  per-thread-tdesc=H

If GDB only offers a scheme that GDBServer doesn't understand, e.g. GDB
sends:

  per-thread-tdesc=X

Then GDBServer just doesn't send this feature back, effectively claiming
it doesn't support 'per-thread-tdesc'.

The great thing about this is that the hard work here is all in writing
the documentation.

To begin with you _only_ need to support the 'N' scheme.  GDB always
sends out just 'per-thread-tdesc=N', GDBServer just checks that the
value is 'N', and replies 'per-thread-tdesc=N'.  GDB checks that the
return value is also 'N', and then we carry on as before.  BUT, we now
have a planned route to add more complex schemes in the future.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-03 13:19           ` Simon Marchi
@ 2023-02-03 16:33             ` Andrew Burgess
  0 siblings, 0 replies; 94+ messages in thread
From: Andrew Burgess @ 2023-02-03 16:33 UTC (permalink / raw)
  To: Simon Marchi, Luis Machado, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

Simon Marchi <simark@simark.ca> writes:

> On 2/3/23 06:27, Luis Machado wrote:
>> On 2/1/23 20:16, Simon Marchi via Gdb-patches wrote:
>>>> IIUC, the tdescs would be deleted during the
>>>> pop_all_targets_at_and_above, when the refcount of the remote_target
>>>> gets to 0 and it gets deleted.  And the threads would be removed in
>>>> generic_mourn_inferior just after.
>>>>
>>>> An idea could be to call generic_mourn_inferior before
>>>> remote_unpush_target (no idea if it works).  Another one would be to
>>>> get a temporary reference to the remote_target object in
>>>> remote_unpush_target, just so that it outlives the threads.
>>>> Or maybe we should say that it's a process target's responsibility to
>>>> delete any thread it "owns" before getting deleted itself.
>>>
>>> Another question related to this popped while reading the following
>>> patch.  When creating a gdbarch from a tdesc, the gdbarch keeps a
>>> pointer to that tdesc (accessible through gdbarch_target_desc).  And
>>> AFAIK, we never delete gdbarches.  So I suppose the gdbarch will refer a
>>> stale target desc.  At first I thought it wouldn't be a problem in
>>> practice, because while that gdbarch object still exists, nothing
>>> references it (it is effectively leaked).  But then I remember that we
>>> cache gdbarches to avoid creating arches with duplicate features.  So
>>> later (let's say if you connect again to a remote), we might want to
>>> create a gdbarch with the same features as before, and we'll dig up the
>>> old gdbarch, that points to the now deleted tdesc.
>> 
>> The target descriptions for aarch64 are all cached using a map in gdb/aarch64-tdep.c:
>> 
>> /* All possible aarch64 target descriptors.  */
>> static std::unordered_map <aarch64_features, target_desc *> tdesc_aarch64_map;
>> 
>> I don't think we should try to delete those, and they should live throughout the life of gdb (unless things get large, then we might consider cleanups).
>
> When debugging natively with GDB, that's true.  When debugging remotely,
> on GDBserver-side, that's true too.  But when debugging remotely, on
> GDB-side, don't we create a new target_desc object for each read target
> description?
>
> Ok, I just saw in xml-tdesc.c:
>
>   /* A record of every XML description we have parsed.  We never discard
>      old descriptions, because we never discard gdbarches.  As long as we
>      have a gdbarch referencing this description, we want to have a copy
>      of it here, so that if we parse the same XML document again we can
>      return the same "struct target_desc *"; if they are not singletons,
>      then we will create unnecessary duplicate gdbarches.  See
>      gdbarch_list_lookup_by_info.  */
>
>   static std::unordered_map<std::string, target_desc_up> xml_cache;
>
> So, at least, a remote sending the same exact XML over and over will
> lead to the same target_desc object being reused.  And there won't be
> lifetime issues, since the target_desc created from XML also live
> forever.  So I guess we're good.

Simon,

Thanks for chasing this down.  I guess my concerns about object life
time are addressed then.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-02-01 20:20     ` Simon Marchi
  2023-02-03 11:31       ` Luis Machado
@ 2023-02-03 16:38       ` Andrew Burgess
  2023-02-03 19:07         ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Andrew Burgess @ 2023-02-03 16:38 UTC (permalink / raw)
  To: Simon Marchi, Thiago Jung Bauermann via Gdb-patches; +Cc: Thiago Jung Bauermann

Simon Marchi <simark@simark.ca> writes:

>> I guess the point I'm driving towards is that maybe instead of a new
>> gdbarch method we should add something like gdbarch_from_tdesc into
>> arch-utils.c (like we have gdbarch_from_bfd and gdbarch_find_by_info),
>> which just does a lookup from tdesc.
>
> One thing I would like to add: I presume that this process
> (gdbarch_find_by_info) is somewhat expensive.  Is there an easy way to
> short-circuit things earlier?  Maybe if we detect that a thread has the
> same target desc id as before, we can avoid recomputing the gdbarch?
> Or, we can cache the gdbarch in the remote_target.

Or could we cache the gdbarch in the tdesc itself?  As you pointed out
for the previous patch, passing the same XML string will result in the
same tdesc object.  So if we had gdbarch_from_tdesc, this can do the
expensive gdbarch lookup, then store the gdbarch in the tdesc object.

Next time we call gdbarch_from_tdesc we can just check for a cached
gdbarch within the tdesc and return that...

...maybe?

Thanks,
Andrew




>                                                      The
> remote_target::m_tdescs would hold both the target desc and
> corresponding gdbarch as values, instead of just the target desc.
> Actually, maybe the remote target wouldn't need to hold the target_desc
> at all, once it has the gdbarch.  Other than maybe for lifetime reasons,
> which are discussed with the previous patch.
>
> Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely
  2023-02-03 16:38       ` Andrew Burgess
@ 2023-02-03 19:07         ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-03 19:07 UTC (permalink / raw)
  To: Andrew Burgess, Thiago Jung Bauermann via Gdb-patches
  Cc: Thiago Jung Bauermann

On 2/3/23 11:38, Andrew Burgess wrote:
> Simon Marchi <simark@simark.ca> writes:
> 
>>> I guess the point I'm driving towards is that maybe instead of a new
>>> gdbarch method we should add something like gdbarch_from_tdesc into
>>> arch-utils.c (like we have gdbarch_from_bfd and gdbarch_find_by_info),
>>> which just does a lookup from tdesc.
>>
>> One thing I would like to add: I presume that this process
>> (gdbarch_find_by_info) is somewhat expensive.  Is there an easy way to
>> short-circuit things earlier?  Maybe if we detect that a thread has the
>> same target desc id as before, we can avoid recomputing the gdbarch?
>> Or, we can cache the gdbarch in the remote_target.
> 
> Or could we cache the gdbarch in the tdesc itself?  As you pointed out
> for the previous patch, passing the same XML string will result in the
> same tdesc object.  So if we had gdbarch_from_tdesc, this can do the
> expensive gdbarch lookup, then store the gdbarch in the tdesc object.
> 
> Next time we call gdbarch_from_tdesc we can just check for a cached
> gdbarch within the tdesc and return that...

Yeah, maybe.  The gdbarch points to the tdesc already, so this would add
a link in the other direction.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply
  2023-02-03 16:29             ` Andrew Burgess
@ 2023-02-04  6:08               ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-04  6:08 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: Simon Marchi, Simon Marchi, gdb-patches


Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org> writes:

> Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
>
>> I suggested a prefix to designate an integer ID as a way to implement
>> only this possibility for now, but which would allow implementing hash
>> IDs later, as additional prefixes. Or another possibility is that if we
>> later decide to support hashes, we could add a separate protocol feature
>> to signal that.
>
> So, I'd also be in favour of supporting the simple "just a number"
> scheme.  Not everything that talks to GDB is our GDBServer, and not
> every target might have the right hashing library.  I'd hate to force
> folk to have to implement some hashing code, just to use this feature of
> the remote protocol.

Yes, that is a good point.

> I have a proposal for how to negotiate different ID types without
> adding a prefix to every ID sent from gdbserver...
>
> We don't need to use a prefix in the actual ID.  I believe you're
> already adding a qSupported feature for per-thread-tdesc.  The
> qSupported mechanism already supports value passing.
>
> So, we could pass a value back and forth in the qSupported negotiation
> where GDB and GDBServer can agree on a numbering scheme.

    ⋮
  <snip>
    ⋮

> The great thing about this is that the hard work here is all in writing
> the documentation.

:-)

> To begin with you _only_ need to support the 'N' scheme.  GDB always
> sends out just 'per-thread-tdesc=N', GDBServer just checks that the
> value is 'N', and replies 'per-thread-tdesc=N'.  GDB checks that the
> return value is also 'N', and then we carry on as before.  BUT, we now
> have a planned route to add more complex schemes in the future.

This is a great idea! Thank you for coming up with it. I will implement
it for the next version of the patch series.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-03 10:57           ` Luis Machado
@ 2023-02-04  6:18             ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-04  6:18 UTC (permalink / raw)
  To: Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/2/23 02:54, Thiago Jung Bauermann wrote:
>> Luis Machado <luis.machado@arm.com> writes:
>> 
>>> On 2/1/23 16:21, Simon Marchi wrote:
>>>>
>>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>>> --- a/gdbserver/linux-low.h
>>>>>> +++ b/gdbserver/linux-low.h
>>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>>      /* Architecture-specific setup for the current thread.  */
>>>>>>      virtual void low_arch_setup () = 0;
>>>>>>    +  /* Allows arch-specific code to set the thread's target description when the
>>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>>> +     is necessary.  */
>>>>>> +  virtual const struct target_desc *
>>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>>
>>>>> I think the comment for this function is not correct.  The function does
>>>>> not SET the thread's target description, but just GETS a target
>>>>> description suitable for `thread`.  It's the caller's job to do the
>>>>> setting.
>>>> This comment also gave me pause.  How does a getter set something.  I
>>>> then understood that it allowed the arch-specific code to provide a
>>>> thread-specific tdesc.  I would suggest just:
>>>
>>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>>> So it doesn't set on its own, but it does allow something else to do
>>> it.
>> Yes, that's what was in my mind when I wrote the comment. But I agree
>> it's unclear, and I adopted Simon's suggested version.
>> 
>>>> The other thought I had while re-reading the patch is why do we need to
>>>> return and store nullptr if the thread target description is the same as
>>>> the main one for the process.  get_thread_tdesc could just return
>>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>>> store that same pointer in thread_info->tdesc.
>> We don't need to return and store nullptr if the thread target
>> description is the same as the main one for the process. Things will
>> work fine if we do as you suggest. IIRC my private branch worked liked
>> that for a while, before I changed it to the current version.
>> I changed it because I thought it was a clearer mental model if
>> thread_info->tdesc is nullptr when there's not thread-specific target
>> description. I can make the get_thread_tdesc method always return a
>> valid target description if you think it's better that way.
>> 
>>>> And get_thread_tdesc would just return that (in fact,
>>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>>> things more complicated down the road, but I can't think of anything.
>> Sorry, I don't understand this part. get_thread_tdesc is necessary
>> because it's the hook that allows arch-specific code to provide a target
>> description for the thread. I don't see how it can become unnecessary.
>> Perhaps you mean the get_thread_target_desc function? Sorry about the
>> names being so similar, I spent some time trying to think of a better
>> name for either the method or the function but failed.
>> In any case, it wouldn't be possible to make get_thread_target_desc just
>> return thread_info->tdesc because at least the way these patches are
>> currently written, when the inferior starts or a new thread of the
>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>> the process of obtaining the pc register), so we will need to cope with
>> that situation.
>> 
>>> Sounds reasonable.
>>>
>>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing
>>> given
>>> the SVE precedent. The process-wide target description/gdbarch no
>>> longer reflects the correct settings for each thread on AArch64's with SVE support.
>> In the first version of these patches I removed the process-wide target
>> description and moved it to thread_info, but it was a big patch that
>> touched many targets. I can bring it back if you think it's worth it
>
> No need. As Simon suggested, we can do this incrementally. I don't think we should hold
> off on
> this series' particular improvements so we can get the more general case sorted.

Sounds good to me. I'll be glad to work on a follow-up series with these
improvements after this one is done.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-03 11:11             ` Luis Machado
@ 2023-02-04 15:21               ` Thiago Jung Bauermann
  2023-02-06  9:07                 ` Luis Machado
  2023-02-06 20:29                 ` Pedro Alves
  0 siblings, 2 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-04 15:21 UTC (permalink / raw)
  To: Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/2/23 03:47, Simon Marchi wrote:
>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>> In any case, it wouldn't be possible to make get_thread_target_desc just
>>> return thread_info->tdesc because at least the way these patches are
>>> currently written, when the inferior starts or a new thread of the
>>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>>> the process of obtaining the pc register), so we will need to cope with
>>> that situation.
>> Ok.  Would it work if a new thread initially inherited the tdesc from
>> its process?
>> 
>
> It should be fine because the first time we fetch a process target
> description, it is eventually obtained from the first and only thread.
> So the SVE vector length should be correct.
>
> Any subsequent attempts to use the process' target description (the
> first one we obtained), after further stops, may end up using an
> incorrect description.
>
> I think this is handled correctly by the target architecture target
> hook though. But there are other places where this is potentially
> incorrect.
>
> For example...
>
> - When using gcore to dump a core file, GDB only dumps a single target
> description. While this might be correct for a target with a fixed
> target description or a AArch64 target that doesn't support SVE, it
> likely won't be correctly for one AArch64 target supporting SVE if its
> threads changed vector length mid-execution. Either we emit target
> description notes by thread, or we don't emit a target description
> note for those cases.
>
> - When loading the above/older gcore core files back, GDB will use a
> potentially incorrect target description. If we decide to emit
> per-thread target descriptions, it should be fine. Otherwise we may
> need to have a "thread architecture" hook for core files as well.
>
> - The remote has no concept of a thread architecture (Thiago is
> addressing this with this patch series).
>
> - AArch64 frames may have slightly different vg values, which means
> their gdbarches are different as well.
>
> Given the differences between two gdbarches are small, we mostly get
> away with it. But if there are further differences (different hooks,
> for example), I fear we may run into a situation where we use an
> incorrect gdbarch to call a particular hook.

Indeed, good points! Thank you for bringing them up. I can address core
file dumping/loading after this series.

Regarding frames with different vg values, it's important to be aware of
this discrepancy but IMHO it makes sense to work on it when it becomes
a problem...

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-03 11:13               ` Luis Machado
@ 2023-02-04 15:26                 ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-04 15:26 UTC (permalink / raw)
  To: Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/3/23 03:47, Thiago Jung Bauermann wrote:
>> Simon Marchi <simark@simark.ca> writes:
>>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>>> Luis Machado <luis.machado@arm.com> writes:
>>>>> Moving towards thread-specific target descriptions/gdbarch would
>>>>> be a positive thing given the SVE precedent. The process-wide
>>>>> target description/gdbarch no longer reflects the correct settings
>>>>> for each thread on AArch64's with SVE support.
>>>>
>>>> In the first version of these patches I removed the process-wide target
>>>> description and moved it to thread_info, but it was a big patch that
>>>> touched many targets. I can bring it back if you think it's worth it.
>>>
>>> At least for the register description, if we decide it's now a
>>> per-thread thing, what does it mean to have a process-wide description
>>> anyway?  I think it would make sense to get rid of it, that could help
>>> confirm our model works (and it would remove the chance of  using the
>>> wrong tdesc by mistake for a thread that has its own tdesc).  It's
>>> probably something that can be done incrementally though.
>>
>> Would it be done incrementally by keeping process_info->tdesc but
>> changing each target in turn to use thread_info->tdesc and ignore the
>> process_info one?
>
> Given only AArch64 has this requirement at the moment, it may be
> easier to leave the process-wide tdesc up until the point we can
> safely/easily switch to thread-specific ones.
>
> After that, AArch64 will have potentially distinct thread tdescs while
> other architectures will have threads sharing the same tdesc.

Ok, sounds good. Thanks for the clarification!

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-01  9:52   ` Luis Machado
@ 2023-02-05  0:06     ` Thiago Jung Bauermann
  2023-02-06  9:10       ` Luis Machado
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-05  0:06 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -80,6 +80,7 @@
>>   #include <unordered_map>
>>   #include "async-event.h"
>>   #include "gdbsupport/selftest.h"
>> +#include "xml-tdesc.h"
>>     /* The remote target.  */
>>   @@ -238,6 +239,16 @@ class remote_state
>>     /* Get the remote arch state for GDBARCH.  */
>>     struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
>>   +  /* Add new ID to the target description list.  The corresponding XML will be
>> +     requested soon.  */
>
> Will it be requested soon or can gdb just ignore it if the user
> doesn't switch to that thread?

In this patch it would be requested soon, right after the threads list
XML and the stop reply packet were parsed.

But in my local branch that will become v4 I implemented Andrew's
suggestion of getting the target descriptions on demand in
remote_state::get_tdesc so now GDB may indeed ignore it.

> If gdb can ignore it, then it might be nice to mention it here that
> gdb can chose to request it at any point in time, but may opt not to
> do it at all.

As a consequence of Andrew's suggestion, the add_tdesc_id method isn't
necessary anymore, so this comment isn't present anymore.

>> +  void add_tdesc_id (ULONGEST id);
>> +
>> +  /* Get the target description corresponding to remote protocol ID.  */
>
> s/remote protocol/remote target description?

I meant that in the sense of “ID that is used in the remote protocol”,
but I agree it's more confusing than helpful. I changed it to:

/* Get the target description corresponding to the given remote target
   description ID.  */

WDYT?

>> @@ -3814,6 +3844,13 @@ start_thread (struct gdb_xml_parser *parser,
>>     attr = xml_find_attribute (attributes, "handle");
>>     if (attr != NULL)
>>       item.thread_handle = hex2bin ((const char *) attr->value.get ());
>> +
>> +  attr = xml_find_attribute (attributes, "tdesc");
>> +  if (attr != NULL)
>
> s/NULL/nullptr

Fixed.

>> diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h
>> index 0fbfc7e043e9..c7cc97c5dfc0 100644
>> --- a/gdb/xml-tdesc.h
>> +++ b/gdb/xml-tdesc.h
>> @@ -38,6 +38,12 @@ const struct target_desc *file_read_description_xml (const char *filename);
>>     const struct target_desc *target_read_description_xml (struct target_ops *);
>>   +/* Read an XML target description with the given ID using OPS.  Parse it, and
>> +   return the parsed description.  */
>> +
>> +const struct target_desc *target_read_description_xml (struct target_ops *ops,
>> +						       ULONGEST id);
>> +
>>   /* Fetches an XML target description using OPS, processing includes,
>>      but not parsing it.  Used to dump whole tdesc as a single XML file.
>>      Returns the description on success, and a disengaged optional
>
> I noticed we're dealing with the target description id as ULONGEST on
> gdb's side, but as unsigned int on gdbserver's side.
>
> Should we make them the same, if possible?

My thinking was that since it's gdbserver that defines what the ID will
be, it can use a simpler type (2³² target descriptions should be enough
for anybody) since it knows what kind of IDs it will issue. But GDB
doesn't know what the remote stub will want to do, so it should use a
big type.

But with Andrew's idea of passing a value during target negotiation to
decide whether the ID will be a number or a hash, then we can use
unsigned int for both types.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-04 15:21               ` Thiago Jung Bauermann
@ 2023-02-06  9:07                 ` Luis Machado
  2023-02-06 12:15                   ` Thiago Jung Bauermann
  2023-02-06 20:29                 ` Pedro Alves
  1 sibling, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-06  9:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/4/23 15:21, Thiago Jung Bauermann wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 2/2/23 03:47, Simon Marchi wrote:
>>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>>> In any case, it wouldn't be possible to make get_thread_target_desc just
>>>> return thread_info->tdesc because at least the way these patches are
>>>> currently written, when the inferior starts or a new thread of the
>>>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>>>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>>>> the process of obtaining the pc register), so we will need to cope with
>>>> that situation.
>>> Ok.  Would it work if a new thread initially inherited the tdesc from
>>> its process?
>>>
>>
>> It should be fine because the first time we fetch a process target
>> description, it is eventually obtained from the first and only thread.
>> So the SVE vector length should be correct.
>>
>> Any subsequent attempts to use the process' target description (the
>> first one we obtained), after further stops, may end up using an
>> incorrect description.
>>
>> I think this is handled correctly by the target architecture target
>> hook though. But there are other places where this is potentially
>> incorrect.
>>
>> For example...
>>
>> - When using gcore to dump a core file, GDB only dumps a single target
>> description. While this might be correct for a target with a fixed
>> target description or a AArch64 target that doesn't support SVE, it
>> likely won't be correctly for one AArch64 target supporting SVE if its
>> threads changed vector length mid-execution. Either we emit target
>> description notes by thread, or we don't emit a target description
>> note for those cases.
>>
>> - When loading the above/older gcore core files back, GDB will use a
>> potentially incorrect target description. If we decide to emit
>> per-thread target descriptions, it should be fine. Otherwise we may
>> need to have a "thread architecture" hook for core files as well.
>>
>> - The remote has no concept of a thread architecture (Thiago is
>> addressing this with this patch series).
>>
>> - AArch64 frames may have slightly different vg values, which means
>> their gdbarches are different as well.
>>
>> Given the differences between two gdbarches are small, we mostly get
>> away with it. But if there are further differences (different hooks,
>> for example), I fear we may run into a situation where we use an
>> incorrect gdbarch to call a particular hook.
> 
> Indeed, good points! Thank you for bringing them up. I can address core
> file dumping/loading after this series.

I have an upcoming patch for SME that should address this for core files, but it still needs some testing.

> 
> Regarding frames with different vg values, it's important to be aware of
> this discrepancy but IMHO it makes sense to work on it when it becomes
> a problem...
> 

Indeed. It will be a problem for SME and streaming mode, but I have another upcoming patch to hopefully address this as well.


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML
  2023-02-05  0:06     ` Thiago Jung Bauermann
@ 2023-02-06  9:10       ` Luis Machado
  0 siblings, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-06  9:10 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

On 2/5/23 00:06, Thiago Jung Bauermann wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 1/30/23 04:45, Thiago Jung Bauermann via Gdb-patches wrote:
>>> --- a/gdb/remote.c
>>> +++ b/gdb/remote.c
>>> @@ -80,6 +80,7 @@
>>>    #include <unordered_map>
>>>    #include "async-event.h"
>>>    #include "gdbsupport/selftest.h"
>>> +#include "xml-tdesc.h"
>>>      /* The remote target.  */
>>>    @@ -238,6 +239,16 @@ class remote_state
>>>      /* Get the remote arch state for GDBARCH.  */
>>>      struct remote_arch_state *get_remote_arch_state (struct gdbarch *gdbarch);
>>>    +  /* Add new ID to the target description list.  The corresponding XML will be
>>> +     requested soon.  */
>>
>> Will it be requested soon or can gdb just ignore it if the user
>> doesn't switch to that thread?
> 
> In this patch it would be requested soon, right after the threads list
> XML and the stop reply packet were parsed.
> 
> But in my local branch that will become v4 I implemented Andrew's
> suggestion of getting the target descriptions on demand in
> remote_state::get_tdesc so now GDB may indeed ignore it.
> 
>> If gdb can ignore it, then it might be nice to mention it here that
>> gdb can chose to request it at any point in time, but may opt not to
>> do it at all.
> 
> As a consequence of Andrew's suggestion, the add_tdesc_id method isn't
> necessary anymore, so this comment isn't present anymore.
> 
>>> +  void add_tdesc_id (ULONGEST id);
>>> +
>>> +  /* Get the target description corresponding to remote protocol ID.  */
>>
>> s/remote protocol/remote target description?
> 
> I meant that in the sense of “ID that is used in the remote protocol”,
> but I agree it's more confusing than helpful. I changed it to:
> 
> /* Get the target description corresponding to the given remote target
>     description ID.  */
> 
> WDYT?
> 

Looks good!


>>> @@ -3814,6 +3844,13 @@ start_thread (struct gdb_xml_parser *parser,
>>>      attr = xml_find_attribute (attributes, "handle");
>>>      if (attr != NULL)
>>>        item.thread_handle = hex2bin ((const char *) attr->value.get ());
>>> +
>>> +  attr = xml_find_attribute (attributes, "tdesc");
>>> +  if (attr != NULL)
>>
>> s/NULL/nullptr
> 
> Fixed.
> 
>>> diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h
>>> index 0fbfc7e043e9..c7cc97c5dfc0 100644
>>> --- a/gdb/xml-tdesc.h
>>> +++ b/gdb/xml-tdesc.h
>>> @@ -38,6 +38,12 @@ const struct target_desc *file_read_description_xml (const char *filename);
>>>      const struct target_desc *target_read_description_xml (struct target_ops *);
>>>    +/* Read an XML target description with the given ID using OPS.  Parse it, and
>>> +   return the parsed description.  */
>>> +
>>> +const struct target_desc *target_read_description_xml (struct target_ops *ops,
>>> +						       ULONGEST id);
>>> +
>>>    /* Fetches an XML target description using OPS, processing includes,
>>>       but not parsing it.  Used to dump whole tdesc as a single XML file.
>>>       Returns the description on success, and a disengaged optional
>>
>> I noticed we're dealing with the target description id as ULONGEST on
>> gdb's side, but as unsigned int on gdbserver's side.
>>
>> Should we make them the same, if possible?
> 
> My thinking was that since it's gdbserver that defines what the ID will
> be, it can use a simpler type (2³² target descriptions should be enough
> for anybody) since it knows what kind of IDs it will issue. But GDB
> doesn't know what the remote stub will want to do, so it should use a
> big type.
> 
> But with Andrew's idea of passing a value during target negotiation to
> decide whether the ID will be a number or a hash, then we can use
> unsigned int for both types.
> 

Got it.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-06  9:07                 ` Luis Machado
@ 2023-02-06 12:15                   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-06 12:15 UTC (permalink / raw)
  To: Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/4/23 15:21, Thiago Jung Bauermann wrote:
>> Luis Machado <luis.machado@arm.com> writes:
>>
>>> On 2/2/23 03:47, Simon Marchi wrote:
>>>> Ok.  Would it work if a new thread initially inherited the tdesc from
>>>> its process?
>>>>
>>>
>>> It should be fine because the first time we fetch a process target
>>> description, it is eventually obtained from the first and only thread.
>>> So the SVE vector length should be correct.
>>>
>>> Any subsequent attempts to use the process' target description (the
>>> first one we obtained), after further stops, may end up using an
>>> incorrect description.
>>>
>>> I think this is handled correctly by the target architecture target
>>> hook though. But there are other places where this is potentially
>>> incorrect.
>>>
>>> For example...
>>>
>>> - When using gcore to dump a core file, GDB only dumps a single target
>>> description. While this might be correct for a target with a fixed
>>> target description or a AArch64 target that doesn't support SVE, it
>>> likely won't be correctly for one AArch64 target supporting SVE if its
>>> threads changed vector length mid-execution. Either we emit target
>>> description notes by thread, or we don't emit a target description
>>> note for those cases.
>>>
>>> - When loading the above/older gcore core files back, GDB will use a
>>> potentially incorrect target description. If we decide to emit
>>> per-thread target descriptions, it should be fine. Otherwise we may
>>> need to have a "thread architecture" hook for core files as well.
>>>
>>> - The remote has no concept of a thread architecture (Thiago is
>>> addressing this with this patch series).
>>>
>>> - AArch64 frames may have slightly different vg values, which means
>>> their gdbarches are different as well.
>>>
>>> Given the differences between two gdbarches are small, we mostly get
>>> away with it. But if there are further differences (different hooks,
>>> for example), I fear we may run into a situation where we use an
>>> incorrect gdbarch to call a particular hook.
>> Indeed, good points! Thank you for bringing them up. I can address core
>> file dumping/loading after this series.
>
> I have an upcoming patch for SME that should address this for core
> files, but it still needs some testing.
>
>> Regarding frames with different vg values, it's important to be aware of
>> this discrepancy but IMHO it makes sense to work on it when it becomes
>> a problem...
>>
>
> Indeed. It will be a problem for SME and streaming mode, but I have
> another upcoming patch to hopefully address this as well.

Nice! Thank you.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support
  2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
                   ` (7 preceding siblings ...)
  2023-01-30  4:45 ` [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors Thiago Jung Bauermann
@ 2023-02-06 19:11 ` Pedro Alves
  2023-02-06 20:05   ` Simon Marchi
  8 siblings, 1 reply; 94+ messages in thread
From: Pedro Alves @ 2023-02-06 19:11 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches

On 2023-01-30 4:45 a.m., Thiago Jung Bauermann via Gdb-patches wrote:
> Hello,
> 
> This is version 3 of the patch series adding support to gdbserver for
> inferiors that change the SVE vector length at runtime. This is already
> supported by GDB, but not by gdbserver. Version 2 was posted here:
> 
> https://inbox.sourceware.org/gdb-patches/20221126020452.1686509-1-thiago.bauermann@linaro.org/
> 
> This version incorporates the review comments from v2 (thanks!). The
> biggest change is that it implements Simon's idea¹:
> 
>> If it's the case, that we need to extend the RSP to allow fetching
>> per-thread tdesc, here's the idea I had in mind for a while, to avoid
>> adding too much overhead.  Stop replies and the qXfer:threads:read reply
>> could include a per-thread tdesc identifier.  That tdesc identifier
>> would be something short, either an incrementing number, or some kind of
>> hash of the tdesc.  It would be something opaque chosen by the stub.  A
>> new packet would be introduced to allow GDB to request the XML given
>> that ID.  On the GDB side, GDB would request the XML when encountering a
>> tdesc ID it doesn't know about, and then cache the result.
> 
> The only difference from the above in this series is that instead of
> creating a new packet to allow GDB to request the XML given the ID, I'm
> extending the qXfer:features:read request: GDB can send "target-id-%u.xml"
> as the annex, where %u is the target description ID. Please let me know if
> you think a separate packet would be better. The remote protocol changes
> are documented in patch 5.
> 
> I had to drop the Reviewed-by tags from some patches because they have some
> significant changes from the version that was reviewed.
> 
> There's also a new testcase exercising the case of an inferior's thread
> changing its SVE vector length. The previous version of this series failed
> the testcase, but this one passes it.
> 
> With this series applied, gdb.arch/aarch64-sve.exp passes all tests on
> extended-remote aarch64-linux. Without them, it fails tests after the
> testcase changes the vector length.
> 
> Tested on native and extended-remote aarch64-linux, x86_64-linux and
> armv7l-linux-gnueabihf (the last one on QEMU TCG).
> 
> ¹ https://inbox.sourceware.org/gdb-patches/559069a3-f3ce-2059-bf4a-44add43979f7@simark.ca/
> 

Ah!  I had also suggested to you something like that at the Cauldron (when we were in line
for lunch.  :-D  However, IIRC, I had suggested that we should be able to cache the tdesc by filename.

Let me explain -- when we fetch a target description, we actually tell the server
to retrieve a tdesc _by a given filename_.  By default, we ask for target.xml, like this:

 qXfer:features:read:target.xml

but then, the retrieved target.xml file may "xi:include" some other file, like for example these do:

 gdb/features/s390-linux64.xml:14:  <xi:include href="s390-core64.xml"/>
 gdb/features/s390-linux64.xml:15:  <xi:include href="s390-acr.xml"/>
 gdb/features/s390-linux64.xml:16:  <xi:include href="s390-fpr.xml"/>

(try grepping for xi:include in the gdb/features/ dir for a lot more hits.)

and so when processing each of those xi:include's, gdb sends another qXfer:features:read packet,
with the corresponding included filename, like e.g., 

  qXfer:features:read:s390-core64.xml

Here's what the manual says:

 @item qXfer:features:read:@var{annex}:@var{offset},@var{length}
 @anchor{qXfer target description read}
 Access the @dfn{target description}.  @xref{Target Descriptions}.  The
 annex specifies which XML document to access.  The main description is
 always loaded from the @samp{target.xml} annex.

So basically I am suggesting that instead a new ID mechanism, we should be able to
use the preexisting annex/filename concept as key.  That means that the stop reply and
the thread listing would include a new "tdesc=foo.xml" attribute, instead of this
ID that then is defined to map to "target-id-%u.xml", which is basically admitting
that tdesc filenames exist anyhow.

I admit I haven't yet read the patches at all yet (of any series version), but
I'd like bring this up already, in case it helps with saving wasted effort.

Pedro Alves

> Changes since v2:
> 
> - Patch “gdbserver: Add assert in find_register_by_number”
>   - Rewritten to follow Simon's suggestion of putting the assert in another
>     function.
> - Patch “gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap”
>   - As suggested by Simon, directly access thread_info::id rather than use
>     pid_of.
>   - Also as suggested by Simon, updated doc comment of
>     process_stratum_target::read_auxv.
> - Patch “gdbserver/linux-aarch64: Factor out function to get aarch64_features”
>   - As suggested by Simon, directly access thread_info::id rather than use
>     lwpid_of.
>   - Also as suggested by Simon, added doc comment for
>     aarch64_get_arch_features.
> - Patch “gdbserver/linux-aarch64: When thread stops, update its target description”
>   - As suggested by Luis, added doc comments to thread_info::tdesc and
>     arch_process_info::has_sve.
>   - As suggested by Simon, renamed arch_update_tdesc to get_thread_tdesc,
>     and return a target_desc pointer (or nullptr) instead of one wrapped in
>     gdb::optional.  The code was changed a bit as well.
>   - As suggested by Luis, expanded doc comment of get_thread_tdesc.
>   - As suggested by Luis, abstracted away trying to fetch a tdesc from a
>     thread and then from a process to a new function
>     "get_thread_target_desc".
>   - Export free_register_cache_thread in gdbserver/regcache.h.
>   - Use free_register_cache_thread in linux_process_target::filter_event to
>     implement Simon's suggestion of only freeing the regcache for the
>     thread with a different tdesc.
> - “gdb/aarch64: Factor out most of the thread_architecture method”
>   - Dropped this patch. It's not needed anymore.
> - “gdbserver: Transmit target description ID in thread list and stop reply”
>   - New patch.
> - “gdb/remote: Parse and use tdesc field in stop reply and threads list XML”
>   - New patch.
> - “gdb/aarch64: Detect vector length changes when debugging remotely”
>   - As suggested by Luis, clarified in the patch description that this patch improves
>     debugging programs remotely. Also, reworded description somewhat.
>   - As suggested by Luis, changed VL references in comments to VG. Also reworded a bit the
>     description of the update_architecture gdbarch method.
>   - Changed the update_architecture gdbarch method (and consequently also
>     aarch64_update_architecture) to take a target description instead of a vector of
>     cached_reg_t.
>   - Changed remote_target::update_thread_list to get the thread target description from
>     the remote target.
>   - Changed remote_target::process_stop_reply to get the thread target description from
>     the remote target.
>   - Renamed remote_thread_info::expedited_arch to arch.
>   - Changed code of remote_target::thread_architecture to be a little bit clearer, and
>     added doc comment.
> - “gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors”
>   - New patch.
> 
> Thiago Jung Bauermann (8):
>   gdbserver: Add assert in find_register_by_number
>   gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
>   gdbserver/linux-aarch64: Factor out function to get aarch64_features
>   gdbserver/linux-aarch64: When thread stops, update its target
>     description
>   gdbserver: Transmit target description ID in thread list and stop
>     reply
>   gdb/remote: Parse tdesc field in stop reply and threads list XML
>   gdb/aarch64: Detect vector length changes when debugging remotely
>   gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE
>     inferiors
> 
>  gdb/aarch64-tdep.c                            |  20 +++
>  gdb/arch-utils.c                              |   8 +
>  gdb/arch-utils.h                              |   4 +
>  gdb/doc/gdb.texinfo                           |  27 ++-
>  gdb/features/threads.dtd                      |   1 +
>  gdb/gdbarch-components.py                     |  15 ++
>  gdb/gdbarch-gen.h                             |  10 ++
>  gdb/gdbarch.c                                 |  22 +++
>  gdb/remote.c                                  | 169 +++++++++++++++++-
>  gdb/testsuite/gdb.arch/aarch64-sve-threads.c  | 125 +++++++++++++
>  .../gdb.arch/aarch64-sve-threads.exp          |  70 ++++++++
>  gdb/xml-tdesc.c                               |  27 ++-
>  gdb/xml-tdesc.h                               |   6 +
>  gdbserver/gdbthread.h                         |   4 +
>  gdbserver/linux-aarch64-low.cc                |  68 +++++--
>  gdbserver/linux-arm-low.cc                    |   2 +-
>  gdbserver/linux-low.cc                        |  35 +++-
>  gdbserver/linux-low.h                         |  15 +-
>  gdbserver/linux-ppc-low.cc                    |   6 +-
>  gdbserver/linux-s390-low.cc                   |   2 +-
>  gdbserver/netbsd-low.cc                       |   4 +-
>  gdbserver/netbsd-low.h                        |   2 +-
>  gdbserver/regcache.cc                         |  14 +-
>  gdbserver/regcache.h                          |   4 +
>  gdbserver/remote-utils.cc                     |  57 ++++++
>  gdbserver/remote-utils.h                      |   9 +
>  gdbserver/server.cc                           |  20 ++-
>  gdbserver/server.h                            |   4 +
>  gdbserver/target.cc                           |   4 +-
>  gdbserver/target.h                            |   4 +-
>  gdbserver/tdesc.cc                            |  13 +-
>  gdbserver/tdesc.h                             |   5 +
>  32 files changed, 717 insertions(+), 59 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.c
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.exp
> 
> 
> base-commit: 6c76a6beade05f8b2ca93e939cf73da2917d379b
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
  2023-02-01  9:07   ` Luis Machado
  2023-02-01 10:54   ` Andrew Burgess
@ 2023-02-06 19:54   ` Pedro Alves
  2023-02-06 20:16     ` Simon Marchi
  2023-02-07 22:28     ` Thiago Jung Bauermann
  2 siblings, 2 replies; 94+ messages in thread
From: Pedro Alves @ 2023-02-06 19:54 UTC (permalink / raw)
  To: Thiago Jung Bauermann, gdb-patches; +Cc: Simon Marchi

On 2023-01-30 4:45 a.m., Thiago Jung Bauermann via Gdb-patches wrote:
> This patch doesn't change gdbserver behaviour, 

That's not actually true -- before the patch, we use the lwpid
of the current thread, while after the patch we always use the pid of the
process.

Here:

>  int
> -linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
> -				 unsigned int len)
> +linux_process_target::read_auxv (int pid, CORE_ADDR offset,
> +				 unsigned char *myaddr, unsigned int len)
>  {
>    char filename[PATH_MAX];
>    int fd, n;
> -  int pid = lwpid_of (current_thread);
>  
>    xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
>  

AFAICT by playing with debugging the gdb.threads/leader-exit.exp program,
you can't read /proc/PID/auxv if the leader thread has exited (is zombie).

Maybe that ends up not mattering in practice, not sure, but it is a
behavior change.

> but after later changes are
> made it avoids a null pointer dereference when HWCAP needs to be obtained
> for a specific process while current_thread is nullptr.
> 
> Fixing linux_read_auxv, linux_get_hwcap and linux_get_hwcap2 to take a PID
> parameter seems more correct than setting current_thread in one particular
> code path.
> 
> Changes are propagated to allow passing the new parameter through the call
> chain.
> 
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> ---
>  gdbserver/linux-aarch64-low.cc |  7 ++++---
>  gdbserver/linux-arm-low.cc     |  2 +-
>  gdbserver/linux-low.cc         | 18 +++++++++---------
>  gdbserver/linux-low.h          |  9 ++++-----
>  gdbserver/linux-ppc-low.cc     |  6 +++---
>  gdbserver/linux-s390-low.cc    |  2 +-
>  gdbserver/netbsd-low.cc        |  4 +---
>  gdbserver/netbsd-low.h         |  2 +-
>  gdbserver/server.cc            |  3 ++-
>  gdbserver/target.cc            |  4 ++--
>  gdbserver/target.h             |  4 ++--
>  11 files changed, 30 insertions(+), 31 deletions(-)
> 
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 3c09e086afee..2ed6e95562c5 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -846,12 +846,13 @@ aarch64_target::low_arch_setup ()
>    if (is_elf64)
>      {
>        struct aarch64_features features;
> +      int pid = current_thread->id.pid ();

You can also write:

  current_process ()->pid

which is a more to the point.  Also, sometimes there's a current
process, but not a current thread, so when we don't actually need a thread,
current_process() is better.

Pedro Alves


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support
  2023-02-06 19:11 ` [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Pedro Alves
@ 2023-02-06 20:05   ` Simon Marchi
  2023-02-06 21:06     ` Pedro Alves
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-06 20:05 UTC (permalink / raw)
  To: Pedro Alves, Thiago Jung Bauermann, gdb-patches


> Ah!  I had also suggested to you something like that at the Cauldron (when we were in line
> for lunch.  :-D  However, IIRC, I had suggested that we should be able to cache the tdesc by filename.
> 
> Let me explain -- when we fetch a target description, we actually tell the server
> to retrieve a tdesc _by a given filename_.  By default, we ask for target.xml, like this:
> 
>  qXfer:features:read:target.xml
> 
> but then, the retrieved target.xml file may "xi:include" some other file, like for example these do:
> 
>  gdb/features/s390-linux64.xml:14:  <xi:include href="s390-core64.xml"/>
>  gdb/features/s390-linux64.xml:15:  <xi:include href="s390-acr.xml"/>
>  gdb/features/s390-linux64.xml:16:  <xi:include href="s390-fpr.xml"/>
> 
> (try grepping for xi:include in the gdb/features/ dir for a lot more hits.)
> 
> and so when processing each of those xi:include's, gdb sends another qXfer:features:read packet,
> with the corresponding included filename, like e.g., 
> 
>   qXfer:features:read:s390-core64.xml
> 
> Here's what the manual says:
> 
>  @item qXfer:features:read:@var{annex}:@var{offset},@var{length}
>  @anchor{qXfer target description read}
>  Access the @dfn{target description}.  @xref{Target Descriptions}.  The
>  annex specifies which XML document to access.  The main description is
>  always loaded from the @samp{target.xml} annex.
> 
> So basically I am suggesting that instead a new ID mechanism, we should be able to
> use the preexisting annex/filename concept as key.  That means that the stop reply and
> the thread listing would include a new "tdesc=foo.xml" attribute, instead of this
> ID that then is defined to map to "target-id-%u.xml", which is basically admitting
> that tdesc filenames exist anyhow.

Just for completeness, how do you envision that working for SVE?
GDBserver would make up unique names for each configuration, like
"target-vq-%d.xml"?

If caching using filenames as keys, what is the scope of that namespace?
Per remote connection, per inferior?  I think it wouldn't work per
remote connection, because fetching "target.xml" for two different
inferiors could give two different answers.

Tangentially, I'm wondering if querying qXfer:features:read (mostly
fetching "target.xml" is going to become thread-sensitive.  In other
words, if GDB set the general thread to a thread with vq == A, gets
target.xml, then sets the general thread to a thread with vq == B, then
gets target.xml, is it going to get two different target descriptions?
I think that it would make sense to do so *.  Therefore, caching
target.xml per-inferior wouldn't be reliable either.  And if included
files could vary per thread, you'd have to make sure to give them unique
names.

* I think that since we're going towards thread-specific tdescs, the
  process-wide tdesc is going to become an obsolete concept, maybe just
  kept for backwards compatibility for when an old GDB not aware of
  per-thread tdescs talks to a new GDBserver aware of it, or vice versa.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-06 19:54   ` Pedro Alves
@ 2023-02-06 20:16     ` Simon Marchi
  2023-02-07 15:19       ` Pedro Alves
  2023-02-07 22:28     ` Thiago Jung Bauermann
  1 sibling, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-06 20:16 UTC (permalink / raw)
  To: Pedro Alves, Thiago Jung Bauermann, gdb-patches

On 2/6/23 14:54, Pedro Alves wrote:
> AFAICT by playing with debugging the gdb.threads/leader-exit.exp program,
> you can't read /proc/PID/auxv if the leader thread has exited (is zombie).
> 
> Maybe that ends up not mattering in practice, not sure, but it is a
> behavior change.

Even if we can't read /proc/PID/auxv if the leader thread has exited,
auxv is still a process-specific resource, not a thread-specific one,
right?  So, I suppose that the target interface could still accept a
pid, but linux_process_target could pick an arbitrary non-exited thread
from that pid to read auxv from?  Although I don't know what would
happen if that chose thread has just exited and we haven't consumed the
event yet.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-02  2:54         ` Thiago Jung Bauermann
  2023-02-02  3:47           ` Simon Marchi
  2023-02-03 10:57           ` Luis Machado
@ 2023-02-06 20:26           ` Pedro Alves
  2023-02-07 21:06             ` Thiago Jung Bauermann
  2 siblings, 1 reply; 94+ messages in thread
From: Pedro Alves @ 2023-02-06 20:26 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2023-02-02 2:54 a.m., Thiago Jung Bauermann via Gdb-patches wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 2/1/23 16:21, Simon Marchi wrote:
>>>
>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>> --- a/gdbserver/linux-low.h
>>>>> +++ b/gdbserver/linux-low.h
>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>     /* Architecture-specific setup for the current thread.  */
>>>>>     virtual void low_arch_setup () = 0;
>>>>>   +  /* Allows arch-specific code to set the thread's target description when the
>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>> +     is necessary.  */
>>>>> +  virtual const struct target_desc *
>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>
>>>> I think the comment for this function is not correct.  The function does
>>>> not SET the thread's target description, but just GETS a target
>>>> description suitable for `thread`.  It's the caller's job to do the
>>>> setting.
>>> This comment also gave me pause.  How does a getter set something.  I
>>> then understood that it allowed the arch-specific code to provide a
>>> thread-specific tdesc.  I would suggest just:
>>
>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>> So it doesn't set on its own, but it does allow something else to do
>> it.
> 
> Yes, that's what was in my mind when I wrote the comment. But I agree
> it's unclear, and I adopted Simon's suggested version.
> 
>>> The other thought I had while re-reading the patch is why do we need to
>>> return and store nullptr if the thread target description is the same as
>>> the main one for the process.  get_thread_tdesc could just return
>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>> store that same pointer in thread_info->tdesc.
> 
> We don't need to return and store nullptr if the thread target
> description is the same as the main one for the process. Things will
> work fine if we do as you suggest. IIRC my private branch worked liked
> that for a while, before I changed it to the current version.
> 
> I changed it because I thought it was a clearer mental model if
> thread_info->tdesc is nullptr when there's not thread-specific target
> description. I can make the get_thread_tdesc method always return a
> valid target description if you think it's better that way.
> 
>>> And get_thread_tdesc would just return that (in fact,
>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>> things more complicated down the road, but I can't think of anything.
> 
> Sorry, I don't understand this part. get_thread_tdesc is necessary
> because it's the hook that allows arch-specific code to provide a target
> description for the thread. I don't see how it can become unnecessary.
> 
> Perhaps you mean the get_thread_target_desc function? Sorry about the
> names being so similar, I spent some time trying to think of a better
> name for either the method or the function but failed.

Please drop the "get_" prefix from the class method, it doesn't really
add value, and we typically don't add it.  Most GDB getter/setters are
in  foo() / set_foo()  pair style, rather than get_foo() / set_foo().

A "get_" prefix is however typically used for global getter functions.

FWIW, I have the same thought as Simon while reading this.

> 
> In any case, it wouldn't be possible to make get_thread_target_desc just
> return thread_info->tdesc because at least the way these patches are
> currently written, when the inferior starts or a new thread of the
> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
> call get_thread_tdesc after the first stop (in get_thread_regcache, in
> the process of obtaining the pc register), so we will need to cope with
> that situation.
> 
>> Sounds reasonable.
>>
>> Moving towards thread-specific target descriptions/gdbarch would be a positive thing given
>> the SVE precedent. The process-wide target description/gdbarch no
>> longer reflects the correct settings for each thread on AArch64's with SVE support.
> 
> In the first version of these patches I removed the process-wide target
> description and moved it to thread_info, but it was a big patch that
> touched many targets. I can bring it back if you think it's worth it.
> 
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-04 15:21               ` Thiago Jung Bauermann
  2023-02-06  9:07                 ` Luis Machado
@ 2023-02-06 20:29                 ` Pedro Alves
  2023-02-07  8:11                   ` Luis Machado
  1 sibling, 1 reply; 94+ messages in thread
From: Pedro Alves @ 2023-02-06 20:29 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Luis Machado
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2023-02-04 3:21 p.m., Thiago Jung Bauermann via Gdb-patches wrote:
> 
> Luis Machado <luis.machado@arm.com> writes:
> 
>> On 2/2/23 03:47, Simon Marchi wrote:
>>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>>> In any case, it wouldn't be possible to make get_thread_target_desc just
>>>> return thread_info->tdesc because at least the way these patches are
>>>> currently written, when the inferior starts or a new thread of the
>>>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>>>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>>>> the process of obtaining the pc register), so we will need to cope with
>>>> that situation.
>>> Ok.  Would it work if a new thread initially inherited the tdesc from
>>> its process?
>>>
>>
>> It should be fine because the first time we fetch a process target
>> description, it is eventually obtained from the first and only thread.
>> So the SVE vector length should be correct.
>>
>> Any subsequent attempts to use the process' target description (the
>> first one we obtained), after further stops, may end up using an
>> incorrect description.
>>
>> I think this is handled correctly by the target architecture target
>> hook though. But there are other places where this is potentially
>> incorrect.
>>
>> For example...
>>
>> - When using gcore to dump a core file, GDB only dumps a single target
>> description. While this might be correct for a target with a fixed
>> target description or a AArch64 target that doesn't support SVE, it
>> likely won't be correctly for one AArch64 target supporting SVE if its
>> threads changed vector length mid-execution. Either we emit target
>> description notes by thread, or we don't emit a target description
>> note for those cases.
>>
>> - When loading the above/older gcore core files back, GDB will use a
>> potentially incorrect target description. If we decide to emit
>> per-thread target descriptions, it should be fine. Otherwise we may
>> need to have a "thread architecture" hook for core files as well.
>>
>> - The remote has no concept of a thread architecture (Thiago is
>> addressing this with this patch series).
>>
>> - AArch64 frames may have slightly different vg values, which means
>> their gdbarches are different as well.
>>
>> Given the differences between two gdbarches are small, we mostly get
>> away with it. But if there are further differences (different hooks,
>> for example), I fear we may run into a situation where we use an
>> incorrect gdbarch to call a particular hook.
> 
> Indeed, good points! Thank you for bringing them up. I can address core
> file dumping/loading after this series.
> 
> Regarding frames with different vg values, it's important to be aware of
> this discrepancy but IMHO it makes sense to work on it when it becomes
> a problem...
> 


Yeah, one thought that keeps crossing my mind is if really modeling all this
stuff as different target descriptions is really the best approach.  The Intel AMX
support posted on the list last year also ran into a similar problem, with the 
matrix registers height/width changing at runtime, and it is impractical (or really,
it really smells like the wrong approach) to have different target descriptions for
every potential matrix size.  Which is not unlike different SVE sizes.  It feels like
a single tdesc should be able to be a bit more dynamic.  It's a bit funny that ptrace
manages to work with a single registers interface, while we don't.

What if we extended the target description mechanism so that a single description
could describe all SVE sizes?  For example, what if a tdesc could describe the SVE
width/length as a dynamic property, retrieved from elsewhere, e.g., from another register?

BTW, for core files, where are we going to retrieve the SVE length from?

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support
  2023-02-06 20:05   ` Simon Marchi
@ 2023-02-06 21:06     ` Pedro Alves
  2023-02-07 13:49       ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Pedro Alves @ 2023-02-06 21:06 UTC (permalink / raw)
  To: Simon Marchi, Thiago Jung Bauermann, gdb-patches

On 2023-02-06 8:05 p.m., Simon Marchi via Gdb-patches wrote:
> 
>> Ah!  I had also suggested to you something like that at the Cauldron (when we were in line
>> for lunch.  :-D  However, IIRC, I had suggested that we should be able to cache the tdesc by filename.
>>
>> Let me explain -- when we fetch a target description, we actually tell the server
>> to retrieve a tdesc _by a given filename_.  By default, we ask for target.xml, like this:
>>
>>  qXfer:features:read:target.xml
>>
>> but then, the retrieved target.xml file may "xi:include" some other file, like for example these do:
>>
>>  gdb/features/s390-linux64.xml:14:  <xi:include href="s390-core64.xml"/>
>>  gdb/features/s390-linux64.xml:15:  <xi:include href="s390-acr.xml"/>
>>  gdb/features/s390-linux64.xml:16:  <xi:include href="s390-fpr.xml"/>
>>
>> (try grepping for xi:include in the gdb/features/ dir for a lot more hits.)
>>
>> and so when processing each of those xi:include's, gdb sends another qXfer:features:read packet,
>> with the corresponding included filename, like e.g., 
>>
>>   qXfer:features:read:s390-core64.xml
>>
>> Here's what the manual says:
>>
>>  @item qXfer:features:read:@var{annex}:@var{offset},@var{length}
>>  @anchor{qXfer target description read}
>>  Access the @dfn{target description}.  @xref{Target Descriptions}.  The
>>  annex specifies which XML document to access.  The main description is
>>  always loaded from the @samp{target.xml} annex.
>>
>> So basically I am suggesting that instead a new ID mechanism, we should be able to
>> use the preexisting annex/filename concept as key.  That means that the stop reply and
>> the thread listing would include a new "tdesc=foo.xml" attribute, instead of this
>> ID that then is defined to map to "target-id-%u.xml", which is basically admitting
>> that tdesc filenames exist anyhow.
> 
> Just for completeness, how do you envision that working for SVE?
> GDBserver would make up unique names for each configuration, like
> "target-vq-%d.xml"?

The string is free form, up to the server to decide what to use for names.  Could 
be that, or "aarch64-linux-sve-vq-%d.xml" or whatever.  Of course, for ports that
wouldn't generate the tdescs on the fly, you'd want to use the same name as the
real existing xml files that are embedded into gdbserver.

> 
> If caching using filenames as keys, what is the scope of that namespace?
> Per remote connection, per inferior?  I think it wouldn't work per
> remote connection, because fetching "target.xml" for two different
> inferiors could give two different answers.

Right, I think we'd make it per-inferior, at least by default, for backwards compatibility.

But we can also think about the server telling gdb about the scope if we want, with qSupported
or some such.  And then if the stub tells gdb that the scope is connection, the stub would also
tell gdb about the architecture of the main thread (in stop reply and thread listings),
say, "the-right-secondary-arch.xml" so gdb would retrieve "qXfer:features:read:the-right-secondary-arch.xml",
for that inferior, and not "qXfer:features:read:target.xml".  Basically, gdb only fetches
"target.xml" when it doesn't know better.

> 
> Tangentially, I'm wondering if querying qXfer:features:read (mostly
> fetching "target.xml" is going to become thread-sensitive.  In other
> words, if GDB set the general thread to a thread with vq == A, gets
> target.xml, then sets the general thread to a thread with vq == B, then
> gets target.xml, is it going to get two different target descriptions?
> I think that it would make sense to do so *.  

I am not so sure about that making sense.

As target.xml is documented as the main tdesc, it would continue that way,
with "main" meaning the tdesc that the initial thread has when the process
is first started.

> Therefore, caching
> target.xml per-inferior wouldn't be reliable either.  And if included
> files could vary per thread, you'd have to make sure to give them unique
> names.

With the numerical ID idea, you have to know which ID to read for the thread,
before you read it.  You don't just go and read the desc with ID 0 thinking that
0 is a different ID depending on thread, right?  So it's no different -- the stop
reply would say "tdesc=whatever-secondary-arch.xml", and GDB would fetch that xml
file if not cached yet, and use the cached version otherwise.

> 
> * I think that since we're going towards thread-specific tdescs, the
>   process-wide tdesc is going to become an obsolete concept, maybe just
>   kept for backwards compatibility for when an old GDB not aware of
>   per-thread tdescs talks to a new GDBserver aware of it, or vice versa.
> 
> Simon
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-06 20:29                 ` Pedro Alves
@ 2023-02-07  8:11                   ` Luis Machado
  2023-02-07 14:39                     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-07  8:11 UTC (permalink / raw)
  To: Pedro Alves, Thiago Jung Bauermann
  Cc: Simon Marchi, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/6/23 20:29, Pedro Alves wrote:
> On 2023-02-04 3:21 p.m., Thiago Jung Bauermann via Gdb-patches wrote:
>>
>> Luis Machado <luis.machado@arm.com> writes:
>>
>>> On 2/2/23 03:47, Simon Marchi wrote:
>>>> On 2/1/23 21:54, Thiago Jung Bauermann wrote:
>>>>> In any case, it wouldn't be possible to make get_thread_target_desc just
>>>>> return thread_info->tdesc because at least the way these patches are
>>>>> currently written, when the inferior starts or a new thread of the
>>>>> inferior is spawned thread_info->tdesc is nullptr. gdbserver will only
>>>>> call get_thread_tdesc after the first stop (in get_thread_regcache, in
>>>>> the process of obtaining the pc register), so we will need to cope with
>>>>> that situation.
>>>> Ok.  Would it work if a new thread initially inherited the tdesc from
>>>> its process?
>>>>
>>>
>>> It should be fine because the first time we fetch a process target
>>> description, it is eventually obtained from the first and only thread.
>>> So the SVE vector length should be correct.
>>>
>>> Any subsequent attempts to use the process' target description (the
>>> first one we obtained), after further stops, may end up using an
>>> incorrect description.
>>>
>>> I think this is handled correctly by the target architecture target
>>> hook though. But there are other places where this is potentially
>>> incorrect.
>>>
>>> For example...
>>>
>>> - When using gcore to dump a core file, GDB only dumps a single target
>>> description. While this might be correct for a target with a fixed
>>> target description or a AArch64 target that doesn't support SVE, it
>>> likely won't be correctly for one AArch64 target supporting SVE if its
>>> threads changed vector length mid-execution. Either we emit target
>>> description notes by thread, or we don't emit a target description
>>> note for those cases.
>>>
>>> - When loading the above/older gcore core files back, GDB will use a
>>> potentially incorrect target description. If we decide to emit
>>> per-thread target descriptions, it should be fine. Otherwise we may
>>> need to have a "thread architecture" hook for core files as well.
>>>
>>> - The remote has no concept of a thread architecture (Thiago is
>>> addressing this with this patch series).
>>>
>>> - AArch64 frames may have slightly different vg values, which means
>>> their gdbarches are different as well.
>>>
>>> Given the differences between two gdbarches are small, we mostly get
>>> away with it. But if there are further differences (different hooks,
>>> for example), I fear we may run into a situation where we use an
>>> incorrect gdbarch to call a particular hook.
>>
>> Indeed, good points! Thank you for bringing them up. I can address core
>> file dumping/loading after this series.
>>
>> Regarding frames with different vg values, it's important to be aware of
>> this discrepancy but IMHO it makes sense to work on it when it becomes
>> a problem...
>>
> 
> 
> Yeah, one thought that keeps crossing my mind is if really modeling all this
> stuff as different target descriptions is really the best approach.  The Intel AMX
> support posted on the list last year also ran into a similar problem, with the
> matrix registers height/width changing at runtime, and it is impractical (or really,
> it really smells like the wrong approach) to have different target descriptions for
> every potential matrix size.  Which is not unlike different SVE sizes.  It feels like
> a single tdesc should be able to be a bit more dynamic.  It's a bit funny that ptrace
> manages to work with a single registers interface, while we don't.

My understanding is that this was a bit hard to justify back when SVE was implemented, as it would
have to touch some other bits of the type system to create a sizeless type for SVE vectors, where
the size would be determined by context.

> 
> What if we extended the target description mechanism so that a single description
> could describe all SVE sizes?  For example, what if a tdesc could describe the SVE
> width/length as a dynamic property, retrieved from elsewhere, e.g., from another register?
> 
> BTW, for core files, where are we going to retrieve the SVE length from?

The thread-specific vector length should be available from the SVE register dump sections.



^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support
  2023-02-06 21:06     ` Pedro Alves
@ 2023-02-07 13:49       ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-07 13:49 UTC (permalink / raw)
  To: Pedro Alves, Thiago Jung Bauermann, gdb-patches

>> Tangentially, I'm wondering if querying qXfer:features:read (mostly
>> fetching "target.xml" is going to become thread-sensitive.  In other
>> words, if GDB set the general thread to a thread with vq == A, gets
>> target.xml, then sets the general thread to a thread with vq == B, then
>> gets target.xml, is it going to get two different target descriptions?
>> I think that it would make sense to do so *.  
> 
> I am not so sure about that making sense.
> 
> As target.xml is documented as the main tdesc, it would continue that way,
> with "main" meaning the tdesc that the initial thread has when the process
> is first started.

My interpretation of the work "main" here was "top-level".  At least, I
suppose that's what the original author meant, because I suppose it was
written assuming there's a single target description "tree" per process.
So there wouldn't need to be the need to differentiate "main" vs
"secondary".

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-07  8:11                   ` Luis Machado
@ 2023-02-07 14:39                     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-07 14:39 UTC (permalink / raw)
  To: Luis Machado
  Cc: Pedro Alves, Simon Marchi, Andrew Burgess,
	Thiago Jung Bauermann via Gdb-patches


Luis Machado <luis.machado@arm.com> writes:

> On 2/6/23 20:29, Pedro Alves wrote:
>> On 2023-02-04 3:21 p.m., Thiago Jung Bauermann via Gdb-patches wrote:
>>>
>>> Luis Machado <luis.machado@arm.com> writes:
>>>
>>>> On 2/2/23 03:47, Simon Marchi wrote:
>>>>> Ok.  Would it work if a new thread initially inherited the tdesc from
>>>>> its process?
>>>>>
>>>>
>>>> It should be fine because the first time we fetch a process target
>>>> description, it is eventually obtained from the first and only thread.
>>>> So the SVE vector length should be correct.
>>>>
>>>> Any subsequent attempts to use the process' target description (the
>>>> first one we obtained), after further stops, may end up using an
>>>> incorrect description.
>>>>
>>>> I think this is handled correctly by the target architecture target
>>>> hook though. But there are other places where this is potentially
>>>> incorrect.
>>>>
>>>> For example...
>>>>
>>>> - When using gcore to dump a core file, GDB only dumps a single target
>>>> description. While this might be correct for a target with a fixed
>>>> target description or a AArch64 target that doesn't support SVE, it
>>>> likely won't be correctly for one AArch64 target supporting SVE if its
>>>> threads changed vector length mid-execution. Either we emit target
>>>> description notes by thread, or we don't emit a target description
>>>> note for those cases.
>>>>
>>>> - When loading the above/older gcore core files back, GDB will use a
>>>> potentially incorrect target description. If we decide to emit
>>>> per-thread target descriptions, it should be fine. Otherwise we may
>>>> need to have a "thread architecture" hook for core files as well.
>>>>
>>>> - The remote has no concept of a thread architecture (Thiago is
>>>> addressing this with this patch series).
>>>>
>>>> - AArch64 frames may have slightly different vg values, which means
>>>> their gdbarches are different as well.
>>>>
>>>> Given the differences between two gdbarches are small, we mostly get
>>>> away with it. But if there are further differences (different hooks,
>>>> for example), I fear we may run into a situation where we use an
>>>> incorrect gdbarch to call a particular hook.
>>>
>>> Indeed, good points! Thank you for bringing them up. I can address core
>>> file dumping/loading after this series.
>>>
>>> Regarding frames with different vg values, it's important to be aware of
>>> this discrepancy but IMHO it makes sense to work on it when it becomes
>>> a problem...
>>>
>> Yeah, one thought that keeps crossing my mind is if really modeling
>> all this stuff as different target descriptions is really the best
>> approach. The Intel AMX support posted on the list last year also ran
>> into a similar problem, with the matrix registers height/width
>> changing at runtime, and it is impractical (or really, it really
>> smells like the wrong approach) to have different target descriptions
>> for every potential matrix size. Which is not unlike different SVE
>> sizes. It feels like a single tdesc should be able to be a bit more
>> dynamic. It's a bit funny that ptrace manages to work with a single
>> registers interface, while we don't.
>
> My understanding is that this was a bit hard to justify back when SVE
> was implemented, as it would have to touch some other bits of the type
> system to create a sizeless type for SVE vectors, where the size would
> be determined by context.

When I started working on these patches I read some older discussions on
the topic of SVE in the mailing list archives and I saw this idea.

So before going down the per-thread target description route I spent
some time trying to figure out a way to make the vector register size a
function of the contents of another register (a pseudo-register, in the
case of SVE), but I failed to see how I could do it.

I'm open to giving it another try but I would need some guidance. It
doesn't need to be detailed instructions, but a high level idea of how
it can be done would be very helpful.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-06 20:16     ` Simon Marchi
@ 2023-02-07 15:19       ` Pedro Alves
  2023-02-07 21:47         ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Pedro Alves @ 2023-02-07 15:19 UTC (permalink / raw)
  To: Simon Marchi, Thiago Jung Bauermann, gdb-patches



On 2023-02-06 8:16 p.m., Simon Marchi wrote:
> On 2/6/23 14:54, Pedro Alves wrote:
>> AFAICT by playing with debugging the gdb.threads/leader-exit.exp program,
>> you can't read /proc/PID/auxv if the leader thread has exited (is zombie).
>>
>> Maybe that ends up not mattering in practice, not sure, but it is a
>> behavior change.
> 
> Even if we can't read /proc/PID/auxv if the leader thread has exited,
> auxv is still a process-specific resource, not a thread-specific one,
> right?  

Right.

> So, I suppose that the target interface could still accept a
> pid, but linux_process_target could pick an arbitrary non-exited thread
> from that pid to read auxv from?  

Right, I think we can do that.

> Although I don't know what would
> happen if that chose thread has just exited and we haven't consumed the
> event yet.

Not sure either.  And I don't know what happens if the thread hasn't exited
when when we open /proc/TID/auxv and then the thread exits before we read
from the file.  These cases should be confirmed.  We may need to keep looking
for a thread until we manage to open & read the file or run out of threads.

BTW, I just noticed this "current_thread == NULL" check here:

 /* Handle qXfer:auxv:read.  */
 
 static int
 handle_qxfer_auxv (const char *annex,
 		   gdb_byte *readbuf, const gdb_byte *writebuf,
 		   ULONGEST offset, LONGEST len)
 {
   if (!the_target->supports_read_auxv () || writebuf != NULL)
     return -2;
 
   if (annex[0] != '\0' || current_thread == NULL)
     return -1;


Since we're removing the thread dependency, I think that check should be replaced by
current_process() == NULL instead.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-06 20:26           ` Pedro Alves
@ 2023-02-07 21:06             ` Thiago Jung Bauermann
  2023-02-09  2:46               ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-07 21:06 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Luis Machado, Simon Marchi, Andrew Burgess,
	Thiago Jung Bauermann via Gdb-patches


Pedro Alves <pedro@palves.net> writes:

> On 2023-02-02 2:54 a.m., Thiago Jung Bauermann via Gdb-patches wrote:
>> 
>> Luis Machado <luis.machado@arm.com> writes:
>> 
>>> On 2/1/23 16:21, Simon Marchi wrote:
>>>>
>>>>>> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
>>>>>> index 221de85aa2ee..b52eb23cc444 100644
>>>>>> --- a/gdbserver/linux-low.h
>>>>>> +++ b/gdbserver/linux-low.h
>>>>>> @@ -604,6 +604,12 @@ class linux_process_target : public process_stratum_target
>>>>>>     /* Architecture-specific setup for the current thread.  */
>>>>>>     virtual void low_arch_setup () = 0;
>>>>>>   +  /* Allows arch-specific code to set the thread's target description when the
>>>>>> +     inferior stops.  Returns nullptr if no thread-specific target description
>>>>>> +     is necessary.  */
>>>>>> +  virtual const struct target_desc *
>>>>>> +    get_thread_tdesc (const thread_info *thread);
>>>>>
>>>>> I think the comment for this function is not correct.  The function does
>>>>> not SET the thread's target description, but just GETS a target
>>>>> description suitable for `thread`.  It's the caller's job to do the
>>>>> setting.
>>>> This comment also gave me pause.  How does a getter set something.  I
>>>> then understood that it allowed the arch-specific code to provide a
>>>> thread-specific tdesc.  I would suggest just:
>>>
>>> FWIW, I read it as "the functions *allows* arch-specific code to set".
>>> So it doesn't set on its own, but it does allow something else to do
>>> it.
>> 
>> Yes, that's what was in my mind when I wrote the comment. But I agree
>> it's unclear, and I adopted Simon's suggested version.
>> 
>>>> The other thought I had while re-reading the patch is why do we need to
>>>> return and store nullptr if the thread target description is the same as
>>>> the main one for the process.  get_thread_tdesc could just return
>>>> process_info->tdesc if we don't need a separate tdesc, and we would
>>>> store that same pointer in thread_info->tdesc.
>> 
>> We don't need to return and store nullptr if the thread target
>> description is the same as the main one for the process. Things will
>> work fine if we do as you suggest. IIRC my private branch worked liked
>> that for a while, before I changed it to the current version.
>> 
>> I changed it because I thought it was a clearer mental model if
>> thread_info->tdesc is nullptr when there's not thread-specific target
>> description. I can make the get_thread_tdesc method always return a
>> valid target description if you think it's better that way.
>> 
>>>> And get_thread_tdesc would just return that (in fact,
>>>> get_thread_tdesc might not be necessary then). Perhaps it makes some
>>>> things more complicated down the road, but I can't think of anything.
>> 
>> Sorry, I don't understand this part. get_thread_tdesc is necessary
>> because it's the hook that allows arch-specific code to provide a target
>> description for the thread. I don't see how it can become unnecessary.
>> 
>> Perhaps you mean the get_thread_target_desc function? Sorry about the
>> names being so similar, I spent some time trying to think of a better
>> name for either the method or the function but failed.
>
> Please drop the "get_" prefix from the class method, it doesn't really
> add value, and we typically don't add it.  Most GDB getter/setters are
> in  foo() / set_foo()  pair style, rather than get_foo() / set_foo().
>
> A "get_" prefix is however typically used for global getter functions.

Ok, I will drop the prefix. Thank you for explaining the pattern.
I wasn't aware of it.

> FWIW, I have the same thought as Simon while reading this.

Ok, I'll change the code to always store a tdesc in thread_info even if
it's the same as the process-wide one. If both you and Simon thought
along the same lines it may be a more intuitive mental model than the
one I was considering.

That is, assuming we continue with the thread-specific tdesc approach
rather than the one which expands tdescs to allow describing one
register's type in terms of another one. I'll revisit my notes and think
more about this.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-07 15:19       ` Pedro Alves
@ 2023-02-07 21:47         ` Thiago Jung Bauermann
  2023-02-09  1:31           ` Simon Marchi
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-07 21:47 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Simon Marchi, gdb-patches


Pedro Alves <pedro@palves.net> writes:

> On 2023-02-06 8:16 p.m., Simon Marchi wrote:
>> On 2/6/23 14:54, Pedro Alves wrote:
>>> AFAICT by playing with debugging the gdb.threads/leader-exit.exp program,
>>> you can't read /proc/PID/auxv if the leader thread has exited (is zombie).
>>>
>>> Maybe that ends up not mattering in practice, not sure, but it is a
>>> behavior change.
>> 
>> Even if we can't read /proc/PID/auxv if the leader thread has exited,
>> auxv is still a process-specific resource, not a thread-specific one,
>> right?  
>
> Right.
>
>> So, I suppose that the target interface could still accept a
>> pid, but linux_process_target could pick an arbitrary non-exited thread
>> from that pid to read auxv from?  
>
> Right, I think we can do that.
>
>> Although I don't know what would
>> happen if that chose thread has just exited and we haven't consumed the
>> event yet.
>
> Not sure either. And I don't know what happens if the thread hasn't
> exited when when we open /proc/TID/auxv and then the thread exits
> before we read from the file. These cases should be confirmed. We may
> need to keep looking for a thread until we manage to open & read the
> file or run out of threads.

Ok, I will look into that. A simpler approach though would be to fetch
auxv at process starts and cache it for the duration of the debugging
session (since auxv doesn't change at runtime, AFAIK). Would that be a
good solution?

> BTW, I just noticed this "current_thread == NULL" check here:
>
>  /* Handle qXfer:auxv:read.  */
>  
>  static int
>  handle_qxfer_auxv (const char *annex,
>  		   gdb_byte *readbuf, const gdb_byte *writebuf,
>  		   ULONGEST offset, LONGEST len)
>  {
>    if (!the_target->supports_read_auxv () || writebuf != NULL)
>      return -2;
>  
>    if (annex[0] != '\0' || current_thread == NULL)
>      return -1;
>
>
> Since we're removing the thread dependency, I think that check should
> be replaced by current_process() == NULL instead.

Ok, I'll submit a patch with this change.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-06 19:54   ` Pedro Alves
  2023-02-06 20:16     ` Simon Marchi
@ 2023-02-07 22:28     ` Thiago Jung Bauermann
  1 sibling, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-07 22:28 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Simon Marchi


Pedro Alves <pedro@palves.net> writes:

> On 2023-01-30 4:45 a.m., Thiago Jung Bauermann via Gdb-patches wrote:
>> This patch doesn't change gdbserver behaviour, 
>
> That's not actually true -- before the patch, we use the lwpid
> of the current thread, while after the patch we always use the pid of the
> process.

Ah, indeed that is true. Thanks for pointing it out.

> Here:
>
>>  int
>> -linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
>> -				 unsigned int len)
>> +linux_process_target::read_auxv (int pid, CORE_ADDR offset,
>> +				 unsigned char *myaddr, unsigned int len)
>>  {
>>    char filename[PATH_MAX];
>>    int fd, n;
>> -  int pid = lwpid_of (current_thread);
>>  
>>    xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
>>  
>
> AFAICT by playing with debugging the gdb.threads/leader-exit.exp program,
> you can't read /proc/PID/auxv if the leader thread has exited (is zombie).
>
> Maybe that ends up not mattering in practice, not sure, but it is a
> behavior change.

We are talking about this in the other branch of this email thread so I
won't respond here, but I'll leave the quote above because I reference
it below.

>> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
>> index 3c09e086afee..2ed6e95562c5 100644
>> --- a/gdbserver/linux-aarch64-low.cc
>> +++ b/gdbserver/linux-aarch64-low.cc
>> @@ -846,12 +846,13 @@ aarch64_target::low_arch_setup ()
>>    if (is_elf64)
>>      {
>>        struct aarch64_features features;
>> +      int pid = current_thread->id.pid ();
>
> You can also write:
>
>   current_process ()->pid
>
> which is a more to the point.  Also, sometimes there's a current
> process, but not a current thread, so when we don't actually need a thread,
> current_process() is better.

In the case of the spots changed by this patch, we know that
current_thread is always set because, as can be seen in the first code
hunk you quoted, before this patch was applied
linux_process_target::read_auxv dereferenced it.

But I agree that it makes more sense to use current_process (). I'll
post a new patch with the change.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-07 21:47         ` Thiago Jung Bauermann
@ 2023-02-09  1:31           ` Simon Marchi
  2023-02-10  3:54             ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-09  1:31 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Pedro Alves; +Cc: gdb-patches

> Ok, I will look into that. A simpler approach though would be to fetch
> auxv at process starts and cache it for the duration of the debugging
> session (since auxv doesn't change at runtime, AFAIK). Would that be a
> good solution?

Not sure, you could be attaching, and at the moment you attach, the
leader has already exited.

Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-07 21:06             ` Thiago Jung Bauermann
@ 2023-02-09  2:46               ` Simon Marchi
  2023-02-10  3:29                 ` Thiago Jung Bauermann
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Marchi @ 2023-02-09  2:46 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Pedro Alves
  Cc: Luis Machado, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches


> That is, assuming we continue with the thread-specific tdesc approach
> rather than the one which expands tdescs to allow describing one
> register's type in terms of another one. I'll revisit my notes and think
> more about this.

Can we expand about this idea?  I think I like it, but I don't see 100%
how it would work.  I can imagine a vector of registers whose size
depends directly on the value of some other register that comes before,
like:

  <vector id="vec" type="some_type" count="some_other_register"/>

Here, "some_other_register" would be a scalar register that comes before
"vec", and whose value dictates directly the number of elements of
"vec".  But if you wanted to say that the number of elements in "vec" is
the value of some_other_register, times 2?  I guess we could write:

  <vector id="vec" type="some_type" count="some_other_register * 2"/>

.. but then we get in the realm of defining a grammar, building a
parser / evaluator, etc.

The type of the vector elements needs to be dynamic too, how do
we define that?

If the number of possibilities is known and static, we could have some
kind of "variant" type, where we list all the possible types, and select
among them at runtime based on the value of a preceding register.

If I understand correctly, all of this makes it so the size of the
response to the g packet will be dynamic too?

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-09  2:46               ` Simon Marchi
@ 2023-02-10  3:29                 ` Thiago Jung Bauermann
  2023-02-10 14:56                   ` Luis Machado
  0 siblings, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-10  3:29 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Pedro Alves, Luis Machado, Andrew Burgess,
	Thiago Jung Bauermann via Gdb-patches


Simon Marchi <simark@simark.ca> writes:

>> That is, assuming we continue with the thread-specific tdesc approach
>> rather than the one which expands tdescs to allow describing one
>> register's type in terms of another one. I'll revisit my notes and think
>> more about this.
>
> Can we expand about this idea?  I think I like it, but I don't see 100%
> how it would work.

Sorry, I can't expand much on it. I like it too, and as I mentioned in
another email I spent some time investigating how it could be done but
I wasn't able to make progress so I decided to do the per-thread tdesc
implementation instead.

I would be willing to try again but I would need help with high-level
design.

> I can imagine a vector of registers whose size
> depends directly on the value of some other register that comes before,
> like:
>
>   <vector id="vec" type="some_type" count="some_other_register"/>
>
> Here, "some_other_register" would be a scalar register that comes before
> "vec", and whose value dictates directly the number of elements of
> "vec".  But if you wanted to say that the number of elements in "vec" is
> the value of some_other_register, times 2?  I guess we could write:
>
>   <vector id="vec" type="some_type" count="some_other_register * 2"/>
>
> .. but then we get in the realm of defining a grammar, building a
> parser / evaluator, etc.

We could rein complexity in by supporting only the simplest of
expressions, e.g. only a very rigid form such as “<operand 1> <op>
<operand 2>” where <op> is one of the basic arithmetic operations.
If that turns out to not be enough then we can increasingly support more
complex operations.

> The type of the vector elements needs to be dynamic too, how do
> we define that?

This is the part where I got stuck, especially on how to make GDB's type
system allow expressing such a type.

> If the number of possibilities is known and static, we could have some
> kind of "variant" type, where we list all the possible types, and select
> among them at runtime based on the value of a preceding register.

Yes, in the case of SVE it's known and static. The maximum vector length
is an architectural feature of the processor, and GDB/gdbserver can get
it via ptrace in the NT_ARM_SVE regset. And it's always a multiple of
16.

It's an interesting idea. Perhaps it's enough, at least for SVE?

> If I understand correctly, all of this makes it so the size of the
> response to the g packet will be dynamic too?

We /could/ set the size of the g packet to always correspond to the
largest vector length possible but it would be a big overhead,
especially if there are many threads involved.

So in practice yes, it will be dynamic if we can help it.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap
  2023-02-09  1:31           ` Simon Marchi
@ 2023-02-10  3:54             ` Thiago Jung Bauermann
  0 siblings, 0 replies; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-10  3:54 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Pedro Alves, gdb-patches


Simon Marchi <simon.marchi@efficios.com> writes:

>> Ok, I will look into that. A simpler approach though would be to fetch
>> auxv at process starts and cache it for the duration of the debugging
>> session (since auxv doesn't change at runtime, AFAIK). Would that be a
>> good solution?
>
> Not sure, you could be attaching, and at the moment you attach, the
> leader has already exited.

Ah, that is true. I'll work on a solution following what Pedro
described, then.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-10  3:29                 ` Thiago Jung Bauermann
@ 2023-02-10 14:56                   ` Luis Machado
  2023-02-10 15:04                     ` Tom Tromey
  0 siblings, 1 reply; 94+ messages in thread
From: Luis Machado @ 2023-02-10 14:56 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Simon Marchi
  Cc: Pedro Alves, Andrew Burgess, Thiago Jung Bauermann via Gdb-patches

On 2/10/23 03:29, Thiago Jung Bauermann wrote:
> 
> Simon Marchi <simark@simark.ca> writes:
> 
>>> That is, assuming we continue with the thread-specific tdesc approach
>>> rather than the one which expands tdescs to allow describing one
>>> register's type in terms of another one. I'll revisit my notes and think
>>> more about this.
>>
>> Can we expand about this idea?  I think I like it, but I don't see 100%
>> how it would work.
> 
> Sorry, I can't expand much on it. I like it too, and as I mentioned in
> another email I spent some time investigating how it could be done but
> I wasn't able to make progress so I decided to do the per-thread tdesc
> implementation instead.
> 
> I would be willing to try again but I would need help with high-level
> design.
> 

My take on it is that it is he appropriate solution, and it would allow us to have a single target description for all the threads.

But it is also a larger effort that has to revamp some things in gdb's type system to allow for sizeless types, and that also has
implications in other areas of gdb.

Also, quite a bit of effort was put into supporting dynamic vector lengths mid-execution for SVE in native gdb, including
some new target hooks to adjust the architecture and the register cache format.

Changing this also means having to support the debugging stubs out there that already support SVE target descriptions. One can say
those stubs are not fully functional in terms of supporting dynamic vector lengths mid-execution, but they already produce target descriptions
in the current format (gdbserver is one of those stubs and QEMU is probably the second most important).

I'd be happy with an intermediate solution like what Thiago put together. It would solve a long-standing issue for SVE and gdbserver and it seems simpler at this point,
plus Thiago already put the effort to write the code.

>> I can imagine a vector of registers whose size
>> depends directly on the value of some other register that comes before,
>> like:
>>
>>    <vector id="vec" type="some_type" count="some_other_register"/>
>>
>> Here, "some_other_register" would be a scalar register that comes before
>> "vec", and whose value dictates directly the number of elements of
>> "vec".  But if you wanted to say that the number of elements in "vec" is
>> the value of some_other_register, times 2?  I guess we could write:
>>
>>    <vector id="vec" type="some_type" count="some_other_register * 2"/>
>>
>> .. but then we get in the realm of defining a grammar, building a
>> parser / evaluator, etc.
> 
> We could rein complexity in by supporting only the simplest of
> expressions, e.g. only a very rigid form such as “<operand 1> <op>
> <operand 2>” where <op> is one of the basic arithmetic operations.
> If that turns out to not be enough then we can increasingly support more
> complex operations.
> 
>> The type of the vector elements needs to be dynamic too, how do
>> we define that?
> 
> This is the part where I got stuck, especially on how to make GDB's type
> system allow expressing such a type.
> 
>> If the number of possibilities is known and static, we could have some
>> kind of "variant" type, where we list all the possible types, and select
>> among them at runtime based on the value of a preceding register.
> 
> Yes, in the case of SVE it's known and static. The maximum vector length
> is an architectural feature of the processor, and GDB/gdbserver can get
> it via ptrace in the NT_ARM_SVE regset. And it's always a multiple of
> 16.
> 

SME is a bit more strict with the allowed vector lengths. It is always a power of 2 between 128 and 2048 bits inclusive.

So in practice 128/256/512/1024/2048 bits.

> It's an interesting idea. Perhaps it's enough, at least for SVE?
> 
>> If I understand correctly, all of this makes it so the size of the
>> response to the g packet will be dynamic too?
> 
> We /could/ set the size of the g packet to always correspond to the
> largest vector length possible but it would be a big overhead,
> especially if there are many threads involved.

Or we could use the opportunity to break free from the g/G packet restrictions and go for a more flexible format while at it.

Given most of the fields contained in these big registers is 0 or same value, there is potential for quite a bit of compression.

Just an idea, while we're throwing ideas out there.

> 
> So in practice yes, it will be dynamic if we can help it.
> 


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-10 14:56                   ` Luis Machado
@ 2023-02-10 15:04                     ` Tom Tromey
  2023-02-10 15:28                       ` Luis Machado
  2023-02-10 17:26                       ` Thiago Jung Bauermann
  0 siblings, 2 replies; 94+ messages in thread
From: Tom Tromey @ 2023-02-10 15:04 UTC (permalink / raw)
  To: Luis Machado via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi, Luis Machado, Pedro Alves,
	Andrew Burgess

Luis> But it is also a larger effort that has to revamp some things in
Luis> gdb's type system to allow for sizeless types, and that also has
Luis> implications in other areas of gdb.

I doubt I understand the problem here, but we do have dynamic types and
dynamic type resolution now.  This lets you express a type's size,
offsets of members, and even fields (via variant parts) by referring to
other members of the object.

Luis> I'd be happy with an intermediate solution like what Thiago put
Luis> together. It would solve a long-standing issue for SVE and
Luis> gdbserver and it seems simpler at this point, plus Thiago already
Luis> put the effort to write the code.

I haven't followed this discussion, but with the remote protocol,
whatever we do now will be baked in forever.  So, it's worth spending
extra time up front to get a really solid approach.  (I'm not saying
this isn't, just pointing out that there's a long-term cost.)

Tom

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-10 15:04                     ` Tom Tromey
@ 2023-02-10 15:28                       ` Luis Machado
  2023-02-10 17:26                       ` Thiago Jung Bauermann
  1 sibling, 0 replies; 94+ messages in thread
From: Luis Machado @ 2023-02-10 15:28 UTC (permalink / raw)
  To: Tom Tromey, Luis Machado via Gdb-patches
  Cc: Thiago Jung Bauermann, Simon Marchi, Pedro Alves, Andrew Burgess

On 2/10/23 15:04, Tom Tromey wrote:
> Luis> But it is also a larger effort that has to revamp some things in
> Luis> gdb's type system to allow for sizeless types, and that also has
> Luis> implications in other areas of gdb.
> 
> I doubt I understand the problem here, but we do have dynamic types and
> dynamic type resolution now.  This lets you express a type's size,
> offsets of members, and even fields (via variant parts) by referring to
> other members of the object.

In summary, we need to define a vector register with size equal to the value of a particular
register (vg).

With every distinct value of that register, you'll have a distinct size in the register buffer, core
files, remote packet etc.

We do have dynamic types, but I don't particularly remember having a type that has a size defined by some
other entity outside of the type system, like a register (or dwarf register).

> 
> Luis> I'd be happy with an intermediate solution like what Thiago put
> Luis> together. It would solve a long-standing issue for SVE and
> Luis> gdbserver and it seems simpler at this point, plus Thiago already
> Luis> put the effort to write the code.
> 
> I haven't followed this discussion, but with the remote protocol,
> whatever we do now will be baked in forever.  So, it's worth spending
> extra time up front to get a really solid approach.  (I'm not saying
> this isn't, just pointing out that there's a long-term cost.)

Sure, but we can always add feature checks for that and fallback to known RSP if a particular feature isn't supported.

The approach Thiago took was, at one point, deemed the appropriate way to get dynamic vector lengths working in gdbserver. So some
amount of thought was put into it already.

I think there are two separate issues here. Per-thread target descriptions/gdbarch and the problem with dynamic vector lengths.

Realistically, having per-thread target descriptions/gdbarch seems like a more relevant feature at this point. It would allow
threads to have different architectures, and I think that is a good addition going forwards. Cell BE made use of this, but the
port has been removed now. It might also be useful for heterogeneous debugging, where you have cores of different architectures.

A separate issue is the one with the SVE dynamic vector length. We did have a chance to make gdb cope with sizeless types when SVE was
initially put together. But at the time it was deemed best to do (potentially) smaller adjustments to make it work for the native case. As a result,
the code we have now handles these changes via per-thread target descriptions.

I suppose AMX has the same issue, but I'm not sure how it was implemented. I remember reading about using a fixed-size buffer, but I haven't
followed that discussion closely.

So if we have other ports that could benefit from such a change to better handle types defined based on external entities (registers, variables etc), I guess
it would make sense to explore that possibility. Otherwise, if we're only trying to solve the particular case of SVE, coming up with a completely new design
might be a bit too much.

Just my $0.02.

> 
> Tom


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-10 15:04                     ` Tom Tromey
  2023-02-10 15:28                       ` Luis Machado
@ 2023-02-10 17:26                       ` Thiago Jung Bauermann
  2023-02-10 21:01                         ` Simon Marchi
  1 sibling, 1 reply; 94+ messages in thread
From: Thiago Jung Bauermann @ 2023-02-10 17:26 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Luis Machado via Gdb-patches, Simon Marchi, Luis Machado,
	Pedro Alves, Andrew Burgess


Tom Tromey <tom@tromey.com> writes:

> Luis> I'd be happy with an intermediate solution like what Thiago put
> Luis> together. It would solve a long-standing issue for SVE and
> Luis> gdbserver and it seems simpler at this point, plus Thiago already
> Luis> put the effort to write the code.
>
> I haven't followed this discussion, but with the remote protocol,
> whatever we do now will be baked in forever.  So, it's worth spending
> extra time up front to get a really solid approach.  (I'm not saying
> this isn't, just pointing out that there's a long-term cost.)

Andrew recommended adding a new feature to the qSupported packet so it
would be an optional extension of the remote protocol — not really baked
into it but rather a complementary muffin.

Per-thread target descriptions are also a very generic feature that
I can see being useful for heterogeneous computers, though I don't know
if there's any actual interest in that in the context of GDB and the
remote protocol.

-- 
Thiago

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description
  2023-02-10 17:26                       ` Thiago Jung Bauermann
@ 2023-02-10 21:01                         ` Simon Marchi
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Marchi @ 2023-02-10 21:01 UTC (permalink / raw)
  To: Thiago Jung Bauermann, Tom Tromey
  Cc: Luis Machado via Gdb-patches, Luis Machado, Pedro Alves, Andrew Burgess

On 2/10/23 12:26, Thiago Jung Bauermann via Gdb-patches wrote:
> 
> Tom Tromey <tom@tromey.com> writes:
> 
>> Luis> I'd be happy with an intermediate solution like what Thiago put
>> Luis> together. It would solve a long-standing issue for SVE and
>> Luis> gdbserver and it seems simpler at this point, plus Thiago already
>> Luis> put the effort to write the code.
>>
>> I haven't followed this discussion, but with the remote protocol,
>> whatever we do now will be baked in forever.  So, it's worth spending
>> extra time up front to get a really solid approach.  (I'm not saying
>> this isn't, just pointing out that there's a long-term cost.)
> 
> Andrew recommended adding a new feature to the qSupported packet so it
> would be an optional extension of the remote protocol — not really baked
> into it but rather a complementary muffin.
> 
> Per-thread target descriptions are also a very generic feature that
> I can see being useful for heterogeneous computers, though I don't know
> if there's any actual interest in that in the context of GDB and the
> remote protocol.

Maybe Pedro will correct me but... for ROCm, it's possible we'll want to
support remote debugging in the future.  And our model is a mix of host
and GPU threads in a single inferior.  So I can see this feature being
useful for that.

Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

end of thread, other threads:[~2023-02-10 21:01 UTC | newest]

Thread overview: 94+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-30  4:45 [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Thiago Jung Bauermann
2023-01-30  4:45 ` [PATCH v3 1/8] gdbserver: Add assert in find_register_by_number Thiago Jung Bauermann
2023-01-31 17:05   ` Simon Marchi
2023-01-31 19:49     ` Thiago Jung Bauermann
2023-02-01 15:43       ` Simon Marchi
2023-01-30  4:45 ` [PATCH v3 2/8] gdbserver: Add PID parameter to linux_get_auxv and linux_get_hwcap Thiago Jung Bauermann
2023-02-01  9:07   ` Luis Machado
2023-02-01 10:54   ` Andrew Burgess
2023-02-01 16:01     ` Simon Marchi
2023-02-01 19:33       ` Thiago Jung Bauermann
2023-02-01 19:53         ` Simon Marchi
2023-02-01 21:55           ` Thiago Jung Bauermann
2023-02-06 19:54   ` Pedro Alves
2023-02-06 20:16     ` Simon Marchi
2023-02-07 15:19       ` Pedro Alves
2023-02-07 21:47         ` Thiago Jung Bauermann
2023-02-09  1:31           ` Simon Marchi
2023-02-10  3:54             ` Thiago Jung Bauermann
2023-02-07 22:28     ` Thiago Jung Bauermann
2023-01-30  4:45 ` [PATCH v3 3/8] gdbserver/linux-aarch64: Factor out function to get aarch64_features Thiago Jung Bauermann
2023-02-01  8:59   ` Luis Machado
2023-02-01 16:04     ` Simon Marchi
2023-02-01 22:13       ` Thiago Jung Bauermann
2023-01-30  4:45 ` [PATCH v3 4/8] gdbserver/linux-aarch64: When thread stops, update its target description Thiago Jung Bauermann
2023-02-01  9:05   ` Luis Machado
2023-02-01 11:06   ` Andrew Burgess
2023-02-01 16:21     ` Simon Marchi
2023-02-01 16:32       ` Luis Machado
2023-02-02  2:54         ` Thiago Jung Bauermann
2023-02-02  3:47           ` Simon Marchi
2023-02-03  3:47             ` Thiago Jung Bauermann
2023-02-03 11:13               ` Luis Machado
2023-02-04 15:26                 ` Thiago Jung Bauermann
2023-02-03 11:11             ` Luis Machado
2023-02-04 15:21               ` Thiago Jung Bauermann
2023-02-06  9:07                 ` Luis Machado
2023-02-06 12:15                   ` Thiago Jung Bauermann
2023-02-06 20:29                 ` Pedro Alves
2023-02-07  8:11                   ` Luis Machado
2023-02-07 14:39                     ` Thiago Jung Bauermann
2023-02-03 10:57           ` Luis Machado
2023-02-04  6:18             ` Thiago Jung Bauermann
2023-02-06 20:26           ` Pedro Alves
2023-02-07 21:06             ` Thiago Jung Bauermann
2023-02-09  2:46               ` Simon Marchi
2023-02-10  3:29                 ` Thiago Jung Bauermann
2023-02-10 14:56                   ` Luis Machado
2023-02-10 15:04                     ` Tom Tromey
2023-02-10 15:28                       ` Luis Machado
2023-02-10 17:26                       ` Thiago Jung Bauermann
2023-02-10 21:01                         ` Simon Marchi
2023-01-30  4:45 ` [PATCH v3 5/8] gdbserver: Transmit target description ID in thread list and stop reply Thiago Jung Bauermann
2023-01-30 12:52   ` Eli Zaretskii
2023-01-30 14:05     ` Thiago Jung Bauermann
2023-02-01  9:39   ` Luis Machado
2023-02-01 12:07   ` Andrew Burgess
2023-02-01 13:03     ` Eli Zaretskii
2023-02-01 17:37     ` Simon Marchi
2023-02-02 20:36       ` Thiago Jung Bauermann
2023-02-02 20:56         ` Simon Marchi
2023-02-01 20:46     ` Simon Marchi
2023-02-02 21:43       ` Thiago Jung Bauermann
2023-02-01 14:51   ` Andrew Burgess
2023-02-01 17:03     ` Simon Marchi
2023-02-02 19:52       ` Thiago Jung Bauermann
2023-02-02 20:51         ` Simon Marchi
2023-02-03  2:44           ` Thiago Jung Bauermann
2023-02-03 16:29             ` Andrew Burgess
2023-02-04  6:08               ` Thiago Jung Bauermann
2023-02-03 11:22       ` Luis Machado
2023-02-03 12:50         ` Simon Marchi
2023-01-30  4:45 ` [PATCH v3 6/8] gdb/remote: Parse tdesc field in stop reply and threads list XML Thiago Jung Bauermann
2023-02-01  9:52   ` Luis Machado
2023-02-05  0:06     ` Thiago Jung Bauermann
2023-02-06  9:10       ` Luis Machado
2023-02-01 14:32   ` Andrew Burgess
2023-02-01 19:50     ` Simon Marchi
2023-02-01 20:16       ` Simon Marchi
2023-02-03 11:27         ` Luis Machado
2023-02-03 13:19           ` Simon Marchi
2023-02-03 16:33             ` Andrew Burgess
2023-01-30  4:45 ` [PATCH v3 7/8] gdb/aarch64: Detect vector length changes when debugging remotely Thiago Jung Bauermann
2023-02-01  9:58   ` Luis Machado
2023-02-01 15:26   ` Andrew Burgess
2023-02-01 20:20     ` Simon Marchi
2023-02-03 11:31       ` Luis Machado
2023-02-03 16:38       ` Andrew Burgess
2023-02-03 19:07         ` Simon Marchi
2023-01-30  4:45 ` [PATCH v3 8/8] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors Thiago Jung Bauermann
2023-02-01 10:10   ` Luis Machado
2023-02-06 19:11 ` [PATCH v3 0/8] gdbserver improvements for AArch64 SVE support Pedro Alves
2023-02-06 20:05   ` Simon Marchi
2023-02-06 21:06     ` Pedro Alves
2023-02-07 13:49       ` Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).