X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Fremote-vx.c;h=13b6c294994ca8e5feaaaafd39dbf3d8555631e4;hb=f09c6a96e688fa371b1b6c066c116b454a710051;hp=a9548a9a238ca89ed4ac56fc0eddbeafc869c159;hpb=568947885c4866d83b3a04c39a43ca8d38762db1;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/remote-vx.c b/gdb/remote-vx.c index a9548a9a23..13b6c29499 100644 --- a/gdb/remote-vx.c +++ b/gdb/remote-vx.c @@ -16,7 +16,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "frame.h" @@ -28,8 +28,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "symtab.h" #include "complaints.h" #include "gdbcmd.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" +#include "gdb-stabs.h" -#include +#include "gdb_string.h" #include #include #include @@ -52,9 +56,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +/* 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 int stop_soon_quietly; /* 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 */ extern struct target_ops vx_ops, vx_run_ops; /* Forward declaration */ @@ -68,7 +79,7 @@ static char *vx_running; /* Called function */ /* Nonzero means target that is being debugged remotely has a floating point processor. */ -static int target_has_fp; +int target_has_fp; /* Default error message when the network is forking up. */ @@ -92,91 +103,91 @@ static char *find_white_space (); static int net_load (filename, pTextAddr, pDataAddr, pBssAddr) - char *filename; - CORE_ADDR *pTextAddr; - CORE_ADDR *pDataAddr; - CORE_ADDR *pBssAddr; - { - enum clnt_stat status; - struct ldfile ldstruct; - struct timeval load_timeout; - - bzero ((char *) &ldstruct, sizeof (ldstruct)); + char *filename; + CORE_ADDR *pTextAddr; + CORE_ADDR *pDataAddr; + CORE_ADDR *pBssAddr; +{ + enum clnt_stat status; + struct ldfile ldstruct; + struct timeval load_timeout; - /* 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. + memset ((char *) &ldstruct, '\0', sizeof (ldstruct)); - 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... */ + /* 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. - load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */ - load_timeout.tv_usec = 0; + 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); + 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; + 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 (addr, procnum) - 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? */ + 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? */ - bzero ((char *) &ptrace_in, sizeof (ptrace_in)); - break_status = 0; + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + break_status = 0; - ptrace_in.addr = addr; - ptrace_in.pid = inferior_pid; + ptrace_in.addr = addr; + ptrace_in.pid = inferior_pid; - status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, - &break_status); + status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, + &break_status); - if (status != RPC_SUCCESS) - return errno; + if (status != RPC_SUCCESS) + return errno; + + if (break_status == -1) + return ENOMEM; + return break_status; /* probably (FIXME) zero */ +} - if (break_status == -1) - return ENOMEM; - return break_status; /* probably (FIXME) zero */ - } - /* returns 0 if successful, errno otherwise */ static int vx_insert_breakpoint (addr) - int addr; - { - return net_break (addr, VX_BREAK_ADD); - } + int addr; +{ + return net_break (addr, VX_BREAK_ADD); +} /* returns 0 if successful, errno otherwise */ static int vx_remove_breakpoint (addr) - int addr; - { - return net_break (addr, VX_BREAK_DELETE); - } + int addr; +{ + return net_break (addr, VX_BREAK_DELETE); +} /* Start an inferior process and sets inferior_pid to its pid. EXEC_FILE is the file to run. @@ -195,8 +206,8 @@ vx_create_inferior (exec_file, args, env) arg_array passArgs; TASK_START taskStart; - bzero ((char *) &passArgs, sizeof (passArgs)); - bzero ((char *) &taskStart, sizeof (taskStart)); + memset ((char *) &passArgs, '\0', sizeof (passArgs)); + memset ((char *) &taskStart, '\0', sizeof (taskStart)); /* parse arguments, put them in passArgs */ @@ -215,10 +226,6 @@ vx_create_inferior (exec_file, args, env) vx_running = savestring (passArgs.arg_array_val[0], strlen (passArgs.arg_array_val[0])); -#ifdef CREATE_INFERIOR_HOOK - CREATE_INFERIOR_HOOK (pid); -#endif - push_target (&vx_run_ops); inferior_pid = taskStart.pid; @@ -239,7 +246,7 @@ vx_create_inferior (exec_file, args, env) stop_soon_quietly = 0; /* insert_step_breakpoint (); FIXME, do we need this? */ - proceed(-1, -1, 0); + proceed (-1, TARGET_SIGNAL_DEFAULT, 0); } /* Fill ARGSTRUCT in argc/argv form with the arguments from the @@ -254,7 +261,7 @@ parse_args (arg_string, arg_struct) register int arg_index = 0; register char *p0; - bzero ((char *) arg_struct, sizeof (arg_array)); + memset ((char *) arg_struct, '\0', sizeof (arg_array)); /* first count how many arguments there are */ @@ -334,12 +341,19 @@ net_wait (pEvent) int pid; enum clnt_stat status; - bzero ((char *) pEvent, sizeof (RDB_EVENT)); + memset ((char *) pEvent, '\0', sizeof (RDB_EVENT)); pid = inferior_pid; - status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent); + status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, + pEvent); - return (status == RPC_SUCCESS)? pEvent->status: -1; + /* 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. @@ -348,156 +362,120 @@ net_wait (pEvent) static int net_quit () { - int pid; - int quit_status; - enum clnt_stat status; + int pid; + int quit_status; + enum clnt_stat status; - quit_status = 0; + quit_status = 0; - /* don't let rdbTask suspend itself by passing a pid of 0 */ + /* don't let rdbTask suspend itself by passing a pid of 0 */ - if ((pid = inferior_pid) == 0) - return -1; + if ((pid = inferior_pid) == 0) + return -1; - status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, - &quit_status); + status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, + &quit_status); - return (status == RPC_SUCCESS)? quit_status: -1; + return (status == RPC_SUCCESS)? quit_status: -1; } /* Read a register or registers from the remote system. */ -static void -vx_read_register (regno) - int regno; +void +net_read_registers (reg_buf, len, procnum) + char *reg_buf; + int len; + u_long procnum; { int status; Rptrace ptrace_in; Ptrace_return ptrace_out; - C_bytes in_data; C_bytes out_data; - extern char registers[]; + char message[100]; - bzero ((char *) &ptrace_in, sizeof (ptrace_in)); - bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); + + /* Initialize RPC input argument structure. */ - /* FIXME, eventually only get the ones we need. */ - registers_fetched (); - ptrace_in.pid = inferior_pid; + 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; - out_data.len = VX_NUM_REGS * REGISTER_RAW_SIZE (0); - out_data.bytes = (caddr_t) registers; - - status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out); + + /* 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; - perror_with_name ("net_ptrace_clnt_call(PTRACE_GETREGS)"); + sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS) + ? "general-purpose" + : "floating-point"); + perror_with_name (message); } - -#ifdef VX_SIZE_FPREGS - /* If the target has floating point registers, fetch them. - Otherwise, zero the floating point register values in - registers[] for good measure, even though we might not - need to. */ - - if (target_has_fp) - { - ptrace_in.pid = inferior_pid; - ptrace_out.info.more_data = (caddr_t) &out_data; - out_data.len = VX_SIZE_FPREGS; - out_data.bytes = (caddr_t) ®isters[REGISTER_BYTE (FP0_REGNUM)]; - - status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out); - if (status) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno; - perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)"); - } - } - else - { - bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], VX_SIZE_FPREGS); - } -#endif /* VX_SIZE_FPREGS */ } -/* Prepare to store registers. Since we will store all of them, - read out their current values now. */ +/* 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 (). */ -static void -vx_prepare_to_store () -{ - /* Fetch all registers, if any of them are not yet fetched. */ - read_register_bytes (0, NULL, REGISTER_BYTES); -} - - -/* Store our register values back into the inferior. - If REGNO is -1, do this for all registers. - Otherwise, REGNO specifies which register (so we can save time). */ - /* FIXME, look at REGNO to save time here */ - -static void -vx_write_register (regno) - int regno; +void +net_write_registers (reg_buf, len, procnum) + char *reg_buf; + int len; + u_long procnum; { - C_bytes in_data; - C_bytes out_data; - extern char registers[]; 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. */ - bzero ((char *) &ptrace_in, sizeof (ptrace_in)); - bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + in_data.bytes = reg_buf; + in_data.len = len; ptrace_in.pid = inferior_pid; - ptrace_in.info.ttype = DATA; + ptrace_in.info.ttype = DATA; ptrace_in.info.more_data = (caddr_t) &in_data; - in_data.bytes = registers; + /* Call RPC; take an error exit if appropriate. */ - in_data.len = VX_NUM_REGS * sizeof (REGISTER_TYPE); - - /* XXX change second param to be a proc number */ - status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out); + status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out); if (status) - error (rpcerr); + error (rpcerr); if (ptrace_out.status == -1) { errno = ptrace_out.errno; - perror_with_name ("net_ptrace_clnt_call(PTRACE_SETREGS)"); + sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS) + ? "general-purpose" + : "floating-point"); + perror_with_name (message); } +} -#ifdef VX_SIZE_FPREGS - /* Store floating point registers if the target has them. */ - - if (target_has_fp) - { - ptrace_in.pid = inferior_pid; - ptrace_in.info.ttype = DATA; - ptrace_in.info.more_data = (caddr_t) &in_data; - - - in_data.bytes = ®isters[REGISTER_BYTE (FP0_REGNUM)]; - in_data.len = VX_SIZE_FPREGS; +/* Prepare to store registers. Since we will store all of them, + read out their current values now. */ - status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out); - if (status) - error (rpcerr); - if (ptrace_out.status == -1) - { - errno = ptrace_out.errno; - perror_with_name ("net_ptrace_clnt_call(PTRACE_SETFPREGS)"); - } - } -#endif /* VX_SIZE_FPREGS */ +static void +vx_prepare_to_store () +{ + /* Fetch all registers, if any of them are not yet fetched. */ + read_register_bytes (0, NULL, REGISTER_BYTES); } /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR @@ -520,9 +498,11 @@ vx_xfer_memory (memaddr, myaddr, len, write, target) Rptrace ptrace_in; Ptrace_return ptrace_out; C_bytes data; + enum ptracereq request; + int nleft, nxfer; - bzero ((char *) &ptrace_in, sizeof (ptrace_in)); - bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */ ptrace_in.addr = (int) memaddr; /* Where from */ @@ -535,71 +515,118 @@ vx_xfer_memory (memaddr, myaddr, len, write, target) data.bytes = (caddr_t) myaddr; /* Where from */ data.len = len; /* How many bytes (again, for XDR) */ - - /* XXX change second param to be a proc number */ - status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out); + request = PTRACE_WRITEDATA; } else { ptrace_out.info.more_data = (caddr_t) &data; - data.bytes = myaddr; /* Where to */ - data.len = len; /* How many (again, for XDR) */ - - /* XXX change second param to be a proc number */ - status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out); + 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. */ - if (status) - error (rpcerr); - if (ptrace_out.status == -1) + nleft = len; + status = 0; + + while (nleft > 0 && status == 0) { - return 0; /* No bytes moved */ + 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; + } } - return len; /* Moved *all* the bytes */ + + /* Return the number of bytes transferred. */ + + return (len - nleft); } static void vx_files_info () { - printf ("\tAttached to host `%s'", vx_host); - printf (", which has %sfloating point", target_has_fp? "": "no "); - printf (".\n"); + 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 () { - printf ("\tRunning %s VxWorks process %s", - vx_running? "child": "attached", - local_hex_string(inferior_pid)); + printf_unfiltered ("\tRunning %s VxWorks process %s", + vx_running ? "child" : "attached", + local_hex_string (inferior_pid)); if (vx_running) - printf (", function `%s'", vx_running); - printf(".\n"); + printf_unfiltered (", function `%s'", vx_running); + printf_unfiltered(".\n"); } static void -vx_resume (step, siggnal) +vx_resume (pid, step, siggnal) + int pid; int step; - int siggnal; + enum target_signal siggnal; { int status; Rptrace ptrace_in; Ptrace_return ptrace_out; + CORE_ADDR cont_addr; + + if (pid == -1) + pid = inferior_pid; if (siggnal != 0 && siggnal != stop_signal) error ("Cannot send signals to VxWorks processes"); - bzero ((char *) &ptrace_in, sizeof (ptrace_in)); - bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + /* 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. */ - ptrace_in.pid = inferior_pid; - ptrace_in.addr = 1; /* Target side insists on this, or it panics. */ + 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 = pid; + 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); - /* XXX change second param to be a proc number */ - status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT, - &ptrace_in, &ptrace_out); if (status) - error (rpcerr); + error (rpcerr); if (ptrace_out.status == -1) { errno = ptrace_out.errno; @@ -615,17 +642,95 @@ vx_mourn_inferior () } +static void vx_add_symbols PARAMS ((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 PARAMS ((bfd *, asection *, void *)); + +static void +find_sect (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR 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 (name, from_tty, text_addr, data_addr, bss_addr) + 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, 0, 0, 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 (struct section_offsets) + + objfile->num_sections * sizeof (offs->offsets)); + memcpy (offs, objfile->section_offsets, + sizeof (struct section_offsets) + + objfile->num_sections * sizeof (offs->offsets)); + + 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. */ + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr - ss.text_start; + ANOFFSET (offs, SECT_OFF_DATA) = data_addr - ss.data_start; + ANOFFSET (offs, SECT_OFF_BSS) = bss_addr - ss.bss_start; + objfile_relocate (objfile, offs); + + /* Need to do this *after* things are relocated. */ + breakpoint_re_set (); +} + /* This function allows the addition of incrementally linked object files. */ static void vx_load_command (arg_string, from_tty) - char* arg_string; + 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"); @@ -634,17 +739,31 @@ vx_load_command (arg_string, from_tty) 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 (inferior_pid != 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 cancelled."); + } + QUIT; immediate_quit++; if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1) error ("Load failed on target machine"); immediate_quit--; - /* FIXME, for now we ignore data_addr and bss_addr. */ - symbol_file_add (arg_string, from_tty, text_addr, 0, 0, 0); + 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 (); } -#ifdef FIXME /* Not ready for prime time */ /* 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. */ @@ -677,7 +796,6 @@ net_step () else error (rpcerr); } -#endif /* Emulate ptrace using RPC calls to the VxWorks target system. Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */ @@ -727,7 +845,7 @@ net_get_symbols (pLoadTable) { enum clnt_stat status; - bzero ((char *) pLoadTable, sizeof (struct ldtabl)); + 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; @@ -749,14 +867,15 @@ vx_lookup_symbol (name, pAddr) SYMBOL_ADDR symbolAddr; *pAddr = 0; - bzero ((char *) &symbolAddr, sizeof (symbolAddr)); + memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr)); status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name, xdr_SYMBOL_ADDR, &symbolAddr); - if (status != RPC_SUCCESS) { + if (status != RPC_SUCCESS) + { complain (&cant_contact_target); return -1; - } + } *pAddr = symbolAddr.addr; return symbolAddr.status; @@ -774,7 +893,7 @@ net_check_for_fp () status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp); if (status != RPC_SUCCESS) - error (rpcerr); + error (rpcerr); return (int) fp; } @@ -789,7 +908,7 @@ net_connect (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. */ @@ -798,11 +917,14 @@ net_connect (host) { 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; } - bzero (&destAddr, sizeof (destAddr)); + memset (&destAddr, '\0', sizeof (destAddr)); destAddr.sin_addr.s_addr = addr; destAddr.sin_family = AF_INET; @@ -814,8 +936,9 @@ net_connect (host) 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 */ - + /* FIXME, here is where we deal with different version numbers of the + proto */ + if (pClient == NULL) { clnt_pcreateerror ("\tnet_connect"); @@ -839,30 +962,19 @@ sleep_ms (ms) 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); + status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, + &select_timeout); if (status < 0 && errno != EINTR) perror_with_name ("select"); } -/* Wait for control to return from inferior to debugger. - If inferior gets a signal, we may decide to start it up again - instead of returning. That is why there is a loop in this function. - When this function actually returns it means the inferior - should be left stopped and GDB should read more commands. */ - -/* For network debugging with VxWorks. - * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc, - * so vx_wait() receives this information directly from - * VxWorks instead of trying to figure out what happenned via a wait() call. - */ - static int -vx_wait (status) - int *status; +vx_wait (pid_to_wait_for, status) + int pid_to_wait_for; + struct target_waitstatus *status; { register int pid; - WAITTYPE w; RDB_EVENT rdbEvent; int quit_failed; @@ -907,54 +1019,61 @@ vx_wait (status) sleep_ms (200); /* FIXME Don't kill the network too badly */ } else if (pid != inferior_pid) - fatal ("Bad pid for debugged task: %s\n", local_hex_string(pid)); + fatal ("Bad pid for debugged task: %s\n", + local_hex_string((unsigned long) pid)); } while (pid == 0); - /* FIXME, eventually do more then SIGTRAP on everything... */ + /* The mostly likely kind. */ + status->kind = TARGET_WAITKIND_STOPPED; + switch (rdbEvent.eventType) { case EVENT_EXIT: - WSETEXIT (w, 0); + status->kind = TARGET_WAITKIND_EXITED; /* FIXME is it possible to distinguish between a - XXX normal vs abnormal exit in VxWorks? */ + normal vs abnormal exit in VxWorks? */ + status->value.integer = 0; break; - case EVENT_START: /* Task was just started. */ - WSETSTOP (w, SIGTRAP); + case EVENT_START: + /* Task was just started. */ + status->value.sig = TARGET_SIGNAL_TRAP; break; case EVENT_STOP: - WSETSTOP (w, SIGTRAP); + status->value.sig = TARGET_SIGNAL_TRAP; /* XXX was it stopped by a signal? act accordingly */ break; case EVENT_BREAK: /* Breakpoint was hit. */ - WSETSTOP (w, SIGTRAP); + status->value.sig = TARGET_SIGNAL_TRAP; break; case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */ - WSETSTOP (w, SIGINT); + status->value.sig = TARGET_SIGNAL_INT; break; case EVENT_BUS_ERR: /* Task made evil nasty reference. */ - WSETSTOP (w, SIGBUS); + status->value.sig = TARGET_SIGNAL_BUS; break; case EVENT_ZERO_DIV: /* Division by zero */ - WSETSTOP (w, SIGFPE); /* Like Unix, call it a float exception. */ + status->value.sig = TARGET_SIGNAL_FPE; break; case EVENT_SIGNAL: - /* The target is not running Unix, and its - faults/traces do not map nicely into Unix signals. - Make sure they do not get confused with Unix signals - by numbering them with values higher than the highest - legal Unix signal. code in the arch-dependent PRINT_RANDOM_SIGNAL - routine will interpret the value for wait_for_inferior. */ - WSETSTOP (w, rdbEvent.sigType + NSIG); +#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 */ - *status = *(int *)&w; /* Grumble union wait crap Grumble */ return pid; } @@ -972,9 +1091,10 @@ add_symbol_stub (arg) { struct ldfile *pLoadFile = (struct ldfile *)arg; - printf("\t%s: ", pLoadFile->name); - symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0, 0, 0); - printf ("ok\n"); + 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. @@ -995,6 +1115,7 @@ vx_open (args, from_tty) struct ldfile *pLoadFile; int i; extern CLIENT *pClient; + int symbols_added = 0; if (!args) error_no_arg ("target machine name"); @@ -1002,8 +1123,8 @@ vx_open (args, from_tty) target_preopen (from_tty); unpush_target (&vx_ops); - printf ("Attaching remote machine across net...\n"); - fflush (stdout); + 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 @@ -1030,14 +1151,20 @@ vx_open (args, from_tty) bootFile = NULL; if (!net_get_boot_file (&bootFile)) { - if (*bootFile) { - printf_filtered ("\t%s: ", bootFile); - 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 ("VxWorks kernel symbols not loaded.\n"); + 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."); @@ -1067,16 +1194,23 @@ vx_open (args, from_tty) do_cleanups (old_chain); } #else - /* Botches, FIXME: - (1) Searches the PATH, not the source path. - (2) data and bss are assumed to be at the usual offsets from text. */ - catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0, - RETURN_MASK_ALL); + /* 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. @@ -1087,7 +1221,7 @@ vx_attach (args, from_tty) char *args; int from_tty; { - int pid; + unsigned long pid; char *cptr = 0; Rptrace ptrace_in; Ptrace_return ptrace_out; @@ -1096,15 +1230,16 @@ vx_attach (args, from_tty) if (!args) error_no_arg ("process-id to attach"); - pid = strtol (args, &cptr, 0); + 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 ("Attaching pid %s.\n", local_hex_string(pid)); + printf_unfiltered ("Attaching pid %s.\n", + local_hex_string((unsigned long) pid)); - bzero ((char *)&ptrace_in, sizeof (ptrace_in)); - bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + 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); @@ -1118,8 +1253,34 @@ vx_attach (args, from_tty) /* It worked... */ push_target (&vx_run_ops); + /* The unsigned long pid will get turned into a signed int here, + but it doesn't seem to matter. inferior_pid must be signed + in order for other parts of GDB to work correctly. */ inferior_pid = pid; vx_running = 0; +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + mark_breakpoints_out (); + + /* 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 (); + + /* We will get a task spawn event immediately. */ + + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + wait_for_inferior (); + stop_soon_quietly = 0; + normal_stop (); } @@ -1146,13 +1307,14 @@ vx_detach (args, from_tty) error ("Argument given to VxWorks \"detach\"."); if (from_tty) - printf ("Detaching pid %s.\n", local_hex_string(inferior_pid)); + printf_unfiltered ("Detaching pid %s.\n", + local_hex_string((unsigned long) inferior_pid)); if (args) /* FIXME, should be possible to leave suspended */ signal = atoi (args); - bzero ((char *)&ptrace_in, sizeof (ptrace_in)); - bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + memset ((char *)&ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out)); ptrace_in.pid = inferior_pid; status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out); @@ -1177,10 +1339,10 @@ vx_kill () Ptrace_return ptrace_out; int status; - printf ("Killing pid %s.\n", local_hex_string(inferior_pid)); + printf_unfiltered ("Killing pid %s.\n", local_hex_string((unsigned long) inferior_pid)); - bzero ((char *)&ptrace_in, sizeof (ptrace_in)); - bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + memset ((char *)&ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out)); ptrace_in.pid = inferior_pid; status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out); @@ -1259,65 +1421,68 @@ vx_proc_open (name, from_tty) /* Target ops structure for accessing memory and such over the net */ struct target_ops vx_ops = { - "vxworks", "VxWorks target memory via RPC over TCP/IP", - "Use VxWorks target memory. \n\ + "vxworks", "VxWorks target memory via RPC over TCP/IP", + "Use VxWorks target memory. \n\ Specify the name of the machine to connect to.", - vx_open, vx_close, vx_attach, 0, /* vx_detach, */ - 0, 0, /* resume, wait */ - 0, 0, /* read_reg, write_reg */ - 0, /* prep_to_store, */ - vx_xfer_memory, vx_files_info, - 0, 0, /* insert_breakpoint, remove_breakpoint */ - 0, 0, 0, 0, 0, /* terminal stuff */ - 0, /* vx_kill, */ - vx_load_command, - vx_lookup_symbol, - vx_create_inferior, 0, /* mourn_inferior */ - 0, /* can_run */ - 0, /* notice_signals */ - core_stratum, 0, /* next */ - 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ - 0, 0, /* Section pointers */ - OPS_MAGIC, /* Always the last thing */ + vx_open, vx_close, vx_attach, 0, /* vx_detach, */ + 0, 0, /* resume, wait */ + 0, 0, /* read_reg, write_reg */ + 0, /* prep_to_store, */ + vx_xfer_memory, vx_files_info, + 0, 0, /* insert_breakpoint, remove_breakpoint */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, /* vx_kill, */ + vx_load_command, + vx_lookup_symbol, + vx_create_inferior, 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* thread_alive */ + 0, /* to_stop */ + core_stratum, 0, /* next */ + 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ }; /* Target ops structure for accessing VxWorks child processes over the net */ struct target_ops vx_run_ops = { - "vxprocess", "VxWorks process", - "VxWorks process, started by the \"run\" command.", - vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */ - vx_resume, vx_wait, - vx_read_register, vx_write_register, - vx_prepare_to_store, - vx_xfer_memory, vx_run_files_info, - vx_insert_breakpoint, vx_remove_breakpoint, - 0, 0, 0, 0, 0, /* terminal stuff */ - vx_kill, - vx_load_command, - vx_lookup_symbol, - 0, vx_mourn_inferior, - 0, /* can_run */ - 0, /* notice_signals */ - process_stratum, 0, /* next */ - 0, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ - /* all_mem is off to avoid spurious msg in "i files" */ - 0, 0, /* Section pointers */ - OPS_MAGIC, /* Always the last thing */ + "vxprocess", "VxWorks process", + "VxWorks process, started by the \"run\" command.", + vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */ + vx_resume, vx_wait, + vx_read_register, vx_write_register, + vx_prepare_to_store, + vx_xfer_memory, vx_run_files_info, + vx_insert_breakpoint, vx_remove_breakpoint, + 0, 0, 0, 0, 0, /* terminal stuff */ + vx_kill, + vx_load_command, + vx_lookup_symbol, + 0, vx_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* thread_alive */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 0, /* all_mem--off to avoid spurious msg in "i files" */ + 1, 1, 1, 1, /* mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ }; /* ==> Remember when reading at end of file, there are two "ops" structs here. */ void _initialize_vx () { - - add_show_from_set - (add_set_cmd ("rpcTimeout", class_support, var_uinteger, + 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); - add_target (&vx_ops); + add_target (&vx_ops); add_target (&vx_run_ops); }