]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gdb/gdb/remote-vx.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gdb / gdb / remote-vx.c
1 /* Memory-access and commands for remote VxWorks processes, for GDB.
2
3    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
4    2000, 2001, 2002 Free Software Foundation, Inc.
5
6    Contributed by Wind River Systems and Cygnus Support.
7
8    This file is part of GDB.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330,
23    Boston, MA 02111-1307, USA.  */
24
25 #include "defs.h"
26 #include "frame.h"
27 #include "inferior.h"
28 #include "target.h"
29 #include "gdbcore.h"
30 #include "command.h"
31 #include "symtab.h"
32 #include "complaints.h"
33 #include "gdbcmd.h"
34 #include "bfd.h"                /* Required by objfiles.h.  */
35 #include "symfile.h"
36 #include "objfiles.h"
37 #include "gdb-stabs.h"
38 #include "regcache.h"
39
40 #include "gdb_string.h"
41 #include <errno.h>
42 #include <signal.h>
43 #include <fcntl.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #define malloc bogon_malloc     /* Sun claims "char *malloc()" not void * */
47 #define free bogon_free         /* Sun claims "int free()" not void */
48 #define realloc bogon_realloc   /* Sun claims "char *realloc()", not void * */
49 #include <rpc/rpc.h>
50 #undef malloc
51 #undef free
52 #undef realloc
53 #include <sys/time.h>           /* UTek's <rpc/rpc.h> doesn't #incl this */
54 #include <netdb.h>
55 #include "vx-share/ptrace.h"
56 #include "vx-share/xdr_ptrace.h"
57 #include "vx-share/xdr_ld.h"
58 #include "vx-share/xdr_rdb.h"
59 #include "vx-share/dbgRpcLib.h"
60
61 #include <symtab.h>
62
63 /* Maximum number of bytes to transfer in a single
64    PTRACE_{READ,WRITE}DATA request.  */
65 #define VX_MEMXFER_MAX 4096
66
67 extern void vx_read_register ();
68 extern void vx_write_register ();
69 extern void symbol_file_command ();
70 extern enum stop_kind stop_soon;        /* for wait_for_inferior */
71
72 static int net_step ();
73 static int net_ptrace_clnt_call ();     /* Forward decl */
74 static enum clnt_stat net_clnt_call ();         /* Forward decl */
75
76 /* Target ops structure for accessing memory and such over the net */
77
78 static struct target_ops vx_ops;
79
80 /* Target ops structure for accessing VxWorks child processes over the net */
81
82 static struct target_ops vx_run_ops;
83
84 /* Saved name of target host and called function for "info files".
85    Both malloc'd.  */
86
87 static char *vx_host;
88 static char *vx_running;        /* Called function */
89
90 /* Nonzero means target that is being debugged remotely has a floating
91    point processor.  */
92
93 int target_has_fp;
94
95 /* Default error message when the network is forking up.  */
96
97 static const char rpcerr[] = "network target debugging:  rpc error";
98
99 CLIENT *pClient;                /* client used in net debugging */
100 static int ptraceSock = RPC_ANYSOCK;
101
102 enum clnt_stat net_clnt_call ();
103 static void parse_args ();
104
105 static struct timeval rpcTimeout =
106 {10, 0};
107
108 static char *skip_white_space ();
109 static char *find_white_space ();
110
111 /* Tell the VxWorks target system to download a file.
112    The load addresses of the text, data, and bss segments are
113    stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively).
114    Returns 0 for success, -1 for failure.  */
115
116 static int
117 net_load (char *filename, CORE_ADDR *pTextAddr, CORE_ADDR *pDataAddr,
118           CORE_ADDR *pBssAddr)
119 {
120   enum clnt_stat status;
121   struct ldfile ldstruct;
122   struct timeval load_timeout;
123
124   memset ((char *) &ldstruct, '\0', sizeof (ldstruct));
125
126   /* We invoke clnt_call () here directly, instead of through
127      net_clnt_call (), because we need to set a large timeout value.
128      The load on the target side can take quite a while, easily
129      more than 10 seconds.  The user can kill this call by typing
130      CTRL-C if there really is a problem with the load.  
131
132      Do not change the tv_sec value without checking -- select() imposes
133      a limit of 10**8 on it for no good reason that I can see...  */
134
135   load_timeout.tv_sec = 99999999;       /* A large number, effectively inf. */
136   load_timeout.tv_usec = 0;
137
138   status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
139                       &ldstruct, load_timeout);
140
141   if (status == RPC_SUCCESS)
142     {
143       if (*ldstruct.name == 0)  /* load failed on VxWorks side */
144         return -1;
145       *pTextAddr = ldstruct.txt_addr;
146       *pDataAddr = ldstruct.data_addr;
147       *pBssAddr = ldstruct.bss_addr;
148       return 0;
149     }
150   else
151     return -1;
152 }
153
154 /* returns 0 if successful, errno if RPC failed or VxWorks complains. */
155
156 static int
157 net_break (int addr, u_long procnum)
158 {
159   enum clnt_stat status;
160   int break_status;
161   Rptrace ptrace_in;            /* XXX This is stupid.  It doesn't need to be a ptrace
162                                    structure.  How about something smaller? */
163
164   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
165   break_status = 0;
166
167   ptrace_in.addr = addr;
168   ptrace_in.pid = PIDGET (inferior_ptid);
169
170   status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
171                           &break_status);
172
173   if (status != RPC_SUCCESS)
174     return errno;
175
176   if (break_status == -1)
177     return ENOMEM;
178   return break_status;          /* probably (FIXME) zero */
179 }
180
181 /* returns 0 if successful, errno otherwise */
182
183 static int
184 vx_insert_breakpoint (int addr)
185 {
186   return net_break (addr, VX_BREAK_ADD);
187 }
188
189 /* returns 0 if successful, errno otherwise */
190
191 static int
192 vx_remove_breakpoint (int addr)
193 {
194   return net_break (addr, VX_BREAK_DELETE);
195 }
196
197 /* Start an inferior process and sets inferior_ptid to its pid.
198    EXEC_FILE is the file to run.
199    ALLARGS is a string containing the arguments to the program.
200    ENV is the environment vector to pass.
201    Returns process id.  Errors reported with error().
202    On VxWorks, we ignore exec_file.  */
203
204 static void
205 vx_create_inferior (char *exec_file, char *args, char **env)
206 {
207   enum clnt_stat status;
208   arg_array passArgs;
209   TASK_START taskStart;
210
211   memset ((char *) &passArgs, '\0', sizeof (passArgs));
212   memset ((char *) &taskStart, '\0', sizeof (taskStart));
213
214   /* parse arguments, put them in passArgs */
215
216   parse_args (args, &passArgs);
217
218   if (passArgs.arg_array_len == 0)
219     error ("You must specify a function name to run, and arguments if any");
220
221   status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
222                           xdr_TASK_START, &taskStart);
223
224   if ((status != RPC_SUCCESS) || (taskStart.status == -1))
225     error ("Can't create process on remote target machine");
226
227   /* Save the name of the running function */
228   vx_running = savestring (passArgs.arg_array_val[0],
229                            strlen (passArgs.arg_array_val[0]));
230
231   push_target (&vx_run_ops);
232   inferior_ptid = pid_to_ptid (taskStart.pid);
233
234   /* We will get a trace trap after one instruction.
235      Insert breakpoints and continue.  */
236
237   init_wait_for_inferior ();
238
239   /* Set up the "saved terminal modes" of the inferior
240      based on what modes we are starting it with.  */
241   target_terminal_init ();
242
243   /* Install inferior's terminal modes.  */
244   target_terminal_inferior ();
245
246   stop_soon = STOP_QUIETLY;
247   wait_for_inferior ();         /* Get the task spawn event */
248   stop_soon = NO_STOP_QUIETLY;
249
250   /* insert_step_breakpoint ();  FIXME, do we need this?  */
251   proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
252 }
253
254 /* Fill ARGSTRUCT in argc/argv form with the arguments from the
255    argument string ARGSTRING.  */
256
257 static void
258 parse_args (char *arg_string, arg_array *arg_struct)
259 {
260   int arg_count = 0;    /* number of arguments */
261   int arg_index = 0;
262   char *p0;
263
264   memset ((char *) arg_struct, '\0', sizeof (arg_array));
265
266   /* first count how many arguments there are */
267
268   p0 = arg_string;
269   while (*p0 != '\0')
270     {
271       if (*(p0 = skip_white_space (p0)) == '\0')
272         break;
273       p0 = find_white_space (p0);
274       arg_count++;
275     }
276
277   arg_struct->arg_array_len = arg_count;
278   arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
279                                                  * sizeof (char *));
280
281   /* now copy argument strings into arg_struct.  */
282
283   while (*(arg_string = skip_white_space (arg_string)))
284     {
285       p0 = find_white_space (arg_string);
286       arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
287                                                            p0 - arg_string);
288       arg_string = p0;
289     }
290
291   arg_struct->arg_array_val[arg_count] = NULL;
292 }
293
294 /* Advance a string pointer across whitespace and return a pointer
295    to the first non-white character.  */
296
297 static char *
298 skip_white_space (char *p)
299 {
300   while (*p == ' ' || *p == '\t')
301     p++;
302   return p;
303 }
304
305 /* Search for the first unquoted whitespace character in a string.
306    Returns a pointer to the character, or to the null terminator
307    if no whitespace is found.  */
308
309 static char *
310 find_white_space (char *p)
311 {
312   int c;
313
314   while ((c = *p) != ' ' && c != '\t' && c)
315     {
316       if (c == '\'' || c == '"')
317         {
318           while (*++p != c && *p)
319             {
320               if (*p == '\\')
321                 p++;
322             }
323           if (!*p)
324             break;
325         }
326       p++;
327     }
328   return p;
329 }
330
331 /* Poll the VxWorks target system for an event related
332    to the debugged task.
333    Returns -1 if remote wait failed, task status otherwise.  */
334
335 static int
336 net_wait (RDB_EVENT *pEvent)
337 {
338   int pid;
339   enum clnt_stat status;
340
341   memset ((char *) pEvent, '\0', sizeof (RDB_EVENT));
342
343   pid = PIDGET (inferior_ptid);
344   status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT,
345                           pEvent);
346
347   /* return (status == RPC_SUCCESS)? pEvent->status: -1; */
348   if (status == RPC_SUCCESS)
349     return ((pEvent->status) ? 1 : 0);
350   else if (status == RPC_TIMEDOUT)
351     return (1);
352   else
353     return (-1);
354 }
355
356 /* Suspend the remote task.
357    Returns -1 if suspend fails on target system, 0 otherwise.  */
358
359 static int
360 net_quit (void)
361 {
362   int pid;
363   int quit_status;
364   enum clnt_stat status;
365
366   quit_status = 0;
367
368   /* don't let rdbTask suspend itself by passing a pid of 0 */
369
370   if ((pid = PIDGET (inferior_ptid)) == 0)
371     return -1;
372
373   status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
374                           &quit_status);
375
376   return (status == RPC_SUCCESS) ? quit_status : -1;
377 }
378
379 /* Read a register or registers from the remote system.  */
380
381 void
382 net_read_registers (char *reg_buf, int len, u_long procnum)
383 {
384   int status;
385   Rptrace ptrace_in;
386   Ptrace_return ptrace_out;
387   C_bytes out_data;
388   char message[100];
389
390   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
391   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
392
393   /* Initialize RPC input argument structure.  */
394
395   ptrace_in.pid = PIDGET (inferior_ptid);
396   ptrace_in.info.ttype = NOINFO;
397
398   /* Initialize RPC return value structure.  */
399
400   out_data.bytes = reg_buf;
401   out_data.len = len;
402   ptrace_out.info.more_data = (caddr_t) & out_data;
403
404   /* Call RPC; take an error exit if appropriate.  */
405
406   status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
407   if (status)
408     error (rpcerr);
409   if (ptrace_out.status == -1)
410     {
411       errno = ptrace_out.errno_num;
412       sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS)
413                ? "general-purpose"
414                : "floating-point");
415       perror_with_name (message);
416     }
417 }
418
419 /* Write register values to a VxWorks target.  REG_BUF points to a buffer
420    containing the raw register values, LEN is the length of REG_BUF in
421    bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or
422    PTRACE_SETFPREGS).  An error exit is taken if the RPC call fails or
423    if an error status is returned by the remote debug server.  This is
424    a utility routine used by vx_write_register ().  */
425
426 void
427 net_write_registers (char *reg_buf, int len, u_long procnum)
428 {
429   int status;
430   Rptrace ptrace_in;
431   Ptrace_return ptrace_out;
432   C_bytes in_data;
433   char message[100];
434
435   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
436   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
437
438   /* Initialize RPC input argument structure.  */
439
440   in_data.bytes = reg_buf;
441   in_data.len = len;
442
443   ptrace_in.pid = PIDGET (inferior_ptid);
444   ptrace_in.info.ttype = DATA;
445   ptrace_in.info.more_data = (caddr_t) & in_data;
446
447   /* Call RPC; take an error exit if appropriate.  */
448
449   status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
450   if (status)
451     error (rpcerr);
452   if (ptrace_out.status == -1)
453     {
454       errno = ptrace_out.errno_num;
455       sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS)
456                ? "general-purpose"
457                : "floating-point");
458       perror_with_name (message);
459     }
460 }
461
462 /* Prepare to store registers.  Since we will store all of them,
463    read out their current values now.  */
464
465 static void
466 vx_prepare_to_store (void)
467 {
468   /* Fetch all registers, if any of them are not yet fetched.  */
469   deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES);
470 }
471
472 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
473    to debugger memory starting at MYADDR.  WRITE is true if writing to the
474    inferior.  TARGET is unused.
475    Result is the number of bytes written or read (zero if error).  The
476    protocol allows us to return a negative count, indicating that we can't
477    handle the current address but can handle one N bytes further, but
478    vxworks doesn't give us that information.  */
479
480 static int
481 vx_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
482                 struct mem_attrib *attrib, struct target_ops *target)
483 {
484   int status;
485   Rptrace ptrace_in;
486   Ptrace_return ptrace_out;
487   C_bytes data;
488   enum ptracereq request;
489   int nleft, nxfer;
490
491   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
492   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
493
494   ptrace_in.pid = PIDGET (inferior_ptid); /* XXX pid unnecessary for READDATA */
495   ptrace_in.addr = (int) memaddr;       /* Where from */
496   ptrace_in.data = len;         /* How many bytes */
497
498   if (write)
499     {
500       ptrace_in.info.ttype = DATA;
501       ptrace_in.info.more_data = (caddr_t) & data;
502
503       data.bytes = (caddr_t) myaddr;    /* Where from */
504       data.len = len;           /* How many bytes (again, for XDR) */
505       request = PTRACE_WRITEDATA;
506     }
507   else
508     {
509       ptrace_out.info.more_data = (caddr_t) & data;
510       request = PTRACE_READDATA;
511     }
512   /* Loop until the entire request has been satisfied, transferring
513      at most VX_MEMXFER_MAX bytes per iteration.  Break from the loop
514      if an error status is returned by the remote debug server.  */
515
516   nleft = len;
517   status = 0;
518
519   while (nleft > 0 && status == 0)
520     {
521       nxfer = min (nleft, VX_MEMXFER_MAX);
522
523       ptrace_in.addr = (int) memaddr;
524       ptrace_in.data = nxfer;
525       data.bytes = (caddr_t) myaddr;
526       data.len = nxfer;
527
528       /* Request a block from the remote debug server; if RPC fails,
529          report an error and return to debugger command level.  */
530
531       if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out))
532         error (rpcerr);
533
534       status = ptrace_out.status;
535       if (status == 0)
536         {
537           memaddr += nxfer;
538           myaddr += nxfer;
539           nleft -= nxfer;
540         }
541       else
542         {
543           /* A target-side error has ocurred.  Set errno to the error
544              code chosen by the target so that a later perror () will
545              say something meaningful.  */
546
547           errno = ptrace_out.errno_num;
548         }
549     }
550
551   /* Return the number of bytes transferred.  */
552
553   return (len - nleft);
554 }
555
556 static void
557 vx_files_info (void)
558 {
559   printf_unfiltered ("\tAttached to host `%s'", vx_host);
560   printf_unfiltered (", which has %sfloating point", target_has_fp ? "" : "no ");
561   printf_unfiltered (".\n");
562 }
563
564 static void
565 vx_run_files_info (void)
566 {
567   printf_unfiltered ("\tRunning %s VxWorks process %s",
568                      vx_running ? "child" : "attached",
569                      local_hex_string (PIDGET (inferior_ptid)));
570   if (vx_running)
571     printf_unfiltered (", function `%s'", vx_running);
572   printf_unfiltered (".\n");
573 }
574
575 static void
576 vx_resume (ptid_t ptid, int step, enum target_signal siggnal)
577 {
578   int status;
579   Rptrace ptrace_in;
580   Ptrace_return ptrace_out;
581   CORE_ADDR cont_addr;
582
583   if (ptid_equal (ptid, minus_one_ptid))
584     ptid = inferior_ptid;
585
586   if (siggnal != 0 && siggnal != stop_signal)
587     error ("Cannot send signals to VxWorks processes");
588
589   /* Set CONT_ADDR to the address at which we are continuing,
590      or to 1 if we are continuing from where the program stopped.
591      This conforms to traditional ptrace () usage, but at the same
592      time has special meaning for the VxWorks remote debug server.
593      If the address is not 1, the server knows that the target
594      program is jumping to a new address, which requires special
595      handling if there is a breakpoint at the new address.  */
596
597   cont_addr = read_register (PC_REGNUM);
598   if (cont_addr == stop_pc)
599     cont_addr = 1;
600
601   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
602   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
603
604   ptrace_in.pid = PIDGET (ptid);
605   ptrace_in.addr = cont_addr;   /* Target side insists on this, or it panics.  */
606
607   if (step)
608     status = net_step ();
609   else
610     status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out);
611
612   if (status)
613     error (rpcerr);
614   if (ptrace_out.status == -1)
615     {
616       errno = ptrace_out.errno_num;
617       perror_with_name ("Resuming remote process");
618     }
619 }
620
621 static void
622 vx_mourn_inferior (void)
623 {
624   pop_target ();                /* Pop back to no-child state */
625   generic_mourn_inferior ();
626 }
627 \f
628
629 static void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR);
630
631 struct find_sect_args
632   {
633     CORE_ADDR text_start;
634     CORE_ADDR data_start;
635     CORE_ADDR bss_start;
636   };
637
638 static void find_sect (bfd *, asection *, void *);
639
640 static void
641 find_sect (bfd *abfd, asection *sect, void *obj)
642 {
643   struct find_sect_args *args = (struct find_sect_args *) obj;
644
645   if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY))
646     args->text_start = bfd_get_section_vma (abfd, sect);
647   else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC)
648     {
649       if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
650         {
651           /* Exclude .ctor and .dtor sections which have SEC_CODE set but not
652              SEC_DATA.  */
653           if (bfd_get_section_flags (abfd, sect) & SEC_DATA)
654             args->data_start = bfd_get_section_vma (abfd, sect);
655         }
656       else
657         args->bss_start = bfd_get_section_vma (abfd, sect);
658     }
659 }
660
661 static void
662 vx_add_symbols (char *name, int from_tty, CORE_ADDR text_addr,
663                 CORE_ADDR data_addr, CORE_ADDR bss_addr)
664 {
665   struct section_offsets *offs;
666   struct objfile *objfile;
667   struct find_sect_args ss;
668
669   /* It might be nice to suppress the breakpoint_re_set which happens here
670      because we are going to do one again after the objfile_relocate.  */
671   objfile = symbol_file_add (name, from_tty, NULL, 0, 0);
672
673   /* This is a (slightly cheesy) way of superceding the old symbols.  A less
674      cheesy way would be to find the objfile with the same name and
675      free_objfile it.  */
676   objfile_to_front (objfile);
677
678   offs =
679     (struct section_offsets *)
680     alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
681   memcpy (offs, objfile->section_offsets,
682           SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
683
684   ss.text_start = 0;
685   ss.data_start = 0;
686   ss.bss_start = 0;
687   bfd_map_over_sections (objfile->obfd, find_sect, &ss);
688
689   /* Both COFF and b.out frontends use these SECT_OFF_* values.  */
690   offs->offsets[SECT_OFF_TEXT (objfile)]  = text_addr - ss.text_start;
691   offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start;
692   offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start;
693   objfile_relocate (objfile, offs);
694 }
695
696 /* This function allows the addition of incrementally linked object files.  */
697
698 static void
699 vx_load_command (char *arg_string, int from_tty)
700 {
701   CORE_ADDR text_addr;
702   CORE_ADDR data_addr;
703   CORE_ADDR bss_addr;
704
705   if (arg_string == 0)
706     error ("The load command takes a file name");
707
708   arg_string = tilde_expand (arg_string);
709   make_cleanup (xfree, arg_string);
710
711   dont_repeat ();
712
713   /* Refuse to load the module if a debugged task is running.  Doing so
714      can have a number of unpleasant consequences to the running task.  */
715
716   if (PIDGET (inferior_ptid) != 0 && target_has_execution)
717     {
718       if (query ("You may not load a module while the target task is running.\n\
719 Kill the target task? "))
720         target_kill ();
721       else
722         error ("Load canceled.");
723     }
724
725   QUIT;
726   immediate_quit++;
727   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
728     error ("Load failed on target machine");
729   immediate_quit--;
730
731   vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
732
733   /* Getting new symbols may change our opinion about what is
734      frameless.  */
735   reinit_frame_cache ();
736 }
737
738 /* Single step the target program at the source or machine level.
739    Takes an error exit if rpc fails.
740    Returns -1 if remote single-step operation fails, else 0.  */
741
742 static int
743 net_step (void)
744 {
745   enum clnt_stat status;
746   int step_status;
747   SOURCE_STEP source_step;
748
749   source_step.taskId = PIDGET (inferior_ptid);
750
751   if (step_range_end)
752     {
753       source_step.startAddr = step_range_start;
754       source_step.endAddr = step_range_end;
755     }
756   else
757     {
758       source_step.startAddr = 0;
759       source_step.endAddr = 0;
760     }
761
762   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
763                           xdr_int, &step_status);
764
765   if (status == RPC_SUCCESS)
766     return step_status;
767   else
768     error (rpcerr);
769 }
770
771 /* Emulate ptrace using RPC calls to the VxWorks target system.
772    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
773
774 static int
775 net_ptrace_clnt_call (enum ptracereq request, Rptrace *pPtraceIn,
776                       Ptrace_return *pPtraceOut)
777 {
778   enum clnt_stat status;
779
780   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
781                           pPtraceOut);
782
783   if (status != RPC_SUCCESS)
784     return -1;
785
786   return 0;
787 }
788
789 /* Query the target for the name of the file from which VxWorks was
790    booted.  pBootFile is the address of a pointer to the buffer to
791    receive the file name; if the pointer pointed to by pBootFile is 
792    NULL, memory for the buffer will be allocated by XDR.
793    Returns -1 if rpc failed, 0 otherwise.  */
794
795 static int
796 net_get_boot_file (char **pBootFile)
797 {
798   enum clnt_stat status;
799
800   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
801                           xdr_wrapstring, pBootFile);
802   return (status == RPC_SUCCESS) ? 0 : -1;
803 }
804
805 /* Fetch a list of loaded object modules from the VxWorks target
806    and store in PLOADTABLE.
807    Returns -1 if rpc failed, 0 otherwise
808    There's no way to check if the returned loadTable is correct.
809    VxWorks doesn't check it.  */
810
811 static int
812 net_get_symbols (ldtabl *pLoadTable)
813 {
814   enum clnt_stat status;
815
816   memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
817
818   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
819   return (status == RPC_SUCCESS) ? 0 : -1;
820 }
821
822 /* Look up a symbol in the VxWorks target's symbol table.
823    Returns status of symbol read on target side (0=success, -1=fail)
824    Returns -1 and complain()s if rpc fails.  */
825
826 static int
827 vx_lookup_symbol (char *name,   /* symbol name */
828                   CORE_ADDR *pAddr)
829 {
830   enum clnt_stat status;
831   SYMBOL_ADDR symbolAddr;
832
833   *pAddr = 0;
834   memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
835
836   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
837                           xdr_SYMBOL_ADDR, &symbolAddr);
838   if (status != RPC_SUCCESS)
839     {
840       complaint (&symfile_complaints, "Lost contact with VxWorks target");
841       return -1;
842     }
843
844   *pAddr = symbolAddr.addr;
845   return symbolAddr.status;
846 }
847
848 /* Check to see if the VxWorks target has a floating point coprocessor.
849    Returns 1 if target has floating point processor, 0 otherwise.
850    Calls error() if rpc fails.  */
851
852 static int
853 net_check_for_fp (void)
854 {
855   enum clnt_stat status;
856   bool_t fp = 0;                /* true if fp processor is present on target board */
857
858   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
859   if (status != RPC_SUCCESS)
860     error (rpcerr);
861
862   return (int) fp;
863 }
864
865 /* Establish an RPC connection with the VxWorks target system.
866    Calls error () if unable to establish connection.  */
867
868 static void
869 net_connect (char *host)
870 {
871   struct sockaddr_in destAddr;
872   struct hostent *destHost;
873   unsigned long addr;
874
875   /* Get the internet address for the given host.  Allow a numeric
876      IP address or a hostname.  */
877
878   addr = inet_addr (host);
879   if (addr == -1)
880     {
881       destHost = (struct hostent *) gethostbyname (host);
882       if (destHost == NULL)
883         /* FIXME: Probably should include hostname here in quotes.
884            For example if the user types "target vxworks vx960 " it should
885            say "Invalid host `vx960 '." not just "Invalid hostname".  */
886         error ("Invalid hostname.  Couldn't find remote host address.");
887       addr = *(unsigned long *) destHost->h_addr;
888     }
889
890   memset (&destAddr, '\0', sizeof (destAddr));
891
892   destAddr.sin_addr.s_addr = addr;
893   destAddr.sin_family = AF_INET;
894   destAddr.sin_port = 0;        /* set to actual port that remote
895                                    ptrace is listening on.  */
896
897   /* Create a tcp client transport on which to issue
898      calls to the remote ptrace server.  */
899
900   ptraceSock = RPC_ANYSOCK;
901   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
902   /* FIXME, here is where we deal with different version numbers of the
903      proto */
904
905   if (pClient == NULL)
906     {
907       clnt_pcreateerror ("\tnet_connect");
908       error ("Couldn't connect to remote target.");
909     }
910 }
911 \f
912 /* Sleep for the specified number of milliseconds 
913  * (assumed to be less than 1000).
914  * If select () is interrupted, returns immediately;
915  * takes an error exit if select () fails for some other reason.
916  */
917
918 static void
919 sleep_ms (long ms)
920 {
921   struct timeval select_timeout;
922   int status;
923
924   select_timeout.tv_sec = 0;
925   select_timeout.tv_usec = ms * 1000;
926
927   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
928                    &select_timeout);
929
930   if (status < 0 && errno != EINTR)
931     perror_with_name ("select");
932 }
933
934 static ptid_t
935 vx_wait (ptid_t ptid_to_wait_for, struct target_waitstatus *status)
936 {
937   int pid;
938   RDB_EVENT rdbEvent;
939   int quit_failed;
940
941   do
942     {
943       /* If CTRL-C is hit during this loop,
944          suspend the inferior process.  */
945
946       quit_failed = 0;
947       if (quit_flag)
948         {
949           quit_failed = (net_quit () == -1);
950           quit_flag = 0;
951         }
952
953       /* If a net_quit () or net_wait () call has failed,
954          allow the user to break the connection with the target.
955          We can't simply error () out of this loop, since the 
956          data structures representing the state of the inferior
957          are in an inconsistent state.  */
958
959       if (quit_failed || net_wait (&rdbEvent) == -1)
960         {
961           terminal_ours ();
962           if (query ("Can't %s.  Disconnect from target system? ",
963                      (quit_failed) ? "suspend remote task"
964                      : "get status of remote task"))
965             {
966               target_mourn_inferior ();
967               error ("Use the \"target\" command to reconnect.");
968             }
969           else
970             {
971               terminal_inferior ();
972               continue;
973             }
974         }
975
976       pid = rdbEvent.taskId;
977       if (pid == 0)
978         {
979           sleep_ms (200);       /* FIXME Don't kill the network too badly */
980         }
981       else if (pid != PIDGET (inferior_ptid))
982         internal_error (__FILE__, __LINE__,
983                         "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_to_ptid (pid);
1040 }
1041 \f
1042 static int
1043 symbol_stub (char *arg)
1044 {
1045   symbol_file_add_main (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         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_ptid = pid_to_ptid (pid);
1213   push_target (&vx_run_ops);
1214
1215   if (vx_running)
1216     xfree (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 (
1243                          (unsigned long) PIDGET (inferior_ptid)));
1244
1245   if (args)                     /* FIXME, should be possible to leave suspended */
1246     signal = atoi (args);
1247
1248   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1249   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1250   ptrace_in.pid = PIDGET (inferior_ptid);
1251
1252   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1253   if (status == -1)
1254     error (rpcerr);
1255   if (ptrace_out.status == -1)
1256     {
1257       errno = ptrace_out.errno_num;
1258       perror_with_name ("Detaching VxWorks process");
1259     }
1260
1261   inferior_ptid = null_ptid;
1262   pop_target ();                /* go back to non-executing VxWorks connection */
1263 }
1264
1265 /* vx_kill -- takes a running task and wipes it out.  */
1266
1267 static void
1268 vx_kill (void)
1269 {
1270   Rptrace ptrace_in;
1271   Ptrace_return ptrace_out;
1272   int status;
1273
1274   printf_unfiltered ("Killing pid %s.\n", local_hex_string ((unsigned long) PIDGET (inferior_ptid)));
1275
1276   memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1277   memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1278   ptrace_in.pid = PIDGET (inferior_ptid);
1279
1280   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1281   if (status == -1)
1282     warning (rpcerr);
1283   else if (ptrace_out.status == -1)
1284     {
1285       errno = ptrace_out.errno_num;
1286       perror_with_name ("Killing VxWorks process");
1287     }
1288
1289   /* If it gives good status, the process is *gone*, no events remain.
1290      If the kill failed, assume the process is gone anyhow.  */
1291   inferior_ptid = null_ptid;
1292   pop_target ();                /* go back to non-executing VxWorks connection */
1293 }
1294
1295 /* Clean up from the VxWorks process target as it goes away.  */
1296
1297 static void
1298 vx_proc_close (int quitting)
1299 {
1300   inferior_ptid = null_ptid;    /* No longer have a process.  */
1301   if (vx_running)
1302     xfree (vx_running);
1303   vx_running = 0;
1304 }
1305 \f
1306 /* Make an RPC call to the VxWorks target.
1307    Returns RPC status.  */
1308
1309 static enum clnt_stat
1310 net_clnt_call (enum ptracereq procNum, xdrproc_t inProc, char *in,
1311                xdrproc_t outProc, char *out)
1312 {
1313   enum clnt_stat status;
1314
1315   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1316
1317   if (status != RPC_SUCCESS)
1318     clnt_perrno (status);
1319
1320   return status;
1321 }
1322
1323 /* Clean up before losing control.  */
1324
1325 static void
1326 vx_close (int quitting)
1327 {
1328   if (pClient)
1329     clnt_destroy (pClient);     /* The net connection */
1330   pClient = 0;
1331
1332   if (vx_host)
1333     xfree (vx_host);            /* The hostname */
1334   vx_host = 0;
1335 }
1336
1337 /* A vxprocess target should be started via "run" not "target".  */
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 }