public inbox for gdb-prs@sourceware.org
help / color / mirror / Atom feed
* [Bug breakpoints/31665] New: [arm] Hardware watchpoints trigger at the wrong place with memset/memcopy/memmove
@ 2024-04-21 21:41 thiago.bauermann at linaro dot org
  0 siblings, 0 replies; only message in thread
From: thiago.bauermann at linaro dot org @ 2024-04-21 21:41 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=31665

            Bug ID: 31665
           Summary: [arm] Hardware watchpoints trigger at the wrong place
                    with memset/memcopy/memmove
           Product: gdb
           Version: HEAD
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: breakpoints
          Assignee: unassigned at sourceware dot org
          Reporter: thiago.bauermann at linaro dot org
  Target Milestone: ---

Created attachment 15476
  --> https://sourceware.org/bugzilla/attachment.cgi?id=15476&action=edit
Disassembly of __memcpy_neon, also used for memmove.

On an armv8l-linux-gnueabihf system, hardware watchpoints only trigger at
the end of the inferior execution instead of in memset, memcpy, or
memmove. E.g., with the following program (which I'm posting upstream as
part of gdb.base/memops-watchpoint.exp):

#include <stdio.h>
#include <string.h>

int
main (void)
{
  /* Some targets need 4-byte alignment for hardware watchpoints.  */
  char s[40] __attribute__ ((aligned (4)))
    = "This is a relatively long string...";
  char a[40] __attribute__ ((aligned (4)))
    = "String to be overwritten with zeroes";
  char b[40] __attribute__ ((aligned (4)))
    = "Another string to be memcopied...";
  char c[40] __attribute__ ((aligned (4)))
    = "Another string to be memmoved...";

  /* Break here.  */
  memset (a, 0, sizeof (a));

  memcpy (b, s, sizeof (b));

  memmove (c, s, sizeof (c));

  printf ("b = '%s'\n", b);
  printf ("c = '%s'\n", c);

  return 0;
}

Compiled with:

$ gcc -fno-builtin-memset       \
      -fno-builtin-memcpy       \
      -fno-builtin-memmove      \
      -g                        \
      -o /tmp/memops-watchpoint \
      /tmp/memops-watchpoint.c

This happens:

(gdb) break 18
Breakpoint 1 at 0x6bc: file /tmp/memops-watchpoint.c, line 18.
(gdb) r
Starting program: /tmp/memops-watchpoint
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".

Breakpoint 1, main () at /tmp/memops-watchpoint.c:18
18        memset (a, 0, sizeof (a));
(gdb) watch -location a[28]
Hardware watchpoint 2: -location a[28]
(gdb) c
Continuing.
b = 'This is a relatively long string...'
c = 'This is a relatively long string...'

Hardware watchpoint 2: -location a[28]

Old value = 104 'h'
New value = 3 '\003'
0xf7fc2868 in _dl_fini () at dl-fini.c:68
warning: 68     dl-fini.c: No such file or directory
(gdb) bt
#0  0xf7fc2868 in _dl_fini () at dl-fini.c:68
#1  0xf7ebe506 in __run_exit_handlers (status=0, listp=0xf7fae534
<__exit_funcs>, run_list_atexit=run_list_atexit@entry=true,
run_dtors=run_dtors@entry=true) at exit.c:113
#2  0xf7ebe612 in __GI_exit (status=<optimized out>) at exit.c:143
#3  0xf7ead7da in __libc_start_call_main (main=0x400625 <main>,
main@entry=0xf7fae000, argc=1, argc@entry=-134549128, argv=0xfffef364,
argv@entry=0xf7faf380 <__exit_funcs_lock>)
    at ../sysdeps/nptl/libc_start_call_main.h:74
#4  0xf7ead886 in __libc_start_main_impl (main=0xf7fae000, argc=-134549128,
argv=0xf7faf380 <__exit_funcs_lock>, init=<optimized out>, fini=0x0,
rtld_fini=0xf7fc27d9 <_dl_fini>, stack_end=0xfffef364)
    at libc-start.c:392
#5  0x00400550 in _start ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

The same behaviour is seen with memcpy and memmove. In the example above,
that would be when watching b[28] and c[28].

When using software watchpoints, it works as expected:

(gdb) break 18
Breakpoint 1 at 0x6bc: file /tmp/memops-watchpoint.c, line 18.
(gdb) r
Starting program: /tmp/memops-watchpoint 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".

Breakpoint 1, main () at /tmp/memops-watchpoint.c:18
18        memset (a, 0, sizeof (a));
(gdb) set can-use-hw-watchpoints 0
(gdb) watch -location a[28]
Watchpoint 2: -location a[28]
(gdb) c
Continuing.

Watchpoint 2: -location a[28]

Old value = 104 'h'
New value = 0 '\000'
memset () at ../sysdeps/arm/memset.S:52
warning: 52     ../sysdeps/arm/memset.S: No such file or directory
(gdb) bt
#0  memset () at ../sysdeps/arm/memset.S:52
#1  0x004006ca in main () at /tmp/memops-watchpoint.c:18
(gdb) 

memset here is:

(gdb) disassemble
Dump of assembler code for function memset:
   0xf7efc1e0 <+0>:     mov     r3, r0
   0xf7efc1e4 <+4>:     cmp     r2, #8
   0xf7efc1e8 <+8>:     bcc     0xf7efc234 <memset+84>
   0xf7efc1ec <+12>:    tst     r3, #3
   0xf7efc1f0 <+16>:    strbne  r1, [r3], #1
   0xf7efc1f4 <+20>:    subne   r2, r2, #1
   0xf7efc1f8 <+24>:    bne     0xf7efc1ec <memset+12>
   0xf7efc1fc <+28>:    and     r1, r1, #255    @ 0xff
   0xf7efc200 <+32>:    orr     r1, r1, r1, lsl #8
   0xf7efc204 <+36>:    orr     r1, r1, r1, lsl #16
   0xf7efc208 <+40>:    mov     r12, r1
   0xf7efc20c <+44>:    subs    r2, r2, #8
   0xf7efc210 <+48>:    stmiacs r3!, {r1, r12}
   0xf7efc214 <+52>:    subscs  r2, r2, #8
   0xf7efc218 <+56>:    stmiacs r3!, {r1, r12}
   0xf7efc21c <+60>:    subscs  r2, r2, #8
   0xf7efc220 <+64>:    stmiacs r3!, {r1, r12}
   0xf7efc224 <+68>:    subscs  r2, r2, #8
   0xf7efc228 <+72>:    stmiacs r3!, {r1, r12}
=> 0xf7efc22c <+76>:    bcs     0xf7efc20c <memset+44>
   0xf7efc230 <+80>:    and     r2, r2, #7
   0xf7efc234 <+84>:    subs    r2, r2, #1
   0xf7efc238 <+88>:    strbcs  r1, [r3], #1
   0xf7efc23c <+92>:    subscs  r2, r2, #1
   0xf7efc240 <+96>:    strbcs  r1, [r3], #1
   0xf7efc244 <+100>:   subscs  r2, r2, #1
   0xf7efc248 <+104>:   strbcs  r1, [r3], #1
   0xf7efc24c <+108>:   subscs  r2, r2, #1
   0xf7efc250 <+112>:   strbcs  r1, [r3], #1
   0xf7efc254 <+116>:   bcs     0xf7efc234 <memset+84>
   0xf7efc258 <+120>:   bx      lr
End of assembler dump.
(gdb) 

The disassembly of __memcpy_neon (used in this machine) is somewhat big,
so I'll attach it instead. memmove also uses __memcpy_neon.

This is with a 32-bit Ubuntu 22.04 userland running on a 64-bit kernel
5.4.0-131-generic, with a Neoverse-N1 processor.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-04-21 21:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-21 21:41 [Bug breakpoints/31665] New: [arm] Hardware watchpoints trigger at the wrong place with memset/memcopy/memmove thiago.bauermann at linaro dot org

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).