[PATCH 12/13] Determine the kind of single step breakpoint

Yao Qi
2016-08-31T15:06:44Z

This patch adds a new gdbarch method breakpoint_kind_from_current_state
for single step breakpoint, and uses it in breakpoint_kind.

gdb:

2016-07-20 Yao Qi <yao.qi@linaro.org>

* arch-utils.c (default_breakpoint_kind_from_current_state):
New function.
* arch-utils.h (default_breakpoint_kind_from_current_state):
Declare.
* arm-tdep.c (arm_breakpoint_kind_from_current_state): New
function.
(arm_gdbarch_init): Call
set_gdbarch_breakpoint_kind_from_current_state.
* breakpoint.c (breakpoint_kind): Call
gdbarch_breakpoint_kind_from_current_state for single step
breakpoint.
* gdbarch.sh (breakpoint_kind_from_current_state): New.
* gdbarch.c, gdbarch.h: Regenerate.
---
gdb/arch-utils.c | 8 ++++++++
gdb/arch-utils.h | 4 ++++
gdb/arm-tdep.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/breakpoint.c | 13 ++++++++++++-
gdb/gdbarch.c | 23 +++++++++++++++++++++++
gdb/gdbarch.h | 8 ++++++++
gdb/gdbarch.sh | 5 +++++
7 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index e236877..ad2787a 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -820,6 +820,14 @@ default_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,

return gdbarch_sw_breakpoint_from_kind (gdbarch, kind, lenptr);
}
+int
+default_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR *pcptr)
+{
+ return gdbarch_breakpoint_kind_from_pc (gdbarch, pcptr);
+}
+

void
default_gen_return_address (struct gdbarch *gdbarch,
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 4af8b9f..2db5ce7 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -213,6 +213,10 @@ extern const gdb_byte *default_breakpoint_from_pc (struct gdbarch *gdbarch,
CORE_ADDR *pcptr,
int *lenptr);

+extern int default_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR *pcptr);
+
extern void default_gen_return_address (struct gdbarch *gdbarch,
struct agent_expr *ax,
struct axs_value *value,
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index f03897c..37b68ed 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -7853,6 +7853,59 @@ arm_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
}
}

+/* Implement the breakpoint_kind_from_current_state gdbarch method. */
+
+static int
+arm_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR *pcptr)
+{
+ gdb_byte buf[4];
+
+ /* Check the memory pointed by PC is readable. */
+ if (target_read_memory (regcache_read_pc (regcache), buf, 4) == 0)
+ {
+ struct arm_get_next_pcs next_pcs_ctx;
+ CORE_ADDR pc;
+ int i;
+ VEC (CORE_ADDR) *next_pcs = NULL;
+ struct cleanup *old_chain
+ = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
+
+ arm_get_next_pcs_ctor (&next_pcs_ctx,
+ &arm_get_next_pcs_ops,
+ gdbarch_byte_order (gdbarch),
+ gdbarch_byte_order_for_code (gdbarch),
+ 0,
+ regcache);
+
+ next_pcs = arm_get_next_pcs (&next_pcs_ctx);
+
+ /* If MEMADDR is the next instruction of current pc, do the
+ software single step computation, and get the thumb mode by
+ the destination address. */
+ for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
+ {
+ if (UNMAKE_THUMB_ADDR (pc) == *pcptr)
+ {
+ do_cleanups (old_chain);
+
+ if (IS_THUMB_ADDR (pc))
+ {
+ *pcptr = MAKE_THUMB_ADDR (*pcptr);
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
+ }
+ else
+ return ARM_BP_KIND_ARM;
+ }
+ }
+
+ do_cleanups (old_chain);
+ }
+
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
+}
+
/* Extract from an array REGBUF containing the (raw) register state a
function return value of type TYPE, and copy that, in virtual
format, into VALBUF. */
@@ -9361,6 +9414,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

/* Breakpoint manipulation. */
SET_GDBARCH_BREAKPOINT_MANIPULATION (arm);
+ set_gdbarch_breakpoint_kind_from_current_state (gdbarch,
+ arm_breakpoint_kind_from_current_state);

/* Information about registers, etc. */
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index cc672f7..2b6976e 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2607,7 +2607,18 @@ build_target_command_list (struct bp_location *bl)
static int
breakpoint_kind (struct bp_location *bl, CORE_ADDR *addr)
{
- return gdbarch_breakpoint_kind_from_pc (bl->gdbarch, addr);
+ if (bl->owner->type == bp_single_step)
+ {
+ struct thread_info *thr = find_thread_global_id (bl->owner->thread);
+ struct regcache *regcache;
+
+ regcache = get_thread_regcache (thr->ptid);
+
+ return gdbarch_breakpoint_kind_from_current_state (bl->gdbarch,
+ regcache, addr);
+ }
+ else
+ return gdbarch_breakpoint_kind_from_pc (bl->gdbarch, addr);
}

/* Insert a low-level "breakpoint" of some type. BL is the breakpoint
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index ca430a9..e480023 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -231,6 +231,7 @@ struct gdbarch
gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc;
gdbarch_breakpoint_kind_from_pc_ftype *breakpoint_kind_from_pc;
gdbarch_sw_breakpoint_from_kind_ftype *sw_breakpoint_from_kind;
+ gdbarch_breakpoint_kind_from_current_state_ftype *breakpoint_kind_from_current_state;
gdbarch_adjust_breakpoint_address_ftype *adjust_breakpoint_address;
gdbarch_memory_insert_breakpoint_ftype *memory_insert_breakpoint;
gdbarch_memory_remove_breakpoint_ftype *memory_remove_breakpoint;
@@ -404,6 +405,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->return_in_first_hidden_param_p = default_return_in_first_hidden_param_p;
gdbarch->breakpoint_from_pc = default_breakpoint_from_pc;
gdbarch->sw_breakpoint_from_kind = NULL;
+ gdbarch->breakpoint_kind_from_current_state = default_breakpoint_kind_from_current_state;
gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
gdbarch->remote_register_number = default_remote_register_number;
@@ -584,6 +586,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
if (gdbarch->breakpoint_kind_from_pc == 0)
fprintf_unfiltered (log, "\n\tbreakpoint_kind_from_pc");
/* Skip verify of sw_breakpoint_from_kind, invalid_p == 0 */
+ /* Skip verify of breakpoint_kind_from_current_state, invalid_p == 0 */
/* Skip verify of adjust_breakpoint_address, has predicate. */
/* Skip verify of memory_insert_breakpoint, invalid_p == 0 */
/* Skip verify of memory_remove_breakpoint, invalid_p == 0 */
@@ -793,6 +796,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: breakpoint_from_pc = <%s>\n",
host_address_to_string (gdbarch->breakpoint_from_pc));
fprintf_unfiltered (file,
+ "gdbarch_dump: breakpoint_kind_from_current_state = <%s>\n",
+ host_address_to_string (gdbarch->breakpoint_kind_from_current_state));
+ fprintf_unfiltered (file,
"gdbarch_dump: breakpoint_kind_from_pc = <%s>\n",
host_address_to_string (gdbarch->breakpoint_kind_from_pc));
fprintf_unfiltered (file,
@@ -2800,6 +2806,23 @@ set_gdbarch_sw_breakpoint_from_kind (struct gdbarch *gdbarch,
}

int
+gdbarch_breakpoint_kind_from_current_state (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR *pcptr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->breakpoint_kind_from_current_state != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_breakpoint_kind_from_current_state called\n");
+ return gdbarch->breakpoint_kind_from_current_state (gdbarch, regcache, pcptr);
+}
+
+void
+set_gdbarch_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ gdbarch_breakpoint_kind_from_current_state_ftype breakpoint_kind_from_current_state)
+{
+ gdbarch->breakpoint_kind_from_current_state = breakpoint_kind_from_current_state;
+}
+
+int
gdbarch_adjust_breakpoint_address_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 65a6a6e..0df6dc8 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -556,6 +556,14 @@ typedef const gdb_byte * (gdbarch_sw_breakpoint_from_kind_ftype) (struct gdbarch
extern const gdb_byte * gdbarch_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size);
extern void set_gdbarch_sw_breakpoint_from_kind (struct gdbarch *gdbarch, gdbarch_sw_breakpoint_from_kind_ftype *sw_breakpoint_from_kind);

+/* Return the breakpoint kind for this target based on the current
+ processor state (e.g. the current instruction mode on ARM) and the
+ *PCPTR. In default, it is gdbarch->breakpoint_kind_from_pc. */
+
+typedef int (gdbarch_breakpoint_kind_from_current_state_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR *pcptr);
+extern int gdbarch_breakpoint_kind_from_current_state (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR *pcptr);
+extern void set_gdbarch_breakpoint_kind_from_current_state (struct gdbarch *gdbarch, gdbarch_breakpoint_kind_from_current_state_ftype *breakpoint_kind_from_current_state);
+
extern int gdbarch_adjust_breakpoint_address_p (struct gdbarch *gdbarch);

typedef CORE_ADDR (gdbarch_adjust_breakpoint_address_ftype) (struct gdbarch *gdbarch, CORE_ADDR bpaddr);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index c999f30..82d2c71 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -564,6 +564,11 @@ m:int:breakpoint_kind_from_pc:CORE_ADDR *pcptr:pcptr::0:
# SIZE is set to the software breakpoint's length in memory.
m:const gdb_byte *:sw_breakpoint_from_kind:int kind, int *size:kind, size::NULL::0

+# Return the breakpoint kind for this target based on the current
+# processor state (e.g. the current instruction mode on ARM) and the
+# *PCPTR. In default, it is gdbarch->breakpoint_kind_from_pc.
+m:int:breakpoint_kind_from_current_state:struct regcache *regcache, CORE_ADDR *pcptr:regcache, pcptr:0:default_breakpoint_kind_from_current_state::0
+
M:CORE_ADDR:adjust_breakpoint_address:CORE_ADDR bpaddr:bpaddr
m:int:memory_insert_breakpoint:struct bp_target_info *bp_tgt:bp_tgt:0:default_memory_insert_breakpoint::0
m:int:memory_remove_breakpoint:struct bp_target_info *bp_tgt:bp_tgt:0:default_memory_remove_breakpoint::0
--
1.9.1