diff options
author | Yao Qi <yao.qi@linaro.org> | 2016-11-03 14:35:14 +0000 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2016-11-03 14:35:14 +0000 |
commit | 833b7ab5008b769dca6db6d5ee1d21d33e730132 (patch) | |
tree | fc32095c2c5c42d58de5ef58eeec05fb0af80da2 | |
parent | 22f13eb869197fc45a0da2a8a96b03d39809862e (diff) | |
download | gdb-833b7ab5008b769dca6db6d5ee1d21d33e730132.zip gdb-833b7ab5008b769dca6db6d5ee1d21d33e730132.tar.gz gdb-833b7ab5008b769dca6db6d5ee1d21d33e730132.tar.bz2 |
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 <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. Update comments.
* gdbarch.sh (breakpoint_kind_from_current_state): New.
* gdbarch.c, gdbarch.h: Regenerate.
-rw-r--r-- | gdb/ChangeLog | 16 | ||||
-rw-r--r-- | gdb/arch-utils.c | 8 | ||||
-rw-r--r-- | gdb/arch-utils.h | 4 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 55 | ||||
-rw-r--r-- | gdb/breakpoint.c | 18 | ||||
-rw-r--r-- | gdb/gdbarch.c | 23 | ||||
-rw-r--r-- | gdb/gdbarch.h | 8 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 5 |
8 files changed, 135 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 313e24c..3482f71 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,21 @@ 2016-11-03 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. Update comments. + * gdbarch.sh (breakpoint_kind_from_current_state): New. + * gdbarch.c, gdbarch.h: Regenerate. + +2016-11-03 Yao Qi <yao.qi@linaro.org> + * arch-utils.c (default_breakpoint_from_pc): New function. * arch-utils.h (GDBARCH_BREAKPOINT_FROM_PC): Remove. (GDBARCH_BREAKPOINT_MANIPULATION): Don't use diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 39e8eb5..d64a73d 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 791725d..9592580 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 ac98944..28fc20c 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 9afbdbd..3908dab 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 1a3acab..463f6e0 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 */ @@ -796,6 +799,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, @@ -2823,6 +2829,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 09cb8cc..add7e13 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 e3ead6b..ae7dd97 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 |