summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2011-12-06 20:03:14 +0000
committerPedro Alves <palves@redhat.com>2011-12-06 20:03:14 +0000
commitf0ba3972e968a8f328d2d465bbd1218e228fbf2a (patch)
treedaeb62e5fc8f74947ee31f0f14a3bcccd14f2006 /gdb
parent31aba06f31d348be54adb50195af858baff6256f (diff)
2011-12-06 Pedro Alves <pedro@codesourcery.com>
gdb/ * breakpoint.c (breakpoint_restore_shadows): Rename to ... (breakpoint_xfer_memory): ... this. Change prototype. Handle memory writes too. * breakpoint.h (breakpoint_restore_shadows): Delete. (breakpoint_xfer_memory): Declare. * mem-break.c (default_memory_insert_breakpoint) (default_memory_remove_breakpoint): Use target_write_raw_memory. (memory_xfer_partial): Rename to ... (memory_xfer_partial_1): ... this. Don't mask out breakpoints here. (memory_xfer_partial): New. (target_write_raw_memory): New. * target.h (target_write_raw_memory): New. gdb/testsuite/ * gdb.base/break-always.exp: Test changing memory at addresses with breakpoints inserted.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/breakpoint.c32
-rw-r--r--gdb/breakpoint.h15
-rw-r--r--gdb/mem-break.c8
-rw-r--r--gdb/target.c80
-rw-r--r--gdb/target.h3
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.base/break-always.exp37
8 files changed, 169 insertions, 27 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ffecf05594..cd9507a37d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,19 @@
+2011-12-06 Pedro Alves <pedro@codesourcery.com>
+
+ * breakpoint.c (breakpoint_restore_shadows): Rename to ...
+ (breakpoint_xfer_memory): ... this. Change prototype. Handle
+ memory writes too.
+ * breakpoint.h (breakpoint_restore_shadows): Delete.
+ (breakpoint_xfer_memory): Declare.
+ * mem-break.c (default_memory_insert_breakpoint)
+ (default_memory_remove_breakpoint): Use target_write_raw_memory.
+ (memory_xfer_partial): Rename to ...
+ (memory_xfer_partial_1): ... this. Don't mask out breakpoints
+ here.
+ (memory_xfer_partial): New.
+ (target_write_raw_memory): New.
+ * target.h (target_write_raw_memory): New.
+
2011-12-06 Doug Evans <dje@google.com>
* linespec.c (decode_dollar): Avoid "may be used uninitialized" warning.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index bd0a0e3295..d9d5bbe592 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1049,7 +1049,9 @@ bp_location_has_shadow (struct bp_location *bl)
bl->address + bp_location_shadow_len_after_address_max <= memaddr */
void
-breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
+breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
+ const gdb_byte *writebuf_org,
+ ULONGEST memaddr, LONGEST len)
{
/* Left boundary, right boundary and median element of our binary
search. */
@@ -1161,8 +1163,32 @@ breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
bp_size -= (bp_addr + bp_size) - (memaddr + len);
}
- memcpy (buf + bp_addr - memaddr,
- bl->target_info.shadow_contents + bptoffset, bp_size);
+ if (readbuf != NULL)
+ {
+ /* Update the read buffer with this inserted breakpoint's
+ shadow. */
+ memcpy (readbuf + bp_addr - memaddr,
+ bl->target_info.shadow_contents + bptoffset, bp_size);
+ }
+ else
+ {
+ struct gdbarch *gdbarch = bl->gdbarch;
+ const unsigned char *bp;
+ CORE_ADDR placed_address = bl->target_info.placed_address;
+ unsigned placed_size = bl->target_info.placed_size;
+
+ /* Update the shadow with what we want to write to memory. */
+ memcpy (bl->target_info.shadow_contents + bptoffset,
+ writebuf_org + bp_addr - memaddr, bp_size);
+
+ /* Determine appropriate breakpoint contents and size for this
+ address. */
+ bp = gdbarch_breakpoint_from_pc (gdbarch, &placed_address, &placed_size);
+
+ /* Update the final write buffer with this inserted
+ breakpoint's INSN. */
+ memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size);
+ }
}
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index ead3930e18..ddf1881011 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1296,10 +1296,17 @@ extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
target. */
int watchpoints_triggered (struct target_waitstatus *);
-/* Update BUF, which is LEN bytes read from the target address MEMADDR,
- by replacing any memory breakpoints with their shadowed contents. */
-void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr,
- LONGEST len);
+/* Helper for transparent breakpoint hiding for memory read and write
+ routines.
+
+ Update one of READBUF or WRITEBUF with either the shadows
+ (READBUF), or the breakpoint instructions (WRITEBUF) of inserted
+ breakpoints at the memory range defined by MEMADDR and extending
+ for LEN bytes. If writing, then WRITEBUF is a copy of WRITEBUF_ORG
+ on entry.*/
+extern void breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
+ const gdb_byte *writebuf_org,
+ ULONGEST memaddr, LONGEST len);
extern int breakpoints_always_inserted_mode (void);
diff --git a/gdb/mem-break.c b/gdb/mem-break.c
index ba7dc242e5..31ca45cdf6 100644
--- a/gdb/mem-break.c
+++ b/gdb/mem-break.c
@@ -60,8 +60,8 @@ default_memory_insert_breakpoint (struct gdbarch *gdbarch,
/* Write the breakpoint. */
if (val == 0)
- val = target_write_memory (bp_tgt->placed_address, bp,
- bp_tgt->placed_size);
+ val = target_write_raw_memory (bp_tgt->placed_address, bp,
+ bp_tgt->placed_size);
return val;
}
@@ -71,8 +71,8 @@ int
default_memory_remove_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- return target_write_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
- bp_tgt->placed_size);
+ return target_write_raw_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
+ bp_tgt->placed_size);
}
diff --git a/gdb/target.c b/gdb/target.c
index 6358b00f48..5700066415 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1388,19 +1388,15 @@ memory_xfer_live_readonly_partial (struct target_ops *ops,
For docs see target.h, to_xfer_partial. */
static LONGEST
-memory_xfer_partial (struct target_ops *ops, enum target_object object,
- void *readbuf, const void *writebuf, ULONGEST memaddr,
- LONGEST len)
+memory_xfer_partial_1 (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
{
LONGEST res;
int reg_len;
struct mem_region *region;
struct inferior *inf;
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- return 0;
-
/* For accesses to unmapped overlay sections, read directly from
files. Must do this first, as MEMADDR may need adjustment. */
if (readbuf != NULL && overlay_debugging)
@@ -1551,11 +1547,7 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
if (res <= 0)
return -1;
else
- {
- if (readbuf && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
- return res;
- }
+ return res;
}
/* If none of those methods found the memory we wanted, fall back
@@ -1584,9 +1576,6 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
}
while (ops != NULL);
- if (res > 0 && readbuf != NULL && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
-
/* Make sure the cache gets updated no matter what - if we are writing
to the stack. Even if this write is not tagged as such, we still need
to update the cache. */
@@ -1606,6 +1595,48 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
return res;
}
+/* Perform a partial memory transfer. For docs see target.h,
+ to_xfer_partial. */
+
+static LONGEST
+memory_xfer_partial (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ int res;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ return 0;
+
+ /* Fill in READBUF with breakpoint shadows, or WRITEBUF with
+ breakpoint insns, thus hiding out from higher layers whether
+ there are software breakpoints inserted in the code stream. */
+ if (readbuf != NULL)
+ {
+ res = memory_xfer_partial_1 (ops, object, readbuf, NULL, memaddr, len);
+
+ if (res > 0 && !show_memory_breakpoints)
+ breakpoint_xfer_memory (readbuf, NULL, NULL, memaddr, res);
+ }
+ else
+ {
+ void *buf;
+ struct cleanup *old_chain;
+
+ buf = xmalloc (len);
+ old_chain = make_cleanup (xfree, buf);
+ memcpy (buf, writebuf, len);
+
+ breakpoint_xfer_memory (NULL, buf, writebuf, memaddr, len);
+ res = memory_xfer_partial_1 (ops, object, NULL, buf, memaddr, len);
+
+ do_cleanups (old_chain);
+ }
+
+ return res;
+}
+
static void
restore_show_memory_breakpoints (void *arg)
{
@@ -1761,6 +1792,25 @@ target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
return EIO;
}
+/* Write LEN bytes from MYADDR to target raw memory at address
+ MEMADDR. Returns either 0 for success or an errno value if any
+ error occurs. If an error occurs, no guarantee is made about how
+ much data got written. Callers that can deal with partial writes
+ should call target_write. */
+
+int
+target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+{
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+ if (target_write (current_target.beneath, TARGET_OBJECT_RAW_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
+ else
+ return EIO;
+}
+
/* Fetch the target's memory map. */
VEC(mem_region_s) *
diff --git a/gdb/target.h b/gdb/target.h
index 1261d90e06..fd488d66f3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -941,6 +941,9 @@ extern int target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len);
extern int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr,
int len);
+extern int target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr,
+ int len);
+
/* Fetches the target's memory map. If one is found it is sorted
and returned, after some consistency checking. Otherwise, NULL
is returned. */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7626a06fd1..ca83855a32 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-12-06 Pedro Alves <pedro@codesourcery.com>
+
+ * gdb.base/break-always.exp: Test changing memory at addresses
+ with breakpoints inserted.
+
2011-12-06 Joel Brobecker <brobecker@acacore.com>
* gdb.ada/fullname_bp.exp: Add tests for other valid linespecs
diff --git a/gdb/testsuite/gdb.base/break-always.exp b/gdb/testsuite/gdb.base/break-always.exp
index ce76af7c06..e20794e99d 100644
--- a/gdb/testsuite/gdb.base/break-always.exp
+++ b/gdb/testsuite/gdb.base/break-always.exp
@@ -49,7 +49,42 @@ gdb_test_no_output "enable 2" "enable 2.H"
gdb_test_no_output "disable 2" "disable 2.I"
gdb_test "info breakpoints" "keep n.*keep n.*keep y.*keep n.*keep n.*" "before re-enable check breakpoint state"
gdb_test_no_output "enable" "re-enable all breakpoints"
-gdb_continue_to_breakpoint "bar" ".*break-always.c:$bar_location.*"
+set bp_address 0
+set test "set breakpoint on bar 2"
+gdb_test_multiple "break bar" $test {
+ -re "Breakpoint 6 at ($hex).*$gdb_prompt $" {
+ set bp_address $expect_out(1,string)
+ pass $test
+ }
+}
+
+# Save the original INSN under the breakpoint.
+gdb_test "p /x \$shadow = *(char *) $bp_address" \
+ " = $hex" \
+ "save shadow"
+# Overwrite memory where the breakpoint is planted. GDB should update
+# its memory breakpoint's shadows, to account for the new contents,
+# and still leave the breakpoint insn planted. Try twice with
+# different values, in case we happen to be writting exactly what was
+# there already.
+gdb_test "p /x *(char *) $bp_address = 0" \
+ " = 0x0" \
+ "write 0 to breakpoint's address"
+gdb_test "p /x *(char *) $bp_address" \
+ " = 0x0" \
+ "read back 0 from the breakpoint's address"
+gdb_test "p /x *(char *) $bp_address = 1" \
+ " = 0x1" \
+ "write 1 to breakpoint's address"
+gdb_test "p /x *(char *) $bp_address" \
+ " = 0x1" \
+ "read back 1 from the breakpoint's address"
+
+# Restore the original contents.
+gdb_test "p /x *(char *) $bp_address = \$shadow" ""
+
+# Run to breakpoint.
+gdb_continue_to_breakpoint "bar" ".*break-always.c:$bar_location.*"