summaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorDaniel Jacobowitz <dan@debian.org>2002-04-20 17:04:09 +0000
committerDaniel Jacobowitz <dan@debian.org>2002-04-20 17:04:09 +0000
commit5f7227726a399f16acf8dc90e91d96d86c6feff7 (patch)
tree27cebeeab7534e32f5bd373c0e405e7d9497ced5 /gdb/gdbserver
parent8aaa2d6e5c53f6e2784bd5d8b0f70d0dcf53e2fb (diff)
downloadgdb-5f7227726a399f16acf8dc90e91d96d86c6feff7.tar.gz
2002-04-20 Daniel Jacobowitz <drow@mvista.com>
* gdbserver/mem-break.c: New file. * gdbserver/mem-break.h: New file. * gdbserver/Makefile.in: Add mem-break.o rule; update server.h dependencies. * gdbserver/inferiors.c (struct inferior_info): Add target_data member. (clear_inferiors): Free target_data member if set. (inferior_target_data, set_inferior_target_data): New functions. * gdbserver/linux-i386-low.c (i386_breakpoint, i386_breakpoint_len) (i386_stop_pc, i386_set_pc): New. Add to the_low_target. * gdbserver/linux-low.c (linux_bp_reinsert): New variable. (struct inferior_linux_data): New. (linux_create_inferior): Use set_inferior_target_data. (linux_attach): Likewise. Call add_inferior. (linux_wait_for_one_inferior): New function. (linux_wait): Call it. (linux_write_memory): Add const. (initialize_low): Call set_breakpoint_data. * gdbserver/linux-low.h (struct linux_target_ops): Add breakpoint handling members. * gdbserver/server.c (attach_inferior): Remove extra add_inferior call. * gdbserver/server.h: Include mem-break.h. Update inferior.c prototypes. * gdbserver/target.c (read_inferior_memory) (write_inferior_memory): New functions. * gdbserver/target.h (read_inferior_memory) (write_inferior_memory): Change macros to prototypes. (struct target_ops): Update comments. Add const to write_memory definition.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/Makefile.in5
-rw-r--r--gdb/gdbserver/inferiors.c17
-rw-r--r--gdb/gdbserver/linux-i386-low.c28
-rw-r--r--gdb/gdbserver/linux-low.c88
-rw-r--r--gdb/gdbserver/linux-low.h5
-rw-r--r--gdb/gdbserver/mem-break.c280
-rw-r--r--gdb/gdbserver/mem-break.h71
-rw-r--r--gdb/gdbserver/server.c2
-rw-r--r--gdb/gdbserver/server.h4
-rw-r--r--gdb/gdbserver/target.c14
-rw-r--r--gdb/gdbserver/target.h17
11 files changed, 515 insertions, 16 deletions
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1e15bc0d887..a0bad13e816 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -124,6 +124,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}
OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
utils.o \
+ mem-break.o \
$(DEPFILES)
# Prevent Sun make from putting in the machine type. Setting
@@ -233,9 +234,11 @@ unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET :
regdat_sh = $(srcdir)/../regformats/regdat.sh
regdef_h = $(srcdir)/../regformats/regdef.h
regcache_h = $(srcdir)/regcache.h
-server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h
+server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \
+ $(srcdir)/mem-break.h
inferiors.o: inferiors.c $(server_h)
+mem-break.o: mem-break.c $(server_h)
regcache.o: regcache.c $(server_h) $(regdef_h)
remote-utils.o: remote-utils.c terminal.h $(server_h)
server.o: server.c $(server_h)
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 1daa3c5de3d..f8cbd04d63b 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -28,6 +28,7 @@
struct inferior_info
{
int pid;
+ void *target_data;
struct inferior_info *next;
};
@@ -63,9 +64,25 @@ clear_inferiors (void)
while (inf)
{
next_inf = inf->next;
+
+ if (inf->target_data)
+ free (inf->target_data);
+
free (inf);
inf = next_inf;
}
inferiors = NULL;
}
+
+void *
+inferior_target_data (struct inferior_info *inferior)
+{
+ return inferior->target_data;
+}
+
+void
+set_inferior_target_data (struct inferior_info *inferior, void *data)
+{
+ inferior->target_data = data;
+}
diff --git a/gdb/gdbserver/linux-i386-low.c b/gdb/gdbserver/linux-i386-low.c
index 2a398d75510..71264321341 100644
--- a/gdb/gdbserver/linux-i386-low.c
+++ b/gdb/gdbserver/linux-i386-low.c
@@ -121,9 +121,37 @@ struct regset_info target_regsets[] = {
#endif /* HAVE_LINUX_REGSETS */
+static const char i386_breakpoint[] = { 0xCC };
+#define i386_breakpoint_len 1
+
+static CORE_ADDR
+i386_stop_pc ()
+{
+ unsigned long pc;
+
+ /* Overkill */
+ fetch_inferior_registers (0);
+
+ collect_register_by_name ("eip", &pc);
+ return pc - 1;
+}
+
+static void
+i386_set_pc (CORE_ADDR newpc)
+{
+ supply_register_by_name ("eip", &newpc);
+
+ /* Overkill */
+ store_inferior_registers (0);
+}
+
struct linux_target_ops the_low_target = {
i386_num_regs,
i386_regmap,
i386_cannot_fetch_register,
i386_cannot_store_register,
+ i386_stop_pc,
+ i386_set_pc,
+ i386_breakpoint,
+ i386_breakpoint_len,
};
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index bd1a87601f5..10966e0afe6 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -35,6 +35,10 @@
#include <stdlib.h>
#include <unistd.h>
+static CORE_ADDR linux_bp_reinsert;
+
+static void linux_resume (int step, int signal);
+
#define PTRACE_ARG3_TYPE long
#define PTRACE_XFER_TYPE long
@@ -46,12 +50,18 @@ extern int errno;
static int inferior_pid;
+struct inferior_linux_data
+{
+ int pid;
+};
+
/* Start an inferior process and returns its pid.
ALLARGS is a vector of program-name and args. */
static int
linux_create_inferior (char *program, char **allargs)
{
+ struct inferior_linux_data *tdata;
int pid;
pid = fork ();
@@ -71,6 +81,10 @@ linux_create_inferior (char *program, char **allargs)
}
add_inferior (pid);
+ tdata = (struct inferior_linux_data *) malloc (sizeof (*tdata));
+ tdata->pid = pid;
+ set_inferior_target_data (current_inferior, tdata);
+
/* FIXME remove */
inferior_pid = pid;
return 0;
@@ -81,6 +95,8 @@ linux_create_inferior (char *program, char **allargs)
static int
linux_attach (int pid)
{
+ struct inferior_linux_data *tdata;
+
if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
{
fprintf (stderr, "Cannot attach to process %d: %s (%d)\n", pid,
@@ -90,6 +106,10 @@ linux_attach (int pid)
_exit (0177);
}
+ add_inferior (pid);
+ tdata = (struct inferior_linux_data *) malloc (sizeof (*tdata));
+ tdata->pid = pid;
+ set_inferior_target_data (current_inferior, tdata);
return 0;
}
@@ -112,19 +132,75 @@ linux_thread_alive (int pid)
return 1;
}
+static int
+linux_wait_for_one_inferior (struct inferior_info *child)
+{
+ struct inferior_linux_data *child_data = inferior_target_data (child);
+ int pid, wstat;
+
+ while (1)
+ {
+ pid = waitpid (child_data->pid, &wstat, 0);
+
+ if (pid != child_data->pid)
+ perror_with_name ("wait");
+
+ /* If this target supports breakpoints, see if we hit one. */
+ if (the_low_target.stop_pc != NULL
+ && WIFSTOPPED (wstat)
+ && WSTOPSIG (wstat) == SIGTRAP)
+ {
+ CORE_ADDR stop_pc;
+
+ if (linux_bp_reinsert != 0)
+ {
+ reinsert_breakpoint (linux_bp_reinsert);
+ linux_bp_reinsert = 0;
+ linux_resume (0, 0);
+ continue;
+ }
+
+ fetch_inferior_registers (0);
+ stop_pc = (*the_low_target.stop_pc) ();
+
+ if (check_breakpoints (stop_pc) != 0)
+ {
+ if (the_low_target.set_pc != NULL)
+ (*the_low_target.set_pc) (stop_pc);
+
+ if (the_low_target.breakpoint_reinsert_addr == NULL)
+ {
+ linux_bp_reinsert = stop_pc;
+ uninsert_breakpoint (stop_pc);
+ linux_resume (1, 0);
+ }
+ else
+ {
+ reinsert_breakpoint_by_bp
+ (stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
+ linux_resume (0, 0);
+ }
+
+ continue;
+ }
+ }
+
+ return wstat;
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
/* Wait for process, returns status */
static unsigned char
linux_wait (char *status)
{
- int pid;
int w;
enable_async_io ();
- pid = waitpid (inferior_pid, &w, 0);
+ w = linux_wait_for_one_inferior (current_inferior);
disable_async_io ();
- if (pid != inferior_pid)
- perror_with_name ("wait");
if (WIFEXITED (w))
{
@@ -440,7 +516,7 @@ linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
returns the value of errno. */
static int
-linux_write_memory (CORE_ADDR memaddr, char *myaddr, int len)
+linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
{
register int i;
/* Round starting address down to longword boundary. */
@@ -508,5 +584,7 @@ void
initialize_low (void)
{
set_target_ops (&linux_target_ops);
+ set_breakpoint_data (the_low_target.breakpoint,
+ the_low_target.breakpoint_len);
init_registers ();
}
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index e485a8ee013..b484982e15e 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -39,6 +39,11 @@ struct linux_target_ops
store the register, and 2 if failure to store the register
is acceptable. */
int (*cannot_store_register) (int);
+ CORE_ADDR (*stop_pc) (void);
+ void (*set_pc) (CORE_ADDR newpc);
+ const char *breakpoint;
+ int breakpoint_len;
+ CORE_ADDR (*breakpoint_reinsert_addr) (void);
};
extern struct linux_target_ops the_low_target;
diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c
new file mode 100644
index 00000000000..91addf6a6ca
--- /dev/null
+++ b/gdb/gdbserver/mem-break.c
@@ -0,0 +1,280 @@
+/* Memory breakpoint operations for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+
+const char *breakpoint_data;
+int breakpoint_len;
+
+#define MAX_BREAKPOINT_LEN 8
+
+struct breakpoint
+{
+ struct breakpoint *next;
+ CORE_ADDR pc;
+ unsigned char old_data[MAX_BREAKPOINT_LEN];
+
+ /* Non-zero iff we are stepping over this breakpoint. */
+ int reinserting;
+
+ /* Non-NULL iff this breakpoint was inserted to step over
+ another one. Points to the other breakpoint (which is also
+ in the *next chain somewhere). */
+ struct breakpoint *breakpoint_to_reinsert;
+
+ /* Function to call when we hit this breakpoint. */
+ void (*handler) (CORE_ADDR);
+};
+
+struct breakpoint *breakpoints;
+
+void
+set_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR))
+{
+ struct breakpoint *bp;
+
+ if (breakpoint_data == NULL)
+ error ("Target does not support breakpoints.");
+
+ bp = malloc (sizeof (struct breakpoint));
+ memset (bp, 0, sizeof (struct breakpoint));
+
+ (*the_target->read_memory) (where, bp->old_data,
+ breakpoint_len);
+ (*the_target->write_memory) (where, breakpoint_data,
+ breakpoint_len);
+
+ bp->pc = where;
+ bp->handler = handler;
+
+ bp->next = breakpoints;
+ breakpoints = bp;
+}
+
+static void
+delete_breakpoint (struct breakpoint *bp)
+{
+ struct breakpoint *cur;
+
+ if (breakpoints == bp)
+ {
+ breakpoints = bp->next;
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ free (bp);
+ return;
+ }
+ cur = breakpoints;
+ while (cur->next)
+ {
+ if (cur->next == bp)
+ {
+ cur->next = bp->next;
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ free (bp);
+ return;
+ }
+ }
+ warning ("Could not find breakpoint in list.");
+}
+
+static struct breakpoint *
+find_breakpoint_at (CORE_ADDR where)
+{
+ struct breakpoint *bp = breakpoints;
+
+ while (bp != NULL)
+ {
+ if (bp->pc == where)
+ return bp;
+ bp = bp->next;
+ }
+
+ return NULL;
+}
+
+static void
+reinsert_breakpoint_handler (CORE_ADDR stop_pc)
+{
+ struct breakpoint *stop_bp, *orig_bp;
+
+ stop_bp = find_breakpoint_at (stop_pc);
+ if (stop_bp == NULL)
+ error ("lost the stopping breakpoint.");
+
+ orig_bp = stop_bp->breakpoint_to_reinsert;
+ if (orig_bp == NULL)
+ error ("no breakpoint to reinsert");
+
+ (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
+ breakpoint_len);
+ orig_bp->reinserting = 0;
+ delete_breakpoint (stop_bp);
+}
+
+void
+reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
+{
+ struct breakpoint *bp, *orig_bp;
+
+ set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
+
+ orig_bp = find_breakpoint_at (stop_at);
+ if (orig_bp == NULL)
+ error ("Could not find original breakpoint in list.");
+
+ bp = find_breakpoint_at (stop_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (reinserting by breakpoint).");
+ bp->breakpoint_to_reinsert = orig_bp;
+
+ (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
+ breakpoint_len);
+ orig_bp->reinserting = 1;
+}
+
+void
+uninsert_breakpoint (CORE_ADDR stopped_at)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stopped_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (uninserting).");
+
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ bp->reinserting = 1;
+}
+
+void
+reinsert_breakpoint (CORE_ADDR stopped_at)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stopped_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (uninserting).");
+ if (! bp->reinserting)
+ error ("Breakpoint already inserted at reinsert time.");
+
+ (*the_target->write_memory) (bp->pc, breakpoint_data,
+ breakpoint_len);
+ bp->reinserting = 0;
+}
+
+int
+check_breakpoints (CORE_ADDR stop_pc)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stop_pc);
+ if (bp == NULL)
+ return 0;
+ if (bp->reinserting)
+ {
+ warning ("Hit a removed breakpoint?");
+ return 0;
+ }
+
+ (*bp->handler) (bp->pc);
+ return 1;
+}
+
+void
+set_breakpoint_data (const char *bp_data, int bp_len)
+{
+ breakpoint_data = bp_data;
+ breakpoint_len = bp_len;
+}
+
+void
+check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+ struct breakpoint *bp = breakpoints;
+ CORE_ADDR mem_end = mem_addr + mem_len;
+
+ for (; bp != NULL; bp = bp->next)
+ {
+ CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR start, end;
+ int copy_offset, copy_len, buf_offset;
+
+ if (mem_addr >= bp_end)
+ continue;
+ if (bp->pc >= mem_end)
+ continue;
+
+ start = bp->pc;
+ if (mem_addr > start)
+ start = mem_addr;
+
+ end = bp_end;
+ if (end > mem_end)
+ end = mem_end;
+
+ copy_len = end - start;
+ copy_offset = start - bp->pc;
+ buf_offset = start - mem_addr;
+
+ memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
+ }
+}
+
+void
+check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+ struct breakpoint *bp = breakpoints;
+ CORE_ADDR mem_end = mem_addr + mem_len;
+
+ for (; bp != NULL; bp = bp->next)
+ {
+ CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR start, end;
+ int copy_offset, copy_len, buf_offset;
+
+ if (mem_addr >= bp_end)
+ continue;
+ if (bp->pc >= mem_end)
+ continue;
+
+ start = bp->pc;
+ if (mem_addr > start)
+ start = mem_addr;
+
+ end = bp_end;
+ if (end > mem_end)
+ end = mem_end;
+
+ copy_len = end - start;
+ copy_offset = start - bp->pc;
+ buf_offset = start - mem_addr;
+
+ memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
+ if (bp->reinserting == 0)
+ memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
+ }
+}
+
+
diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h
new file mode 100644
index 00000000000..356e7630cab
--- /dev/null
+++ b/gdb/gdbserver/mem-break.h
@@ -0,0 +1,71 @@
+/* Memory breakpoint interfaces for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef MEM_BREAK_H
+#define MEM_BREAK_H
+
+/* Breakpoints are opaque. */
+
+/* Create a new breakpoint at WHERE, and call HANDLER when
+ it is hit. */
+
+void set_breakpoint_at (CORE_ADDR where,
+ void (*handler) (CORE_ADDR));
+
+/* Create a reinsertion breakpoint at STOP_AT for the breakpoint
+ currently at STOP_PC (and temporarily remove the breakpoint at
+ STOP_PC). */
+
+void reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at);
+
+/* Change the status of the breakpoint at WHERE to inserted. */
+
+void reinsert_breakpoint (CORE_ADDR where);
+
+/* Change the status of the breakpoint at WHERE to uninserted. */
+
+void uninsert_breakpoint (CORE_ADDR where);
+
+/* See if any breakpoint claims ownership of STOP_PC. Call the handler for
+ the breakpoint, if found. */
+
+int check_breakpoints (CORE_ADDR stop_pc);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+ to MEM_ADDR + MEM_LEN. Update the data already read from the target
+ (in BUF) if necessary. */
+
+void check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+ to MEM_ADDR + MEM_LEN. Update the data to be written to the target
+ (in BUF) if necessary, as well as the original data for any breakpoints. */
+
+void check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* Set the byte pattern to insert for memory breakpoints. This function
+ must be called before any breakpoints are set. */
+
+void set_breakpoint_data (const char *bp_data, int bp_len);
+
+#endif /* MEM_BREAK_H */
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 3afab2b1d11..ba85b59d2c8 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -48,8 +48,6 @@ attach_inferior (int pid, char *statusptr, unsigned char *sigptr)
if (myattach (pid) != 0)
return -1;
- add_inferior (pid);
-
*sigptr = mywait (statusptr);
return 0;
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 3f0a543c716..0d084222582 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -58,6 +58,7 @@ typedef long long CORE_ADDR;
#include "gdb/signals.h"
#include "target.h"
+#include "mem-break.h"
/* Target-specific functions */
@@ -74,6 +75,9 @@ extern struct inferior_info *current_inferior;
extern int signal_pid;
void add_inferior (int pid);
void clear_inferiors (void);
+void *inferior_target_data (struct inferior_info *);
+void set_inferior_target_data (struct inferior_info *, void *);
+
/* Public variables in server.c */
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index 3bd87d3ea05..53a4c1ef55a 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -26,6 +26,20 @@
struct target_ops *the_target;
void
+read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ (*the_target->read_memory) (memaddr, myaddr, len);
+ check_mem_read (memaddr, myaddr, len);
+}
+
+int
+write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ check_mem_write (memaddr, myaddr, len);
+ return (*the_target->write_memory) (memaddr, myaddr, len);
+}
+
+void
set_target_ops (struct target_ops *target)
{
the_target = (struct target_ops *) malloc (sizeof (*the_target));
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 685a801cb97..6d06b9fd4ab 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -81,24 +81,27 @@ struct target_ops
void (*store_registers) (int regno);
- /* Read memory from the inferior process.
+ /* Read memory from the inferior process. This should generally be
+ called through read_inferior_memory, which handles breakpoint shadowing.
Read LEN bytes at MEMADDR into a buffer at MYADDR. */
void (*read_memory) (CORE_ADDR memaddr, char *myaddr, int len);
- /* Write memory to the inferior process.
+ /* Write memory to the inferior process. This should generally be
+ called through write_inferior_memory, which handles breakpoint shadowing.
Write LEN bytes from the buffer at MYADDR to MEMADDR.
Returns 0 on success and errno on failure. */
- int (*write_memory) (CORE_ADDR memaddr, char *myaddr, int len);
+ int (*write_memory) (CORE_ADDR memaddr, const char *myaddr, int len);
/* Query GDB for the values of any symbols we're interested in.
This function is called whenever we receive a "qSymbols::"
query, which corresponds to every time more symbols (might)
- become available. */
+ become available. NULL if we aren't interested in any
+ symbols. */
void (*look_up_symbols) (void);
};
@@ -131,10 +134,8 @@ void set_target_ops (struct target_ops *);
#define store_inferior_registers(regno) \
(*the_target->store_registers) (regno)
-#define read_inferior_memory(memaddr,myaddr,len) \
- (*the_target->read_memory) (memaddr, myaddr, len)
+void read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
-#define write_inferior_memory(memaddr,myaddr,len) \
- (*the_target->write_memory) (memaddr, myaddr, len)
+int write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
#endif /* TARGET_H */