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