mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-12-19 01:19:41 +08:00
On aarch64-linux, with test-case gdb.base/watchpoint-unaligned.exp I run into: ... (gdb) watch data.u.size8twice[1]^M Hardware watchpoint 241: data.u.size8twice[1]^M (gdb) PASS: gdb.base/watchpoint-unaligned.exp: watch data.u.size8twice[1] continue^M Continuing.^M FAIL: gdb.base/watchpoint-unaligned.exp: continue (timeout) FAIL: gdb.base/watchpoint-unaligned.exp: size8twice write ... This happens as follows. We start the exec and set an 8-byte hardware watchpoint on data.u.size8twice[1] at address 0x440048: ... (gdb) p sizeof (data.u.size8twice[1]) $1 = 8 (gdb) p &data.u.size8twice[1] $2 = (uint64_t *) 0x440048 <data+16> ... We continue execution, and a 16-byte write at address 0x440040 triggers the hardware watchpoint: ... 4101c8: a9000801 stp x1, x2, [x0] ... When checking whether a watchpoint has triggered in aarch64_stopped_data_address, we check against address 0x440040 (passed in parameter addr_trap). This behaviour is documented: ... /* ADDR_TRAP reports the first address of the memory range accessed by the CPU, regardless of what was the memory range watched. ... */ ... and consequently the matching logic compares against an addr_watch_aligned: ... && addr_trap >= addr_watch_aligned && addr_trap < addr_watch + len) ... However, the comparison fails: ... (gdb) p /x addr_watch_aligned $3 = 0x440048 (gdb) p addr_trap >= addr_watch_aligned $4 = false ... Consequently, aarch64_stopped_data_address returns false, and stopped_by_watchpoint returns false, and watchpoints_triggered returns 0, which make infrun think it's looking at a delayed hardware breakpoint/watchpoint trap: ... [infrun] handle_signal_stop: stop_pc=0x4101c8 [infrun] handle_signal_stop: delayed hardware breakpoint/watchpoint trap, ignoring ... Infrun then ignores the trap and continues, but runs into the same situation again and again, causing a hang which then causes the test timeout. Fix this by allowing a match 8 bytes below addr_watch_aligned. This introduces the possibility for false positives, so we only do this for regular "value changed" watchpoints. An earlier version of this patch worked by aligning addr_watch_aligned to 16 instead of 8: ... - const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); + const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 16); ... but while that fixed the test-case, it didn't fix the problem completely, so extend the test-case to check more scenarios. Tested on aarch64-linux. Tested-By: Luis Machado <luis.machado@arm.com> Approved-By: Luis Machado <luis.machado@arm.com> PR tdep/29423 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29423
98 lines
2.1 KiB
C
98 lines
2.1 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2017-2024 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/>. */
|
|
|
|
#include <stdint.h>
|
|
#include <assert.h>
|
|
|
|
static int again;
|
|
|
|
static volatile struct
|
|
{
|
|
uint64_t alignment;
|
|
union
|
|
{
|
|
uint64_t size8[1];
|
|
uint32_t size4[2];
|
|
uint16_t size2[4];
|
|
uint8_t size1[8];
|
|
uint64_t size8twice[3];
|
|
}
|
|
u;
|
|
} data;
|
|
|
|
static int size = 0;
|
|
static int offset;
|
|
|
|
static void
|
|
write_size8twice (void)
|
|
{
|
|
static const uint64_t first = 1;
|
|
static const uint64_t second = 2;
|
|
|
|
#ifdef __aarch64__
|
|
volatile void *p = &data.u.size8twice[offset];
|
|
asm volatile ("stp %1, %2, [%0]"
|
|
: /* output */
|
|
: "r" (p), "r" (first), "r" (second) /* input */
|
|
: "memory" /* clobber */);
|
|
#else
|
|
data.u.size8twice[offset] = first;
|
|
data.u.size8twice[offset + 1] = second;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
volatile uint64_t local;
|
|
|
|
assert (sizeof (data) == 8 + 3 * 8);
|
|
|
|
write_size8twice ();
|
|
|
|
while (size)
|
|
{
|
|
switch (size)
|
|
{
|
|
/* __s390x__ also defines __s390__ */
|
|
#ifdef __s390__
|
|
# define ACCESS(var) var = ~var
|
|
#else
|
|
# define ACCESS(var) local = var
|
|
#endif
|
|
case 8:
|
|
ACCESS (data.u.size8[offset]);
|
|
break;
|
|
case 4:
|
|
ACCESS (data.u.size4[offset]);
|
|
break;
|
|
case 2:
|
|
ACCESS (data.u.size2[offset]);
|
|
break;
|
|
case 1:
|
|
ACCESS (data.u.size1[offset]);
|
|
break;
|
|
#undef ACCESS
|
|
default:
|
|
assert (0);
|
|
}
|
|
size = 0;
|
|
size = size; /* start_again */
|
|
}
|
|
return 0; /* final_return */
|
|
}
|