[RFA] Try2: Ignore breakpoints when reading memory.

Vladimir Prus
2008-02-24T14:51:00Z

This a second attempt at making gdb always ignore
any memory breakpoints that are inserted and show the original
memory content. This patch is the immediate prerequisite for the
patch that makes breakpoints always inserted.

Unlike the previous patch, there's a mechanism to:
1. Control the new behaviour from command line.
2. Temporary force specific behavior, if some code
needs it.

OK?

- Volodya

* breakpoint.h (breakpoint_restore_shadows): New
declaration.
* breakpoint.c (breakpoint_restore_shadows): New.
(read_memory_nobpt): Use breakpoint_restore_shadows.
* target.c (memory_xfer_partial): Call
breakpoint_restore_shadows.
(restore_show_memory_breakpoints)
(make_show_memory_beakpoints_cleanup): New.
(show_memory_breakpoints, show_show_memory_breakpoints): New.
(initialize_targets): Register set/show 'show-memory-breakpoints'.
* target.h (make_show_memory_beakpoints_cleanup): Declare.
* ppc-linux-tdep.c (ppc_linux_memory_remove_breakpoint):
Make sure we see memory breakpoints when checking if
breakpoint is still there.
---
gdb/breakpoint.c | 83 +++++++++++++++++++++----------------------------
gdb/breakpoint.h | 4 ++
gdb/ppc-linux-tdep.c | 4 ++
gdb/target.c | 52 +++++++++++++++++++++++++++++--
gdb/target.h | 5 +++
5 files changed, 98 insertions(+), 50 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index dca4ca1..9a7800c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -712,14 +712,26 @@ commands_from_control_command (char *arg, struct command_line *cmd)
int
read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr, unsigned len)
{
- int status;
- const struct bp_location *b;
+ int status = 0;
+ /* Make sure the following read will ignore memory breakpoints. */
+ struct cleanup *cleanup = make_show_memory_breakpoints_cleanup (0);
+
+ status = target_read_memory (memaddr, myaddr, len);
+
+ do_cleanups (cleanup);
+
+ return status;
+}
+
+void
+breakpoint_restore_shadows (gdb_byte *buf,
+ ULONGEST memaddr,
+ LONGEST len)
+{
+ struct bp_location *b;
CORE_ADDR bp_addr = 0;
int bp_size = 0;
-
- if (gdbarch_breakpoint_from_pc (current_gdbarch, &bp_addr, &bp_size) == NULL)
- /* No breakpoints on this machine. */
- return target_read_memory (memaddr, myaddr, len);
+ int bptoffset = 0;

ALL_BP_LOCATIONS (b)
{
@@ -738,60 +750,37 @@ read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr, unsigned len)
if (bp_size == 0)
/* bp isn't valid, or doesn't shadow memory. */
continue;
+
if (bp_addr + bp_size <= memaddr)
/* The breakpoint is entirely before the chunk of memory we
are reading. */
continue;
+
if (bp_addr >= memaddr + len)
/* The breakpoint is entirely after the chunk of memory we are
reading. */
continue;
- /* Copy the breakpoint from the shadow contents, and recurse for
- the things before and after. */
- {
- /* Offset within shadow_contents. */
- int bptoffset = 0;
-
- if (bp_addr < memaddr)
- {
- /* Only copy the second part of the breakpoint. */
- bp_size -= memaddr - bp_addr;
- bptoffset = memaddr - bp_addr;
- bp_addr = memaddr;
- }

- if (bp_addr + bp_size > memaddr + len)
- {
- /* Only copy the first part of the breakpoint. */
- bp_size -= (bp_addr + bp_size) - (memaddr + len);
- }
-
- memcpy (myaddr + bp_addr - memaddr,
- b->target_info.shadow_contents + bptoffset, bp_size);
+ /* Offset within shadow_contents. */
+ if (bp_addr < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bp_size -= memaddr - bp_addr;
+ bptoffset = memaddr - bp_addr;
+ bp_addr = memaddr;
+ }

- if (bp_addr > memaddr)
- {
- /* Copy the section of memory before the breakpoint. */
- status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
- if (status != 0)
- return status;
- }
+ if (bp_addr + bp_size > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bp_size -= (bp_addr + bp_size) - (memaddr + len);
+ }

- if (bp_addr + bp_size < memaddr + len)
- {
- /* Copy the section of memory after the breakpoint. */
- status = read_memory_nobpt (bp_addr + bp_size,
- myaddr + bp_addr + bp_size - memaddr,
- memaddr + len - (bp_addr + bp_size));
- if (status != 0)
- return status;
- }
- return 0;
- }
+ memcpy (buf + bp_addr - memaddr,
+ b->target_info.shadow_contents + bptoffset, bp_size);
}
- /* Nothing overlaps. Just call read_memory_noerr. */
- return target_read_memory (memaddr, myaddr, len);
}
+
\f

/* A wrapper function for inserting catchpoints. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 41730c0..159c406 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -854,4 +854,8 @@ extern int deprecated_remove_raw_breakpoint (void *);
target. */
int watchpoints_triggered (struct target_waitstatus *);

+extern void breakpoint_restore_shadows (gdb_byte *buf,
+ ULONGEST memaddr,
+ LONGEST len);
+
#endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 4b35f7f..bf084f5 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -280,12 +280,15 @@ ppc_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
int val;
int bplen;
gdb_byte old_contents[BREAKPOINT_MAX];
+ struct cleanup *cleanup;

/* Determine appropriate breakpoint contents and size for this address. */
bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen);
if (bp == NULL)
error (_("Software breakpoints not implemented for this target."));

+ /* Make sure we see the memory breakpoints. */
+ cleanup = make_show_memory_breakpoints_cleanup (1);
val = target_read_memory (addr, old_contents, bplen);

/* If our breakpoint is no longer at the address, this means that the
@@ -294,6 +297,7 @@ ppc_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);

+ do_cleanups (cleanup);
return val;
}

diff --git a/gdb/target.c b/gdb/target.c
index 87ddf24..32271eb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -203,6 +203,18 @@ int attach_flag;

static int trust_readonly = 0;

+/* Nonzero if we should show true memory content including
+ memory breakpoint inserted by gdb. */
+
+static int show_memory_breakpoints = 0;
+
+static void
+show_show_memory_breakpoints (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Memory breakpoints show mode is %s.\n"), value);
+}
+
/* Non-zero if we want to see trace of target level stuff. */

static int targetdebug = 0;
@@ -1064,7 +1076,11 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf
if (res <= 0)
return -1;
else
- return res;
+ {
+ if (readbuf && !show_memory_breakpoints)
+ breakpoint_restore_shadows (readbuf, memaddr, reg_len);
+ return res;
+ }
}

/* If none of those methods found the memory we wanted, fall back
@@ -1082,22 +1098,40 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf
res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
readbuf, writebuf, memaddr, reg_len);
if (res > 0)
- return res;
+ break;

/* We want to continue past core files to executables, but not
past a running target's memory. */
if (ops->to_has_all_memory)
- return res;
+ break;

ops = ops->beneath;
}
while (ops != NULL);

+ if (readbuf && !show_memory_breakpoints)
+ breakpoint_restore_shadows (readbuf, memaddr, reg_len);
+
/* If we still haven't got anything, return the last error. We
give up. */
return res;
}

+static void
+restore_show_memory_breakpoints (void *arg)
+{
+ show_memory_breakpoints = (int)arg;
+}
+
+struct cleanup *
+make_show_memory_breakpoints_cleanup (int show)
+{
+ int current = show_memory_breakpoints;
+ show_memory_breakpoints = show;
+
+ return make_cleanup (restore_show_memory_breakpoints, (void *)current);
+}
+
static LONGEST
target_xfer_partial (struct target_ops *ops,
enum target_object object, const char *annex,
@@ -2798,6 +2832,18 @@ result in significant performance improvement for remote targets."),
show_trust_readonly,
&setlist, &showlist);

+ add_setshow_boolean_cmd ("show-memory-breakpoints", class_support,
+ &show_memory_breakpoints, _("\
+Set mode for showing memory breakpoints."), _("\
+Show mode for showing memory breakpoints."), _("\
+When this mode is off (which is default), all memory reads will return\n\
+memory content as if no memory breakpoint were inserted. When this mode\n\
+if on, memory reads will see inserted memory breakpoints. In particular,\n\
+the disassemble command will show the breakpoint instructions."),
+ NULL,
+ show_show_memory_breakpoints,
+ &setlist, &showlist);
+
add_com ("monitor", class_obscure, do_monitor_command,
_("Send a command to the remote monitor (remote targets only)."));

diff --git a/gdb/target.h b/gdb/target.h
index 3f332fd..dcc5cee 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1248,6 +1248,11 @@ extern enum target_signal target_signal_from_command (int);

/* Any target can call this to switch to remote protocol (in remote.c). */
extern void push_remote_target (char *name, int from_tty);
+
+/* Set the show memory breakpoints mode to show, and installs a cleanup
+ to restore it back to the current value. */
+extern struct cleanup * make_show_memory_breakpoints_cleanup (int show);
+
\f
/* Imported from machine dependent code */

--
1.5.3.5