diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 33 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 5 | ||||
-rw-r--r-- | gdb/gdbserver/inferiors.c | 17 | ||||
-rw-r--r-- | gdb/gdbserver/linux-i386-low.c | 28 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 88 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.h | 5 | ||||
-rw-r--r-- | gdb/gdbserver/mem-break.c | 280 | ||||
-rw-r--r-- | gdb/gdbserver/mem-break.h | 71 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 2 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 4 | ||||
-rw-r--r-- | gdb/gdbserver/target.c | 14 | ||||
-rw-r--r-- | gdb/gdbserver/target.h | 17 |
12 files changed, 548 insertions, 16 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7b92527..32f2a24 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 1e15bc0..a0bad13 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 1daa3c5..f8cbd04 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 2a398d7..7126432 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 bd1a876..10966e0 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 e485a8e..b484982 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 0000000..91addf6 --- /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 0000000..356e763 --- /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 3afab2b..ba85b59 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 3f0a543..0d08422 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 3bd87d3..53a4c1e 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 685a801..6d06b9f 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 */ |