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.
This commit is contained in:
Daniel Jacobowitz 2002-04-20 17:04:09 +00:00
parent e101598283
commit 611cb4a542
12 changed files with 548 additions and 16 deletions

View File

@ -1,3 +1,36 @@
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.
2002-04-19 Andrew Cagney <ac131313@redhat.com>
* sparc-tdep.c (sparc_get_saved_register): Use get_prev_frame

View File

@ -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)

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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 ();
}

View File

@ -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;

280
gdb/gdbserver/mem-break.c Normal file
View File

@ -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);
}
}

71
gdb/gdbserver/mem-break.h Normal file
View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -25,6 +25,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)
{

View File

@ -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 */