[ARM] Fixup PC in software single step

When I exercise GDBserver software single step, I see the following
error, which has been already handled by GDB properly.

In GDBserver log, we can see, GDBserver tries to single step instruction
on 0xb6e0a6e4, and destination address is 0xffff0fe0,

 stop pc is 0xb6e0a6e4
 Writing f001f0e7 to 0xffff0fe0 in process 7132
 Failed to insert breakpoint at 0xffff0fe0 (Input/output error).
 Failed to insert breakpoint at 0xffff0fe0 (-1).

(gdb) disassemble __aeabi_read_tp,+8
Dump of assembler code from 0xb6e0a6e0 to 0xb6e0a6e8:
   0xb6e0a6e0 <__aeabi_read_tp+0>:	mvn	r0, #61440	; 0xf000
   0xb6e0a6e4 <__aeabi_read_tp+4>:	sub	pc, r0, #31

however, it fails inserting breakpoint there.  This problem has already
fixed by GDB, see comments in arm-linux-tdep.c:arm_linux_software_single_step

      /* The Linux kernel offers some user-mode helpers in a high page.  We can
	 not read this page (as of 2.6.23), and even if we could then we
	 couldn't set breakpoints in it, and even if we could then the atomic
	 operations would fail when interrupted.  They are all called as
	 functions and return to the address in LR, so step to there
	 instead.  */

so we need to do the same thing in GDB side as well.  This patch adds
a new field fixup in arm_get_next_pcs_ops, so that we can fix up PC
for arm-linux target.  In this way, both GDB and GDBserver can single
step instructions going to kernel helpers.

gdb:

2016-02-12  Yao Qi  <yao.qi@linaro.org>

	* arch/arm-get-next-pcs.c (arm_get_next_pcs): Call
	self->ops->fixup if it isn't NULL.
	* arch/arm-get-next-pcs.h: Include gdb_vecs.h.
	(struct arm_get_next_pcs_ops) <fixup>: New field.
	* arch/arm-linux.c: Include common-regcache.h and
	arch/arm-get-next-pcs.h.
	(arm_linux_get_next_pcs_fixup): New function.
	* arch/arm-linux.h (arm_linux_get_next_pcs_fixup): Declare.
	* arm-linux-tdep.c (arm_linux_get_next_pcs_ops): Initialize
	it with arm_linux_get_next_pcs_fixup.
	(arm_linux_software_single_step): Move code to
	arm_linux_get_next_pcs_fixup.
	* arm-tdep.c (arm_get_next_pcs_ops): Initialize it.

gdb/gdbserver:

2016-02-12  Yao Qi  <yao.qi@linaro.org>

	* linux-arm-low.c (get_next_pcs_ops): Initialize it with
	arm_linux_get_next_pcs_fixup.
This commit is contained in:
Yao Qi 2016-02-08 16:05:31 +00:00
parent 020ecd38e7
commit ed443b61e1
9 changed files with 67 additions and 15 deletions

View File

@ -1,3 +1,19 @@
2016-02-12 Yao Qi <yao.qi@linaro.org>
* arch/arm-get-next-pcs.c (arm_get_next_pcs): Call
self->ops->fixup if it isn't NULL.
* arch/arm-get-next-pcs.h: Include gdb_vecs.h.
(struct arm_get_next_pcs_ops) <fixup>: New field.
* arch/arm-linux.c: Include common-regcache.h and
arch/arm-get-next-pcs.h.
(arm_linux_get_next_pcs_fixup): New function.
* arch/arm-linux.h (arm_linux_get_next_pcs_fixup): Declare.
* arm-linux-tdep.c (arm_linux_get_next_pcs_ops): Initialize
it with arm_linux_get_next_pcs_fixup.
(arm_linux_software_single_step): Move code to
arm_linux_get_next_pcs_fixup.
* arm-tdep.c (arm_get_next_pcs_ops): Initialize it.
2016-02-12 Marcin Kościelnicki <koriakin@0x04.net>
* xml-tdesc.c (target_fetch_description_xml) [!HAVE_LIBEXPAT]: Warn

View File

@ -923,5 +923,16 @@ arm_get_next_pcs (struct arm_get_next_pcs *self)
next_pcs = arm_get_next_pcs_raw (self);
}
if (self->ops->fixup != NULL)
{
CORE_ADDR nextpc;
int i;
for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, nextpc); i++)
{
nextpc = self->ops->fixup (self, nextpc);
VEC_replace (CORE_ADDR, next_pcs, i, nextpc);
}
}
return next_pcs;
}

View File

@ -19,6 +19,7 @@
#ifndef ARM_GET_NEXT_PCS_H
#define ARM_GET_NEXT_PCS_H 1
#include "gdb_vecs.h"
/* Forward declaration. */
struct arm_get_next_pcs;
@ -30,6 +31,9 @@ struct arm_get_next_pcs_ops
CORE_ADDR (*syscall_next_pc) (struct arm_get_next_pcs *self, CORE_ADDR pc);
CORE_ADDR (*addr_bits_remove) (struct arm_get_next_pcs *self, CORE_ADDR val);
int (*is_thumb) (struct arm_get_next_pcs *self);
/* Fix up PC if needed. */
CORE_ADDR (*fixup) (struct arm_get_next_pcs *self, CORE_ADDR pc);
};
/* Context for a get_next_pcs call on ARM. */

View File

@ -18,8 +18,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "common-defs.h"
#include "common-regcache.h"
#include "arch/arm.h"
#include "arm-linux.h"
#include "arch/arm-get-next-pcs.h"
/* Calculate the offset from stack pointer of the pc register on the stack
in the case of a sigreturn or sigreturn_rt syscall. */
@ -55,3 +57,21 @@ arm_linux_sigreturn_next_pc_offset (unsigned long sp,
return pc_offset;
}
/* Implementation of "fixup" method of struct arm_get_next_pcs_ops
for arm-linux. */
CORE_ADDR
arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
CORE_ADDR nextpc)
{
/* The Linux kernel offers some user-mode helpers in a high page. We can
not read this page (as of 2.6.23), and even if we could then we
couldn't set breakpoints in it, and even if we could then the atomic
operations would fail when interrupted. They are all called as
functions and return to the address in LR, so step to there
instead. */
if (nextpc > 0xffff0000)
nextpc = regcache_raw_get_unsigned (self->regcache, ARM_LR_REGNUM);
return nextpc;
}

View File

@ -71,4 +71,8 @@ arm_linux_sigreturn_next_pc_offset (unsigned long sp,
unsigned long svc_number,
int is_sigreturn);
struct arm_get_next_pcs;
CORE_ADDR arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
CORE_ADDR pc);
#endif /* ARM_LINUX_H */

View File

@ -274,7 +274,8 @@ static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
arm_get_next_pcs_read_memory_unsigned_integer,
arm_linux_get_next_pcs_syscall_next_pc,
arm_get_next_pcs_addr_bits_remove,
arm_get_next_pcs_is_thumb
arm_get_next_pcs_is_thumb,
arm_linux_get_next_pcs_fixup,
};
static void
@ -950,18 +951,7 @@ arm_linux_software_single_step (struct frame_info *frame)
next_pcs = arm_get_next_pcs (&next_pcs_ctx);
for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
{
/* The Linux kernel offers some user-mode helpers in a high page. We can
not read this page (as of 2.6.23), and even if we could then we
couldn't set breakpoints in it, and even if we could then the atomic
operations would fail when interrupted. They are all called as
functions and return to the address in LR, so step to there
instead. */
if (pc > 0xffff0000)
pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
}
arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
do_cleanups (old_chain);

View File

@ -247,7 +247,8 @@ static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = {
arm_get_next_pcs_read_memory_unsigned_integer,
arm_get_next_pcs_syscall_next_pc,
arm_get_next_pcs_addr_bits_remove,
arm_get_next_pcs_is_thumb
arm_get_next_pcs_is_thumb,
NULL,
};
struct arm_prologue_cache

View File

@ -1,3 +1,8 @@
2016-02-12 Yao Qi <yao.qi@linaro.org>
* linux-arm-low.c (get_next_pcs_ops): Initialize it with
arm_linux_get_next_pcs_fixup.
2016-02-12 Marcin Kościelnicki <koriakin@0x04.net>
* tracepoint.c (x_tracepoint_action_download): Change

View File

@ -157,7 +157,8 @@ static struct arm_get_next_pcs_ops get_next_pcs_ops = {
get_next_pcs_read_memory_unsigned_integer,
get_next_pcs_syscall_next_pc,
get_next_pcs_addr_bits_remove,
get_next_pcs_is_thumb
get_next_pcs_is_thumb,
arm_linux_get_next_pcs_fixup,
};
static int