* mn10300.igen (OP_F0F4): Need to load contents of register AN0
[platform/upstream/binutils.git] / gdb / remote-vx.c
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 \f
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
720 /* This function allows the addition of incrementally linked object files.  */
721
722 static void
723 vx_load_command (arg_string, from_tty)
724      char *arg_string;
725      int from_tty;
726 {
727   CORE_ADDR text_addr;
728   CORE_ADDR data_addr;
729   CORE_ADDR bss_addr;
730
731   if (arg_string == 0)
732     error ("The load command takes a file name");
733
734   arg_string = tilde_expand (arg_string);
735   make_cleanup (free, arg_string);
736
737   dont_repeat ();
738
739   /* Refuse to load the module if a debugged task is running.  Doing so
740      can have a number of unpleasant consequences to the running task.  */
741
742   if (inferior_pid != 0 && target_has_execution)
743     {
744       if (query ("You may not load a module while the target task is running.\n\
745 Kill the target task? "))
746         target_kill ();
747       else
748         error ("Load cancelled.");
749     }
750
751   QUIT;
752   immediate_quit++;
753   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
754     error ("Load failed on target machine");
755   immediate_quit--;
756
757   vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
758
759   /* Getting new symbols may change our opinion about what is
760      frameless.  */
761   reinit_frame_cache ();
762 }
763
764 /* Single step the target program at the source or machine level.
765    Takes an error exit if rpc fails.
766    Returns -1 if remote single-step operation fails, else 0.  */
767
768 static int
769 net_step ()
770 {
771   enum clnt_stat status;
772   int step_status;
773   SOURCE_STEP source_step;
774
775   source_step.taskId = inferior_pid;
776
777   if (step_range_end)
778     {
779       source_step.startAddr = step_range_start;
780       source_step.endAddr = step_range_end;
781     }
782   else
783     {
784       source_step.startAddr = 0;
785       source_step.endAddr = 0;
786     }
787
788   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
789                           xdr_int, &step_status);
790
791   if (status == RPC_SUCCESS)
792     return step_status;
793   else 
794     error (rpcerr);
795 }
796
797 /* Emulate ptrace using RPC calls to the VxWorks target system.
798    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
799
800 static int
801 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
802     enum ptracereq request;
803     Rptrace *pPtraceIn;
804     Ptrace_return *pPtraceOut;
805 {
806   enum clnt_stat status;
807
808   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
809                           pPtraceOut);
810
811   if (status != RPC_SUCCESS)
812       return -1;
813
814   return 0;
815 }
816
817 /* Query the target for the name of the file from which VxWorks was
818    booted.  pBootFile is the address of a pointer to the buffer to
819    receive the file name; if the pointer pointed to by pBootFile is 
820    NULL, memory for the buffer will be allocated by XDR.
821    Returns -1 if rpc failed, 0 otherwise.  */
822
823 static int
824 net_get_boot_file (pBootFile)
825      char **pBootFile;
826 {
827   enum clnt_stat status;
828
829   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
830                           xdr_wrapstring, pBootFile);
831   return (status == RPC_SUCCESS) ? 0 : -1;
832 }
833
834 /* Fetch a list of loaded object modules from the VxWorks target.
835    Returns -1 if rpc failed, 0 otherwise
836    There's no way to check if the returned loadTable is correct.
837    VxWorks doesn't check it.  */
838
839 static int
840 net_get_symbols (pLoadTable)
841      ldtabl *pLoadTable;                /* return pointer to ldtabl here */
842 {
843   enum clnt_stat status;
844
845   memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
846
847   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
848   return (status == RPC_SUCCESS) ? 0 : -1;
849 }
850
851 /* Look up a symbol in the VxWorks target's symbol table.
852    Returns status of symbol read on target side (0=success, -1=fail)
853    Returns -1 and complain()s if rpc fails.  */
854
855 struct complaint cant_contact_target =
856   {"Lost contact with VxWorks target", 0, 0};
857
858 static int
859 vx_lookup_symbol (name, pAddr)
860      char *name;                /* symbol name */
861      CORE_ADDR *pAddr;
862 {
863   enum clnt_stat status;
864   SYMBOL_ADDR symbolAddr;
865
866   *pAddr = 0;
867   memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
868
869   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
870                           xdr_SYMBOL_ADDR, &symbolAddr);
871   if (status != RPC_SUCCESS)
872     {
873       complain (&cant_contact_target);
874       return -1;
875     }
876
877   *pAddr = symbolAddr.addr;
878   return symbolAddr.status;
879 }
880
881 /* Check to see if the VxWorks target has a floating point coprocessor.
882    Returns 1 if target has floating point processor, 0 otherwise.
883    Calls error() if rpc fails.  */
884
885 static int
886 net_check_for_fp ()
887 {
888   enum clnt_stat status;
889   bool_t fp = 0;        /* true if fp processor is present on target board */
890
891   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
892   if (status != RPC_SUCCESS)
893     error (rpcerr);
894
895    return (int) fp;
896 }
897
898 /* Establish an RPC connection with the VxWorks target system.
899    Calls error () if unable to establish connection.  */
900
901 static void
902 net_connect (host)
903      char *host;
904 {
905   struct sockaddr_in destAddr;
906   struct hostent *destHost;
907   unsigned long addr;
908
909   /* Get the internet address for the given host.  Allow a numeric
910      IP address or a hostname.  */
911
912   addr = inet_addr (host);
913   if (addr == -1)
914     {
915       destHost = (struct hostent *) gethostbyname (host);
916       if (destHost == NULL)
917         /* FIXME: Probably should include hostname here in quotes.
918            For example if the user types "target vxworks vx960 " it should
919            say "Invalid host `vx960 '." not just "Invalid hostname".  */
920         error ("Invalid hostname.  Couldn't find remote host address.");
921       addr = * (unsigned long *) destHost->h_addr;
922     }
923
924   memset (&destAddr, '\0', sizeof (destAddr));
925
926   destAddr.sin_addr.s_addr = addr;
927   destAddr.sin_family      = AF_INET;
928   destAddr.sin_port        = 0; /* set to actual port that remote
929                                    ptrace is listening on.  */
930
931   /* Create a tcp client transport on which to issue
932      calls to the remote ptrace server.  */
933
934   ptraceSock = RPC_ANYSOCK;
935   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
936   /* FIXME, here is where we deal with different version numbers of the
937      proto */
938
939   if (pClient == NULL)
940     {
941       clnt_pcreateerror ("\tnet_connect");
942       error ("Couldn't connect to remote target.");
943     }
944 }
945 \f
946 /* Sleep for the specified number of milliseconds 
947  * (assumed to be less than 1000).
948  * If select () is interrupted, returns immediately;
949  * takes an error exit if select () fails for some other reason.
950  */
951
952 static void
953 sleep_ms (ms)
954      long ms;
955 {
956   struct timeval select_timeout;
957   int status;
958
959   select_timeout.tv_sec = 0;
960   select_timeout.tv_usec = ms * 1000;
961
962   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
963                    &select_timeout);
964
965   if (status < 0 && errno != EINTR)
966     perror_with_name ("select");
967 }
968
969 static int
970 vx_wait (pid_to_wait_for, status)
971      int pid_to_wait_for;
972      struct target_waitstatus *status;
973 {
974   register int pid;
975   RDB_EVENT rdbEvent;
976   int quit_failed;
977
978   do
979     {
980       /* If CTRL-C is hit during this loop,
981          suspend the inferior process.  */
982
983       quit_failed = 0;
984       if (quit_flag)
985         {
986           quit_failed = (net_quit () == -1);
987           quit_flag = 0;
988         }
989
990       /* If a net_quit () or net_wait () call has failed,
991          allow the user to break the connection with the target.
992          We can't simply error () out of this loop, since the 
993          data structures representing the state of the inferior
994          are in an inconsistent state.  */
995
996       if (quit_failed || net_wait (&rdbEvent) == -1)
997         {
998           terminal_ours ();
999           if (query ("Can't %s.  Disconnect from target system? ",
1000                      (quit_failed) ? "suspend remote task"
1001                                    : "get status of remote task"))
1002             {
1003               target_mourn_inferior();
1004               error ("Use the \"target\" command to reconnect.");
1005             }
1006           else
1007             {
1008               terminal_inferior ();
1009               continue;
1010             }
1011         }
1012       
1013       pid = rdbEvent.taskId;
1014       if (pid == 0)
1015         {
1016           sleep_ms (200);       /* FIXME Don't kill the network too badly */
1017         }
1018       else if (pid != inferior_pid)
1019         fatal ("Bad pid for debugged task: %s\n",
1020                local_hex_string((unsigned long) pid));
1021     } while (pid == 0);
1022
1023   /* The mostly likely kind.  */
1024   status->kind = TARGET_WAITKIND_STOPPED;
1025
1026   switch (rdbEvent.eventType)
1027     {
1028     case EVENT_EXIT:
1029       status->kind = TARGET_WAITKIND_EXITED;
1030       /* FIXME is it possible to distinguish between a
1031          normal vs abnormal exit in VxWorks? */
1032       status->value.integer = 0;
1033       break;
1034
1035     case EVENT_START:
1036       /* Task was just started. */
1037       status->value.sig = TARGET_SIGNAL_TRAP;
1038       break;
1039
1040     case EVENT_STOP:
1041       status->value.sig = TARGET_SIGNAL_TRAP;
1042       /* XXX was it stopped by a signal?  act accordingly */
1043       break;
1044
1045     case EVENT_BREAK:           /* Breakpoint was hit. */
1046       status->value.sig = TARGET_SIGNAL_TRAP;
1047       break;
1048
1049     case EVENT_SUSPEND:         /* Task was suspended, probably by ^C. */
1050       status->value.sig = TARGET_SIGNAL_INT;
1051       break;
1052
1053     case EVENT_BUS_ERR:         /* Task made evil nasty reference. */
1054       status->value.sig = TARGET_SIGNAL_BUS;
1055       break;
1056
1057     case EVENT_ZERO_DIV:        /* Division by zero */
1058       status->value.sig = TARGET_SIGNAL_FPE;
1059       break;
1060
1061     case EVENT_SIGNAL:
1062 #ifdef I80960
1063       status->value.sig = i960_fault_to_signal (rdbEvent.sigType);
1064 #else
1065       /* Back in the old days, before enum target_signal, this code used
1066          to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL
1067          would take care of it.  But PRINT_RANDOM_SIGNAL has never been
1068          defined except on the i960, so I don't really know what we are
1069          supposed to do on other architectures.  */
1070       status->value.sig = TARGET_SIGNAL_UNKNOWN;
1071 #endif
1072       break;
1073     } /* switch */
1074   return pid;
1075 }
1076 \f
1077 static int
1078 symbol_stub (arg)
1079      char *arg;
1080 {
1081   symbol_file_command (arg, 0);
1082   return 1;
1083 }
1084
1085 static int
1086 add_symbol_stub (arg)
1087      char *arg;
1088 {
1089   struct ldfile *pLoadFile = (struct ldfile *)arg;
1090
1091   printf_unfiltered("\t%s: ", pLoadFile->name);
1092   vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr,
1093                   pLoadFile->data_addr, pLoadFile->bss_addr);
1094   printf_unfiltered ("ok\n");
1095   return 1;
1096 }
1097 /* Target command for VxWorks target systems.
1098
1099    Used in vxgdb.  Takes the name of a remote target machine
1100    running vxWorks and connects to it to initialize remote network
1101    debugging.  */
1102
1103 static void
1104 vx_open (args, from_tty)
1105      char *args;
1106      int from_tty;
1107 {
1108   extern int close ();
1109   char *bootFile;
1110   extern char *source_path;
1111   struct ldtabl loadTable;
1112   struct ldfile *pLoadFile;
1113   int i;
1114   extern CLIENT *pClient;
1115   int symbols_added = 0;
1116
1117   if (!args)
1118     error_no_arg ("target machine name");
1119
1120   target_preopen (from_tty);
1121   
1122   unpush_target (&vx_ops);
1123   printf_unfiltered ("Attaching remote machine across net...\n");
1124   gdb_flush (gdb_stdout);
1125
1126   /* Allow the user to kill the connect attempt by typing ^C.
1127      Wait until the call to target_has_fp () completes before
1128      disallowing an immediate quit, since even if net_connect ()
1129      is successful, the remote debug server might be hung.  */
1130
1131   immediate_quit++;
1132
1133   net_connect (args);
1134   target_has_fp = net_check_for_fp ();
1135   printf_filtered ("Connected to %s.\n", args);
1136
1137   immediate_quit--;
1138
1139   push_target (&vx_ops);
1140
1141   /* Save a copy of the target host's name.  */
1142   vx_host = savestring (args, strlen (args));
1143
1144   /* Find out the name of the file from which the target was booted
1145      and load its symbol table.  */
1146
1147   printf_filtered ("Looking in Unix path for all loaded modules:\n");
1148   bootFile = NULL;
1149   if (!net_get_boot_file (&bootFile))
1150     {
1151       if (*bootFile)
1152         {
1153           printf_filtered ("\t%s: ", bootFile);
1154           /* This assumes that the kernel is never relocated.  Hope that is an
1155              accurate assumption.  */
1156           if (catch_errors
1157               (symbol_stub,
1158                bootFile,
1159                "Error while reading symbols from boot file:\n",
1160                RETURN_MASK_ALL))
1161             puts_filtered ("ok\n");
1162         }
1163       else if (from_tty)
1164         printf_unfiltered ("VxWorks kernel symbols not loaded.\n");
1165     }
1166   else
1167     error ("Can't retrieve boot file name from target machine.");
1168
1169   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1170
1171   if (net_get_symbols (&loadTable) != 0)
1172     error ("Can't read loaded modules from target machine");
1173
1174   i = 0-1;
1175   while (++i < loadTable.tbl_size)
1176     {
1177       QUIT;     /* FIXME, avoids clnt_freeres below:  mem leak */
1178       pLoadFile = &loadTable.tbl_ent [i];
1179 #ifdef WRS_ORIG
1180   {
1181     register int desc;
1182     struct cleanup *old_chain;
1183     char *fullname = NULL;
1184
1185     desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1186     if (desc < 0)
1187         perror_with_name (pLoadFile->name);
1188     old_chain = make_cleanup (close, desc);
1189     add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1190                       pLoadFile->bss_addr);
1191     do_cleanups (old_chain);
1192   }
1193 #else
1194       /* FIXME: Is there something better to search than the PATH? (probably
1195          not the source path, since source might be in different directories
1196          than objects.  */
1197
1198       if (catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0,
1199                         RETURN_MASK_ALL))
1200         symbols_added = 1;
1201 #endif
1202     }
1203   printf_filtered ("Done.\n");
1204
1205   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1206
1207   /* Getting new symbols may change our opinion about what is
1208      frameless.  */
1209   if (symbols_added)
1210     reinit_frame_cache ();
1211 }
1212 \f
1213 /* Takes a task started up outside of gdb and ``attaches'' to it.
1214    This stops it cold in its tracks and allows us to start tracing it.  */
1215
1216 static void
1217 vx_attach (args, from_tty)
1218      char *args;
1219      int from_tty;
1220 {
1221   unsigned long pid;
1222   char *cptr = 0;
1223   Rptrace ptrace_in;
1224   Ptrace_return ptrace_out;
1225   int status;
1226
1227   if (!args)
1228     error_no_arg ("process-id to attach");
1229
1230   pid = strtoul (args, &cptr, 0);
1231   if ((cptr == args) || (*cptr != '\0'))
1232     error ("Invalid process-id -- give a single number in decimal or 0xhex");
1233
1234   if (from_tty)
1235     printf_unfiltered ("Attaching pid %s.\n",
1236                        local_hex_string((unsigned long) pid));
1237
1238   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1239   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1240   ptrace_in.pid = pid;
1241
1242   status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1243   if (status == -1)
1244     error (rpcerr);
1245   if (ptrace_out.status == -1)
1246     {
1247       errno = ptrace_out.errno;
1248       perror_with_name ("Attaching remote process");
1249     }
1250
1251   /* It worked... */
1252
1253   inferior_pid = pid;
1254   push_target (&vx_run_ops);
1255
1256   if (vx_running)
1257     free (vx_running);
1258   vx_running = 0;
1259 }
1260
1261 /* detach_command --
1262    takes a program previously attached to and detaches it.
1263    The program resumes execution and will no longer stop
1264    on signals, etc.  We better not have left any breakpoints
1265    in the program or it'll die when it hits one.  For this
1266    to work, it may be necessary for the process to have been
1267    previously attached.  It *might* work if the program was
1268    started via the normal ptrace (PTRACE_TRACEME).  */
1269
1270 static void
1271 vx_detach (args, from_tty)
1272      char *args;
1273      int from_tty;
1274 {
1275   Rptrace ptrace_in;
1276   Ptrace_return ptrace_out;
1277   int signal = 0;
1278   int status;
1279
1280   if (args)
1281     error ("Argument given to VxWorks \"detach\".");
1282
1283   if (from_tty)
1284       printf_unfiltered ("Detaching pid %s.\n",
1285               local_hex_string((unsigned long) inferior_pid));
1286
1287   if (args)             /* FIXME, should be possible to leave suspended */
1288     signal = atoi (args);
1289   
1290   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1291   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1292   ptrace_in.pid = inferior_pid;
1293
1294   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1295   if (status == -1)
1296     error (rpcerr);
1297   if (ptrace_out.status == -1)
1298     {
1299       errno = ptrace_out.errno;
1300       perror_with_name ("Detaching VxWorks process");
1301     }
1302
1303   inferior_pid = 0;
1304   pop_target ();        /* go back to non-executing VxWorks connection */
1305 }
1306
1307 /* vx_kill -- takes a running task and wipes it out.  */
1308
1309 static void
1310 vx_kill ()
1311 {
1312   Rptrace ptrace_in;
1313   Ptrace_return ptrace_out;
1314   int status;
1315
1316   printf_unfiltered ("Killing pid %s.\n", local_hex_string((unsigned long) inferior_pid));
1317
1318   memset ((char *)&ptrace_in,  '\0', sizeof (ptrace_in));
1319   memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out));
1320   ptrace_in.pid = inferior_pid;
1321
1322   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1323   if (status == -1)
1324     warning (rpcerr);
1325   else if (ptrace_out.status == -1)
1326     {
1327       errno = ptrace_out.errno;
1328       perror_with_name ("Killing VxWorks process");
1329     }
1330
1331   /* If it gives good status, the process is *gone*, no events remain.
1332      If the kill failed, assume the process is gone anyhow.  */
1333   inferior_pid = 0;
1334   pop_target ();        /* go back to non-executing VxWorks connection */
1335 }
1336
1337 /* Clean up from the VxWorks process target as it goes away.  */
1338
1339 static void
1340 vx_proc_close (quitting)
1341      int quitting;
1342 {
1343   inferior_pid = 0;             /* No longer have a process.  */
1344   if (vx_running)
1345     free (vx_running);
1346   vx_running = 0;
1347 }
1348 \f
1349 /* Make an RPC call to the VxWorks target.
1350    Returns RPC status.  */
1351
1352 static enum clnt_stat
1353 net_clnt_call (procNum, inProc, in, outProc, out)
1354     enum ptracereq procNum;
1355     xdrproc_t inProc;
1356     char *in;
1357     xdrproc_t outProc;
1358     char *out;
1359 {
1360   enum clnt_stat status;
1361   
1362   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1363
1364   if (status != RPC_SUCCESS)
1365       clnt_perrno (status);
1366
1367   return status;
1368 }
1369
1370 /* Clean up before losing control.  */
1371
1372 static void
1373 vx_close (quitting)
1374      int quitting;
1375 {
1376   if (pClient)
1377     clnt_destroy (pClient);     /* The net connection */
1378   pClient = 0;
1379
1380   if (vx_host)
1381     free (vx_host);             /* The hostname */
1382   vx_host = 0;
1383 }
1384
1385 /* A vxprocess target should be started via "run" not "target".  */
1386 /*ARGSUSED*/
1387 static void
1388 vx_proc_open (name, from_tty)
1389      char *name;
1390      int from_tty;
1391 {
1392   error ("Use the \"run\" command to start a VxWorks process.");
1393 }
1394
1395 /* Target ops structure for accessing memory and such over the net */
1396
1397 struct target_ops vx_ops ;
1398
1399 static void init_vx_ops(void)
1400 {
1401   vx_ops.to_shortname =   "vxworks";
1402   vx_ops.to_longname =   "VxWorks target memory via RPC over TCP/IP";
1403   vx_ops.to_doc =   "Use VxWorks target memory.  \n\
1404 Specify the name of the machine to connect to.",
1405     vx_ops.to_open =   vx_open;
1406   vx_ops.to_close =   vx_close;
1407   vx_ops.to_attach =   vx_attach;
1408   vx_ops.to_detach =   0; /* vx_detach, */
1409   vx_ops.to_resume =   0;
1410   vx_ops.to_wait  =   0; /* resume, wait */
1411   vx_ops.to_fetch_registers  =   0;
1412   vx_ops.to_store_registers  =   0; /* read_reg, write_reg */
1413   vx_ops.to_prepare_to_store =   0; /* prep_to_store, */
1414   vx_ops.to_xfer_memory  =   vx_xfer_memory;
1415   vx_ops.to_files_info  =   vx_files_info;
1416   vx_ops.to_insert_breakpoint =   0;
1417   vx_ops.to_remove_breakpoint =   0; /* insert_breakpoint, remove_breakpoint */
1418   vx_ops.to_terminal_init  =   0;
1419   vx_ops.to_terminal_inferior =   0;
1420   vx_ops.to_terminal_ours_for_output =   0;
1421   vx_ops.to_terminal_ours  =   0;
1422   vx_ops.to_terminal_info  =   0;       /* terminal stuff */
1423   vx_ops.to_kill  =   0; /* vx_kill, */
1424   vx_ops.to_load  =   vx_load_command;
1425   vx_ops.to_lookup_symbol =   vx_lookup_symbol;
1426   vx_ops.to_create_inferior =   vx_create_inferior;
1427   vx_ops.to_mourn_inferior =   0;  /* mourn_inferior */
1428   vx_ops.to_can_run  =   0; /* can_run */
1429   vx_ops.to_notice_signals =   0; /* notice_signals */
1430   vx_ops.to_thread_alive  =   0; /* thread_alive */
1431   vx_ops.to_stop  =   0;                                /* to_stop */
1432   vx_ops.to_stratum =   core_stratum;
1433   vx_ops.DONT_USE =   0; /* next */
1434   vx_ops.to_has_all_memory =   1;
1435   vx_ops.to_has_memory =   1;
1436   vx_ops.to_has_stack =   0;
1437   vx_ops.to_has_registers =   0;
1438   vx_ops.to_has_execution =   0;        /* all mem, mem, stack, regs, exec */
1439   vx_ops.to_sections =   0;
1440   vx_ops.to_sections_end =   0;
1441   vx_ops.to_magic =   OPS_MAGIC;                /* Always the last thing */
1442 };
1443
1444 /* Target ops structure for accessing VxWorks child processes over the net */
1445
1446 struct target_ops vx_run_ops ;
1447
1448 static void init_vx_run_ops(void)
1449 {
1450   vx_run_ops.to_shortname =   "vxprocess";
1451   vx_run_ops.to_longname =   "VxWorks process";
1452   vx_run_ops.to_doc =   "VxWorks process; started by the \"run\" command.",
1453     vx_run_ops.to_open =   vx_proc_open;
1454   vx_run_ops.to_close =   vx_proc_close;
1455   vx_run_ops.to_attach =   0;
1456   vx_run_ops.to_detach =   vx_detach; 
1457   vx_run_ops.to_resume =   vx_resume;
1458   vx_run_ops.to_wait  =   vx_wait;
1459   vx_run_ops.to_fetch_registers  =   vx_read_register;
1460   vx_run_ops.to_store_registers  =   vx_write_register;
1461   vx_run_ops.to_prepare_to_store =   vx_prepare_to_store;
1462   vx_run_ops.to_xfer_memory  =   vx_xfer_memory;
1463   vx_run_ops.to_files_info  =   vx_run_files_info;
1464   vx_run_ops.to_insert_breakpoint =   vx_insert_breakpoint;
1465   vx_run_ops.to_remove_breakpoint =   vx_remove_breakpoint;
1466   vx_run_ops.to_terminal_init  =   0;
1467   vx_run_ops.to_terminal_inferior =   0;
1468   vx_run_ops.to_terminal_ours_for_output =   0;
1469   vx_run_ops.to_terminal_ours  =   0;
1470   vx_run_ops.to_terminal_info  =   0;
1471   vx_run_ops.to_kill  =   vx_kill;
1472   vx_run_ops.to_load  =   vx_load_command;
1473   vx_run_ops.to_lookup_symbol =   vx_lookup_symbol;
1474   vx_run_ops.to_create_inferior =   0;
1475   vx_run_ops.to_mourn_inferior =   vx_mourn_inferior ;
1476   vx_run_ops.to_can_run =   0; 
1477   vx_run_ops.to_notice_signals  =   0; 
1478   vx_run_ops.to_thread_alive =   0; 
1479   vx_run_ops.to_stop  =   0;    
1480   vx_run_ops.to_stratum  =   process_stratum;
1481   vx_run_ops.DONT_USE =   0; 
1482   vx_run_ops.to_has_all_memory =   0; 
1483   vx_run_ops.to_has_memory =   1;
1484   vx_run_ops.to_has_stack =   1;
1485   vx_run_ops.to_has_registers =   1;
1486   vx_run_ops.to_has_execution =   1;    
1487   vx_run_ops.to_sections =   0;
1488   vx_run_ops.to_sections_end =   0;     
1489   vx_run_ops.to_magic =   OPS_MAGIC;    
1490 }
1491 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1492 \f
1493 void
1494 _initialize_vx ()
1495 {
1496   init_vx_ops() ;
1497   init_vx_run_ops() ;
1498   add_show_from_set
1499     (add_set_cmd ("vxworks-timeout", class_support, var_uinteger,
1500                   (char *) &rpcTimeout.tv_sec,
1501                   "Set seconds to wait for rpc calls to return.\n\
1502 Set the number of seconds to wait for rpc calls to return.", &setlist),
1503      &showlist);
1504
1505   add_target (&vx_ops);
1506   add_target (&vx_run_ops);
1507 }