diff options
Diffstat (limited to 'gdb/remote-vx.c')
-rw-r--r-- | gdb/remote-vx.c | 1401 |
1 files changed, 0 insertions, 1401 deletions
diff --git a/gdb/remote-vx.c b/gdb/remote-vx.c deleted file mode 100644 index 76baff5..0000000 --- a/gdb/remote-vx.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* Memory-access and commands for remote VxWorks processes, for GDB. - - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999, - 2000, 2001, 2002 Free Software Foundation, Inc. - - Contributed by Wind River Systems and Cygnus Support. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include "defs.h" -#include "frame.h" -#include "inferior.h" -#include "target.h" -#include "gdbcore.h" -#include "command.h" -#include "symtab.h" -#include "complaints.h" -#include "gdbcmd.h" -#include "bfd.h" /* Required by objfiles.h. */ -#include "symfile.h" -#include "objfiles.h" -#include "gdb-stabs.h" -#include "regcache.h" - -#include "gdb_string.h" -#include <errno.h> -#include <signal.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/socket.h> -#define malloc bogon_malloc /* Sun claims "char *malloc()" not void * */ -#define free bogon_free /* Sun claims "int free()" not void */ -#define realloc bogon_realloc /* Sun claims "char *realloc()", not void * */ -#include <rpc/rpc.h> -#undef malloc -#undef free -#undef realloc -#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */ -#include <netdb.h> -#include "vx-share/ptrace.h" -#include "vx-share/xdr_ptrace.h" -#include "vx-share/xdr_ld.h" -#include "vx-share/xdr_rdb.h" -#include "vx-share/dbgRpcLib.h" - -#include <symtab.h> - -/* Maximum number of bytes to transfer in a single - PTRACE_{READ,WRITE}DATA request. */ -#define VX_MEMXFER_MAX 4096 - -extern void vx_read_register (); -extern void vx_write_register (); -extern void symbol_file_command (); -extern enum stop_kind stop_soon; /* for wait_for_inferior */ - -static int net_step (); -static int net_ptrace_clnt_call (); /* Forward decl */ -static enum clnt_stat net_clnt_call (); /* Forward decl */ - -/* Target ops structure for accessing memory and such over the net */ - -static struct target_ops vx_ops; - -/* Target ops structure for accessing VxWorks child processes over the net */ - -static struct target_ops vx_run_ops; - -/* Saved name of target host and called function for "info files". - Both malloc'd. */ - -static char *vx_host; -static char *vx_running; /* Called function */ - -/* Nonzero means target that is being debugged remotely has a floating - point processor. */ - -int target_has_fp; - -/* Default error message when the network is forking up. */ - -static const char rpcerr[] = "network target debugging: rpc error"; - -CLIENT *pClient; /* client used in net debugging */ -static int ptraceSock = RPC_ANYSOCK; - -enum clnt_stat net_clnt_call (); -static void parse_args (); - -static struct timeval rpcTimeout = -{10, 0}; - -static char *skip_white_space (); -static char *find_white_space (); - -/* Tell the VxWorks target system to download a file. - The load addresses of the text, data, and bss segments are - stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively). - Returns 0 for success, -1 for failure. */ - -static int -net_load (char *filename, CORE_ADDR *pTextAddr, CORE_ADDR *pDataAddr, - CORE_ADDR *pBssAddr) -{ - enum clnt_stat status; - struct ldfile ldstruct; - struct timeval load_timeout; - - memset ((char *) &ldstruct, '\0', sizeof (ldstruct)); - - /* We invoke clnt_call () here directly, instead of through - net_clnt_call (), because we need to set a large timeout value. - The load on the target side can take quite a while, easily - more than 10 seconds. The user can kill this call by typing - CTRL-C if there really is a problem with the load. - - Do not change the tv_sec value without checking -- select() imposes - a limit of 10**8 on it for no good reason that I can see... */ - - load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */ - load_timeout.tv_usec = 0; - - status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile, - &ldstruct, load_timeout); - - if (status == RPC_SUCCESS) - { - if (*ldstruct.name == 0) /* load failed on VxWorks side */ - return -1; - *pTextAddr = ldstruct.txt_addr; - *pDataAddr = ldstruct.data_addr; - *pBssAddr = ldstruct.bss_addr; - return 0; - } - else - return -1; -} - -/* returns 0 if successful, errno if RPC failed or VxWorks complains. */ - -static int -net_break (int addr, u_long procnum) -{ - enum clnt_stat status; - int break_status; - Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace - structure. How about something smaller? */ - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - break_status = 0; - - ptrace_in.addr = addr; - ptrace_in.pid = PIDGET (inferior_ptid); - - status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, - &break_status); - - if (status != RPC_SUCCESS) - return errno; - - if (break_status == -1) - return ENOMEM; - return break_status; /* probably (FIXME) zero */ -} - -/* returns 0 if successful, errno otherwise */ - -static int -vx_insert_breakpoint (int addr) -{ - return net_break (addr, VX_BREAK_ADD); -} - -/* returns 0 if successful, errno otherwise */ - -static int -vx_remove_breakpoint (int addr) -{ - return net_break (addr, VX_BREAK_DELETE); -} - -/* Start an inferior process and sets inferior_ptid to its pid. - EXEC_FILE is the file to run. - ALLARGS is a string containing the arguments to the program. - ENV is the environment vector to pass. - Returns process id. Errors reported with error(). - On VxWorks, we ignore exec_file. */ - -static void -vx_create_inferior (char *exec_file, char *args, char **env, int from_tty) -{ - enum clnt_stat status; - arg_array passArgs; - TASK_START taskStart; - - memset ((char *) &passArgs, '\0', sizeof (passArgs)); - memset ((char *) &taskStart, '\0', sizeof (taskStart)); - - /* parse arguments, put them in passArgs */ - - parse_args (args, &passArgs); - - if (passArgs.arg_array_len == 0) - error ("You must specify a function name to run, and arguments if any"); - - status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs, - xdr_TASK_START, &taskStart); - - if ((status != RPC_SUCCESS) || (taskStart.status == -1)) - error ("Can't create process on remote target machine"); - - /* Save the name of the running function */ - vx_running = savestring (passArgs.arg_array_val[0], - strlen (passArgs.arg_array_val[0])); - - push_target (&vx_run_ops); - inferior_ptid = pid_to_ptid (taskStart.pid); - - /* We will get a trace trap after one instruction. - Insert breakpoints and continue. */ - - init_wait_for_inferior (); - - /* Set up the "saved terminal modes" of the inferior - based on what modes we are starting it with. */ - target_terminal_init (); - - /* Install inferior's terminal modes. */ - target_terminal_inferior (); - - stop_soon = STOP_QUIETLY; - wait_for_inferior (); /* Get the task spawn event */ - stop_soon = NO_STOP_QUIETLY; - - /* insert_step_breakpoint (); FIXME, do we need this? */ - proceed (-1, TARGET_SIGNAL_DEFAULT, 0); -} - -/* Fill ARGSTRUCT in argc/argv form with the arguments from the - argument string ARGSTRING. */ - -static void -parse_args (char *arg_string, arg_array *arg_struct) -{ - int arg_count = 0; /* number of arguments */ - int arg_index = 0; - char *p0; - - memset ((char *) arg_struct, '\0', sizeof (arg_array)); - - /* first count how many arguments there are */ - - p0 = arg_string; - while (*p0 != '\0') - { - if (*(p0 = skip_white_space (p0)) == '\0') - break; - p0 = find_white_space (p0); - arg_count++; - } - - arg_struct->arg_array_len = arg_count; - arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1) - * sizeof (char *)); - - /* now copy argument strings into arg_struct. */ - - while (*(arg_string = skip_white_space (arg_string))) - { - p0 = find_white_space (arg_string); - arg_struct->arg_array_val[arg_index++] = savestring (arg_string, - p0 - arg_string); - arg_string = p0; - } - - arg_struct->arg_array_val[arg_count] = NULL; -} - -/* Advance a string pointer across whitespace and return a pointer - to the first non-white character. */ - -static char * -skip_white_space (char *p) -{ - while (*p == ' ' || *p == '\t') - p++; - return p; -} - -/* Search for the first unquoted whitespace character in a string. - Returns a pointer to the character, or to the null terminator - if no whitespace is found. */ - -static char * -find_white_space (char *p) -{ - int c; - - while ((c = *p) != ' ' && c != '\t' && c) - { - if (c == '\'' || c == '"') - { - while (*++p != c && *p) - { - if (*p == '\\') - p++; - } - if (!*p) - break; - } - p++; - } - return p; -} - -/* Poll the VxWorks target system for an event related - to the debugged task. - Returns -1 if remote wait failed, task status otherwise. */ - -static int -net_wait (RDB_EVENT *pEvent) -{ - int pid; - enum clnt_stat status; - - memset ((char *) pEvent, '\0', sizeof (RDB_EVENT)); - - pid = PIDGET (inferior_ptid); - status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, - pEvent); - - /* return (status == RPC_SUCCESS)? pEvent->status: -1; */ - if (status == RPC_SUCCESS) - return ((pEvent->status) ? 1 : 0); - else if (status == RPC_TIMEDOUT) - return (1); - else - return (-1); -} - -/* Suspend the remote task. - Returns -1 if suspend fails on target system, 0 otherwise. */ - -static int -net_quit (void) -{ - int pid; - int quit_status; - enum clnt_stat status; - - quit_status = 0; - - /* don't let rdbTask suspend itself by passing a pid of 0 */ - - if ((pid = PIDGET (inferior_ptid)) == 0) - return -1; - - status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, - &quit_status); - - return (status == RPC_SUCCESS) ? quit_status : -1; -} - -/* Read a register or registers from the remote system. */ - -void -net_read_registers (char *reg_buf, int len, u_long procnum) -{ - int status; - Rptrace ptrace_in; - Ptrace_return ptrace_out; - C_bytes out_data; - char message[100]; - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - - /* Initialize RPC input argument structure. */ - - ptrace_in.pid = PIDGET (inferior_ptid); - ptrace_in.info.ttype = NOINFO; - - /* Initialize RPC return value structure. */ - - out_data.bytes = reg_buf; - out_data.len = len; - ptrace_out.info.more_data = (caddr_t) & out_data; - - /* Call RPC; take an error exit if appropriate. */ - - status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out); - if (status) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS) - ? "general-purpose" - : "floating-point"); - perror_with_name (message); - } -} - -/* Write register values to a VxWorks target. REG_BUF points to a buffer - containing the raw register values, LEN is the length of REG_BUF in - bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or - PTRACE_SETFPREGS). An error exit is taken if the RPC call fails or - if an error status is returned by the remote debug server. This is - a utility routine used by vx_write_register (). */ - -void -net_write_registers (char *reg_buf, int len, u_long procnum) -{ - int status; - Rptrace ptrace_in; - Ptrace_return ptrace_out; - C_bytes in_data; - char message[100]; - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - - /* Initialize RPC input argument structure. */ - - in_data.bytes = reg_buf; - in_data.len = len; - - ptrace_in.pid = PIDGET (inferior_ptid); - ptrace_in.info.ttype = DATA; - ptrace_in.info.more_data = (caddr_t) & in_data; - - /* Call RPC; take an error exit if appropriate. */ - - status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out); - if (status) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS) - ? "general-purpose" - : "floating-point"); - perror_with_name (message); - } -} - -/* Prepare to store registers. Since we will store all of them, - read out their current values now. */ - -static void -vx_prepare_to_store (void) -{ - /* Fetch all registers, if any of them are not yet fetched. */ - deprecated_read_register_bytes (0, NULL, deprecated_register_bytes ()); -} - -/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR - to debugger memory starting at MYADDR. WRITE is true if writing to the - inferior. TARGET is unused. - Result is the number of bytes written or read (zero if error). The - protocol allows us to return a negative count, indicating that we can't - handle the current address but can handle one N bytes further, but - vxworks doesn't give us that information. */ - -static int -vx_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, - struct mem_attrib *attrib, struct target_ops *target) -{ - int status; - Rptrace ptrace_in; - Ptrace_return ptrace_out; - C_bytes data; - enum ptracereq request; - int nleft, nxfer; - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - - ptrace_in.pid = PIDGET (inferior_ptid); /* XXX pid unnecessary for READDATA */ - ptrace_in.addr = (int) memaddr; /* Where from */ - ptrace_in.data = len; /* How many bytes */ - - if (write) - { - ptrace_in.info.ttype = DATA; - ptrace_in.info.more_data = (caddr_t) & data; - - data.bytes = (caddr_t) myaddr; /* Where from */ - data.len = len; /* How many bytes (again, for XDR) */ - request = PTRACE_WRITEDATA; - } - else - { - ptrace_out.info.more_data = (caddr_t) & data; - request = PTRACE_READDATA; - } - /* Loop until the entire request has been satisfied, transferring - at most VX_MEMXFER_MAX bytes per iteration. Break from the loop - if an error status is returned by the remote debug server. */ - - nleft = len; - status = 0; - - while (nleft > 0 && status == 0) - { - nxfer = min (nleft, VX_MEMXFER_MAX); - - ptrace_in.addr = (int) memaddr; - ptrace_in.data = nxfer; - data.bytes = (caddr_t) myaddr; - data.len = nxfer; - - /* Request a block from the remote debug server; if RPC fails, - report an error and return to debugger command level. */ - - if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out)) - error (rpcerr); - - status = ptrace_out.status; - if (status == 0) - { - memaddr += nxfer; - myaddr += nxfer; - nleft -= nxfer; - } - else - { - /* A target-side error has ocurred. Set errno to the error - code chosen by the target so that a later perror () will - say something meaningful. */ - - errno = ptrace_out.errno_num; - } - } - - /* Return the number of bytes transferred. */ - - return (len - nleft); -} - -static void -vx_files_info (void) -{ - printf_unfiltered ("\tAttached to host `%s'", vx_host); - printf_unfiltered (", which has %sfloating point", target_has_fp ? "" : "no "); - printf_unfiltered (".\n"); -} - -static void -vx_run_files_info (void) -{ - printf_unfiltered ("\tRunning %s VxWorks process %s", - vx_running ? "child" : "attached", - hex_string (PIDGET (inferior_ptid))); - if (vx_running) - printf_unfiltered (", function `%s'", vx_running); - printf_unfiltered (".\n"); -} - -static void -vx_resume (ptid_t ptid, int step, enum target_signal siggnal) -{ - int status; - Rptrace ptrace_in; - Ptrace_return ptrace_out; - CORE_ADDR cont_addr; - - if (ptid_equal (ptid, minus_one_ptid)) - ptid = inferior_ptid; - - if (siggnal != 0 && siggnal != stop_signal) - error ("Cannot send signals to VxWorks processes"); - - /* Set CONT_ADDR to the address at which we are continuing, - or to 1 if we are continuing from where the program stopped. - This conforms to traditional ptrace () usage, but at the same - time has special meaning for the VxWorks remote debug server. - If the address is not 1, the server knows that the target - program is jumping to a new address, which requires special - handling if there is a breakpoint at the new address. */ - - cont_addr = read_register (PC_REGNUM); - if (cont_addr == stop_pc) - cont_addr = 1; - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - - ptrace_in.pid = PIDGET (ptid); - ptrace_in.addr = cont_addr; /* Target side insists on this, or it panics. */ - - if (step) - status = net_step (); - else - status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out); - - if (status) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - perror_with_name ("Resuming remote process"); - } -} - -static void -vx_mourn_inferior (void) -{ - pop_target (); /* Pop back to no-child state */ - generic_mourn_inferior (); -} - - -static void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR); - -struct find_sect_args - { - CORE_ADDR text_start; - CORE_ADDR data_start; - CORE_ADDR bss_start; - }; - -static void find_sect (bfd *, asection *, void *); - -static void -find_sect (bfd *abfd, asection *sect, void *obj) -{ - struct find_sect_args *args = (struct find_sect_args *) obj; - - if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY)) - args->text_start = bfd_get_section_vma (abfd, sect); - else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC) - { - if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) - { - /* Exclude .ctor and .dtor sections which have SEC_CODE set but not - SEC_DATA. */ - if (bfd_get_section_flags (abfd, sect) & SEC_DATA) - args->data_start = bfd_get_section_vma (abfd, sect); - } - else - args->bss_start = bfd_get_section_vma (abfd, sect); - } -} - -static void -vx_add_symbols (char *name, int from_tty, CORE_ADDR text_addr, - CORE_ADDR data_addr, CORE_ADDR bss_addr) -{ - struct section_offsets *offs; - struct objfile *objfile; - struct find_sect_args ss; - - /* It might be nice to suppress the breakpoint_re_set which happens here - because we are going to do one again after the objfile_relocate. */ - objfile = symbol_file_add (name, from_tty, NULL, 0, 0); - - /* This is a (slightly cheesy) way of superceding the old symbols. A less - cheesy way would be to find the objfile with the same name and - free_objfile it. */ - objfile_to_front (objfile); - - offs = - (struct section_offsets *) - alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)); - memcpy (offs, objfile->section_offsets, - SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)); - - ss.text_start = 0; - ss.data_start = 0; - ss.bss_start = 0; - bfd_map_over_sections (objfile->obfd, find_sect, &ss); - - /* Both COFF and b.out frontends use these SECT_OFF_* values. */ - offs->offsets[SECT_OFF_TEXT (objfile)] = text_addr - ss.text_start; - offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start; - offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start; - objfile_relocate (objfile, offs); -} - -/* This function allows the addition of incrementally linked object files. */ - -static void -vx_load_command (char *arg_string, int from_tty) -{ - CORE_ADDR text_addr; - CORE_ADDR data_addr; - CORE_ADDR bss_addr; - - if (arg_string == 0) - error ("The load command takes a file name"); - - arg_string = tilde_expand (arg_string); - make_cleanup (xfree, arg_string); - - dont_repeat (); - - /* Refuse to load the module if a debugged task is running. Doing so - can have a number of unpleasant consequences to the running task. */ - - if (PIDGET (inferior_ptid) != 0 && target_has_execution) - { - if (query ("You may not load a module while the target task is running.\n\ -Kill the target task? ")) - target_kill (); - else - error ("Load canceled."); - } - - QUIT; - immediate_quit++; - if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1) - error ("Load failed on target machine"); - immediate_quit--; - - vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr); - - /* Getting new symbols may change our opinion about what is - frameless. */ - reinit_frame_cache (); -} - -/* Single step the target program at the source or machine level. - Takes an error exit if rpc fails. - Returns -1 if remote single-step operation fails, else 0. */ - -static int -net_step (void) -{ - enum clnt_stat status; - int step_status; - SOURCE_STEP source_step; - - source_step.taskId = PIDGET (inferior_ptid); - source_step.startAddr = 0; - source_step.endAddr = 0; - - status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step, - xdr_int, &step_status); - - if (status == RPC_SUCCESS) - return step_status; - else - error (rpcerr); -} - -/* Emulate ptrace using RPC calls to the VxWorks target system. - Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */ - -static int -net_ptrace_clnt_call (enum ptracereq request, Rptrace *pPtraceIn, - Ptrace_return *pPtraceOut) -{ - enum clnt_stat status; - - status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return, - pPtraceOut); - - if (status != RPC_SUCCESS) - return -1; - - return 0; -} - -/* Query the target for the name of the file from which VxWorks was - booted. pBootFile is the address of a pointer to the buffer to - receive the file name; if the pointer pointed to by pBootFile is - NULL, memory for the buffer will be allocated by XDR. - Returns -1 if rpc failed, 0 otherwise. */ - -static int -net_get_boot_file (char **pBootFile) -{ - enum clnt_stat status; - - status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0, - xdr_wrapstring, pBootFile); - return (status == RPC_SUCCESS) ? 0 : -1; -} - -/* Fetch a list of loaded object modules from the VxWorks target - and store in PLOADTABLE. - Returns -1 if rpc failed, 0 otherwise - There's no way to check if the returned loadTable is correct. - VxWorks doesn't check it. */ - -static int -net_get_symbols (ldtabl *pLoadTable) -{ - enum clnt_stat status; - - memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl)); - - status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable); - return (status == RPC_SUCCESS) ? 0 : -1; -} - -/* Look up a symbol in the VxWorks target's symbol table. - Returns status of symbol read on target side (0=success, -1=fail) - Returns -1 and complain()s if rpc fails. */ - -static int -vx_lookup_symbol (char *name, /* symbol name */ - CORE_ADDR *pAddr) -{ - enum clnt_stat status; - SYMBOL_ADDR symbolAddr; - - *pAddr = 0; - memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr)); - - status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name, - xdr_SYMBOL_ADDR, &symbolAddr); - if (status != RPC_SUCCESS) - { - complaint (&symfile_complaints, "Lost contact with VxWorks target"); - return -1; - } - - *pAddr = symbolAddr.addr; - return symbolAddr.status; -} - -/* Check to see if the VxWorks target has a floating point coprocessor. - Returns 1 if target has floating point processor, 0 otherwise. - Calls error() if rpc fails. */ - -static int -net_check_for_fp (void) -{ - enum clnt_stat status; - bool_t fp = 0; /* true if fp processor is present on target board */ - - status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp); - if (status != RPC_SUCCESS) - error (rpcerr); - - return (int) fp; -} - -/* Establish an RPC connection with the VxWorks target system. - Calls error () if unable to establish connection. */ - -static void -net_connect (char *host) -{ - struct sockaddr_in destAddr; - struct hostent *destHost; - unsigned long addr; - - /* Get the internet address for the given host. Allow a numeric - IP address or a hostname. */ - - addr = inet_addr (host); - if (addr == -1) - { - destHost = (struct hostent *) gethostbyname (host); - if (destHost == NULL) - /* FIXME: Probably should include hostname here in quotes. - For example if the user types "target vxworks vx960 " it should - say "Invalid host `vx960 '." not just "Invalid hostname". */ - error ("Invalid hostname. Couldn't find remote host address."); - addr = *(unsigned long *) destHost->h_addr; - } - - memset (&destAddr, '\0', sizeof (destAddr)); - - destAddr.sin_addr.s_addr = addr; - destAddr.sin_family = AF_INET; - destAddr.sin_port = 0; /* set to actual port that remote - ptrace is listening on. */ - - /* Create a tcp client transport on which to issue - calls to the remote ptrace server. */ - - ptraceSock = RPC_ANYSOCK; - pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0); - /* FIXME, here is where we deal with different version numbers of the - proto */ - - if (pClient == NULL) - { - clnt_pcreateerror ("\tnet_connect"); - error ("Couldn't connect to remote target."); - } -} - -/* Sleep for the specified number of milliseconds - * (assumed to be less than 1000). - * If select () is interrupted, returns immediately; - * takes an error exit if select () fails for some other reason. - */ - -static void -sleep_ms (long ms) -{ - struct timeval select_timeout; - int status; - - select_timeout.tv_sec = 0; - select_timeout.tv_usec = ms * 1000; - - status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, - &select_timeout); - - if (status < 0 && errno != EINTR) - perror_with_name ("select"); -} - -static ptid_t -vx_wait (ptid_t ptid_to_wait_for, struct target_waitstatus *status) -{ - int pid; - RDB_EVENT rdbEvent; - int quit_failed; - - do - { - /* If CTRL-C is hit during this loop, - suspend the inferior process. */ - - quit_failed = 0; - if (quit_flag) - { - quit_failed = (net_quit () == -1); - quit_flag = 0; - } - - /* If a net_quit () or net_wait () call has failed, - allow the user to break the connection with the target. - We can't simply error () out of this loop, since the - data structures representing the state of the inferior - are in an inconsistent state. */ - - if (quit_failed || net_wait (&rdbEvent) == -1) - { - terminal_ours (); - if (query ("Can't %s. Disconnect from target system? ", - (quit_failed) ? "suspend remote task" - : "get status of remote task")) - { - target_mourn_inferior (); - error ("Use the \"target\" command to reconnect."); - } - else - { - terminal_inferior (); - continue; - } - } - - pid = rdbEvent.taskId; - if (pid == 0) - { - sleep_ms (200); /* FIXME Don't kill the network too badly */ - } - else if (pid != PIDGET (inferior_ptid)) - internal_error (__FILE__, __LINE__, - "Bad pid for debugged task: %s\n", - hex_string ((unsigned long) pid)); - } - while (pid == 0); - - /* The mostly likely kind. */ - status->kind = TARGET_WAITKIND_STOPPED; - - switch (rdbEvent.eventType) - { - case EVENT_EXIT: - status->kind = TARGET_WAITKIND_EXITED; - /* FIXME is it possible to distinguish between a - normal vs abnormal exit in VxWorks? */ - status->value.integer = 0; - break; - - case EVENT_START: - /* Task was just started. */ - status->value.sig = TARGET_SIGNAL_TRAP; - break; - - case EVENT_STOP: - status->value.sig = TARGET_SIGNAL_TRAP; - /* XXX was it stopped by a signal? act accordingly */ - break; - - case EVENT_BREAK: /* Breakpoint was hit. */ - status->value.sig = TARGET_SIGNAL_TRAP; - break; - - case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */ - status->value.sig = TARGET_SIGNAL_INT; - break; - - case EVENT_BUS_ERR: /* Task made evil nasty reference. */ - status->value.sig = TARGET_SIGNAL_BUS; - break; - - case EVENT_ZERO_DIV: /* Division by zero */ - status->value.sig = TARGET_SIGNAL_FPE; - break; - - case EVENT_SIGNAL: -#ifdef I80960 - status->value.sig = i960_fault_to_signal (rdbEvent.sigType); -#else - /* Back in the old days, before enum target_signal, this code used - to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL - would take care of it. But PRINT_RANDOM_SIGNAL has never been - defined except on the i960, so I don't really know what we are - supposed to do on other architectures. */ - status->value.sig = TARGET_SIGNAL_UNKNOWN; -#endif - break; - } /* switch */ - return pid_to_ptid (pid); -} - -static int -symbol_stub (char *arg) -{ - symbol_file_add_main (arg, 0); - return 1; -} - -static int -add_symbol_stub (char *arg) -{ - struct ldfile *pLoadFile = (struct ldfile *) arg; - - printf_unfiltered ("\t%s: ", pLoadFile->name); - vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr, - pLoadFile->data_addr, pLoadFile->bss_addr); - printf_unfiltered ("ok\n"); - return 1; -} -/* Target command for VxWorks target systems. - - Used in vxgdb. Takes the name of a remote target machine - running vxWorks and connects to it to initialize remote network - debugging. */ - -static void -vx_open (char *args, int from_tty) -{ - extern int close (); - char *bootFile; - extern char *source_path; - struct ldtabl loadTable; - struct ldfile *pLoadFile; - int i; - extern CLIENT *pClient; - int symbols_added = 0; - - if (!args) - error_no_arg ("target machine name"); - - target_preopen (from_tty); - - unpush_target (&vx_ops); - printf_unfiltered ("Attaching remote machine across net...\n"); - gdb_flush (gdb_stdout); - - /* Allow the user to kill the connect attempt by typing ^C. - Wait until the call to target_has_fp () completes before - disallowing an immediate quit, since even if net_connect () - is successful, the remote debug server might be hung. */ - - immediate_quit++; - - net_connect (args); - target_has_fp = net_check_for_fp (); - printf_filtered ("Connected to %s.\n", args); - - immediate_quit--; - - push_target (&vx_ops); - - /* Save a copy of the target host's name. */ - vx_host = savestring (args, strlen (args)); - - /* Find out the name of the file from which the target was booted - and load its symbol table. */ - - printf_filtered ("Looking in Unix path for all loaded modules:\n"); - bootFile = NULL; - if (!net_get_boot_file (&bootFile)) - { - if (*bootFile) - { - printf_filtered ("\t%s: ", bootFile); - /* This assumes that the kernel is never relocated. Hope that is an - accurate assumption. */ - if (catch_errors - (symbol_stub, - bootFile, - "Error while reading symbols from boot file:\n", - RETURN_MASK_ALL)) - puts_filtered ("ok\n"); - } - else if (from_tty) - printf_unfiltered ("VxWorks kernel symbols not loaded.\n"); - } - else - error ("Can't retrieve boot file name from target machine."); - - clnt_freeres (pClient, xdr_wrapstring, &bootFile); - - if (net_get_symbols (&loadTable) != 0) - error ("Can't read loaded modules from target machine"); - - i = 0 - 1; - while (++i < loadTable.tbl_size) - { - QUIT; /* FIXME, avoids clnt_freeres below: mem leak */ - pLoadFile = &loadTable.tbl_ent[i]; -#ifdef WRS_ORIG - { - int desc; - struct cleanup *old_chain; - char *fullname = NULL; - - desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname); - if (desc < 0) - perror_with_name (pLoadFile->name); - old_chain = make_cleanup (close, desc); - add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr, - pLoadFile->bss_addr); - do_cleanups (old_chain); - } -#else - /* FIXME: Is there something better to search than the PATH? (probably - not the source path, since source might be in different directories - than objects. */ - - if (catch_errors (add_symbol_stub, (char *) pLoadFile, (char *) 0, - RETURN_MASK_ALL)) - symbols_added = 1; -#endif - } - printf_filtered ("Done.\n"); - - clnt_freeres (pClient, xdr_ldtabl, &loadTable); - - /* Getting new symbols may change our opinion about what is - frameless. */ - if (symbols_added) - reinit_frame_cache (); -} - -/* Takes a task started up outside of gdb and ``attaches'' to it. - This stops it cold in its tracks and allows us to start tracing it. */ - -static void -vx_attach (char *args, int from_tty) -{ - unsigned long pid; - char *cptr = 0; - Rptrace ptrace_in; - Ptrace_return ptrace_out; - int status; - - if (!args) - error_no_arg ("process-id to attach"); - - pid = strtoul (args, &cptr, 0); - if ((cptr == args) || (*cptr != '\0')) - error ("Invalid process-id -- give a single number in decimal or 0xhex"); - - if (from_tty) - printf_unfiltered ("Attaching pid %s.\n", - hex_string ((unsigned long) pid)); - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - ptrace_in.pid = pid; - - status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out); - if (status == -1) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - perror_with_name ("Attaching remote process"); - } - - /* It worked... */ - - inferior_ptid = pid_to_ptid (pid); - push_target (&vx_run_ops); - - if (vx_running) - xfree (vx_running); - vx_running = 0; -} - -/* detach_command -- - takes a program previously attached to and detaches it. - The program resumes execution and will no longer stop - on signals, etc. We better not have left any breakpoints - in the program or it'll die when it hits one. For this - to work, it may be necessary for the process to have been - previously attached. It *might* work if the program was - started via the normal ptrace (PTRACE_TRACEME). */ - -static void -vx_detach (char *args, int from_tty) -{ - Rptrace ptrace_in; - Ptrace_return ptrace_out; - int signal = 0; - int status; - - if (args) - error ("Argument given to VxWorks \"detach\"."); - - if (from_tty) - printf_unfiltered ("Detaching pid %s.\n", - hex_string ( - (unsigned long) PIDGET (inferior_ptid))); - - if (args) /* FIXME, should be possible to leave suspended */ - signal = atoi (args); - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - ptrace_in.pid = PIDGET (inferior_ptid); - - status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out); - if (status == -1) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - perror_with_name ("Detaching VxWorks process"); - } - - inferior_ptid = null_ptid; - pop_target (); /* go back to non-executing VxWorks connection */ -} - -/* vx_kill -- takes a running task and wipes it out. */ - -static void -vx_kill (void) -{ - Rptrace ptrace_in; - Ptrace_return ptrace_out; - int status; - - printf_unfiltered ("Killing pid %s.\n", - hex_string ((unsigned long) PIDGET (inferior_ptid))); - - memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); - memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); - ptrace_in.pid = PIDGET (inferior_ptid); - - status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out); - if (status == -1) - warning (rpcerr); - else if (ptrace_out.status == -1) - { - errno = ptrace_out.errno_num; - perror_with_name ("Killing VxWorks process"); - } - - /* If it gives good status, the process is *gone*, no events remain. - If the kill failed, assume the process is gone anyhow. */ - inferior_ptid = null_ptid; - pop_target (); /* go back to non-executing VxWorks connection */ -} - -/* Clean up from the VxWorks process target as it goes away. */ - -static void -vx_proc_close (int quitting) -{ - inferior_ptid = null_ptid; /* No longer have a process. */ - if (vx_running) - xfree (vx_running); - vx_running = 0; -} - -/* Make an RPC call to the VxWorks target. - Returns RPC status. */ - -static enum clnt_stat -net_clnt_call (enum ptracereq procNum, xdrproc_t inProc, char *in, - xdrproc_t outProc, char *out) -{ - enum clnt_stat status; - - status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout); - - if (status != RPC_SUCCESS) - clnt_perrno (status); - - return status; -} - -/* Clean up before losing control. */ - -static void -vx_close (int quitting) -{ - if (pClient) - clnt_destroy (pClient); /* The net connection */ - pClient = 0; - - if (vx_host) - xfree (vx_host); /* The hostname */ - vx_host = 0; -} - -/* A vxprocess target should be started via "run" not "target". */ -static void -vx_proc_open (char *name, int from_tty) -{ - error ("Use the \"run\" command to start a VxWorks process."); -} - -static void -init_vx_ops (void) -{ - vx_ops.to_shortname = "vxworks"; - vx_ops.to_longname = "VxWorks target memory via RPC over TCP/IP"; - vx_ops.to_doc = "Use VxWorks target memory. \n\ -Specify the name of the machine to connect to."; - vx_ops.to_open = vx_open; - vx_ops.to_close = vx_close; - vx_ops.to_attach = vx_attach; - vx_ops.deprecated_xfer_memory = vx_xfer_memory; - vx_ops.to_files_info = vx_files_info; - vx_ops.to_load = vx_load_command; - vx_ops.to_lookup_symbol = vx_lookup_symbol; - vx_ops.to_create_inferior = vx_create_inferior; - vx_ops.to_stratum = core_stratum; - vx_ops.to_has_all_memory = 1; - vx_ops.to_has_memory = 1; - vx_ops.to_magic = OPS_MAGIC; /* Always the last thing */ -}; - -static void -init_vx_run_ops (void) -{ - vx_run_ops.to_shortname = "vxprocess"; - vx_run_ops.to_longname = "VxWorks process"; - vx_run_ops.to_doc = "VxWorks process; started by the \"run\" command."; - vx_run_ops.to_open = vx_proc_open; - vx_run_ops.to_close = vx_proc_close; - vx_run_ops.to_detach = vx_detach; - vx_run_ops.to_resume = vx_resume; - vx_run_ops.to_wait = vx_wait; - vx_run_ops.to_fetch_registers = vx_read_register; - vx_run_ops.to_store_registers = vx_write_register; - vx_run_ops.to_prepare_to_store = vx_prepare_to_store; - vx_run_ops.deprecated_xfer_memory = vx_xfer_memory; - vx_run_ops.to_files_info = vx_run_files_info; - vx_run_ops.to_insert_breakpoint = vx_insert_breakpoint; - vx_run_ops.to_remove_breakpoint = vx_remove_breakpoint; - vx_run_ops.to_kill = vx_kill; - vx_run_ops.to_load = vx_load_command; - vx_run_ops.to_lookup_symbol = vx_lookup_symbol; - vx_run_ops.to_mourn_inferior = vx_mourn_inferior; - vx_run_ops.to_stratum = process_stratum; - vx_run_ops.to_has_memory = 1; - vx_run_ops.to_has_stack = 1; - vx_run_ops.to_has_registers = 1; - vx_run_ops.to_has_execution = 1; - vx_run_ops.to_magic = OPS_MAGIC; -} - -void -_initialize_vx (void) -{ - init_vx_ops (); - add_target (&vx_ops); - init_vx_run_ops (); - add_target (&vx_run_ops); - - deprecated_add_show_from_set - (add_set_cmd ("vxworks-timeout", class_support, var_uinteger, - (char *) &rpcTimeout.tv_sec, - "Set seconds to wait for rpc calls to return.\n\ -Set the number of seconds to wait for rpc calls to return.", &setlist), - &showlist); -} |