X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ftarget.c;h=4f4f8b042f2230e61710e8d6bf997fd84d9db4ed;hb=7e73cedf75b6388ab7786d5c8bd06368f94ee69b;hp=62717c0dcfea5c31a22da754cfbf3477676a6284;hpb=67ac97591175936a06cc1ef1df228746edcdb545;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/target.c b/gdb/target.c index 62717c0dcf..4f4f8b042f 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1,26 +1,28 @@ /* Select target systems and architectures at runtime for GDB. - Copyright 1990, 1992, 1993 Free Software Foundation, Inc. + Copyright 1990, 1992-1995, 1998-2000 Free Software Foundation, Inc. Contributed by Cygnus Support. -This file is part of GDB. + 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 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. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 "defs.h" #include #include +#include "gdb_string.h" #include "target.h" #include "gdbcmd.h" #include "symtab.h" @@ -28,47 +30,114 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bfd.h" #include "symfile.h" #include "objfiles.h" +#include "gdb_wait.h" +#include extern int errno; -static void -target_info PARAMS ((char *, int)); +static void target_info (char *, int); -static void -cleanup_target PARAMS ((struct target_ops *)); +static void cleanup_target (struct target_ops *); -static void -maybe_kill_then_create_inferior PARAMS ((char *, char *, char **)); +static void maybe_kill_then_create_inferior (char *, char *, char **); -static void -maybe_kill_then_attach PARAMS ((char *, int)); +static void default_clone_and_follow_inferior (int, int *); -static void -kill_or_be_killed PARAMS ((int)); +static void maybe_kill_then_attach (char *, int); -static void -default_terminal_info PARAMS ((char *, int)); +static void kill_or_be_killed (int); -static int -nosymbol PARAMS ((char *, CORE_ADDR *)); +static void default_terminal_info (char *, int); -static void -tcomplain PARAMS ((void)); +static int nosymbol (char *, CORE_ADDR *); + +static void tcomplain (void); + +static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *); + +static int return_zero (void); + +static int return_one (void); + +void target_ignore (void); + +static void target_command (char *, int); + +static struct target_ops *find_default_run_target (char *); + +static void update_current_target (void); + +static void nosupport_runtime (void); + +static void normal_target_post_startup_inferior (int pid); + +/* Transfer LEN bytes between target address MEMADDR and GDB address + MYADDR. Returns 0 for success, errno code for failure (which + includes partial transfers -- if you want a more useful response to + partial transfers, try either target_read_memory_partial or + target_write_memory_partial). */ static int -nomemory PARAMS ((CORE_ADDR, char *, int, int)); +target_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write); + +static void init_dummy_target (void); + +static void debug_to_open (char *, int); + +static void debug_to_close (int); + +static void debug_to_attach (char *, int); + +static void debug_to_detach (char *, int); + +static void debug_to_resume (int, int, enum target_signal); + +static int debug_to_wait (int, struct target_waitstatus *); + +static void debug_to_fetch_registers (int); + +static void debug_to_store_registers (int); + +static void debug_to_prepare_to_store (void); static int -return_zero PARAMS ((void)); +debug_to_xfer_memory (CORE_ADDR, char *, int, int, struct target_ops *); -static void -ignore PARAMS ((void)); +static void debug_to_files_info (struct target_ops *); -static void -target_command PARAMS ((char *, int)); +static int debug_to_insert_breakpoint (CORE_ADDR, char *); -static struct target_ops * -find_default_run_target PARAMS ((char *)); +static int debug_to_remove_breakpoint (CORE_ADDR, char *); + +static void debug_to_terminal_init (void); + +static void debug_to_terminal_inferior (void); + +static void debug_to_terminal_ours_for_output (void); + +static void debug_to_terminal_ours (void); + +static void debug_to_terminal_info (char *, int); + +static void debug_to_kill (void); + +static void debug_to_load (char *, int); + +static int debug_to_lookup_symbol (char *, CORE_ADDR *); + +static void debug_to_create_inferior (char *, char *, char **); + +static void debug_to_mourn_inferior (void); + +static int debug_to_can_run (void); + +static void debug_to_notice_signals (int); + +static int debug_to_thread_alive (int); + +static void debug_to_stop (void); + +static int debug_to_query (int /*char */ , char *, char *, int *); /* Pointer to array of target architecture structures; the size of the array; the current index into the array; the allocated size of the @@ -82,46 +151,37 @@ unsigned target_struct_allocsize; /* The initial current target, so that there is always a semi-valid current target. */ -struct target_ops dummy_target = {"None", "None", "", - 0, 0, /* open, close */ - find_default_attach, 0, /* attach, detach */ - 0, 0, /* resume, wait */ - 0, 0, 0, /* registers */ - 0, 0, /* memory */ - 0, 0, /* bkpts */ - 0, 0, 0, 0, 0, /* terminal */ - 0, 0, /* kill, load */ - 0, /* lookup_symbol */ - find_default_create_inferior, /* create_inferior */ - 0, /* mourn_inferior */ - 0, /* can_run */ - 0, /* notice_signals */ - dummy_stratum, 0, /* stratum, next */ - 0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */ - 0, 0, /* section pointers */ - OPS_MAGIC, -}; +static struct target_ops dummy_target; -/* The target structure we are currently using to talk to a process - or file or whatever "inferior" we have. */ +/* Top of target stack. */ -struct target_ops *current_target; +struct target_stack_item *target_stack; -/* The stack of target structures that have been pushed. */ +/* The target structure we are currently using to talk to a process + or file or whatever "inferior" we have. */ -struct target_ops **current_target_stack; +struct target_ops current_target; /* Command list for target. */ static struct cmd_list_element *targetlist = NULL; +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +int attach_flag; + +/* Non-zero if we want to see trace of target level stuff. */ + +static int targetdebug = 0; + +static void setup_target_debug (void); + /* The user just typed 'target' without the name of a target. */ /* ARGSUSED */ static void -target_command (arg, from_tty) - char *arg; - int from_tty; +target_command (char *arg, int from_tty) { fputs_filtered ("Argument required (target name). Try `help target'\n", gdb_stdout); @@ -130,16 +190,8 @@ target_command (arg, from_tty) /* Add a possible target architecture to the list. */ void -add_target (t) - struct target_ops *t; +add_target (struct target_ops *t) { - if (t->to_magic != OPS_MAGIC) - { - fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n", - t->to_shortname); - abort(); - } - if (!target_structs) { target_struct_allocsize = DEFAULT_ALLOCSIZE; @@ -150,11 +202,11 @@ add_target (t) { target_struct_allocsize *= 2; target_structs = (struct target_ops **) - xrealloc ((char *) target_structs, - target_struct_allocsize * sizeof (*target_structs)); + xrealloc ((char *) target_structs, + target_struct_allocsize * sizeof (*target_structs)); } target_structs[target_struct_size++] = t; - cleanup_target (t); +/* cleanup_target (t); */ if (targetlist == NULL) add_prefix_cmd ("target", class_run, target_command, @@ -169,82 +221,63 @@ information on the arguments for a particular protocol, type\n\ /* Stub functions */ -static void -ignore () +void +target_ignore (void) +{ +} + +void +target_load (char *arg, int from_tty) { + (*current_target.to_load) (arg, from_tty); } /* ARGSUSED */ static int -nomemory (memaddr, myaddr, len, write) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; +nomemory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct target_ops *t) { - errno = EIO; /* Can't read/write this location */ - return 0; /* No bytes handled */ + errno = EIO; /* Can't read/write this location */ + return 0; /* No bytes handled */ } static void -tcomplain () +tcomplain (void) { error ("You can't do that when your target is `%s'", - current_target->to_shortname); + current_target.to_shortname); } void -noprocess () +noprocess (void) { - error ("You can't do that without a process to debug"); + error ("You can't do that without a process to debug."); } /* ARGSUSED */ static int -nosymbol (name, addrp) - char *name; - CORE_ADDR *addrp; +nosymbol (char *name, CORE_ADDR *addrp) { - return 1; /* Symbol does not exist in target env */ + return 1; /* Symbol does not exist in target env */ } /* ARGSUSED */ static void -default_terminal_info (args, from_tty) - char *args; - int from_tty; +nosupport_runtime (void) { - printf_unfiltered("No saved terminal information.\n"); + if (!inferior_pid) + noprocess (); + else + error ("No run-time support for this"); } -#if 0 -/* With strata, this function is no longer needed. FIXME. */ -/* This is the default target_create_inferior function. It looks up - the stack for some target that cares to create inferiors, then - calls it -- or complains if not found. */ +/* ARGSUSED */ static void -upstack_create_inferior (exec, args, env) - char *exec; - char *args; - char **env; +default_terminal_info (char *args, int from_tty) { - struct target_ops *t; - - for (t = current_target; - t; - t = t->to_next) - { - if (t->to_create_inferior != upstack_create_inferior) - { - t->to_create_inferior (exec, args, env); - return; - } - - } - tcomplain(); + printf_unfiltered ("No saved terminal information.\n"); } -#endif /* This is the default target_create_inferior and target_attach function. If the current target is executing, it asks whether to kill it off. @@ -252,101 +285,335 @@ upstack_create_inferior (exec, args, env) the target, and the operation should be attempted. */ static void -kill_or_be_killed (from_tty) - int from_tty; +kill_or_be_killed (int from_tty) { if (target_has_execution) { printf_unfiltered ("You are already running a program:\n"); target_files_info (); - if (query ("Kill it? ")) { - target_kill (); - if (target_has_execution) - error ("Killing the program did not help."); - return; - } else { - error ("Program not killed."); - } + if (query ("Kill it? ")) + { + target_kill (); + if (target_has_execution) + error ("Killing the program did not help."); + return; + } + else + { + error ("Program not killed."); + } } - tcomplain(); + tcomplain (); } static void -maybe_kill_then_attach (args, from_tty) - char *args; - int from_tty; +maybe_kill_then_attach (char *args, int from_tty) { kill_or_be_killed (from_tty); target_attach (args, from_tty); } static void -maybe_kill_then_create_inferior (exec, args, env) - char *exec; - char *args; - char **env; +maybe_kill_then_create_inferior (char *exec, char *args, char **env) { kill_or_be_killed (0); target_create_inferior (exec, args, env); } +static void +default_clone_and_follow_inferior (int child_pid, int *followed_child) +{ + target_clone_and_follow_inferior (child_pid, followed_child); +} + /* Clean up a target struct so it no longer has any zero pointers in it. We default entries, at least to stubs that print error messages. */ static void -cleanup_target (t) - struct target_ops *t; +cleanup_target (struct target_ops *t) { - /* Check magic number. If wrong, it probably means someone changed - the struct definition, but not all the places that initialize one. */ - if (t->to_magic != OPS_MAGIC) - { - fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n", - t->to_shortname); - abort(); - } - #define de_fault(field, value) \ - if (!t->field) t->field = value - - /* FIELD DEFAULT VALUE */ - - de_fault (to_open, (void (*)())tcomplain); - de_fault (to_close, (void (*)())ignore); - de_fault (to_attach, maybe_kill_then_attach); - de_fault (to_detach, (void (*)())ignore); - de_fault (to_resume, (void (*)())noprocess); - de_fault (to_wait, (int (*)())noprocess); - de_fault (to_fetch_registers, (void (*)())ignore); - de_fault (to_store_registers, (void (*)())noprocess); - de_fault (to_prepare_to_store, (void (*)())noprocess); - de_fault (to_xfer_memory, (int (*)())nomemory); - de_fault (to_files_info, (void (*)())ignore); - de_fault (to_insert_breakpoint, memory_insert_breakpoint); - de_fault (to_remove_breakpoint, memory_remove_breakpoint); - de_fault (to_terminal_init, ignore); - de_fault (to_terminal_inferior, ignore); - de_fault (to_terminal_ours_for_output,ignore); - de_fault (to_terminal_ours, ignore); - de_fault (to_terminal_info, default_terminal_info); - de_fault (to_kill, (void (*)())noprocess); - de_fault (to_load, (void (*)())tcomplain); - de_fault (to_lookup_symbol, nosymbol); - de_fault (to_create_inferior, maybe_kill_then_create_inferior); - de_fault (to_mourn_inferior, (void (*)())noprocess); - de_fault (to_can_run, return_zero); - de_fault (to_notice_signals, (void (*)())ignore); - de_fault (to_next, 0); - de_fault (to_has_all_memory, 0); - de_fault (to_has_memory, 0); - de_fault (to_has_stack, 0); - de_fault (to_has_registers, 0); - de_fault (to_has_execution, 0); - + if (!t->field) \ + t->field = value + + de_fault (to_open, + (void (*) (char *, int)) + tcomplain); + de_fault (to_close, + (void (*) (int)) + target_ignore); + de_fault (to_attach, + maybe_kill_then_attach); + de_fault (to_post_attach, + (void (*) (int)) + target_ignore); + de_fault (to_require_attach, + maybe_kill_then_attach); + de_fault (to_detach, + (void (*) (char *, int)) + target_ignore); + de_fault (to_require_detach, + (void (*) (int, char *, int)) + target_ignore); + de_fault (to_resume, + (void (*) (int, int, enum target_signal)) + noprocess); + de_fault (to_wait, + (int (*) (int, struct target_waitstatus *)) + noprocess); + de_fault (to_post_wait, + (void (*) (int, int)) + target_ignore); + de_fault (to_fetch_registers, + (void (*) (int)) + target_ignore); + de_fault (to_store_registers, + (void (*) (int)) + noprocess); + de_fault (to_prepare_to_store, + (void (*) (void)) + noprocess); + de_fault (to_xfer_memory, + (int (*) (CORE_ADDR, char *, int, int, struct target_ops *)) + nomemory); + de_fault (to_files_info, + (void (*) (struct target_ops *)) + target_ignore); + de_fault (to_insert_breakpoint, + memory_insert_breakpoint); + de_fault (to_remove_breakpoint, + memory_remove_breakpoint); + de_fault (to_terminal_init, + (void (*) (void)) + target_ignore); + de_fault (to_terminal_inferior, + (void (*) (void)) + target_ignore); + de_fault (to_terminal_ours_for_output, + (void (*) (void)) + target_ignore); + de_fault (to_terminal_ours, + (void (*) (void)) + target_ignore); + de_fault (to_terminal_info, + default_terminal_info); + de_fault (to_kill, + (void (*) (void)) + noprocess); + de_fault (to_load, + (void (*) (char *, int)) + tcomplain); + de_fault (to_lookup_symbol, + (int (*) (char *, CORE_ADDR *)) + nosymbol); + de_fault (to_create_inferior, + maybe_kill_then_create_inferior); + de_fault (to_post_startup_inferior, + (void (*) (int)) + target_ignore); + de_fault (to_acknowledge_created_inferior, + (void (*) (int)) + target_ignore); + de_fault (to_clone_and_follow_inferior, + default_clone_and_follow_inferior); + de_fault (to_post_follow_inferior_by_clone, + (void (*) (void)) + target_ignore); + de_fault (to_insert_fork_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_remove_fork_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_insert_vfork_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_remove_vfork_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_has_forked, + (int (*) (int, int *)) + return_zero); + de_fault (to_has_vforked, + (int (*) (int, int *)) + return_zero); + de_fault (to_can_follow_vfork_prior_to_exec, + (int (*) (void)) + return_zero); + de_fault (to_post_follow_vfork, + (void (*) (int, int, int, int)) + target_ignore); + de_fault (to_insert_exec_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_remove_exec_catchpoint, + (int (*) (int)) + tcomplain); + de_fault (to_has_execd, + (int (*) (int, char **)) + return_zero); + de_fault (to_reported_exec_events_per_exec_call, + (int (*) (void)) + return_one); + de_fault (to_has_syscall_event, + (int (*) (int, enum target_waitkind *, int *)) + return_zero); + de_fault (to_has_exited, + (int (*) (int, int, int *)) + return_zero); + de_fault (to_mourn_inferior, + (void (*) (void)) + noprocess); + de_fault (to_can_run, + return_zero); + de_fault (to_notice_signals, + (void (*) (int)) + target_ignore); + de_fault (to_thread_alive, + (int (*) (int)) + return_zero); + de_fault (to_find_new_threads, + (void (*) (void)) + target_ignore); + de_fault (to_extra_thread_info, + (char *(*) (struct thread_info *)) + return_zero); + de_fault (to_stop, + (void (*) (void)) + target_ignore); + de_fault (to_query, + (int (*) (int, char *, char *, int *)) + return_zero); + de_fault (to_rcmd, + (void (*) (char *, struct ui_file *)) + tcomplain); + de_fault (to_enable_exception_callback, + (struct symtab_and_line * (*) (enum exception_event_kind, int)) + nosupport_runtime); + de_fault (to_get_current_exception_event, + (struct exception_event_record * (*) (void)) + nosupport_runtime); + de_fault (to_pid_to_exec_file, + (char *(*) (int)) + return_zero); + de_fault (to_core_file_to_sym_file, + (char *(*) (char *)) + return_zero); + de_fault (to_can_async_p, + (int (*) (void)) + return_zero); + de_fault (to_is_async_p, + (int (*) (void)) + return_zero); + de_fault (to_async, + (void (*) (void (*) (enum inferior_event_type, void*), void*)) + tcomplain); #undef de_fault } +/* Go through the target stack from top to bottom, copying over zero entries in + current_target. In effect, we are doing class inheritance through the + pushed target vectors. */ + +static void +update_current_target (void) +{ + struct target_stack_item *item; + struct target_ops *t; + + /* First, reset current_target */ + memset (¤t_target, 0, sizeof current_target); + + for (item = target_stack; item; item = item->next) + { + t = item->target_ops; + +#define INHERIT(FIELD, TARGET) \ + if (!current_target.FIELD) \ + current_target.FIELD = TARGET->FIELD + + INHERIT (to_shortname, t); + INHERIT (to_longname, t); + INHERIT (to_doc, t); + INHERIT (to_open, t); + INHERIT (to_close, t); + INHERIT (to_attach, t); + INHERIT (to_post_attach, t); + INHERIT (to_require_attach, t); + INHERIT (to_detach, t); + INHERIT (to_require_detach, t); + INHERIT (to_resume, t); + INHERIT (to_wait, t); + INHERIT (to_post_wait, t); + INHERIT (to_fetch_registers, t); + INHERIT (to_store_registers, t); + INHERIT (to_prepare_to_store, t); + INHERIT (to_xfer_memory, t); + INHERIT (to_files_info, t); + INHERIT (to_insert_breakpoint, t); + INHERIT (to_remove_breakpoint, t); + INHERIT (to_terminal_init, t); + INHERIT (to_terminal_inferior, t); + INHERIT (to_terminal_ours_for_output, t); + INHERIT (to_terminal_ours, t); + INHERIT (to_terminal_info, t); + INHERIT (to_kill, t); + INHERIT (to_load, t); + INHERIT (to_lookup_symbol, t); + INHERIT (to_create_inferior, t); + INHERIT (to_post_startup_inferior, t); + INHERIT (to_acknowledge_created_inferior, t); + INHERIT (to_clone_and_follow_inferior, t); + INHERIT (to_post_follow_inferior_by_clone, t); + INHERIT (to_insert_fork_catchpoint, t); + INHERIT (to_remove_fork_catchpoint, t); + INHERIT (to_insert_vfork_catchpoint, t); + INHERIT (to_remove_vfork_catchpoint, t); + INHERIT (to_has_forked, t); + INHERIT (to_has_vforked, t); + INHERIT (to_can_follow_vfork_prior_to_exec, t); + INHERIT (to_post_follow_vfork, t); + INHERIT (to_insert_exec_catchpoint, t); + INHERIT (to_remove_exec_catchpoint, t); + INHERIT (to_has_execd, t); + INHERIT (to_reported_exec_events_per_exec_call, t); + INHERIT (to_has_syscall_event, t); + INHERIT (to_has_exited, t); + INHERIT (to_mourn_inferior, t); + INHERIT (to_can_run, t); + INHERIT (to_notice_signals, t); + INHERIT (to_thread_alive, t); + INHERIT (to_find_new_threads, t); + INHERIT (to_pid_to_str, t); + INHERIT (to_extra_thread_info, t); + INHERIT (to_stop, t); + INHERIT (to_query, t); + INHERIT (to_rcmd, t); + INHERIT (to_enable_exception_callback, t); + INHERIT (to_get_current_exception_event, t); + INHERIT (to_pid_to_exec_file, t); + INHERIT (to_core_file_to_sym_file, t); + INHERIT (to_stratum, t); + INHERIT (DONT_USE, t); + INHERIT (to_has_all_memory, t); + INHERIT (to_has_memory, t); + INHERIT (to_has_stack, t); + INHERIT (to_has_registers, t); + INHERIT (to_has_execution, t); + INHERIT (to_has_thread_control, t); + INHERIT (to_sections, t); + INHERIT (to_sections_end, t); + INHERIT (to_can_async_p, t); + INHERIT (to_is_async_p, t); + INHERIT (to_async, t); + INHERIT (to_async_mask_value, t); + INHERIT (to_magic, t); + +#undef INHERIT + } +} + /* Push a new target type into the stack of the existing target accessors, possibly superseding some of the existing accessors. @@ -358,98 +625,140 @@ cleanup_target (t) checking them. */ int -push_target (t) - struct target_ops *t; +push_target (struct target_ops *t) { - struct target_ops *st, *prev; + struct target_stack_item *cur, *prev, *tmp; + + /* Check magic number. If wrong, it probably means someone changed + the struct definition, but not all the places that initialize one. */ + if (t->to_magic != OPS_MAGIC) + { + fprintf_unfiltered (gdb_stderr, + "Magic number of %s target struct wrong\n", + t->to_shortname); + abort (); + } + + /* Find the proper stratum to install this target in. */ + + for (prev = NULL, cur = target_stack; cur; prev = cur, cur = cur->next) + { + if ((int) (t->to_stratum) >= (int) (cur->target_ops->to_stratum)) + break; + } + + /* If there's already targets at this stratum, remove them. */ + + if (cur) + while (t->to_stratum == cur->target_ops->to_stratum) + { + /* There's already something on this stratum. Close it off. */ + if (cur->target_ops->to_close) + (cur->target_ops->to_close) (0); + if (prev) + prev->next = cur->next; /* Unchain old target_ops */ + else + target_stack = cur->next; /* Unchain first on list */ + tmp = cur->next; + free (cur); + cur = tmp; + } + + /* We have removed all targets in our stratum, now add the new one. */ + + tmp = (struct target_stack_item *) + xmalloc (sizeof (struct target_stack_item)); + tmp->next = cur; + tmp->target_ops = t; - for (prev = 0, st = current_target; - st; - prev = st, st = st->to_next) { - if ((int)(t->to_stratum) >= (int)(st->to_stratum)) - break; - } - - while (t->to_stratum == st->to_stratum) { - /* There's already something on this stratum. Close it off. */ - (st->to_close) (0); - if (prev) - prev->to_next = st->to_next; /* Unchain old target_ops */ - else - current_target = st->to_next; /* Unchain first on list */ - st = st->to_next; - } - - /* We have removed all targets in our stratum, now add ourself. */ - t->to_next = st; if (prev) - prev->to_next = t; + prev->next = tmp; else - current_target = t; + target_stack = tmp; + + update_current_target (); + + cleanup_target (¤t_target); /* Fill in the gaps */ + + if (targetdebug) + setup_target_debug (); - cleanup_target (current_target); return prev != 0; } /* Remove a target_ops vector from the stack, wherever it may be. - Return how many times it was removed (0 or 1 unless bug). */ + Return how many times it was removed (0 or 1). */ int -unpush_target (t) - struct target_ops *t; +unpush_target (struct target_ops *t) { - struct target_ops *u, *v; - int result = 0; + struct target_stack_item *cur, *prev; - for (u = current_target, v = 0; - u; - v = u, u = u->to_next) - if (u == t) - { - if (v == 0) - pop_target(); /* unchain top copy */ - else { - (t->to_close)(0); /* Let it clean up */ - v->to_next = t->to_next; /* unchain middle copy */ - } - result++; - } - return result; + if (t->to_close) + t->to_close (0); /* Let it clean up */ + + /* Look for the specified target. Note that we assume that a target + can only occur once in the target stack. */ + + for (cur = target_stack, prev = NULL; cur; prev = cur, cur = cur->next) + if (cur->target_ops == t) + break; + + if (!cur) + return 0; /* Didn't find target_ops, quit now */ + + /* Unchain the target */ + + if (!prev) + target_stack = cur->next; + else + prev->next = cur->next; + + free (cur); /* Release the target_stack_item */ + + update_current_target (); + cleanup_target (¤t_target); + + return 1; } void -pop_target () +pop_target (void) { - (current_target->to_close)(0); /* Let it clean up */ - current_target = current_target->to_next; -#if 0 - /* This will dump core if ever called--push_target expects current_target - to be non-NULL. But I don't think it's needed; I don't see how the - dummy_target could ever be removed from the stack. */ - if (!current_target) /* At bottom, push dummy. */ - push_target (&dummy_target); -#endif + (current_target.to_close) (0); /* Let it clean up */ + if (unpush_target (target_stack->target_ops) == 1) + return; + + fprintf_unfiltered (gdb_stderr, + "pop_target couldn't find target %s\n", + current_target.to_shortname); + abort (); } #undef MIN #define MIN(A, B) (((A) <= (B)) ? (A) : (B)) -/* target_read_string -- read a null terminated string from MEMADDR in target. - The read may also be terminated early by getting an error from target_xfer_ - memory. - LEN is the size of the buffer pointed to by MYADDR. Note that a terminating - null will only be written if there is sufficient room. The return value is - is the number of bytes (including the null) actually transferred. -*/ +/* target_read_string -- read a null terminated string, up to LEN bytes, + from MEMADDR in target. Set *ERRNOP to the errno code, or 0 if successful. + Set *STRING to a pointer to malloc'd memory containing the data; the caller + is responsible for freeing it. Return the number of bytes successfully + read. */ int -target_read_string (memaddr, myaddr, len) - CORE_ADDR memaddr; - char *myaddr; - int len; +target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop) { int tlen, origlen, offset, i; char buf[4]; + int errcode = 0; + char *buffer; + int buffer_allocated; + char *bufptr; + unsigned int nbytes_read = 0; + + /* Small for testing. */ + buffer_allocated = 4; + buffer = xmalloc (buffer_allocated); + bufptr = buffer; origlen = len; @@ -458,20 +767,48 @@ target_read_string (memaddr, myaddr, len) tlen = MIN (len, 4 - (memaddr & 3)); offset = memaddr & 3; - if (target_xfer_memory (memaddr & ~3, buf, 4, 0)) - return origlen - len; + errcode = target_xfer_memory (memaddr & ~3, buf, 4, 0); + if (errcode != 0) + { + /* The transfer request might have crossed the boundary to an + unallocated region of memory. Retry the transfer, requesting + a single byte. */ + tlen = 1; + offset = 0; + errcode = target_xfer_memory (memaddr, buf, 1, 0); + if (errcode != 0) + goto done; + } + + if (bufptr - buffer + tlen > buffer_allocated) + { + unsigned int bytes; + bytes = bufptr - buffer; + buffer_allocated *= 2; + buffer = xrealloc (buffer, buffer_allocated); + bufptr = buffer + bytes; + } for (i = 0; i < tlen; i++) { - *myaddr++ = buf[i + offset]; + *bufptr++ = buf[i + offset]; if (buf[i + offset] == '\000') - return (origlen - len) + i + 1; + { + nbytes_read += i + 1; + goto done; + } } memaddr += tlen; len -= tlen; + nbytes_read += tlen; } - return origlen; +done: + if (errnop != NULL) + *errnop = errcode; + if (string != NULL) + *string = buffer; + return nbytes_read; } /* Read LEN bytes of target memory at address MEMADDR, placing the results in @@ -485,65 +822,17 @@ target_read_string (memaddr, myaddr, len) deal with partial reads should call target_read_memory_partial. */ int -target_read_memory (memaddr, myaddr, len) - CORE_ADDR memaddr; - char *myaddr; - int len; +target_read_memory (CORE_ADDR memaddr, char *myaddr, int len) { return target_xfer_memory (memaddr, myaddr, len, 0); } -/* Read LEN bytes of target memory at address MEMADDR, placing the results - in GDB's memory at MYADDR. Returns a count of the bytes actually read, - and optionally an errno value in the location pointed to by ERRNOPTR - if ERRNOPTR is non-null. */ - -int -target_read_memory_partial (memaddr, myaddr, len, errnoptr) - CORE_ADDR memaddr; - char *myaddr; - int len; - int *errnoptr; -{ - int nread; /* Number of bytes actually read. */ - int errcode; /* Error from last read. */ - - /* First try a complete read. */ - errcode = target_xfer_memory (memaddr, myaddr, len, 0); - if (errcode == 0) - { - /* Got it all. */ - nread = len; - } - else - { - /* Loop, reading one byte at a time until we get as much as we can. */ - for (errcode = 0, nread = 0; len > 0 && errcode == 0; nread++, len--) - { - errcode = target_xfer_memory (memaddr++, myaddr++, 1, 0); - } - /* If an error, the last read was unsuccessful, so adjust count. */ - if (errcode != 0) - { - nread--; - } - } - if (errnoptr != NULL) - { - *errnoptr = errcode; - } - return (nread); -} - int -target_write_memory (memaddr, myaddr, len) - CORE_ADDR memaddr; - char *myaddr; - int len; +target_write_memory (CORE_ADDR memaddr, char *myaddr, int len) { return target_xfer_memory (memaddr, myaddr, len, 1); } - + /* Move memory to or from the targets. Iterate until all of it has been moved, if necessary. The top target gets priority; anything it doesn't want, is offered to the next one down, etc. Note the @@ -554,24 +843,25 @@ target_write_memory (memaddr, myaddr, len) Result is 0 or errno value. */ -int -target_xfer_memory (memaddr, myaddr, len, write) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; +static int +target_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write) { int curlen; int res; struct target_ops *t; + struct target_stack_item *item; + + /* Zero length requests are ok and require no work. */ + if (len == 0) + return 0; /* to_xfer_memory is not guaranteed to set errno, even when it returns 0. */ errno = 0; /* The quick case is that the top target does it all. */ - res = current_target->to_xfer_memory - (memaddr, myaddr, len, write, current_target); + res = current_target.to_xfer_memory + (memaddr, myaddr, len, write, ¤t_target); if (res == len) return 0; @@ -582,15 +872,19 @@ target_xfer_memory (memaddr, myaddr, len, write) for (; len > 0;) { curlen = len; /* Want to do it all */ - for (t = current_target; - t; - t = t->to_has_all_memory? 0: t->to_next) + for (item = target_stack; item; item = item->next) { - res = t->to_xfer_memory(memaddr, myaddr, curlen, write, t); - if (res > 0) break; /* Handled all or part of xfer */ - if (res == 0) continue; /* Handled none */ - curlen = -res; /* Could handle once we get past res bytes */ + t = item->target_ops; + if (!t->to_has_memory) + continue; + + res = t->to_xfer_memory (memaddr, myaddr, curlen, write, t); + if (res > 0) + break; /* Handled all or part of xfer */ + if (t->to_has_all_memory) + break; } + if (res <= 0) { /* If this address is for nonexistent memory, @@ -602,24 +896,92 @@ target_xfer_memory (memaddr, myaddr, len, write) else return errno; } -bump: + bump: memaddr += res; - myaddr += res; - len -= res; + myaddr += res; + len -= res; } return 0; /* We managed to cover it all somehow. */ } +/* Perform a partial memory transfer. */ + +static int +target_xfer_memory_partial (CORE_ADDR memaddr, char *buf, int len, + int write_p, int *err) +{ + int res; + int err_res; + int len_res; + struct target_ops *t; + struct target_stack_item *item; + + /* Zero length requests are ok and require no work. */ + if (len == 0) + { + *err = 0; + return 0; + } + + /* The quick case is that the top target does it all. */ + res = current_target.to_xfer_memory (memaddr, buf, len, write_p, ¤t_target); + if (res > 0) + { + *err = 0; + return res; + } + + /* xfer memory doesn't always reliably set errno. */ + errno = 0; + + /* Try all levels of the target stack to see one can handle it. */ + for (item = target_stack; item; item = item->next) + { + t = item->target_ops; + if (!t->to_has_memory) + continue; + res = t->to_xfer_memory (memaddr, buf, len, write_p, t); + if (res > 0) + { + /* Handled all or part of xfer */ + *err = 0; + return res; + } + if (t->to_has_all_memory) + break; + } + + /* Total failure. Return error. */ + if (errno != 0) + { + *err = errno; + return -1; + } + *err = EIO; + return -1; +} + +int +target_read_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err) +{ + return target_xfer_memory_partial (memaddr, buf, len, 0, err); +} + +int +target_write_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err) +{ + return target_xfer_memory_partial (memaddr, buf, len, 1, err); +} + /* ARGSUSED */ static void -target_info (args, from_tty) - char *args; - int from_tty; +target_info (char *args, int from_tty) { struct target_ops *t; + struct target_stack_item *item; int has_all_mem = 0; - + if (symfile_objfile != NULL) printf_unfiltered ("Symbols from \"%s\".\n", symfile_objfile->name); @@ -628,16 +990,19 @@ target_info (args, from_tty) return; #endif - for (t = current_target; - t; - t = t->to_next) + for (item = target_stack; item; item = item->next) { - if ((int)(t->to_stratum) <= (int)dummy_stratum) + t = item->target_ops; + + if (!t->to_has_memory) + continue; + + if ((int) (t->to_stratum) <= (int) dummy_stratum) continue; if (has_all_mem) - printf_unfiltered("\tWhile running this, gdb does not access memory from...\n"); - printf_unfiltered("%s:\n", t->to_longname); - (t->to_files_info)(t); + printf_unfiltered ("\tWhile running this, GDB does not access memory from...\n"); + printf_unfiltered ("%s:\n", t->to_longname); + (t->to_files_info) (t); has_all_mem = t->to_has_all_memory; } } @@ -646,32 +1011,57 @@ target_info (args, from_tty) anything. */ void -target_preopen (from_tty) - int from_tty; +target_preopen (int from_tty) { - dont_repeat(); + dont_repeat (); if (target_has_execution) - { - if (query ("A program is being debugged already. Kill it? ")) - target_kill (); + { + if (!from_tty + || query ("A program is being debugged already. Kill it? ")) + target_kill (); else - error ("Program not killed."); + error ("Program not killed."); } + + /* Calling target_kill may remove the target from the stack. But if + it doesn't (which seems like a win for UDI), remove it now. */ + + if (target_has_execution) + pop_target (); } /* Detach a target after doing deferred register stores. */ void -target_detach (args, from_tty) - char *args; - int from_tty; +target_detach (char *args, int from_tty) { /* Handle any optimized stores to the inferior. */ #ifdef DO_DEFERRED_STORES DO_DEFERRED_STORES; #endif - (current_target->to_detach) (args, from_tty); + (current_target.to_detach) (args, from_tty); +} + +void +target_link (char *modname, CORE_ADDR *t_reloc) +{ + if (STREQ (current_target.to_shortname, "rombug")) + { + (current_target.to_lookup_symbol) (modname, t_reloc); + if (*t_reloc == 0) + error ("Unable to link to %s and get relocation in rombug", modname); + } + else + *t_reloc = (CORE_ADDR) -1; +} + +int +target_async_mask (int mask) +{ + int saved_async_masked_status = target_async_mask_value; + target_async_mask_value = mask; + return saved_async_masked_status; } /* Look through the list of possible targets for a target that can @@ -681,8 +1071,7 @@ target_detach (args, from_tty) Result is always valid (error() is called for errors). */ static struct target_ops * -find_default_run_target (do_mesg) - char *do_mesg; +find_default_run_target (char *do_mesg) { struct target_ops **t; struct target_ops *runable = NULL; @@ -693,7 +1082,7 @@ find_default_run_target (do_mesg) for (t = target_structs; t < target_structs + target_struct_size; ++t) { - if (target_can_run(*t)) + if ((*t)->to_can_run && target_can_run (*t)) { runable = *t; ++count; @@ -707,45 +1096,186 @@ find_default_run_target (do_mesg) } void -find_default_attach (args, from_tty) - char *args; - int from_tty; +find_default_attach (char *args, int from_tty) { struct target_ops *t; - t = find_default_run_target("attach"); + t = find_default_run_target ("attach"); (t->to_attach) (args, from_tty); return; } void -find_default_create_inferior (exec_file, allargs, env) - char *exec_file; - char *allargs; - char **env; +find_default_require_attach (char *args, int from_tty) +{ + struct target_ops *t; + + t = find_default_run_target ("require_attach"); + (t->to_require_attach) (args, from_tty); + return; +} + +void +find_default_require_detach (int pid, char *args, int from_tty) +{ + struct target_ops *t; + + t = find_default_run_target ("require_detach"); + (t->to_require_detach) (pid, args, from_tty); + return; +} + +void +find_default_create_inferior (char *exec_file, char *allargs, char **env) { struct target_ops *t; - t = find_default_run_target("run"); + t = find_default_run_target ("run"); (t->to_create_inferior) (exec_file, allargs, env); return; } +void +find_default_clone_and_follow_inferior (int child_pid, int *followed_child) +{ + struct target_ops *t; + + t = find_default_run_target ("run"); + (t->to_clone_and_follow_inferior) (child_pid, followed_child); + return; +} + static int -return_zero () +return_zero (void) { return 0; } -struct target_ops * -find_core_target () +static int +return_one (void) { - struct target_ops **t; + return 1; +} + +/* + * Resize the to_sections pointer. Also make sure that anyone that + * was holding on to an old value of it gets updated. + * Returns the old size. + */ + +int +target_resize_to_sections (struct target_ops *target, int num_added) +{ + struct target_ops **t; + struct section_table *old_value; + int old_count; + + old_value = target->to_sections; + + if (target->to_sections) + { + old_count = target->to_sections_end - target->to_sections; + target->to_sections = (struct section_table *) + xrealloc ((char *) target->to_sections, + (sizeof (struct section_table)) * (num_added + old_count)); + } + else + { + old_count = 0; + target->to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * num_added); + } + target->to_sections_end = target->to_sections + (num_added + old_count); + + /* Check to see if anyone else was pointing to this structure. + If old_value was null, then no one was. */ + + if (old_value) + { + for (t = target_structs; t < target_structs + target_struct_size; + ++t) + { + if ((*t)->to_sections == old_value) + { + (*t)->to_sections = target->to_sections; + (*t)->to_sections_end = target->to_sections_end; + } + } + } + + return old_count; + +} + +/* Remove all target sections taken from ABFD. + + Scan the current target stack for targets whose section tables + refer to sections from BFD, and remove those sections. We use this + when we notice that the inferior has unloaded a shared object, for + example. */ +void +remove_target_sections (bfd *abfd) +{ + struct target_ops **t; + + for (t = target_structs; t < target_structs + target_struct_size; t++) + { + struct section_table *src, *dest; + + dest = (*t)->to_sections; + for (src = (*t)->to_sections; src < (*t)->to_sections_end; src++) + if (src->bfd != abfd) + { + /* Keep this section. */ + if (dest < src) *dest = *src; + dest++; + } + + /* If we've dropped any sections, resize the section table. */ + if (dest < src) + target_resize_to_sections (*t, dest - src); + } +} + + + + +/* Find a single runnable target in the stack and return it. If for + some reason there is more than one, return NULL. */ + +struct target_ops * +find_run_target (void) +{ + struct target_ops **t; struct target_ops *runable = NULL; int count; - + count = 0; - + + for (t = target_structs; t < target_structs + target_struct_size; ++t) + { + if ((*t)->to_can_run && target_can_run (*t)) + { + runable = *t; + ++count; + } + } + + return (count == 1 ? runable : NULL); +} + +/* Find a single core_stratum target in the list of targets and return it. + If for some reason there is more than one, return NULL. */ + +struct target_ops * +find_core_target (void) +{ + struct target_ops **t; + struct target_ops *runable = NULL; + int count; + + count = 0; + for (t = target_structs; t < target_structs + target_struct_size; ++t) { @@ -755,12 +1285,64 @@ find_core_target () ++count; } } - - return(count == 1 ? runable : NULL); + + return (count == 1 ? runable : NULL); +} + +/* + * Find the next target down the stack from the specified target. + */ + +struct target_ops * +find_target_beneath (struct target_ops *t) +{ + struct target_stack_item *cur; + + for (cur = target_stack; cur; cur = cur->next) + if (cur->target_ops == t) + break; + + if (cur == NULL || cur->next == NULL) + return NULL; + else + return cur->next->target_ops; +} + + +/* The inferior process has died. Long live the inferior! */ + +void +generic_mourn_inferior (void) +{ + extern int show_breakpoint_hit_counts; + + inferior_pid = 0; + attach_flag = 0; + breakpoint_init_inferior (inf_exited); + registers_changed (); + +#ifdef CLEAR_DEFERRED_STORES + /* Delete any pending stores to the inferior... */ + CLEAR_DEFERRED_STORES; +#endif + + reopen_exec_file (); + reinit_frame_cache (); + + /* It is confusing to the user for ignore counts to stick around + from previous runs of the inferior. So clear them. */ + /* However, it is more confusing for the ignore counts to disappear when + using hit counts. So don't clear them if we're counting hits. */ + if (!show_breakpoint_hit_counts) + breakpoint_clear_ignore_counts (); + + if (detach_hook) + detach_hook (); } /* This table must match in order and size the signals in enum target_signal in target.h. */ +/* *INDENT-OFF* */ static struct { char *name; char *string; @@ -806,27 +1388,79 @@ static struct { {"SIGLWP", "Signal LWP"}, {"SIGDANGER", "Swap space dangerously low"}, {"SIGGRANT", "Monitor mode granted"}, - {"SIGRETRACT", "Need to relinguish monitor mode"}, + {"SIGRETRACT", "Need to relinquish monitor mode"}, {"SIGMSG", "Monitor mode data available"}, {"SIGSOUND", "Sound completed"}, {"SIGSAK", "Secure attention"}, + {"SIGPRIO", "SIGPRIO"}, + {"SIG33", "Real-time event 33"}, + {"SIG34", "Real-time event 34"}, + {"SIG35", "Real-time event 35"}, + {"SIG36", "Real-time event 36"}, + {"SIG37", "Real-time event 37"}, + {"SIG38", "Real-time event 38"}, + {"SIG39", "Real-time event 39"}, + {"SIG40", "Real-time event 40"}, + {"SIG41", "Real-time event 41"}, + {"SIG42", "Real-time event 42"}, + {"SIG43", "Real-time event 43"}, + {"SIG44", "Real-time event 44"}, + {"SIG45", "Real-time event 45"}, + {"SIG46", "Real-time event 46"}, + {"SIG47", "Real-time event 47"}, + {"SIG48", "Real-time event 48"}, + {"SIG49", "Real-time event 49"}, + {"SIG50", "Real-time event 50"}, + {"SIG51", "Real-time event 51"}, + {"SIG52", "Real-time event 52"}, + {"SIG53", "Real-time event 53"}, + {"SIG54", "Real-time event 54"}, + {"SIG55", "Real-time event 55"}, + {"SIG56", "Real-time event 56"}, + {"SIG57", "Real-time event 57"}, + {"SIG58", "Real-time event 58"}, + {"SIG59", "Real-time event 59"}, + {"SIG60", "Real-time event 60"}, + {"SIG61", "Real-time event 61"}, + {"SIG62", "Real-time event 62"}, + {"SIG63", "Real-time event 63"}, + {"SIGCANCEL", "LWP internal signal"}, + {"SIG32", "Real-time event 32"}, + +#if defined(MACH) || defined(__MACH__) + /* Mach exceptions */ + {"EXC_BAD_ACCESS", "Could not access memory"}, + {"EXC_BAD_INSTRUCTION", "Illegal instruction/operand"}, + {"EXC_ARITHMETIC", "Arithmetic exception"}, + {"EXC_EMULATION", "Emulation instruction"}, + {"EXC_SOFTWARE", "Software generated exception"}, + {"EXC_BREAKPOINT", "Breakpoint"}, +#endif + {"SIGINFO", "Information request"}, + {NULL, "Unknown signal"}, + {NULL, "Internal error: printing TARGET_SIGNAL_DEFAULT"}, + /* Last entry, used to check whether the table is the right size. */ {NULL, "TARGET_SIGNAL_MAGIC"} }; +/* *INDENT-ON* */ + + /* Return the string for a signal. */ char * -target_signal_to_string (sig) - enum target_signal sig; +target_signal_to_string (enum target_signal sig) { - return signals[sig].string; + if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST)) + return signals[sig].string; + else + return signals[TARGET_SIGNAL_UNKNOWN].string; } /* Return the name for a signal. */ char * -target_signal_to_name (sig) - enum target_signal sig; +target_signal_to_name (enum target_signal sig) { if (sig == TARGET_SIGNAL_UNKNOWN) /* I think the code which prints this will always print it along with @@ -837,8 +1471,7 @@ target_signal_to_name (sig) /* Given a name, return its signal. */ enum target_signal -target_signal_from_name (name) - char *name; +target_signal_from_name (char *name) { enum target_signal sig; @@ -847,39 +1480,1445 @@ target_signal_from_name (name) questionable; seems like by now people should call it SIGABRT instead. */ - for (sig = TARGET_SIGNAL_HUP; signals[sig].name != NULL; ++sig) + /* This ugly cast brought to you by the native VAX compiler. */ + for (sig = TARGET_SIGNAL_HUP; + signals[sig].name != NULL; + sig = (enum target_signal) ((int) sig + 1)) if (STREQ (name, signals[sig].name)) return sig; return TARGET_SIGNAL_UNKNOWN; } -/* Convert a normal process ID to a string. Returns the string in a static - buffer. */ +/* The following functions are to help certain targets deal + with the signal/waitstatus stuff. They could just as well be in + a file called native-utils.c or unixwaitstatus-utils.c or whatever. */ -char * -normal_pid_to_str (pid) - int pid; +/* Convert host signal to our signals. */ +enum target_signal +target_signal_from_host (int hostsig) { - static char buf[30]; + /* A switch statement would make sense but would require special kludges + to deal with the cases where more than one signal has the same number. */ - sprintf (buf, "process %d", pid); + if (hostsig == 0) + return TARGET_SIGNAL_0; - return buf; +#if defined (SIGHUP) + if (hostsig == SIGHUP) + return TARGET_SIGNAL_HUP; +#endif +#if defined (SIGINT) + if (hostsig == SIGINT) + return TARGET_SIGNAL_INT; +#endif +#if defined (SIGQUIT) + if (hostsig == SIGQUIT) + return TARGET_SIGNAL_QUIT; +#endif +#if defined (SIGILL) + if (hostsig == SIGILL) + return TARGET_SIGNAL_ILL; +#endif +#if defined (SIGTRAP) + if (hostsig == SIGTRAP) + return TARGET_SIGNAL_TRAP; +#endif +#if defined (SIGABRT) + if (hostsig == SIGABRT) + return TARGET_SIGNAL_ABRT; +#endif +#if defined (SIGEMT) + if (hostsig == SIGEMT) + return TARGET_SIGNAL_EMT; +#endif +#if defined (SIGFPE) + if (hostsig == SIGFPE) + return TARGET_SIGNAL_FPE; +#endif +#if defined (SIGKILL) + if (hostsig == SIGKILL) + return TARGET_SIGNAL_KILL; +#endif +#if defined (SIGBUS) + if (hostsig == SIGBUS) + return TARGET_SIGNAL_BUS; +#endif +#if defined (SIGSEGV) + if (hostsig == SIGSEGV) + return TARGET_SIGNAL_SEGV; +#endif +#if defined (SIGSYS) + if (hostsig == SIGSYS) + return TARGET_SIGNAL_SYS; +#endif +#if defined (SIGPIPE) + if (hostsig == SIGPIPE) + return TARGET_SIGNAL_PIPE; +#endif +#if defined (SIGALRM) + if (hostsig == SIGALRM) + return TARGET_SIGNAL_ALRM; +#endif +#if defined (SIGTERM) + if (hostsig == SIGTERM) + return TARGET_SIGNAL_TERM; +#endif +#if defined (SIGUSR1) + if (hostsig == SIGUSR1) + return TARGET_SIGNAL_USR1; +#endif +#if defined (SIGUSR2) + if (hostsig == SIGUSR2) + return TARGET_SIGNAL_USR2; +#endif +#if defined (SIGCLD) + if (hostsig == SIGCLD) + return TARGET_SIGNAL_CHLD; +#endif +#if defined (SIGCHLD) + if (hostsig == SIGCHLD) + return TARGET_SIGNAL_CHLD; +#endif +#if defined (SIGPWR) + if (hostsig == SIGPWR) + return TARGET_SIGNAL_PWR; +#endif +#if defined (SIGWINCH) + if (hostsig == SIGWINCH) + return TARGET_SIGNAL_WINCH; +#endif +#if defined (SIGURG) + if (hostsig == SIGURG) + return TARGET_SIGNAL_URG; +#endif +#if defined (SIGIO) + if (hostsig == SIGIO) + return TARGET_SIGNAL_IO; +#endif +#if defined (SIGPOLL) + if (hostsig == SIGPOLL) + return TARGET_SIGNAL_POLL; +#endif +#if defined (SIGSTOP) + if (hostsig == SIGSTOP) + return TARGET_SIGNAL_STOP; +#endif +#if defined (SIGTSTP) + if (hostsig == SIGTSTP) + return TARGET_SIGNAL_TSTP; +#endif +#if defined (SIGCONT) + if (hostsig == SIGCONT) + return TARGET_SIGNAL_CONT; +#endif +#if defined (SIGTTIN) + if (hostsig == SIGTTIN) + return TARGET_SIGNAL_TTIN; +#endif +#if defined (SIGTTOU) + if (hostsig == SIGTTOU) + return TARGET_SIGNAL_TTOU; +#endif +#if defined (SIGVTALRM) + if (hostsig == SIGVTALRM) + return TARGET_SIGNAL_VTALRM; +#endif +#if defined (SIGPROF) + if (hostsig == SIGPROF) + return TARGET_SIGNAL_PROF; +#endif +#if defined (SIGXCPU) + if (hostsig == SIGXCPU) + return TARGET_SIGNAL_XCPU; +#endif +#if defined (SIGXFSZ) + if (hostsig == SIGXFSZ) + return TARGET_SIGNAL_XFSZ; +#endif +#if defined (SIGWIND) + if (hostsig == SIGWIND) + return TARGET_SIGNAL_WIND; +#endif +#if defined (SIGPHONE) + if (hostsig == SIGPHONE) + return TARGET_SIGNAL_PHONE; +#endif +#if defined (SIGLOST) + if (hostsig == SIGLOST) + return TARGET_SIGNAL_LOST; +#endif +#if defined (SIGWAITING) + if (hostsig == SIGWAITING) + return TARGET_SIGNAL_WAITING; +#endif +#if defined (SIGCANCEL) + if (hostsig == SIGCANCEL) + return TARGET_SIGNAL_CANCEL; +#endif +#if defined (SIGLWP) + if (hostsig == SIGLWP) + return TARGET_SIGNAL_LWP; +#endif +#if defined (SIGDANGER) + if (hostsig == SIGDANGER) + return TARGET_SIGNAL_DANGER; +#endif +#if defined (SIGGRANT) + if (hostsig == SIGGRANT) + return TARGET_SIGNAL_GRANT; +#endif +#if defined (SIGRETRACT) + if (hostsig == SIGRETRACT) + return TARGET_SIGNAL_RETRACT; +#endif +#if defined (SIGMSG) + if (hostsig == SIGMSG) + return TARGET_SIGNAL_MSG; +#endif +#if defined (SIGSOUND) + if (hostsig == SIGSOUND) + return TARGET_SIGNAL_SOUND; +#endif +#if defined (SIGSAK) + if (hostsig == SIGSAK) + return TARGET_SIGNAL_SAK; +#endif +#if defined (SIGPRIO) + if (hostsig == SIGPRIO) + return TARGET_SIGNAL_PRIO; +#endif + + /* Mach exceptions. Assumes that the values for EXC_ are positive! */ +#if defined (EXC_BAD_ACCESS) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BAD_ACCESS) + return TARGET_EXC_BAD_ACCESS; +#endif +#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BAD_INSTRUCTION) + return TARGET_EXC_BAD_INSTRUCTION; +#endif +#if defined (EXC_ARITHMETIC) && defined (_NSIG) + if (hostsig == _NSIG + EXC_ARITHMETIC) + return TARGET_EXC_ARITHMETIC; +#endif +#if defined (EXC_EMULATION) && defined (_NSIG) + if (hostsig == _NSIG + EXC_EMULATION) + return TARGET_EXC_EMULATION; +#endif +#if defined (EXC_SOFTWARE) && defined (_NSIG) + if (hostsig == _NSIG + EXC_SOFTWARE) + return TARGET_EXC_SOFTWARE; +#endif +#if defined (EXC_BREAKPOINT) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BREAKPOINT) + return TARGET_EXC_BREAKPOINT; +#endif + +#if defined (SIGINFO) + if (hostsig == SIGINFO) + return TARGET_SIGNAL_INFO; +#endif + +#if defined (REALTIME_LO) + if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) + { + /* This block of TARGET_SIGNAL_REALTIME value is in order. */ + if (33 <= hostsig && hostsig <= 63) + return (enum target_signal) + (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33); + else if (hostsig == 32) + return TARGET_SIGNAL_REALTIME_32; + else + error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); + } +#endif + +#if defined (SIGRTMIN) + if (hostsig >= SIGRTMIN && hostsig <= SIGRTMAX) + { + /* This block of TARGET_SIGNAL_REALTIME value is in order. */ + if (33 <= hostsig && hostsig <= 63) + return (enum target_signal) + (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33); + else + error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); + } +#endif + return TARGET_SIGNAL_UNKNOWN; } - -static char targ_desc[] = - "Names of targets and files being debugged.\n\ -Shows the entire stack of targets currently in use (including the exec-file,\n\ -core-file, and process, if any), as well as the symbol file name."; +/* Convert a OURSIG (an enum target_signal) to the form used by the + target operating system (refered to as the ``host'') or zero if the + equivalent host signal is not available. Set/clear OURSIG_OK + accordingly. */ + +static int +do_target_signal_to_host (enum target_signal oursig, + int *oursig_ok) +{ + *oursig_ok = 1; + switch (oursig) + { + case TARGET_SIGNAL_0: + return 0; + +#if defined (SIGHUP) + case TARGET_SIGNAL_HUP: + return SIGHUP; +#endif +#if defined (SIGINT) + case TARGET_SIGNAL_INT: + return SIGINT; +#endif +#if defined (SIGQUIT) + case TARGET_SIGNAL_QUIT: + return SIGQUIT; +#endif +#if defined (SIGILL) + case TARGET_SIGNAL_ILL: + return SIGILL; +#endif +#if defined (SIGTRAP) + case TARGET_SIGNAL_TRAP: + return SIGTRAP; +#endif +#if defined (SIGABRT) + case TARGET_SIGNAL_ABRT: + return SIGABRT; +#endif +#if defined (SIGEMT) + case TARGET_SIGNAL_EMT: + return SIGEMT; +#endif +#if defined (SIGFPE) + case TARGET_SIGNAL_FPE: + return SIGFPE; +#endif +#if defined (SIGKILL) + case TARGET_SIGNAL_KILL: + return SIGKILL; +#endif +#if defined (SIGBUS) + case TARGET_SIGNAL_BUS: + return SIGBUS; +#endif +#if defined (SIGSEGV) + case TARGET_SIGNAL_SEGV: + return SIGSEGV; +#endif +#if defined (SIGSYS) + case TARGET_SIGNAL_SYS: + return SIGSYS; +#endif +#if defined (SIGPIPE) + case TARGET_SIGNAL_PIPE: + return SIGPIPE; +#endif +#if defined (SIGALRM) + case TARGET_SIGNAL_ALRM: + return SIGALRM; +#endif +#if defined (SIGTERM) + case TARGET_SIGNAL_TERM: + return SIGTERM; +#endif +#if defined (SIGUSR1) + case TARGET_SIGNAL_USR1: + return SIGUSR1; +#endif +#if defined (SIGUSR2) + case TARGET_SIGNAL_USR2: + return SIGUSR2; +#endif +#if defined (SIGCHLD) || defined (SIGCLD) + case TARGET_SIGNAL_CHLD: +#if defined (SIGCHLD) + return SIGCHLD; +#else + return SIGCLD; +#endif +#endif /* SIGCLD or SIGCHLD */ +#if defined (SIGPWR) + case TARGET_SIGNAL_PWR: + return SIGPWR; +#endif +#if defined (SIGWINCH) + case TARGET_SIGNAL_WINCH: + return SIGWINCH; +#endif +#if defined (SIGURG) + case TARGET_SIGNAL_URG: + return SIGURG; +#endif +#if defined (SIGIO) + case TARGET_SIGNAL_IO: + return SIGIO; +#endif +#if defined (SIGPOLL) + case TARGET_SIGNAL_POLL: + return SIGPOLL; +#endif +#if defined (SIGSTOP) + case TARGET_SIGNAL_STOP: + return SIGSTOP; +#endif +#if defined (SIGTSTP) + case TARGET_SIGNAL_TSTP: + return SIGTSTP; +#endif +#if defined (SIGCONT) + case TARGET_SIGNAL_CONT: + return SIGCONT; +#endif +#if defined (SIGTTIN) + case TARGET_SIGNAL_TTIN: + return SIGTTIN; +#endif +#if defined (SIGTTOU) + case TARGET_SIGNAL_TTOU: + return SIGTTOU; +#endif +#if defined (SIGVTALRM) + case TARGET_SIGNAL_VTALRM: + return SIGVTALRM; +#endif +#if defined (SIGPROF) + case TARGET_SIGNAL_PROF: + return SIGPROF; +#endif +#if defined (SIGXCPU) + case TARGET_SIGNAL_XCPU: + return SIGXCPU; +#endif +#if defined (SIGXFSZ) + case TARGET_SIGNAL_XFSZ: + return SIGXFSZ; +#endif +#if defined (SIGWIND) + case TARGET_SIGNAL_WIND: + return SIGWIND; +#endif +#if defined (SIGPHONE) + case TARGET_SIGNAL_PHONE: + return SIGPHONE; +#endif +#if defined (SIGLOST) + case TARGET_SIGNAL_LOST: + return SIGLOST; +#endif +#if defined (SIGWAITING) + case TARGET_SIGNAL_WAITING: + return SIGWAITING; +#endif +#if defined (SIGCANCEL) + case TARGET_SIGNAL_CANCEL: + return SIGCANCEL; +#endif +#if defined (SIGLWP) + case TARGET_SIGNAL_LWP: + return SIGLWP; +#endif +#if defined (SIGDANGER) + case TARGET_SIGNAL_DANGER: + return SIGDANGER; +#endif +#if defined (SIGGRANT) + case TARGET_SIGNAL_GRANT: + return SIGGRANT; +#endif +#if defined (SIGRETRACT) + case TARGET_SIGNAL_RETRACT: + return SIGRETRACT; +#endif +#if defined (SIGMSG) + case TARGET_SIGNAL_MSG: + return SIGMSG; +#endif +#if defined (SIGSOUND) + case TARGET_SIGNAL_SOUND: + return SIGSOUND; +#endif +#if defined (SIGSAK) + case TARGET_SIGNAL_SAK: + return SIGSAK; +#endif +#if defined (SIGPRIO) + case TARGET_SIGNAL_PRIO: + return SIGPRIO; +#endif + + /* Mach exceptions. Assumes that the values for EXC_ are positive! */ +#if defined (EXC_BAD_ACCESS) && defined (_NSIG) + case TARGET_EXC_BAD_ACCESS: + return _NSIG + EXC_BAD_ACCESS; +#endif +#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) + case TARGET_EXC_BAD_INSTRUCTION: + return _NSIG + EXC_BAD_INSTRUCTION; +#endif +#if defined (EXC_ARITHMETIC) && defined (_NSIG) + case TARGET_EXC_ARITHMETIC: + return _NSIG + EXC_ARITHMETIC; +#endif +#if defined (EXC_EMULATION) && defined (_NSIG) + case TARGET_EXC_EMULATION: + return _NSIG + EXC_EMULATION; +#endif +#if defined (EXC_SOFTWARE) && defined (_NSIG) + case TARGET_EXC_SOFTWARE: + return _NSIG + EXC_SOFTWARE; +#endif +#if defined (EXC_BREAKPOINT) && defined (_NSIG) + case TARGET_EXC_BREAKPOINT: + return _NSIG + EXC_BREAKPOINT; +#endif + +#if defined (SIGINFO) + case TARGET_SIGNAL_INFO: + return SIGINFO; +#endif + + default: +#if defined (REALTIME_LO) + if (oursig >= TARGET_SIGNAL_REALTIME_33 + && oursig <= TARGET_SIGNAL_REALTIME_63) + { + /* This block of signals is continuous, and + TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ + int retsig = + (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; + if (retsig >= REALTIME_LO && retsig < REALTIME_HI) + return retsig; + } +#if (REALTIME_LO < 33) + else if (oursig == TARGET_SIGNAL_REALTIME_32) + { + /* TARGET_SIGNAL_REALTIME_32 isn't contiguous with + TARGET_SIGNAL_REALTIME_33. It is 32 by definition. */ + return 32; + } +#endif +#endif + +#if defined (SIGRTMIN) + if (oursig >= TARGET_SIGNAL_REALTIME_33 + && oursig <= TARGET_SIGNAL_REALTIME_63) + { + /* This block of signals is continuous, and + TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ + int retsig = + (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; + if (retsig >= SIGRTMIN && retsig <= SIGRTMAX) + return retsig; + } +#endif + *oursig_ok = 0; + return 0; + } +} + +int +target_signal_to_host_p (enum target_signal oursig) +{ + int oursig_ok; + do_target_signal_to_host (oursig, &oursig_ok); + return oursig_ok; +} + +int +target_signal_to_host (enum target_signal oursig) +{ + int oursig_ok; + int targ_signo = do_target_signal_to_host (oursig, &oursig_ok); + if (!oursig_ok) + { + /* The user might be trying to do "signal SIGSAK" where this system + doesn't have SIGSAK. */ + warning ("Signal %s does not exist on this system.\n", + target_signal_to_name (oursig)); + return 0; + } + else + return targ_signo; +} + +/* Helper function for child_wait and the Lynx derivatives of child_wait. + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our + translation of that in OURSTATUS. */ void -_initialize_targets () +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) { - current_target = &dummy_target; - cleanup_target (current_target); +#ifdef CHILD_SPECIAL_WAITSTATUS + /* CHILD_SPECIAL_WAITSTATUS should return nonzero and set *OURSTATUS + if it wants to deal with hoststatus. */ + if (CHILD_SPECIAL_WAITSTATUS (ourstatus, hoststatus)) + return; +#endif - add_info ("target", target_info, targ_desc); - add_info ("files", target_info, targ_desc); + if (WIFEXITED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (hoststatus); + } + else if (!WIFSTOPPED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = target_signal_from_host (WTERMSIG (hoststatus)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus)); + } +} + +/* In some circumstances we allow a command to specify a numeric + signal. The idea is to keep these circumstances limited so that + users (and scripts) develop portable habits. For comparison, + POSIX.2 `kill' requires that 1,2,3,6,9,14, and 15 work (and using a + numeric signal at all is obsolescent. We are slightly more + lenient and allow 1-15 which should match host signal numbers on + most systems. Use of symbolic signal names is strongly encouraged. */ + +enum target_signal +target_signal_from_command (int num) +{ + if (num >= 1 && num <= 15) + return (enum target_signal) num; + error ("Only signals 1-15 are valid as numeric signals.\n\ +Use \"info signals\" for a list of symbolic signals."); +} + +/* Returns zero to leave the inferior alone, one to interrupt it. */ +int (*target_activity_function) (void); +int target_activity_fd; + +/* Convert a normal process ID to a string. Returns the string in a static + buffer. */ + +char * +normal_pid_to_str (int pid) +{ + static char buf[30]; + + if (STREQ (current_target.to_shortname, "remote")) + sprintf (buf, "thread %d", pid); + else + sprintf (buf, "process %d", pid); + + return buf; +} + +/* Some targets (such as ttrace-based HPUX) don't allow us to request + notification of inferior events such as fork and vork immediately + after the inferior is created. (This because of how gdb gets an + inferior created via invoking a shell to do it. In such a scenario, + if the shell init file has commands in it, the shell will fork and + exec for each of those commands, and we will see each such fork + event. Very bad.) + + This function is used by all targets that allow us to request + notification of forks, etc at inferior creation time; e.g., in + target_acknowledge_forked_child. + */ +static void +normal_target_post_startup_inferior (int pid) +{ + /* This space intentionally left blank. */ +} + +/* Set up the handful of non-empty slots needed by the dummy target + vector. */ + +static void +init_dummy_target (void) +{ + dummy_target.to_shortname = "None"; + dummy_target.to_longname = "None"; + dummy_target.to_doc = ""; + dummy_target.to_attach = find_default_attach; + dummy_target.to_require_attach = find_default_require_attach; + dummy_target.to_require_detach = find_default_require_detach; + dummy_target.to_create_inferior = find_default_create_inferior; + dummy_target.to_clone_and_follow_inferior = find_default_clone_and_follow_inferior; + dummy_target.to_pid_to_str = normal_pid_to_str; + dummy_target.to_stratum = dummy_stratum; + dummy_target.to_magic = OPS_MAGIC; +} + + +static struct target_ops debug_target; + +static void +debug_to_open (char *args, int from_tty) +{ + debug_target.to_open (args, from_tty); + + fprintf_unfiltered (gdb_stdlog, "target_open (%s, %d)\n", args, from_tty); +} + +static void +debug_to_close (int quitting) +{ + debug_target.to_close (quitting); + + fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting); +} + +static void +debug_to_attach (char *args, int from_tty) +{ + debug_target.to_attach (args, from_tty); + + fprintf_unfiltered (gdb_stdlog, "target_attach (%s, %d)\n", args, from_tty); +} + + +static void +debug_to_post_attach (int pid) +{ + debug_target.to_post_attach (pid); + + fprintf_unfiltered (gdb_stdlog, "target_post_attach (%d)\n", pid); +} + +static void +debug_to_require_attach (char *args, int from_tty) +{ + debug_target.to_require_attach (args, from_tty); + + fprintf_unfiltered (gdb_stdlog, + "target_require_attach (%s, %d)\n", args, from_tty); +} + +static void +debug_to_detach (char *args, int from_tty) +{ + debug_target.to_detach (args, from_tty); + + fprintf_unfiltered (gdb_stdlog, "target_detach (%s, %d)\n", args, from_tty); +} + +static void +debug_to_require_detach (int pid, char *args, int from_tty) +{ + debug_target.to_require_detach (pid, args, from_tty); + + fprintf_unfiltered (gdb_stdlog, + "target_require_detach (%d, %s, %d)\n", pid, args, from_tty); +} + +static void +debug_to_resume (int pid, int step, enum target_signal siggnal) +{ + debug_target.to_resume (pid, step, siggnal); + + fprintf_unfiltered (gdb_stdlog, "target_resume (%d, %s, %s)\n", pid, + step ? "step" : "continue", + target_signal_to_name (siggnal)); +} + +static int +debug_to_wait (int pid, struct target_waitstatus *status) +{ + int retval; + + retval = debug_target.to_wait (pid, status); + + fprintf_unfiltered (gdb_stdlog, + "target_wait (%d, status) = %d, ", pid, retval); + fprintf_unfiltered (gdb_stdlog, "status->kind = "); + switch (status->kind) + { + case TARGET_WAITKIND_EXITED: + fprintf_unfiltered (gdb_stdlog, "exited, status = %d\n", + status->value.integer); + break; + case TARGET_WAITKIND_STOPPED: + fprintf_unfiltered (gdb_stdlog, "stopped, signal = %s\n", + target_signal_to_name (status->value.sig)); + break; + case TARGET_WAITKIND_SIGNALLED: + fprintf_unfiltered (gdb_stdlog, "signalled, signal = %s\n", + target_signal_to_name (status->value.sig)); + break; + case TARGET_WAITKIND_LOADED: + fprintf_unfiltered (gdb_stdlog, "loaded\n"); + break; + case TARGET_WAITKIND_FORKED: + fprintf_unfiltered (gdb_stdlog, "forked\n"); + break; + case TARGET_WAITKIND_VFORKED: + fprintf_unfiltered (gdb_stdlog, "vforked\n"); + break; + case TARGET_WAITKIND_EXECD: + fprintf_unfiltered (gdb_stdlog, "execd\n"); + break; + case TARGET_WAITKIND_SPURIOUS: + fprintf_unfiltered (gdb_stdlog, "spurious\n"); + break; + default: + fprintf_unfiltered (gdb_stdlog, "unknown???\n"); + break; + } + + return retval; +} + +static void +debug_to_post_wait (int pid, int status) +{ + debug_target.to_post_wait (pid, status); + + fprintf_unfiltered (gdb_stdlog, "target_post_wait (%d, %d)\n", + pid, status); +} + +static void +debug_to_fetch_registers (int regno) +{ + debug_target.to_fetch_registers (regno); + + fprintf_unfiltered (gdb_stdlog, "target_fetch_registers (%s)", + regno != -1 ? REGISTER_NAME (regno) : "-1"); + if (regno != -1) + fprintf_unfiltered (gdb_stdlog, " = 0x%lx %ld", + (unsigned long) read_register (regno), + (unsigned long) read_register (regno)); + fprintf_unfiltered (gdb_stdlog, "\n"); +} + +static void +debug_to_store_registers (int regno) +{ + debug_target.to_store_registers (regno); + + if (regno >= 0 && regno < NUM_REGS) + fprintf_unfiltered (gdb_stdlog, "target_store_registers (%s) = 0x%lx %ld\n", + REGISTER_NAME (regno), + (unsigned long) read_register (regno), + (unsigned long) read_register (regno)); + else + fprintf_unfiltered (gdb_stdlog, "target_store_registers (%d)\n", regno); +} + +static void +debug_to_prepare_to_store (void) +{ + debug_target.to_prepare_to_store (); + + fprintf_unfiltered (gdb_stdlog, "target_prepare_to_store ()\n"); +} + +static int +debug_to_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct target_ops *target) +{ + int retval; + + retval = debug_target.to_xfer_memory (memaddr, myaddr, len, write, target); + + fprintf_unfiltered (gdb_stdlog, + "target_xfer_memory (0x%x, xxx, %d, %s, xxx) = %d", + (unsigned int) memaddr, /* possable truncate long long */ + len, write ? "write" : "read", retval); + + + + if (retval > 0) + { + int i; + + fputs_unfiltered (", bytes =", gdb_stdlog); + for (i = 0; i < retval; i++) + { + if ((((long) &(myaddr[i])) & 0xf) == 0) + fprintf_unfiltered (gdb_stdlog, "\n"); + fprintf_unfiltered (gdb_stdlog, " %02x", myaddr[i] & 0xff); + } + } + + fputc_unfiltered ('\n', gdb_stdlog); + + return retval; +} + +static void +debug_to_files_info (struct target_ops *target) +{ + debug_target.to_files_info (target); + + fprintf_unfiltered (gdb_stdlog, "target_files_info (xxx)\n"); +} + +static int +debug_to_insert_breakpoint (CORE_ADDR addr, char *save) +{ + int retval; + + retval = debug_target.to_insert_breakpoint (addr, save); + + fprintf_unfiltered (gdb_stdlog, + "target_insert_breakpoint (0x%lx, xxx) = %ld\n", + (unsigned long) addr, + (unsigned long) retval); + return retval; +} + +static int +debug_to_remove_breakpoint (CORE_ADDR addr, char *save) +{ + int retval; + + retval = debug_target.to_remove_breakpoint (addr, save); + + fprintf_unfiltered (gdb_stdlog, + "target_remove_breakpoint (0x%lx, xxx) = %ld\n", + (unsigned long) addr, + (unsigned long) retval); + return retval; +} + +static void +debug_to_terminal_init (void) +{ + debug_target.to_terminal_init (); + + fprintf_unfiltered (gdb_stdlog, "target_terminal_init ()\n"); +} + +static void +debug_to_terminal_inferior (void) +{ + debug_target.to_terminal_inferior (); + + fprintf_unfiltered (gdb_stdlog, "target_terminal_inferior ()\n"); +} + +static void +debug_to_terminal_ours_for_output (void) +{ + debug_target.to_terminal_ours_for_output (); + + fprintf_unfiltered (gdb_stdlog, "target_terminal_ours_for_output ()\n"); +} + +static void +debug_to_terminal_ours (void) +{ + debug_target.to_terminal_ours (); + + fprintf_unfiltered (gdb_stdlog, "target_terminal_ours ()\n"); +} + +static void +debug_to_terminal_info (char *arg, int from_tty) +{ + debug_target.to_terminal_info (arg, from_tty); + + fprintf_unfiltered (gdb_stdlog, "target_terminal_info (%s, %d)\n", arg, + from_tty); +} + +static void +debug_to_kill (void) +{ + debug_target.to_kill (); + + fprintf_unfiltered (gdb_stdlog, "target_kill ()\n"); +} + +static void +debug_to_load (char *args, int from_tty) +{ + debug_target.to_load (args, from_tty); + + fprintf_unfiltered (gdb_stdlog, "target_load (%s, %d)\n", args, from_tty); +} + +static int +debug_to_lookup_symbol (char *name, CORE_ADDR *addrp) +{ + int retval; + + retval = debug_target.to_lookup_symbol (name, addrp); + + fprintf_unfiltered (gdb_stdlog, "target_lookup_symbol (%s, xxx)\n", name); + + return retval; +} + +static void +debug_to_create_inferior (char *exec_file, char *args, char **env) +{ + debug_target.to_create_inferior (exec_file, args, env); + + fprintf_unfiltered (gdb_stdlog, "target_create_inferior (%s, %s, xxx)\n", + exec_file, args); +} + +static void +debug_to_post_startup_inferior (int pid) +{ + debug_target.to_post_startup_inferior (pid); + + fprintf_unfiltered (gdb_stdlog, "target_post_startup_inferior (%d)\n", + pid); +} + +static void +debug_to_acknowledge_created_inferior (int pid) +{ + debug_target.to_acknowledge_created_inferior (pid); + + fprintf_unfiltered (gdb_stdlog, "target_acknowledge_created_inferior (%d)\n", + pid); +} + +static void +debug_to_clone_and_follow_inferior (int child_pid, int *followed_child) +{ + debug_target.to_clone_and_follow_inferior (child_pid, followed_child); + + fprintf_unfiltered (gdb_stdlog, + "target_clone_and_follow_inferior (%d, %d)\n", + child_pid, *followed_child); +} + +static void +debug_to_post_follow_inferior_by_clone (void) +{ + debug_target.to_post_follow_inferior_by_clone (); + + fprintf_unfiltered (gdb_stdlog, "target_post_follow_inferior_by_clone ()\n"); +} + +static int +debug_to_insert_fork_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_insert_fork_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_insert_fork_catchpoint (%d) = %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_remove_fork_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_remove_fork_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_remove_fork_catchpoint (%d) = %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_insert_vfork_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_insert_vfork_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_insert_vfork_catchpoint (%d)= %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_remove_vfork_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_remove_vfork_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_remove_vfork_catchpoint (%d) = %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_has_forked (int pid, int *child_pid) +{ + int has_forked; + + has_forked = debug_target.to_has_forked (pid, child_pid); + + fprintf_unfiltered (gdb_stdlog, "target_has_forked (%d, %d) = %d\n", + pid, *child_pid, has_forked); + + return has_forked; +} + +static int +debug_to_has_vforked (int pid, int *child_pid) +{ + int has_vforked; + + has_vforked = debug_target.to_has_vforked (pid, child_pid); + + fprintf_unfiltered (gdb_stdlog, "target_has_vforked (%d, %d) = %d\n", + pid, *child_pid, has_vforked); + + return has_vforked; +} + +static int +debug_to_can_follow_vfork_prior_to_exec (void) +{ + int can_immediately_follow_vfork; + + can_immediately_follow_vfork = debug_target.to_can_follow_vfork_prior_to_exec (); + + fprintf_unfiltered (gdb_stdlog, "target_can_follow_vfork_prior_to_exec () = %d\n", + can_immediately_follow_vfork); + + return can_immediately_follow_vfork; +} + +static void +debug_to_post_follow_vfork (int parent_pid, int followed_parent, int child_pid, + int followed_child) +{ + debug_target.to_post_follow_vfork (parent_pid, followed_parent, child_pid, followed_child); + + fprintf_unfiltered (gdb_stdlog, + "target_post_follow_vfork (%d, %d, %d, %d)\n", + parent_pid, followed_parent, child_pid, followed_child); +} + +static int +debug_to_insert_exec_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_insert_exec_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_insert_exec_catchpoint (%d) = %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_remove_exec_catchpoint (int pid) +{ + int retval; + + retval = debug_target.to_remove_exec_catchpoint (pid); + + fprintf_unfiltered (gdb_stdlog, "target_remove_exec_catchpoint (%d) = %d\n", + pid, retval); + + return retval; +} + +static int +debug_to_has_execd (int pid, char **execd_pathname) +{ + int has_execd; + + has_execd = debug_target.to_has_execd (pid, execd_pathname); + + fprintf_unfiltered (gdb_stdlog, "target_has_execd (%d, %s) = %d\n", + pid, (*execd_pathname ? *execd_pathname : ""), + has_execd); + + return has_execd; +} + +static int +debug_to_reported_exec_events_per_exec_call (void) +{ + int reported_exec_events; + + reported_exec_events = debug_target.to_reported_exec_events_per_exec_call (); + + fprintf_unfiltered (gdb_stdlog, + "target_reported_exec_events_per_exec_call () = %d\n", + reported_exec_events); + + return reported_exec_events; +} + +static int +debug_to_has_syscall_event (int pid, enum target_waitkind *kind, + int *syscall_id) +{ + int has_syscall_event; + char *kind_spelling = "??"; + + has_syscall_event = debug_target.to_has_syscall_event (pid, kind, syscall_id); + if (has_syscall_event) + { + switch (*kind) + { + case TARGET_WAITKIND_SYSCALL_ENTRY: + kind_spelling = "SYSCALL_ENTRY"; + break; + case TARGET_WAITKIND_SYSCALL_RETURN: + kind_spelling = "SYSCALL_RETURN"; + break; + default: + break; + } + } + + fprintf_unfiltered (gdb_stdlog, + "target_has_syscall_event (%d, %s, %d) = %d\n", + pid, kind_spelling, *syscall_id, has_syscall_event); + + return has_syscall_event; +} + +static int +debug_to_has_exited (int pid, int wait_status, int *exit_status) +{ + int has_exited; + + has_exited = debug_target.to_has_exited (pid, wait_status, exit_status); + + fprintf_unfiltered (gdb_stdlog, "target_has_exited (%d, %d, %d) = %d\n", + pid, wait_status, *exit_status, has_exited); + + return has_exited; +} + +static void +debug_to_mourn_inferior (void) +{ + debug_target.to_mourn_inferior (); + + fprintf_unfiltered (gdb_stdlog, "target_mourn_inferior ()\n"); +} + +static int +debug_to_can_run (void) +{ + int retval; + + retval = debug_target.to_can_run (); + + fprintf_unfiltered (gdb_stdlog, "target_can_run () = %d\n", retval); + + return retval; +} + +static void +debug_to_notice_signals (int pid) +{ + debug_target.to_notice_signals (pid); + + fprintf_unfiltered (gdb_stdlog, "target_notice_signals (%d)\n", pid); +} + +static int +debug_to_thread_alive (int pid) +{ + int retval; + + retval = debug_target.to_thread_alive (pid); + + fprintf_unfiltered (gdb_stdlog, "target_thread_alive (%d) = %d\n", + pid, retval); + + return retval; +} + +static void +debug_to_find_new_threads (void) +{ + debug_target.to_find_new_threads (); + + fputs_unfiltered ("target_find_new_threads ()\n", gdb_stdlog); +} + +static void +debug_to_stop (void) +{ + debug_target.to_stop (); + + fprintf_unfiltered (gdb_stdlog, "target_stop ()\n"); +} + +static int +debug_to_query (int type, char *req, char *resp, int *siz) +{ + int retval; + + retval = debug_target.to_query (type, req, resp, siz); + + fprintf_unfiltered (gdb_stdlog, "target_query (%c, %s, %s, %d) = %d\n", type, req, resp, *siz, retval); + + return retval; +} + +static void +debug_to_rcmd (char *command, + struct ui_file *outbuf) +{ + debug_target.to_rcmd (command, outbuf); + fprintf_unfiltered (gdb_stdlog, "target_rcmd (%s, ...)\n", command); +} + +static struct symtab_and_line * +debug_to_enable_exception_callback (enum exception_event_kind kind, int enable) +{ + struct symtab_and_line *result; + result = debug_target.to_enable_exception_callback (kind, enable); + fprintf_unfiltered (gdb_stdlog, + "target get_exception_callback_sal (%d, %d)\n", + kind, enable); + return result; +} + +static struct exception_event_record * +debug_to_get_current_exception_event (void) +{ + struct exception_event_record *result; + result = debug_target.to_get_current_exception_event (); + fprintf_unfiltered (gdb_stdlog, "target get_current_exception_event ()\n"); + return result; +} + +static char * +debug_to_pid_to_exec_file (int pid) +{ + char *exec_file; + + exec_file = debug_target.to_pid_to_exec_file (pid); + + fprintf_unfiltered (gdb_stdlog, "target_pid_to_exec_file (%d) = %s\n", + pid, exec_file); + + return exec_file; +} + +static char * +debug_to_core_file_to_sym_file (char *core) +{ + char *sym_file; + + sym_file = debug_target.to_core_file_to_sym_file (core); + + fprintf_unfiltered (gdb_stdlog, "target_core_file_to_sym_file (%s) = %s\n", + core, sym_file); + + return sym_file; +} + +static void +setup_target_debug (void) +{ + memcpy (&debug_target, ¤t_target, sizeof debug_target); + + current_target.to_open = debug_to_open; + current_target.to_close = debug_to_close; + current_target.to_attach = debug_to_attach; + current_target.to_post_attach = debug_to_post_attach; + current_target.to_require_attach = debug_to_require_attach; + current_target.to_detach = debug_to_detach; + current_target.to_require_detach = debug_to_require_detach; + current_target.to_resume = debug_to_resume; + current_target.to_wait = debug_to_wait; + current_target.to_post_wait = debug_to_post_wait; + current_target.to_fetch_registers = debug_to_fetch_registers; + current_target.to_store_registers = debug_to_store_registers; + current_target.to_prepare_to_store = debug_to_prepare_to_store; + current_target.to_xfer_memory = debug_to_xfer_memory; + current_target.to_files_info = debug_to_files_info; + current_target.to_insert_breakpoint = debug_to_insert_breakpoint; + current_target.to_remove_breakpoint = debug_to_remove_breakpoint; + current_target.to_terminal_init = debug_to_terminal_init; + current_target.to_terminal_inferior = debug_to_terminal_inferior; + current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output; + current_target.to_terminal_ours = debug_to_terminal_ours; + current_target.to_terminal_info = debug_to_terminal_info; + current_target.to_kill = debug_to_kill; + current_target.to_load = debug_to_load; + current_target.to_lookup_symbol = debug_to_lookup_symbol; + current_target.to_create_inferior = debug_to_create_inferior; + current_target.to_post_startup_inferior = debug_to_post_startup_inferior; + current_target.to_acknowledge_created_inferior = debug_to_acknowledge_created_inferior; + current_target.to_clone_and_follow_inferior = debug_to_clone_and_follow_inferior; + current_target.to_post_follow_inferior_by_clone = debug_to_post_follow_inferior_by_clone; + current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint; + current_target.to_remove_fork_catchpoint = debug_to_remove_fork_catchpoint; + current_target.to_insert_vfork_catchpoint = debug_to_insert_vfork_catchpoint; + current_target.to_remove_vfork_catchpoint = debug_to_remove_vfork_catchpoint; + current_target.to_has_forked = debug_to_has_forked; + current_target.to_has_vforked = debug_to_has_vforked; + current_target.to_can_follow_vfork_prior_to_exec = debug_to_can_follow_vfork_prior_to_exec; + current_target.to_post_follow_vfork = debug_to_post_follow_vfork; + current_target.to_insert_exec_catchpoint = debug_to_insert_exec_catchpoint; + current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint; + current_target.to_has_execd = debug_to_has_execd; + current_target.to_reported_exec_events_per_exec_call = debug_to_reported_exec_events_per_exec_call; + current_target.to_has_syscall_event = debug_to_has_syscall_event; + current_target.to_has_exited = debug_to_has_exited; + current_target.to_mourn_inferior = debug_to_mourn_inferior; + current_target.to_can_run = debug_to_can_run; + current_target.to_notice_signals = debug_to_notice_signals; + current_target.to_thread_alive = debug_to_thread_alive; + current_target.to_find_new_threads = debug_to_find_new_threads; + current_target.to_stop = debug_to_stop; + current_target.to_query = debug_to_query; + current_target.to_rcmd = debug_to_rcmd; + current_target.to_enable_exception_callback = debug_to_enable_exception_callback; + current_target.to_get_current_exception_event = debug_to_get_current_exception_event; + current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file; + current_target.to_core_file_to_sym_file = debug_to_core_file_to_sym_file; + +} + + +static char targ_desc[] = +"Names of targets and files being debugged.\n\ +Shows the entire stack of targets currently in use (including the exec-file,\n\ +core-file, and process, if any), as well as the symbol file name."; + +static void +do_monitor_command (char *cmd, + int from_tty) +{ + if ((current_target.to_rcmd + == (void (*) (char *, struct ui_file *)) tcomplain) + || (current_target.to_rcmd == debug_to_rcmd + && (debug_target.to_rcmd + == (void (*) (char *, struct ui_file *)) tcomplain))) + { + error ("\"monitor\" command not supported by this target.\n"); + } + target_rcmd (cmd, gdb_stdtarg); +} + +void +initialize_targets (void) +{ + init_dummy_target (); + push_target (&dummy_target); + + add_info ("target", target_info, targ_desc); + add_info ("files", target_info, targ_desc); + + add_show_from_set ( + add_set_cmd ("target", class_maintenance, var_zinteger, + (char *) &targetdebug, + "Set target debugging.\n\ +When non-zero, target debugging is enabled.", &setdebuglist), + &showdebuglist); + + + add_com ("monitor", class_obscure, do_monitor_command, + "Send a command to the remote monitor (remote targets only)."); if (!STREQ (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC")) abort ();