xref: /openbsd-src/gnu/usr.bin/binutils/gdb/remote-vx.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /* Memory-access and commands for remote VxWorks processes, for GDB.
2    Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3    Contributed by Wind River Systems and Cygnus Support.
4 
5 This file is part of GDB.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20 
21 #include "defs.h"
22 #include "frame.h"
23 #include "inferior.h"
24 #include "wait.h"
25 #include "target.h"
26 #include "gdbcore.h"
27 #include "command.h"
28 #include "symtab.h"
29 #include "complaints.h"
30 #include "gdbcmd.h"
31 #include "bfd.h" /* Required by objfiles.h.  */
32 #include "symfile.h" /* Required by objfiles.h.  */
33 #include "objfiles.h"
34 #include "gdb-stabs.h"
35 
36 #include "gdb_string.h"
37 #include <errno.h>
38 #include <signal.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #define malloc bogon_malloc	/* Sun claims "char *malloc()" not void * */
43 #define free bogon_free		/* Sun claims "int free()" not void */
44 #define realloc bogon_realloc	/* Sun claims "char *realloc()", not void * */
45 #include <rpc/rpc.h>
46 #undef malloc
47 #undef free
48 #undef realloc
49 #include <sys/time.h>		/* UTek's <rpc/rpc.h> doesn't #incl this */
50 #include <netdb.h>
51 #include "vx-share/ptrace.h"
52 #include "vx-share/xdr_ptrace.h"
53 #include "vx-share/xdr_ld.h"
54 #include "vx-share/xdr_rdb.h"
55 #include "vx-share/dbgRpcLib.h"
56 
57 #include <symtab.h>
58 
59 /* Maximum number of bytes to transfer in a single
60    PTRACE_{READ,WRITE}DATA request.  */
61 #define VX_MEMXFER_MAX 4096
62 
63 extern void vx_read_register ();
64 extern void vx_write_register ();
65 extern void symbol_file_command ();
66 extern int stop_soon_quietly;		/* for wait_for_inferior */
67 
68 static int net_step ();
69 static int net_ptrace_clnt_call ();	/* Forward decl */
70 static enum clnt_stat net_clnt_call ();	/* Forward decl */
71 extern struct target_ops vx_ops, vx_run_ops;	/* Forward declaration */
72 
73 /* Saved name of target host and called function for "info files".
74    Both malloc'd.  */
75 
76 static char *vx_host;
77 static char *vx_running;		/* Called function */
78 
79 /* Nonzero means target that is being debugged remotely has a floating
80    point processor.  */
81 
82 int target_has_fp;
83 
84 /* Default error message when the network is forking up.  */
85 
86 static const char rpcerr[] = "network target debugging:  rpc error";
87 
88 CLIENT *pClient;         /* client used in net debugging */
89 static int ptraceSock = RPC_ANYSOCK;
90 
91 enum clnt_stat net_clnt_call();
92 static void parse_args ();
93 
94 static struct timeval rpcTimeout = { 10, 0 };
95 
96 static char *skip_white_space ();
97 static char *find_white_space ();
98 
99 /* Tell the VxWorks target system to download a file.
100    The load addresses of the text, data, and bss segments are
101    stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively).
102    Returns 0 for success, -1 for failure.  */
103 
104 static int
105 net_load (filename, pTextAddr, pDataAddr, pBssAddr)
106      char *filename;
107      CORE_ADDR *pTextAddr;
108      CORE_ADDR *pDataAddr;
109      CORE_ADDR *pBssAddr;
110 {
111   enum clnt_stat status;
112   struct ldfile ldstruct;
113   struct timeval load_timeout;
114 
115   memset ((char *) &ldstruct, '\0', sizeof (ldstruct));
116 
117   /* We invoke clnt_call () here directly, instead of through
118      net_clnt_call (), because we need to set a large timeout value.
119      The load on the target side can take quite a while, easily
120      more than 10 seconds.  The user can kill this call by typing
121      CTRL-C if there really is a problem with the load.
122 
123      Do not change the tv_sec value without checking -- select() imposes
124      a limit of 10**8 on it for no good reason that I can see...  */
125 
126   load_timeout.tv_sec = 99999999;   /* A large number, effectively inf. */
127   load_timeout.tv_usec = 0;
128 
129   status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
130 		      &ldstruct, load_timeout);
131 
132   if (status == RPC_SUCCESS)
133     {
134       if (*ldstruct.name == 0)	/* load failed on VxWorks side */
135 	return -1;
136       *pTextAddr = ldstruct.txt_addr;
137       *pDataAddr = ldstruct.data_addr;
138       *pBssAddr = ldstruct.bss_addr;
139       return 0;
140     }
141   else
142     return -1;
143 }
144 
145 /* returns 0 if successful, errno if RPC failed or VxWorks complains. */
146 
147 static int
148 net_break (addr, procnum)
149      int addr;
150      u_long procnum;
151 {
152   enum clnt_stat status;
153   int break_status;
154   Rptrace ptrace_in;  /* XXX This is stupid.  It doesn't need to be a ptrace
155 			 structure.  How about something smaller? */
156 
157   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
158   break_status = 0;
159 
160   ptrace_in.addr = addr;
161   ptrace_in.pid = inferior_pid;
162 
163   status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
164 			  &break_status);
165 
166   if (status != RPC_SUCCESS)
167       return errno;
168 
169   if (break_status == -1)
170     return ENOMEM;
171   return break_status;	/* probably (FIXME) zero */
172 }
173 
174 /* returns 0 if successful, errno otherwise */
175 
176 static int
177 vx_insert_breakpoint (addr)
178      int addr;
179 {
180   return net_break (addr, VX_BREAK_ADD);
181 }
182 
183 /* returns 0 if successful, errno otherwise */
184 
185 static int
186 vx_remove_breakpoint (addr)
187      int addr;
188 {
189   return net_break (addr, VX_BREAK_DELETE);
190 }
191 
192 /* Start an inferior process and sets inferior_pid to its pid.
193    EXEC_FILE is the file to run.
194    ALLARGS is a string containing the arguments to the program.
195    ENV is the environment vector to pass.
196    Returns process id.  Errors reported with error().
197    On VxWorks, we ignore exec_file.  */
198 
199 static void
200 vx_create_inferior (exec_file, args, env)
201      char *exec_file;
202      char *args;
203      char **env;
204 {
205   enum clnt_stat status;
206   arg_array passArgs;
207   TASK_START taskStart;
208 
209   memset ((char *) &passArgs, '\0', sizeof (passArgs));
210   memset ((char *) &taskStart, '\0', sizeof (taskStart));
211 
212   /* parse arguments, put them in passArgs */
213 
214   parse_args (args, &passArgs);
215 
216   if (passArgs.arg_array_len == 0)
217     error ("You must specify a function name to run, and arguments if any");
218 
219   status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
220 			  xdr_TASK_START, &taskStart);
221 
222   if ((status != RPC_SUCCESS) || (taskStart.status == -1))
223     error ("Can't create process on remote target machine");
224 
225   /* Save the name of the running function */
226   vx_running = savestring (passArgs.arg_array_val[0],
227 			   strlen (passArgs.arg_array_val[0]));
228 
229   push_target (&vx_run_ops);
230   inferior_pid = taskStart.pid;
231 
232   /* We will get a trace trap after one instruction.
233      Insert breakpoints and continue.  */
234 
235   init_wait_for_inferior ();
236 
237   /* Set up the "saved terminal modes" of the inferior
238      based on what modes we are starting it with.  */
239   target_terminal_init ();
240 
241   /* Install inferior's terminal modes.  */
242   target_terminal_inferior ();
243 
244   stop_soon_quietly = 1;
245   wait_for_inferior ();		/* Get the task spawn event */
246   stop_soon_quietly = 0;
247 
248   /* insert_step_breakpoint ();  FIXME, do we need this?  */
249   proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
250 }
251 
252 /* Fill ARGSTRUCT in argc/argv form with the arguments from the
253    argument string ARGSTRING.  */
254 
255 static void
256 parse_args (arg_string, arg_struct)
257      register char *arg_string;
258      arg_array *arg_struct;
259 {
260   register int arg_count = 0;	/* number of arguments */
261   register int arg_index = 0;
262   register char *p0;
263 
264   memset ((char *) arg_struct, '\0', sizeof (arg_array));
265 
266   /* first count how many arguments there are */
267 
268   p0 = arg_string;
269   while (*p0 != '\0')
270     {
271       if (*(p0 = skip_white_space (p0)) == '\0')
272 	break;
273       p0 = find_white_space (p0);
274       arg_count++;
275     }
276 
277   arg_struct->arg_array_len = arg_count;
278   arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
279 						 * sizeof (char *));
280 
281   /* now copy argument strings into arg_struct.  */
282 
283   while (*(arg_string = skip_white_space (arg_string)))
284     {
285       p0 = find_white_space (arg_string);
286       arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
287 							   p0 - arg_string);
288       arg_string = p0;
289     }
290 
291   arg_struct->arg_array_val[arg_count] = NULL;
292 }
293 
294 /* Advance a string pointer across whitespace and return a pointer
295    to the first non-white character.  */
296 
297 static char *
298 skip_white_space (p)
299      register char *p;
300 {
301   while (*p == ' ' || *p == '\t')
302     p++;
303   return p;
304 }
305 
306 /* Search for the first unquoted whitespace character in a string.
307    Returns a pointer to the character, or to the null terminator
308    if no whitespace is found.  */
309 
310 static char *
311 find_white_space (p)
312      register char *p;
313 {
314   register int c;
315 
316   while ((c = *p) != ' ' && c != '\t' && c)
317     {
318       if (c == '\'' || c == '"')
319 	{
320 	  while (*++p != c && *p)
321 	    {
322 	      if (*p == '\\')
323 		p++;
324 	    }
325 	  if (!*p)
326 	    break;
327 	}
328       p++;
329     }
330   return p;
331 }
332 
333 /* Poll the VxWorks target system for an event related
334    to the debugged task.
335    Returns -1 if remote wait failed, task status otherwise.  */
336 
337 static int
338 net_wait (pEvent)
339     RDB_EVENT *pEvent;
340 {
341     int pid;
342     enum clnt_stat status;
343 
344     memset ((char *) pEvent, '\0', sizeof (RDB_EVENT));
345 
346     pid = inferior_pid;
347     status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT,
348 			    pEvent);
349 
350     /* return (status == RPC_SUCCESS)? pEvent->status: -1; */
351     if (status == RPC_SUCCESS)
352       return ((pEvent->status) ? 1 : 0);
353     else if (status == RPC_TIMEDOUT)
354       return (1);
355     else
356       return (-1);
357 }
358 
359 /* Suspend the remote task.
360    Returns -1 if suspend fails on target system, 0 otherwise.  */
361 
362 static int
363 net_quit ()
364 {
365   int pid;
366   int quit_status;
367   enum clnt_stat status;
368 
369   quit_status = 0;
370 
371   /* don't let rdbTask suspend itself by passing a pid of 0 */
372 
373   if ((pid = inferior_pid) == 0)
374     return -1;
375 
376   status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
377 			  &quit_status);
378 
379   return (status == RPC_SUCCESS)? quit_status: -1;
380 }
381 
382 /* Read a register or registers from the remote system.  */
383 
384 void
385 net_read_registers (reg_buf, len, procnum)
386      char *reg_buf;
387      int len;
388      u_long procnum;
389 {
390   int status;
391   Rptrace ptrace_in;
392   Ptrace_return ptrace_out;
393   C_bytes out_data;
394   char message[100];
395 
396   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
397   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
398 
399   /* Initialize RPC input argument structure.  */
400 
401   ptrace_in.pid = inferior_pid;
402   ptrace_in.info.ttype = NOINFO;
403 
404   /* Initialize RPC return value structure.  */
405 
406   out_data.bytes = reg_buf;
407   out_data.len = len;
408   ptrace_out.info.more_data = (caddr_t) &out_data;
409 
410   /* Call RPC; take an error exit if appropriate.  */
411 
412   status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
413   if (status)
414     error (rpcerr);
415   if (ptrace_out.status == -1)
416     {
417       errno = ptrace_out.errno;
418       sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS)
419 						 ? "general-purpose"
420 						 : "floating-point");
421       perror_with_name (message);
422     }
423 }
424 
425 /* Write register values to a VxWorks target.  REG_BUF points to a buffer
426    containing the raw register values, LEN is the length of REG_BUF in
427    bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or
428    PTRACE_SETFPREGS).  An error exit is taken if the RPC call fails or
429    if an error status is returned by the remote debug server.  This is
430    a utility routine used by vx_write_register ().  */
431 
432 void
433 net_write_registers (reg_buf, len, procnum)
434      char *reg_buf;
435      int len;
436      u_long procnum;
437 {
438   int status;
439   Rptrace ptrace_in;
440   Ptrace_return ptrace_out;
441   C_bytes in_data;
442   char message[100];
443 
444   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
445   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
446 
447   /* Initialize RPC input argument structure.  */
448 
449   in_data.bytes = reg_buf;
450   in_data.len = len;
451 
452   ptrace_in.pid = inferior_pid;
453   ptrace_in.info.ttype = DATA;
454   ptrace_in.info.more_data = (caddr_t) &in_data;
455 
456   /* Call RPC; take an error exit if appropriate.  */
457 
458   status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
459   if (status)
460     error (rpcerr);
461   if (ptrace_out.status == -1)
462     {
463       errno = ptrace_out.errno;
464       sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS)
465 						 ? "general-purpose"
466 						 : "floating-point");
467       perror_with_name (message);
468     }
469 }
470 
471 /* Prepare to store registers.  Since we will store all of them,
472    read out their current values now.  */
473 
474 static void
475 vx_prepare_to_store ()
476 {
477   /* Fetch all registers, if any of them are not yet fetched.  */
478   read_register_bytes (0, NULL, REGISTER_BYTES);
479 }
480 
481 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
482    to debugger memory starting at MYADDR.  WRITE is true if writing to the
483    inferior.
484    Result is the number of bytes written or read (zero if error).  The
485    protocol allows us to return a negative count, indicating that we can't
486    handle the current address but can handle one N bytes further, but
487    vxworks doesn't give us that information.  */
488 
489 static int
490 vx_xfer_memory (memaddr, myaddr, len, write, target)
491      CORE_ADDR memaddr;
492      char *myaddr;
493      int len;
494      int write;
495      struct target_ops *target;			/* ignored */
496 {
497   int status;
498   Rptrace ptrace_in;
499   Ptrace_return ptrace_out;
500   C_bytes data;
501   enum ptracereq request;
502   int nleft, nxfer;
503 
504   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
505   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
506 
507   ptrace_in.pid = inferior_pid;		/* XXX pid unnecessary for READDATA */
508   ptrace_in.addr = (int) memaddr;	/* Where from */
509   ptrace_in.data = len;			/* How many bytes */
510 
511   if (write)
512     {
513       ptrace_in.info.ttype     = DATA;
514       ptrace_in.info.more_data = (caddr_t) &data;
515 
516       data.bytes = (caddr_t) myaddr;	/* Where from */
517       data.len   = len;			/* How many bytes (again, for XDR) */
518       request = PTRACE_WRITEDATA;
519     }
520   else
521     {
522       ptrace_out.info.more_data = (caddr_t) &data;
523       request = PTRACE_READDATA;
524     }
525   /* Loop until the entire request has been satisfied, transferring
526      at most VX_MEMXFER_MAX bytes per iteration.  Break from the loop
527      if an error status is returned by the remote debug server.  */
528 
529   nleft = len;
530   status = 0;
531 
532   while (nleft > 0 && status == 0)
533     {
534       nxfer = min (nleft, VX_MEMXFER_MAX);
535 
536       ptrace_in.addr = (int) memaddr;
537       ptrace_in.data = nxfer;
538       data.bytes = (caddr_t) myaddr;
539       data.len = nxfer;
540 
541       /* Request a block from the remote debug server; if RPC fails,
542          report an error and return to debugger command level.  */
543 
544       if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out))
545         error (rpcerr);
546 
547       status = ptrace_out.status;
548       if (status == 0)
549         {
550           memaddr += nxfer;
551           myaddr += nxfer;
552           nleft -= nxfer;
553         }
554       else
555         {
556           /* A target-side error has ocurred.  Set errno to the error
557              code chosen by the target so that a later perror () will
558              say something meaningful.  */
559 
560           errno = ptrace_out.errno;
561         }
562     }
563 
564   /* Return the number of bytes transferred.  */
565 
566   return (len - nleft);
567 }
568 
569 static void
570 vx_files_info ()
571 {
572   printf_unfiltered ("\tAttached to host `%s'", vx_host);
573   printf_unfiltered (", which has %sfloating point", target_has_fp? "": "no ");
574   printf_unfiltered (".\n");
575 }
576 
577 static void
578 vx_run_files_info ()
579 {
580   printf_unfiltered ("\tRunning %s VxWorks process %s",
581 		     vx_running ? "child" : "attached",
582 		     local_hex_string (inferior_pid));
583   if (vx_running)
584     printf_unfiltered (", function `%s'", vx_running);
585   printf_unfiltered(".\n");
586 }
587 
588 static void
589 vx_resume (pid, step, siggnal)
590      int pid;
591      int step;
592      enum target_signal siggnal;
593 {
594   int status;
595   Rptrace ptrace_in;
596   Ptrace_return ptrace_out;
597   CORE_ADDR cont_addr;
598 
599   if (pid == -1)
600     pid = inferior_pid;
601 
602   if (siggnal != 0 && siggnal != stop_signal)
603     error ("Cannot send signals to VxWorks processes");
604 
605   /* Set CONT_ADDR to the address at which we are continuing,
606      or to 1 if we are continuing from where the program stopped.
607      This conforms to traditional ptrace () usage, but at the same
608      time has special meaning for the VxWorks remote debug server.
609      If the address is not 1, the server knows that the target
610      program is jumping to a new address, which requires special
611      handling if there is a breakpoint at the new address.  */
612 
613   cont_addr = read_register (PC_REGNUM);
614   if (cont_addr == stop_pc)
615     cont_addr = 1;
616 
617   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
618   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
619 
620   ptrace_in.pid = pid;
621   ptrace_in.addr = cont_addr; /* Target side insists on this, or it panics.  */
622 
623   if (step)
624     status = net_step();
625   else
626     status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out);
627 
628   if (status)
629     error (rpcerr);
630   if (ptrace_out.status == -1)
631     {
632       errno = ptrace_out.errno;
633       perror_with_name ("Resuming remote process");
634     }
635 }
636 
637 static void
638 vx_mourn_inferior ()
639 {
640   pop_target ();		/* Pop back to no-child state */
641   generic_mourn_inferior ();
642 }
643 
644 
645 static void vx_add_symbols PARAMS ((char *, int, CORE_ADDR, CORE_ADDR,
646 				    CORE_ADDR));
647 
648 struct find_sect_args {
649   CORE_ADDR text_start;
650   CORE_ADDR data_start;
651   CORE_ADDR bss_start;
652 };
653 
654 static void find_sect PARAMS ((bfd *, asection *, void *));
655 
656 static void
657 find_sect (abfd, sect, obj)
658      bfd *abfd;
659      asection *sect;
660      PTR obj;
661 {
662   struct find_sect_args *args = (struct find_sect_args *)obj;
663 
664   if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY))
665     args->text_start = bfd_get_section_vma (abfd, sect);
666   else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC)
667     {
668       if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
669 	{
670 	  /* Exclude .ctor and .dtor sections which have SEC_CODE set but not
671 	     SEC_DATA.  */
672 	  if (bfd_get_section_flags (abfd, sect) & SEC_DATA)
673 	    args->data_start = bfd_get_section_vma (abfd, sect);
674 	}
675       else
676 	args->bss_start = bfd_get_section_vma (abfd, sect);
677     }
678 }
679 
680 static void
681 vx_add_symbols (name, from_tty, text_addr, data_addr, bss_addr)
682      char *name;
683      int from_tty;
684      CORE_ADDR text_addr;
685      CORE_ADDR data_addr;
686      CORE_ADDR bss_addr;
687 {
688   struct section_offsets *offs;
689   struct objfile *objfile;
690   struct find_sect_args ss;
691 
692   /* It might be nice to suppress the breakpoint_re_set which happens here
693      because we are going to do one again after the objfile_relocate.  */
694   objfile = symbol_file_add (name, from_tty, 0, 0, 0, 0);
695 
696   /* This is a (slightly cheesy) way of superceding the old symbols.  A less
697      cheesy way would be to find the objfile with the same name and
698      free_objfile it.  */
699   objfile_to_front (objfile);
700 
701   offs = (struct section_offsets *)
702     alloca (sizeof (struct section_offsets)
703 	    + objfile->num_sections * sizeof (offs->offsets));
704   memcpy (offs, objfile->section_offsets,
705 	  sizeof (struct section_offsets)
706 	  + objfile->num_sections * sizeof (offs->offsets));
707 
708   ss.text_start = 0;
709   ss.data_start = 0;
710   ss.bss_start = 0;
711   bfd_map_over_sections (objfile->obfd, find_sect, &ss);
712 
713   /* Both COFF and b.out frontends use these SECT_OFF_* values.  */
714   ANOFFSET (offs, SECT_OFF_TEXT) = text_addr - ss.text_start;
715   ANOFFSET (offs, SECT_OFF_DATA) = data_addr - ss.data_start;
716   ANOFFSET (offs, SECT_OFF_BSS) = bss_addr - ss.bss_start;
717   objfile_relocate (objfile, offs);
718 
719   /* Need to do this *after* things are relocated.  */
720   breakpoint_re_set ();
721 }
722 
723 /* This function allows the addition of incrementally linked object files.  */
724 
725 static void
726 vx_load_command (arg_string, from_tty)
727      char *arg_string;
728      int from_tty;
729 {
730   CORE_ADDR text_addr;
731   CORE_ADDR data_addr;
732   CORE_ADDR bss_addr;
733 
734   if (arg_string == 0)
735     error ("The load command takes a file name");
736 
737   arg_string = tilde_expand (arg_string);
738   make_cleanup (free, arg_string);
739 
740   dont_repeat ();
741 
742   /* Refuse to load the module if a debugged task is running.  Doing so
743      can have a number of unpleasant consequences to the running task.  */
744 
745   if (inferior_pid != 0 && target_has_execution)
746     {
747       if (query ("You may not load a module while the target task is running.\n\
748 Kill the target task? "))
749         target_kill ();
750       else
751         error ("Load cancelled.");
752     }
753 
754   QUIT;
755   immediate_quit++;
756   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
757     error ("Load failed on target machine");
758   immediate_quit--;
759 
760   vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
761 
762   /* Getting new symbols may change our opinion about what is
763      frameless.  */
764   reinit_frame_cache ();
765 }
766 
767 /* Single step the target program at the source or machine level.
768    Takes an error exit if rpc fails.
769    Returns -1 if remote single-step operation fails, else 0.  */
770 
771 static int
772 net_step ()
773 {
774   enum clnt_stat status;
775   int step_status;
776   SOURCE_STEP source_step;
777 
778   source_step.taskId = inferior_pid;
779 
780   if (step_range_end)
781     {
782       source_step.startAddr = step_range_start;
783       source_step.endAddr = step_range_end;
784     }
785   else
786     {
787       source_step.startAddr = 0;
788       source_step.endAddr = 0;
789     }
790 
791   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
792 			  xdr_int, &step_status);
793 
794   if (status == RPC_SUCCESS)
795     return step_status;
796   else
797     error (rpcerr);
798 }
799 
800 /* Emulate ptrace using RPC calls to the VxWorks target system.
801    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
802 
803 static int
804 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
805     enum ptracereq request;
806     Rptrace *pPtraceIn;
807     Ptrace_return *pPtraceOut;
808 {
809   enum clnt_stat status;
810 
811   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
812 			  pPtraceOut);
813 
814   if (status != RPC_SUCCESS)
815       return -1;
816 
817   return 0;
818 }
819 
820 /* Query the target for the name of the file from which VxWorks was
821    booted.  pBootFile is the address of a pointer to the buffer to
822    receive the file name; if the pointer pointed to by pBootFile is
823    NULL, memory for the buffer will be allocated by XDR.
824    Returns -1 if rpc failed, 0 otherwise.  */
825 
826 static int
827 net_get_boot_file (pBootFile)
828      char **pBootFile;
829 {
830   enum clnt_stat status;
831 
832   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
833 			  xdr_wrapstring, pBootFile);
834   return (status == RPC_SUCCESS) ? 0 : -1;
835 }
836 
837 /* Fetch a list of loaded object modules from the VxWorks target.
838    Returns -1 if rpc failed, 0 otherwise
839    There's no way to check if the returned loadTable is correct.
840    VxWorks doesn't check it.  */
841 
842 static int
843 net_get_symbols (pLoadTable)
844      ldtabl *pLoadTable;		/* return pointer to ldtabl here */
845 {
846   enum clnt_stat status;
847 
848   memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
849 
850   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
851   return (status == RPC_SUCCESS) ? 0 : -1;
852 }
853 
854 /* Look up a symbol in the VxWorks target's symbol table.
855    Returns status of symbol read on target side (0=success, -1=fail)
856    Returns -1 and complain()s if rpc fails.  */
857 
858 struct complaint cant_contact_target =
859   {"Lost contact with VxWorks target", 0, 0};
860 
861 static int
862 vx_lookup_symbol (name, pAddr)
863      char *name;		/* symbol name */
864      CORE_ADDR *pAddr;
865 {
866   enum clnt_stat status;
867   SYMBOL_ADDR symbolAddr;
868 
869   *pAddr = 0;
870   memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
871 
872   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
873 			  xdr_SYMBOL_ADDR, &symbolAddr);
874   if (status != RPC_SUCCESS)
875     {
876       complain (&cant_contact_target);
877       return -1;
878     }
879 
880   *pAddr = symbolAddr.addr;
881   return symbolAddr.status;
882 }
883 
884 /* Check to see if the VxWorks target has a floating point coprocessor.
885    Returns 1 if target has floating point processor, 0 otherwise.
886    Calls error() if rpc fails.  */
887 
888 static int
889 net_check_for_fp ()
890 {
891   enum clnt_stat status;
892   bool_t fp = 0;	/* true if fp processor is present on target board */
893 
894   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
895   if (status != RPC_SUCCESS)
896     error (rpcerr);
897 
898    return (int) fp;
899 }
900 
901 /* Establish an RPC connection with the VxWorks target system.
902    Calls error () if unable to establish connection.  */
903 
904 static void
905 net_connect (host)
906      char *host;
907 {
908   struct sockaddr_in destAddr;
909   struct hostent *destHost;
910   unsigned long addr;
911 
912   /* Get the internet address for the given host.  Allow a numeric
913      IP address or a hostname.  */
914 
915   addr = inet_addr (host);
916   if (addr == -1)
917     {
918       destHost = (struct hostent *) gethostbyname (host);
919       if (destHost == NULL)
920 	/* FIXME: Probably should include hostname here in quotes.
921 	   For example if the user types "target vxworks vx960 " it should
922 	   say "Invalid host `vx960 '." not just "Invalid hostname".  */
923 	error ("Invalid hostname.  Couldn't find remote host address.");
924       addr = * (unsigned long *) destHost->h_addr;
925     }
926 
927   memset (&destAddr, '\0', sizeof (destAddr));
928 
929   destAddr.sin_addr.s_addr = addr;
930   destAddr.sin_family      = AF_INET;
931   destAddr.sin_port        = 0;	/* set to actual port that remote
932 			           ptrace is listening on.  */
933 
934   /* Create a tcp client transport on which to issue
935      calls to the remote ptrace server.  */
936 
937   ptraceSock = RPC_ANYSOCK;
938   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
939   /* FIXME, here is where we deal with different version numbers of the
940      proto */
941 
942   if (pClient == NULL)
943     {
944       clnt_pcreateerror ("\tnet_connect");
945       error ("Couldn't connect to remote target.");
946     }
947 }
948 
949 /* Sleep for the specified number of milliseconds
950  * (assumed to be less than 1000).
951  * If select () is interrupted, returns immediately;
952  * takes an error exit if select () fails for some other reason.
953  */
954 
955 static void
956 sleep_ms (ms)
957      long ms;
958 {
959   struct timeval select_timeout;
960   int status;
961 
962   select_timeout.tv_sec = 0;
963   select_timeout.tv_usec = ms * 1000;
964 
965   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
966 		   &select_timeout);
967 
968   if (status < 0 && errno != EINTR)
969     perror_with_name ("select");
970 }
971 
972 static int
973 vx_wait (pid_to_wait_for, status)
974      int pid_to_wait_for;
975      struct target_waitstatus *status;
976 {
977   register int pid;
978   RDB_EVENT rdbEvent;
979   int quit_failed;
980 
981   do
982     {
983       /* If CTRL-C is hit during this loop,
984 	 suspend the inferior process.  */
985 
986       quit_failed = 0;
987       if (quit_flag)
988 	{
989 	  quit_failed = (net_quit () == -1);
990 	  quit_flag = 0;
991 	}
992 
993       /* If a net_quit () or net_wait () call has failed,
994 	 allow the user to break the connection with the target.
995 	 We can't simply error () out of this loop, since the
996 	 data structures representing the state of the inferior
997 	 are in an inconsistent state.  */
998 
999       if (quit_failed || net_wait (&rdbEvent) == -1)
1000 	{
1001 	  terminal_ours ();
1002 	  if (query ("Can't %s.  Disconnect from target system? ",
1003 		     (quit_failed) ? "suspend remote task"
1004 		                   : "get status of remote task"))
1005 	    {
1006 	      target_mourn_inferior();
1007 	      error ("Use the \"target\" command to reconnect.");
1008 	    }
1009 	  else
1010 	    {
1011 	      terminal_inferior ();
1012 	      continue;
1013 	    }
1014 	}
1015 
1016       pid = rdbEvent.taskId;
1017       if (pid == 0)
1018 	{
1019 	  sleep_ms (200);	/* FIXME Don't kill the network too badly */
1020 	}
1021       else if (pid != inferior_pid)
1022 	fatal ("Bad pid for debugged task: %s\n",
1023 	       local_hex_string((unsigned long) pid));
1024     } while (pid == 0);
1025 
1026   /* The mostly likely kind.  */
1027   status->kind = TARGET_WAITKIND_STOPPED;
1028 
1029   switch (rdbEvent.eventType)
1030     {
1031     case EVENT_EXIT:
1032       status->kind = TARGET_WAITKIND_EXITED;
1033       /* FIXME is it possible to distinguish between a
1034 	 normal vs abnormal exit in VxWorks? */
1035       status->value.integer = 0;
1036       break;
1037 
1038     case EVENT_START:
1039       /* Task was just started. */
1040       status->value.sig = TARGET_SIGNAL_TRAP;
1041       break;
1042 
1043     case EVENT_STOP:
1044       status->value.sig = TARGET_SIGNAL_TRAP;
1045       /* XXX was it stopped by a signal?  act accordingly */
1046       break;
1047 
1048     case EVENT_BREAK:		/* Breakpoint was hit. */
1049       status->value.sig = TARGET_SIGNAL_TRAP;
1050       break;
1051 
1052     case EVENT_SUSPEND:		/* Task was suspended, probably by ^C. */
1053       status->value.sig = TARGET_SIGNAL_INT;
1054       break;
1055 
1056     case EVENT_BUS_ERR:		/* Task made evil nasty reference. */
1057       status->value.sig = TARGET_SIGNAL_BUS;
1058       break;
1059 
1060     case EVENT_ZERO_DIV:	/* Division by zero */
1061       status->value.sig = TARGET_SIGNAL_FPE;
1062       break;
1063 
1064     case EVENT_SIGNAL:
1065 #ifdef I80960
1066       status->value.sig = i960_fault_to_signal (rdbEvent.sigType);
1067 #else
1068       /* Back in the old days, before enum target_signal, this code used
1069 	 to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL
1070 	 would take care of it.  But PRINT_RANDOM_SIGNAL has never been
1071 	 defined except on the i960, so I don't really know what we are
1072 	 supposed to do on other architectures.  */
1073       status->value.sig = TARGET_SIGNAL_UNKNOWN;
1074 #endif
1075       break;
1076     } /* switch */
1077   return pid;
1078 }
1079 
1080 static int
1081 symbol_stub (arg)
1082      char *arg;
1083 {
1084   symbol_file_command (arg, 0);
1085   return 1;
1086 }
1087 
1088 static int
1089 add_symbol_stub (arg)
1090      char *arg;
1091 {
1092   struct ldfile *pLoadFile = (struct ldfile *)arg;
1093 
1094   printf_unfiltered("\t%s: ", pLoadFile->name);
1095   vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr,
1096 		  pLoadFile->data_addr, pLoadFile->bss_addr);
1097   printf_unfiltered ("ok\n");
1098   return 1;
1099 }
1100 /* Target command for VxWorks target systems.
1101 
1102    Used in vxgdb.  Takes the name of a remote target machine
1103    running vxWorks and connects to it to initialize remote network
1104    debugging.  */
1105 
1106 static void
1107 vx_open (args, from_tty)
1108      char *args;
1109      int from_tty;
1110 {
1111   extern int close ();
1112   char *bootFile;
1113   extern char *source_path;
1114   struct ldtabl loadTable;
1115   struct ldfile *pLoadFile;
1116   int i;
1117   extern CLIENT *pClient;
1118   int symbols_added = 0;
1119 
1120   if (!args)
1121     error_no_arg ("target machine name");
1122 
1123   target_preopen (from_tty);
1124 
1125   unpush_target (&vx_ops);
1126   printf_unfiltered ("Attaching remote machine across net...\n");
1127   gdb_flush (gdb_stdout);
1128 
1129   /* Allow the user to kill the connect attempt by typing ^C.
1130      Wait until the call to target_has_fp () completes before
1131      disallowing an immediate quit, since even if net_connect ()
1132      is successful, the remote debug server might be hung.  */
1133 
1134   immediate_quit++;
1135 
1136   net_connect (args);
1137   target_has_fp = net_check_for_fp ();
1138   printf_filtered ("Connected to %s.\n", args);
1139 
1140   immediate_quit--;
1141 
1142   push_target (&vx_ops);
1143 
1144   /* Save a copy of the target host's name.  */
1145   vx_host = savestring (args, strlen (args));
1146 
1147   /* Find out the name of the file from which the target was booted
1148      and load its symbol table.  */
1149 
1150   printf_filtered ("Looking in Unix path for all loaded modules:\n");
1151   bootFile = NULL;
1152   if (!net_get_boot_file (&bootFile))
1153     {
1154       if (*bootFile)
1155 	{
1156 	  printf_filtered ("\t%s: ", bootFile);
1157 	  /* This assumes that the kernel is never relocated.  Hope that is an
1158 	     accurate assumption.  */
1159 	  if (catch_errors
1160 	      (symbol_stub,
1161 	       bootFile,
1162 	       "Error while reading symbols from boot file:\n",
1163 	       RETURN_MASK_ALL))
1164 	    puts_filtered ("ok\n");
1165 	}
1166       else if (from_tty)
1167 	printf_unfiltered ("VxWorks kernel symbols not loaded.\n");
1168     }
1169   else
1170     error ("Can't retrieve boot file name from target machine.");
1171 
1172   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1173 
1174   if (net_get_symbols (&loadTable) != 0)
1175     error ("Can't read loaded modules from target machine");
1176 
1177   i = 0-1;
1178   while (++i < loadTable.tbl_size)
1179     {
1180       QUIT;	/* FIXME, avoids clnt_freeres below:  mem leak */
1181       pLoadFile = &loadTable.tbl_ent [i];
1182 #ifdef WRS_ORIG
1183   {
1184     register int desc;
1185     struct cleanup *old_chain;
1186     char *fullname = NULL;
1187 
1188     desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1189     if (desc < 0)
1190 	perror_with_name (pLoadFile->name);
1191     old_chain = make_cleanup (close, desc);
1192     add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1193 		      pLoadFile->bss_addr);
1194     do_cleanups (old_chain);
1195   }
1196 #else
1197       /* FIXME: Is there something better to search than the PATH? (probably
1198 	 not the source path, since source might be in different directories
1199 	 than objects.  */
1200 
1201       if (catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0,
1202 			RETURN_MASK_ALL))
1203 	symbols_added = 1;
1204 #endif
1205     }
1206   printf_filtered ("Done.\n");
1207 
1208   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1209 
1210   /* Getting new symbols may change our opinion about what is
1211      frameless.  */
1212   if (symbols_added)
1213     reinit_frame_cache ();
1214 }
1215 
1216 /* Takes a task started up outside of gdb and ``attaches'' to it.
1217    This stops it cold in its tracks and allows us to start tracing it.  */
1218 
1219 static void
1220 vx_attach (args, from_tty)
1221      char *args;
1222      int from_tty;
1223 {
1224   unsigned long pid;
1225   char *cptr = 0;
1226   Rptrace ptrace_in;
1227   Ptrace_return ptrace_out;
1228   int status;
1229 
1230   if (!args)
1231     error_no_arg ("process-id to attach");
1232 
1233   pid = strtoul (args, &cptr, 0);
1234   if ((cptr == args) || (*cptr != '\0'))
1235     error ("Invalid process-id -- give a single number in decimal or 0xhex");
1236 
1237   if (from_tty)
1238     printf_unfiltered ("Attaching pid %s.\n",
1239 		       local_hex_string((unsigned long) pid));
1240 
1241   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1242   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1243   ptrace_in.pid = pid;
1244 
1245   status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1246   if (status == -1)
1247     error (rpcerr);
1248   if (ptrace_out.status == -1)
1249     {
1250       errno = ptrace_out.errno;
1251       perror_with_name ("Attaching remote process");
1252     }
1253 
1254   /* It worked... */
1255   push_target (&vx_run_ops);
1256   /* The unsigned long pid will get turned into a signed int here,
1257      but it doesn't seem to matter.  inferior_pid must be signed
1258      in order for other parts of GDB to work correctly.  */
1259   inferior_pid = pid;
1260   vx_running = 0;
1261 #if defined (START_INFERIOR_HOOK)
1262   START_INFERIOR_HOOK ();
1263 #endif
1264 
1265   mark_breakpoints_out ();
1266 
1267   /* Set up the "saved terminal modes" of the inferior
1268      based on what modes we are starting it with.  */
1269 
1270   target_terminal_init ();
1271 
1272   /* Install inferior's terminal modes.  */
1273 
1274   target_terminal_inferior ();
1275 
1276   /* We will get a task spawn event immediately.  */
1277 
1278   init_wait_for_inferior ();
1279   clear_proceed_status ();
1280   stop_soon_quietly = 1;
1281   wait_for_inferior ();
1282   stop_soon_quietly = 0;
1283   normal_stop ();
1284 }
1285 
1286 
1287 /* detach_command --
1288    takes a program previously attached to and detaches it.
1289    The program resumes execution and will no longer stop
1290    on signals, etc.  We better not have left any breakpoints
1291    in the program or it'll die when it hits one.  For this
1292    to work, it may be necessary for the process to have been
1293    previously attached.  It *might* work if the program was
1294    started via the normal ptrace (PTRACE_TRACEME).  */
1295 
1296 static void
1297 vx_detach (args, from_tty)
1298      char *args;
1299      int from_tty;
1300 {
1301   Rptrace ptrace_in;
1302   Ptrace_return ptrace_out;
1303   int signal = 0;
1304   int status;
1305 
1306   if (args)
1307     error ("Argument given to VxWorks \"detach\".");
1308 
1309   if (from_tty)
1310       printf_unfiltered ("Detaching pid %s.\n",
1311 	      local_hex_string((unsigned long) inferior_pid));
1312 
1313   if (args)		/* FIXME, should be possible to leave suspended */
1314     signal = atoi (args);
1315 
1316   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1317   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1318   ptrace_in.pid = inferior_pid;
1319 
1320   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1321   if (status == -1)
1322     error (rpcerr);
1323   if (ptrace_out.status == -1)
1324     {
1325       errno = ptrace_out.errno;
1326       perror_with_name ("Detaching VxWorks process");
1327     }
1328 
1329   inferior_pid = 0;
1330   pop_target ();	/* go back to non-executing VxWorks connection */
1331 }
1332 
1333 /* vx_kill -- takes a running task and wipes it out.  */
1334 
1335 static void
1336 vx_kill ()
1337 {
1338   Rptrace ptrace_in;
1339   Ptrace_return ptrace_out;
1340   int status;
1341 
1342   printf_unfiltered ("Killing pid %s.\n", local_hex_string((unsigned long) inferior_pid));
1343 
1344   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1345   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1346   ptrace_in.pid = inferior_pid;
1347 
1348   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1349   if (status == -1)
1350     warning (rpcerr);
1351   else if (ptrace_out.status == -1)
1352     {
1353       errno = ptrace_out.errno;
1354       perror_with_name ("Killing VxWorks process");
1355     }
1356 
1357   /* If it gives good status, the process is *gone*, no events remain.
1358      If the kill failed, assume the process is gone anyhow.  */
1359   inferior_pid = 0;
1360   pop_target ();	/* go back to non-executing VxWorks connection */
1361 }
1362 
1363 /* Clean up from the VxWorks process target as it goes away.  */
1364 
1365 static void
1366 vx_proc_close (quitting)
1367      int quitting;
1368 {
1369   inferior_pid = 0;		/* No longer have a process.  */
1370   if (vx_running)
1371     free (vx_running);
1372   vx_running = 0;
1373 }
1374 
1375 /* Make an RPC call to the VxWorks target.
1376    Returns RPC status.  */
1377 
1378 static enum clnt_stat
1379 net_clnt_call (procNum, inProc, in, outProc, out)
1380     enum ptracereq procNum;
1381     xdrproc_t inProc;
1382     char *in;
1383     xdrproc_t outProc;
1384     char *out;
1385 {
1386   enum clnt_stat status;
1387 
1388   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1389 
1390   if (status != RPC_SUCCESS)
1391       clnt_perrno (status);
1392 
1393   return status;
1394 }
1395 
1396 /* Clean up before losing control.  */
1397 
1398 static void
1399 vx_close (quitting)
1400      int quitting;
1401 {
1402   if (pClient)
1403     clnt_destroy (pClient);	/* The net connection */
1404   pClient = 0;
1405 
1406   if (vx_host)
1407     free (vx_host);		/* The hostname */
1408   vx_host = 0;
1409 }
1410 
1411 /* A vxprocess target should be started via "run" not "target".  */
1412 /*ARGSUSED*/
1413 static void
1414 vx_proc_open (name, from_tty)
1415      char *name;
1416      int from_tty;
1417 {
1418   error ("Use the \"run\" command to start a VxWorks process.");
1419 }
1420 
1421 /* Target ops structure for accessing memory and such over the net */
1422 
1423 struct target_ops vx_ops = {
1424   "vxworks", "VxWorks target memory via RPC over TCP/IP",
1425   "Use VxWorks target memory.  \n\
1426 Specify the name of the machine to connect to.",
1427   vx_open, vx_close, vx_attach, 0, /* vx_detach, */
1428   0, 0, /* resume, wait */
1429   0, 0, /* read_reg, write_reg */
1430   0, /* prep_to_store, */
1431   vx_xfer_memory, vx_files_info,
1432   0, 0, /* insert_breakpoint, remove_breakpoint */
1433   0, 0, 0, 0, 0,	/* terminal stuff */
1434   0, /* vx_kill, */
1435   vx_load_command,
1436   vx_lookup_symbol,
1437   vx_create_inferior, 0,  /* mourn_inferior */
1438   0, /* can_run */
1439   0, /* notice_signals */
1440   0, /* thread_alive */
1441   0,				/* to_stop */
1442   core_stratum, 0, /* next */
1443   1, 1, 0, 0, 0,	/* all mem, mem, stack, regs, exec */
1444   0, 0,			/* Section pointers */
1445   OPS_MAGIC,		/* Always the last thing */
1446 };
1447 
1448 /* Target ops structure for accessing VxWorks child processes over the net */
1449 
1450 struct target_ops vx_run_ops = {
1451   "vxprocess", "VxWorks process",
1452   "VxWorks process, started by the \"run\" command.",
1453   vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */
1454   vx_resume, vx_wait,
1455   vx_read_register, vx_write_register,
1456   vx_prepare_to_store,
1457   vx_xfer_memory, vx_run_files_info,
1458   vx_insert_breakpoint, vx_remove_breakpoint,
1459   0, 0, 0, 0, 0,	/* terminal stuff */
1460   vx_kill,
1461   vx_load_command,
1462   vx_lookup_symbol,
1463   0, vx_mourn_inferior,
1464   0, /* can_run */
1465   0, /* notice_signals */
1466   0, /* thread_alive */
1467   0,				/* to_stop */
1468   process_stratum, 0, /* next */
1469   0, /* all_mem--off to avoid spurious msg in "i files" */
1470   1, 1, 1, 1,	/* mem, stack, regs, exec */
1471   0, 0,			/* Section pointers */
1472   OPS_MAGIC,		/* Always the last thing */
1473 };
1474 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1475 
1476 void
1477 _initialize_vx ()
1478 {
1479   add_show_from_set
1480     (add_set_cmd ("vxworks-timeout", class_support, var_uinteger,
1481 		  (char *) &rpcTimeout.tv_sec,
1482 		  "Set seconds to wait for rpc calls to return.\n\
1483 Set the number of seconds to wait for rpc calls to return.", &setlist),
1484      &showlist);
1485 
1486   add_target (&vx_ops);
1487   add_target (&vx_run_ops);
1488 }
1489