]> Git Repo - binutils.git/blob - gdb/remote-vx.68.c
Sat Nov 30 18:58:40 1991 Steve Chamberlain (sac at cygnus.com)
[binutils.git] / gdb / remote-vx.68.c
1 /* Memory-access and commands for remote VxWorks processes, for GDB.
2    Copyright 1990, 1991 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 #define  TM_FILE_OVERRIDE
22 #include "defs.h"
23 #include "tm-vxworks68.h"
24 #include "frame.h"
25 #include "inferior.h"
26 #include "wait.h"
27 #include "target.h"
28 #include "gdbcore.h"
29 #include "command.h"
30 #include "symtab.h"
31 #include "symfile.h"            /* for struct complaint */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/socket.h>
41 #define free bogon_free         /* Sun claims "int free()" not void */
42 #include <rpc/rpc.h>
43 #undef free
44 #include <netdb.h>
45 #include <ptrace.h>
46 #include "xdr_ptrace.h"
47 #include "xdr_ld.h"
48 #include "xdr_rdb.h"
49 #include "dbgRpcLib.h"
50
51 /* get rid of value.h if possible */
52 #include <value.h>
53 #include <symtab.h>
54  
55 extern value call_function_by_hand ();
56 extern void symbol_file_command ();
57 extern int stop_soon_quietly;           /* for wait_for_inferior */
58
59 static int net_ptrace_clnt_call ();     /* Forward decl */
60 static enum clnt_stat net_clnt_call (); /* Forward decl */
61 extern struct target_ops vx_ops, vx_run_ops;    /* Forward declaration */
62
63 /* Saved name of target host and called function for "info files".
64    Both malloc'd.  */
65
66 static char *vx_host;
67 static char *vx_running;
68
69 /* Nonzero means target that is being debugged remotely has a floating
70    point processor.  */
71
72 static int target_has_fp;
73
74 /* Default error message when the network is forking up.  */
75
76 static const char rpcerr[] = "network target debugging:  rpc error";
77
78 CLIENT *pClient;         /* client used in net debugging */
79 static int ptraceSock = RPC_ANYSOCK;
80 extern int errno;
81
82 enum clnt_stat net_clnt_call();
83 static void parse_args ();
84
85 static struct timeval rpcTimeout = { 10, 0 };
86
87 static char *skip_white_space ();
88 static char *find_white_space ();
89  
90 /* Tell the VxWorks target system to download a file.
91    The load addresses of the text, data, and bss segments are
92    stored in pTextAddr, pDataAddr, and *pBssAddr (respectively).
93    Returns 0 for success, -1 for failure.  */
94
95 static int
96 net_load (filename, pTextAddr, pDataAddr, pBssAddr)
97     char *filename;
98     CORE_ADDR *pTextAddr;
99     CORE_ADDR *pDataAddr;
100     CORE_ADDR *pBssAddr;
101     {
102     enum clnt_stat status;
103     struct ldfile ldstruct;
104     struct timeval load_timeout;
105  
106     bzero ((char *) &ldstruct, sizeof (ldstruct));
107
108     /* We invoke clnt_call () here directly, instead of through
109        net_clnt_call (), because we need to set a large timeout value.
110        The load on the target side can take quite a while, easily
111        more than 10 seconds.  The user can kill this call by typing
112        CTRL-C if there really is a problem with the load.  */
113
114     load_timeout.tv_sec = 0x7FFF7FFF;   /* 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 /* Call a function on the VxWorks target system.
181    ARGS is a vector of values of arguments (NARGS of them).
182    FUNCTION is a value, the function to be called.
183    Returns a struct value * representing what the function returned.
184    May fail to return, if a breakpoint or signal is hit
185    during the execution of the function.  */
186
187 #ifdef FIXME
188 /* FIXME, function calls are really fried.  GO back to manual method. */
189 value
190 vx_call_function (function, nargs, args)
191      value function;
192      int nargs;
193      value *args;
194 {
195   register CORE_ADDR sp;
196   register int i;
197   CORE_ADDR start_sp;
198   static REGISTER_TYPE dummy[] = CALL_DUMMY;
199   REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)];
200   CORE_ADDR old_sp;
201   struct type *value_type;
202   unsigned char struct_return;
203   CORE_ADDR struct_addr;
204   struct inferior_status inf_status;
205   struct cleanup *old_chain;
206   CORE_ADDR funaddr;
207   int using_gcc;
208
209   save_inferior_status (&inf_status, 1);
210   old_chain = make_cleanup (restore_inferior_status, &inf_status);
211
212   /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
213      (and POP_FRAME for restoring them).  (At least on most machines)
214      they are saved on the stack in the inferior.  */
215   PUSH_DUMMY_FRAME;
216
217   old_sp = sp = read_register (SP_REGNUM);
218
219 #if 1 INNER_THAN 2              /* Stack grows down */
220   sp -= sizeof dummy;
221   start_sp = sp;
222 #else                           /* Stack grows up */
223   start_sp = sp;
224   sp += sizeof dummy;
225 #endif
226
227   funaddr = find_function_addr (function, &value_type);
228
229   {
230     struct block *b = block_for_pc (funaddr);
231     /* If compiled without -g, assume GCC.  */
232     using_gcc = b == NULL || BLOCK_GCC_COMPILED (b);
233   }
234
235   /* Are we returning a value using a structure return or a normal
236      value return? */
237
238   struct_return = using_struct_return (function, funaddr, value_type,
239                                        using_gcc);
240
241   /* Create a call sequence customized for this function
242      and the number of arguments for it.  */
243   bcopy (dummy, dummy1, sizeof dummy);
244   FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
245                   value_type, using_gcc);
246
247 #if CALL_DUMMY_LOCATION == ON_STACK
248   write_memory (start_sp, dummy1, sizeof dummy);
249
250 #else /* Not on stack.  */
251 #if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
252   /* Convex Unix prohibits executing in the stack segment. */
253   /* Hope there is empty room at the top of the text segment. */
254   {
255     static checked = 0;
256     if (!checked)
257       for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp)
258         if (read_memory_integer (start_sp, 1) != 0)
259           error ("text segment full -- no place to put call");
260     checked = 1;
261     sp = old_sp;
262     start_sp = text_end - sizeof dummy;
263     write_memory (start_sp, dummy1, sizeof dummy);
264   }
265 #else /* After text_end.  */
266   {
267     int errcode;
268     sp = old_sp;
269     start_sp = text_end;
270     errcode = target_write_memory (start_sp, dummy1, sizeof dummy);
271     if (errcode != 0)
272       error ("Cannot write text segment -- call_function failed");
273   }
274 #endif /* After text_end.  */
275 #endif /* Not on stack.  */
276
277 #ifdef STACK_ALIGN
278   /* If stack grows down, we must leave a hole at the top. */
279   {
280     int len = 0;
281
282     /* Reserve space for the return structure to be written on the
283        stack, if necessary */
284
285     if (struct_return)
286       len += TYPE_LENGTH (value_type);
287     
288     for (i = nargs - 1; i >= 0; i--)
289       len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i])));
290 #ifdef CALL_DUMMY_STACK_ADJUST
291     len += CALL_DUMMY_STACK_ADJUST;
292 #endif
293 #if 1 INNER_THAN 2
294     sp -= STACK_ALIGN (len) - len;
295 #else
296     sp += STACK_ALIGN (len) - len;
297 #endif
298   }
299 #endif /* STACK_ALIGN */
300
301     /* Reserve space for the return structure to be written on the
302        stack, if necessary */
303
304     if (struct_return)
305       {
306 #if 1 INNER_THAN 2
307         sp -= TYPE_LENGTH (value_type);
308         struct_addr = sp;
309 #else
310         struct_addr = sp;
311         sp += TYPE_LENGTH (value_type);
312 #endif
313       }
314
315 #if defined (REG_STRUCT_HAS_ADDR)
316   {
317     /* This is a machine like the sparc, where we need to pass a pointer
318        to the structure, not the structure itself.  */
319     if (REG_STRUCT_HAS_ADDR (using_gcc))
320       for (i = nargs - 1; i >= 0; i--)
321         if (   TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT
322             || TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_UNION)
323           {
324             CORE_ADDR addr;
325 #if !(1 INNER_THAN 2)
326             /* The stack grows up, so the address of the thing we push
327                is the stack pointer before we push it.  */
328             addr = sp;
329 #endif
330             /* Push the structure.  */
331             sp = value_push (sp, args[i]);
332 #if 1 INNER_THAN 2
333             /* The stack grows down, so the address of the thing we push
334                is the stack pointer after we push it.  */
335             addr = sp;
336 #endif
337             /* The value we're going to pass is the address of the thing
338                we just pushed.  */
339             args[i] = value_from_long (builtin_type_long, (LONGEST) addr);
340           }
341   }
342 #endif /* REG_STRUCT_HAS_ADDR.  */
343
344 #ifdef PUSH_ARGUMENTS
345   PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr);
346 #else /* !PUSH_ARGUMENTS */
347   for (i = nargs - 1; i >= 0; i--)
348     sp = value_arg_push (sp, args[i]);
349 #endif /* !PUSH_ARGUMENTS */
350
351 #ifdef CALL_DUMMY_STACK_ADJUST
352 #if 1 INNER_THAN 2
353   sp -= CALL_DUMMY_STACK_ADJUST;
354 #else
355   sp += CALL_DUMMY_STACK_ADJUST;
356 #endif
357 #endif /* CALL_DUMMY_STACK_ADJUST */
358
359   /* Store the address at which the structure is supposed to be
360      written.  Note that this (and the code which reserved the space
361      above) assumes that gcc was used to compile this function.  Since
362      it doesn't cost us anything but space and if the function is pcc
363      it will ignore this value, we will make that assumption.
364
365      Also note that on some machines (like the sparc) pcc uses a 
366      convention like gcc's.  */
367
368   if (struct_return)
369     STORE_STRUCT_RETURN (struct_addr, sp);
370
371   /* Write the stack pointer.  This is here because the statements above
372      might fool with it.  On SPARC, this write also stores the register
373      window into the right place in the new stack frame, which otherwise
374      wouldn't happen.  (See write_inferior_registers in sparc-xdep.c.)  */
375   write_register (SP_REGNUM, sp);
376
377   /* Figure out the value returned by the function.  */
378   {
379     char retbuf[REGISTER_BYTES];
380
381     /* Execute the stack dummy routine, calling FUNCTION.
382        When it is done, discard the empty frame
383        after storing the contents of all regs into retbuf.  */
384     run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf);
385
386     do_cleanups (old_chain);
387
388     return value_being_returned (value_type, retbuf, struct_return);
389   }
390 }
391 /* should return a value of some sort */
392  
393 value
394 vx_call_function (funcAddr, nargs, args, valueType)
395     char *funcAddr;
396     int nargs;
397     value *args;
398     struct type * valueType;
399 {
400     int i;
401     func_call funcInfo;
402     arg_value *argValue;
403     enum clnt_stat status;
404     register int len;
405     arg_value funcReturn;
406     value gdbValue;
407
408     argValue = (arg_value *) xmalloc (nargs * sizeof (arg_value));
409
410     bzero (argValue, nargs * sizeof (arg_value));
411     bzero (&funcReturn, sizeof (funcReturn));
412
413     for (i = nargs - 1; i >= 0; i--)
414         {
415         len = TYPE_LENGTH (VALUE_TYPE (args [i]));
416
417         switch (TYPE_CODE (VALUE_TYPE (args[i])))
418             {
419             /* XXX put other types here.  Where's CHAR, etc??? */
420
421             case TYPE_CODE_FLT:
422                 argValue[i].type = T_FLOAT;
423                 break;
424             case TYPE_CODE_INT:
425             case TYPE_CODE_PTR:
426             case TYPE_CODE_ENUM:
427             case TYPE_CODE_FUNC:
428                 argValue[i].type = T_INT;
429                 break;
430
431             case TYPE_CODE_UNDEF:
432             case TYPE_CODE_ARRAY:
433             case TYPE_CODE_STRUCT:
434             case TYPE_CODE_UNION:
435             case TYPE_CODE_VOID:
436             case TYPE_CODE_SET:
437             case TYPE_CODE_RANGE:
438             case TYPE_CODE_PASCAL_ARRAY:
439             case TYPE_CODE_MEMBER:          /* C++ */
440             case TYPE_CODE_METHOD:          /* C++ */
441             case TYPE_CODE_REF:             /* C++ */
442             default:
443                 error ("No corresponding VxWorks type for %d.  CHECK IT OUT!!!\n",
444                         TYPE_CODE(VALUE_TYPE(args[i])));
445             } /* switch */
446         if (TYPE_CODE(VALUE_TYPE(args[i])) == TYPE_CODE_FUNC)
447             argValue[i].arg_value_u.v_int = VALUE_ADDRESS(args[i]);
448         else
449             bcopy (VALUE_CONTENTS (args[i]), (char *) &argValue[i].arg_value_u,
450                    len);
451         }
452
453     /* XXX what should the type of this function addr be?
454      * XXX Both in gdb and vxWorks
455      */
456     funcInfo.func_addr = (int) funcAddr;
457     funcInfo.args.args_len = nargs;
458     funcInfo.args.args_val = argValue;
459
460     status = net_clnt_call (VX_CALL_FUNC, xdr_func_call, (char *) &funcInfo,
461                             xdr_arg_value, &funcReturn);
462
463     free ((char *) argValue);
464
465     if (status == RPC_SUCCESS)
466         {
467         /* XXX this assumes that vxWorks ALWAYS returns an int, and that
468          * XXX gdb isn't expecting anything more
469          */
470
471         /*******************
472         if (funcReturn.type == T_UNKNOWN)
473             return YYYXXX...;
474         *******************/
475         gdbValue = allocate_value (valueType);
476         bcopy (&funcReturn.arg_value_u.v_int, VALUE_CONTENTS (gdbValue),
477                 sizeof (int));
478         return gdbValue;
479         }
480     else 
481         error (rpcerr);
482     }
483 #endif /* FIXME */
484  
485 /* Start an inferior process and sets inferior_pid to its pid.
486    EXEC_FILE is the file to run.
487    ALLARGS is a string containing the arguments to the program.
488    ENV is the environment vector to pass.
489    Returns process id.  Errors reported with error().
490    On VxWorks, we ignore exec_file.  */
491  
492 void
493 vx_create_inferior (exec_file, args, env)
494      char *exec_file;
495      char *args;
496      char **env;
497 {
498   enum clnt_stat status;
499   arg_array passArgs;
500   TASK_START taskStart;
501
502   bzero ((char *) &passArgs, sizeof (passArgs));
503   bzero ((char *) &taskStart, sizeof (taskStart));
504
505   /* parse arguments, put them in passArgs */
506
507   parse_args (args, &passArgs);
508
509   if (passArgs.arg_array_len == 0)
510     error ("You must specify a function name to run, and arguments if any");
511
512   status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
513                           xdr_TASK_START, &taskStart);
514
515   if ((status != RPC_SUCCESS) || (taskStart.status == -1))
516     error ("Can't create process on remote target machine");
517
518   /* Save the name of the running function */
519   if (vx_running)
520     free (vx_running);
521   vx_running = savestring (passArgs.arg_array_val[0],
522                            strlen (passArgs.arg_array_val[0]));
523
524 #ifdef CREATE_INFERIOR_HOOK
525   CREATE_INFERIOR_HOOK (pid);
526 #endif  
527
528   push_target (&vx_run_ops);
529   inferior_pid = taskStart.pid;
530
531 #if defined (START_INFERIOR_HOOK)
532   START_INFERIOR_HOOK ();
533 #endif
534
535   /* We will get a trace trap after one instruction.
536      Insert breakpoints and continue.  */
537
538   init_wait_for_inferior ();
539
540   /* Set up the "saved terminal modes" of the inferior
541      based on what modes we are starting it with.  */
542   target_terminal_init ();
543
544   /* Install inferior's terminal modes.  */
545   target_terminal_inferior ();
546
547   /* remote_start(args); */
548   /* trap_expected = 0; */
549   stop_soon_quietly = 1;
550   wait_for_inferior ();         /* Get the task spawn event */
551   stop_soon_quietly = 0;
552
553   /* insert_step_breakpoint ();  FIXME, do we need this?  */
554   proceed(-1, -1, 0);
555 }
556
557 /* Fill ARGSTRUCT in argc/argv form with the arguments from the
558    argument string ARGSTRING.  */
559
560 static void
561 parse_args (arg_string, arg_struct)
562      register char *arg_string;
563      arg_array *arg_struct;
564 {
565   register int arg_count = 0;   /* number of arguments */
566   register int arg_index = 0;
567   register char *p0;
568  
569   bzero ((char *) arg_struct, sizeof (arg_array));
570  
571   /* first count how many arguments there are */
572
573   p0 = arg_string;
574   while (*p0 != '\0')
575     {
576       if (*(p0 = skip_white_space (p0)) == '\0')
577         break;
578       p0 = find_white_space (p0);
579       arg_count++;
580     }
581
582   arg_struct->arg_array_len = arg_count;
583   arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
584                                                  * sizeof (char *));
585
586   /* now copy argument strings into arg_struct.  */
587
588   while (*(arg_string = skip_white_space (arg_string)))
589     {
590       p0 = find_white_space (arg_string);
591       arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
592                                                            p0 - arg_string);
593       arg_string = p0;
594     }
595
596   arg_struct->arg_array_val[arg_count] = NULL;
597 }
598
599 /* Advance a string pointer across whitespace and return a pointer
600    to the first non-white character.  */
601
602 static char *
603 skip_white_space (p)
604      register char *p;
605 {
606   while (*p == ' ' || *p == '\t')
607     p++;
608   return p;
609 }
610     
611 /* Search for the first unquoted whitespace character in a string.
612    Returns a pointer to the character, or to the null terminator
613    if no whitespace is found.  */
614
615 static char *
616 find_white_space (p)
617      register char *p;
618 {
619   register int c;
620
621   while ((c = *p) != ' ' && c != '\t' && c)
622     {
623       if (c == '\'' || c == '"')
624         {
625           while (*++p != c && *p)
626             {
627               if (*p == '\\')
628                 p++;
629             }
630           if (!*p)
631             break;
632         }
633       p++;
634     }
635   return p;
636 }
637     
638 /* Poll the VxWorks target system for an event related
639    to the debugged task.
640    Returns -1 if remote wait failed, task status otherwise.  */
641
642 int
643 net_wait (pEvent)
644     RDB_EVENT *pEvent;
645 {
646     int pid;
647     enum clnt_stat status;
648
649     bzero ((char *) pEvent, sizeof (RDB_EVENT));
650
651     pid = inferior_pid;
652     status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent);
653
654     return (status == RPC_SUCCESS)? pEvent->status: -1;
655 }
656     
657 /* Suspend the remote task.
658    Returns -1 if suspend fails on target system, 0 otherwise.  */
659
660 int
661 net_quit ()
662 {
663     int pid;
664     int quit_status;
665     enum clnt_stat status;
666
667     quit_status = 0;
668
669     /* don't let rdbTask suspend itself by passing a pid of 0 */
670
671     if ((pid = inferior_pid) == 0)
672         return -1;
673
674     status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
675                             &quit_status);
676
677     return (status == RPC_SUCCESS)? quit_status: -1;
678 }
679
680 /* Read a register or registers from the remote system.  */
681
682 int
683 vx_read_register (regno)
684      int regno;
685 {
686   int status;
687   Rptrace ptrace_in;
688   Ptrace_return ptrace_out;
689   struct regs inferior_registers;
690   struct fp_status inferior_fp_registers;
691   extern char registers[];
692
693   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
694   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
695
696   /* FIXME, eventually only get the ones we need.  */
697   registers_fetched ();
698   
699   ptrace_in.pid = inferior_pid;
700   ptrace_out.info.more_data = (caddr_t) &inferior_registers;
701   status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out);
702   if (status)
703     error (rpcerr);
704   if (ptrace_out.status == -1)
705     {
706       errno = ptrace_out.errno;
707       return -1;
708     }
709   
710 #ifdef I80960
711 #else  /* I80960 */
712   bcopy (&inferior_registers, registers, 16 * 4);
713   *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
714   *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
715
716   if (target_has_fp)
717     {
718       ptrace_in.pid = inferior_pid;
719       ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers;
720       status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
721       if (status)
722         error (rpcerr);
723       if (ptrace_out.status == -1)
724         {
725           errno = ptrace_out.errno;
726           return -1;
727         }
728       
729       bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
730              sizeof inferior_fp_registers.fps_regs);
731       bcopy (&inferior_fp_registers.fps_control,
732          &registers[REGISTER_BYTE (FPC_REGNUM)],
733          sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
734     }
735   else
736     {
737       bzero (&registers[REGISTER_BYTE (FP0_REGNUM)],
738              sizeof inferior_fp_registers.fps_regs);
739       bzero (&registers[REGISTER_BYTE (FPC_REGNUM)],
740          sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
741     }
742 #endif
743   return 0;
744 }
745
746 /* Prepare to store registers.  Since we will store all of them,
747    read out their current values now.  */
748
749 void
750 vx_prepare_to_store ()
751 {
752   vx_read_register (-1);
753 }
754
755
756 /* Store our register values back into the inferior.
757    If REGNO is -1, do this for all registers.
758    Otherwise, REGNO specifies which register (so we can save time).  */
759    /* FIXME, look at REGNO to save time here */
760
761 vx_write_register (regno)
762      int regno;
763 {
764   struct regs inferior_registers;
765   struct fp_status inferior_fp_registers;
766   extern char registers[];
767   int status;
768   Rptrace ptrace_in;
769   Ptrace_return ptrace_out;
770
771   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
772   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
773
774   bcopy (registers, &inferior_registers, 16 * 4);
775   inferior_registers.r_ps = *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
776   inferior_registers.r_pc = *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
777   ptrace_in.pid = inferior_pid;
778   ptrace_in.info.ttype     = REGS;
779   ptrace_in.info.more_data = (caddr_t) &inferior_registers;
780
781   /* XXX change second param to be a proc number */
782   status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out);
783   if (status)
784       error (rpcerr);
785   if (ptrace_out.status == -1)
786     {
787       errno = ptrace_out.errno;
788       return -1;
789     }
790
791   if (target_has_fp)
792     {
793       bcopy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
794              sizeof inferior_fp_registers.fps_regs);
795       bcopy (&registers[REGISTER_BYTE (FPC_REGNUM)],
796          &inferior_fp_registers.fps_control,
797          sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
798
799       ptrace_in.pid = inferior_pid;
800       ptrace_in.info.ttype     = FPREGS;
801       ptrace_in.info.more_data = (caddr_t) &inferior_fp_registers;
802
803       status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out);
804       if (status)
805           error (rpcerr);
806       if (ptrace_out.status == -1)
807         {
808           errno = ptrace_out.errno;
809           return -1;
810         }
811     }
812   return 0;
813 }
814
815 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
816    to debugger memory starting at MYADDR.  WRITE is true if writing to the
817    inferior.
818    Result is the number of bytes written or read (zero if error).  The
819    protocol allows us to return a negative count, indicating that we can't
820    handle the current address but can handle one N bytes further, but
821    vxworks doesn't give us that information.  */
822
823 int
824 vx_xfer_memory (memaddr, myaddr, len, write)
825      CORE_ADDR memaddr;
826      char *myaddr;
827      int len;
828 {
829   int status;
830   Rptrace ptrace_in;
831   Ptrace_return ptrace_out;
832   C_bytes data;
833
834   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
835   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
836
837   ptrace_in.pid = inferior_pid;         /* XXX pid unnecessary for READDATA */
838   ptrace_in.addr = (int) memaddr;       /* Where from */
839   ptrace_in.data = len;                 /* How many bytes */
840
841   if (write)
842     {
843       ptrace_in.info.ttype     = DATA;
844       ptrace_in.info.more_data = (caddr_t) &data;
845
846       data.bytes = (caddr_t) myaddr;    /* Where from */
847       data.len   = len;                 /* How many bytes (again, for XDR) */
848
849       /* XXX change second param to be a proc number */
850       status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out);
851     }
852   else
853     {
854       ptrace_out.info.more_data = (caddr_t) &data;
855       data.bytes = myaddr;              /* Where to */
856       data.len   = len;                 /* How many (again, for XDR) */
857
858       /* XXX change second param to be a proc number */
859       status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out);
860     }
861
862   if (status)
863       error (rpcerr);
864   if (ptrace_out.status == -1)
865     {
866       return 0;         /* No bytes moved */
867     }
868   return len;           /* Moved *all* the bytes */
869 }
870
871 void
872 vx_files_info ()
873 {
874   printf ("\tAttached to host `%s'", vx_host);
875   printf (", which has %sfloating point", target_has_fp? "": "no ");
876   printf (".\n");
877 }
878
879 void
880 vx_run_files_info ()
881 {
882   printf ("\tRunning VxWorks process 0x%x, function `%s'.\n",
883           inferior_pid, vx_running);
884 }
885
886 void
887 vx_resume (step, siggnal)
888      int step;
889      int siggnal;
890 {
891   int status;
892   Rptrace ptrace_in;
893   Ptrace_return ptrace_out;
894
895   if (siggnal != 0)
896     error ("Cannot send signals to VxWorks processes");
897
898   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
899   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
900
901   ptrace_in.pid = inferior_pid;
902   ptrace_in.addr = 1;   /* Target side insists on this, or it panics.  */
903
904   /* XXX change second param to be a proc number */
905   status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT,
906                                  &ptrace_in, &ptrace_out);
907   if (status)
908       error (rpcerr);
909   if (ptrace_out.status == -1)
910     {
911       errno = ptrace_out.errno;
912       perror_with_name ("Resuming remote process");
913     }
914 }
915
916 void
917 vx_mourn_inferior ()
918 {
919   pop_target ();                /* Pop back to no-child state */
920   generic_mourn_inferior ();
921 }
922
923 \f
924 /* This function allows the addition of incrementally linked object files.  */
925
926 void
927 vx_add_file_command (arg_string, from_tty)
928      char* arg_string;
929      int from_tty;
930 {
931   CORE_ADDR text_addr;
932   CORE_ADDR data_addr;
933   CORE_ADDR bss_addr;
934   
935   if (arg_string == 0)
936     error ("add-file takes a file name in VxWorks");
937
938   arg_string = tilde_expand (arg_string);
939   make_cleanup (free, arg_string);
940
941   dont_repeat ();
942
943   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
944     error ("Load failed on target machine");
945
946   /* FIXME, for now we ignore data_addr and bss_addr.  */
947   symbol_file_add (arg_string, from_tty, text_addr, 0);
948 }
949
950 #ifdef FIXME  /* Not ready for prime time */
951 /* Single step the target program at the source or machine level.
952    Takes an error exit if rpc fails.
953    Returns -1 if remote single-step operation fails, else 0.  */
954
955 static int
956 net_step ()
957 {
958   enum clnt_stat status;
959   int step_status;
960   SOURCE_STEP source_step;
961
962   source_step.taskId = inferior_pid;
963
964   if (step_range_end)
965     {
966       source_step.startAddr = step_range_start;
967       source_step.endAddr = step_range_end;
968     }
969   else
970     {
971       source_step.startAddr = 0;
972       source_step.endAddr = 0;
973     }
974
975   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
976                           xdr_int, &step_status);
977
978   if (status == RPC_SUCCESS)
979     return step_status;
980   else 
981     error (rpcerr);
982 }
983 #endif
984
985 /* Emulate ptrace using RPC calls to the VxWorks target system.
986    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
987
988 static int
989 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
990     enum ptracereq request;
991     Rptrace *pPtraceIn;
992     Ptrace_return *pPtraceOut;
993 {
994   enum clnt_stat status;
995
996   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
997                           pPtraceOut);
998
999   if (status != RPC_SUCCESS)
1000       return -1;
1001
1002   return 0;
1003 }
1004
1005 /* Query the target for the name of the file from which VxWorks was
1006    booted.  pBootFile is the address of a pointer to the buffer to
1007    receive the file name; if the pointer pointed to by pBootFile is 
1008    NULL, memory for the buffer will be allocated by XDR.
1009    Returns -1 if rpc failed, 0 otherwise.  */
1010
1011 int
1012 net_get_boot_file (pBootFile)
1013      char **pBootFile;
1014 {
1015   enum clnt_stat status;
1016
1017   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
1018                           xdr_wrapstring, pBootFile);
1019   return (status == RPC_SUCCESS) ? 0 : -1;
1020 }
1021
1022 /* Fetch a list of loaded object modules from the VxWorks target.
1023    Returns -1 if rpc failed, 0 otherwise
1024    There's no way to check if the returned loadTable is correct.
1025    VxWorks doesn't check it.  */
1026
1027 int
1028 net_get_symbols (pLoadTable)
1029      ldtabl *pLoadTable;                /* return pointer to ldtabl here */
1030 {
1031   enum clnt_stat status;
1032
1033   bzero ((char *) pLoadTable, sizeof (struct ldtabl));
1034
1035   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
1036   return (status == RPC_SUCCESS) ? 0 : -1;
1037 }
1038
1039 /* Look up a symbol in the VxWorks target's symbol table.
1040    Returns status of symbol read on target side (0=success, -1=fail)
1041    Returns -1 and complain()s if rpc fails.  */
1042
1043 struct complaint cant_contact_target =
1044   {"Lost contact with VxWorks target", 0, 0};
1045
1046 int
1047 vx_lookup_symbol (name, pAddr)
1048      char *name;                /* symbol name */
1049      CORE_ADDR *pAddr;
1050 {
1051   enum clnt_stat status;
1052   SYMBOL_ADDR symbolAddr;
1053
1054   *pAddr = 0;
1055   bzero ((char *) &symbolAddr, sizeof (symbolAddr));
1056
1057   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
1058                           xdr_SYMBOL_ADDR, &symbolAddr);
1059   if (status != RPC_SUCCESS) {
1060       complain (&cant_contact_target, 0);
1061       return -1;
1062   }
1063
1064   *pAddr = symbolAddr.addr;
1065   return symbolAddr.status;
1066 }
1067
1068 /* Check to see if the VxWorks target has a floating point coprocessor.
1069    Returns 1 if target has floating point processor, 0 otherwise.
1070    Calls error() if rpc fails.  */
1071
1072 int
1073 net_check_for_fp ()
1074 {
1075   enum clnt_stat status;
1076   bool_t fp = 0;        /* true if fp processor is present on target board */
1077
1078   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
1079   if (status != RPC_SUCCESS)
1080       error (rpcerr);
1081
1082    return (int) fp;
1083 }
1084
1085 /* Establish an RPC connection with the VxWorks target system.
1086    Calls error () if unable to establish connection.  */
1087
1088 void
1089 net_connect (host)
1090      char *host;
1091 {
1092   struct sockaddr_in destAddr;
1093   struct hostent *destHost;
1094
1095   /* get the internet address for the given host */
1096
1097   if ((destHost = (struct hostent *) gethostbyname (host)) == NULL)
1098       error ("Invalid hostname.  Couldn't attach remote target.");
1099
1100   bzero (&destAddr, sizeof (destAddr));
1101
1102   destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr;
1103   destAddr.sin_family      = AF_INET;
1104   destAddr.sin_port        = 0; /* set to actual port that remote
1105                                    ptrace is listening on.  */
1106
1107   /* Create a tcp client transport on which to issue
1108      calls to the remote ptrace server.  */
1109
1110   ptraceSock = RPC_ANYSOCK;
1111   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
1112   /* FIXME, here is where we deal with different version numbers of the proto */
1113   
1114   if (pClient == NULL)
1115     {
1116       clnt_pcreateerror ("\tnet_connect");
1117       error ("Couldn't connect to remote target.");
1118     }
1119 }
1120 \f
1121 /* Sleep for the specified number of milliseconds 
1122  * (assumed to be less than 1000).
1123  * If select () is interrupted, returns immediately;
1124  * takes an error exit if select () fails for some other reason.
1125  */
1126
1127 static void
1128 sleep_ms (ms)
1129      long ms;
1130 {
1131   struct timeval select_timeout;
1132   int status;
1133
1134   select_timeout.tv_sec = 0;
1135   select_timeout.tv_usec = ms * 1000;
1136
1137   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout);
1138
1139   if (status < 0 && errno != EINTR)
1140     perror_with_name ("select");
1141 }
1142
1143 /* Wait for control to return from inferior to debugger.
1144    If inferior gets a signal, we may decide to start it up again
1145    instead of returning.  That is why there is a loop in this function.
1146    When this function actually returns it means the inferior
1147    should be left stopped and GDB should read more commands.  */
1148
1149 /* For network debugging with VxWorks.
1150  * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc,
1151  * so vx_wait() receives this information directly from
1152  * VxWorks instead of trying to figure out what happenned via a wait() call.
1153  */
1154
1155 static int
1156 vx_wait (status)
1157      int *status;
1158 {
1159   register int pid;
1160   WAITTYPE w;
1161   RDB_EVENT rdbEvent;
1162   int quit_failed;
1163
1164   do
1165     {
1166       /* If CTRL-C is hit during this loop,
1167          suspend the inferior process.  */
1168
1169       quit_failed = 0;
1170       if (quit_flag)
1171         {
1172           quit_failed = (net_quit () == -1);
1173           quit_flag = 0;
1174         }
1175
1176       /* If a net_quit () or net_wait () call has failed,
1177          allow the user to break the connection with the target.
1178          We can't simply error () out of this loop, since the 
1179          data structures representing the state of the inferior
1180          are in an inconsistent state.  */
1181
1182       if (quit_failed || net_wait (&rdbEvent) == -1)
1183         {
1184           terminal_ours ();
1185           if (query ("Can't %s.  Disconnect from target system? ",
1186                      (quit_failed) ? "suspend remote task"
1187                                    : "get status of remote task"))
1188             {
1189               target_mourn_inferior();
1190               error ("Use the \"target\" command to reconnect.");
1191             }
1192           else
1193             {
1194               terminal_inferior ();
1195               continue;
1196             }
1197         }
1198       
1199
1200       if (quit_failed || net_wait (&rdbEvent) == -1)
1201         {
1202           error ("Wait on remote target failed");
1203         }
1204       
1205       pid = rdbEvent.taskId;
1206       if (pid == 0)
1207         {
1208           sleep_ms (200);       /* FIXME Don't kill the network too badly */
1209         }
1210       else if (pid != inferior_pid)
1211         fatal ("Bad pid for debugged task: 0x%x\n", pid);
1212     } while (pid == 0);
1213
1214   /* FIXME, eventually do more then SIGTRAP on everything...  */
1215   switch (rdbEvent.eventType)
1216     {
1217     case EVENT_EXIT:
1218       WSETEXIT (w, 0);
1219       /* FIXME is it possible to distinguish between a
1220          XXX   normal vs abnormal exit in VxWorks? */
1221       break;
1222
1223     case EVENT_START:
1224       WSETSTOP (w, SIGTRAP);
1225       break;
1226
1227     case EVENT_STOP:
1228       WSETSTOP (w, SIGTRAP);
1229       /* XXX was it stopped by a signal?  act accordingly */
1230       break;
1231
1232     case EVENT_BREAK:
1233         /* Expecting a trace trap.  Stop the inferior and
1234          * return silently when it happens.  */
1235       WSETSTOP (w, SIGTRAP);
1236       break;
1237
1238     case EVENT_SUSPEND:
1239       target_terminal_ours_for_output ();
1240       printf ("\nRemote task suspended\n");  /* FIXME */
1241       fflush (stdout);
1242       WSETSTOP (w, SIGTRAP);
1243       break;
1244
1245     case EVENT_SIGNAL:
1246       /* The target is not running Unix, and its
1247          faults/traces do not map nicely into Unix signals.
1248          Make sure they do not get confused with Unix signals
1249          by numbering them with values higher than the highest
1250          legal Unix signal.  code in the arch-dependent PRINT_RANDOM_SIGNAL
1251          routine will interpret the value for wait_for_inferior.  */
1252       WSETSTOP (w, rdbEvent.sigType + NSIG);
1253       break;
1254     } /* switch */
1255   *status = *(int *)&w;         /* Grumble union wait crap Grumble */
1256   return pid;
1257 }
1258 \f
1259 static int
1260 symbol_stub (arg)
1261      int arg;
1262 {
1263   char *bootFile = (char *)arg;
1264   symbol_file_command (bootFile, 0);
1265   return 1;
1266 }
1267
1268 static int
1269 add_symbol_stub (arg)
1270      int arg;
1271 {
1272   struct ldfile *pLoadFile = (struct ldfile *)arg;
1273
1274   symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0);
1275   return 1;
1276 }
1277 /* Target command for VxWorks target systems.
1278
1279    Used in vxgdb.  Takes the name of a remote target machine
1280    running vxWorks and connects to it to initialize remote network
1281    debugging.  */
1282
1283 static void
1284 vx_open (args, from_tty)
1285      char *args;
1286      int from_tty;
1287 {
1288   extern int close ();
1289   char *bootFile;
1290   extern char *source_path;
1291   struct ldtabl loadTable;
1292   struct ldfile *pLoadFile;
1293   int i;
1294   extern CLIENT *pClient;
1295
1296   if (!args)
1297     error_no_arg ("target machine name");
1298
1299   target_preopen ();
1300   
1301   printf ("Attaching remote machine across net...\n");
1302   fflush (stdout);
1303
1304   /* Allow the user to kill the connect attempt by typing ^C.
1305      Wait until the call to target_has_fp () completes before
1306      disallowing an immediate quit, since even if net_connect ()
1307      is successful, the remote debug server might be hung.  */
1308
1309   immediate_quit++;
1310
1311   net_connect (args);
1312   target_has_fp = net_check_for_fp ();
1313   printf_filtered ("Connected to %s\n", args);
1314
1315   immediate_quit--;
1316
1317   push_target (&vx_ops);
1318
1319   /* Save a copy of the target host's name.  */
1320   if (vx_host)
1321     free (vx_host);
1322   vx_host = savestring (args, strlen (args));
1323
1324   /* Find out the name of the file from which the target was booted
1325      and load its symbol table.  */
1326
1327   bootFile = NULL;
1328   if (!net_get_boot_file (&bootFile))
1329     {
1330       if (*bootFile) {
1331         printf_filtered ("%s: ", bootFile);
1332         if (catch_errors (symbol_stub, (int)bootFile,
1333                 "Error reading symbols from boot file"))
1334           puts_filtered ("ok\n");
1335       } else if (from_tty)
1336         printf ("VxWorks kernel symbols not loaded.\n");
1337     }
1338   else
1339     error ("Can't retrieve boot file name from target machine.");
1340
1341   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1342
1343   if (net_get_symbols (&loadTable) != 0)
1344     error ("Can't read loaded modules from target machine");
1345
1346   i = 0-1;
1347   while (++i < loadTable.tbl_size)
1348     {
1349     QUIT;       /* FIXME, avoids clnt_freeres below:  mem leak */
1350     pLoadFile = &loadTable.tbl_ent [i];
1351 #ifdef WRS_ORIG
1352   {
1353     register int desc;
1354     struct cleanup *old_chain;
1355     char *fullname = NULL;
1356
1357     desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1358     if (desc < 0)
1359         perror_with_name (pLoadFile->name);
1360     old_chain = make_cleanup (close, desc);
1361     add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1362                       pLoadFile->bss_addr);
1363     do_cleanups (old_chain);
1364   }
1365 #else
1366     /* Botches, FIXME:
1367        (1)  Searches the PATH, not the source path.
1368        (2)  data and bss are assumed to be at the usual offsets from text.  */
1369     catch_errors (add_symbol_stub, (int)pLoadFile,
1370         "Error in reading symbols from loaded module.");
1371 #endif
1372     }
1373
1374   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1375
1376   if (from_tty)
1377     {
1378       puts_filtered ("Success!\n");
1379     }
1380 }
1381 \f
1382 /* Cross-net conversion of floats to and from extended form.
1383    (This is needed because different target machines have different
1384     extended floating point formats.)  */
1385
1386 /* Convert from an extended float to a double.
1387
1388    The extended float is stored as raw data pointed to by FROM.
1389    Return the converted value as raw data in the double pointed to by TO.
1390 */
1391
1392 static void
1393 vx_convert_to_virtual (regno, from, to)
1394     int regno;
1395     char *from;
1396     char *to;
1397 {
1398   enum clnt_stat status;
1399   ext_fp from_ext_fp;
1400   double to_double;
1401
1402   if (REGISTER_CONVERTIBLE (regno)) 
1403     {
1404       if (!target_has_fp) {
1405         *(double *)to = 0.0;    /* Skip the trouble if no float anyway */
1406         return;
1407       }
1408       bcopy (from, (char *) &from_ext_fp, sizeof (from_ext_fp));
1409       bzero ((char *) &to_double, sizeof (to_double));
1410
1411       status = net_clnt_call (VX_CONV_FROM_68881, xdr_ext_fp, &from_ext_fp,
1412                               xdr_double, &to_double);
1413       if (status == RPC_SUCCESS)
1414           bcopy ((char *) &to_double, to, sizeof (to_double));
1415       else
1416           error (rpcerr);
1417     }
1418   else
1419     bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno));
1420 }
1421
1422
1423 /* The converse:  convert from a double to an extended float.
1424
1425    The double is stored as raw data pointed to by FROM.
1426    Return the converted value as raw data in the extended
1427    float pointed to by TO.
1428 */
1429
1430 static void
1431 vx_convert_from_virtual (regno, from, to)
1432     int regno;
1433     char *from;
1434     char *to;
1435 {
1436   enum clnt_stat status;
1437   ext_fp to_ext_fp;
1438   double from_double;
1439
1440   if (REGISTER_CONVERTIBLE (regno)) 
1441     {
1442       if (!target_has_fp) {
1443         bzero (to, REGISTER_RAW_SIZE (FP0_REGNUM));     /* Shrug */
1444         return;
1445       }
1446       bcopy (from, (char *) &from_double, sizeof (from_double));
1447       bzero ((char *) &to_ext_fp, sizeof (to_ext_fp));
1448
1449       status = net_clnt_call (VX_CONV_TO_68881, xdr_double, &from_double,
1450                               xdr_ext_fp, &to_ext_fp);
1451       if (status == RPC_SUCCESS)
1452           bcopy ((char *) &to_ext_fp, to, sizeof (to_ext_fp));
1453       else
1454           error (rpcerr);
1455     }
1456   else
1457     bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno));
1458 }
1459 \f
1460 /* Make an RPC call to the VxWorks target.
1461    Returns RPC status.  */
1462
1463 static enum clnt_stat
1464 net_clnt_call (procNum, inProc, in, outProc, out)
1465     enum ptracereq procNum;
1466     xdrproc_t inProc;
1467     char *in;
1468     xdrproc_t outProc;
1469     char *out;
1470 {
1471   enum clnt_stat status;
1472   
1473   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1474
1475   if (status != RPC_SUCCESS)
1476       clnt_perrno (status);
1477
1478   return status;
1479 }
1480
1481 /* A vxprocess target should be started via "run" not "target".  */
1482 /*ARGSUSED*/
1483 static void
1484 vx_proc_open (name, from_tty)
1485      char *name;
1486      int from_tty;
1487 {
1488   error ("Use the \"run\" command to start a VxWorks process.");
1489 }
1490
1491
1492 /* Target ops structure for accessing memory and such over the net */
1493
1494 struct target_ops vx_ops = {
1495         "vxworks", "VxWorks target memory via RPC over TCP/IP",
1496         "Use VxWorks target memory.  \n\
1497 Specify the name of the machine to connect to.",
1498         vx_open, 0, /* vx_detach, */
1499         0, 0, /* resume, wait */
1500         0, 0, /* read_reg, write_reg */
1501         0, vx_convert_to_virtual, vx_convert_from_virtual,  /* prep_to_store, */
1502         vx_xfer_memory, vx_files_info,
1503         0, 0, /* insert_breakpoint, remove_breakpoint */
1504         0, 0, 0, 0, 0,  /* terminal stuff */
1505         0, /* vx_kill, */
1506         vx_add_file_command,
1507         call_function_by_hand,  /* FIXME, calling fns is maybe botched? */
1508         vx_lookup_symbol,
1509         vx_create_inferior, 0,  /* mourn_inferior */
1510         core_stratum, 0, /* next */
1511         1, 1, 0, 0, 0,  /* all mem, mem, stack, regs, exec */
1512         OPS_MAGIC,              /* Always the last thing */
1513 };
1514
1515 /* Target ops structure for accessing VxWorks child processes over the net */
1516
1517 struct target_ops vx_run_ops = {
1518         "vxprocess", "VxWorks process",
1519         "VxWorks process, started by the \"run\" command.",
1520         vx_proc_open, 0, /* vx_detach, */
1521         vx_resume, vx_wait,
1522         vx_read_register, vx_write_register,
1523         vx_prepare_to_store, vx_convert_to_virtual, vx_convert_from_virtual,
1524         vx_xfer_memory, vx_run_files_info,
1525         vx_insert_breakpoint, vx_remove_breakpoint,
1526         0, 0, 0, 0, 0,  /* terminal stuff */
1527         0, /* vx_kill, */
1528         vx_add_file_command,
1529         call_function_by_hand,  /* FIXME, calling fns is maybe botched? */
1530         vx_lookup_symbol,
1531         vx_create_inferior, vx_mourn_inferior,
1532         process_stratum, 0, /* next */
1533         1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
1534         OPS_MAGIC,              /* Always the last thing */
1535 };
1536 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1537 \f
1538 void
1539 _initialize_vx ()
1540 {
1541   add_target (&vx_ops);
1542   add_target (&vx_run_ops);
1543 }
This page took 0.106144 seconds and 4 git commands to generate.