/* Select target systems and architectures at runtime for GDB.
- Copyright (C) 1990 Free Software Foundation, Inc.
+ Copyright 1990, 1992 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
-GDB is free software; you can redistribute it and/or modify
+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 1, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
-GDB is distributed in the hope that it will be useful,
+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 GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <stdio.h>
+#include "defs.h"
#include <errno.h>
#include <ctype.h>
-#include "defs.h"
#include "target.h"
#include "gdbcmd.h"
#include "symtab.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
+#include "objfiles.h"
+
+extern int errno;
+
+static void
+target_info PARAMS ((char *, int));
+
+static void
+cleanup_target PARAMS ((struct target_ops *));
+
+static void
+maybe_kill_then_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+maybe_kill_then_attach PARAMS ((char *, int));
+
+static void
+kill_or_be_killed PARAMS ((int));
+
+static void
+default_terminal_info PARAMS ((char *, int));
+
+static int
+nosymbol PARAMS ((char *, CORE_ADDR *));
+
+static void
+tcomplain PARAMS ((void));
+
+static int
+nomemory PARAMS ((CORE_ADDR, char *, int, int));
-extern int memory_insert_breakpoint(), memory_remove_breakpoint();
-extern void host_convert_to_virtual(), host_convert_from_virtual();
-extern void add_syms_addr_command();
+static int
+return_zero PARAMS ((void));
-static void cleanup_target ();
+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
/* The initial current target, so that there is always a semi-valid
current target. */
-struct target_ops dummy_target = {"None", "None",
- 0, 0, 0, 0, /* open, close, attach, detach */
+struct target_ops dummy_target = {"None", "None", "",
+ 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 */
- add_syms_addr_command, /* add_syms */
- 0, 0, /* call_function, lookup_symbol */
- 0, 0, /* create_inferior, mourn_inferior */
+ 0, /* lookup_symbol */
+ find_default_create_inferior, /* create_inferior */
+ 0, /* mourn_inferior */
+ 0, /* can_run */
dummy_stratum, 0, /* stratum, next */
0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* section pointers */
OPS_MAGIC,
};
struct target_ops **current_target_stack;
+/* Command list for target. */
+
+static struct cmd_list_element *targetlist = NULL;
+
+/* The user just typed 'target' without the name of a target. */
+
+/* ARGSUSED */
+static void
+target_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ fputs_filtered ("Argument required (target name). Try `help target'\n",
+ stdout);
+}
/* Add a possible target architecture to the list. */
if (target_struct_size >= target_struct_allocsize)
{
target_struct_allocsize *= 2;
- target_structs = (struct target_ops **) xrealloc (target_structs,
- target_struct_allocsize * sizeof (*target_structs));
+ target_structs = (struct target_ops **)
+ xrealloc ((char *) target_structs,
+ target_struct_allocsize * sizeof (*target_structs));
}
target_structs[target_struct_size++] = t;
cleanup_target (t);
+
+ if (targetlist == NULL)
+ add_prefix_cmd ("target", class_run, target_command,
+ "Connect to a target machine or process.\n\
+The first argument is the type or protocol of the target machine.\n\
+Remaining arguments are interpreted by the target protocol. For more\n\
+information on the arguments for a particular protocol, type\n\
+`help target ' followed by the protocol name.",
+ &targetlist, "target ", 0, &cmdlist);
+ add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist);
}
/* Stub functions */
int len;
int write;
{
+ errno = EIO; /* Can't read/write this location */
return 0; /* No bytes handled */
}
current_target->to_shortname);
}
-static int
+void
noprocess ()
{
error ("You can't do that without a process to debug");
}
+/* ARGSUSED */
static int
nosymbol (name, addrp)
char *name;
return 1; /* Symbol does not exist in target env */
}
+/* ARGSUSED */
static void
default_terminal_info (args, from_tty)
char *args;
kill_or_be_killed (from_tty)
int from_tty;
{
- struct target_ops *savecur;
-
if (target_has_execution)
{
printf ("You are already running a program:\n");
target_files_info ();
if (query ("Kill it? ")) {
- savecur = current_target;
- target_kill (0, from_tty);
+ target_kill ();
if (target_has_execution)
error ("Killing the program did not help.");
return;
/* FIELD DEFAULT VALUE */
- de_fault (to_open, tcomplain);
+ 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, noprocess);
- de_fault (to_fetch_registers, noprocess);
- de_fault (to_store_registers, 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_convert_to_virtual, host_convert_to_virtual);
- de_fault (to_convert_from_virtual, host_convert_from_virtual);
- de_fault (to_xfer_memory, nomemory);
- de_fault (to_files_info, ignore);
+ 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_ours, ignore);
de_fault (to_terminal_info, default_terminal_info);
de_fault (to_kill, (void (*)())noprocess);
- de_fault (to_load, tcomplain);
- de_fault (to_add_syms, tcomplain);
- de_fault (to_call_function, (struct value *(*)())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_next, 0);
de_fault (to_has_all_memory, 0);
de_fault (to_has_memory, 0);
push_target (&dummy_target);
}
-/* Print things about the whole set of targets and about the
- current target stack. */
-static void
-targets_info ()
+#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.
+*/
+
+int
+target_read_string (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
{
- int i;
+ int tlen, origlen, offset, i;
+ char buf[4];
- printf("Possible targets:\n\n");
- for (i = 0; i < target_struct_size; i++)
- printf ("%-15s %s\n",
- target_structs[i]->to_shortname,
- target_structs[i]->to_longname);
+ origlen = len;
+
+ while (len > 0)
+ {
+ tlen = MIN (len, 4 - (memaddr & 3));
+ offset = memaddr & 3;
+
+ if (target_xfer_memory (memaddr & ~3, buf, 4, 0))
+ return origlen - len;
+
+ for (i = 0; i < tlen; i++)
+ {
+ *myaddr++ = buf[i + offset];
+ if (buf[i + offset] == '\000')
+ return (origlen - len) + i + 1;
+ }
+
+ memaddr += tlen;
+ len -= tlen;
+ }
+ return origlen;
}
/* Move memory to or from the targets. Iterate until all of it has
struct target_ops *t;
/* The quick case is that the top target does it all. */
- res = current_target->to_xfer_memory(memaddr, myaddr, len, write);
+ res = current_target->to_xfer_memory
+ (memaddr, myaddr, len, write, current_target);
if (res == len)
return 0;
t;
t = t->to_has_all_memory? 0: t->to_next)
{
- res = t->to_xfer_memory(memaddr, myaddr, curlen, write);
+ 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 */
/* If this address is for nonexistent memory,
read zeros if reading, or do nothing if writing. Return error. */
if (!write)
- bzero (myaddr, len);
- return EIO;
+ memset (myaddr, 0, len);
+ if (errno == 0)
+ return EIO;
+ else
+ return errno;
}
bump:
memaddr += res;
}
+/* ARGSUSED */
static void
target_info (args, from_tty)
char *args;
struct target_ops *t;
int has_all_mem = 0;
- if (symfile != 0)
- printf ("Symbols from \"%s\".\n", symfile);
+ if (symfile_objfile != NULL)
+ printf ("Symbols from \"%s\".\n", symfile_objfile->name);
#ifdef FILES_INFO_HOOK
if (FILES_INFO_HOOK ())
if (has_all_mem)
printf("\tWhile running this, gdb does not access memory from...\n");
printf("%s:\n", t->to_longname);
- (t->to_files_info)();
+ (t->to_files_info)(t);
has_all_mem = t->to_has_all_memory;
}
}
-/* The target command selects a target and calls its open routine.
- The open routine takes the rest of the parameters from the command,
- and (if successful) pushes a new target onto the stack. */
+/* This is to be called by the open routine before it does
+ anything. */
-static void
-target_command (args, from_tty)
- char *args;
+void
+target_preopen (from_tty)
int from_tty;
{
- int i, possible;
- char *rest;
- char *argend;
-
dont_repeat();
- if (!args)
- error (
- "Argument required (target name). `info targets' lists possible targets");
-
if (target_has_execution)
{
if (query ("A program is being debugged already. Kill it? "))
- target_kill ((char *)0, from_tty);
+ target_kill ();
else
error ("Program not killed.");
}
-
- /* Skip to first space, or end of args */
- for (rest = args; *rest && !isspace(*rest); rest++) ;
- argend = rest;
- if (*rest == '\0')
- rest = 0; /* Only one word in args */
- else
- {
- for (rest++; isspace (*rest); rest++) ;
- if (*rest == '\0') /* Only one word w/trailing blanks */
- rest = 0;
- }
+}
- /* Search target list for a match */
+/* 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.
- possible = -1;
- for (i = 0; i < target_struct_size; i++)
+ 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;
+ int count;
+
+ count = 0;
+
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
{
- if (!strncmp (args, target_structs[i]->to_shortname, argend - args)) {
- /* If we have an exact match, it's time to quit. */
- if (target_structs[i]->to_shortname[args-argend] == '\0') {
- possible = i;
- break;
+ if (target_can_run(*t))
+ {
+ runable = *t;
+ ++count;
}
- if (possible > 0)
- error ("Ambiguous target. `info targets' will list all targets");
- possible = i;
- }
}
- if (possible < 0)
- error ("No such target. `info targets' will list all targets");
- (*target_structs[possible]->to_open) (rest, from_tty);
+ 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;
}
static char targ_desc[] =
current_target = &dummy_target;
cleanup_target (current_target);
- add_info ("targets", targets_info,
- "Names of all possible targets.\n\
-A target is typically a protocol for talking to debugging facilities;\n\
-for example, `child' for Unix child processes, or `vxworks' for a\n\
-TCP/IP link to a VxWorks system.");
-
add_info ("target", target_info, targ_desc);
add_info ("files", target_info, targ_desc);
-
- add_com ("target", class_run, target_command,
-"Connect to a target machine or process.\n\
-The first argument is the type or protocol of the target machine. Remaining\n\
-arguments are interpreted by the target protocol, but typically include\n\
-things like device names or host names to connect with, process numbers,\n\
-baud rates, etc. You can list all possible targets with the `info targets'\n\
-command.");
}