8f03268fae7851fbbc9aaa4806c5163ed392382f
[platform/upstream/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, 2001 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"
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.  TARGET is unused.
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 (CORE_ADDR memaddr, char *myaddr, int len, int write,
479                 struct mem_attrib *attrib ATTRIBUTE_UNUSED,
480                 struct target_ops *target ATTRIBUTE_UNUSED)
481 {
482   int status;
483   Rptrace ptrace_in;
484   Ptrace_return ptrace_out;
485   C_bytes data;
486   enum ptracereq request;
487   int nleft, nxfer;
488
489   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
490   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
491
492   ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */
493   ptrace_in.addr = (int) memaddr;       /* Where from */
494   ptrace_in.data = len;         /* How many bytes */
495
496   if (write)
497     {
498       ptrace_in.info.ttype = DATA;
499       ptrace_in.info.more_data = (caddr_t) & data;
500
501       data.bytes = (caddr_t) myaddr;    /* Where from */
502       data.len = len;           /* How many bytes (again, for XDR) */
503       request = PTRACE_WRITEDATA;
504     }
505   else
506     {
507       ptrace_out.info.more_data = (caddr_t) & data;
508       request = PTRACE_READDATA;
509     }
510   /* Loop until the entire request has been satisfied, transferring
511      at most VX_MEMXFER_MAX bytes per iteration.  Break from the loop
512      if an error status is returned by the remote debug server.  */
513
514   nleft = len;
515   status = 0;
516
517   while (nleft > 0 && status == 0)
518     {
519       nxfer = min (nleft, VX_MEMXFER_MAX);
520
521       ptrace_in.addr = (int) memaddr;
522       ptrace_in.data = nxfer;
523       data.bytes = (caddr_t) myaddr;
524       data.len = nxfer;
525
526       /* Request a block from the remote debug server; if RPC fails,
527          report an error and return to debugger command level.  */
528
529       if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out))
530         error (rpcerr);
531
532       status = ptrace_out.status;
533       if (status == 0)
534         {
535           memaddr += nxfer;
536           myaddr += nxfer;
537           nleft -= nxfer;
538         }
539       else
540         {
541           /* A target-side error has ocurred.  Set errno to the error
542              code chosen by the target so that a later perror () will
543              say something meaningful.  */
544
545           errno = ptrace_out.errno_num;
546         }
547     }
548
549   /* Return the number of bytes transferred.  */
550
551   return (len - nleft);
552 }
553
554 static void
555 vx_files_info (void)
556 {
557   printf_unfiltered ("\tAttached to host `%s'", vx_host);
558   printf_unfiltered (", which has %sfloating point", target_has_fp ? "" : "no ");
559   printf_unfiltered (".\n");
560 }
561
562 static void
563 vx_run_files_info (void)
564 {
565   printf_unfiltered ("\tRunning %s VxWorks process %s",
566                      vx_running ? "child" : "attached",
567                      local_hex_string (inferior_pid));
568   if (vx_running)
569     printf_unfiltered (", function `%s'", vx_running);
570   printf_unfiltered (".\n");
571 }
572
573 static void
574 vx_resume (int pid, int step, enum target_signal siggnal)
575 {
576   int status;
577   Rptrace ptrace_in;
578   Ptrace_return ptrace_out;
579   CORE_ADDR cont_addr;
580
581   if (pid == -1)
582     pid = inferior_pid;
583
584   if (siggnal != 0 && siggnal != stop_signal)
585     error ("Cannot send signals to VxWorks processes");
586
587   /* Set CONT_ADDR to the address at which we are continuing,
588      or to 1 if we are continuing from where the program stopped.
589      This conforms to traditional ptrace () usage, but at the same
590      time has special meaning for the VxWorks remote debug server.
591      If the address is not 1, the server knows that the target
592      program is jumping to a new address, which requires special
593      handling if there is a breakpoint at the new address.  */
594
595   cont_addr = read_register (PC_REGNUM);
596   if (cont_addr == stop_pc)
597     cont_addr = 1;
598
599   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
600   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
601
602   ptrace_in.pid = pid;
603   ptrace_in.addr = cont_addr;   /* Target side insists on this, or it panics.  */
604
605   if (step)
606     status = net_step ();
607   else
608     status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out);
609
610   if (status)
611     error (rpcerr);
612   if (ptrace_out.status == -1)
613     {
614       errno = ptrace_out.errno_num;
615       perror_with_name ("Resuming remote process");
616     }
617 }
618
619 static void
620 vx_mourn_inferior (void)
621 {
622   pop_target ();                /* Pop back to no-child state */
623   generic_mourn_inferior ();
624 }
625 \f
626
627 static void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR);
628
629 struct find_sect_args
630   {
631     CORE_ADDR text_start;
632     CORE_ADDR data_start;
633     CORE_ADDR bss_start;
634   };
635
636 static void find_sect (bfd *, asection *, void *);
637
638 static void
639 find_sect (bfd *abfd, asection *sect, PTR obj)
640 {
641   struct find_sect_args *args = (struct find_sect_args *) obj;
642
643   if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY))
644     args->text_start = bfd_get_section_vma (abfd, sect);
645   else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC)
646     {
647       if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
648         {
649           /* Exclude .ctor and .dtor sections which have SEC_CODE set but not
650              SEC_DATA.  */
651           if (bfd_get_section_flags (abfd, sect) & SEC_DATA)
652             args->data_start = bfd_get_section_vma (abfd, sect);
653         }
654       else
655         args->bss_start = bfd_get_section_vma (abfd, sect);
656     }
657 }
658
659 static void
660 vx_add_symbols (char *name, int from_tty, CORE_ADDR text_addr,
661                 CORE_ADDR data_addr, CORE_ADDR bss_addr)
662 {
663   struct section_offsets *offs;
664   struct objfile *objfile;
665   struct find_sect_args ss;
666
667   /* It might be nice to suppress the breakpoint_re_set which happens here
668      because we are going to do one again after the objfile_relocate.  */
669   objfile = symbol_file_add (name, from_tty, NULL, 0, 0);
670
671   /* This is a (slightly cheesy) way of superceding the old symbols.  A less
672      cheesy way would be to find the objfile with the same name and
673      free_objfile it.  */
674   objfile_to_front (objfile);
675
676   offs = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
677   memcpy (offs, objfile->section_offsets, SIZEOF_SECTION_OFFSETS);
678
679   ss.text_start = 0;
680   ss.data_start = 0;
681   ss.bss_start = 0;
682   bfd_map_over_sections (objfile->obfd, find_sect, &ss);
683
684   /* Both COFF and b.out frontends use these SECT_OFF_* values.  */
685   offs->offsets[SECT_OFF_TEXT (objfile)]  = text_addr - ss.text_start;
686   offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start;
687   offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start;
688   objfile_relocate (objfile, offs);
689 }
690
691 /* This function allows the addition of incrementally linked object files.  */
692
693 static void
694 vx_load_command (char *arg_string, int from_tty)
695 {
696   CORE_ADDR text_addr;
697   CORE_ADDR data_addr;
698   CORE_ADDR bss_addr;
699
700   if (arg_string == 0)
701     error ("The load command takes a file name");
702
703   arg_string = tilde_expand (arg_string);
704   make_cleanup (xfree, arg_string);
705
706   dont_repeat ();
707
708   /* Refuse to load the module if a debugged task is running.  Doing so
709      can have a number of unpleasant consequences to the running task.  */
710
711   if (inferior_pid != 0 && target_has_execution)
712     {
713       if (query ("You may not load a module while the target task is running.\n\
714 Kill the target task? "))
715         target_kill ();
716       else
717         error ("Load canceled.");
718     }
719
720   QUIT;
721   immediate_quit++;
722   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
723     error ("Load failed on target machine");
724   immediate_quit--;
725
726   vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
727
728   /* Getting new symbols may change our opinion about what is
729      frameless.  */
730   reinit_frame_cache ();
731 }
732
733 /* Single step the target program at the source or machine level.
734    Takes an error exit if rpc fails.
735    Returns -1 if remote single-step operation fails, else 0.  */
736
737 static int
738 net_step (void)
739 {
740   enum clnt_stat status;
741   int step_status;
742   SOURCE_STEP source_step;
743
744   source_step.taskId = inferior_pid;
745
746   if (step_range_end)
747     {
748       source_step.startAddr = step_range_start;
749       source_step.endAddr = step_range_end;
750     }
751   else
752     {
753       source_step.startAddr = 0;
754       source_step.endAddr = 0;
755     }
756
757   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
758                           xdr_int, &step_status);
759
760   if (status == RPC_SUCCESS)
761     return step_status;
762   else
763     error (rpcerr);
764 }
765
766 /* Emulate ptrace using RPC calls to the VxWorks target system.
767    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
768
769 static int
770 net_ptrace_clnt_call (enum ptracereq request, Rptrace *pPtraceIn,
771                       Ptrace_return *pPtraceOut)
772 {
773   enum clnt_stat status;
774
775   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
776                           pPtraceOut);
777
778   if (status != RPC_SUCCESS)
779     return -1;
780
781   return 0;
782 }
783
784 /* Query the target for the name of the file from which VxWorks was
785    booted.  pBootFile is the address of a pointer to the buffer to
786    receive the file name; if the pointer pointed to by pBootFile is 
787    NULL, memory for the buffer will be allocated by XDR.
788    Returns -1 if rpc failed, 0 otherwise.  */
789
790 static int
791 net_get_boot_file (char **pBootFile)
792 {
793   enum clnt_stat status;
794
795   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
796                           xdr_wrapstring, pBootFile);
797   return (status == RPC_SUCCESS) ? 0 : -1;
798 }
799
800 /* Fetch a list of loaded object modules from the VxWorks target
801    and store in PLOADTABLE.
802    Returns -1 if rpc failed, 0 otherwise
803    There's no way to check if the returned loadTable is correct.
804    VxWorks doesn't check it.  */
805
806 static int
807 net_get_symbols (ldtabl *pLoadTable)
808 {
809   enum clnt_stat status;
810
811   memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
812
813   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
814   return (status == RPC_SUCCESS) ? 0 : -1;
815 }
816
817 /* Look up a symbol in the VxWorks target's symbol table.
818    Returns status of symbol read on target side (0=success, -1=fail)
819    Returns -1 and complain()s if rpc fails.  */
820
821 struct complaint cant_contact_target =
822 {"Lost contact with VxWorks target", 0, 0};
823
824 static int
825 vx_lookup_symbol (char *name,   /* symbol name */
826                   CORE_ADDR *pAddr)
827 {
828   enum clnt_stat status;
829   SYMBOL_ADDR symbolAddr;
830
831   *pAddr = 0;
832   memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
833
834   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
835                           xdr_SYMBOL_ADDR, &symbolAddr);
836   if (status != RPC_SUCCESS)
837     {
838       complain (&cant_contact_target);
839       return -1;
840     }
841
842   *pAddr = symbolAddr.addr;
843   return symbolAddr.status;
844 }
845
846 /* Check to see if the VxWorks target has a floating point coprocessor.
847    Returns 1 if target has floating point processor, 0 otherwise.
848    Calls error() if rpc fails.  */
849
850 static int
851 net_check_for_fp (void)
852 {
853   enum clnt_stat status;
854   bool_t fp = 0;                /* true if fp processor is present on target board */
855
856   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
857   if (status != RPC_SUCCESS)
858     error (rpcerr);
859
860   return (int) fp;
861 }
862
863 /* Establish an RPC connection with the VxWorks target system.
864    Calls error () if unable to establish connection.  */
865
866 static void
867 net_connect (char *host)
868 {
869   struct sockaddr_in destAddr;
870   struct hostent *destHost;
871   unsigned long addr;
872
873   /* Get the internet address for the given host.  Allow a numeric
874      IP address or a hostname.  */
875
876   addr = inet_addr (host);
877   if (addr == -1)
878     {
879       destHost = (struct hostent *) gethostbyname (host);
880       if (destHost == NULL)
881         /* FIXME: Probably should include hostname here in quotes.
882            For example if the user types "target vxworks vx960 " it should
883            say "Invalid host `vx960 '." not just "Invalid hostname".  */
884         error ("Invalid hostname.  Couldn't find remote host address.");
885       addr = *(unsigned long *) destHost->h_addr;
886     }
887
888   memset (&destAddr, '\0', sizeof (destAddr));
889
890   destAddr.sin_addr.s_addr = addr;
891   destAddr.sin_family = AF_INET;
892   destAddr.sin_port = 0;        /* set to actual port that remote
893                                    ptrace is listening on.  */
894
895   /* Create a tcp client transport on which to issue
896      calls to the remote ptrace server.  */
897
898   ptraceSock = RPC_ANYSOCK;
899   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
900   /* FIXME, here is where we deal with different version numbers of the
901      proto */
902
903   if (pClient == NULL)
904     {
905       clnt_pcreateerror ("\tnet_connect");
906       error ("Couldn't connect to remote target.");
907     }
908 }
909 \f
910 /* Sleep for the specified number of milliseconds 
911  * (assumed to be less than 1000).
912  * If select () is interrupted, returns immediately;
913  * takes an error exit if select () fails for some other reason.
914  */
915
916 static void
917 sleep_ms (long ms)
918 {
919   struct timeval select_timeout;
920   int status;
921
922   select_timeout.tv_sec = 0;
923   select_timeout.tv_usec = ms * 1000;
924
925   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
926                    &select_timeout);
927
928   if (status < 0 && errno != EINTR)
929     perror_with_name ("select");
930 }
931
932 static int
933 vx_wait (int pid_to_wait_for, struct target_waitstatus *status)
934 {
935   register int pid;
936   RDB_EVENT rdbEvent;
937   int quit_failed;
938
939   do
940     {
941       /* If CTRL-C is hit during this loop,
942          suspend the inferior process.  */
943
944       quit_failed = 0;
945       if (quit_flag)
946         {
947           quit_failed = (net_quit () == -1);
948           quit_flag = 0;
949         }
950
951       /* If a net_quit () or net_wait () call has failed,
952          allow the user to break the connection with the target.
953          We can't simply error () out of this loop, since the 
954          data structures representing the state of the inferior
955          are in an inconsistent state.  */
956
957       if (quit_failed || net_wait (&rdbEvent) == -1)
958         {
959           terminal_ours ();
960           if (query ("Can't %s.  Disconnect from target system? ",
961                      (quit_failed) ? "suspend remote task"
962                      : "get status of remote task"))
963             {
964               target_mourn_inferior ();
965               error ("Use the \"target\" command to reconnect.");
966             }
967           else
968             {
969               terminal_inferior ();
970               continue;
971             }
972         }
973
974       pid = rdbEvent.taskId;
975       if (pid == 0)
976         {
977           sleep_ms (200);       /* FIXME Don't kill the network too badly */
978         }
979       else if (pid != inferior_pid)
980         internal_error ("Bad pid for debugged task: %s\n",
981                         local_hex_string ((unsigned long) pid));
982     }
983   while (pid == 0);
984
985   /* The mostly likely kind.  */
986   status->kind = TARGET_WAITKIND_STOPPED;
987
988   switch (rdbEvent.eventType)
989     {
990     case EVENT_EXIT:
991       status->kind = TARGET_WAITKIND_EXITED;
992       /* FIXME is it possible to distinguish between a
993          normal vs abnormal exit in VxWorks? */
994       status->value.integer = 0;
995       break;
996
997     case EVENT_START:
998       /* Task was just started. */
999       status->value.sig = TARGET_SIGNAL_TRAP;
1000       break;
1001
1002     case EVENT_STOP:
1003       status->value.sig = TARGET_SIGNAL_TRAP;
1004       /* XXX was it stopped by a signal?  act accordingly */
1005       break;
1006
1007     case EVENT_BREAK:           /* Breakpoint was hit. */
1008       status->value.sig = TARGET_SIGNAL_TRAP;
1009       break;
1010
1011     case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */
1012       status->value.sig = TARGET_SIGNAL_INT;
1013       break;
1014
1015     case EVENT_BUS_ERR: /* Task made evil nasty reference. */
1016       status->value.sig = TARGET_SIGNAL_BUS;
1017       break;
1018
1019     case EVENT_ZERO_DIV:        /* Division by zero */
1020       status->value.sig = TARGET_SIGNAL_FPE;
1021       break;
1022
1023     case EVENT_SIGNAL:
1024 #ifdef I80960
1025       status->value.sig = i960_fault_to_signal (rdbEvent.sigType);
1026 #else
1027       /* Back in the old days, before enum target_signal, this code used
1028          to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL
1029          would take care of it.  But PRINT_RANDOM_SIGNAL has never been
1030          defined except on the i960, so I don't really know what we are
1031          supposed to do on other architectures.  */
1032       status->value.sig = TARGET_SIGNAL_UNKNOWN;
1033 #endif
1034       break;
1035     }                           /* switch */
1036   return pid;
1037 }
1038 \f
1039 static int
1040 symbol_stub (char *arg)
1041 {
1042   symbol_file_add_main (arg, 0);
1043   return 1;
1044 }
1045
1046 static int
1047 add_symbol_stub (char *arg)
1048 {
1049   struct ldfile *pLoadFile = (struct ldfile *) arg;
1050
1051   printf_unfiltered ("\t%s: ", pLoadFile->name);
1052   vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr,
1053                   pLoadFile->data_addr, pLoadFile->bss_addr);
1054   printf_unfiltered ("ok\n");
1055   return 1;
1056 }
1057 /* Target command for VxWorks target systems.
1058
1059    Used in vxgdb.  Takes the name of a remote target machine
1060    running vxWorks and connects to it to initialize remote network
1061    debugging.  */
1062
1063 static void
1064 vx_open (char *args, int from_tty)
1065 {
1066   extern int close ();
1067   char *bootFile;
1068   extern char *source_path;
1069   struct ldtabl loadTable;
1070   struct ldfile *pLoadFile;
1071   int i;
1072   extern CLIENT *pClient;
1073   int symbols_added = 0;
1074
1075   if (!args)
1076     error_no_arg ("target machine name");
1077
1078   target_preopen (from_tty);
1079
1080   unpush_target (&vx_ops);
1081   printf_unfiltered ("Attaching remote machine across net...\n");
1082   gdb_flush (gdb_stdout);
1083
1084   /* Allow the user to kill the connect attempt by typing ^C.
1085      Wait until the call to target_has_fp () completes before
1086      disallowing an immediate quit, since even if net_connect ()
1087      is successful, the remote debug server might be hung.  */
1088
1089   immediate_quit++;
1090
1091   net_connect (args);
1092   target_has_fp = net_check_for_fp ();
1093   printf_filtered ("Connected to %s.\n", args);
1094
1095   immediate_quit--;
1096
1097   push_target (&vx_ops);
1098
1099   /* Save a copy of the target host's name.  */
1100   vx_host = savestring (args, strlen (args));
1101
1102   /* Find out the name of the file from which the target was booted
1103      and load its symbol table.  */
1104
1105   printf_filtered ("Looking in Unix path for all loaded modules:\n");
1106   bootFile = NULL;
1107   if (!net_get_boot_file (&bootFile))
1108     {
1109       if (*bootFile)
1110         {
1111           printf_filtered ("\t%s: ", bootFile);
1112           /* This assumes that the kernel is never relocated.  Hope that is an
1113              accurate assumption.  */
1114           if (catch_errors
1115               (symbol_stub,
1116                bootFile,
1117                "Error while reading symbols from boot file:\n",
1118                RETURN_MASK_ALL))
1119             puts_filtered ("ok\n");
1120         }
1121       else if (from_tty)
1122         printf_unfiltered ("VxWorks kernel symbols not loaded.\n");
1123     }
1124   else
1125     error ("Can't retrieve boot file name from target machine.");
1126
1127   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1128
1129   if (net_get_symbols (&loadTable) != 0)
1130     error ("Can't read loaded modules from target machine");
1131
1132   i = 0 - 1;
1133   while (++i < loadTable.tbl_size)
1134     {
1135       QUIT;                     /* FIXME, avoids clnt_freeres below:  mem leak */
1136       pLoadFile = &loadTable.tbl_ent[i];
1137 #ifdef WRS_ORIG
1138       {
1139         register int desc;
1140         struct cleanup *old_chain;
1141         char *fullname = NULL;
1142
1143         desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1144         if (desc < 0)
1145           perror_with_name (pLoadFile->name);
1146         old_chain = make_cleanup (close, desc);
1147         add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1148                           pLoadFile->bss_addr);
1149         do_cleanups (old_chain);
1150       }
1151 #else
1152       /* FIXME: Is there something better to search than the PATH? (probably
1153          not the source path, since source might be in different directories
1154          than objects.  */
1155
1156       if (catch_errors (add_symbol_stub, (char *) pLoadFile, (char *) 0,
1157                         RETURN_MASK_ALL))
1158         symbols_added = 1;
1159 #endif
1160     }
1161   printf_filtered ("Done.\n");
1162
1163   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1164
1165   /* Getting new symbols may change our opinion about what is
1166      frameless.  */
1167   if (symbols_added)
1168     reinit_frame_cache ();
1169 }
1170 \f
1171 /* Takes a task started up outside of gdb and ``attaches'' to it.
1172    This stops it cold in its tracks and allows us to start tracing it.  */
1173
1174 static void
1175 vx_attach (char *args, int from_tty)
1176 {
1177   unsigned long pid;
1178   char *cptr = 0;
1179   Rptrace ptrace_in;
1180   Ptrace_return ptrace_out;
1181   int status;
1182
1183   if (!args)
1184     error_no_arg ("process-id to attach");
1185
1186   pid = strtoul (args, &cptr, 0);
1187   if ((cptr == args) || (*cptr != '\0'))
1188     error ("Invalid process-id -- give a single number in decimal or 0xhex");
1189
1190   if (from_tty)
1191     printf_unfiltered ("Attaching pid %s.\n",
1192                        local_hex_string ((unsigned long) pid));
1193
1194   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1195   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1196   ptrace_in.pid = pid;
1197
1198   status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1199   if (status == -1)
1200     error (rpcerr);
1201   if (ptrace_out.status == -1)
1202     {
1203       errno = ptrace_out.errno_num;
1204       perror_with_name ("Attaching remote process");
1205     }
1206
1207   /* It worked... */
1208
1209   inferior_pid = pid;
1210   push_target (&vx_run_ops);
1211
1212   if (vx_running)
1213     xfree (vx_running);
1214   vx_running = 0;
1215 }
1216
1217 /* detach_command --
1218    takes a program previously attached to and detaches it.
1219    The program resumes execution and will no longer stop
1220    on signals, etc.  We better not have left any breakpoints
1221    in the program or it'll die when it hits one.  For this
1222    to work, it may be necessary for the process to have been
1223    previously attached.  It *might* work if the program was
1224    started via the normal ptrace (PTRACE_TRACEME).  */
1225
1226 static void
1227 vx_detach (char *args, int from_tty)
1228 {
1229   Rptrace ptrace_in;
1230   Ptrace_return ptrace_out;
1231   int signal = 0;
1232   int status;
1233
1234   if (args)
1235     error ("Argument given to VxWorks \"detach\".");
1236
1237   if (from_tty)
1238     printf_unfiltered ("Detaching pid %s.\n",
1239                        local_hex_string ((unsigned long) inferior_pid));
1240
1241   if (args)                     /* FIXME, should be possible to leave suspended */
1242     signal = atoi (args);
1243
1244   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1245   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1246   ptrace_in.pid = inferior_pid;
1247
1248   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1249   if (status == -1)
1250     error (rpcerr);
1251   if (ptrace_out.status == -1)
1252     {
1253       errno = ptrace_out.errno_num;
1254       perror_with_name ("Detaching VxWorks process");
1255     }
1256
1257   inferior_pid = 0;
1258   pop_target ();                /* go back to non-executing VxWorks connection */
1259 }
1260
1261 /* vx_kill -- takes a running task and wipes it out.  */
1262
1263 static void
1264 vx_kill (void)
1265 {
1266   Rptrace ptrace_in;
1267   Ptrace_return ptrace_out;
1268   int status;
1269
1270   printf_unfiltered ("Killing pid %s.\n", local_hex_string ((unsigned long) inferior_pid));
1271
1272   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1273   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1274   ptrace_in.pid = inferior_pid;
1275
1276   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1277   if (status == -1)
1278     warning (rpcerr);
1279   else if (ptrace_out.status == -1)
1280     {
1281       errno = ptrace_out.errno_num;
1282       perror_with_name ("Killing VxWorks process");
1283     }
1284
1285   /* If it gives good status, the process is *gone*, no events remain.
1286      If the kill failed, assume the process is gone anyhow.  */
1287   inferior_pid = 0;
1288   pop_target ();                /* go back to non-executing VxWorks connection */
1289 }
1290
1291 /* Clean up from the VxWorks process target as it goes away.  */
1292
1293 static void
1294 vx_proc_close (int quitting)
1295 {
1296   inferior_pid = 0;             /* No longer have a process.  */
1297   if (vx_running)
1298     xfree (vx_running);
1299   vx_running = 0;
1300 }
1301 \f
1302 /* Make an RPC call to the VxWorks target.
1303    Returns RPC status.  */
1304
1305 static enum clnt_stat
1306 net_clnt_call (enum ptracereq procNum, xdrproc_t inProc, char *in,
1307                xdrproc_t outProc, char *out)
1308 {
1309   enum clnt_stat status;
1310
1311   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1312
1313   if (status != RPC_SUCCESS)
1314     clnt_perrno (status);
1315
1316   return status;
1317 }
1318
1319 /* Clean up before losing control.  */
1320
1321 static void
1322 vx_close (int quitting)
1323 {
1324   if (pClient)
1325     clnt_destroy (pClient);     /* The net connection */
1326   pClient = 0;
1327
1328   if (vx_host)
1329     xfree (vx_host);            /* The hostname */
1330   vx_host = 0;
1331 }
1332
1333 /* A vxprocess target should be started via "run" not "target".  */
1334 /*ARGSUSED */
1335 static void
1336 vx_proc_open (char *name, int from_tty)
1337 {
1338   error ("Use the \"run\" command to start a VxWorks process.");
1339 }
1340
1341 static void
1342 init_vx_ops (void)
1343 {
1344   vx_ops.to_shortname = "vxworks";
1345   vx_ops.to_longname = "VxWorks target memory via RPC over TCP/IP";
1346   vx_ops.to_doc = "Use VxWorks target memory.  \n\
1347 Specify the name of the machine to connect to.";
1348   vx_ops.to_open = vx_open;
1349   vx_ops.to_close = vx_close;
1350   vx_ops.to_attach = vx_attach;
1351   vx_ops.to_xfer_memory = vx_xfer_memory;
1352   vx_ops.to_files_info = vx_files_info;
1353   vx_ops.to_load = vx_load_command;
1354   vx_ops.to_lookup_symbol = vx_lookup_symbol;
1355   vx_ops.to_create_inferior = vx_create_inferior;
1356   vx_ops.to_stratum = core_stratum;
1357   vx_ops.to_has_all_memory = 1;
1358   vx_ops.to_has_memory = 1;
1359   vx_ops.to_magic = OPS_MAGIC;  /* Always the last thing */
1360 };
1361
1362 static void
1363 init_vx_run_ops (void)
1364 {
1365   vx_run_ops.to_shortname = "vxprocess";
1366   vx_run_ops.to_longname = "VxWorks process";
1367   vx_run_ops.to_doc = "VxWorks process; started by the \"run\" command.";
1368   vx_run_ops.to_open = vx_proc_open;
1369   vx_run_ops.to_close = vx_proc_close;
1370   vx_run_ops.to_detach = vx_detach;
1371   vx_run_ops.to_resume = vx_resume;
1372   vx_run_ops.to_wait = vx_wait;
1373   vx_run_ops.to_fetch_registers = vx_read_register;
1374   vx_run_ops.to_store_registers = vx_write_register;
1375   vx_run_ops.to_prepare_to_store = vx_prepare_to_store;
1376   vx_run_ops.to_xfer_memory = vx_xfer_memory;
1377   vx_run_ops.to_files_info = vx_run_files_info;
1378   vx_run_ops.to_insert_breakpoint = vx_insert_breakpoint;
1379   vx_run_ops.to_remove_breakpoint = vx_remove_breakpoint;
1380   vx_run_ops.to_kill = vx_kill;
1381   vx_run_ops.to_load = vx_load_command;
1382   vx_run_ops.to_lookup_symbol = vx_lookup_symbol;
1383   vx_run_ops.to_mourn_inferior = vx_mourn_inferior;
1384   vx_run_ops.to_stratum = process_stratum;
1385   vx_run_ops.to_has_memory = 1;
1386   vx_run_ops.to_has_stack = 1;
1387   vx_run_ops.to_has_registers = 1;
1388   vx_run_ops.to_has_execution = 1;
1389   vx_run_ops.to_magic = OPS_MAGIC;
1390 }
1391 \f
1392 void
1393 _initialize_vx (void)
1394 {
1395   init_vx_ops ();
1396   add_target (&vx_ops);
1397   init_vx_run_ops ();
1398   add_target (&vx_run_ops);
1399
1400   add_show_from_set
1401     (add_set_cmd ("vxworks-timeout", class_support, var_uinteger,
1402                   (char *) &rpcTimeout.tv_sec,
1403                   "Set seconds to wait for rpc calls to return.\n\
1404 Set the number of seconds to wait for rpc calls to return.", &setlist),
1405      &showlist);
1406 }