diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 073b293d79..769a0413d7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +Thu Feb 2 19:02:45 1995 Rob Savoye + + * array-rom.c: Remove the non GDB remote protocol config stuff. + + * monitor.c: All reading/writing functions for memory and + registers work. + Thu Feb 2 16:11:04 1995 Kung Hsu * config/arc/.Sanitize: New file for config/arc directory. diff --git a/gdb/array-rom.c b/gdb/array-rom.c index ccf29bdf80..dae6089b69 100644 --- a/gdb/array-rom.c +++ b/gdb/array-rom.c @@ -26,7 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ extern int baud_rate; -void array_open(); void gdb_open(); void monitor_open(); @@ -36,6 +35,9 @@ void monitor_open(); * different strings than GDB does, and doesn't support all the * registers either. So, typing "info reg sp" becomes a "r30". */ +static char *array_regnames[] = REGISTER_NAMES; + +#if 0 static char *array_regnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", @@ -55,6 +57,7 @@ static char *array_regnames[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }; +#endif /* * Define the monitor command strings. Since these are passed directly @@ -64,90 +67,6 @@ static char *array_regnames[] = { struct target_ops array_ops = { "array", - "Array Tech's custom debug monitor for their LSI based RAID controller board", - "Debug on an Array Tech RAID controller.\n\ -Specify the serial device it is connected to (e.g. /dev/ttya).", - array_open, - monitor_close, - monitor_attach, - monitor_detach, - monitor_resume, - monitor_wait, - monitor_fetch_register, - monitor_store_register, - monitor_prepare_to_store, - monitor_xfer_inferior_memory, - monitor_files_info, - monitor_insert_breakpoint, - monitor_remove_breakpoint, /* Breakpoints */ - 0, - 0, - 0, - 0, - 0, /* Terminal handling */ - monitor_kill, - monitor_load, /* load */ - 0, /* lookup_symbol */ - monitor_create_inferior, - monitor_mourn_inferior, - 0, /* can_run */ - 0, /* notice_signals */ - 0, /* to_stop */ - process_stratum, - 0, /* next */ - 1, - 1, - 1, - 1, - 1, /* all mem, mem, stack, regs, exec */ - 0, - 0, /* Section pointers */ - OPS_MAGIC, /* Always the last thing */ -}; - -struct monitor_ops array_cmds = { - 1, /* 1 for ASCII, 0 for binary */ - "\003.\r\n", /* monitor init string */ - "go %x\n", /* execute or usually GO command */ - "c\n", /* continue command */ - "s\n", /* single step */ - "brk %x\n", /* set a breakpoint */ - "unbrk %x\n", /* clear a breakpoint */ - 0, /* 0 for number, 1 for address */ - { - "p %x %x\n", /* set memory */ - "", /* delimiter */ - "", /* the result */ - }, - { - "g %x %x\n", /* get memory */ - "", /* delimiter */ - "", /* the result */ - }, - { - "p %s %x\n", /* set a register */ - "", /* delimiter between registers */ - "", /* the result */ - }, - { - "g %s\n", /* get a register */ - "", /* delimiter between registers */ - "", /* the result */ - }, - "sload -a tty(0)\r\n", /* download command */ - ">> ", /* monitor command prompt */ - "", /* end-of-command delimitor */ - "", /* optional command terminator */ - &array_ops, /* target operations */ - "none,srec,default", /* load types */ - "none", /* load protocols */ - "4800", /* supported baud rates */ - 2, /* number of stop bits */ - array_regnames /* registers names */ -}; - -struct target_ops gdb_ops = { - "gdb", "Debug using the standard GDB remote protocol for the Array Tech target.", "Debug using the standard GDB remote protocol for the Array Tech target.\n\ Specify the serial device it is connected to (e.g. /dev/ttya).", @@ -190,7 +109,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).", OPS_MAGIC, /* Always the last thing */ }; -struct monitor_ops gdb_cmds = { +struct monitor_ops array_cmds = { 0, /* 1 for ASCII, 0 for binary */ "$?#b8+\n", /* monitor init string */ "go %x", /* execute or usually GO command */ @@ -223,7 +142,7 @@ struct monitor_ops gdb_cmds = { ">> ", /* monitor command prompt */ "", /* end-of-command delimitor */ "", /* optional command terminator */ - &gdb_ops, /* target operations */ + &array_ops, /* target operations */ "none,srec,default", /* load types */ "none", /* load protocols */ "4800", /* supported baud rates */ @@ -235,23 +154,6 @@ void gdb_open(args, from_tty) char *args; int from_tty; -{ - target_preopen(from_tty); - push_target (&gdb_ops); - push_monitor (&gdb_cmds); - monitor_open (args, "gdb", from_tty); -} - -void -_initialize_gdb_proto () -{ - add_target (&gdb_ops); -} - -void -array_open(args, from_tty) - char *args; - int from_tty; { target_preopen(from_tty); push_target (&array_ops); @@ -263,12 +165,9 @@ void _initialize_array () { add_target (&array_ops); - - /* this is the default, since it's the only baud rate supported by the hardware */ baud_rate = 4800; } - diff --git a/gdb/monitor.c b/gdb/monitor.c index 130bd28377..7c6e3da264 100644 --- a/gdb/monitor.c +++ b/gdb/monitor.c @@ -59,6 +59,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define CSTOPB 0x00000040 #endif +static const char hexchars[]="0123456789abcdef"; +static char *hex2mem(); + #define SWAP_TARGET_AND_HOST(buffer,len) \ do \ { \ @@ -77,9 +80,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ } \ while (0) - -extern void make_xmodem_packet(); -extern void print_xmodem_packet(); +static void make_xmodem_packet(); +static void print_xmodem_packet(); +static void make_gdb_packet(); +static unsigned long ascii2hexword(); +static char *hexword2ascii(); +static int tohex(); +static int to_hex(); +static int from_hex(); struct monitor_ops *current_monitor; extern struct cmd_list_element *setlist; @@ -96,7 +104,13 @@ static int hashmark; /* flag set by "set hash" */ FILE *log_file; #endif -static int timeout = 24; +static int timeout = 30; +/* Having this larger than 400 causes us to be incompatible with m68k-stub.c + and i386-stub.c. Normally, no one would notice because it only matters + for writing large chunks of memory (e.g. in downloads). Also, this needs + to be more than 400 if required to hold the registers (see below, where + we round it up based on REGISTER_BYTES). */ +#define PBUFSIZ 400 /* * Descriptor for I/O to remote machine. Initialize it to NULL so that @@ -209,7 +223,7 @@ printf_monitor(va_alist) { va_list args; char *pattern; - char buf[200]; + char buf[PBUFSIZ]; int i; va_start(args); @@ -220,6 +234,8 @@ printf_monitor(va_alist) debuglogs (1, "printf_monitor(), Sending: \"%s\".", buf); + if (strlen(buf) > PBUFSIZ) + error ("printf_monitor(): string too long"); if (SERIAL_WRITE(monitor_desc, buf, strlen(buf))) fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno)); } @@ -251,8 +267,8 @@ debuglogs(va_alist) { va_list args; char *pattern, *p; - char buf[200]; - char newbuf[300]; + unsigned char buf[PBUFSIZ]; + char newbuf[PBUFSIZ]; int level, i; va_start(args); @@ -269,7 +285,9 @@ debuglogs(va_alist) /* convert some characters so it'll look right in the log */ p = newbuf; - for (i=0 ; buf[i] != '\0'; i++) { + for (i = 0 ; buf[i] != '\0'; i++) { + if (i > PBUFSIZ) + error ("Debug message too long"); switch (buf[i]) { case '\n': /* newlines */ *p++ = '\\'; @@ -300,7 +318,12 @@ debuglogs(va_alist) *p++ = buf[i] + 'A'; continue; } - } + if (buf[i] >= 128) { /* modify control characters */ + *p++ = '!'; + *p++ = buf[i] + 'A'; + continue; + } + } *p = '\0'; /* terminate the string */ if (sr_get_debug() > level) @@ -326,8 +349,10 @@ readchar(timeout) c = SERIAL_READCHAR(monitor_desc, timeout); - if (sr_get_debug() > 5) + if (sr_get_debug() > 5) { putchar(c & 0x7f); + debuglogs (5, "readchar: timeout = %d\n", timeout); + } #ifdef LOG_FILE if (isascii (c)) @@ -539,8 +564,6 @@ monitor_create_inferior (execfile, args, env) entry_pt = (int) bfd_get_start_address (exec_bfd); - debuglogs (3, "create_inferior(exexfile=%s, args=%s, env=%s)", execfile, args, env); - /* The "process" (board) is already stopped awaiting our commands, and the program is already downloaded. We just set its PC and go. */ @@ -599,7 +622,7 @@ monitor_open(args, name, from_tty) SERIAL_RAW(monitor_desc); -#ifndef __GO32__ +#if !defined(__GO32__) && !defined(GDB_TARGET_IS_PA_ELF) /* some systems only work with 2 stop bits */ if (STOPBITS == 2) { temptempio = (TERMINAL *)SERIAL_GET_TTY_STATE(monitor_desc); @@ -607,6 +630,7 @@ monitor_open(args, name, from_tty) temptempio->sg_cflag |= baud_rate | CSTOPB; #else temptempio->c_cflag |= baud_rate | CSTOPB; +/*** temptempio->c_lflag |= ~0x00000008; turn off echo ***/ #endif SERIAL_SET_TTY_STATE(monitor_desc, temptempio); debuglogs (4, "Set serial port to 2 stop bits"); @@ -622,13 +646,26 @@ monitor_open(args, name, from_tty) fprintf_filtered (log_file, "Remote target %s connected to %s\n\n", TARGET_NAME, dev_name); #endif - /* wake up the monitor and see if it's alive */ - printf_monitor(INIT_CMD); - expect_prompt(1); /* See if we get a prompt */ + /* see if the target is alive. For a ROM monitor, we can just try to force the + prompt to print a few times. FOr the GDB remote protocol, the application + being debugged is sitting at a breakpoint and waiting for GDB to initialize + the connection. We force it to give us an empty packet to see if it's alive. + */ + if (GDBPROTO) { + debuglogs (3, "Trying to ACK the target's debug stub"); + printf_monitor (INIT_CMD); /* ask for the last signal */ + expect ("$S05#b8",0); /* look for a response */ + printf_monitor ("+"); /* ask for the last signal */ + expect_prompt(1); /* See if we get a prompt */ + } else { + /* wake up the monitor and see if it's alive */ + printf_monitor(INIT_CMD); + expect_prompt(1); /* See if we get a prompt */ - /* try again to be sure */ - printf_monitor(INIT_CMD); - expect_prompt(1); /* See if we get a prompt */ + /* try again to be sure */ + printf_monitor(INIT_CMD); + expect_prompt(1); /* See if we get a prompt */ + } if (from_tty) printf("Remote target %s connected to %s\n", TARGET_NAME, dev_name); @@ -773,15 +810,39 @@ get_reg_name (regno) * block regs. */ void -monitor_fetch_registers () +monitor_fetch_registers (ignored) + int ignored; { - int regno; + int regno, i; + char *p; + unsigned char packet[PBUFSIZ]; + char regs[REGISTER_BYTES]; - /* yeah yeah, i know this is horribly inefficient. but it isn't done - very often... i'll clean it up later. */ + debuglogs (1, "monitor_fetch_registers (ignored=%d)\n", ignored); - for (regno = 0; regno <= PC_REGNUM; regno++) - monitor_fetch_register(regno); + memset (packet, 0, PBUFSIZ); + if (GDBPROTO) { + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + make_gdb_packet (packet, "g"); + if (monitor_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (monitor_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + /* FIXME: read bytes from packet */ + debuglogs (4, "monitor_fetch_registers: Got a \"%s\" back\n", packet); + for (regno = 0; regno <= PC_REGNUM+4; regno++) { + /* supply register stores in target byte order, so swap here */ + /* FIXME: convert from ASCII hex to raw bytes */ + i = ascii2hexword (packet + (regno * 8)); + debuglogs (5, "Adding register %d = %x\n", regno, i); + SWAP_TARGET_AND_HOST (&i, 4); + supply_register (regno, (char *)&i); + } + } else { + for (regno = 0; regno <= PC_REGNUM; regno++) + monitor_fetch_register(regno); + } } /* @@ -824,17 +885,48 @@ monitor_fetch_register (regno) return; } -/* Store the remote registers from the contents of the block REGS. */ - +/* + * monitor_store_registers - store the remote registers. + */ void -monitor_store_registers () +monitor_store_registers (ignored) + int ignored; { int regno; - + unsigned long i; + char packet[PBUFSIZ]; + char buf[PBUFSIZ]; + char num[9]; + debuglogs (1, "monitor_store_registers()"); - for (regno = 0; regno <= PC_REGNUM; regno++) - monitor_store_register(regno); + if (GDBPROTO) { + memset (packet, 0, PBUFSIZ); + memset (buf, 0, PBUFSIZ); + buf[0] = 'G'; + + /* Unimplemented registers read as all bits zero. */ + /* FIXME: read bytes from packet */ + for (regno = 0; regno < 41; regno++) { /* FIXME */ + /* supply register stores in target byte order, so swap here */ + /* FIXME: convert from ASCII hex to raw bytes */ + i = (unsigned long)read_register (regno); +#if 0 + SWAP_TARGET_AND_HOST (&i, 4); +#endif + hexword2ascii (num, i); + strcpy (buf+(regno * 8)+1, num); + } + *(buf + (regno * 8) + 2) = 0; + make_gdb_packet (packet, buf); + if (monitor_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (monitor_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + } else { + for (regno = 0; regno <= PC_REGNUM; regno++) + monitor_store_register(regno); + } registers_changed (); } @@ -910,26 +1002,62 @@ monitor_write_inferior_memory (memaddr, myaddr, len) unsigned char *myaddr; int len; { - int i; - char buf[10]; - + unsigned long i; + int j; + char packet[PBUFSIZ]; + char buf[PBUFSIZ]; + char num[9]; + char *p; + debuglogs (1, "monitor_write_inferior_memory (memaddr=0x%x, myaddr=0x%x, len=%d)", memaddr, myaddr, len); + memset (buf, '\0', PBUFSIZ); /* this also sets the string terminator */ + p = buf; - for (i = 0; i < len; i++) { - printf_monitor (ROMCMD(SET_MEM), memaddr + i, myaddr[i] ); - if (*ROMDELIM(SET_MEM) != 0) { /* if there's a delimiter */ - expect (ROMDELIM(SET_MEM), 1); - expect (CMD_DELIM); - printf_monitor ("%x", myaddr[i]); + if (GDBPROTO) { + *p++ = 'M'; /* The command to write memory */ + hexword2ascii (num, memaddr); /* convert the address */ + strcpy (p, num); /* copy the address */ + p += 8; + *p++ = ','; /* add comma delimeter */ + hexword2ascii (num, len); /* Get the length as a 4 digit number */ + *p++ = num[4]; + *p++ = num[5]; + *p++ = num[6]; + *p++ = num[7]; + *p++ = ':'; /* add the colon delimeter */ + for (j = 0; j < len; j++) { /* copy the data in after converting it */ +#if 0 + hexword2ascii (num, myaddr[j]); +#endif + *p++ = tohex ((myaddr[j] >> 4) & 0xf); + *p++ = tohex (myaddr[j] & 0xf); +#if 0 + strcpy ((buf+14)+(j * 2), num+6); +#endif } -/*** printf_monitor ("%x", myaddr[i]); ***/ - if (sr_get_debug() > 1) - printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]); - if (*ROMDELIM(SET_MEM) != 0) { - expect (CMD_DELIM); - printf_monitor (CMD_END); + + make_gdb_packet (packet, buf); + if (monitor_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (monitor_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + } else { + for (i = 0; i < len; i++) { + printf_monitor (ROMCMD(SET_MEM), memaddr + i, myaddr[i] ); + if (*ROMDELIM(SET_MEM) != 0) { /* if there's a delimiter */ + expect (ROMDELIM(SET_MEM), 1); + expect (CMD_DELIM); + printf_monitor ("%x", myaddr[i]); + } + /*** printf_monitor ("%x", myaddr[i]); ***/ + if (sr_get_debug() > 1) + printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]); + if (*ROMDELIM(SET_MEM) != 0) { + expect (CMD_DELIM); + printf_monitor (CMD_END); + } + expect_prompt (1); } - expect_prompt (1); } return len; } @@ -947,6 +1075,7 @@ monitor_read_inferior_memory(memaddr, myaddr, len) { int i, j; char buf[20]; + char packet[PBUFSIZ]; /* Number of bytes read so far. */ int count; @@ -987,23 +1116,40 @@ monitor_read_inferior_memory(memaddr, myaddr, len) debuglogs (3, "Display %d bytes at %x for Big Endian host", len_this_pass, startaddr); - for (i = 0; i < len_this_pass; i++) { - printf_monitor (ROMCMD(GET_MEM), startaddr, startaddr); - sprintf (buf, ROMCMD(GET_MEM), startaddr, startaddr); - if (*ROMDELIM(GET_MEM) != 0) { /* if there's a delimiter */ - expect (ROMDELIM(GET_MEM), 1); - } else { + if (GDBPROTO) { + for (i = 0; i < len_this_pass; i++) { + sprintf (buf, "m%08x,%04x", startaddr, len_this_pass); + make_gdb_packet (packet, buf); + if (monitor_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (monitor_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + debuglogs (4, "monitor_read_inferior: Got a \"%s\" back\n", packet); + for (j = 0; j < len_this_pass ; j++) { /* extract the byte values */ + myaddr[count++] = from_hex (*(packet+(j*2))) * 16 + from_hex (*(packet+(j*2)+1)); + debuglogs (5, "myaddr set to %x\n", myaddr[count-1]); + } + startaddr += 1; + } + } else { + for (i = 0; i < len_this_pass; i++) { + printf_monitor (ROMCMD(GET_MEM), startaddr, startaddr); sprintf (buf, ROMCMD(GET_MEM), startaddr, startaddr); - expect (buf,1); /* get the command echo */ - get_hex_word(1); /* strip away the address */ + if (*ROMDELIM(GET_MEM) != 0) { /* if there's a delimiter */ + expect (ROMDELIM(GET_MEM), 1); + } else { + sprintf (buf, ROMCMD(GET_MEM), startaddr, startaddr); + expect (buf,1); /* get the command echo */ + get_hex_word(1); /* strip away the address */ + } + get_hex_byte (&myaddr[count++]); /* get the value at this address */ + + if (*ROMDELIM(GET_MEM) != 0) { + printf_monitor (CMD_END); + } + expect_prompt (1); + startaddr += 1; } - get_hex_byte (&myaddr[count++]); /* get the value at this address */ - - if (*ROMDELIM(GET_MEM) != 0) { - printf_monitor (CMD_END); - } - expect_prompt (1); - startaddr += 1; } } return len; @@ -1524,7 +1670,7 @@ monitor_make_srec (buffer, type, memaddr, myaddr, len) * SUM = Add the contents of the 128 bytes and use the low-order * 8 bits of the result. */ -void +static void make_xmodem_packet (packet, data, len) unsigned char packet[]; unsigned char *data; @@ -1566,7 +1712,7 @@ make_xmodem_packet (packet, data, len) /* * print_xmodem_packet -- print the packet as a debug check */ -void +static void print_xmodem_packet(packet) char packet[]; { @@ -1608,6 +1754,308 @@ print_xmodem_packet(packet) putchar ('\n'); } +/* + * make_gdb_packet -- make a GDB packet. The data is always ASCII. + * A debug packet whose contents are + * is encapsulated for transmission in the form: + * + * $ # CSUM1 CSUM2 + * + * must be ASCII alphanumeric and cannot include characters + * '$' or '#'. If starts with two characters followed by + * ':', then the existing stubs interpret this as a sequence number. + * + * CSUM1 and CSUM2 are ascii hex representation of an 8-bit + * checksum of , the most significant nibble is sent first. + * the hex digits 0-9,a-f are used. + * + */ +static void +make_gdb_packet (buf, data) + char *buf, *data; +{ + int i; + unsigned char csum = 0; + int cnt; + char *p; + + debuglogs (3, "make_gdb_packet(%s)\n", data); + cnt = strlen (data); + if (cnt > PBUFSIZ) + error ("make_gdb_packet(): to much data\n"); + + /* start with the packet header */ + p = buf; + *p++ = '$'; + + /* calculate the checksum */ + for (i = 0; i < cnt; i++) { + csum += data[i]; + *p++ = data[i]; + } + + /* terminate the data with a '#' */ + *p++ = '#'; + + /* add the checksum as two ascii digits */ + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + *p = 0x0; /* Null terminator on string */ +} + +/* + * monitor_send_packet -- send a GDB packet to the target with error handling. We + * get a '+' (ACK) back if the packet is received and the checksum + * matches. Otherwise a '-' (NAK) is returned. It returns a 1 for a + * successful transmition, or a 0 for a failure. + */ +int +monitor_send_packet (packet) + char *packet; +{ + int c, retries, i; + char junk[PBUFSIZ]; + + retries = 0; + +#if 0 + /* scan the packet to make sure it only contains valid characters. + this may sound silly, but sometimes a garbled packet will hang + the target board. We scan the whole thing, then print the error + message. + */ + for (i = 0; i < strlen(packet); i++) { + debuglogs (5, "monitor_send_packet(): Scanning \'%c\'\n", packet[i]); + /* legit hex numbers or command */ + if ((isxdigit(packet[i])) || (isalpha(packet[i]))) + continue; + switch (packet[i]) { + case '+': /* ACK */ + case '-': /* NAK */ + case '#': /* end of packet */ + case '$': /* start of packet */ + continue; + default: /* bogus character */ + retries++; + debuglogs (4, "monitor_send_packet(): Found a non-ascii digit \'%c\' in the packet.\n", packet[i]); + } + } +#endif + + if (retries > 0) + error ("Can't send packet, found %d non-ascii characters", retries); + + /* ok, try to send the packet */ + retries = 0; + while (retries <= 10) { + printf_monitor ("%s", packet); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (retries <= 10) { + c = readchar (timeout); + debuglogs (3, "Reading a GDB protocol packet... Got a '%c'\n", c); + switch (c) { + case '+': + debuglogs (3, "Got Ack\n"); + return 1; + case SERIAL_TIMEOUT: + debuglogs (3, "Timed out reading serial port\n"); + break; /* Retransmit buffer */ + case '-': + debuglogs (3, "Got NAK\n"); + break; /* FIXME: (maybe) was a continue */ + case '$': + /* it's probably an old response, or the echo of our command. + * just gobble up the packet and ignore it. + */ + debuglogs (3, "Got a junk packet\n"); + do { + c = readchar (timeout); + junk[i++] = c; + } while (c != '#'); + c = readchar (timeout); + junk[i++] = c; + c = readchar (timeout); + junk[i++] = c; + junk[i++] = '\0'; + debuglogs (3, "Reading a junk packet, got a \"%s\"\n", junk); + continue; /* Now, go look for next packet */ + default: + continue; + } + retries++; + debuglogs (3, "Retransmitting packet \"%s\"\n", packet); + break; /* Here to retransmit */ + } + } /* outer while */ + return 0; +} + +/* + * monitor_get_packet -- get a GDB packet from the target. Basically we read till we + * see a '#', then check the checksum. It returns a 1 if it's gotten a + * packet, or a 0 it the packet wasn't transmitted correctly. + */ +int +monitor_get_packet (packet) + char *packet; +{ + int c; + int retries; + unsigned char csum; + unsigned char pktcsum; + char *bp; + + csum = 0; + bp = packet; + + memset (packet, 1, PBUFSIZ); + retries = 0; + while (retries <= 10) { + do { + c = readchar (timeout); + if (c == SERIAL_TIMEOUT) { + debuglogs (3, "monitor_get_packet: got time out from serial port.\n"); + } + debuglogs (3, "Waiting for a '$', got a %c\n", c); + } while (c != '$'); + + retries = 0; + while (retries <= 10) { + c = readchar (timeout); + debuglogs (3, "monitor_get_packet: got a '%c'\n", c); + switch (c) { + case SERIAL_TIMEOUT: + debuglogs (3, "Timeout in mid-packet, retrying\n"); + return 0; + case '$': + debuglogs (3, "Saw new packet start in middle of old one\n"); + return 0; /* Start a new packet, count retries */ + case '#': + *bp = '\0'; + pktcsum = from_hex (readchar (timeout)) << 4; + pktcsum |= from_hex (readchar (timeout)); + if (csum == pktcsum) { + debuglogs (3, "\nGDB packet checksum correct, packet data is \"%s\",\n", packet); + printf_monitor ("+"); + expect_prompt (1); + return 1; + } + debuglogs (3, "Bad checksum, sentsum=0x%x, csum=0x%x\n", pktcsum, csum); + return 0; + case '*': /* Run length encoding */ + debuglogs (5, "Run length encoding in packet\n"); + csum += c; + c = readchar (timeout); + csum += c; + c = c - ' ' + 3; /* Compute repeat count */ + + if (c > 0 && c < 255 && bp + c - 1 < packet + PBUFSIZ - 1) { + memset (bp, *(bp - 1), c); + bp += c; + continue; + } + *bp = '\0'; + printf_filtered ("Repeat count %d too large for buffer.\n", c); + return 0; + + default: + if ((!isxdigit(c)) && (!ispunct(c))) + debuglogs (4, "Got a non-ascii digit \'%c\'.\\n", c); + if (bp < packet + PBUFSIZ - 1) { + *bp++ = c; + csum += c; + continue; + } + + *bp = '\0'; + puts_filtered ("Remote packet too long.\n"); + return 0; + } + } + } +} + +/* + * ascii2hexword -- convert an ascii number represented by 8 digits to a hex value. + */ +static unsigned long +ascii2hexword (mem) + unsigned char *mem; +{ + unsigned long val; + int i; + char buf[9]; + + val = 0; + for (i = 0; i < 8; i++) { + val <<= 4; + if (mem[i] >= 'A' && mem[i] <= 'F') + val = val + mem[i] - 'A' + 10; + if (mem[i] >= 'a' && mem[i] <= 'f') + val = val + mem[i] - 'a' + 10; + if (mem[i] >= '0' && mem[i] <= '9') + val = val + mem[i] - '0'; + buf[i] = mem[i]; + } + buf[8] = '\0'; + debuglogs (4, "ascii2hexword() got a 0x%x from %s(%x).\n", val, buf, mem); + return val; +} + +/* + * ascii2hexword -- convert a hex value to an ascii number represented by 8 + * digits. + */ +static char* +hexword2ascii (mem, num) + unsigned char *mem; + unsigned long num; +{ + int i; + unsigned char ch; + + debuglogs (4, "hexword2ascii() converting %x ", num); + for (i = 7; i >= 0; i--) { + mem[i] = tohex ((num >> 4) & 0xf); + mem[i] = tohex (num & 0xf); + num = num >> 4; + } + mem[8] = '\0'; + debuglogs (4, "\tto a %s", mem); +} + +/* Convert hex digit A to a number. */ +static int +from_hex (a) + int a; +{ + if (a == 0) + return 0; + + debuglogs (4, "from_hex got a 0x%x(%c)\n",a,a); + if (a >= '0' && a <= '9') + return a - '0'; + if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else { + error ("Reply contains invalid hex digit 0x%x", a); + } +} + +/* Convert number NIB to a hex digit. */ +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + /* * _initialize_remote_monitors -- setup a few addtitional commands that * are usually only used by monitors.