From: Yao Qi Date: Thu, 3 Nov 2016 14:35:14 +0000 (+0000) Subject: Determine the kind of single step breakpoint X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=833b7ab5008b769dca6db6d5ee1d21d33e730132;p=binutils-gdb.git Determine the kind of single step breakpoint This patch adds a new gdbarch method breakpoint_kind_from_current_state for single step breakpoint, and uses it in breakpoint_kind. gdb: 2016-11-03 Yao Qi * 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. Update comments. * gdbarch.sh (breakpoint_kind_from_current_state): New. * gdbarch.c, gdbarch.h: Regenerate. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 313e24c1f2f..3482f71e063 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2016-11-03 Yao Qi + + * 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. Update comments. + * gdbarch.sh (breakpoint_kind_from_current_state): New. + * gdbarch.c, gdbarch.h: Regenerate. + 2016-11-03 Yao Qi * arch-utils.c (default_breakpoint_from_pc): New function. diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 39e8eb53e4d..d64a73db2eb 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -848,6 +848,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 791725db977..9592580d79b 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -218,6 +218,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 ac989447041..28fc20c4414 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -7901,6 +7901,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. */ @@ -9409,6 +9462,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 9afbdbdd58e..3908dabffec 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2603,12 +2603,26 @@ build_target_command_list (struct bp_location *bl) bl->target_info.persist = 1; } -/* Return the kind of breakpoint on address *ADDR. */ +/* Return the kind of breakpoint on address *ADDR. Get the kind + of breakpoint according to ADDR except single-step breakpoint. + Get the kind of single-step breakpoint according to the current + registers state. */ 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 1a3acabd49a..463f6e0b89c 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -232,6 +232,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; @@ -406,6 +407,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; @@ -587,6 +589,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 */ @@ -795,6 +798,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (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)); @@ -2822,6 +2828,23 @@ set_gdbarch_sw_breakpoint_from_kind (struct gdbarch *gdbarch, gdbarch->sw_breakpoint_from_kind = sw_breakpoint_from_kind; } +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) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 09cb8cc7fe1..add7e13383b 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -564,6 +564,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 e3ead6b440c..ae7dd97c531 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -569,6 +569,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