1130812Smarcel/* Memory-access and commands for remote VxWorks processes, for GDB.
2130812Smarcel
3130812Smarcel   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
4130812Smarcel   2000, 2001, 2002 Free Software Foundation, Inc.
5130812Smarcel
6130812Smarcel   Contributed by Wind River Systems and Cygnus Support.
7130812Smarcel
8130812Smarcel   This file is part of GDB.
9130812Smarcel
10130812Smarcel   This program is free software; you can redistribute it and/or modify
11130812Smarcel   it under the terms of the GNU General Public License as published by
12130812Smarcel   the Free Software Foundation; either version 2 of the License, or
13130812Smarcel   (at your option) any later version.
14130812Smarcel
15130812Smarcel   This program is distributed in the hope that it will be useful,
16130812Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
17130812Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18130812Smarcel   GNU General Public License for more details.
19130812Smarcel
20130812Smarcel   You should have received a copy of the GNU General Public License
21130812Smarcel   along with this program; if not, write to the Free Software
22130812Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
23130812Smarcel   Boston, MA 02111-1307, USA.  */
24130812Smarcel
25130812Smarcel#include "defs.h"
26130812Smarcel#include "frame.h"
27130812Smarcel#include "inferior.h"
28130812Smarcel#include "target.h"
29130812Smarcel#include "gdbcore.h"
30130812Smarcel#include "command.h"
31130812Smarcel#include "symtab.h"
32130812Smarcel#include "complaints.h"
33130812Smarcel#include "gdbcmd.h"
34130812Smarcel#include "bfd.h"		/* Required by objfiles.h.  */
35130812Smarcel#include "symfile.h"
36130812Smarcel#include "objfiles.h"
37130812Smarcel#include "gdb-stabs.h"
38130812Smarcel#include "regcache.h"
39130812Smarcel
40130812Smarcel#include "gdb_string.h"
41130812Smarcel#include <errno.h>
42130812Smarcel#include <signal.h>
43130812Smarcel#include <fcntl.h>
44130812Smarcel#include <sys/types.h>
45130812Smarcel#include <sys/socket.h>
46130812Smarcel#define malloc bogon_malloc	/* Sun claims "char *malloc()" not void * */
47130812Smarcel#define free bogon_free		/* Sun claims "int free()" not void */
48130812Smarcel#define realloc bogon_realloc	/* Sun claims "char *realloc()", not void * */
49130812Smarcel#include <rpc/rpc.h>
50130812Smarcel#undef malloc
51130812Smarcel#undef free
52130812Smarcel#undef realloc
53130812Smarcel#include <sys/time.h>		/* UTek's <rpc/rpc.h> doesn't #incl this */
54130812Smarcel#include <netdb.h>
55130812Smarcel#include "vx-share/ptrace.h"
56130812Smarcel#include "vx-share/xdr_ptrace.h"
57130812Smarcel#include "vx-share/xdr_ld.h"
58130812Smarcel#include "vx-share/xdr_rdb.h"
59130812Smarcel#include "vx-share/dbgRpcLib.h"
60130812Smarcel
61130812Smarcel#include <symtab.h>
62130812Smarcel
63130812Smarcel/* Maximum number of bytes to transfer in a single
64130812Smarcel   PTRACE_{READ,WRITE}DATA request.  */
65130812Smarcel#define VX_MEMXFER_MAX 4096
66130812Smarcel
67130812Smarcelextern void vx_read_register ();
68130812Smarcelextern void vx_write_register ();
69130812Smarcelextern void symbol_file_command ();
70130812Smarcelextern enum stop_kind stop_soon;	/* for wait_for_inferior */
71130812Smarcel
72130812Smarcelstatic int net_step ();
73130812Smarcelstatic int net_ptrace_clnt_call ();	/* Forward decl */
74130812Smarcelstatic enum clnt_stat net_clnt_call ();		/* Forward decl */
75130812Smarcel
76130812Smarcel/* Target ops structure for accessing memory and such over the net */
77130812Smarcel
78130812Smarcelstatic struct target_ops vx_ops;
79130812Smarcel
80130812Smarcel/* Target ops structure for accessing VxWorks child processes over the net */
81130812Smarcel
82130812Smarcelstatic struct target_ops vx_run_ops;
83130812Smarcel
84130812Smarcel/* Saved name of target host and called function for "info files".
85130812Smarcel   Both malloc'd.  */
86130812Smarcel
87130812Smarcelstatic char *vx_host;
88130812Smarcelstatic char *vx_running;	/* Called function */
89130812Smarcel
90130812Smarcel/* Nonzero means target that is being debugged remotely has a floating
91130812Smarcel   point processor.  */
92130812Smarcel
93130812Smarcelint target_has_fp;
94130812Smarcel
95130812Smarcel/* Default error message when the network is forking up.  */
96130812Smarcel
97130812Smarcelstatic const char rpcerr[] = "network target debugging:  rpc error";
98130812Smarcel
99130812SmarcelCLIENT *pClient;		/* client used in net debugging */
100130812Smarcelstatic int ptraceSock = RPC_ANYSOCK;
101130812Smarcel
102130812Smarcelenum clnt_stat net_clnt_call ();
103130812Smarcelstatic void parse_args ();
104130812Smarcel
105130812Smarcelstatic struct timeval rpcTimeout =
106130812Smarcel{10, 0};
107130812Smarcel
108130812Smarcelstatic char *skip_white_space ();
109130812Smarcelstatic char *find_white_space ();
110130812Smarcel
111130812Smarcel/* Tell the VxWorks target system to download a file.
112130812Smarcel   The load addresses of the text, data, and bss segments are
113130812Smarcel   stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively).
114130812Smarcel   Returns 0 for success, -1 for failure.  */
115130812Smarcel
116130812Smarcelstatic int
117130812Smarcelnet_load (char *filename, CORE_ADDR *pTextAddr, CORE_ADDR *pDataAddr,
118130812Smarcel	  CORE_ADDR *pBssAddr)
119130812Smarcel{
120130812Smarcel  enum clnt_stat status;
121130812Smarcel  struct ldfile ldstruct;
122130812Smarcel  struct timeval load_timeout;
123130812Smarcel
124130812Smarcel  memset ((char *) &ldstruct, '\0', sizeof (ldstruct));
125130812Smarcel
126130812Smarcel  /* We invoke clnt_call () here directly, instead of through
127130812Smarcel     net_clnt_call (), because we need to set a large timeout value.
128130812Smarcel     The load on the target side can take quite a while, easily
129130812Smarcel     more than 10 seconds.  The user can kill this call by typing
130130812Smarcel     CTRL-C if there really is a problem with the load.
131130812Smarcel
132130812Smarcel     Do not change the tv_sec value without checking -- select() imposes
133130812Smarcel     a limit of 10**8 on it for no good reason that I can see...  */
134130812Smarcel
135130812Smarcel  load_timeout.tv_sec = 99999999;	/* A large number, effectively inf. */
136130812Smarcel  load_timeout.tv_usec = 0;
137130812Smarcel
138130812Smarcel  status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
139130812Smarcel		      &ldstruct, load_timeout);
140130812Smarcel
141130812Smarcel  if (status == RPC_SUCCESS)
142130812Smarcel    {
143130812Smarcel      if (*ldstruct.name == 0)	/* load failed on VxWorks side */
144130812Smarcel	return -1;
145130812Smarcel      *pTextAddr = ldstruct.txt_addr;
146130812Smarcel      *pDataAddr = ldstruct.data_addr;
147130812Smarcel      *pBssAddr = ldstruct.bss_addr;
148130812Smarcel      return 0;
149130812Smarcel    }
150130812Smarcel  else
151130812Smarcel    return -1;
152130812Smarcel}
153130812Smarcel
154130812Smarcel/* returns 0 if successful, errno if RPC failed or VxWorks complains. */
155130812Smarcel
156130812Smarcelstatic int
157130812Smarcelnet_break (int addr, u_long procnum)
158130812Smarcel{
159130812Smarcel  enum clnt_stat status;
160130812Smarcel  int break_status;
161130812Smarcel  Rptrace ptrace_in;		/* XXX This is stupid.  It doesn't need to be a ptrace
162130812Smarcel				   structure.  How about something smaller? */
163130812Smarcel
164130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
165130812Smarcel  break_status = 0;
166130812Smarcel
167130812Smarcel  ptrace_in.addr = addr;
168130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid);
169130812Smarcel
170130812Smarcel  status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
171130812Smarcel			  &break_status);
172130812Smarcel
173130812Smarcel  if (status != RPC_SUCCESS)
174130812Smarcel    return errno;
175130812Smarcel
176130812Smarcel  if (break_status == -1)
177130812Smarcel    return ENOMEM;
178130812Smarcel  return break_status;		/* probably (FIXME) zero */
179130812Smarcel}
180130812Smarcel
181130812Smarcel/* returns 0 if successful, errno otherwise */
182130812Smarcel
183130812Smarcelstatic int
184130812Smarcelvx_insert_breakpoint (int addr)
185130812Smarcel{
186130812Smarcel  return net_break (addr, VX_BREAK_ADD);
187130812Smarcel}
188130812Smarcel
189130812Smarcel/* returns 0 if successful, errno otherwise */
190130812Smarcel
191130812Smarcelstatic int
192130812Smarcelvx_remove_breakpoint (int addr)
193130812Smarcel{
194130812Smarcel  return net_break (addr, VX_BREAK_DELETE);
195130812Smarcel}
196130812Smarcel
197130812Smarcel/* Start an inferior process and sets inferior_ptid to its pid.
198130812Smarcel   EXEC_FILE is the file to run.
199130812Smarcel   ALLARGS is a string containing the arguments to the program.
200130812Smarcel   ENV is the environment vector to pass.
201130812Smarcel   Returns process id.  Errors reported with error().
202130812Smarcel   On VxWorks, we ignore exec_file.  */
203130812Smarcel
204130812Smarcelstatic void
205130812Smarcelvx_create_inferior (char *exec_file, char *args, char **env)
206130812Smarcel{
207130812Smarcel  enum clnt_stat status;
208130812Smarcel  arg_array passArgs;
209130812Smarcel  TASK_START taskStart;
210130812Smarcel
211130812Smarcel  memset ((char *) &passArgs, '\0', sizeof (passArgs));
212130812Smarcel  memset ((char *) &taskStart, '\0', sizeof (taskStart));
213130812Smarcel
214130812Smarcel  /* parse arguments, put them in passArgs */
215130812Smarcel
216130812Smarcel  parse_args (args, &passArgs);
217130812Smarcel
218130812Smarcel  if (passArgs.arg_array_len == 0)
219130812Smarcel    error ("You must specify a function name to run, and arguments if any");
220130812Smarcel
221130812Smarcel  status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
222130812Smarcel			  xdr_TASK_START, &taskStart);
223130812Smarcel
224130812Smarcel  if ((status != RPC_SUCCESS) || (taskStart.status == -1))
225130812Smarcel    error ("Can't create process on remote target machine");
226130812Smarcel
227130812Smarcel  /* Save the name of the running function */
228130812Smarcel  vx_running = savestring (passArgs.arg_array_val[0],
229130812Smarcel			   strlen (passArgs.arg_array_val[0]));
230130812Smarcel
231130812Smarcel  push_target (&vx_run_ops);
232130812Smarcel  inferior_ptid = pid_to_ptid (taskStart.pid);
233130812Smarcel
234130812Smarcel  /* We will get a trace trap after one instruction.
235130812Smarcel     Insert breakpoints and continue.  */
236130812Smarcel
237130812Smarcel  init_wait_for_inferior ();
238130812Smarcel
239130812Smarcel  /* Set up the "saved terminal modes" of the inferior
240130812Smarcel     based on what modes we are starting it with.  */
241130812Smarcel  target_terminal_init ();
242130812Smarcel
243130812Smarcel  /* Install inferior's terminal modes.  */
244130812Smarcel  target_terminal_inferior ();
245130812Smarcel
246130812Smarcel  stop_soon = STOP_QUIETLY;
247130812Smarcel  wait_for_inferior ();		/* Get the task spawn event */
248130812Smarcel  stop_soon = NO_STOP_QUIETLY;
249130812Smarcel
250130812Smarcel  /* insert_step_breakpoint ();  FIXME, do we need this?  */
251130812Smarcel  proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
252130812Smarcel}
253130812Smarcel
254130812Smarcel/* Fill ARGSTRUCT in argc/argv form with the arguments from the
255130812Smarcel   argument string ARGSTRING.  */
256130812Smarcel
257130812Smarcelstatic void
258130812Smarcelparse_args (char *arg_string, arg_array *arg_struct)
259130812Smarcel{
260130812Smarcel  int arg_count = 0;	/* number of arguments */
261130812Smarcel  int arg_index = 0;
262130812Smarcel  char *p0;
263130812Smarcel
264130812Smarcel  memset ((char *) arg_struct, '\0', sizeof (arg_array));
265130812Smarcel
266130812Smarcel  /* first count how many arguments there are */
267130812Smarcel
268130812Smarcel  p0 = arg_string;
269130812Smarcel  while (*p0 != '\0')
270130812Smarcel    {
271130812Smarcel      if (*(p0 = skip_white_space (p0)) == '\0')
272130812Smarcel	break;
273130812Smarcel      p0 = find_white_space (p0);
274130812Smarcel      arg_count++;
275130812Smarcel    }
276130812Smarcel
277130812Smarcel  arg_struct->arg_array_len = arg_count;
278130812Smarcel  arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
279130812Smarcel						 * sizeof (char *));
280130812Smarcel
281130812Smarcel  /* now copy argument strings into arg_struct.  */
282130812Smarcel
283130812Smarcel  while (*(arg_string = skip_white_space (arg_string)))
284130812Smarcel    {
285130812Smarcel      p0 = find_white_space (arg_string);
286130812Smarcel      arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
287130812Smarcel							   p0 - arg_string);
288130812Smarcel      arg_string = p0;
289130812Smarcel    }
290130812Smarcel
291130812Smarcel  arg_struct->arg_array_val[arg_count] = NULL;
292130812Smarcel}
293130812Smarcel
294130812Smarcel/* Advance a string pointer across whitespace and return a pointer
295130812Smarcel   to the first non-white character.  */
296130812Smarcel
297130812Smarcelstatic char *
298130812Smarcelskip_white_space (char *p)
299130812Smarcel{
300130812Smarcel  while (*p == ' ' || *p == '\t')
301130812Smarcel    p++;
302130812Smarcel  return p;
303130812Smarcel}
304130812Smarcel
305130812Smarcel/* Search for the first unquoted whitespace character in a string.
306130812Smarcel   Returns a pointer to the character, or to the null terminator
307130812Smarcel   if no whitespace is found.  */
308130812Smarcel
309130812Smarcelstatic char *
310130812Smarcelfind_white_space (char *p)
311130812Smarcel{
312130812Smarcel  int c;
313130812Smarcel
314130812Smarcel  while ((c = *p) != ' ' && c != '\t' && c)
315130812Smarcel    {
316130812Smarcel      if (c == '\'' || c == '"')
317130812Smarcel	{
318130812Smarcel	  while (*++p != c && *p)
319130812Smarcel	    {
320130812Smarcel	      if (*p == '\\')
321130812Smarcel		p++;
322130812Smarcel	    }
323130812Smarcel	  if (!*p)
324130812Smarcel	    break;
325130812Smarcel	}
326130812Smarcel      p++;
327130812Smarcel    }
328130812Smarcel  return p;
329130812Smarcel}
330130812Smarcel
331130812Smarcel/* Poll the VxWorks target system for an event related
332130812Smarcel   to the debugged task.
333130812Smarcel   Returns -1 if remote wait failed, task status otherwise.  */
334130812Smarcel
335130812Smarcelstatic int
336130812Smarcelnet_wait (RDB_EVENT *pEvent)
337130812Smarcel{
338130812Smarcel  int pid;
339130812Smarcel  enum clnt_stat status;
340130812Smarcel
341130812Smarcel  memset ((char *) pEvent, '\0', sizeof (RDB_EVENT));
342130812Smarcel
343130812Smarcel  pid = PIDGET (inferior_ptid);
344130812Smarcel  status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT,
345130812Smarcel			  pEvent);
346130812Smarcel
347130812Smarcel  /* return (status == RPC_SUCCESS)? pEvent->status: -1; */
348130812Smarcel  if (status == RPC_SUCCESS)
349130812Smarcel    return ((pEvent->status) ? 1 : 0);
350130812Smarcel  else if (status == RPC_TIMEDOUT)
351130812Smarcel    return (1);
352130812Smarcel  else
353130812Smarcel    return (-1);
354130812Smarcel}
355130812Smarcel
356130812Smarcel/* Suspend the remote task.
357130812Smarcel   Returns -1 if suspend fails on target system, 0 otherwise.  */
358130812Smarcel
359130812Smarcelstatic int
360130812Smarcelnet_quit (void)
361130812Smarcel{
362130812Smarcel  int pid;
363130812Smarcel  int quit_status;
364130812Smarcel  enum clnt_stat status;
365130812Smarcel
366130812Smarcel  quit_status = 0;
367130812Smarcel
368130812Smarcel  /* don't let rdbTask suspend itself by passing a pid of 0 */
369130812Smarcel
370130812Smarcel  if ((pid = PIDGET (inferior_ptid)) == 0)
371130812Smarcel    return -1;
372130812Smarcel
373130812Smarcel  status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
374130812Smarcel			  &quit_status);
375130812Smarcel
376130812Smarcel  return (status == RPC_SUCCESS) ? quit_status : -1;
377130812Smarcel}
378130812Smarcel
379130812Smarcel/* Read a register or registers from the remote system.  */
380130812Smarcel
381130812Smarcelvoid
382130812Smarcelnet_read_registers (char *reg_buf, int len, u_long procnum)
383130812Smarcel{
384130812Smarcel  int status;
385130812Smarcel  Rptrace ptrace_in;
386130812Smarcel  Ptrace_return ptrace_out;
387130812Smarcel  C_bytes out_data;
388130812Smarcel  char message[100];
389130812Smarcel
390130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
391130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
392130812Smarcel
393130812Smarcel  /* Initialize RPC input argument structure.  */
394130812Smarcel
395130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid);
396130812Smarcel  ptrace_in.info.ttype = NOINFO;
397130812Smarcel
398130812Smarcel  /* Initialize RPC return value structure.  */
399130812Smarcel
400130812Smarcel  out_data.bytes = reg_buf;
401130812Smarcel  out_data.len = len;
402130812Smarcel  ptrace_out.info.more_data = (caddr_t) & out_data;
403130812Smarcel
404130812Smarcel  /* Call RPC; take an error exit if appropriate.  */
405130812Smarcel
406130812Smarcel  status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
407130812Smarcel  if (status)
408130812Smarcel    error (rpcerr);
409130812Smarcel  if (ptrace_out.status == -1)
410130812Smarcel    {
411130812Smarcel      errno = ptrace_out.errno_num;
412130812Smarcel      sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS)
413130812Smarcel	       ? "general-purpose"
414130812Smarcel	       : "floating-point");
415130812Smarcel      perror_with_name (message);
416130812Smarcel    }
417130812Smarcel}
418130812Smarcel
419130812Smarcel/* Write register values to a VxWorks target.  REG_BUF points to a buffer
420130812Smarcel   containing the raw register values, LEN is the length of REG_BUF in
421130812Smarcel   bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or
422130812Smarcel   PTRACE_SETFPREGS).  An error exit is taken if the RPC call fails or
423130812Smarcel   if an error status is returned by the remote debug server.  This is
424130812Smarcel   a utility routine used by vx_write_register ().  */
425130812Smarcel
426130812Smarcelvoid
427130812Smarcelnet_write_registers (char *reg_buf, int len, u_long procnum)
428130812Smarcel{
429130812Smarcel  int status;
430130812Smarcel  Rptrace ptrace_in;
431130812Smarcel  Ptrace_return ptrace_out;
432130812Smarcel  C_bytes in_data;
433130812Smarcel  char message[100];
434130812Smarcel
435130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
436130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
437130812Smarcel
438130812Smarcel  /* Initialize RPC input argument structure.  */
439130812Smarcel
440130812Smarcel  in_data.bytes = reg_buf;
441130812Smarcel  in_data.len = len;
442130812Smarcel
443130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid);
444130812Smarcel  ptrace_in.info.ttype = DATA;
445130812Smarcel  ptrace_in.info.more_data = (caddr_t) & in_data;
446130812Smarcel
447130812Smarcel  /* Call RPC; take an error exit if appropriate.  */
448130812Smarcel
449130812Smarcel  status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
450130812Smarcel  if (status)
451130812Smarcel    error (rpcerr);
452130812Smarcel  if (ptrace_out.status == -1)
453130812Smarcel    {
454130812Smarcel      errno = ptrace_out.errno_num;
455130812Smarcel      sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS)
456130812Smarcel	       ? "general-purpose"
457130812Smarcel	       : "floating-point");
458130812Smarcel      perror_with_name (message);
459130812Smarcel    }
460130812Smarcel}
461130812Smarcel
462130812Smarcel/* Prepare to store registers.  Since we will store all of them,
463130812Smarcel   read out their current values now.  */
464130812Smarcel
465130812Smarcelstatic void
466130812Smarcelvx_prepare_to_store (void)
467130812Smarcel{
468130812Smarcel  /* Fetch all registers, if any of them are not yet fetched.  */
469130812Smarcel  deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES);
470130812Smarcel}
471130812Smarcel
472130812Smarcel/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
473130812Smarcel   to debugger memory starting at MYADDR.  WRITE is true if writing to the
474130812Smarcel   inferior.  TARGET is unused.
475130812Smarcel   Result is the number of bytes written or read (zero if error).  The
476130812Smarcel   protocol allows us to return a negative count, indicating that we can't
477130812Smarcel   handle the current address but can handle one N bytes further, but
478130812Smarcel   vxworks doesn't give us that information.  */
479130812Smarcel
480130812Smarcelstatic int
481130812Smarcelvx_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
482130812Smarcel		struct mem_attrib *attrib, struct target_ops *target)
483130812Smarcel{
484130812Smarcel  int status;
485130812Smarcel  Rptrace ptrace_in;
486130812Smarcel  Ptrace_return ptrace_out;
487130812Smarcel  C_bytes data;
488130812Smarcel  enum ptracereq request;
489130812Smarcel  int nleft, nxfer;
490130812Smarcel
491130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
492130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
493130812Smarcel
494130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid); /* XXX pid unnecessary for READDATA */
495130812Smarcel  ptrace_in.addr = (int) memaddr;	/* Where from */
496130812Smarcel  ptrace_in.data = len;		/* How many bytes */
497130812Smarcel
498130812Smarcel  if (write)
499130812Smarcel    {
500130812Smarcel      ptrace_in.info.ttype = DATA;
501130812Smarcel      ptrace_in.info.more_data = (caddr_t) & data;
502130812Smarcel
503130812Smarcel      data.bytes = (caddr_t) myaddr;	/* Where from */
504130812Smarcel      data.len = len;		/* How many bytes (again, for XDR) */
505130812Smarcel      request = PTRACE_WRITEDATA;
506130812Smarcel    }
507130812Smarcel  else
508130812Smarcel    {
509130812Smarcel      ptrace_out.info.more_data = (caddr_t) & data;
510130812Smarcel      request = PTRACE_READDATA;
511130812Smarcel    }
512130812Smarcel  /* Loop until the entire request has been satisfied, transferring
513130812Smarcel     at most VX_MEMXFER_MAX bytes per iteration.  Break from the loop
514130812Smarcel     if an error status is returned by the remote debug server.  */
515130812Smarcel
516130812Smarcel  nleft = len;
517130812Smarcel  status = 0;
518130812Smarcel
519130812Smarcel  while (nleft > 0 && status == 0)
520130812Smarcel    {
521130812Smarcel      nxfer = min (nleft, VX_MEMXFER_MAX);
522130812Smarcel
523130812Smarcel      ptrace_in.addr = (int) memaddr;
524130812Smarcel      ptrace_in.data = nxfer;
525130812Smarcel      data.bytes = (caddr_t) myaddr;
526130812Smarcel      data.len = nxfer;
527130812Smarcel
528130812Smarcel      /* Request a block from the remote debug server; if RPC fails,
529130812Smarcel         report an error and return to debugger command level.  */
530130812Smarcel
531130812Smarcel      if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out))
532130812Smarcel	error (rpcerr);
533130812Smarcel
534130812Smarcel      status = ptrace_out.status;
535130812Smarcel      if (status == 0)
536130812Smarcel	{
537130812Smarcel	  memaddr += nxfer;
538130812Smarcel	  myaddr += nxfer;
539130812Smarcel	  nleft -= nxfer;
540130812Smarcel	}
541130812Smarcel      else
542130812Smarcel	{
543130812Smarcel	  /* A target-side error has ocurred.  Set errno to the error
544130812Smarcel	     code chosen by the target so that a later perror () will
545130812Smarcel	     say something meaningful.  */
546130812Smarcel
547130812Smarcel	  errno = ptrace_out.errno_num;
548130812Smarcel	}
549130812Smarcel    }
550130812Smarcel
551130812Smarcel  /* Return the number of bytes transferred.  */
552130812Smarcel
553130812Smarcel  return (len - nleft);
554130812Smarcel}
555130812Smarcel
556130812Smarcelstatic void
557130812Smarcelvx_files_info (void)
558130812Smarcel{
559130812Smarcel  printf_unfiltered ("\tAttached to host `%s'", vx_host);
560130812Smarcel  printf_unfiltered (", which has %sfloating point", target_has_fp ? "" : "no ");
561130812Smarcel  printf_unfiltered (".\n");
562130812Smarcel}
563130812Smarcel
564130812Smarcelstatic void
565130812Smarcelvx_run_files_info (void)
566130812Smarcel{
567130812Smarcel  printf_unfiltered ("\tRunning %s VxWorks process %s",
568130812Smarcel		     vx_running ? "child" : "attached",
569130812Smarcel		     local_hex_string (PIDGET (inferior_ptid)));
570130812Smarcel  if (vx_running)
571130812Smarcel    printf_unfiltered (", function `%s'", vx_running);
572130812Smarcel  printf_unfiltered (".\n");
573130812Smarcel}
574130812Smarcel
575130812Smarcelstatic void
576130812Smarcelvx_resume (ptid_t ptid, int step, enum target_signal siggnal)
577130812Smarcel{
578130812Smarcel  int status;
579130812Smarcel  Rptrace ptrace_in;
580130812Smarcel  Ptrace_return ptrace_out;
581130812Smarcel  CORE_ADDR cont_addr;
582130812Smarcel
583130812Smarcel  if (ptid_equal (ptid, minus_one_ptid))
584130812Smarcel    ptid = inferior_ptid;
585130812Smarcel
586130812Smarcel  if (siggnal != 0 && siggnal != stop_signal)
587130812Smarcel    error ("Cannot send signals to VxWorks processes");
588130812Smarcel
589130812Smarcel  /* Set CONT_ADDR to the address at which we are continuing,
590130812Smarcel     or to 1 if we are continuing from where the program stopped.
591130812Smarcel     This conforms to traditional ptrace () usage, but at the same
592130812Smarcel     time has special meaning for the VxWorks remote debug server.
593130812Smarcel     If the address is not 1, the server knows that the target
594130812Smarcel     program is jumping to a new address, which requires special
595130812Smarcel     handling if there is a breakpoint at the new address.  */
596130812Smarcel
597130812Smarcel  cont_addr = read_register (PC_REGNUM);
598130812Smarcel  if (cont_addr == stop_pc)
599130812Smarcel    cont_addr = 1;
600130812Smarcel
601130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
602130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
603130812Smarcel
604130812Smarcel  ptrace_in.pid = PIDGET (ptid);
605130812Smarcel  ptrace_in.addr = cont_addr;	/* Target side insists on this, or it panics.  */
606130812Smarcel
607130812Smarcel  if (step)
608130812Smarcel    status = net_step ();
609130812Smarcel  else
610130812Smarcel    status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out);
611130812Smarcel
612130812Smarcel  if (status)
613130812Smarcel    error (rpcerr);
614130812Smarcel  if (ptrace_out.status == -1)
615130812Smarcel    {
616130812Smarcel      errno = ptrace_out.errno_num;
617130812Smarcel      perror_with_name ("Resuming remote process");
618130812Smarcel    }
619130812Smarcel}
620130812Smarcel
621130812Smarcelstatic void
622130812Smarcelvx_mourn_inferior (void)
623130812Smarcel{
624130812Smarcel  pop_target ();		/* Pop back to no-child state */
625130812Smarcel  generic_mourn_inferior ();
626130812Smarcel}
627130812Smarcel
628130812Smarcel
629130812Smarcelstatic void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR);
630130812Smarcel
631130812Smarcelstruct find_sect_args
632130812Smarcel  {
633130812Smarcel    CORE_ADDR text_start;
634130812Smarcel    CORE_ADDR data_start;
635130812Smarcel    CORE_ADDR bss_start;
636130812Smarcel  };
637130812Smarcel
638130812Smarcelstatic void find_sect (bfd *, asection *, void *);
639130812Smarcel
640130812Smarcelstatic void
641130812Smarcelfind_sect (bfd *abfd, asection *sect, void *obj)
642130812Smarcel{
643130812Smarcel  struct find_sect_args *args = (struct find_sect_args *) obj;
644130812Smarcel
645130812Smarcel  if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY))
646130812Smarcel    args->text_start = bfd_get_section_vma (abfd, sect);
647130812Smarcel  else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC)
648130812Smarcel    {
649130812Smarcel      if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
650130812Smarcel	{
651130812Smarcel	  /* Exclude .ctor and .dtor sections which have SEC_CODE set but not
652130812Smarcel	     SEC_DATA.  */
653130812Smarcel	  if (bfd_get_section_flags (abfd, sect) & SEC_DATA)
654130812Smarcel	    args->data_start = bfd_get_section_vma (abfd, sect);
655130812Smarcel	}
656130812Smarcel      else
657130812Smarcel	args->bss_start = bfd_get_section_vma (abfd, sect);
658130812Smarcel    }
659130812Smarcel}
660130812Smarcel
661130812Smarcelstatic void
662130812Smarcelvx_add_symbols (char *name, int from_tty, CORE_ADDR text_addr,
663130812Smarcel		CORE_ADDR data_addr, CORE_ADDR bss_addr)
664130812Smarcel{
665130812Smarcel  struct section_offsets *offs;
666130812Smarcel  struct objfile *objfile;
667130812Smarcel  struct find_sect_args ss;
668130812Smarcel
669130812Smarcel  /* It might be nice to suppress the breakpoint_re_set which happens here
670130812Smarcel     because we are going to do one again after the objfile_relocate.  */
671130812Smarcel  objfile = symbol_file_add (name, from_tty, NULL, 0, 0);
672130812Smarcel
673130812Smarcel  /* This is a (slightly cheesy) way of superceding the old symbols.  A less
674130812Smarcel     cheesy way would be to find the objfile with the same name and
675130812Smarcel     free_objfile it.  */
676130812Smarcel  objfile_to_front (objfile);
677130812Smarcel
678130812Smarcel  offs =
679130812Smarcel    (struct section_offsets *)
680130812Smarcel    alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
681130812Smarcel  memcpy (offs, objfile->section_offsets,
682130812Smarcel          SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
683130812Smarcel
684130812Smarcel  ss.text_start = 0;
685130812Smarcel  ss.data_start = 0;
686130812Smarcel  ss.bss_start = 0;
687130812Smarcel  bfd_map_over_sections (objfile->obfd, find_sect, &ss);
688130812Smarcel
689130812Smarcel  /* Both COFF and b.out frontends use these SECT_OFF_* values.  */
690130812Smarcel  offs->offsets[SECT_OFF_TEXT (objfile)]  = text_addr - ss.text_start;
691130812Smarcel  offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start;
692130812Smarcel  offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start;
693130812Smarcel  objfile_relocate (objfile, offs);
694130812Smarcel}
695130812Smarcel
696130812Smarcel/* This function allows the addition of incrementally linked object files.  */
697130812Smarcel
698130812Smarcelstatic void
699130812Smarcelvx_load_command (char *arg_string, int from_tty)
700130812Smarcel{
701130812Smarcel  CORE_ADDR text_addr;
702130812Smarcel  CORE_ADDR data_addr;
703130812Smarcel  CORE_ADDR bss_addr;
704130812Smarcel
705130812Smarcel  if (arg_string == 0)
706130812Smarcel    error ("The load command takes a file name");
707130812Smarcel
708130812Smarcel  arg_string = tilde_expand (arg_string);
709130812Smarcel  make_cleanup (xfree, arg_string);
710130812Smarcel
711130812Smarcel  dont_repeat ();
712130812Smarcel
713130812Smarcel  /* Refuse to load the module if a debugged task is running.  Doing so
714130812Smarcel     can have a number of unpleasant consequences to the running task.  */
715130812Smarcel
716130812Smarcel  if (PIDGET (inferior_ptid) != 0 && target_has_execution)
717130812Smarcel    {
718130812Smarcel      if (query ("You may not load a module while the target task is running.\n\
719130812SmarcelKill the target task? "))
720130812Smarcel	target_kill ();
721130812Smarcel      else
722130812Smarcel	error ("Load canceled.");
723130812Smarcel    }
724130812Smarcel
725130812Smarcel  QUIT;
726130812Smarcel  immediate_quit++;
727130812Smarcel  if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
728130812Smarcel    error ("Load failed on target machine");
729130812Smarcel  immediate_quit--;
730130812Smarcel
731130812Smarcel  vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
732130812Smarcel
733130812Smarcel  /* Getting new symbols may change our opinion about what is
734130812Smarcel     frameless.  */
735130812Smarcel  reinit_frame_cache ();
736130812Smarcel}
737130812Smarcel
738130812Smarcel/* Single step the target program at the source or machine level.
739130812Smarcel   Takes an error exit if rpc fails.
740130812Smarcel   Returns -1 if remote single-step operation fails, else 0.  */
741130812Smarcel
742130812Smarcelstatic int
743130812Smarcelnet_step (void)
744130812Smarcel{
745130812Smarcel  enum clnt_stat status;
746130812Smarcel  int step_status;
747130812Smarcel  SOURCE_STEP source_step;
748130812Smarcel
749130812Smarcel  source_step.taskId = PIDGET (inferior_ptid);
750130812Smarcel
751130812Smarcel  if (step_range_end)
752130812Smarcel    {
753130812Smarcel      source_step.startAddr = step_range_start;
754130812Smarcel      source_step.endAddr = step_range_end;
755130812Smarcel    }
756130812Smarcel  else
757130812Smarcel    {
758130812Smarcel      source_step.startAddr = 0;
759130812Smarcel      source_step.endAddr = 0;
760130812Smarcel    }
761130812Smarcel
762130812Smarcel  status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
763130812Smarcel			  xdr_int, &step_status);
764130812Smarcel
765130812Smarcel  if (status == RPC_SUCCESS)
766130812Smarcel    return step_status;
767130812Smarcel  else
768130812Smarcel    error (rpcerr);
769130812Smarcel}
770130812Smarcel
771130812Smarcel/* Emulate ptrace using RPC calls to the VxWorks target system.
772130812Smarcel   Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
773130812Smarcel
774130812Smarcelstatic int
775130812Smarcelnet_ptrace_clnt_call (enum ptracereq request, Rptrace *pPtraceIn,
776130812Smarcel		      Ptrace_return *pPtraceOut)
777130812Smarcel{
778130812Smarcel  enum clnt_stat status;
779130812Smarcel
780130812Smarcel  status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
781130812Smarcel			  pPtraceOut);
782130812Smarcel
783130812Smarcel  if (status != RPC_SUCCESS)
784130812Smarcel    return -1;
785130812Smarcel
786130812Smarcel  return 0;
787130812Smarcel}
788130812Smarcel
789130812Smarcel/* Query the target for the name of the file from which VxWorks was
790130812Smarcel   booted.  pBootFile is the address of a pointer to the buffer to
791130812Smarcel   receive the file name; if the pointer pointed to by pBootFile is
792130812Smarcel   NULL, memory for the buffer will be allocated by XDR.
793130812Smarcel   Returns -1 if rpc failed, 0 otherwise.  */
794130812Smarcel
795130812Smarcelstatic int
796130812Smarcelnet_get_boot_file (char **pBootFile)
797130812Smarcel{
798130812Smarcel  enum clnt_stat status;
799130812Smarcel
800130812Smarcel  status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
801130812Smarcel			  xdr_wrapstring, pBootFile);
802130812Smarcel  return (status == RPC_SUCCESS) ? 0 : -1;
803130812Smarcel}
804130812Smarcel
805130812Smarcel/* Fetch a list of loaded object modules from the VxWorks target
806130812Smarcel   and store in PLOADTABLE.
807130812Smarcel   Returns -1 if rpc failed, 0 otherwise
808130812Smarcel   There's no way to check if the returned loadTable is correct.
809130812Smarcel   VxWorks doesn't check it.  */
810130812Smarcel
811130812Smarcelstatic int
812130812Smarcelnet_get_symbols (ldtabl *pLoadTable)
813130812Smarcel{
814130812Smarcel  enum clnt_stat status;
815130812Smarcel
816130812Smarcel  memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
817130812Smarcel
818130812Smarcel  status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
819130812Smarcel  return (status == RPC_SUCCESS) ? 0 : -1;
820130812Smarcel}
821130812Smarcel
822130812Smarcel/* Look up a symbol in the VxWorks target's symbol table.
823130812Smarcel   Returns status of symbol read on target side (0=success, -1=fail)
824130812Smarcel   Returns -1 and complain()s if rpc fails.  */
825130812Smarcel
826130812Smarcelstatic int
827130812Smarcelvx_lookup_symbol (char *name,	/* symbol name */
828130812Smarcel		  CORE_ADDR *pAddr)
829130812Smarcel{
830130812Smarcel  enum clnt_stat status;
831130812Smarcel  SYMBOL_ADDR symbolAddr;
832130812Smarcel
833130812Smarcel  *pAddr = 0;
834130812Smarcel  memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
835130812Smarcel
836130812Smarcel  status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
837130812Smarcel			  xdr_SYMBOL_ADDR, &symbolAddr);
838130812Smarcel  if (status != RPC_SUCCESS)
839130812Smarcel    {
840130812Smarcel      complaint (&symfile_complaints, "Lost contact with VxWorks target");
841130812Smarcel      return -1;
842130812Smarcel    }
843130812Smarcel
844130812Smarcel  *pAddr = symbolAddr.addr;
845130812Smarcel  return symbolAddr.status;
846130812Smarcel}
847130812Smarcel
848130812Smarcel/* Check to see if the VxWorks target has a floating point coprocessor.
849130812Smarcel   Returns 1 if target has floating point processor, 0 otherwise.
850130812Smarcel   Calls error() if rpc fails.  */
851130812Smarcel
852130812Smarcelstatic int
853130812Smarcelnet_check_for_fp (void)
854130812Smarcel{
855130812Smarcel  enum clnt_stat status;
856130812Smarcel  bool_t fp = 0;		/* true if fp processor is present on target board */
857130812Smarcel
858130812Smarcel  status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
859130812Smarcel  if (status != RPC_SUCCESS)
860130812Smarcel    error (rpcerr);
861130812Smarcel
862130812Smarcel  return (int) fp;
863130812Smarcel}
864130812Smarcel
865130812Smarcel/* Establish an RPC connection with the VxWorks target system.
866130812Smarcel   Calls error () if unable to establish connection.  */
867130812Smarcel
868130812Smarcelstatic void
869130812Smarcelnet_connect (char *host)
870130812Smarcel{
871130812Smarcel  struct sockaddr_in destAddr;
872130812Smarcel  struct hostent *destHost;
873130812Smarcel  unsigned long addr;
874130812Smarcel
875130812Smarcel  /* Get the internet address for the given host.  Allow a numeric
876130812Smarcel     IP address or a hostname.  */
877130812Smarcel
878130812Smarcel  addr = inet_addr (host);
879130812Smarcel  if (addr == -1)
880130812Smarcel    {
881130812Smarcel      destHost = (struct hostent *) gethostbyname (host);
882130812Smarcel      if (destHost == NULL)
883130812Smarcel	/* FIXME: Probably should include hostname here in quotes.
884130812Smarcel	   For example if the user types "target vxworks vx960 " it should
885130812Smarcel	   say "Invalid host `vx960 '." not just "Invalid hostname".  */
886130812Smarcel	error ("Invalid hostname.  Couldn't find remote host address.");
887130812Smarcel      addr = *(unsigned long *) destHost->h_addr;
888130812Smarcel    }
889130812Smarcel
890130812Smarcel  memset (&destAddr, '\0', sizeof (destAddr));
891130812Smarcel
892130812Smarcel  destAddr.sin_addr.s_addr = addr;
893130812Smarcel  destAddr.sin_family = AF_INET;
894130812Smarcel  destAddr.sin_port = 0;	/* set to actual port that remote
895130812Smarcel				   ptrace is listening on.  */
896130812Smarcel
897130812Smarcel  /* Create a tcp client transport on which to issue
898130812Smarcel     calls to the remote ptrace server.  */
899130812Smarcel
900130812Smarcel  ptraceSock = RPC_ANYSOCK;
901130812Smarcel  pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
902130812Smarcel  /* FIXME, here is where we deal with different version numbers of the
903130812Smarcel     proto */
904130812Smarcel
905130812Smarcel  if (pClient == NULL)
906130812Smarcel    {
907130812Smarcel      clnt_pcreateerror ("\tnet_connect");
908130812Smarcel      error ("Couldn't connect to remote target.");
909130812Smarcel    }
910130812Smarcel}
911130812Smarcel
912130812Smarcel/* Sleep for the specified number of milliseconds
913130812Smarcel * (assumed to be less than 1000).
914130812Smarcel * If select () is interrupted, returns immediately;
915130812Smarcel * takes an error exit if select () fails for some other reason.
916130812Smarcel */
917130812Smarcel
918130812Smarcelstatic void
919130812Smarcelsleep_ms (long ms)
920130812Smarcel{
921130812Smarcel  struct timeval select_timeout;
922130812Smarcel  int status;
923130812Smarcel
924130812Smarcel  select_timeout.tv_sec = 0;
925130812Smarcel  select_timeout.tv_usec = ms * 1000;
926130812Smarcel
927130812Smarcel  status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
928130812Smarcel		   &select_timeout);
929130812Smarcel
930130812Smarcel  if (status < 0 && errno != EINTR)
931130812Smarcel    perror_with_name ("select");
932130812Smarcel}
933130812Smarcel
934130812Smarcelstatic ptid_t
935130812Smarcelvx_wait (ptid_t ptid_to_wait_for, struct target_waitstatus *status)
936130812Smarcel{
937130812Smarcel  int pid;
938130812Smarcel  RDB_EVENT rdbEvent;
939130812Smarcel  int quit_failed;
940130812Smarcel
941130812Smarcel  do
942130812Smarcel    {
943130812Smarcel      /* If CTRL-C is hit during this loop,
944130812Smarcel         suspend the inferior process.  */
945130812Smarcel
946130812Smarcel      quit_failed = 0;
947130812Smarcel      if (quit_flag)
948130812Smarcel	{
949130812Smarcel	  quit_failed = (net_quit () == -1);
950130812Smarcel	  quit_flag = 0;
951130812Smarcel	}
952130812Smarcel
953130812Smarcel      /* If a net_quit () or net_wait () call has failed,
954130812Smarcel         allow the user to break the connection with the target.
955130812Smarcel         We can't simply error () out of this loop, since the
956130812Smarcel         data structures representing the state of the inferior
957130812Smarcel         are in an inconsistent state.  */
958130812Smarcel
959130812Smarcel      if (quit_failed || net_wait (&rdbEvent) == -1)
960130812Smarcel	{
961130812Smarcel	  terminal_ours ();
962130812Smarcel	  if (query ("Can't %s.  Disconnect from target system? ",
963130812Smarcel		     (quit_failed) ? "suspend remote task"
964130812Smarcel		     : "get status of remote task"))
965130812Smarcel	    {
966130812Smarcel	      target_mourn_inferior ();
967130812Smarcel	      error ("Use the \"target\" command to reconnect.");
968130812Smarcel	    }
969130812Smarcel	  else
970130812Smarcel	    {
971130812Smarcel	      terminal_inferior ();
972130812Smarcel	      continue;
973130812Smarcel	    }
974130812Smarcel	}
975130812Smarcel
976130812Smarcel      pid = rdbEvent.taskId;
977130812Smarcel      if (pid == 0)
978130812Smarcel	{
979130812Smarcel	  sleep_ms (200);	/* FIXME Don't kill the network too badly */
980130812Smarcel	}
981130812Smarcel      else if (pid != PIDGET (inferior_ptid))
982130812Smarcel	internal_error (__FILE__, __LINE__,
983130812Smarcel			"Bad pid for debugged task: %s\n",
984130812Smarcel			local_hex_string ((unsigned long) pid));
985130812Smarcel    }
986130812Smarcel  while (pid == 0);
987130812Smarcel
988130812Smarcel  /* The mostly likely kind.  */
989130812Smarcel  status->kind = TARGET_WAITKIND_STOPPED;
990130812Smarcel
991130812Smarcel  switch (rdbEvent.eventType)
992130812Smarcel    {
993130812Smarcel    case EVENT_EXIT:
994130812Smarcel      status->kind = TARGET_WAITKIND_EXITED;
995130812Smarcel      /* FIXME is it possible to distinguish between a
996130812Smarcel         normal vs abnormal exit in VxWorks? */
997130812Smarcel      status->value.integer = 0;
998130812Smarcel      break;
999130812Smarcel
1000130812Smarcel    case EVENT_START:
1001130812Smarcel      /* Task was just started. */
1002130812Smarcel      status->value.sig = TARGET_SIGNAL_TRAP;
1003130812Smarcel      break;
1004130812Smarcel
1005130812Smarcel    case EVENT_STOP:
1006130812Smarcel      status->value.sig = TARGET_SIGNAL_TRAP;
1007130812Smarcel      /* XXX was it stopped by a signal?  act accordingly */
1008130812Smarcel      break;
1009130812Smarcel
1010130812Smarcel    case EVENT_BREAK:		/* Breakpoint was hit. */
1011130812Smarcel      status->value.sig = TARGET_SIGNAL_TRAP;
1012130812Smarcel      break;
1013130812Smarcel
1014130812Smarcel    case EVENT_SUSPEND:	/* Task was suspended, probably by ^C. */
1015130812Smarcel      status->value.sig = TARGET_SIGNAL_INT;
1016130812Smarcel      break;
1017130812Smarcel
1018130812Smarcel    case EVENT_BUS_ERR:	/* Task made evil nasty reference. */
1019130812Smarcel      status->value.sig = TARGET_SIGNAL_BUS;
1020130812Smarcel      break;
1021130812Smarcel
1022130812Smarcel    case EVENT_ZERO_DIV:	/* Division by zero */
1023130812Smarcel      status->value.sig = TARGET_SIGNAL_FPE;
1024130812Smarcel      break;
1025130812Smarcel
1026130812Smarcel    case EVENT_SIGNAL:
1027130812Smarcel#ifdef I80960
1028130812Smarcel      status->value.sig = i960_fault_to_signal (rdbEvent.sigType);
1029130812Smarcel#else
1030130812Smarcel      /* Back in the old days, before enum target_signal, this code used
1031130812Smarcel         to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL
1032130812Smarcel         would take care of it.  But PRINT_RANDOM_SIGNAL has never been
1033130812Smarcel         defined except on the i960, so I don't really know what we are
1034130812Smarcel         supposed to do on other architectures.  */
1035130812Smarcel      status->value.sig = TARGET_SIGNAL_UNKNOWN;
1036130812Smarcel#endif
1037130812Smarcel      break;
1038130812Smarcel    }				/* switch */
1039130812Smarcel  return pid_to_ptid (pid);
1040130812Smarcel}
1041130812Smarcel
1042130812Smarcelstatic int
1043130812Smarcelsymbol_stub (char *arg)
1044130812Smarcel{
1045130812Smarcel  symbol_file_add_main (arg, 0);
1046130812Smarcel  return 1;
1047130812Smarcel}
1048130812Smarcel
1049130812Smarcelstatic int
1050130812Smarceladd_symbol_stub (char *arg)
1051130812Smarcel{
1052130812Smarcel  struct ldfile *pLoadFile = (struct ldfile *) arg;
1053130812Smarcel
1054130812Smarcel  printf_unfiltered ("\t%s: ", pLoadFile->name);
1055130812Smarcel  vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr,
1056130812Smarcel		  pLoadFile->data_addr, pLoadFile->bss_addr);
1057130812Smarcel  printf_unfiltered ("ok\n");
1058130812Smarcel  return 1;
1059130812Smarcel}
1060130812Smarcel/* Target command for VxWorks target systems.
1061130812Smarcel
1062130812Smarcel   Used in vxgdb.  Takes the name of a remote target machine
1063130812Smarcel   running vxWorks and connects to it to initialize remote network
1064130812Smarcel   debugging.  */
1065130812Smarcel
1066130812Smarcelstatic void
1067130812Smarcelvx_open (char *args, int from_tty)
1068130812Smarcel{
1069130812Smarcel  extern int close ();
1070130812Smarcel  char *bootFile;
1071130812Smarcel  extern char *source_path;
1072130812Smarcel  struct ldtabl loadTable;
1073130812Smarcel  struct ldfile *pLoadFile;
1074130812Smarcel  int i;
1075130812Smarcel  extern CLIENT *pClient;
1076130812Smarcel  int symbols_added = 0;
1077130812Smarcel
1078130812Smarcel  if (!args)
1079130812Smarcel    error_no_arg ("target machine name");
1080130812Smarcel
1081130812Smarcel  target_preopen (from_tty);
1082130812Smarcel
1083130812Smarcel  unpush_target (&vx_ops);
1084130812Smarcel  printf_unfiltered ("Attaching remote machine across net...\n");
1085130812Smarcel  gdb_flush (gdb_stdout);
1086130812Smarcel
1087130812Smarcel  /* Allow the user to kill the connect attempt by typing ^C.
1088130812Smarcel     Wait until the call to target_has_fp () completes before
1089130812Smarcel     disallowing an immediate quit, since even if net_connect ()
1090130812Smarcel     is successful, the remote debug server might be hung.  */
1091130812Smarcel
1092130812Smarcel  immediate_quit++;
1093130812Smarcel
1094130812Smarcel  net_connect (args);
1095130812Smarcel  target_has_fp = net_check_for_fp ();
1096130812Smarcel  printf_filtered ("Connected to %s.\n", args);
1097130812Smarcel
1098130812Smarcel  immediate_quit--;
1099130812Smarcel
1100130812Smarcel  push_target (&vx_ops);
1101130812Smarcel
1102130812Smarcel  /* Save a copy of the target host's name.  */
1103130812Smarcel  vx_host = savestring (args, strlen (args));
1104130812Smarcel
1105130812Smarcel  /* Find out the name of the file from which the target was booted
1106130812Smarcel     and load its symbol table.  */
1107130812Smarcel
1108130812Smarcel  printf_filtered ("Looking in Unix path for all loaded modules:\n");
1109130812Smarcel  bootFile = NULL;
1110130812Smarcel  if (!net_get_boot_file (&bootFile))
1111130812Smarcel    {
1112130812Smarcel      if (*bootFile)
1113130812Smarcel	{
1114130812Smarcel	  printf_filtered ("\t%s: ", bootFile);
1115130812Smarcel	  /* This assumes that the kernel is never relocated.  Hope that is an
1116130812Smarcel	     accurate assumption.  */
1117130812Smarcel	  if (catch_errors
1118130812Smarcel	      (symbol_stub,
1119130812Smarcel	       bootFile,
1120130812Smarcel	       "Error while reading symbols from boot file:\n",
1121130812Smarcel	       RETURN_MASK_ALL))
1122130812Smarcel	    puts_filtered ("ok\n");
1123130812Smarcel	}
1124130812Smarcel      else if (from_tty)
1125130812Smarcel	printf_unfiltered ("VxWorks kernel symbols not loaded.\n");
1126130812Smarcel    }
1127130812Smarcel  else
1128130812Smarcel    error ("Can't retrieve boot file name from target machine.");
1129130812Smarcel
1130130812Smarcel  clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1131130812Smarcel
1132130812Smarcel  if (net_get_symbols (&loadTable) != 0)
1133130812Smarcel    error ("Can't read loaded modules from target machine");
1134130812Smarcel
1135130812Smarcel  i = 0 - 1;
1136130812Smarcel  while (++i < loadTable.tbl_size)
1137130812Smarcel    {
1138130812Smarcel      QUIT;			/* FIXME, avoids clnt_freeres below:  mem leak */
1139130812Smarcel      pLoadFile = &loadTable.tbl_ent[i];
1140130812Smarcel#ifdef WRS_ORIG
1141130812Smarcel      {
1142130812Smarcel	int desc;
1143130812Smarcel	struct cleanup *old_chain;
1144130812Smarcel	char *fullname = NULL;
1145130812Smarcel
1146130812Smarcel	desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1147130812Smarcel	if (desc < 0)
1148130812Smarcel	  perror_with_name (pLoadFile->name);
1149130812Smarcel	old_chain = make_cleanup (close, desc);
1150130812Smarcel	add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1151130812Smarcel			  pLoadFile->bss_addr);
1152130812Smarcel	do_cleanups (old_chain);
1153130812Smarcel      }
1154130812Smarcel#else
1155130812Smarcel      /* FIXME: Is there something better to search than the PATH? (probably
1156130812Smarcel         not the source path, since source might be in different directories
1157130812Smarcel         than objects.  */
1158130812Smarcel
1159130812Smarcel      if (catch_errors (add_symbol_stub, (char *) pLoadFile, (char *) 0,
1160130812Smarcel			RETURN_MASK_ALL))
1161130812Smarcel	symbols_added = 1;
1162130812Smarcel#endif
1163130812Smarcel    }
1164130812Smarcel  printf_filtered ("Done.\n");
1165130812Smarcel
1166130812Smarcel  clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1167130812Smarcel
1168130812Smarcel  /* Getting new symbols may change our opinion about what is
1169130812Smarcel     frameless.  */
1170130812Smarcel  if (symbols_added)
1171130812Smarcel    reinit_frame_cache ();
1172130812Smarcel}
1173130812Smarcel
1174130812Smarcel/* Takes a task started up outside of gdb and ``attaches'' to it.
1175130812Smarcel   This stops it cold in its tracks and allows us to start tracing it.  */
1176130812Smarcel
1177130812Smarcelstatic void
1178130812Smarcelvx_attach (char *args, int from_tty)
1179130812Smarcel{
1180130812Smarcel  unsigned long pid;
1181130812Smarcel  char *cptr = 0;
1182130812Smarcel  Rptrace ptrace_in;
1183130812Smarcel  Ptrace_return ptrace_out;
1184130812Smarcel  int status;
1185130812Smarcel
1186130812Smarcel  if (!args)
1187130812Smarcel    error_no_arg ("process-id to attach");
1188130812Smarcel
1189130812Smarcel  pid = strtoul (args, &cptr, 0);
1190130812Smarcel  if ((cptr == args) || (*cptr != '\0'))
1191130812Smarcel    error ("Invalid process-id -- give a single number in decimal or 0xhex");
1192130812Smarcel
1193130812Smarcel  if (from_tty)
1194130812Smarcel    printf_unfiltered ("Attaching pid %s.\n",
1195130812Smarcel		       local_hex_string ((unsigned long) pid));
1196130812Smarcel
1197130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1198130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1199130812Smarcel  ptrace_in.pid = pid;
1200130812Smarcel
1201130812Smarcel  status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1202130812Smarcel  if (status == -1)
1203130812Smarcel    error (rpcerr);
1204130812Smarcel  if (ptrace_out.status == -1)
1205130812Smarcel    {
1206130812Smarcel      errno = ptrace_out.errno_num;
1207130812Smarcel      perror_with_name ("Attaching remote process");
1208130812Smarcel    }
1209130812Smarcel
1210130812Smarcel  /* It worked... */
1211130812Smarcel
1212130812Smarcel  inferior_ptid = pid_to_ptid (pid);
1213130812Smarcel  push_target (&vx_run_ops);
1214130812Smarcel
1215130812Smarcel  if (vx_running)
1216130812Smarcel    xfree (vx_running);
1217130812Smarcel  vx_running = 0;
1218130812Smarcel}
1219130812Smarcel
1220130812Smarcel/* detach_command --
1221130812Smarcel   takes a program previously attached to and detaches it.
1222130812Smarcel   The program resumes execution and will no longer stop
1223130812Smarcel   on signals, etc.  We better not have left any breakpoints
1224130812Smarcel   in the program or it'll die when it hits one.  For this
1225130812Smarcel   to work, it may be necessary for the process to have been
1226130812Smarcel   previously attached.  It *might* work if the program was
1227130812Smarcel   started via the normal ptrace (PTRACE_TRACEME).  */
1228130812Smarcel
1229130812Smarcelstatic void
1230130812Smarcelvx_detach (char *args, int from_tty)
1231130812Smarcel{
1232130812Smarcel  Rptrace ptrace_in;
1233130812Smarcel  Ptrace_return ptrace_out;
1234130812Smarcel  int signal = 0;
1235130812Smarcel  int status;
1236130812Smarcel
1237130812Smarcel  if (args)
1238130812Smarcel    error ("Argument given to VxWorks \"detach\".");
1239130812Smarcel
1240130812Smarcel  if (from_tty)
1241130812Smarcel    printf_unfiltered ("Detaching pid %s.\n",
1242130812Smarcel		       local_hex_string (
1243130812Smarcel		         (unsigned long) PIDGET (inferior_ptid)));
1244130812Smarcel
1245130812Smarcel  if (args)			/* FIXME, should be possible to leave suspended */
1246130812Smarcel    signal = atoi (args);
1247130812Smarcel
1248130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1249130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1250130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid);
1251130812Smarcel
1252130812Smarcel  status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1253130812Smarcel  if (status == -1)
1254130812Smarcel    error (rpcerr);
1255130812Smarcel  if (ptrace_out.status == -1)
1256130812Smarcel    {
1257130812Smarcel      errno = ptrace_out.errno_num;
1258130812Smarcel      perror_with_name ("Detaching VxWorks process");
1259130812Smarcel    }
1260130812Smarcel
1261130812Smarcel  inferior_ptid = null_ptid;
1262130812Smarcel  pop_target ();		/* go back to non-executing VxWorks connection */
1263130812Smarcel}
1264130812Smarcel
1265130812Smarcel/* vx_kill -- takes a running task and wipes it out.  */
1266130812Smarcel
1267130812Smarcelstatic void
1268130812Smarcelvx_kill (void)
1269130812Smarcel{
1270130812Smarcel  Rptrace ptrace_in;
1271130812Smarcel  Ptrace_return ptrace_out;
1272130812Smarcel  int status;
1273130812Smarcel
1274130812Smarcel  printf_unfiltered ("Killing pid %s.\n", local_hex_string ((unsigned long) PIDGET (inferior_ptid)));
1275130812Smarcel
1276130812Smarcel  memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
1277130812Smarcel  memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
1278130812Smarcel  ptrace_in.pid = PIDGET (inferior_ptid);
1279130812Smarcel
1280130812Smarcel  status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1281130812Smarcel  if (status == -1)
1282130812Smarcel    warning (rpcerr);
1283130812Smarcel  else if (ptrace_out.status == -1)
1284130812Smarcel    {
1285130812Smarcel      errno = ptrace_out.errno_num;
1286130812Smarcel      perror_with_name ("Killing VxWorks process");
1287130812Smarcel    }
1288130812Smarcel
1289130812Smarcel  /* If it gives good status, the process is *gone*, no events remain.
1290130812Smarcel     If the kill failed, assume the process is gone anyhow.  */
1291130812Smarcel  inferior_ptid = null_ptid;
1292130812Smarcel  pop_target ();		/* go back to non-executing VxWorks connection */
1293130812Smarcel}
1294130812Smarcel
1295130812Smarcel/* Clean up from the VxWorks process target as it goes away.  */
1296130812Smarcel
1297130812Smarcelstatic void
1298130812Smarcelvx_proc_close (int quitting)
1299130812Smarcel{
1300130812Smarcel  inferior_ptid = null_ptid;	/* No longer have a process.  */
1301130812Smarcel  if (vx_running)
1302130812Smarcel    xfree (vx_running);
1303130812Smarcel  vx_running = 0;
1304130812Smarcel}
1305130812Smarcel
1306130812Smarcel/* Make an RPC call to the VxWorks target.
1307130812Smarcel   Returns RPC status.  */
1308130812Smarcel
1309130812Smarcelstatic enum clnt_stat
1310130812Smarcelnet_clnt_call (enum ptracereq procNum, xdrproc_t inProc, char *in,
1311130812Smarcel	       xdrproc_t outProc, char *out)
1312130812Smarcel{
1313130812Smarcel  enum clnt_stat status;
1314130812Smarcel
1315130812Smarcel  status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1316130812Smarcel
1317130812Smarcel  if (status != RPC_SUCCESS)
1318130812Smarcel    clnt_perrno (status);
1319130812Smarcel
1320130812Smarcel  return status;
1321130812Smarcel}
1322130812Smarcel
1323130812Smarcel/* Clean up before losing control.  */
1324130812Smarcel
1325130812Smarcelstatic void
1326130812Smarcelvx_close (int quitting)
1327130812Smarcel{
1328130812Smarcel  if (pClient)
1329130812Smarcel    clnt_destroy (pClient);	/* The net connection */
1330130812Smarcel  pClient = 0;
1331130812Smarcel
1332130812Smarcel  if (vx_host)
1333130812Smarcel    xfree (vx_host);		/* The hostname */
1334130812Smarcel  vx_host = 0;
1335130812Smarcel}
1336130812Smarcel
1337130812Smarcel/* A vxprocess target should be started via "run" not "target".  */
1338130812Smarcelstatic void
1339130812Smarcelvx_proc_open (char *name, int from_tty)
1340130812Smarcel{
1341130812Smarcel  error ("Use the \"run\" command to start a VxWorks process.");
1342130812Smarcel}
1343130812Smarcel
1344130812Smarcelstatic void
1345130812Smarcelinit_vx_ops (void)
1346130812Smarcel{
1347130812Smarcel  vx_ops.to_shortname = "vxworks";
1348130812Smarcel  vx_ops.to_longname = "VxWorks target memory via RPC over TCP/IP";
1349130812Smarcel  vx_ops.to_doc = "Use VxWorks target memory.  \n\
1350130812SmarcelSpecify the name of the machine to connect to.";
1351130812Smarcel  vx_ops.to_open = vx_open;
1352130812Smarcel  vx_ops.to_close = vx_close;
1353130812Smarcel  vx_ops.to_attach = vx_attach;
1354130812Smarcel  vx_ops.to_xfer_memory = vx_xfer_memory;
1355130812Smarcel  vx_ops.to_files_info = vx_files_info;
1356130812Smarcel  vx_ops.to_load = vx_load_command;
1357130812Smarcel  vx_ops.to_lookup_symbol = vx_lookup_symbol;
1358130812Smarcel  vx_ops.to_create_inferior = vx_create_inferior;
1359130812Smarcel  vx_ops.to_stratum = core_stratum;
1360130812Smarcel  vx_ops.to_has_all_memory = 1;
1361130812Smarcel  vx_ops.to_has_memory = 1;
1362130812Smarcel  vx_ops.to_magic = OPS_MAGIC;	/* Always the last thing */
1363130812Smarcel};
1364130812Smarcel
1365130812Smarcelstatic void
1366130812Smarcelinit_vx_run_ops (void)
1367130812Smarcel{
1368130812Smarcel  vx_run_ops.to_shortname = "vxprocess";
1369130812Smarcel  vx_run_ops.to_longname = "VxWorks process";
1370130812Smarcel  vx_run_ops.to_doc = "VxWorks process; started by the \"run\" command.";
1371130812Smarcel  vx_run_ops.to_open = vx_proc_open;
1372130812Smarcel  vx_run_ops.to_close = vx_proc_close;
1373130812Smarcel  vx_run_ops.to_detach = vx_detach;
1374130812Smarcel  vx_run_ops.to_resume = vx_resume;
1375130812Smarcel  vx_run_ops.to_wait = vx_wait;
1376130812Smarcel  vx_run_ops.to_fetch_registers = vx_read_register;
1377130812Smarcel  vx_run_ops.to_store_registers = vx_write_register;
1378130812Smarcel  vx_run_ops.to_prepare_to_store = vx_prepare_to_store;
1379130812Smarcel  vx_run_ops.to_xfer_memory = vx_xfer_memory;
1380130812Smarcel  vx_run_ops.to_files_info = vx_run_files_info;
1381130812Smarcel  vx_run_ops.to_insert_breakpoint = vx_insert_breakpoint;
1382130812Smarcel  vx_run_ops.to_remove_breakpoint = vx_remove_breakpoint;
1383130812Smarcel  vx_run_ops.to_kill = vx_kill;
1384130812Smarcel  vx_run_ops.to_load = vx_load_command;
1385130812Smarcel  vx_run_ops.to_lookup_symbol = vx_lookup_symbol;
1386130812Smarcel  vx_run_ops.to_mourn_inferior = vx_mourn_inferior;
1387130812Smarcel  vx_run_ops.to_stratum = process_stratum;
1388130812Smarcel  vx_run_ops.to_has_memory = 1;
1389130812Smarcel  vx_run_ops.to_has_stack = 1;
1390130812Smarcel  vx_run_ops.to_has_registers = 1;
1391130812Smarcel  vx_run_ops.to_has_execution = 1;
1392130812Smarcel  vx_run_ops.to_magic = OPS_MAGIC;
1393130812Smarcel}
1394130812Smarcel
1395130812Smarcelvoid
1396130812Smarcel_initialize_vx (void)
1397130812Smarcel{
1398130812Smarcel  init_vx_ops ();
1399130812Smarcel  add_target (&vx_ops);
1400130812Smarcel  init_vx_run_ops ();
1401130812Smarcel  add_target (&vx_run_ops);
1402130812Smarcel
1403130812Smarcel  add_show_from_set
1404130812Smarcel    (add_set_cmd ("vxworks-timeout", class_support, var_uinteger,
1405130812Smarcel		  (char *) &rpcTimeout.tv_sec,
1406130812Smarcel		  "Set seconds to wait for rpc calls to return.\n\
1407130812SmarcelSet the number of seconds to wait for rpc calls to return.", &setlist),
1408130812Smarcel     &showlist);
1409130812Smarcel}
1410