/* Select target systems and architectures at runtime for GDB.
- Copyright 1990, 1992 Free Software Foundation, Inc.
+ Copyright 1990, 1992, 1993 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
static int
nomemory PARAMS ((CORE_ADDR, char *, int, int));
+static int
+return_zero PARAMS ((void));
+
static void
ignore PARAMS ((void));
+
static void
target_command PARAMS ((char *, int));
+static struct target_ops *
+find_default_run_target PARAMS ((char *));
+
/* Pointer to array of target architecture structures; the size of the
array; the current index into the array; the allocated size of the
array. */
current target. */
struct target_ops dummy_target = {"None", "None", "",
- 0, 0, 0, 0, /* open, close, attach, detach */
+ 0, 0, /* open, close */
+ find_default_attach, 0, /* attach, detach */
0, 0, /* resume, wait */
- 0, 0, 0, 0, 0, /* registers */
+ 0, 0, 0, /* registers */
0, 0, /* memory */
0, 0, /* bkpts */
0, 0, 0, 0, 0, /* terminal */
0, 0, /* kill, load */
0, /* lookup_symbol */
- 0, 0, /* create_inferior, mourn_inferior */
+ 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 */
char *arg;
int from_tty;
{
- fputs_filtered ("Argument required (target name).\n", stdout);
+ fputs_filtered ("Argument required (target name). Try `help target'\n",
+ gdb_stdout);
}
/* Add a possible target architecture to the list. */
{
if (t->to_magic != OPS_MAGIC)
{
- fprintf(stderr, "Magic number of %s target struct wrong\n",
+ fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n",
t->to_shortname);
abort();
}
char *args;
int from_tty;
{
- printf("No saved terminal information.\n");
+ printf_unfiltered("No saved terminal information.\n");
}
#if 0
{
if (target_has_execution)
{
- printf ("You are already running a program:\n");
+ printf_unfiltered ("You are already running a program:\n");
target_files_info ();
if (query ("Kill it? ")) {
target_kill ();
the struct definition, but not all the places that initialize one. */
if (t->to_magic != OPS_MAGIC)
{
- fprintf(stderr, "Magic number of %s target struct wrong\n",
+ fprintf_unfiltered(gdb_stderr, "Magic number of %s target struct wrong\n",
t->to_shortname);
abort();
}
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_convert_to_virtual, host_convert_to_virtual);
- de_fault (to_convert_from_virtual, host_convert_from_virtual);
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_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);
{
(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
}
+#undef MIN
#define MIN(A, B) (((A) <= (B)) ? (A) : (B))
/* target_read_string -- read a null terminated string from MEMADDR in target.
return origlen;
}
-/* 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
- business with curlen: if an early target says "no, but I have a
- boundary overlapping this xfer" then we shorten what we offer to
- the subsequent targets so the early guy will get a chance at the
- tail before the subsequent ones do.
+/* Read LEN bytes of target memory at address MEMADDR, placing the results in
+ GDB's memory at MYADDR. Returns either 0 for success or an errno value
+ if any error occurs.
- Result is 0 or errno value. */
+ If an error occurs, no guarantee is made about the contents of the data at
+ MYADDR. In particular, the caller should not depend upon partial reads
+ filling the buffer with good data. There is no way for the caller to know
+ how much good data might have been transfered anyway. Callers that can
+ deal with partial reads should call target_read_memory_partial. */
int
target_read_memory (memaddr, myaddr, 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;
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
+ business with curlen: if an early target says "no, but I have a
+ boundary overlapping this xfer" then we shorten what we offer to
+ the subsequent targets so the early guy will get a chance at the
+ tail before the subsequent ones do.
+
+ Result is 0 or errno value. */
+
int
target_xfer_memory (memaddr, myaddr, len, write)
CORE_ADDR memaddr;
int curlen;
int res;
struct target_ops *t;
-
+
+ /* 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);
/* If this address is for nonexistent memory,
read zeros if reading, or do nothing if writing. Return error. */
if (!write)
- (void) memset (myaddr, 0, len);
+ memset (myaddr, 0, len);
if (errno == 0)
return EIO;
else
int has_all_mem = 0;
if (symfile_objfile != NULL)
- printf ("Symbols from \"%s\".\n", symfile_objfile->name);
+ printf_unfiltered ("Symbols from \"%s\".\n", symfile_objfile->name);
#ifdef FILES_INFO_HOOK
if (FILES_INFO_HOOK ())
if ((int)(t->to_stratum) <= (int)dummy_stratum)
continue;
if (has_all_mem)
- printf("\tWhile running this, gdb does not access memory from...\n");
- printf("%s:\n", t->to_longname);
+ 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;
}
}
}
+/* Detach a target after doing deferred register stores. */
+
+void
+target_detach (args, from_tty)
+ 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);
+}
+
+/* Look through the list of possible targets for a target that can
+ execute a run or attach command without any other data. This is
+ used to locate the default process stratum.
+
+ Result is always valid (error() is called for errors). */
+
+static struct target_ops *
+find_default_run_target (do_mesg)
+ char *do_mesg;
+{
+ 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 (target_can_run(*t))
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ if (count != 1)
+ error ("Don't know how to %s. Try \"help target\".", do_mesg);
+
+ return runable;
+}
+
+void
+find_default_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ struct target_ops *t;
+
+ 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;
+{
+ struct target_ops *t;
+
+ t = find_default_run_target("run");
+ (t->to_create_inferior) (exec_file, allargs, env);
+ return;
+}
+
+static int
+return_zero ()
+{
+ return 0;
+}
+
+struct target_ops *
+find_core_target ()
+{
+ 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_stratum == core_stratum)
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ return(count == 1 ? runable : NULL);
+}
+\f
+/* This table must match in order and size the signals in enum target_signal
+ in target.h. */
+static struct {
+ char *name;
+ char *string;
+ } signals [] =
+{
+ {"0", "Signal 0"},
+ {"SIGHUP", "Hangup"},
+ {"SIGINT", "Interrupt"},
+ {"SIGQUIT", "Quit"},
+ {"SIGILL", "Illegal instruction"},
+ {"SIGTRAP", "Trace/breakpoint trap"},
+ {"SIGABRT", "Aborted"},
+ {"SIGEMT", "Emulation trap"},
+ {"SIGFPE", "Arithmetic exception"},
+ {"SIGKILL", "Killed"},
+ {"SIGBUS", "Bus error"},
+ {"SIGSEGV", "Segmentation fault"},
+ {"SIGSYS", "Bad system call"},
+ {"SIGPIPE", "Broken pipe"},
+ {"SIGALRM", "Alarm clock"},
+ {"SIGTERM", "Terminated"},
+ {"SIGURG", "Urgent I/O condition"},
+ {"SIGSTOP", "Stopped (signal)"},
+ {"SIGTSTP", "Stopped (user)"},
+ {"SIGCONT", "Continued"},
+ {"SIGCHLD", "Child status changed"},
+ {"SIGTTIN", "Stopped (tty input)"},
+ {"SIGTTOU", "Stopped (tty output)"},
+ {"SIGIO", "I/O possible"},
+ {"SIGXCPU", "CPU time limit exceeded"},
+ {"SIGXFSZ", "File size limit exceeded"},
+ {"SIGVTALRM", "Virtual timer expired"},
+ {"SIGPROF", "Profiling timer expired"},
+ {"SIGWINCH", "Window size changed"},
+ {"SIGLOST", "Resource lost"},
+ {"SIGUSR1", "User defined signal 1"},
+ {"SIGUSR2", "User defined signal 2"},
+ {"SIGPWR", "Power fail/restart"},
+ {"SIGPOLL", "Pollable event occurred"},
+ {"SIGWIND", "SIGWIND"},
+ {"SIGPHONE", "SIGPHONE"},
+ {"SIGWAITING", "Process's LWPs are blocked"},
+ {"SIGLWP", "Signal LWP"},
+ {"SIGDANGER", "Swap space dangerously low"},
+ {"SIGGRANT", "Monitor mode granted"},
+ {"SIGRETRACT", "Need to relinguish monitor mode"},
+ {"SIGMSG", "Monitor mode data available"},
+ {"SIGSOUND", "Sound completed"},
+ {"SIGSAK", "Secure attention"},
+ {NULL, "Unknown signal"},
+ /* Last entry, used to check whether the table is the right size. */
+ {NULL, "TARGET_SIGNAL_MAGIC"}
+};
+
+/* Return the string for a signal. */
+char *
+target_signal_to_string (sig)
+ enum target_signal sig;
+{
+ return signals[sig].string;
+}
+
+/* Return the name for a signal. */
+char *
+target_signal_to_name (sig)
+ enum target_signal sig;
+{
+ if (sig == TARGET_SIGNAL_UNKNOWN)
+ /* I think the code which prints this will always print it along with
+ the string, so no need to be verbose. */
+ return "?";
+ return signals[sig].name;
+}
+
+/* Given a name, return its signal. */
+enum target_signal
+target_signal_from_name (name)
+ char *name;
+{
+ enum target_signal sig;
+
+ /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD"
+ for TARGET_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more
+ questionable; seems like by now people should call it SIGABRT
+ instead. */
+
+ for (sig = TARGET_SIGNAL_HUP; signals[sig].name != NULL; ++sig)
+ if (STREQ (name, signals[sig].name))
+ return sig;
+ return TARGET_SIGNAL_UNKNOWN;
+}
+\f
+/* Convert a normal process ID to a string. Returns the string in a static
+ buffer. */
+
+char *
+normal_pid_to_str (pid)
+ int pid;
+{
+ static char buf[30];
+
+ sprintf (buf, "process %d", pid);
+
+ return buf;
+}
+\f
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\
add_info ("target", target_info, targ_desc);
add_info ("files", target_info, targ_desc);
+
+ if (!STREQ (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC"))
+ abort ();
}