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