1 /* Memory-access and commands for remote VxWorks processes, for GDB.
2 Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3 Contributed by Wind River Systems and Cygnus Support.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
29 #include "symfile.h" /* for struct complaint */
35 #include <sys/types.h>
37 #include <sys/socket.h>
38 #define free bogon_free /* Sun claims "int free()" not void */
41 #include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
43 #include "vx-share/ptrace.h"
44 #include "vx-share/xdr_ptrace.h"
45 #include "vx-share/xdr_ld.h"
46 #include "vx-share/xdr_rdb.h"
47 #include "vx-share/dbgRpcLib.h"
51 extern void symbol_file_command ();
52 extern int stop_soon_quietly; /* for wait_for_inferior */
53 extern void host_convert_to_virtual ();
54 extern void host_convert_from_virtual ();
56 static int net_ptrace_clnt_call (); /* Forward decl */
57 static enum clnt_stat net_clnt_call (); /* Forward decl */
58 extern struct target_ops vx_ops, vx_run_ops; /* Forward declaration */
60 /* Saved name of target host and called function for "info files".
64 static char *vx_running; /* Called function */
66 /* Nonzero means target that is being debugged remotely has a floating
69 static int target_has_fp;
71 /* Default error message when the network is forking up. */
73 static const char rpcerr[] = "network target debugging: rpc error";
75 CLIENT *pClient; /* client used in net debugging */
76 static int ptraceSock = RPC_ANYSOCK;
78 enum clnt_stat net_clnt_call();
79 static void parse_args ();
81 static struct timeval rpcTimeout = { 10, 0 };
83 static char *skip_white_space ();
84 static char *find_white_space ();
86 /* Tell the VxWorks target system to download a file.
87 The load addresses of the text, data, and bss segments are
88 stored in pTextAddr, pDataAddr, and *pBssAddr (respectively).
89 Returns 0 for success, -1 for failure. */
92 net_load (filename, pTextAddr, pDataAddr, pBssAddr)
98 enum clnt_stat status;
99 struct ldfile ldstruct;
100 struct timeval load_timeout;
102 bzero ((char *) &ldstruct, sizeof (ldstruct));
104 /* We invoke clnt_call () here directly, instead of through
105 net_clnt_call (), because we need to set a large timeout value.
106 The load on the target side can take quite a while, easily
107 more than 10 seconds. The user can kill this call by typing
108 CTRL-C if there really is a problem with the load.
110 Do not change the tv_sec value without checking -- select() imposes
111 a limit of 10**8 on it for no good reason that I can see... */
113 load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */
114 load_timeout.tv_usec = 0;
116 status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
117 &ldstruct, load_timeout);
119 if (status == RPC_SUCCESS)
121 if (*ldstruct.name == NULL) /* load failed on VxWorks side */
123 *pTextAddr = ldstruct.txt_addr;
124 *pDataAddr = ldstruct.data_addr;
125 *pBssAddr = ldstruct.bss_addr;
132 /* returns 0 if successful, errno if RPC failed or VxWorks complains. */
135 net_break (addr, procnum)
139 enum clnt_stat status;
141 Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace
142 structure. How about something smaller? */
144 bzero ((char *) &ptrace_in, sizeof (ptrace_in));
147 ptrace_in.addr = addr;
148 ptrace_in.pid = inferior_pid;
150 status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
153 if (status != RPC_SUCCESS)
156 if (break_status == -1)
158 return break_status; /* probably (FIXME) zero */
161 /* returns 0 if successful, errno otherwise */
164 vx_insert_breakpoint (addr)
167 return net_break (addr, VX_BREAK_ADD);
170 /* returns 0 if successful, errno otherwise */
173 vx_remove_breakpoint (addr)
176 return net_break (addr, VX_BREAK_DELETE);
179 /* Start an inferior process and sets inferior_pid to its pid.
180 EXEC_FILE is the file to run.
181 ALLARGS is a string containing the arguments to the program.
182 ENV is the environment vector to pass.
183 Returns process id. Errors reported with error().
184 On VxWorks, we ignore exec_file. */
187 vx_create_inferior (exec_file, args, env)
192 enum clnt_stat status;
194 TASK_START taskStart;
196 bzero ((char *) &passArgs, sizeof (passArgs));
197 bzero ((char *) &taskStart, sizeof (taskStart));
199 /* parse arguments, put them in passArgs */
201 parse_args (args, &passArgs);
203 if (passArgs.arg_array_len == 0)
204 error ("You must specify a function name to run, and arguments if any");
206 status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
207 xdr_TASK_START, &taskStart);
209 if ((status != RPC_SUCCESS) || (taskStart.status == -1))
210 error ("Can't create process on remote target machine");
212 /* Save the name of the running function */
213 vx_running = savestring (passArgs.arg_array_val[0],
214 strlen (passArgs.arg_array_val[0]));
216 #ifdef CREATE_INFERIOR_HOOK
217 CREATE_INFERIOR_HOOK (pid);
220 push_target (&vx_run_ops);
221 inferior_pid = taskStart.pid;
223 /* We will get a trace trap after one instruction.
224 Insert breakpoints and continue. */
226 init_wait_for_inferior ();
228 /* Set up the "saved terminal modes" of the inferior
229 based on what modes we are starting it with. */
230 target_terminal_init ();
232 /* Install inferior's terminal modes. */
233 target_terminal_inferior ();
235 stop_soon_quietly = 1;
236 wait_for_inferior (); /* Get the task spawn event */
237 stop_soon_quietly = 0;
239 /* insert_step_breakpoint (); FIXME, do we need this? */
243 /* Fill ARGSTRUCT in argc/argv form with the arguments from the
244 argument string ARGSTRING. */
247 parse_args (arg_string, arg_struct)
248 register char *arg_string;
249 arg_array *arg_struct;
251 register int arg_count = 0; /* number of arguments */
252 register int arg_index = 0;
255 bzero ((char *) arg_struct, sizeof (arg_array));
257 /* first count how many arguments there are */
262 if (*(p0 = skip_white_space (p0)) == '\0')
264 p0 = find_white_space (p0);
268 arg_struct->arg_array_len = arg_count;
269 arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
272 /* now copy argument strings into arg_struct. */
274 while (*(arg_string = skip_white_space (arg_string)))
276 p0 = find_white_space (arg_string);
277 arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
282 arg_struct->arg_array_val[arg_count] = NULL;
285 /* Advance a string pointer across whitespace and return a pointer
286 to the first non-white character. */
292 while (*p == ' ' || *p == '\t')
297 /* Search for the first unquoted whitespace character in a string.
298 Returns a pointer to the character, or to the null terminator
299 if no whitespace is found. */
307 while ((c = *p) != ' ' && c != '\t' && c)
309 if (c == '\'' || c == '"')
311 while (*++p != c && *p)
324 /* Poll the VxWorks target system for an event related
325 to the debugged task.
326 Returns -1 if remote wait failed, task status otherwise. */
333 enum clnt_stat status;
335 bzero ((char *) pEvent, sizeof (RDB_EVENT));
338 status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent);
340 return (status == RPC_SUCCESS)? pEvent->status: -1;
343 /* Suspend the remote task.
344 Returns -1 if suspend fails on target system, 0 otherwise. */
351 enum clnt_stat status;
355 /* don't let rdbTask suspend itself by passing a pid of 0 */
357 if ((pid = inferior_pid) == 0)
360 status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
363 return (status == RPC_SUCCESS)? quit_status: -1;
366 /* Read a register or registers from the remote system. */
369 vx_read_register (regno)
374 Ptrace_return ptrace_out;
377 extern char registers[];
379 bzero ((char *) &ptrace_in, sizeof (ptrace_in));
380 bzero ((char *) &ptrace_out, sizeof (ptrace_out));
382 /* FIXME, eventually only get the ones we need. */
383 registers_fetched ();
385 ptrace_in.pid = inferior_pid;
386 ptrace_out.info.more_data = (caddr_t) &out_data;
387 out_data.len = 18 * REGISTER_RAW_SIZE (0); /* FIXME 68k hack */
388 out_data.bytes = (caddr_t) registers;
390 status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out);
393 if (ptrace_out.status == -1)
395 errno = ptrace_out.errno;
396 perror_with_name ("net_ptrace_clnt_call(PTRACE_GETREGS)");
401 bcopy ((char *) inferior_registers.r_lreg,
402 ®isters[REGISTER_BYTE (R0_REGNUM)], 16 * sizeof (int));
403 bcopy ((char *) inferior_registers.r_greg,
404 ®isters[REGISTER_BYTE (G0_REGNUM)], 16 * sizeof (int));
406 /* Don't assume that a location in registers[] is properly aligned. */
408 bcopy ((char *) &inferior_registers.r_pcw,
409 ®isters[REGISTER_BYTE (PCW_REGNUM)], sizeof (int));
410 bcopy ((char *) &inferior_registers.r_acw,
411 ®isters[REGISTER_BYTE (ACW_REGNUM)], sizeof (int));
412 bcopy ((char *) &inferior_registers.r_lreg[2], /* r2 (RIP) -> IP */
413 ®isters[REGISTER_BYTE (IP_REGNUM)], sizeof (int));
414 bcopy ((char *) &inferior_registers.r_tcw,
415 ®isters[REGISTER_BYTE (TCW_REGNUM)], sizeof (int));
417 /* If the target has floating point registers, fetch them.
418 Otherwise, zero the floating point register values in
419 registers[] for good measure, even though we might not
424 ptrace_in.pid = inferior_pid;
425 ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers;
426 status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
429 if (ptrace_out.status == -1)
431 errno = ptrace_out.errno;
432 perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
435 bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
436 REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
440 bzero ((char *) ®isters[REGISTER_BYTE (FP0_REGNUM)],
441 REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
444 #else /* not 960, thus must be 68000: FIXME! */
448 ptrace_in.pid = inferior_pid;
449 ptrace_out.info.more_data = (caddr_t) &out_data;
450 out_data.len = 8 * REGISTER_RAW_SIZE (FP0_REGNUM) /* FIXME */
451 + (3 * sizeof (REGISTER_TYPE));
452 out_data.bytes = (caddr_t) ®isters[REGISTER_BYTE (FP0_REGNUM)];
454 status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
457 if (ptrace_out.status == -1)
459 errno = ptrace_out.errno;
460 perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
465 bzero (®isters[REGISTER_BYTE (FP0_REGNUM)],
466 8 * REGISTER_RAW_SIZE (FP0_REGNUM));
467 bzero (®isters[REGISTER_BYTE (FPC_REGNUM)],
468 3 * sizeof (REGISTER_TYPE));
470 #endif /* various architectures */
473 /* Prepare to store registers. Since we will store all of them,
474 read out their current values now. */
477 vx_prepare_to_store ()
479 vx_read_register (-1);
483 /* Store our register values back into the inferior.
484 If REGNO is -1, do this for all registers.
485 Otherwise, REGNO specifies which register (so we can save time). */
486 /* FIXME, look at REGNO to save time here */
489 vx_write_register (regno)
494 extern char registers[];
497 Ptrace_return ptrace_out;
499 bzero ((char *) &ptrace_in, sizeof (ptrace_in));
500 bzero ((char *) &ptrace_out, sizeof (ptrace_out));
502 ptrace_in.pid = inferior_pid;
503 ptrace_in.info.ttype = DATA;
504 ptrace_in.info.more_data = (caddr_t) &in_data;
506 in_data.bytes = registers;
511 bcopy (®isters[REGISTER_BYTE (R0_REGNUM)],
512 (char *) inferior_registers.r_lreg, 16 * sizeof (int));
513 bcopy (®isters[REGISTER_BYTE (G0_REGNUM)],
514 (char *) inferior_registers.r_greg, 16 * sizeof (int));
516 /* Don't assume that a location in registers[] is properly aligned. */
518 bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)],
519 (char *) &inferior_registers.r_pcw, sizeof (int));
520 bcopy (®isters[REGISTER_BYTE (ACW_REGNUM)],
521 (char *) &inferior_registers.r_acw, sizeof (int));
522 bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)],
523 (char *) &inferior_registers.r_tcw, sizeof (int));
525 #else /* not 960 -- assume 68k -- FIXME */
527 in_data.len = 18 * sizeof (REGISTER_TYPE);
529 #endif /* Different register sets */
531 /* XXX change second param to be a proc number */
532 status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out);
535 if (ptrace_out.status == -1)
537 errno = ptrace_out.errno;
538 perror_with_name ("net_ptrace_clnt_call(PTRACE_SETREGS)");
541 /* Store floating point registers if the target has them. */
545 ptrace_in.pid = inferior_pid;
546 ptrace_in.info.ttype = DATA;
547 ptrace_in.info.more_data = (caddr_t) &in_data;
552 bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
553 sizeof inferior_fp_registers.fps_regs);
555 #else /* not 960 -- assume 68k -- FIXME */
557 in_data.bytes = ®isters[REGISTER_BYTE (FP0_REGNUM)];
558 in_data.len = (8 * REGISTER_RAW_SIZE (FP0_REGNUM)
559 + (3 * sizeof (REGISTER_TYPE)));
561 #endif /* Different register sets */
563 status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out);
566 if (ptrace_out.status == -1)
568 errno = ptrace_out.errno;
569 perror_with_name ("net_ptrace_clnt_call(PTRACE_SETFPREGS)");
574 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
575 to debugger memory starting at MYADDR. WRITE is true if writing to the
577 Result is the number of bytes written or read (zero if error). The
578 protocol allows us to return a negative count, indicating that we can't
579 handle the current address but can handle one N bytes further, but
580 vxworks doesn't give us that information. */
583 vx_xfer_memory (memaddr, myaddr, len, write, target)
588 struct target_ops *target; /* ignored */
592 Ptrace_return ptrace_out;
595 bzero ((char *) &ptrace_in, sizeof (ptrace_in));
596 bzero ((char *) &ptrace_out, sizeof (ptrace_out));
598 ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */
599 ptrace_in.addr = (int) memaddr; /* Where from */
600 ptrace_in.data = len; /* How many bytes */
604 ptrace_in.info.ttype = DATA;
605 ptrace_in.info.more_data = (caddr_t) &data;
607 data.bytes = (caddr_t) myaddr; /* Where from */
608 data.len = len; /* How many bytes (again, for XDR) */
610 /* XXX change second param to be a proc number */
611 status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out);
615 ptrace_out.info.more_data = (caddr_t) &data;
616 data.bytes = myaddr; /* Where to */
617 data.len = len; /* How many (again, for XDR) */
619 /* XXX change second param to be a proc number */
620 status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out);
625 if (ptrace_out.status == -1)
627 return 0; /* No bytes moved */
629 return len; /* Moved *all* the bytes */
635 printf ("\tAttached to host `%s'", vx_host);
636 printf (", which has %sfloating point", target_has_fp? "": "no ");
643 printf ("\tRunning %s VxWorks process %s",
644 vx_running? "child": "attached",
645 local_hex_string(inferior_pid));
647 printf (", function `%s'", vx_running);
652 vx_resume (step, siggnal)
658 Ptrace_return ptrace_out;
660 if (siggnal != 0 && siggnal != stop_signal)
661 error ("Cannot send signals to VxWorks processes");
663 bzero ((char *) &ptrace_in, sizeof (ptrace_in));
664 bzero ((char *) &ptrace_out, sizeof (ptrace_out));
666 ptrace_in.pid = inferior_pid;
667 ptrace_in.addr = 1; /* Target side insists on this, or it panics. */
669 /* XXX change second param to be a proc number */
670 status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT,
671 &ptrace_in, &ptrace_out);
674 if (ptrace_out.status == -1)
676 errno = ptrace_out.errno;
677 perror_with_name ("Resuming remote process");
684 pop_target (); /* Pop back to no-child state */
685 generic_mourn_inferior ();
689 /* This function allows the addition of incrementally linked object files. */
692 vx_load_command (arg_string, from_tty)
701 error ("The load command takes a file name");
703 arg_string = tilde_expand (arg_string);
704 make_cleanup (free, arg_string);
710 if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
711 error ("Load failed on target machine");
714 /* FIXME, for now we ignore data_addr and bss_addr. */
715 symbol_file_add (arg_string, from_tty, text_addr, 0, 0, 0);
718 #ifdef FIXME /* Not ready for prime time */
719 /* Single step the target program at the source or machine level.
720 Takes an error exit if rpc fails.
721 Returns -1 if remote single-step operation fails, else 0. */
726 enum clnt_stat status;
728 SOURCE_STEP source_step;
730 source_step.taskId = inferior_pid;
734 source_step.startAddr = step_range_start;
735 source_step.endAddr = step_range_end;
739 source_step.startAddr = 0;
740 source_step.endAddr = 0;
743 status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
744 xdr_int, &step_status);
746 if (status == RPC_SUCCESS)
753 /* Emulate ptrace using RPC calls to the VxWorks target system.
754 Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */
757 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
758 enum ptracereq request;
760 Ptrace_return *pPtraceOut;
762 enum clnt_stat status;
764 status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
767 if (status != RPC_SUCCESS)
773 /* Query the target for the name of the file from which VxWorks was
774 booted. pBootFile is the address of a pointer to the buffer to
775 receive the file name; if the pointer pointed to by pBootFile is
776 NULL, memory for the buffer will be allocated by XDR.
777 Returns -1 if rpc failed, 0 otherwise. */
780 net_get_boot_file (pBootFile)
783 enum clnt_stat status;
785 status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
786 xdr_wrapstring, pBootFile);
787 return (status == RPC_SUCCESS) ? 0 : -1;
790 /* Fetch a list of loaded object modules from the VxWorks target.
791 Returns -1 if rpc failed, 0 otherwise
792 There's no way to check if the returned loadTable is correct.
793 VxWorks doesn't check it. */
796 net_get_symbols (pLoadTable)
797 ldtabl *pLoadTable; /* return pointer to ldtabl here */
799 enum clnt_stat status;
801 bzero ((char *) pLoadTable, sizeof (struct ldtabl));
803 status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
804 return (status == RPC_SUCCESS) ? 0 : -1;
807 /* Look up a symbol in the VxWorks target's symbol table.
808 Returns status of symbol read on target side (0=success, -1=fail)
809 Returns -1 and complain()s if rpc fails. */
811 struct complaint cant_contact_target =
812 {"Lost contact with VxWorks target", 0, 0};
815 vx_lookup_symbol (name, pAddr)
816 char *name; /* symbol name */
819 enum clnt_stat status;
820 SYMBOL_ADDR symbolAddr;
823 bzero ((char *) &symbolAddr, sizeof (symbolAddr));
825 status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
826 xdr_SYMBOL_ADDR, &symbolAddr);
827 if (status != RPC_SUCCESS) {
828 complain (&cant_contact_target, 0);
832 *pAddr = symbolAddr.addr;
833 return symbolAddr.status;
836 /* Check to see if the VxWorks target has a floating point coprocessor.
837 Returns 1 if target has floating point processor, 0 otherwise.
838 Calls error() if rpc fails. */
843 enum clnt_stat status;
844 bool_t fp = 0; /* true if fp processor is present on target board */
846 status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
847 if (status != RPC_SUCCESS)
853 /* Establish an RPC connection with the VxWorks target system.
854 Calls error () if unable to establish connection. */
860 struct sockaddr_in destAddr;
861 struct hostent *destHost;
863 /* get the internet address for the given host */
865 if ((destHost = (struct hostent *) gethostbyname (host)) == NULL)
866 error ("Invalid hostname. Couldn't find remote host address.");
868 bzero (&destAddr, sizeof (destAddr));
870 destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr;
871 destAddr.sin_family = AF_INET;
872 destAddr.sin_port = 0; /* set to actual port that remote
873 ptrace is listening on. */
875 /* Create a tcp client transport on which to issue
876 calls to the remote ptrace server. */
878 ptraceSock = RPC_ANYSOCK;
879 pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
880 /* FIXME, here is where we deal with different version numbers of the proto */
884 clnt_pcreateerror ("\tnet_connect");
885 error ("Couldn't connect to remote target.");
889 /* Sleep for the specified number of milliseconds
890 * (assumed to be less than 1000).
891 * If select () is interrupted, returns immediately;
892 * takes an error exit if select () fails for some other reason.
899 struct timeval select_timeout;
902 select_timeout.tv_sec = 0;
903 select_timeout.tv_usec = ms * 1000;
905 status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout);
907 if (status < 0 && errno != EINTR)
908 perror_with_name ("select");
911 /* Wait for control to return from inferior to debugger.
912 If inferior gets a signal, we may decide to start it up again
913 instead of returning. That is why there is a loop in this function.
914 When this function actually returns it means the inferior
915 should be left stopped and GDB should read more commands. */
917 /* For network debugging with VxWorks.
918 * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc,
919 * so vx_wait() receives this information directly from
920 * VxWorks instead of trying to figure out what happenned via a wait() call.
934 /* If CTRL-C is hit during this loop,
935 suspend the inferior process. */
940 quit_failed = (net_quit () == -1);
944 /* If a net_quit () or net_wait () call has failed,
945 allow the user to break the connection with the target.
946 We can't simply error () out of this loop, since the
947 data structures representing the state of the inferior
948 are in an inconsistent state. */
950 if (quit_failed || net_wait (&rdbEvent) == -1)
953 if (query ("Can't %s. Disconnect from target system? ",
954 (quit_failed) ? "suspend remote task"
955 : "get status of remote task"))
957 target_mourn_inferior();
958 error ("Use the \"target\" command to reconnect.");
962 terminal_inferior ();
967 pid = rdbEvent.taskId;
970 sleep_ms (200); /* FIXME Don't kill the network too badly */
972 else if (pid != inferior_pid)
973 fatal ("Bad pid for debugged task: %s\n", local_hex_string(pid));
976 /* FIXME, eventually do more then SIGTRAP on everything... */
977 switch (rdbEvent.eventType)
981 /* FIXME is it possible to distinguish between a
982 XXX normal vs abnormal exit in VxWorks? */
985 case EVENT_START: /* Task was just started. */
986 WSETSTOP (w, SIGTRAP);
990 WSETSTOP (w, SIGTRAP);
991 /* XXX was it stopped by a signal? act accordingly */
994 case EVENT_BREAK: /* Breakpoint was hit. */
995 WSETSTOP (w, SIGTRAP);
998 case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */
999 WSETSTOP (w, SIGINT);
1002 case EVENT_BUS_ERR: /* Task made evil nasty reference. */
1003 WSETSTOP (w, SIGBUS);
1006 case EVENT_ZERO_DIV: /* Division by zero */
1007 WSETSTOP (w, SIGFPE); /* Like Unix, call it a float exception. */
1011 /* The target is not running Unix, and its
1012 faults/traces do not map nicely into Unix signals.
1013 Make sure they do not get confused with Unix signals
1014 by numbering them with values higher than the highest
1015 legal Unix signal. code in the arch-dependent PRINT_RANDOM_SIGNAL
1016 routine will interpret the value for wait_for_inferior. */
1017 WSETSTOP (w, rdbEvent.sigType + NSIG);
1020 *status = *(int *)&w; /* Grumble union wait crap Grumble */
1028 symbol_file_command (arg, 0);
1033 add_symbol_stub (arg)
1036 struct ldfile *pLoadFile = (struct ldfile *)arg;
1038 printf("\t%s: ", pLoadFile->name);
1039 symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0, 0, 0);
1043 /* Target command for VxWorks target systems.
1045 Used in vxgdb. Takes the name of a remote target machine
1046 running vxWorks and connects to it to initialize remote network
1050 vx_open (args, from_tty)
1054 extern int close ();
1056 extern char *source_path;
1057 struct ldtabl loadTable;
1058 struct ldfile *pLoadFile;
1060 extern CLIENT *pClient;
1063 error_no_arg ("target machine name");
1065 target_preopen (from_tty);
1067 unpush_target (&vx_ops);
1068 printf ("Attaching remote machine across net...\n");
1071 /* Allow the user to kill the connect attempt by typing ^C.
1072 Wait until the call to target_has_fp () completes before
1073 disallowing an immediate quit, since even if net_connect ()
1074 is successful, the remote debug server might be hung. */
1079 target_has_fp = net_check_for_fp ();
1080 printf_filtered ("Connected to %s.\n", args);
1084 push_target (&vx_ops);
1086 /* Save a copy of the target host's name. */
1087 vx_host = savestring (args, strlen (args));
1089 /* Find out the name of the file from which the target was booted
1090 and load its symbol table. */
1092 printf_filtered ("Looking in Unix path for all loaded modules:\n");
1094 if (!net_get_boot_file (&bootFile))
1097 printf_filtered ("\t%s: ", bootFile);
1098 if (catch_errors (symbol_stub, bootFile,
1099 "Error while reading symbols from boot file:\n"))
1100 puts_filtered ("ok\n");
1101 } else if (from_tty)
1102 printf ("VxWorks kernel symbols not loaded.\n");
1105 error ("Can't retrieve boot file name from target machine.");
1107 clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1109 if (net_get_symbols (&loadTable) != 0)
1110 error ("Can't read loaded modules from target machine");
1113 while (++i < loadTable.tbl_size)
1115 QUIT; /* FIXME, avoids clnt_freeres below: mem leak */
1116 pLoadFile = &loadTable.tbl_ent [i];
1120 struct cleanup *old_chain;
1121 char *fullname = NULL;
1123 desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1125 perror_with_name (pLoadFile->name);
1126 old_chain = make_cleanup (close, desc);
1127 add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1128 pLoadFile->bss_addr);
1129 do_cleanups (old_chain);
1133 (1) Searches the PATH, not the source path.
1134 (2) data and bss are assumed to be at the usual offsets from text. */
1135 catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0);
1138 printf_filtered ("Done.\n");
1140 clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1143 /* attach_command --
1144 takes a task started up outside of gdb and ``attaches'' to it.
1145 This stops it cold in its tracks and allows us to start tracing it. */
1148 vx_attach (args, from_tty)
1155 Ptrace_return ptrace_out;
1161 error_no_arg ("process-id to attach");
1163 pid = strtol (args, &cptr, 0);
1164 if ((cptr == args) || (*cptr != '\0'))
1165 error ("Invalid process-id -- give a single number in decimal or 0xhex");
1168 printf ("Attaching pid %s.\n", local_hex_string(pid));
1170 bzero ((char *)&ptrace_in, sizeof (ptrace_in));
1171 bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1172 ptrace_in.pid = pid;
1174 status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1177 if (ptrace_out.status == -1)
1179 errno = ptrace_out.errno;
1180 perror_with_name ("Attaching remote process");
1184 push_target (&vx_run_ops);
1188 mark_breakpoints_out ();
1190 /* Set up the "saved terminal modes" of the inferior
1191 based on what modes we are starting it with. */
1192 target_terminal_init ();
1194 /* Install inferior's terminal modes. */
1195 target_terminal_inferior ();
1197 /* We will get a task spawn event immediately. */
1198 init_wait_for_inferior ();
1199 clear_proceed_status ();
1200 stop_soon_quietly = 1;
1201 wait_for_inferior ();
1202 stop_soon_quietly = 0;
1207 /* detach_command --
1208 takes a program previously attached to and detaches it.
1209 The program resumes execution and will no longer stop
1210 on signals, etc. We better not have left any breakpoints
1211 in the program or it'll die when it hits one. For this
1212 to work, it may be necessary for the process to have been
1213 previously attached. It *might* work if the program was
1214 started via the normal ptrace (PTRACE_TRACEME). */
1217 vx_detach (args, from_tty)
1222 Ptrace_return ptrace_out;
1227 error ("Argument given to VxWorks \"detach\".");
1230 printf ("Detaching pid %s.\n", local_hex_string(inferior_pid));
1232 if (args) /* FIXME, should be possible to leave suspended */
1233 signal = atoi (args);
1235 bzero ((char *)&ptrace_in, sizeof (ptrace_in));
1236 bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1237 ptrace_in.pid = inferior_pid;
1239 status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1242 if (ptrace_out.status == -1)
1244 errno = ptrace_out.errno;
1245 perror_with_name ("Detaching VxWorks process");
1249 pop_target (); /* go back to non-executing VxWorks connection */
1252 /* vx_kill -- takes a running task and wipes it out. */
1255 vx_kill (args, from_tty)
1260 Ptrace_return ptrace_out;
1264 error ("Argument given to VxWorks \"kill\".");
1267 printf ("Killing pid %s.\n", local_hex_string(inferior_pid));
1269 bzero ((char *)&ptrace_in, sizeof (ptrace_in));
1270 bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1271 ptrace_in.pid = inferior_pid;
1273 status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1276 if (ptrace_out.status == -1)
1278 errno = ptrace_out.errno;
1279 perror_with_name ("Killing VxWorks process");
1282 /* If it gives good status, the process is *gone*, no events remain. */
1284 pop_target (); /* go back to non-executing VxWorks connection */
1287 /* Clean up from the VxWorks process target as it goes away. */
1290 vx_proc_close (quitting)
1293 inferior_pid = 0; /* No longer have a process. */
1299 /* Make an RPC call to the VxWorks target.
1300 Returns RPC status. */
1302 static enum clnt_stat
1303 net_clnt_call (procNum, inProc, in, outProc, out)
1304 enum ptracereq procNum;
1310 enum clnt_stat status;
1312 status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1314 if (status != RPC_SUCCESS)
1315 clnt_perrno (status);
1320 /* Clean up before losing control. */
1327 clnt_destroy (pClient); /* The net connection */
1331 free (vx_host); /* The hostname */
1335 /* A vxprocess target should be started via "run" not "target". */
1338 vx_proc_open (name, from_tty)
1342 error ("Use the \"run\" command to start a VxWorks process.");
1345 /* Target ops structure for accessing memory and such over the net */
1347 struct target_ops vx_ops = {
1348 "vxworks", "VxWorks target memory via RPC over TCP/IP",
1349 "Use VxWorks target memory. \n\
1350 Specify the name of the machine to connect to.",
1351 vx_open, vx_close, vx_attach, 0, /* vx_detach, */
1352 0, 0, /* resume, wait */
1353 0, 0, /* read_reg, write_reg */
1354 0, host_convert_to_virtual, host_convert_from_virtual, /* prep_to_store, */
1355 vx_xfer_memory, vx_files_info,
1356 0, 0, /* insert_breakpoint, remove_breakpoint */
1357 0, 0, 0, 0, 0, /* terminal stuff */
1361 vx_create_inferior, 0, /* mourn_inferior */
1362 core_stratum, 0, /* next */
1363 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */
1364 0, 0, /* Section pointers */
1365 OPS_MAGIC, /* Always the last thing */
1368 /* Target ops structure for accessing VxWorks child processes over the net */
1370 struct target_ops vx_run_ops = {
1371 "vxprocess", "VxWorks process",
1372 "VxWorks process, started by the \"run\" command.",
1373 vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */
1375 vx_read_register, vx_write_register,
1376 vx_prepare_to_store, host_convert_to_virtual, host_convert_from_virtual,
1377 vx_xfer_memory, vx_run_files_info,
1378 vx_insert_breakpoint, vx_remove_breakpoint,
1379 0, 0, 0, 0, 0, /* terminal stuff */
1383 0, vx_mourn_inferior,
1384 process_stratum, 0, /* next */
1385 0, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
1386 /* all_mem is off to avoid spurious msg in "i files" */
1387 0, 0, /* Section pointers */
1388 OPS_MAGIC, /* Always the last thing */
1390 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1395 add_target (&vx_ops);
1396 add_target (&vx_run_ops);