Fix breakpoint size when stepping over a permanent breakpoint in GDBServer.

When manually stepping over a permanent breakpoint on ARM we need to fetch the
right breakpoint size based on the current instruction set used.

Since this is not encoded in the stop_pc, the instruction mode needs to be
fetched from the CPSR register.

This is done by introducing a new target operation called :
breakpoint_kind_from_current_state.

For other targets that do not need this, breakpoint_kind_from_pc is used.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-arm-low.c (arm_is_thumb_mode): New function.
	(arm_breakpoint_at): Use arm_is_thumb_mode.
	(arm_breakpoint_kind_from_current_state): New function.
	(struct linux_target_ops) <breakpoint_kind_from_current_state>:
	Initialize.
	* linux-low.c (linux_wait_1): Call breakpoint_kind_from_current_state.
	(linux_breakpoint_kind_from_current_state): New function.
	(struct target_ops <breakpoint_kind_from_current_state>: Initialize.
	* linux-low.h (struct linux_target_ops)
	<breakpoint_kind_from_current_state>: New field.
	* target.h (struct target_ops): Likewise.
	(target_breakpoint_kind_from_current_state): New macro.
This commit is contained in:
Antoine Tremblay 2015-11-30 15:08:04 -05:00
parent fddedbe665
commit 769ef81fec
5 changed files with 83 additions and 2 deletions

View File

@ -1,3 +1,18 @@
2015-11-30 Antoine Tremblay <antoine.tremblay@ericsson.com>
* linux-arm-low.c (arm_is_thumb_mode): New function.
(arm_breakpoint_at): Use arm_is_thumb_mode.
(arm_breakpoint_kind_from_current_state): New function.
(struct linux_target_ops) <breakpoint_kind_from_current_state>:
Initialize.
* linux-low.c (linux_wait_1): Call breakpoint_kind_from_current_state.
(linux_breakpoint_kind_from_current_state): New function.
(struct target_ops <breakpoint_kind_from_current_state>: Initialize.
* linux-low.h (struct linux_target_ops)
<breakpoint_kind_from_current_state>: New field.
* target.h (struct target_ops): Likewise.
(target_breakpoint_kind_from_current_state): New macro.
2015-11-30 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_resume): Wake up the event loop before

View File

@ -264,8 +264,10 @@ static const unsigned short thumb_breakpoint = 0xde01;
static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 };
#define thumb2_breakpoint_len 4
/* Returns 1 if the current instruction set is thumb, 0 otherwise. */
static int
arm_breakpoint_at (CORE_ADDR where)
arm_is_thumb_mode (void)
{
struct regcache *regcache = get_thread_regcache (current_thread, 1);
unsigned long cpsr;
@ -273,6 +275,17 @@ arm_breakpoint_at (CORE_ADDR where)
collect_register_by_name (regcache, "cpsr", &cpsr);
if (cpsr & 0x20)
return 1;
else
return 0;
}
/* Returns 1 if there is a software breakpoint at location. */
static int
arm_breakpoint_at (CORE_ADDR where)
{
if (arm_is_thumb_mode ())
{
/* Thumb mode. */
unsigned short insn;
@ -996,6 +1009,23 @@ arm_sw_breakpoint_from_kind (int kind , int *size)
return NULL;
}
/* Implementation of the linux_target_ops method
"breakpoint_kind_from_current_state". */
static int
arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
{
if (arm_is_thumb_mode ())
{
*pcptr = MAKE_THUMB_ADDR (*pcptr);
return arm_breakpoint_kind_from_pc (pcptr);
}
else
{
return arm_breakpoint_kind_from_pc (pcptr);
}
}
struct linux_target_ops the_low_target = {
arm_arch_setup,
arm_regs_info,
@ -1021,6 +1051,14 @@ struct linux_target_ops the_low_target = {
arm_new_thread,
arm_new_fork,
arm_prepare_to_resume,
NULL, /* process_qsupported */
NULL, /* supports_tracepoints */
NULL, /* get_thread_area */
NULL, /* install_fast_tracepoint_jump_pad */
NULL, /* emit_ops */
NULL, /* get_min_fast_tracepoint_insn_len */
NULL, /* supports_range_stepping */
arm_breakpoint_kind_from_current_state
};
void

View File

@ -3084,7 +3084,8 @@ linux_wait_1 (ptid_t ptid,
int breakpoint_kind = 0;
CORE_ADDR stop_pc = event_child->stop_pc;
breakpoint_kind = the_target->breakpoint_kind_from_pc (&stop_pc);
breakpoint_kind =
the_target->breakpoint_kind_from_current_state (&stop_pc);
the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc);
if (debug_threads)
@ -7036,6 +7037,18 @@ linux_sw_breakpoint_from_kind (int kind, int *size)
return (*the_low_target.sw_breakpoint_from_kind) (kind, size);
}
/* Implementation of the target_ops method
"breakpoint_kind_from_current_state". */
static int
linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
{
if (the_low_target.breakpoint_kind_from_current_state != NULL)
return (*the_low_target.breakpoint_kind_from_current_state) (pcptr);
else
return linux_breakpoint_kind_from_pc (pcptr);
}
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_arch_setup,
@ -7133,6 +7146,7 @@ static struct target_ops linux_target_ops = {
linux_breakpoint_kind_from_pc,
linux_sw_breakpoint_from_kind,
linux_proc_tid_get_name,
linux_breakpoint_kind_from_current_state
};
static void

View File

@ -233,6 +233,9 @@ struct linux_target_ops
/* Returns true if the low target supports range stepping. */
int (*supports_range_stepping) (void);
/* See target.h. */
int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
};
extern struct linux_target_ops the_low_target;

View File

@ -457,6 +457,12 @@ struct target_ops
/* Return the thread's name, or NULL if the target is unable to determine it.
The returned value must not be freed by the caller. */
const char *(*thread_name) (ptid_t thread);
/* Return the breakpoint kind for this target based on the current
processor state (e.g. the current instruction mode on ARM) and the
PC. The PCPTR is adjusted to the real memory location in case a flag
(e.g., the Thumb bit on ARM) is present in the PC. */
int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
};
extern struct target_ops *the_target;
@ -644,6 +650,11 @@ int kill_inferior (int);
? (*the_target->breakpoint_kind_from_pc) (pcptr) \
: default_breakpoint_kind_from_pc (pcptr))
#define target_breakpoint_kind_from_current_state(pcptr) \
(the_target->breakpoint_kind_from_current_state \
? (*the_target->breakpoint_kind_from_current_state) (pcptr) \
: target_breakpoint_kind_from_pc (pcptr))
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);