]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/tdep] Handle M1 ldp in aarch64_stopped_data_address
authorTom de Vries <tdevries@suse.de>
Tue, 12 Aug 2025 14:35:05 +0000 (16:35 +0200)
committerTom de Vries <tdevries@suse.de>
Tue, 12 Aug 2025 14:35:05 +0000 (16:35 +0200)
In test-case gdb.base/watchpoint-unaligned.exp, in function write_size8twice,
two adjacent 8-byte vars are written.  For aarch64, we use a single stp
instruction for that.

If we do the same in function read_size8twice for two adjacent 8-byte var reads
using aarch64 insn ldp, on an aarch64-linux M1 system we get a hang:
...
(gdb) continue^M
Continuing.^M
FAIL: $exp: fun=read_size8twice: offset=0: index=1: continue (timeout)
FAIL: $exp: fun=read_size8twice: offset=0: index=1: $got_hit
...

The same problem was observed for stp in PR tdep/29423, fixed by commit
9a03f218534 ("[gdb/tdep] Fix gdb.base/watchpoint-unaligned.exp on aarch64").

See that commit for an explanation of the hang.

That commit introduced max_access_size in aarch64_stopped_data_address:
...
   The access size also can be larger than that of the watchpoint
   itself.  For instance, the access size of an stp instruction is 16.
   So, if we use stp to store to address p, and set a watchpoint on
   address p + 8, the reported ADDR_TRAP can be p + 8 (observed on
   RK3399 SOC). But it also can be p (observed on M1 SOC).  Checking
   for this situation introduces the possibility of false positives,
   so we only do this for hw_write watchpoints.  */
const CORE_ADDR max_access_size = type == hw_write ? 16 : 8;
...

If we say that hangs are worse than false positives, then we should also fix
this case.

Fix this by setting max_access_size to 16 for all watchpoint types.

Tested on aarch64-linux, both on an M1 SOC and an RK3399 SOC.

Approved-By: Luis Machado <luis.machado.foss@gmail.com>
gdb/nat/aarch64-hw-point.c
gdb/testsuite/gdb.base/watchpoint-unaligned.c

index 6d8dce86dfee734a0cd53285651cd903acc39490..8c0854bcc8882348343f7adac4b02c301104a341 100644 (file)
@@ -710,10 +710,8 @@ aarch64_stopped_data_address (const struct aarch64_debug_reg_state *state,
           itself.  For instance, the access size of an stp instruction is 16.
           So, if we use stp to store to address p, and set a watchpoint on
           address p + 8, the reported ADDR_TRAP can be p + 8 (observed on
-          RK3399 SOC). But it also can be p (observed on M1 SOC).  Checking
-          for this situation introduces the possibility of false positives,
-          so we only do this for hw_write watchpoints.  */
-       const CORE_ADDR max_access_size = type == hw_write ? 16 : 8;
+          RK3399 SOC). But it also can be p (observed on M1 SOC).  */
+       const CORE_ADDR max_access_size = 16;
        const CORE_ADDR addr_watch_base = addr_watch_aligned -
          (max_access_size - AARCH64_HWP_MAX_LEN_PER_REG);
        if (!(addr_trap >= addr_watch_base
index baa7ae021a1ed1c14d1a0f5f152e0f02123c8ea7..ca2fa457c1446b23c027b59183aa0553fb5a8a59 100644 (file)
@@ -71,8 +71,16 @@ read_size8twice (void)
   static uint64_t volatile first;
   static uint64_t volatile second;
 
+#ifdef __aarch64__
+  volatile void *p = &data.u.size8twice[offset];
+  asm volatile ("ldp %0, %1, [%2]"
+              : "=r" (first), "=r" (second) /* output */
+              : "r" (p)  /* input */
+              : /* clobber */);
+#else
   first = data.u.size8twice[offset];
   second = data.u.size8twice[offset + 1];
+#endif
 
   /* Setting a breakpoint on an instruction after an instruction triggering a
      watchpoint makes it ambiguous which one will be reported.