[Bug breakpoints/31665] New: [arm] Hardware watchpoints trigger at the wrong place with memset/memcopy/memmove
thiago.bauermann at linaro dot org
sourceware-bugzilla@sourceware.org
Sun Apr 21 21:41:23 GMT 2024
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.
More information about the Gdb-prs
mailing list