* vx-share/{reg.h,xdr_regs.h,xdr_regs.c}: Remove, unused.
[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 "defs.h"
22 #include "frame.h"
23 #include "inferior.h"
24 #include "wait.h"
25 #include "target.h"
26 #include "gdbcore.h"
27 #include "command.h"
28 #include "symtab.h"
29 #include "symfile.h"            /* for struct complaint */
30
31 #include <string.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #define malloc bogon_malloc     /* Sun claims "char *malloc()" not void * */
38 #define free bogon_free         /* Sun claims "int free()" not void */
39 #define realloc bogon_realloc   /* Sun claims "char *realloc()", not void * */
40 #include <rpc/rpc.h>
41 #undef malloc
42 #undef free
43 #undef realloc
44 #include <sys/time.h>           /* UTek's <rpc/rpc.h> doesn't #incl this */
45 #include <netdb.h>
46 #include "vx-share/ptrace.h"
47 #include "vx-share/xdr_ptrace.h"
48 #include "vx-share/xdr_ld.h"
49 #include "vx-share/xdr_rdb.h"
50 #include "vx-share/dbgRpcLib.h"
51
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 == 0)        /* 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 static 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 static 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 static 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 static 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 static 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 static void
370 vx_read_register (regno)
371      int regno;
372 {
373   int status;
374   Rptrace ptrace_in;
375   Ptrace_return ptrace_out;
376   C_bytes in_data;
377   C_bytes out_data;
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) &out_data;
388 #ifndef I80960
389   out_data.len   = 18 * REGISTER_RAW_SIZE (0);          /* FIXME 68k hack */
390 #else
391   out_data.len = (16 + 16 + 3) * REGISTER_RAW_SIZE (0);
392 #endif
393   out_data.bytes = (caddr_t) registers;
394   
395   status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out);
396   if (status)
397     error (rpcerr);
398   if (ptrace_out.status == -1)
399     {
400       errno = ptrace_out.errno;
401       perror_with_name ("net_ptrace_clnt_call(PTRACE_GETREGS)");
402     }
403   
404 #ifdef I80960
405
406   {
407     /* If the target has floating point registers, fetch them.
408        Otherwise, zero the floating point register values in
409        registers[] for good measure, even though we might not
410        need to.  */
411     /* @@ Can't use this -- the rdb library for the 960 target
412        doesn't support setting or retrieving FP regs.  KR  */
413 #if 0
414     struct fp_status inferior_fp_registers;
415
416     if (target_has_fp)
417       {
418         ptrace_in.pid = inferior_pid;
419         ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers;
420         status = net_ptrace_clnt_call (PTRACE_GETFPREGS,
421                                        &ptrace_in, &ptrace_out);
422         if (status)
423           error (rpcerr);
424         if (ptrace_out.status == -1)
425           {
426             errno = ptrace_out.errno;
427             perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
428           }
429
430         bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
431                REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
432       }
433     else
434       {
435         bzero ((char *) &registers[REGISTER_BYTE (FP0_REGNUM)],
436                REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
437       }
438 #endif
439   }
440 #else  /* not 960, thus must be 68000:  FIXME!  */
441
442   if (target_has_fp)
443     {
444       ptrace_in.pid = inferior_pid;
445       ptrace_out.info.more_data = (caddr_t) &out_data;
446       out_data.len   =  8 * REGISTER_RAW_SIZE (FP0_REGNUM)      /* FIXME */
447                      + (3 * sizeof (REGISTER_TYPE));
448       out_data.bytes = (caddr_t) &registers[REGISTER_BYTE (FP0_REGNUM)];
449   
450       status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
451       if (status)
452         error (rpcerr);
453       if (ptrace_out.status == -1)
454         {
455           errno = ptrace_out.errno;
456           perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
457         }
458     }
459   else
460     {
461       bzero (&registers[REGISTER_BYTE (FP0_REGNUM)],
462              8 * REGISTER_RAW_SIZE (FP0_REGNUM));
463       bzero (&registers[REGISTER_BYTE (FPC_REGNUM)],
464              3 * sizeof (REGISTER_TYPE));
465     }
466 #endif  /* various architectures */
467 }
468
469 /* Prepare to store registers.  Since we will store all of them,
470    read out their current values now.  */
471
472 static void
473 vx_prepare_to_store ()
474 {
475   /* Fetch all registers, if any of them are not yet fetched.  */
476   read_register_bytes (0, NULL, REGISTER_BYTES);
477 }
478
479
480 /* Store our register values back into the inferior.
481    If REGNO is -1, do this for all registers.
482    Otherwise, REGNO specifies which register (so we can save time).  */
483    /* FIXME, look at REGNO to save time here */
484
485 static void
486 vx_write_register (regno)
487      int regno;
488 {
489   C_bytes in_data;
490   C_bytes out_data;
491   extern char registers[];
492   int status;
493   Rptrace ptrace_in;
494   Ptrace_return ptrace_out;
495
496   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
497   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
498
499   ptrace_in.pid = inferior_pid;
500   ptrace_in.info.ttype     = DATA;
501   ptrace_in.info.more_data = (caddr_t) &in_data;
502
503   in_data.bytes = registers;
504
505 #ifdef I80960
506
507   in_data.len = (16 + 16 + 3) * sizeof (REGISTER_TYPE);
508
509 #else  /* not 960 -- assume 68k -- FIXME */
510
511   in_data.len = 18 * sizeof (REGISTER_TYPE);
512
513 #endif  /* Different register sets */
514
515   /* XXX change second param to be a proc number */
516   status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out);
517   if (status)
518       error (rpcerr);
519   if (ptrace_out.status == -1)
520     {
521       errno = ptrace_out.errno;
522       perror_with_name ("net_ptrace_clnt_call(PTRACE_SETREGS)");
523     }
524
525   /* Store floating point registers if the target has them.  */
526
527   if (target_has_fp)
528     {
529       ptrace_in.pid = inferior_pid;
530       ptrace_in.info.ttype     = DATA;
531       ptrace_in.info.more_data = (caddr_t) &in_data;
532
533
534 #ifdef I80960
535 #if 0 /* @@ Not supported by target.  */
536       in_data.bytes = &registers[REGISTER_BYTE (FP0_REGNUM)];
537       in_data.len = 4 * REGISTER_RAW_SIZE (FP0_REGNUM);
538 #endif
539 #else  /* not 960 -- assume 68k -- FIXME */
540
541       in_data.bytes = &registers[REGISTER_BYTE (FP0_REGNUM)];
542       in_data.len = (8 * REGISTER_RAW_SIZE (FP0_REGNUM)
543                       + (3 * sizeof (REGISTER_TYPE)));
544
545 #endif  /* Different register sets */
546
547       status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out);
548       if (status)
549           error (rpcerr);
550       if (ptrace_out.status == -1)
551         {
552           errno = ptrace_out.errno;
553           perror_with_name ("net_ptrace_clnt_call(PTRACE_SETFPREGS)");
554         }
555     }
556 }
557
558 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
559    to debugger memory starting at MYADDR.  WRITE is true if writing to the
560    inferior.
561    Result is the number of bytes written or read (zero if error).  The
562    protocol allows us to return a negative count, indicating that we can't
563    handle the current address but can handle one N bytes further, but
564    vxworks doesn't give us that information.  */
565
566 static int
567 vx_xfer_memory (memaddr, myaddr, len, write, target)
568      CORE_ADDR memaddr;
569      char *myaddr;
570      int len;
571      int write;
572      struct target_ops *target;                 /* ignored */
573 {
574   int status;
575   Rptrace ptrace_in;
576   Ptrace_return ptrace_out;
577   C_bytes data;
578
579   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
580   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
581
582   ptrace_in.pid = inferior_pid;         /* XXX pid unnecessary for READDATA */
583   ptrace_in.addr = (int) memaddr;       /* Where from */
584   ptrace_in.data = len;                 /* How many bytes */
585
586   if (write)
587     {
588       ptrace_in.info.ttype     = DATA;
589       ptrace_in.info.more_data = (caddr_t) &data;
590
591       data.bytes = (caddr_t) myaddr;    /* Where from */
592       data.len   = len;                 /* How many bytes (again, for XDR) */
593
594       /* XXX change second param to be a proc number */
595       status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out);
596     }
597   else
598     {
599       ptrace_out.info.more_data = (caddr_t) &data;
600       data.bytes = myaddr;              /* Where to */
601       data.len   = len;                 /* How many (again, for XDR) */
602
603       /* XXX change second param to be a proc number */
604       status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out);
605     }
606
607   if (status)
608       error (rpcerr);
609   if (ptrace_out.status == -1)
610     {
611       return 0;         /* No bytes moved */
612     }
613   return len;           /* Moved *all* the bytes */
614 }
615
616 static void
617 vx_files_info ()
618 {
619   printf ("\tAttached to host `%s'", vx_host);
620   printf (", which has %sfloating point", target_has_fp? "": "no ");
621   printf (".\n");
622 }
623
624 static void
625 vx_run_files_info ()
626 {
627   printf ("\tRunning %s VxWorks process %s", 
628           vx_running? "child": "attached",
629           local_hex_string(inferior_pid));
630   if (vx_running)
631     printf (", function `%s'", vx_running);
632   printf(".\n");
633 }
634
635 static void
636 vx_resume (step, siggnal)
637      int step;
638      int siggnal;
639 {
640   int status;
641   Rptrace ptrace_in;
642   Ptrace_return ptrace_out;
643
644   if (siggnal != 0 && siggnal != stop_signal)
645     error ("Cannot send signals to VxWorks processes");
646
647   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
648   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
649
650   ptrace_in.pid = inferior_pid;
651   ptrace_in.addr = 1;   /* Target side insists on this, or it panics.  */
652
653   /* XXX change second param to be a proc number */
654   status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT,
655                                  &ptrace_in, &ptrace_out);
656   if (status)
657       error (rpcerr);
658   if (ptrace_out.status == -1)
659     {
660       errno = ptrace_out.errno;
661       perror_with_name ("Resuming remote process");
662     }
663 }
664
665 static void
666 vx_mourn_inferior ()
667 {
668   pop_target ();                /* Pop back to no-child state */
669   generic_mourn_inferior ();
670 }
671
672 \f
673 /* This function allows the addition of incrementally linked object files.  */
674
675 static void
676 vx_load_command (arg_string, from_tty)
677      char* arg_string;
678      int from_tty;
679 {
680   CORE_ADDR text_addr;
681   CORE_ADDR data_addr;
682   CORE_ADDR bss_addr;
683   
684   if (arg_string == 0)
685     error ("The load command takes a file name");
686
687   arg_string = tilde_expand (arg_string);
688   make_cleanup (free, arg_string);
689
690   dont_repeat ();
691
692   QUIT;
693   immediate_quit++;
694   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
695     error ("Load failed on target machine");
696   immediate_quit--;
697
698   /* FIXME, for now we ignore data_addr and bss_addr.  */
699   symbol_file_add (arg_string, from_tty, text_addr, 0, 0, 0);
700 }
701
702 #ifdef FIXME  /* Not ready for prime time */
703 /* Single step the target program at the source or machine level.
704    Takes an error exit if rpc fails.
705    Returns -1 if remote single-step operation fails, else 0.  */
706
707 static int
708 net_step ()
709 {
710   enum clnt_stat status;
711   int step_status;
712   SOURCE_STEP source_step;
713
714   source_step.taskId = inferior_pid;
715
716   if (step_range_end)
717     {
718       source_step.startAddr = step_range_start;
719       source_step.endAddr = step_range_end;
720     }
721   else
722     {
723       source_step.startAddr = 0;
724       source_step.endAddr = 0;
725     }
726
727   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
728                           xdr_int, &step_status);
729
730   if (status == RPC_SUCCESS)
731     return step_status;
732   else 
733     error (rpcerr);
734 }
735 #endif
736
737 /* Emulate ptrace using RPC calls to the VxWorks target system.
738    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
739
740 static int
741 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
742     enum ptracereq request;
743     Rptrace *pPtraceIn;
744     Ptrace_return *pPtraceOut;
745 {
746   enum clnt_stat status;
747
748   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
749                           pPtraceOut);
750
751   if (status != RPC_SUCCESS)
752       return -1;
753
754   return 0;
755 }
756
757 /* Query the target for the name of the file from which VxWorks was
758    booted.  pBootFile is the address of a pointer to the buffer to
759    receive the file name; if the pointer pointed to by pBootFile is 
760    NULL, memory for the buffer will be allocated by XDR.
761    Returns -1 if rpc failed, 0 otherwise.  */
762
763 static int
764 net_get_boot_file (pBootFile)
765      char **pBootFile;
766 {
767   enum clnt_stat status;
768
769   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
770                           xdr_wrapstring, pBootFile);
771   return (status == RPC_SUCCESS) ? 0 : -1;
772 }
773
774 /* Fetch a list of loaded object modules from the VxWorks target.
775    Returns -1 if rpc failed, 0 otherwise
776    There's no way to check if the returned loadTable is correct.
777    VxWorks doesn't check it.  */
778
779 static int
780 net_get_symbols (pLoadTable)
781      ldtabl *pLoadTable;                /* return pointer to ldtabl here */
782 {
783   enum clnt_stat status;
784
785   bzero ((char *) pLoadTable, sizeof (struct ldtabl));
786
787   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
788   return (status == RPC_SUCCESS) ? 0 : -1;
789 }
790
791 /* Look up a symbol in the VxWorks target's symbol table.
792    Returns status of symbol read on target side (0=success, -1=fail)
793    Returns -1 and complain()s if rpc fails.  */
794
795 struct complaint cant_contact_target =
796   {"Lost contact with VxWorks target", 0, 0};
797
798 static int
799 vx_lookup_symbol (name, pAddr)
800      char *name;                /* symbol name */
801      CORE_ADDR *pAddr;
802 {
803   enum clnt_stat status;
804   SYMBOL_ADDR symbolAddr;
805
806   *pAddr = 0;
807   bzero ((char *) &symbolAddr, sizeof (symbolAddr));
808
809   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
810                           xdr_SYMBOL_ADDR, &symbolAddr);
811   if (status != RPC_SUCCESS) {
812       complain (&cant_contact_target, 0);
813       return -1;
814   }
815
816   *pAddr = symbolAddr.addr;
817   return symbolAddr.status;
818 }
819
820 /* Check to see if the VxWorks target has a floating point coprocessor.
821    Returns 1 if target has floating point processor, 0 otherwise.
822    Calls error() if rpc fails.  */
823
824 static int
825 net_check_for_fp ()
826 {
827   enum clnt_stat status;
828   bool_t fp = 0;        /* true if fp processor is present on target board */
829
830   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
831   if (status != RPC_SUCCESS)
832       error (rpcerr);
833
834    return (int) fp;
835 }
836
837 /* Establish an RPC connection with the VxWorks target system.
838    Calls error () if unable to establish connection.  */
839
840 static void
841 net_connect (host)
842      char *host;
843 {
844   struct sockaddr_in destAddr;
845   struct hostent *destHost;
846
847   /* get the internet address for the given host */
848
849   if ((destHost = (struct hostent *) gethostbyname (host)) == NULL)
850       error ("Invalid hostname.  Couldn't find remote host address.");
851
852   bzero (&destAddr, sizeof (destAddr));
853
854   destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr;
855   destAddr.sin_family      = AF_INET;
856   destAddr.sin_port        = 0; /* set to actual port that remote
857                                    ptrace is listening on.  */
858
859   /* Create a tcp client transport on which to issue
860      calls to the remote ptrace server.  */
861
862   ptraceSock = RPC_ANYSOCK;
863   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
864   /* FIXME, here is where we deal with different version numbers of the proto */
865   
866   if (pClient == NULL)
867     {
868       clnt_pcreateerror ("\tnet_connect");
869       error ("Couldn't connect to remote target.");
870     }
871 }
872 \f
873 /* Sleep for the specified number of milliseconds 
874  * (assumed to be less than 1000).
875  * If select () is interrupted, returns immediately;
876  * takes an error exit if select () fails for some other reason.
877  */
878
879 static void
880 sleep_ms (ms)
881      long ms;
882 {
883   struct timeval select_timeout;
884   int status;
885
886   select_timeout.tv_sec = 0;
887   select_timeout.tv_usec = ms * 1000;
888
889   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout);
890
891   if (status < 0 && errno != EINTR)
892     perror_with_name ("select");
893 }
894
895 /* Wait for control to return from inferior to debugger.
896    If inferior gets a signal, we may decide to start it up again
897    instead of returning.  That is why there is a loop in this function.
898    When this function actually returns it means the inferior
899    should be left stopped and GDB should read more commands.  */
900
901 /* For network debugging with VxWorks.
902  * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc,
903  * so vx_wait() receives this information directly from
904  * VxWorks instead of trying to figure out what happenned via a wait() call.
905  */
906
907 static int
908 vx_wait (status)
909      int *status;
910 {
911   register int pid;
912   WAITTYPE w;
913   RDB_EVENT rdbEvent;
914   int quit_failed;
915
916   do
917     {
918       /* If CTRL-C is hit during this loop,
919          suspend the inferior process.  */
920
921       quit_failed = 0;
922       if (quit_flag)
923         {
924           quit_failed = (net_quit () == -1);
925           quit_flag = 0;
926         }
927
928       /* If a net_quit () or net_wait () call has failed,
929          allow the user to break the connection with the target.
930          We can't simply error () out of this loop, since the 
931          data structures representing the state of the inferior
932          are in an inconsistent state.  */
933
934       if (quit_failed || net_wait (&rdbEvent) == -1)
935         {
936           terminal_ours ();
937           if (query ("Can't %s.  Disconnect from target system? ",
938                      (quit_failed) ? "suspend remote task"
939                                    : "get status of remote task"))
940             {
941               target_mourn_inferior();
942               error ("Use the \"target\" command to reconnect.");
943             }
944           else
945             {
946               terminal_inferior ();
947               continue;
948             }
949         }
950       
951       pid = rdbEvent.taskId;
952       if (pid == 0)
953         {
954           sleep_ms (200);       /* FIXME Don't kill the network too badly */
955         }
956       else if (pid != inferior_pid)
957         fatal ("Bad pid for debugged task: %s\n", local_hex_string(pid));
958     } while (pid == 0);
959
960   /* FIXME, eventually do more then SIGTRAP on everything...  */
961   switch (rdbEvent.eventType)
962     {
963     case EVENT_EXIT:
964       WSETEXIT (w, 0);
965       /* FIXME is it possible to distinguish between a
966          XXX   normal vs abnormal exit in VxWorks? */
967       break;
968
969     case EVENT_START:           /* Task was just started. */
970       WSETSTOP (w, SIGTRAP);
971       break;
972
973     case EVENT_STOP:
974       WSETSTOP (w, SIGTRAP);
975       /* XXX was it stopped by a signal?  act accordingly */
976       break;
977
978     case EVENT_BREAK:           /* Breakpoint was hit. */
979       WSETSTOP (w, SIGTRAP);
980       break;
981
982     case EVENT_SUSPEND:         /* Task was suspended, probably by ^C. */
983       WSETSTOP (w, SIGINT);
984       break;
985
986     case EVENT_BUS_ERR:         /* Task made evil nasty reference. */
987       WSETSTOP (w, SIGBUS);
988       break;
989
990     case EVENT_ZERO_DIV:        /* Division by zero */
991       WSETSTOP (w, SIGFPE);     /* Like Unix, call it a float exception. */
992       break;
993
994     case EVENT_SIGNAL:
995       /* The target is not running Unix, and its
996          faults/traces do not map nicely into Unix signals.
997          Make sure they do not get confused with Unix signals
998          by numbering them with values higher than the highest
999          legal Unix signal.  code in the arch-dependent PRINT_RANDOM_SIGNAL
1000          routine will interpret the value for wait_for_inferior.  */
1001       WSETSTOP (w, rdbEvent.sigType + NSIG);
1002       break;
1003     } /* switch */
1004   *status = *(int *)&w;         /* Grumble union wait crap Grumble */
1005   return pid;
1006 }
1007 \f
1008 static int
1009 symbol_stub (arg)
1010      char *arg;
1011 {
1012   symbol_file_command (arg, 0);
1013   return 1;
1014 }
1015
1016 static int
1017 add_symbol_stub (arg)
1018      char *arg;
1019 {
1020   struct ldfile *pLoadFile = (struct ldfile *)arg;
1021
1022   printf("\t%s: ", pLoadFile->name);
1023   symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0, 0, 0);
1024   printf ("ok\n");
1025   return 1;
1026 }
1027 /* Target command for VxWorks target systems.
1028
1029    Used in vxgdb.  Takes the name of a remote target machine
1030    running vxWorks and connects to it to initialize remote network
1031    debugging.  */
1032
1033 static void
1034 vx_open (args, from_tty)
1035      char *args;
1036      int from_tty;
1037 {
1038   extern int close ();
1039   char *bootFile;
1040   extern char *source_path;
1041   struct ldtabl loadTable;
1042   struct ldfile *pLoadFile;
1043   int i;
1044   extern CLIENT *pClient;
1045
1046   if (!args)
1047     error_no_arg ("target machine name");
1048
1049   target_preopen (from_tty);
1050   
1051   unpush_target (&vx_ops);
1052   printf ("Attaching remote machine across net...\n");
1053   fflush (stdout);
1054
1055   /* Allow the user to kill the connect attempt by typing ^C.
1056      Wait until the call to target_has_fp () completes before
1057      disallowing an immediate quit, since even if net_connect ()
1058      is successful, the remote debug server might be hung.  */
1059
1060   immediate_quit++;
1061
1062   net_connect (args);
1063   target_has_fp = net_check_for_fp ();
1064   printf_filtered ("Connected to %s.\n", args);
1065
1066   immediate_quit--;
1067
1068   push_target (&vx_ops);
1069
1070   /* Save a copy of the target host's name.  */
1071   vx_host = savestring (args, strlen (args));
1072
1073   /* Find out the name of the file from which the target was booted
1074      and load its symbol table.  */
1075
1076   printf_filtered ("Looking in Unix path for all loaded modules:\n");
1077   bootFile = NULL;
1078   if (!net_get_boot_file (&bootFile))
1079     {
1080       if (*bootFile) {
1081         printf_filtered ("\t%s: ", bootFile);
1082         if (catch_errors (symbol_stub, bootFile,
1083                 "Error while reading symbols from boot file:\n"))
1084           puts_filtered ("ok\n");
1085       } else if (from_tty)
1086         printf ("VxWorks kernel symbols not loaded.\n");
1087     }
1088   else
1089     error ("Can't retrieve boot file name from target machine.");
1090
1091   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1092
1093   if (net_get_symbols (&loadTable) != 0)
1094     error ("Can't read loaded modules from target machine");
1095
1096   i = 0-1;
1097   while (++i < loadTable.tbl_size)
1098     {
1099       QUIT;     /* FIXME, avoids clnt_freeres below:  mem leak */
1100       pLoadFile = &loadTable.tbl_ent [i];
1101 #ifdef WRS_ORIG
1102   {
1103     register int desc;
1104     struct cleanup *old_chain;
1105     char *fullname = NULL;
1106
1107     desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1108     if (desc < 0)
1109         perror_with_name (pLoadFile->name);
1110     old_chain = make_cleanup (close, desc);
1111     add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1112                       pLoadFile->bss_addr);
1113     do_cleanups (old_chain);
1114   }
1115 #else
1116       /* Botches, FIXME:
1117          (1)  Searches the PATH, not the source path.
1118          (2)  data and bss are assumed to be at the usual offsets from text.  */
1119       catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0);
1120 #endif
1121     }
1122   printf_filtered ("Done.\n");
1123
1124   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1125 }
1126 \f
1127 /* Takes a task started up outside of gdb and ``attaches'' to it.
1128    This stops it cold in its tracks and allows us to start tracing it.  */
1129
1130 static void
1131 vx_attach (args, from_tty)
1132      char *args;
1133      int from_tty;
1134 {
1135   int pid;
1136   char *cptr = 0;
1137   Rptrace ptrace_in;
1138   Ptrace_return ptrace_out;
1139   int status;
1140
1141   if (!args)
1142     error_no_arg ("process-id to attach");
1143
1144   pid = strtol (args, &cptr, 0);
1145   if ((cptr == args) || (*cptr != '\0'))
1146     error ("Invalid process-id -- give a single number in decimal or 0xhex");
1147
1148   if (from_tty)
1149       printf ("Attaching pid %s.\n", local_hex_string(pid));
1150
1151   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1152   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1153   ptrace_in.pid = pid;
1154
1155   status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1156   if (status == -1)
1157     error (rpcerr);
1158   if (ptrace_out.status == -1)
1159     {
1160       errno = ptrace_out.errno;
1161       perror_with_name ("Attaching remote process");
1162     }
1163
1164   /* It worked... */
1165   push_target (&vx_run_ops);
1166   inferior_pid = pid;
1167   vx_running = 0;
1168 }
1169
1170
1171 /* detach_command --
1172    takes a program previously attached to and detaches it.
1173    The program resumes execution and will no longer stop
1174    on signals, etc.  We better not have left any breakpoints
1175    in the program or it'll die when it hits one.  For this
1176    to work, it may be necessary for the process to have been
1177    previously attached.  It *might* work if the program was
1178    started via the normal ptrace (PTRACE_TRACEME).  */
1179
1180 static void
1181 vx_detach (args, from_tty)
1182      char *args;
1183      int from_tty;
1184 {
1185   Rptrace ptrace_in;
1186   Ptrace_return ptrace_out;
1187   int signal = 0;
1188   int status;
1189
1190   if (args)
1191     error ("Argument given to VxWorks \"detach\".");
1192
1193   if (from_tty)
1194       printf ("Detaching pid %s.\n", local_hex_string(inferior_pid));
1195
1196   if (args)             /* FIXME, should be possible to leave suspended */
1197     signal = atoi (args);
1198   
1199   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1200   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1201   ptrace_in.pid = inferior_pid;
1202
1203   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1204   if (status == -1)
1205     error (rpcerr);
1206   if (ptrace_out.status == -1)
1207     {
1208       errno = ptrace_out.errno;
1209       perror_with_name ("Detaching VxWorks process");
1210     }
1211
1212   inferior_pid = 0;
1213   pop_target ();        /* go back to non-executing VxWorks connection */
1214 }
1215
1216 /* vx_kill -- takes a running task and wipes it out.  */
1217
1218 static void
1219 vx_kill ()
1220 {
1221   Rptrace ptrace_in;
1222   Ptrace_return ptrace_out;
1223   int status;
1224
1225   printf ("Killing pid %s.\n", local_hex_string(inferior_pid));
1226
1227   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1228   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1229   ptrace_in.pid = inferior_pid;
1230
1231   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1232   if (status == -1)
1233     warning (rpcerr);
1234   else if (ptrace_out.status == -1)
1235     {
1236       errno = ptrace_out.errno;
1237       perror_with_name ("Killing VxWorks process");
1238     }
1239
1240   /* If it gives good status, the process is *gone*, no events remain.
1241      If the kill failed, assume the process is gone anyhow.  */
1242   inferior_pid = 0;
1243   pop_target ();        /* go back to non-executing VxWorks connection */
1244 }
1245
1246 /* Clean up from the VxWorks process target as it goes away.  */
1247
1248 static void
1249 vx_proc_close (quitting)
1250      int quitting;
1251 {
1252   inferior_pid = 0;             /* No longer have a process.  */
1253   if (vx_running)
1254     free (vx_running);
1255   vx_running = 0;
1256 }
1257 \f
1258 /* Make an RPC call to the VxWorks target.
1259    Returns RPC status.  */
1260
1261 static enum clnt_stat
1262 net_clnt_call (procNum, inProc, in, outProc, out)
1263     enum ptracereq procNum;
1264     xdrproc_t inProc;
1265     char *in;
1266     xdrproc_t outProc;
1267     char *out;
1268 {
1269   enum clnt_stat status;
1270   
1271   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1272
1273   if (status != RPC_SUCCESS)
1274       clnt_perrno (status);
1275
1276   return status;
1277 }
1278
1279 /* Clean up before losing control.  */
1280
1281 static void
1282 vx_close (quitting)
1283      int quitting;
1284 {
1285   if (pClient)
1286     clnt_destroy (pClient);     /* The net connection */
1287   pClient = 0;
1288
1289   if (vx_host)
1290     free (vx_host);             /* The hostname */
1291   vx_host = 0;
1292 }
1293
1294 /* A vxprocess target should be started via "run" not "target".  */
1295 /*ARGSUSED*/
1296 static void
1297 vx_proc_open (name, from_tty)
1298      char *name;
1299      int from_tty;
1300 {
1301   error ("Use the \"run\" command to start a VxWorks process.");
1302 }
1303
1304 /* Target ops structure for accessing memory and such over the net */
1305
1306 struct target_ops vx_ops = {
1307         "vxworks", "VxWorks target memory via RPC over TCP/IP",
1308         "Use VxWorks target memory.  \n\
1309 Specify the name of the machine to connect to.",
1310         vx_open, vx_close, vx_attach, 0, /* vx_detach, */
1311         0, 0, /* resume, wait */
1312         0, 0, /* read_reg, write_reg */
1313         0, /* prep_to_store, */
1314         vx_xfer_memory, vx_files_info,
1315         0, 0, /* insert_breakpoint, remove_breakpoint */
1316         0, 0, 0, 0, 0,  /* terminal stuff */
1317         0, /* vx_kill, */
1318         vx_load_command,
1319         vx_lookup_symbol,
1320         vx_create_inferior, 0,  /* mourn_inferior */
1321         0, /* can_run */
1322         0, /* notice_signals */
1323         core_stratum, 0, /* next */
1324         1, 1, 0, 0, 0,  /* all mem, mem, stack, regs, exec */
1325         0, 0,                   /* Section pointers */
1326         OPS_MAGIC,              /* Always the last thing */
1327 };
1328
1329 /* Target ops structure for accessing VxWorks child processes over the net */
1330
1331 struct target_ops vx_run_ops = {
1332         "vxprocess", "VxWorks process",
1333         "VxWorks process, started by the \"run\" command.",
1334         vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */
1335         vx_resume, vx_wait,
1336         vx_read_register, vx_write_register,
1337         vx_prepare_to_store,
1338         vx_xfer_memory, vx_run_files_info,
1339         vx_insert_breakpoint, vx_remove_breakpoint,
1340         0, 0, 0, 0, 0,  /* terminal stuff */
1341         vx_kill,
1342         vx_load_command,
1343         vx_lookup_symbol,
1344         0, vx_mourn_inferior,
1345         0,  /* can_run */
1346         0, /* notice_signals */
1347         process_stratum, 0, /* next */
1348         0, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
1349                         /* all_mem is off to avoid spurious msg in "i files" */
1350         0, 0,                   /* Section pointers */
1351         OPS_MAGIC,              /* Always the last thing */
1352 };
1353 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1354 \f
1355 void
1356 _initialize_vx ()
1357 {
1358   add_target (&vx_ops);
1359   add_target (&vx_run_ops);
1360 }