From 5c8ba01776c033aafffbfa0dc972cb29a22a5113 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Tue, 14 Nov 1995 23:24:10 +0000 Subject: [PATCH] * monitor.c (monitor_load_srec monitor_make_srec): Move all S-record download code into srec.c. * srec.c srec.h: New files. Contain S-record loading routines formerly in monitor.c. * serial.c serial.h: New routine just like fprintf, but uses serial_t instead of FILE *. * sh-tdep.c (frame_find_saved_regs init_extra_frame_info): Don't add four to saved pc (makes things match manual). Also, fix bug where we didn't get pc from stack frame correctly. * config/sh/tm-sh.h (SAVED_PC_AFTER_CALL): Don't add four to saved pc. Real hardware does this for you. * sh3-rom.c (sh3_load): New routine. Sets up for download then calls generic S-record loader. * config/h8300/h8300.mt, config/h8500/h8500.mt, config/m68k/monitor.mt, config/pa/hppapro.mt, config/sh/sh.mt: Add srec.o to TDEPFILES. --- gdb/.Sanitize | 2 + gdb/ChangeLog | 19 ++++ gdb/serial.c | 29 ++++++ gdb/serial.h | 3 + gdb/sh-tdep.c | 23 ++--- gdb/sh3-rom.c | 23 ++++- gdb/srec.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/srec.h | 35 +++++++ 8 files changed, 370 insertions(+), 18 deletions(-) create mode 100644 gdb/srec.c create mode 100644 gdb/srec.h diff --git a/gdb/.Sanitize b/gdb/.Sanitize index 0373b87a4a7..e5dfd52347d 100644 --- a/gdb/.Sanitize +++ b/gdb/.Sanitize @@ -327,6 +327,8 @@ sparc-stub.c sparc-tdep.c sparcl-stub.c sparcl-tdep.c +srec.c +srec.h stabsread.c stabsread.h stack.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f36bb55f74d..c28ff5b1cd1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +Tue Nov 14 14:51:05 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c (monitor_load_srec monitor_make_srec): Move all + S-record download code into srec.c. + * srec.c srec.h: New files. Contain S-record loading routines + formerly in monitor.c. + * serial.c serial.h: New routine just like fprintf, but uses + serial_t instead of FILE *. + * sh-tdep.c (frame_find_saved_regs init_extra_frame_info): + Don't add four to saved pc (makes things match manual). Also, fix + bug where we didn't get pc from stack frame correctly. + * config/sh/tm-sh.h (SAVED_PC_AFTER_CALL): Don't add four to + saved pc. Real hardware does this for you. + * sh3-rom.c (sh3_load): New routine. Sets up for download then + calls generic S-record loader. + * config/h8300/h8300.mt, config/h8500/h8500.mt, + config/m68k/monitor.mt, config/pa/hppapro.mt, config/sh/sh.mt: + Add srec.o to TDEPFILES. + Tue Nov 14 15:57:36 1995 Michael Meissner * remote-ppcbug.c: New file to support the Motorola PPCBUG monitor diff --git a/gdb/serial.c b/gdb/serial.c index 8a3a21b5060..ea886a6a3c9 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -307,6 +307,35 @@ connect_command (args, fromtty) } #endif /* 0 */ +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +serial_printf (serial_t desc, const char *format, ...) +#else +serial_printf (va_alist) + va_dcl +#endif +{ + va_list args; + char *buf; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + serial_t desc; + char *format; + + va_start (args); + desc = va_arg (args, serial_t); + format = va_arg (args, char *); +#endif + + vasprintf (&buf, format, args); + SERIAL_WRITE (desc, buf, strlen (buf)); + + free (buf); + va_end (args); +} + void _initialize_serial () { diff --git a/gdb/serial.h b/gdb/serial.h index 60a6da34f77..2cf06f36f5b 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -167,4 +167,7 @@ void serial_close PARAMS ((serial_t, int)); #define SERIAL_UN_FDOPEN(SERIAL_T) serial_close(SERIAL_T, 0) +extern void serial_printf PARAMS ((serial_t desc, const char *, ...)) + ATTR_FORMAT(printf, 2, 3); + #endif /* SERIAL_H */ diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 95a3f1969c8..a56c826e9fb 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -213,23 +213,11 @@ frame_find_saved_regs (fi, fsr) fi->f_offset = depth - where[FP_REGNUM] - 4; /* Work out the return pc - either from the saved pr or the pr value */ - /* Just called, so dig out the real return */ - if (fi->return_pc == 0) - { - fi->return_pc = read_register (PR_REGNUM) + 4; - } - else - { - if (fsr->regs[PR_REGNUM]) - { - fi->return_pc = read_memory_integer (fsr->regs[PR_REGNUM], 4) + 4; - } - else - { - fi->return_pc = read_register (PR_REGNUM) + 4; - } - } + if (fsr->regs[PR_REGNUM]) + fi->return_pc = read_memory_integer (fsr->regs[PR_REGNUM], 4); + else + fi->return_pc = read_register (PR_REGNUM); } /* initialize the extra info saved in a FRAME */ @@ -241,6 +229,9 @@ init_extra_frame_info (fromleaf, fi) { struct frame_saved_regs dummy; + if (fi->next) + fi->pc = fi->next->return_pc; + frame_find_saved_regs (fi, &dummy); } diff --git a/gdb/sh3-rom.c b/gdb/sh3-rom.c index b52fa5e6b0d..0973bfd620a 100644 --- a/gdb/sh3-rom.c +++ b/gdb/sh3-rom.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "target.h" #include "monitor.h" #include "serial.h" +#include "srec.h" static void sh3_open PARAMS ((char *args, int from_tty)); @@ -102,6 +103,24 @@ sh3_supply_register (regname, regnamelen, val, vallen) val = monitor_supply_register (regno++, val); } +static void +sh3_load (desc, file, hashmark) + serial_t desc; + char *file; + int hashmark; +{ + monitor_printf ("il;s:x\r"); + monitor_expect ("\005", NULL, 0); /* Look for ENQ */ + SERIAL_WRITE (desc, "\006", 1); /* Send ACK */ + monitor_expect ("LO x\r", NULL, 0); /* Look for filename */ + + load_srec (desc, file, 80, SREC_ALL, hashmark); + + monitor_expect ("\005", NULL, 0); /* Look for ENQ */ + SERIAL_WRITE (desc, "\006", 1); /* Send ACK */ + monitor_expect_prompt (NULL, 0); +} + /* This array of registers need to match the indexes used by GDB. This exists because the various ROM monitors use different strings than does GDB, and don't necessarily support all the registers @@ -167,8 +186,8 @@ static struct monitor_ops sh3_cmds = /* register_pattern */ "\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)", sh3_supply_register, /* supply_register */ - NULL, /* load_routine (defaults to SRECs) */ - "il;s:x\r\006", /* download command */ + sh3_load, /* load_routine */ + NULL, /* download command */ NULL, /* Load response */ "\n:", /* monitor command prompt */ "\r", /* end-of-line terminator */ diff --git a/gdb/srec.c b/gdb/srec.c new file mode 100644 index 00000000000..daf97c964c8 --- /dev/null +++ b/gdb/srec.c @@ -0,0 +1,254 @@ +/* S-record download support for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "serial.h" +#include "srec.h" + +extern int remote_debug; + +static int make_srec PARAMS ((char *srec, CORE_ADDR targ_addr, bfd *abfd, + asection *sect, int sectoff, int *maxrecsize, + int flags)); + +/* Download an executable by converting it to S records. DESC is a serial_t + to send the data to. FILE is the name of the file to be loaded. + MAXRECSIZE is the length in chars of the largest S-record the host can + accomodate. This is measured from the starting `S' to the last char of the + checksum. FLAGS is various random flags, and HASHMARK is non-zero to cause + a `#' to be printed out for each record loaded. */ + +void +load_srec (desc, file, maxrecsize, flags, hashmark) + serial_t desc; + const char *file; + int maxrecsize; + int flags; + int hashmark; +{ + bfd *abfd; + asection *s; + char *buffer, srec[1024]; + int i; + int reclen; + + buffer = alloca (maxrecsize + 1); + + abfd = bfd_openr (file, 0); + if (!abfd) + { + printf_filtered ("Unable to open file %s\n", file); + return; + } + + if (bfd_check_format (abfd, bfd_object) == 0) + { + printf_filtered ("File is not an object file\n"); + return; + } + + for (s = abfd->sections; s; s = s->next) + if (s->flags & SEC_LOAD) + { + int numbytes; + + printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, + s->vma + s->_raw_size); + gdb_flush (gdb_stdout); + + for (i = 0; i < s->_raw_size; i += numbytes) + { + reclen = maxrecsize; + numbytes = make_srec (srec, s->vma + i, abfd, s, i, &reclen, + flags); + + if (remote_debug) + fprintf_unfiltered (gdb_stderr, "%.*s", reclen, srec); + SERIAL_WRITE (desc, srec, reclen); + + if (hashmark) + { + putchar_unfiltered ('#'); + gdb_flush (gdb_stdout); + } + } /* Per-packet (or S-record) loop */ + + putchar_unfiltered ('\n'); + } /* Loadable sections */ + + if (hashmark) + putchar_unfiltered ('\n'); + + /* Write a type 7 terminator record. no data for a type 7, and there + is no data, so len is 0. */ + + reclen = maxrecsize; + make_srec (srec, abfd->start_address, NULL, NULL, 0, &reclen, flags); + + if (remote_debug) + fprintf_unfiltered (gdb_stderr, "%.*s", reclen, srec); + SERIAL_WRITE (desc, srec, reclen); + + SERIAL_WRITE (desc, "\r\r", 2); /* Some monitors need these to wake up */ + + SERIAL_FLUSH_INPUT (desc); +} + +/* + * make_srec -- make an srecord. This writes each line, one at a + * time, each with it's own header and trailer line. + * An srecord looks like this: + * + * byte count-+ address + * start ---+ | | data +- checksum + * | | | | + * S01000006F6B692D746573742E73726563E4 + * S315000448600000000000000000FC00005900000000E9 + * S31A0004000023C1400037DE00F023604000377B009020825000348D + * S30B0004485A0000000000004E + * S70500040000F6 + * + * S
+ * + * Where + * - length + * is the number of bytes following upto the checksum. Note that + * this is not the number of chars following, since it takes two + * chars to represent a byte. + * - type + * is one of: + * 0) header record + * 1) two byte address data record + * 2) three byte address data record + * 3) four byte address data record + * 7) four byte address termination record + * 8) three byte address termination record + * 9) two byte address termination record + * + * - address + * is the start address of the data following, or in the case of + * a termination record, the start address of the image + * - data + * is the data. + * - checksum + * is the sum of all the raw byte data in the record, from the length + * upwards, modulo 256 and subtracted from 255. + * + * This routine returns the length of the S-record. + * + */ + +static int +make_srec (srec, targ_addr, abfd, sect, sectoff, maxrecsize, flags) + char *srec; + CORE_ADDR targ_addr; + bfd *abfd; + asection *sect; + int sectoff; + int *maxrecsize; + int flags; +{ + unsigned char checksum; + int tmp; + const static char hextab[] = "0123456789ABCDEF"; + const static char data_code_table[] = "xx123"; + const static char term_code_table[] = "xx987"; + const static char *formats[] = {NULL, NULL, "S%c%02X%04X", "S%c%02X%06X", + "S%c%02X%08X"}; + char const *code_table; + int addr_size; + int payload_size; + int type_code; + char *binbuf; + char *p; + + if (sect) + { + tmp = flags; /* Data record */ + code_table = data_code_table; + binbuf = alloca (*maxrecsize/2); + } + else + { + tmp = flags >> SREC_TERM_SHIFT; /* Term record */ + code_table = term_code_table; + } + + if (tmp & SREC_4_BYTE_ADDR && targ_addr > 0xffffff) + addr_size = 4; + else if (tmp & SREC_3_BYTE_ADDR && targ_addr > 0xffff) + addr_size = 3; + else if (tmp & SREC_2_BYTE_ADDR && targ_addr > 0xff) + addr_size = 2; + else + fatal ("make_srec: Bad address (0x%x), or bad flags (0x%x).", targ_addr, + flags); + +/* Now that we know the address size, we can figure out how much data this + record can hold. */ + + if (sect) + { + payload_size = (*maxrecsize - (1 + 1 + 2 + addr_size * 2 + 2)) / 2; + payload_size = min (payload_size, sect->_raw_size - sectoff); + + bfd_get_section_contents (abfd, sect, binbuf, sectoff, payload_size); + } + else + payload_size = 0; /* Term packets have no payload */ + +/* Output the header. */ + + sprintf (srec, formats[addr_size], code_table[addr_size], + addr_size + payload_size + 1, targ_addr); + +/* Note that the checksum is calculated on the raw data, not the hexified + data. It includes the length, address and the data portions of the + packet. */ + + checksum = 0; + + checksum += (payload_size + addr_size + 1 /* Packet length */ + + (targ_addr & 0xff) /* Address... */ + + ((targ_addr >> 8) & 0xff) + + ((targ_addr >> 16) & 0xff) + + ((targ_addr >> 24) & 0xff)); + + p = srec + 1 + 1 + 2 + addr_size * 2; + + /* build the srecord */ + for (tmp = 0; tmp < payload_size; tmp++) + { + unsigned char k; + + k = binbuf[tmp]; + *p++ = hextab [k >> 4]; + *p++ = hextab [k & 0xf]; + checksum += k; + } + + checksum = ~checksum; + + *p++ = hextab[checksum >> 4]; + *p++ = hextab[checksum & 0xf]; + *p++ = '\r'; + + *maxrecsize = p - srec; + return payload_size; +} diff --git a/gdb/srec.h b/gdb/srec.h new file mode 100644 index 00000000000..1446bda3f17 --- /dev/null +++ b/gdb/srec.h @@ -0,0 +1,35 @@ +/* S-record download support for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +void load_srec PARAMS ((serial_t desc, const char *file, int maxrecsize, + int flags, int hashmark)); + +/* S-record capability flags */ + +/* Which record types are supported */ +#define SREC_2_BYTE_ADDR 0x00000001 +#define SREC_3_BYTE_ADDR 0x00000002 +#define SREC_4_BYTE_ADDR 0x00000004 +#define SREC_TERM_SHIFT 3 + +#define SREC_ALL (SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR \ + | ((SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR) \ + << SREC_TERM_SHIFT)) + +#define SREC_BINARY 0x00000040 /* Supports binary form of S-records */ -- 2.30.2