aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/breakpoint.c60
-rw-r--r--gdb/breakpoint.h5
-rw-r--r--gdb/infrun.c23
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,