/* 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 #include "inferior.h" #include "wait.h" #include "value.h" #include #include #include #include #include #include #include #include #include #include #include #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); }