aarch64 multi-arch part 6: HW breakpoint on unaligned address

Nowadays, both aarch64 GDB and linux kernel assumes that address for
setting breakpoint should be 4-byte aligned.  However that is not true
after we support multi-arch, because thumb instruction can be at 2-byte
aligned address.  Patch http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/375141.html
to linux kernel is to teach kernel to handle 2-byte aligned address for
HW breakpoint, while this patch is to teach aarch64 GDB handle 2-byte
aligned address.

First of all, we call gdbarch_breakpoint_from_pc to get the instruction
length rather than using hard-coded 4.  Secondly, in GDBserver, we set
length back to 2 if it is 3, because GDB encode 3 in it to indicate it
is a 32-bit thumb breakpoint.  Then we relax the address alignment
check from 4-byte aligned to 2-byte aligned.

This patch enables some tests (such as gdb.base/break-idempotent.exp,
gdb.base/cond-eval-mode.exp, gdb.base/watchpoint-reuse-slot.exp,) and
fixes many fails (such as gdb.base/hbreak2.exp) when the program is
compiled in thumb mode on aarch64.

Regression tested on aarch64-linux, both native and gdbserver.  This
is the last patch of multi-arch work.

gdb:

2015-10-15  Yao Qi  <yao.qi@linaro.org>

	* aarch64-linux-nat.c (aarch64_linux_insert_hw_breakpoint):
	Call gdbarch_breakpoint_from_pc to instruction length.
	(aarch64_linux_remove_hw_breakpoint): Likewise.
	* common/common-regcache.h (regcache_register_size): Declare.
	* nat/aarch64-linux-hw-point.c: Include "common-regcache.h".
	(aarch64_point_is_aligned): Set alignment to 2 for breakpoint if
	the process is 32bit, otherwise set alignment to 4.
	(aarch64_handle_breakpoint): Update comments.
	* regcache.c (regcache_register_size): New function.

gdb/gdbserver:

2015-10-15  Yao Qi  <yao.qi@linaro.org>

	* linux-aarch64-low.c (aarch64_insert_point): Set len to 2
	if it is 3.
	(aarch64_remove_point): Likewise.
	* regcache.c (regcache_register_size): New function.
This commit is contained in:
Yao Qi 2015-10-15 15:05:10 +01:00
parent 21c40443ce
commit 8d689ee570
8 changed files with 87 additions and 11 deletions

View File

@ -1,3 +1,15 @@
2015-10-15 Yao Qi <yao.qi@linaro.org>
* aarch64-linux-nat.c (aarch64_linux_insert_hw_breakpoint):
Call gdbarch_breakpoint_from_pc to instruction length.
(aarch64_linux_remove_hw_breakpoint): Likewise.
* common/common-regcache.h (regcache_register_size): Declare.
* nat/aarch64-linux-hw-point.c: Include "common-regcache.h".
(aarch64_point_is_aligned): Set alignment to 2 for breakpoint if
the process is 32bit, otherwise set alignment to 4.
(aarch64_handle_breakpoint): Update comments.
* regcache.c (regcache_register_size): New function.
2015-10-15 Aleksandar Ristovski <aristovski@qnx.com>
* gdbarch.sh (core_regset_section): Remove.

View File

@ -608,11 +608,13 @@ aarch64_linux_insert_hw_breakpoint (struct target_ops *self,
{
int ret;
CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address;
const int len = 4;
int len;
const enum target_hw_bp_type type = hw_execute;
struct aarch64_debug_reg_state *state
= aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
gdbarch_breakpoint_from_pc (gdbarch, &addr, &len);
if (show_debug_regs)
fprintf_unfiltered
(gdb_stdlog,
@ -640,11 +642,13 @@ aarch64_linux_remove_hw_breakpoint (struct target_ops *self,
{
int ret;
CORE_ADDR addr = bp_tgt->placed_address;
const int len = 4;
int len = 4;
const enum target_hw_bp_type type = hw_execute;
struct aarch64_debug_reg_state *state
= aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
gdbarch_breakpoint_from_pc (gdbarch, &addr, &len);
if (show_debug_regs)
fprintf_unfiltered
(gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",

View File

@ -28,6 +28,11 @@
extern struct regcache *get_thread_regcache_for_ptid (ptid_t ptid);
/* Return the size of register numbered N in REGCACHE. This function
must be provided by the client. */
extern int regcache_register_size (const struct regcache *regcache, int n);
/* Read the PC register. This function must be provided by the
client. */

View File

@ -1,3 +1,10 @@
2015-10-15 Yao Qi <yao.qi@linaro.org>
* linux-aarch64-low.c (aarch64_insert_point): Set len to 2
if it is 3.
(aarch64_remove_point): Likewise.
* regcache.c (regcache_register_size): New function.
2015-10-12 Yao Qi <yao.qi@linaro.org>
* linux-aarch64-low.c: Update all callers as emit_load_store

View File

@ -315,9 +315,17 @@ aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
ret = -1;
}
else
ret =
aarch64_handle_breakpoint (targ_type, addr, len, 1 /* is_insert */,
state);
{
if (len == 3)
{
/* LEN is 3 means the breakpoint is set on a 32-bit thumb
instruction. Set it to 2 to correctly encode length bit
mask in hardware/watchpoint control register. */
len = 2;
}
ret = aarch64_handle_breakpoint (targ_type, addr, len,
1 /* is_insert */, state);
}
if (show_debug_regs)
aarch64_show_debug_reg_state (state, "insert_point", addr, len,
@ -353,9 +361,17 @@ aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */,
state);
else
ret =
aarch64_handle_breakpoint (targ_type, addr, len, 0 /* is_insert */,
state);
{
if (len == 3)
{
/* LEN is 3 means the breakpoint is set on a 32-bit thumb
instruction. Set it to 2 to correctly encode length bit
mask in hardware/watchpoint control register. */
len = 2;
}
ret = aarch64_handle_breakpoint (targ_type, addr, len,
0 /* is_insert */, state);
}
if (show_debug_regs)
aarch64_show_debug_reg_state (state, "remove_point", addr, len,

View File

@ -316,6 +316,14 @@ register_size (const struct target_desc *tdesc, int n)
return tdesc->reg_defs[n].size / 8;
}
/* See common/common-regcache.h. */
int
regcache_register_size (const struct regcache *regcache, int n)
{
return register_size (regcache->tdesc, n);
}
static unsigned char *
register_data (struct regcache *regcache, int n, int fetch)
{

View File

@ -18,6 +18,7 @@
#include "common-defs.h"
#include "break-common.h"
#include "common-regcache.h"
#include "nat/linux-nat.h"
#include "aarch64-linux-hw-point.h"
@ -112,8 +113,23 @@ aarch64_point_encode_ctrl_reg (enum target_hw_bp_type type, int len)
static int
aarch64_point_is_aligned (int is_watchpoint, CORE_ADDR addr, int len)
{
unsigned int alignment = is_watchpoint ? AARCH64_HWP_ALIGNMENT
: AARCH64_HBP_ALIGNMENT;
unsigned int alignment = 0;
if (is_watchpoint)
alignment = AARCH64_HWP_ALIGNMENT;
else
{
struct regcache *regcache
= get_thread_regcache_for_ptid (current_lwp_ptid ());
/* Set alignment to 2 only if the current process is 32-bit,
since thumb instruction can be 2-byte aligned. Otherwise, set
alignment to AARCH64_HBP_ALIGNMENT. */
if (regcache_register_size (regcache, 0) == 8)
alignment = AARCH64_HBP_ALIGNMENT;
else
alignment = 2;
}
if (addr & (alignment - 1))
return 0;
@ -445,7 +461,7 @@ aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr,
struct aarch64_debug_reg_state *state)
{
/* The hardware breakpoint on AArch64 should always be 4-byte
aligned. */
aligned, but on AArch32, it can be 2-byte aligned. */
if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len))
return -1;

View File

@ -179,6 +179,14 @@ register_size (struct gdbarch *gdbarch, int regnum)
return size;
}
/* See common/common-regcache.h. */
int
regcache_register_size (const struct regcache *regcache, int n)
{
return register_size (get_regcache_arch (regcache), n);
}
/* The register cache for storing raw register values. */
struct regcache