diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/breakpoint.c | 60 | ||||
-rw-r--r-- | gdb/breakpoint.h | 5 | ||||
-rw-r--r-- | gdb/infrun.c | 23 |
4 files changed, 96 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index acefa8e..38a42ea 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2015-10-30 Pedro Alves <palves@redhat.com> + + * breakpoint.c (breakpoint_in_range_p) + (breakpoint_location_address_range_overlap): New functions. + * breakpoint.h (breakpoint_in_range_p): New declaration. + * infrun.c (displaced_step_prepare_throw): If there's a breakpoint + in the scratch pad range, don't displaced step. + 2015-10-30 Marcin KoĆcielnicki <koriakin@0x04.net> * amd64-linux-tdep.c (amd64_x32_linux_init_abi): Fix size_msghdr, diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 2c901ff..5863573 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -173,6 +173,10 @@ static int breakpoint_location_address_match (struct bp_location *bl, struct address_space *aspace, CORE_ADDR addr); +static int breakpoint_location_address_range_overlap (struct bp_location *, + struct address_space *, + CORE_ADDR, int); + static void breakpoints_info (char *, int); static void watchpoints_info (char *, int); @@ -4243,6 +4247,40 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc) return any_breakpoint_here ? ordinary_breakpoint_here : no_breakpoint_here; } +/* See breakpoint.h. */ + +int +breakpoint_in_range_p (struct address_space *aspace, + CORE_ADDR addr, ULONGEST len) +{ + struct bp_location *bl, **blp_tmp; + + ALL_BP_LOCATIONS (bl, blp_tmp) + { + if (bl->loc_type != bp_loc_software_breakpoint + && bl->loc_type != bp_loc_hardware_breakpoint) + continue; + + if ((breakpoint_enabled (bl->owner) + || bl->permanent) + && breakpoint_location_address_range_overlap (bl, aspace, + addr, len)) + { + if (overlay_debugging + && section_is_overlay (bl->section) + && !section_is_mapped (bl->section)) + { + /* Unmapped overlay -- can't be a match. */ + continue; + } + + return 1; + } + } + + return 0; +} + /* Return true if there's a moribund breakpoint at PC. */ int @@ -7079,6 +7117,28 @@ breakpoint_location_address_match (struct bp_location *bl, aspace, addr))); } +/* Returns true if the [ADDR,ADDR+LEN) range in ASPACE overlaps + breakpoint BL. BL may be a ranged breakpoint. In most targets, a + match happens only if ASPACE matches the breakpoint's address + space. On targets that have global breakpoints, the address space + doesn't really matter. */ + +static int +breakpoint_location_address_range_overlap (struct bp_location *bl, + struct address_space *aspace, + CORE_ADDR addr, int len) +{ + if (gdbarch_has_global_breakpoints (target_gdbarch ()) + || bl->pspace->aspace == aspace) + { + int bl_len = bl->length != 0 ? bl->length : 1; + + if (mem_ranges_overlap (addr, len, bl->address, bl_len)) + return 1; + } + return 0; +} + /* If LOC1 and LOC2's owners are not tracepoints, returns false directly. Then, if LOC1 and LOC2 represent the same tracepoint location, returns true, otherwise returns false. */ diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 896d3eb..ee8b2e0 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -1146,6 +1146,11 @@ extern int program_breakpoint_here_p (struct gdbarch *gdbarch, CORE_ADDR address extern enum breakpoint_here breakpoint_here_p (struct address_space *, CORE_ADDR); +/* Return true if an enabled breakpoint exists in the range defined by + ADDR and LEN, in ASPACE. */ +extern int breakpoint_in_range_p (struct address_space *aspace, + CORE_ADDR addr, ULONGEST len); + extern int moribund_breakpoint_here_p (struct address_space *, CORE_ADDR); extern int breakpoint_inserted_here_p (struct address_space *, CORE_ADDR); diff --git a/gdb/infrun.c b/gdb/infrun.c index 917f9be..ef4ccb4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1729,6 +1729,7 @@ displaced_step_prepare_throw (ptid_t ptid) struct thread_info *tp = find_thread_ptid (ptid); struct regcache *regcache = get_thread_regcache (ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct address_space *aspace = get_regcache_aspace (regcache); CORE_ADDR original, copy; ULONGEST len; struct displaced_step_closure *closure; @@ -1784,6 +1785,28 @@ displaced_step_prepare_throw (ptid_t ptid) copy = gdbarch_displaced_step_location (gdbarch); len = gdbarch_max_insn_length (gdbarch); + if (breakpoint_in_range_p (aspace, copy, len)) + { + /* There's a breakpoint set in the scratch pad location range + (which is usually around the entry point). We'd either + install it before resuming, which would overwrite/corrupt the + scratch pad, or if it was already inserted, this displaced + step would overwrite it. The latter is OK in the sense that + we already assume that no thread is going to execute the code + in the scratch pad range (after initial startup) anyway, but + the former is unacceptable. Simply punt and fallback to + stepping over this breakpoint in-line. */ + if (debug_displaced) + { + fprintf_unfiltered (gdb_stdlog, + "displaced: breakpoint set in scratch pad. " + "Stepping over breakpoint in-line instead.\n"); + } + + do_cleanups (old_cleanups); + return -1; + } + /* Save the original contents of the copy area. */ displaced->step_saved_copy = (gdb_byte *) xmalloc (len); ignore_cleanups = make_cleanup (free_current_contents, |