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
67extern void vx_read_register ();
68extern void vx_write_register ();
69extern void symbol_file_command ();
70extern enum stop_kind stop_soon;	/* for wait_for_inferior */
71
72static int net_step ();
73static int net_ptrace_clnt_call ();	/* Forward decl */
74static enum clnt_stat net_clnt_call ();		/* Forward decl */
75
76/* Target ops structure for accessing memory and such over the net */
77
78static struct target_ops vx_ops;
79
80/* Target ops structure for accessing VxWorks child processes over the net */
81
82static struct target_ops vx_run_ops;
83
84/* Saved name of target host and called function for "info files".
85   Both malloc'd.  */
86
87static char *vx_host;
88static char *vx_running;	/* Called function */
89
90/* Nonzero means target that is being debugged remotely has a floating
91   point processor.  */
92
93int target_has_fp;
94
95/* Default error message when the network is forking up.  */
96
97static const char rpcerr[] = "network target debugging:  rpc error";
98
99CLIENT *pClient;		/* client used in net debugging */
100static int ptraceSock = RPC_ANYSOCK;
101
102enum clnt_stat net_clnt_call ();
103static void parse_args ();
104
105static struct timeval rpcTimeout =
106{10, 0};
107
108static char *skip_white_space ();
109static 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
116static int
117net_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
156static int
157net_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
183static int
184vx_insert_breakpoint (int addr)
185{
186  return net_break (addr, VX_BREAK_ADD);
187}
188
189/* returns 0 if successful, errno otherwise */
190
191static int
192vx_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
204static void
205vx_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
257static void
258parse_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
297static char *
298skip_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
309static char *
310find_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
335static int
336net_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
359static int
360net_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
381void
382net_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
426void
427net_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
465static void
466vx_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
480static int
481vx_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
556static void
557vx_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
564static void
565vx_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
575static void
576vx_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
621static void
622vx_mourn_inferior (void)
623{
624  pop_target ();		/* Pop back to no-child state */
625  generic_mourn_inferior ();
626}
627
628
629static void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR);
630
631struct find_sect_args
632  {
633    CORE_ADDR text_start;
634    CORE_ADDR data_start;
635    CORE_ADDR bss_start;
636  };
637
638static void find_sect (bfd *, asection *, void *);
639
640static void
641find_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
661static void
662vx_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
698static void
699vx_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\
719Kill 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
742static int
743net_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
774static int
775net_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
795static int
796net_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
811static int
812net_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
826static int
827vx_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
852static int
853net_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
868static void
869net_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
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
918static void
919sleep_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
934static ptid_t
935vx_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
1042static int
1043symbol_stub (char *arg)
1044{
1045  symbol_file_add_main (arg, 0);
1046  return 1;
1047}
1048
1049static int
1050add_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
1066static void
1067vx_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
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
1177static void
1178vx_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
1229static void
1230vx_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
1267static void
1268vx_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
1297static void
1298vx_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
1306/* Make an RPC call to the VxWorks target.
1307   Returns RPC status.  */
1308
1309static enum clnt_stat
1310net_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
1325static void
1326vx_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".  */
1338static void
1339vx_proc_open (char *name, int from_tty)
1340{
1341  error ("Use the \"run\" command to start a VxWorks process.");
1342}
1343
1344static void
1345init_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\
1350Specify 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
1365static void
1366init_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
1395void
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\
1407Set the number of seconds to wait for rpc calls to return.", &setlist),
1408     &showlist);
1409}
1410