diff options
author | Stan Shebs <shebs@codesourcery.com> | 1995-05-03 01:43:27 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1995-05-03 01:43:27 +0000 |
commit | 33bc979d1764c81a88c5681e4fee0099203bed75 (patch) | |
tree | f0272c8a35fcf0922be6e18b8ea87dd3b56d6efb /gdb/remote-nrom.c | |
parent | 55ac59da2eab55ab8f74d69eab13c36d4da9fd3b (diff) | |
download | gdb-33bc979d1764c81a88c5681e4fee0099203bed75.zip gdb-33bc979d1764c81a88c5681e4fee0099203bed75.tar.gz gdb-33bc979d1764c81a88c5681e4fee0099203bed75.tar.bz2 |
* configure.in (--enable-netrom): New configuration option.
* Makefile.in (REMOTE_OBS): Rename from REMOTE_O, append
value of NETROM_OBS.
(NETROM_OBS): New variable.
* remote-nrom.c: New file, NetROM target support.
* config/a29k/a29k-udi.mt, config/i960/vxworks960.mt: Use
REMOTE_OBS instead of REMOTE_O.
start-sanitize-arc
* config/arc/arc.mt: Ditto.
end-sanitize-arc
Diffstat (limited to 'gdb/remote-nrom.c')
-rw-r--r-- | gdb/remote-nrom.c | 1356 |
1 files changed, 1356 insertions, 0 deletions
diff --git a/gdb/remote-nrom.c b/gdb/remote-nrom.c new file mode 100644 index 0000000..1699d4c --- /dev/null +++ b/gdb/remote-nrom.c @@ -0,0 +1,1356 @@ +/* Remote debugging with the XLNT Designs, Inc (XDI) NetROM. + Copyright 1990, 1991, 1992, 1995 Free Software Foundation, Inc. + Contributed by: + Roger Moyers + XLNT Designs, Inc. + 15050 Avenue of Science, Suite 106 + San Diego, CA 92128 + (619)487-9320 + roger@xlnt.com + Adapted from work done at Cygnus Support in remote-nindy.c, + later merged in by Stan Shebs at Cygnus. + +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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "gdbcmd.h" +#include <string.h> +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <stropts.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netdb.h> +#include <unistd.h> +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" + +/* Packet header found on every packet sent to/from GDB. */ + +typedef struct gpkthdr { + unsigned char csum; /* Check sum */ + unsigned char seq_num; /* Sequence number */ + unsigned short len; /* Number of bytes in packet */ + unsigned char cmd; /* GDB command */ + unsigned char pad[3]; + unsigned long addr; /* Address if needed */ + unsigned long datalen; /* # of bytes to read/write */ +} GPKTHDR; + +#define GDB_START_DELIMITER '[' +#define GDB_END_DELIMITER ']' + +/* GDB requests. */ + +#define GDB_QUERY_CMD 0x01 +#define GDB_STATUS 0x02 +#define GDB_READ_REGS 0x03 +#define GDB_WRITE_REGS 0x04 +#define GDB_READ_MEM 0x05 +#define GDB_WRITE_MEM 0x06 +#define GDB_CONTINUE 0x07 +#define GDB_STEP 0x08 + +/* Responses. */ + +#define GDB_ACK 0x11 +#define GDB_NACK 0x12 +#define GDB_READ_REG_RESP 0x13 +#define GDB_READ_MEM_RESP 0x14 +#define GDB_WRITE_REG_RESP 0x15 +#define GDB_WRITE_MEM_RESP 0x16 + +#define GDB_BP_TRAP "05" +#define GDB_BUSERR_TRAP "10" +#define GDB_ILLOP_TRAP "40" + +#define GDB_ACK_VALUE "OK" + +/* Default ports used to talk with the NetROM. */ + +#define DEFAULT_NETROM_TARGET_PORT 1235 +#define DEFAULT_NETROM_LOAD_PORT 1236 +#define DEFAULT_NETROM_CONTROL_PORT 1237 + +#define UC(b) (((long)b)&0xff) + +#define NROM_BUF_SIZE 2048 +#define MAX_SEND_ATTEMPTS 10 +#define READ_BUF_SIZE 2048 + +/* Definitions for filetype. */ + +#define BINARY_FTYPE 0 +#define MOTO_SREC 1 +#define INTEL_HEX 2 + +#if 0 /* for debugging, if anyone cares */ +static char *GCMDTYPE[] = { + "ZERO", + "GDB_QUERY", + "GDB_STATUS", + "GDB_READ_REGS", + "GDB_WRITE_REGS", + "GDB_READ_MEM", + "GDB_WRITE_MEM", + "GDB_CONTINUE", + "GDB_STEP", + "CMD9", + "CMDA", + "CMDB", + "CMDC", + "CMDD", + "CMDE", + "CMDF", + "RESP0", + "GDB_ACK", + "GDB_NACK", + "GDB_READ_REG_RESP", + "GDB_READ_MEM_RESP", + "GDB_WRITE_REG_RESP", + "GDB_WRITE_MEM_RESP" +}; +#endif + +static void nrom_attach PARAMS ((char *, int)); + +static int nrom_can_run PARAMS ((void)); + +static void nrom_close PARAMS ((int)); + +static void nrom_create_inferior PARAMS ((char *, char *, char **)); + +static void nrom_detach PARAMS ((char *, int)); + +static void nrom_fetch_registers PARAMS ((int)); + +static void nrom_files_info PARAMS ((struct target_ops *)); + +static void nrom_kill PARAMS ((void)); + +static void nrom_load PARAMS ((char *, int)); + +static void nrom_mourn PARAMS ((void)); + +static void nrom_open PARAMS ((char *,int)); + +static void nrom_resume PARAMS ((int, int, enum target_signal)); + +static void nrom_prepare_to_store PARAMS ((void)); + +static void nrom_store_registers PARAMS ((int)); + +static int nrom_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static int nrom_xfer_inferior_memory PARAMS ((CORE_ADDR, char *, int, int, + struct target_ops *)); + +static int nrom_write_inferior_memory PARAMS ((CORE_ADDR, char *, int)); + +static int nrom_read_inferior_memory PARAMS ((CORE_ADDR, char *, int)); + +/* New commands. */ + +static void nrom_set_target_port PARAMS ((char *, int)); + +static void nrom_set_control_port PARAMS ((char *, int)); + +static void nrom_set_load_port PARAMS ((char *, int)); + +static void nrom_set_ipaddr PARAMS ((char *, int)); + +static void nrom_set_filetype PARAMS ((char *, int)); + +static void nrom_show_status PARAMS ((char *, int)); + +static void nrom_passthru PARAMS ((char *, int)); + +/* Packet functions. */ + +static void build_pkt PARAMS ((int, unsigned char *, long, + unsigned char *, unsigned long, unsigned long, + int)); + +static int compute_csum PARAMS ((unsigned char *, int)); + +#if 0 +static void dump_pkt PARAMS ((GPKTHDR *, unsigned char *)); +#endif + +static int get_seq_number PARAMS ((void)); + +static char *hex2mem PARAMS ((char *, char *, int)); + +static char *mem2hex PARAMS ((char *, char *, int)); + +static void nrom_send PARAMS ((int, char *, int, long, long, char *)); + +static void send_query_cmd PARAMS ((void)); + +static int send_pkt PARAMS ((int, char *, int, long, int)); + +static int read_pkt PARAMS ((char *)); + +static void send_query_cmd PARAMS ((void)); + +static int tohex PARAMS ((int)); + +static int parse_pkt PARAMS ((unsigned char *, GPKTHDR *, char *)); + +static int writen PARAMS ((int, char *, int)); + +/* Private globals. */ + +/* We talk to the NetROM over these sockets. */ + +static int nrom_load_sock = -1; +static int nrom_targ_sock = -1; +static int nrom_ctrl_sock = -1; + +/* For binding to the socket we ned a sockaddr_in structure. */ + +static struct sockaddr_in nrom_sin; + +/* The IP Address of the NetROM is needed so we know who to talk to. */ + +static unsigned long nrom_ipaddr = 0; + +static int load_port = DEFAULT_NETROM_LOAD_PORT; +static int target_port = DEFAULT_NETROM_TARGET_PORT; +static int control_port = DEFAULT_NETROM_CONTROL_PORT; + +static int nrom_filetype = BINARY_FTYPE; + +static unsigned char host_seq_num = 0; + +static char hexchars[] = "0123456789abcdef"; + +static char freadbuf[READ_BUF_SIZE]; + +static char readbuf[NROM_BUF_SIZE]; +static int bufdata = 0; +static int bufindex = 0; + +static char workbuf[NROM_BUF_SIZE]; +static char sendbuf[NROM_BUF_SIZE]; + +/* Forward data declaration. */ + +extern struct target_ops nrom_ops; + +/* This routine builds a packet to send to gdb running on the host. */ + +static void +build_pkt (cmd, data, datalen, pkt, addr, len, seq) + int cmd; + unsigned char *data; + long datalen; + unsigned char *pkt; + unsigned long addr; + unsigned long len; + int seq; +{ + GPKTHDR phdr; + char *dptr; + char *pktptr; + unsigned char csum; + int plen; + + phdr.csum = 0; + phdr.len = sizeof(GPKTHDR) + datalen; + phdr.seq_num = seq; + phdr.cmd = cmd; + phdr.pad[0] = phdr.pad[1] = phdr.pad[2] = 0; + phdr.addr = addr; + phdr.datalen = len; + /* Convert packet header to ASCII. */ + dptr = mem2hex ((char *) &phdr, pkt, sizeof(GPKTHDR)); + + /* Calculate pkt length now that it is converted. */ + plen = (int) ((unsigned long)dptr - (unsigned long)pkt) + datalen; + /* Put data in packet. */ + if (datalen > 0) + memcpy (dptr, data, datalen); + + /* Compute checksum. For computing checksum we skip first two bytes + since this is where the checksum will go. */ + pktptr = pkt + 2; + csum = compute_csum (pktptr, plen - 2); + *pkt++ = hexchars[csum >> 4]; + *pkt++ = hexchars[csum % 16]; + dptr += datalen; + *dptr = '\0'; +} + +static int +compute_csum (data, len) + unsigned char *data; + int len; +{ + unsigned char csum; + + csum = 0; + while (len > 0) + { + csum += *data++; + --len; + } + return csum; +} + +#if 0 /* for debugging, if anyone cares */ +static void +dump_pkt (hdr, data) + GPKTHDR *hdr; + unsigned char *data; +{ + int i; + + printf_filtered ("PACKET: csum = %x,seq = %d,len = %d\n",hdr->csum,hdr->seq_num, + hdr->len); + + printf_filtered ("cmd = %s,addr = %x, datalen = %d\n", GCMDTYPE[hdr->cmd], + hdr->addr,hdr->datalen); + if (hdr->datalen) + { + for (i = 0; i < hdr->datalen * 2; i++) + printf_filtered ("%x",data[i]); + printf_filtered ("\n"); + } +} +#endif + +static int +get_seq_number() +{ + return host_seq_num++; +} + +int +hex (ch) + int ch; +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if((ch >= 'A') && (ch <= 'F')) + return ((ch - 'A') + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + return 0; +} + +/* Convert the hex array pointed to by buf into binary to be placed in mem + return a pointer to the character AFTER the last byte written. */ + +static char* +hex2mem(buf, mem, count) + char* buf; + char* mem; + int count; +{ + int i; + unsigned char ch; + + for (i = 0; i < count; i++) + { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + *mem++ = ch; + } + return mem; +} + +/* Convert the memory pointed to by mem into hex, placing result in buf + return a pointer to the last char put in buf (null) */ + +static char * +mem2hex (mem, buf, count) + char* mem; + char* buf; + int count; +{ + int i; + unsigned char ch; + + for (i = 0; i < count; i++) + { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return buf; +} + +static int +nrom_control_send (s, nbytes) + char *s; + int nbytes; +{ + long len; + char buf[10]; + + /* clear leading characters */ + /* FIXME: The ioctl uses here seem bogus to me. -sts */ + len = 1; + while (len > 0) + { + if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0) + { + perror ("nrom_control_send ioctl"); + return (-1); + } + if (len > 0) + { + if (read (nrom_ctrl_sock, buf, 1) < 0) + { + perror ("nrom_control_send read"); + return (-1); + } + } + } + + if (remote_debug) + printf_filtered ("nrom_control_send: sending '%s' (%d bytes) to NetROM\n", + s, nbytes); + + if (writen (nrom_ctrl_sock, s, nbytes) < 0) + { + perror ("nrom_control_send"); + return (-1); + } + + /* clear trailing characters */ + len = 1; + while (len > 0) + { + if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0) + { + perror ("nrom_control_send ioctl"); + return (-1); + } + if (len > 0) + { + if (read (nrom_ctrl_sock, buf, 1) < 0) + { + perror ("nrom_control_send read"); + return (-1); + } + } + } + return 0; +} + +static void +nrom_kill () +{ +} + +/* Download a file specified in ARGS to the netROM. */ + +static void +nrom_load (args, fromtty) + char *args; + int fromtty; +{ + int fd, rd_amt, fsize; + struct sockaddr_in sin; + bfd *pbfd; + asection *section; + char *downloadstring = "download 0\n"; + + /* Tell the netrom to get ready to download. */ + if (nrom_control_send (downloadstring, strlen (downloadstring)) < 0) + error ("nrom_load: control_send() of `%s' failed", downloadstring); + + /* Wait for the download daemon to start up. */ + sleep (1); + + nrom_load_sock = socket (AF_INET, SOCK_STREAM, 0); + if (nrom_load_sock == -1) + error ("Could not create download socket, error %d", errno); + + memset (&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_family = AF_INET; + sin.sin_port = htons (load_port); + sin.sin_addr.s_addr = htonl (nrom_ipaddr); + + if (connect (nrom_load_sock, &sin, sizeof(sin)) == -1) + error ("Connect failed, error %d", errno); + + pbfd = bfd_openr (args, 0); + + if (pbfd) + { + if (!bfd_check_format (pbfd, bfd_object)) + error ("\"%s\": not in executable format: %s", + args, bfd_errmsg (bfd_get_error ())); + + for (section = pbfd->sections; section; section = section->next) + { + if (bfd_get_section_flags (pbfd, section) & SEC_ALLOC) + { + bfd_vma section_address; + unsigned long section_size; + const char *section_name; + + section_name = bfd_get_section_name (pbfd, section); + section_address = bfd_get_section_vma (pbfd, section); + section_size = bfd_section_size (pbfd, section); + + if (bfd_get_section_flags (pbfd, section) & SEC_LOAD) + { + file_ptr fptr; + + printf_filtered ("[Loading section %s at %x (%d bytes)]\n", + section_name, section_address, + section_size); + + fptr = 0; + + while (section_size > 0) + { + char buffer[1024]; + int count; + + count = min (section_size, 1024); + + bfd_get_section_contents (pbfd, section, buffer, fptr, + count); + + writen (nrom_load_sock, buffer, count); + section_address += count; + fptr += count; + section_size -= count; + } + } + else /* BSS and such */ + { + printf_filtered ("[section %s: not loading]\n", + section_name); + } + } + } + } + else + error ("\"%s\": Could not open", args); + + close (nrom_load_sock); +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ + +static void +nrom_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ +} + +/* Open a connection to the remote NetROM devices. */ + +static void +nrom_open (name, from_tty) + char *name; + int from_tty; +{ + int errn; + + if (name) + nrom_set_ipaddr (name, from_tty); + else if (nrom_ipaddr == 0) + error ( +"To open a NetROM connection, you must specify the hostname\n\ +or IP address of the NetROM device you wish to use."); + + push_target (&nrom_ops); + + /* Create the socket used for talking with the target. */ + nrom_targ_sock = socket (AF_INET, SOCK_STREAM, 0); + + /* Bind the socket. */ + nrom_sin.sin_family = AF_INET; + nrom_sin.sin_port = htons (target_port); + nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr); + + /* Connect to the remote host. */ + if (connect (nrom_targ_sock, &nrom_sin, sizeof(nrom_sin)) == -1) + error ("Connect failed, error %d", errno); + + /* Create the socket used for talking with the debugger services. */ + nrom_ctrl_sock = socket (AF_INET, SOCK_STREAM, 0); + + /* Bind the socket. */ + nrom_sin.sin_family = AF_INET; + nrom_sin.sin_port = htons (control_port); + nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr); + + /* Connect to the remote host. */ + if (connect (nrom_ctrl_sock, &nrom_sin, sizeof(nrom_sin)) == -1) + { + errn = errno; + close (nrom_targ_sock); + error ("Connect control_socket failed, error %d", errn); + } + + if (from_tty) + { + unsigned char *i; + + printf_filtered ("Connected to NetROM device \"%s\"", name); + i = (unsigned char *) &nrom_ipaddr; + printf_filtered (" (%d.%d.%d.%d)\n", + UC(i[0]), UC(i[1]), UC(i[2]), UC(i[3])); + } +} + +static int +nrom_can_run () +{ + return 1; +} + +/* Close out all files and local state before this target loses control. */ + +static void +nrom_close (quitting) + int quitting; +{ +} + +/* Attach to the target that is already loaded and possibly running */ + +static void +nrom_attach (args, from_tty) + char *args; + int from_tty; +{ + int nwaiting; + char buf[10]; + + if (from_tty) + printf_filtered ("Attaching to NetROM\n"); + + /* clear any pending data on the socket */ + printf_filtered ("Waiting for pending data to arrive... "); + fflush(stdout); + sleep(1); + printf_filtered ("that's long enough!\n"); + while (1) + { + if (ioctl(nrom_targ_sock, FIONREAD, &nwaiting) != 0) + { + /* couldn't determine data left */ + perror("nrom_attach: ioctl FIONREAD"); + break; + } + else if (nwaiting > 0) + { + /* flush incoming data */ + while (nwaiting != 0) + { + if (read (nrom_targ_sock, buf, 1) < 0) + { + perror("nrom_attach: read"); + exit(1); + } + if (remote_debug > 2) + putc(buf[0], stdout); + nwaiting--; + } + } + else + { + /* no more data */ + break; + } + } + printf_filtered ("Pending data removed\n"); + + /* We will get a task spawn event immediately. */ + send_query_cmd (); + target_has_execution = 1; +/* + start_remote(); +*/ +} + +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ + +static void +nrom_detach (args, from_tty) + char *args; + int from_tty; +{ + pop_target (); + if (from_tty) + printf_filtered ("Ending remote debugging\n"); +} + +/* Tell the remote machine to resume. */ + +static void +nrom_prepare_to_store() +{ +} + +static void +nrom_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + if (step) + send_pkt (GDB_STEP, NULL, 0, 0, 0); + else + send_pkt (GDB_CONTINUE, NULL, 0, 0, 0); +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +static int +nrom_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + static char pkt[NROM_BUF_SIZE], inbuf[NROM_BUF_SIZE]; + GPKTHDR phdr; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + while (1) + { + if (read_pkt (pkt) == -1) + continue; + + if (parse_pkt (pkt, &phdr, inbuf) < 0) + { + if (remote_debug) + printf_filtered ("Bad packet in nrom_wait\n"); + send_query_cmd (); + continue; + } + + /* Got good packet. Verify command is right. */ + if (phdr.cmd != GDB_STATUS) + { + /* Wrong response. Resend command. */ + send_query_cmd (); + continue; + } + /* Packet is fine. Exit loop. */ + return inferior_pid; + } +} + +/* Read the remote registers. */ + +static void +nrom_fetch_registers (regno) + int regno; +{ + char buf[NROM_BUF_SIZE]; + char regs[REGISTER_BYTES]; + int i; + +#ifdef DEBUG + printf_filtered ("reg no is %d\n",regno); +#endif + + nrom_send (GDB_READ_REGS, NULL, 0, -1, 0, buf); + memcpy (regs, buf, REGISTER_BYTES); + for (i = 0; i < NUM_REGS; i++) + supply_register (i, ®s[REGISTER_BYTE(i)]); +#ifdef NO_SINGLE_REG + nrom_send (GDB_READ_REGS, NULL, 0, regno, 0, buf); + if (regno != -1) + supply_register(regno,buf); + else + { + memcpy (regs, buf, REGISTER_BYTES); + for (i = 0; i < NUM_REGS; i++) + supply_register (i, ®s[REGISTER_BYTE(i)]); + } +#endif +} + +static void +nrom_send (cmd, data, datalen, addr, len, resp) + int cmd; + char *data; + int datalen; + long addr; + long len; + char *resp; +{ + GPKTHDR phdr; + char inbuf[NROM_BUF_SIZE]; + + while (1) + { + while (send_pkt (cmd, data, datalen, addr, len) < 0) + ; + if (read_pkt (inbuf) != -1) + { + if (parse_pkt (inbuf, &phdr, resp) < 0) + continue; + if (phdr.cmd != GDB_NACK) + return; + } + } +} + +static void +nrom_set_filetype (args, fromtty) + char *args; + int fromtty; +{ + if (args[0] == 'b') + nrom_filetype = BINARY_FTYPE; + else if (args[0] == 'm') + nrom_filetype = MOTO_SREC; + else if (args[0] == 'i') + nrom_filetype = INTEL_HEX; + else + printf_filtered ("Unknown file type\n"); +} + +static void +nrom_set_ipaddr (args, fromtty) + char *args; + int fromtty; +{ + struct hostent *h; + char buf[10]; + int i,j,val; + unsigned long newip = 0; + + /* First do a check to see if they typed in a hostname. */ + if (!(*args)) + error ("Please enter a hostname or IP address"); + + h = gethostbyname (args); + if (h) + { + /* It is a hostname. We just need the ipaddress. */ + memcpy (&nrom_ipaddr, h->h_addr, h->h_length); + } + else + { + /* Better be in decimal dot notation,ie. xx.xx.xx.xx */ + if (isdigit (args[0]) && strchr (args, '.')) + { + j = 4; + while (j) + { + memset (buf, 0, 10); + i = 0; + while((*args) && (*args != '.')) + { + buf[i] = *args++; + i++; + } + if (i) + { + val = (int) strtol (buf, NULL, 10); + + if (val > 255) + error ("Invalid IP address"); + + j--; + newip |= val << (8 * j); + args++; + } + } + } + else + { + error ("Invalid host name/address"); + } + nrom_ipaddr = newip; + } +} + +static void +nrom_set_load_port (args, fromtty) + char *args; + int fromtty; +{ + load_port = (int) strtol (args, NULL, 10); +} + +static void +nrom_set_target_port (args, from_tty) + char *args; + int from_tty; +{ + target_port = (int) strtol (args, NULL, 10); +} + +static void +nrom_set_control_port (args, fromtty) + char *args; + int fromtty; +{ + control_port = (int) strtol (args, NULL, 10); +} + +static void +nrom_show_status (args,from_tty) + char *args; + int from_tty; +{ + unsigned char *i; + + i = (unsigned char *)&nrom_ipaddr; + + printf_filtered ("NetROM target port is %d\n", target_port); + printf_filtered ("NetROM download port is %d\n", load_port); + printf_filtered ("NetROM debug control port is %d\n", control_port); + + printf_filtered ("NetROM IP Address is %d.%d.%d.%d\n", + UC(i[0]), UC(i[1]), UC(i[2]), UC(i[3])); + if (nrom_filetype == BINARY_FTYPE) + printf_filtered ("download filetype is binary\n"); + else if (nrom_filetype == MOTO_SREC) + printf_filtered ("download filetype is moto-srec\n"); + else if (nrom_filetype == INTEL_HEX) + printf_filtered ("download filetype is intel-hex\n"); +} + +/* Pass arguments directly to the NetROM. */ + +static void +nrom_passthru (args, fromtty) + char *args; + int fromtty; +{ + char buf[1024]; + + sprintf(buf, "%s\n", args); + if (nrom_control_send (buf, strlen (buf)) < 0) + error ("nrom_reset: control_send() of `%s'failed", args); +} + +static void +nrom_store_registers (regno) +int regno; +{ + char buf[NROM_BUF_SIZE]; + int i; + char *p; + + p = buf; + for (i = 0; i < REGISTER_BYTES; i++) + { + *p++ = tohex ((registers[i] >> 4) & 0xf); + *p++ = tohex (registers[i] & 0xf); + } + *p = '\0'; + nrom_send (GDB_WRITE_REGS, buf, REGISTER_BYTES * 2, 0, REGISTER_BYTES * 2, + buf); +} + +static int +nrom_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + if (write) + return nrom_write_inferior_memory (memaddr, myaddr, len); + else + return nrom_read_inferior_memory (memaddr, myaddr, len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. */ + +static int +nrom_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[NROM_BUF_SIZE],obuf[NROM_BUF_SIZE]; + int i; + char *p; + + p = obuf; + for (i = 0; i < len; i++) + { + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); + } + *p = '\0'; + nrom_send (GDB_WRITE_MEM, obuf, len * 2, memaddr, len, buf); + + return len; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ + +static int +nrom_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[NROM_BUF_SIZE]; + + nrom_send (GDB_READ_MEM, NULL, 0, memaddr, len, buf); + memcpy (myaddr, buf, len); + return len; +} + +static void +nrom_files_info (ignore) + struct target_ops *ignore; +{ +} + +static void +nrom_mourn() +{ + unpush_target (&nrom_ops); + generic_mourn_inferior (); +} + +/* Convert a packet into its parts and verify check sum. */ + +static int +parse_pkt (pkt, hdr, data) + unsigned char *pkt; + GPKTHDR *hdr; + char *data; +{ + unsigned char xcsum; + unsigned char *dptr; + + /* Build packet header from received data. */ + hex2mem (pkt, (char *) hdr, sizeof(GPKTHDR)); + if (remote_debug > 1) + { + printf_filtered ("Packet received: csum = %x,seq number = %x,len = %d\n", + hdr->csum,hdr->seq_num,hdr->len); + printf_filtered ("cmd = %x,addr = %x,datalen = %d\n", + hdr->cmd,hdr->addr,hdr->datalen); + } + /* Skip first two bytes of packet when computing checksum. */ + dptr = (sizeof(GPKTHDR) * 2) + pkt; + pkt += 2; + if (remote_debug > 1) + { + printf_filtered ("Computing checksum over pkt %s\n",pkt); + printf_filtered ("Of length %d\n",strlen(pkt)); + } + xcsum = compute_csum (pkt, strlen (pkt)); + if (xcsum != hdr->csum) + { + if (remote_debug) + printf_filtered ("Checksum failure: computed %x, received %x\n",xcsum, + hdr->csum); + return (-1); + } + + /* Copy data portion to callers data buffer converting from ASCII + to data as we go. */ + hex2mem (dptr, data, hdr->datalen); + return 0; +} + +static int +read_pkt (pkt) + char *pkt; +{ + int n, tries; + struct sockaddr_in from; + int from_len = sizeof(from); + int gotstart; + int total_len; + char *p; + + p = pkt; + total_len = 0; + gotstart = 0; + + while (1) + { + /* Don't let us get wedged if the target is losing. */ + QUIT; + + if (bufdata == 0) + { + bufindex = 0; + n = NROM_BUF_SIZE; + /* Perform read on socket. This will wait. */ + bufdata = recvfrom (nrom_targ_sock, readbuf, n, 0, &from, &from_len); + if (bufdata < 0) + { + printf_filtered ("Error on socket read of %d\n",errno); + return (-1); + } + if (remote_debug > 2) + { + readbuf[bufdata] = '\0'; + printf_filtered ("Received %d bytes. Data is %s\n", + bufdata, readbuf); + } + } + + /* skip stuff between packets */ + while (gotstart == 0 && bufdata != 0 + && readbuf[bufindex] != GDB_START_DELIMITER) + { + bufdata--; + bufindex++; + } + + /* look for a start if we haven't seen one */ + if (gotstart == 0 && bufdata != 0 + && readbuf[bufindex] == GDB_START_DELIMITER) + { + gotstart = 1; + bufindex++; + bufdata--; + } + + /* copy packet data */ + if (gotstart != 0) + { + while (bufdata && readbuf[bufindex] != GDB_END_DELIMITER) + { + *p = readbuf[bufindex]; + p++; + bufdata--; + bufindex++; + total_len++; + if (total_len > NROM_BUF_SIZE) + { + error ("read_pkt: packet length exceeds %d\n", + NROM_BUF_SIZE); + return (-1); + } + } + *p = '\0'; + if (remote_debug > 2) + printf_filtered ("Packet is '%s'\n", pkt); + } + + /* Make sure this is the end of the packet. */ + if (gotstart != 0 && bufdata != 0 + && readbuf[bufindex] == GDB_END_DELIMITER) + { + gotstart = 0; + bufindex++; + bufdata--; + /* Ensure that the packet is terminated. */ + *p = '\0'; + if (remote_debug > 2) + printf_filtered ("Returning '%s'\n", pkt); + return 0; + } + } +} + +static void +send_query_cmd () +{ + while (send_pkt (GDB_QUERY_CMD, NULL, 0, 0, 0) < 0) + ; +} + +static int +send_pkt (cmd, data, datalen, addr, len) + int cmd; + char *data; + int datalen; + long addr; + int len; +{ + char c[2]; + unsigned char seq; + struct sockaddr_in mysin; + int send_cnt; + + while (1) + { + /* Get a sequence number for this packet. */ + seq = get_seq_number (); + /* Build the packet. */ + build_pkt (cmd, data, datalen, workbuf, addr, len, seq); + /* Put delimiters around the pkt. */ + memset (sendbuf, 0, NROM_BUF_SIZE); + sendbuf[0] = GDB_START_DELIMITER; + strcat (sendbuf, workbuf); + c[0] = GDB_END_DELIMITER; + c[1] = '\0'; + strcat (sendbuf, c); + + /* Send the packet out on our socket. */ + if (remote_debug > 1) + printf_filtered ("Sending pkt: %s\n", sendbuf); + mysin.sin_family = AF_INET; + mysin.sin_port = target_port; + mysin.sin_addr.S_un.S_addr = nrom_ipaddr; + + send_cnt = 0; + while (send_cnt < MAX_SEND_ATTEMPTS) + { + if (sendto (nrom_targ_sock, sendbuf, strlen(sendbuf), 0, &mysin, + sizeof(struct sockaddr_in)) < 0) + { + printf_filtered ("sendto error of %d\n", errno); + send_cnt++; + } + else + break; + } + if (send_cnt >= MAX_SEND_ATTEMPTS) + { + printf_filtered ("Socket send failed after %d tries\n", + MAX_SEND_ATTEMPTS); + return (-1); + } + return 1; + } +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* snatched from Stevens, pp279+ */ + +int +writen (sock, ptr, nbytes) + int sock; + char *ptr; + int nbytes; +{ + int nleft, nwritten; + char *buf = ptr; + + nleft = nbytes; + while (nleft > 0) + { + nwritten = write (sock, buf, nleft); + if (nwritten <= 0) + return nwritten; + nleft -= nwritten; + buf += nwritten; + } + return (nbytes - nleft); +} + +/* Define the target vector. */ + +struct target_ops nrom_ops = { + "nrom", /* to_shortname */ + "Remote XDI `NetROM' target", /* to_longname */ + "Remote debug using a NetROM over Ethernet", + nrom_open, /* to_open */ + nrom_close, + nrom_attach, + nrom_detach, + nrom_resume, + nrom_wait, /* to_wait */ + nrom_fetch_registers, /* to_fetch_registers */ + nrom_store_registers, /* to_store_registers */ + nrom_prepare_to_store, /* to_prepare_to_store */ + nrom_xfer_inferior_memory, /* to_xfer_memory */ + nrom_files_info, /* to_files_info */ + NULL, /* to_insert_breakpoint */ + NULL, /* to_remove_breakpoint */ + NULL, + NULL, + NULL, + NULL, + NULL, + nrom_kill, + nrom_load, + NULL, + nrom_create_inferior, /* to_create_inferior */ + nrom_mourn, + nrom_can_run, + 0, /* to_notice_signals */ + 0, + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, + 1, + 1, + 1, + 0, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_nrom () +{ + add_target (&nrom_ops); + + /* Add some commands for helpers. */ + add_cmd ("nrom_ipaddr", no_class, nrom_set_ipaddr, + "Set the IP Address of the NetROM\n", + &setlist); + add_cmd ("target_port", no_class, nrom_set_target_port, + "Set the Port to use for NetROM target communication\n", + &setlist); + add_cmd ("load_port", no_class, nrom_set_load_port, + "Set the Port to use for NetROM downloads\n", + &setlist); + add_cmd ("control_port", no_class, nrom_set_control_port, + "Set the Port to use for NetROM debugger services\n", + &setlist); + add_cmd ("nrom_filetype", no_class, nrom_set_filetype, + "Set the filetype to use on NetROM downloads", + &setlist); + + add_cmd ("nrom", no_class, nrom_show_status, + "Show the current NetROM status\n", + &showlist); + + add_cmd ("nrom", no_class, nrom_passthru, + "Pass arguments as command to NetROM", + &cmdlist); +} |