From: Mark Alexander Date: Mon, 29 Dec 1997 21:50:10 +0000 (+0000) Subject: * dve3900-rom.c: New file to support Densan DVE-R3900/20 board. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7e9576e098e8f293a9bc9d53da7cda4335aa7d0f;p=binutils-gdb.git * dve3900-rom.c: New file to support Densan DVE-R3900/20 board. * monitor.c (monitor_debug): Move to utils.c, rename to puts_debug. (monitor_write_memory, monitor_read_memory, monitor_insert_breakpoint, monitor_remove_breakpoint): Remove useless address bits if current monitor has MO_ADDR_BITS_REMOVE flag. * monitor.h (MO_ADDR_BITS_REMOVE): Define. * utils.c (puts_debug): Formerly monitor_debug from monitor.c; move here and make public. Add better support for carriage returns. * defs.h (puts_debug): Declare. * dsrec.c (load_srec): Use puts_debug to print remotedebug information. Output header record correctly. (make_srec): Output a header record instead of a termination record if sect is non-NULL (value is ignored), but abfd is NULL. * config/mips/tm-tx39.h (DEFAULT_MIPS_TYPE): Remove definition. (REGISTER_NAMES): Define to add R3900-specific registers. * config/mips/tm-tx39l.h: Ditto. * config/mips/tx39.mt (TDEPFILES): Add dve3900-rom.o and support files. * config/mips/tx39l.mt: Ditto. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a72276fcf6a..b15f4eb9c33 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +Mon Dec 29 21:25:34 1997 Mark Alexander + + * dve3900-rom.c: New file to support Densan DVE-R3900/20 board. + * monitor.c (monitor_debug): Move to utils.c, rename to puts_debug. + (monitor_write_memory, monitor_read_memory, monitor_insert_breakpoint, + monitor_remove_breakpoint): Remove useless address bits if current + monitor has MO_ADDR_BITS_REMOVE flag. + * monitor.h (MO_ADDR_BITS_REMOVE): Define. + * utils.c (puts_debug): Formerly monitor_debug from monitor.c; + move here and make public. Add better support for carriage returns. + * defs.h (puts_debug): Declare. + * dsrec.c (load_srec): Use puts_debug to print remotedebug information. + Output header record correctly. + (make_srec): Output a header record instead of a termination record + if sect is non-NULL (value is ignored), but abfd is NULL. + * config/mips/tm-tx39.h (DEFAULT_MIPS_TYPE): Remove definition. + (REGISTER_NAMES): Define to add R3900-specific registers. + * config/mips/tm-tx39l.h: Ditto. + * config/mips/tx39.mt (TDEPFILES): Add dve3900-rom.o and support files. + * config/mips/tx39l.mt: Ditto. + Wed Dec 24 12:48:48 1997 Stan Shebs * dsrec.c: Cosmetic improvements. diff --git a/gdb/config/mips/tm-tx39.h b/gdb/config/mips/tm-tx39.h index f46ee21bb6f..7db466a934a 100644 --- a/gdb/config/mips/tm-tx39.h +++ b/gdb/config/mips/tm-tx39.h @@ -21,5 +21,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "mips/tm-bigmips.h" -#undef DEFAULT_MIPS_TYPE -#define DEFAULT_MIPS_TYPE "r3900" +#undef REGISTER_NAMES +#define REGISTER_NAMES \ + { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ + "sr", "lo", "hi", "bad", "cause","pc", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "config", "cache", "debug", "depc", "epc", "" \ + } diff --git a/gdb/config/mips/tm-tx39l.h b/gdb/config/mips/tm-tx39l.h index 7da13207099..53be627612b 100644 --- a/gdb/config/mips/tm-tx39l.h +++ b/gdb/config/mips/tm-tx39l.h @@ -21,5 +21,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "mips/tm-mips.h" -#undef DEFAULT_MIPS_TYPE -#define DEFAULT_MIPS_TYPE "r3900" +#undef REGISTER_NAMES +#define REGISTER_NAMES \ + { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ + "sr", "lo", "hi", "bad", "cause","pc", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "", "", \ + "", "", "", "", "", "", "", "", \ + "", "", "config", "cache", "debug", "depc", "epc", "" \ + } diff --git a/gdb/config/mips/tx39.mt b/gdb/config/mips/tx39.mt index 6ae1dad2046..8b4c1a92c24 100644 --- a/gdb/config/mips/tx39.mt +++ b/gdb/config/mips/tx39.mt @@ -1,5 +1,5 @@ # Target: Big-endian mips board, typically an IDT. -TDEPFILES= mips-tdep.o remote-mips.o remote-array.o +TDEPFILES= mips-tdep.o remote-mips.o dve3900-rom.o monitor.o dsrec.o TM_FILE= tm-tx39.h SIM_OBS = remote-sim.o SIM = ../sim/mips/libsim.a diff --git a/gdb/config/mips/tx39l.mt b/gdb/config/mips/tx39l.mt index fe339d633dd..35083293d45 100644 --- a/gdb/config/mips/tx39l.mt +++ b/gdb/config/mips/tx39l.mt @@ -1,5 +1,5 @@ # Target: Big-endian mips board, typically an IDT. -TDEPFILES= mips-tdep.o remote-mips.o remote-array.o +TDEPFILES= mips-tdep.o remote-mips.o dve3900-rom.o monitor.o dsrec.o TM_FILE= tm-tx39l.h SIM_OBS = remote-sim.o SIM = ../sim/mips/libsim.a diff --git a/gdb/defs.h b/gdb/defs.h index 75325480808..aa5dd5f1484 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -118,7 +118,7 @@ enum command_class all_classes = -2, all_commands = -1, /* Classes of commands */ no_class = -1, class_run = 0, class_vars, class_stack, - class_files, class_support, class_info, class_breakpoint, + class_files, class_support, class_info, class_breakpoint, class_trace, class_alias, class_obscure, class_user, class_maintenance, class_pseudo }; @@ -309,6 +309,8 @@ extern void puts_filtered PARAMS ((const char *)); extern void puts_unfiltered PARAMS ((const char *)); +extern void puts_debug PARAMS ((char *prefix, char *string, char *suffix)); + extern void vprintf_filtered PARAMS ((const char *, va_list)) ATTR_FORMAT(printf, 1, 0); @@ -771,7 +773,7 @@ extern void set_architecture_from_file PARAMS ((bfd *)); /* Notify target of a change to the selected architecture. Zero return status indicates that the target did not like the change. */ extern int (*target_architecture_hook) PARAMS ((const bfd_arch_info_type *ap)); -extern void set_architecture PARAMS ((char *arg, int from_tty)); +extern void set_architecture_from_arch_mach PARAMS ((enum bfd_architecture arch, unsigned long mach)); /* Number of bits in a char or unsigned char for the target machine. Just like CHAR_BIT in but describes the target machine. */ diff --git a/gdb/dsrec.c b/gdb/dsrec.c index 03b5517d8d4..6a40e7eae7a 100644 --- a/gdb/dsrec.c +++ b/gdb/dsrec.c @@ -82,9 +82,12 @@ load_srec (desc, file, load_offset, maxrecsize, flags, hashmark, waitack) is no data, so len is 0. */ reclen = maxrecsize; - make_srec (srec, 0, NULL, NULL, 0, &reclen, flags); + make_srec (srec, 0, NULL, (asection *)1, 0, &reclen, flags); if (remote_debug) - fprintf_unfiltered (gdb_stderr, "%.*s\\r\n", reclen-1, srec); + { + srec[reclen] = '\0'; + puts_debug ("sent -->", srec, "<--"); + } SERIAL_WRITE (desc, srec, reclen); for (s = abfd->sections; s; s = s->next) @@ -93,8 +96,7 @@ load_srec (desc, file, load_offset, maxrecsize, flags, hashmark, waitack) int numbytes; bfd_vma addr = bfd_get_section_vma (abfd, s) + load_offset; bfd_size_type size = bfd_get_section_size_before_reloc (s); - char * section_name = bfd_get_section_name (abfd, s); - + char * section_name = (char *)bfd_get_section_name (abfd, s); printf_filtered ("%s\t: 0x%08x .. 0x%08x ", section_name, (int) addr, (int) addr + size); gdb_flush (gdb_stdout); @@ -108,7 +110,10 @@ load_srec (desc, file, load_offset, maxrecsize, flags, hashmark, waitack) i, &reclen, flags); if (remote_debug) - fprintf_unfiltered (gdb_stderr, "%.*s\\r\n", reclen-1, srec); + { + srec[reclen] = '\0'; + puts_debug ("sent -->", srec, "<--"); + } /* Repeatedly send the S-record until a good acknowledgement is sent back. */ @@ -145,11 +150,16 @@ load_srec (desc, file, load_offset, maxrecsize, flags, hashmark, waitack) make_srec (srec, abfd->start_address, NULL, NULL, 0, &reclen, flags); if (remote_debug) - fprintf_unfiltered (gdb_stderr, "%.*s\\r\n", reclen-1, srec); + { + srec[reclen] = '\0'; + puts_debug ("sent -->", srec, "<--"); + } + SERIAL_WRITE (desc, srec, reclen); /* Some monitors need these to wake up properly. (Which ones? -sts) */ SERIAL_WRITE (desc, "\r\r", 2); + puts_debug ("sent -->", "\r\r", "<---"); SERIAL_FLUSH_INPUT (desc); @@ -215,6 +225,7 @@ make_srec (srec, targ_addr, abfd, sect, sectoff, maxrecsize, flags) const static char hextab[] = "0123456789ABCDEF"; const static char data_code_table[] = "123"; const static char term_code_table[] = "987"; + const static char header_code_table[] = "000"; const static char *formats[] = { "S%c%02X%04X", "S%c%02X%06X", "S%c%02X%08X" }; @@ -226,8 +237,8 @@ make_srec (srec, targ_addr, abfd, sect, sectoff, maxrecsize, flags) if (sect) { - tmp = flags; /* Data record */ - code_table = data_code_table; + tmp = flags; /* Data or header record */ + code_table = abfd ? data_code_table : header_code_table; binbuf = alloca (*maxrecsize/2); } else @@ -249,7 +260,7 @@ make_srec (srec, targ_addr, abfd, sect, sectoff, maxrecsize, flags) /* Now that we know the address size, we can figure out how much data this record can hold. */ - if (sect) + if (sect && abfd) { payload_size = (*maxrecsize - (1 + 1 + 2 + addr_size * 2 + 2)) / 2; payload_size = min (payload_size, sect->_raw_size - sectoff); @@ -257,7 +268,7 @@ make_srec (srec, targ_addr, abfd, sect, sectoff, maxrecsize, flags) bfd_get_section_contents (abfd, sect, binbuf, sectoff, payload_size); } else - payload_size = 0; /* Term packets have no payload */ + payload_size = 0; /* Term or header packets have no payload */ /* Output the header. */ diff --git a/gdb/dve3900-rom.c b/gdb/dve3900-rom.c new file mode 100644 index 00000000000..511b4fede80 --- /dev/null +++ b/gdb/dve3900-rom.c @@ -0,0 +1,466 @@ +/* Remote debugging interface for Densan DVE-R3900 ROM monitor for + GDB, the GNU debugger. + Copyright 1997 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 "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void r3900_open PARAMS ((char *args, int from_tty)); + +/* Pointers to static functions in monitor.c for fetching and storing + registers. We can't use these function in certain cases where the Densan + monitor acts perversely: for registers that it displays in bit-map + format, and those that can't be modified at all. In those cases + we have to use our own functions to fetch and store their values. */ + +static void (*orig_monitor_fetch_registers) PARAMS ((int regno)); +static void (*orig_monitor_store_registers) PARAMS ((int regno)); + + +/* This array of registers needs to match the indexes used by GDB. The + whole reason this exists is because the various ROM monitors use + different names than GDB does, and don't support all the registers + either. */ + +static char *r3900_regnames[NUM_REGS] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + + "S", /* PS_REGNUM */ + "l", /* LO_REGNUM */ + "h", /* HI_REGNUM */ + "B", /* BADVADDR_REGNUM */ + "Pcause", /* CAUSE_REGNUM */ + "p" /* PC_REGNUM */ +}; + + +/* Table of register names produced by monitor's register dump command. */ + +static struct reg_entry +{ + char *name; + int regno; +} reg_table[] = +{ + { "r0_zero", 0 }, { "r1_at", 1 }, { "r2_v0", 2 }, { "r3_v1", 3 }, + { "r4_a0", 4 }, { "r5_a1", 5 }, { "r6_a2", 6 }, { "r7_a3", 7 }, + { "r8_t0", 8 }, { "r9_t1", 9 }, { "r10_t2", 10 }, { "r11_t3", 11 }, + { "r12_t4", 12 }, { "r13_t5", 13 }, { "r14_t6", 14 }, { "r15_t7", 15 }, + { "r16_s0", 16 }, { "r17_s1", 17 }, { "r18_s2", 18 }, { "r19_s3", 19 }, + { "r20_s4", 20 }, { "r21_s5", 21 }, { "r22_s6", 22 }, { "r23_s7", 23 }, + { "r24_t8", 24 }, { "r25_t9", 25 }, { "r26_k0", 26 }, { "r27_k1", 27 }, + { "r28_gp", 28 }, { "r29_sp", 29 }, { "r30_fp", 30 }, { "r31_ra", 31 }, + { "HI", HI_REGNUM }, + { "LO", LO_REGNUM }, + { "PC", PC_REGNUM }, + { "BadV", BADVADDR_REGNUM }, + { NULL, 0 } +}; + + +/* The monitor prints register values in the form + + regname = xxxx xxxx + + We look up the register name in a table, and remove the embedded space in + the hex value before passing it to monitor_supply_register. */ + +static void +r3900_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno = -1; + int i; + char valbuf[10]; + char *p; + + /* Perform some sanity checks on the register name and value. */ + if (regnamelen < 2 || regnamelen > 7 || vallen != 9) + return; + + /* Look up the register name. */ + for (i = 0; reg_table[i].name != NULL; i++) + { + int rlen = strlen (reg_table[i].name); + if (rlen == regnamelen && strncmp (regname, reg_table[i].name, rlen) == 0) + { + regno = reg_table[i].regno; + break; + } + } + if (regno == -1) + return; + + /* Copy the hex value to a buffer and eliminate the embedded space. */ + for (i = 0, p = valbuf; i < vallen; i++) + if (val[i] != ' ') + *p++ = val[i]; + *p = '\0'; + + monitor_supply_register (regno, valbuf); +} + +/* Fetch the BadVaddr register. Unlike the other registers, this + one can't be modified, and the monitor won't even prompt to let + you modify it. */ + +static void +r3900_fetch_badvaddr() +{ + char buf[20]; + int c; + + monitor_printf ("xB\r"); + monitor_expect ("BadV=", NULL, 0); + monitor_expect_prompt (buf, sizeof(buf)); + monitor_supply_register (BADVADDR_REGNUM, buf); +} + + +/* Certain registers are "bitmapped", in that the monitor can only display + them or let the user modify them as a series of named bitfields. + This structure describes a field in a bitmapped register. */ + +struct bit_field +{ + char *prefix; /* string appearing before the value */ + char *suffix; /* string appearing after the value */ + char *user_name; /* name used by human when entering field value */ + int length; /* number of bits in the field */ + int start; /* starting (least significant) bit number of field */ +}; + +/* The monitor displays the cache register along with the status register, + as if they were a single register. So when we want to fetch the + status register, parse but otherwise ignore the fields of the + cache register that the monitor displays. Register fields that should + be ignored have a length of zero in the tables below. */ + +static struct bit_field status_fields [] = +{ + /* Status register portion */ + { "SR[]", "sw", 2, 8 }, + { "[]", "iec", 1, 0 }, + + /* Cache register portion (dummy for parsing only) */ + { "CR[] ", "dalc", 0, 8 }, + + { NULL, NULL, 0, 0 } /* end of table marker */ +}; + + +static struct bit_field cache_fields [] = +{ + /* Status register portion (dummy for parsing only) */ + { "SR[]", "sw", 0, 8 }, + { "[]", "iec", 0, 0 }, + + /* Cache register portion */ + { "CR[] ", "dalc", 1, 8 }, + + { NULL, NULL, NULL, 0, 0 } /* end of table marker */ +}; + +static struct bit_field cause_fields[] = +{ + { "]" , "ec", 5, 2 }, + + { NULL, NULL, NULL, 0, 0 } /* end of table marker */ +}; + + +/* Read a series of bit fields from the monitor, and return their + combined binary value. */ + +static unsigned long +r3900_fetch_fields (bf) + struct bit_field *bf; +{ + char buf[20]; + int c; + unsigned long val = 0; + unsigned long bits; + + for ( ; bf->prefix != NULL; bf++) + { + monitor_expect (bf->prefix, NULL, 0); /* get prefix */ + monitor_expect (bf->suffix, buf, sizeof (buf)); /* hex value, suffix */ + if (bf->length != 0) + { + bits = strtoul (buf, NULL, 16); /* get field value */ + bits &= ((1 << bf->length) - 1); /* mask out useless bits */ + val |= bits << bf->start; /* insert into register */ + } + + } + + return val; +} + +static void +r3900_fetch_bitmapped_register (regno, bf) + int regno; + struct bit_field *bf; +{ + char buf[20]; + int c; + unsigned long val; + unsigned long bits; + unsigned char regbuf[MAX_REGISTER_RAW_SIZE]; + + monitor_printf ("x%s\r", r3900_regnames[regno]); + val = r3900_fetch_fields (bf); + monitor_printf (".\r"); + monitor_expect_prompt (NULL, 0); + + /* supply register stores in target byte order, so swap here */ + + store_unsigned_integer (regbuf, REGISTER_RAW_SIZE (regno), val); + supply_register (regno, regbuf); + +} + +/* Fetch all registers (if regno is -1), or one register from the + monitor. For most registers, we can use the generic monitor_ + monitor_fetch_registers function. But others are displayed in + very unusual fashion and must be handled specially. */ + +static void +r3900_fetch_registers (regno) + int regno; +{ + switch (regno) + { + case BADVADDR_REGNUM: + r3900_fetch_badvaddr (); + return; + case PS_REGNUM: + r3900_fetch_bitmapped_register (PS_REGNUM, status_fields); + return; + case CAUSE_REGNUM: + r3900_fetch_bitmapped_register (CAUSE_REGNUM, cause_fields); + return; + default: + orig_monitor_fetch_registers (regno); + } +} + + +/* Write the new value of the bitmapped register to the monitor. */ + +static void +r3900_store_bitmapped_register (regno, bf) + int regno; + struct bit_field *bf; +{ + unsigned long oldval, newval; + + /* Fetch the current value of the register. */ + monitor_printf ("x%s\r", r3900_regnames[regno]); + oldval = r3900_fetch_fields (bf); + newval = read_register (regno); + + /* To save time, write just the fields that have changed. */ + for ( ; bf->prefix != NULL; bf++) + { + if (bf->length != 0) + { + unsigned long oldbits, newbits, mask; + + mask = (1 << bf->length) - 1; + oldbits = (oldval >> bf->start) & mask; + newbits = (newval >> bf->start) & mask; + if (oldbits != newbits) + monitor_printf ("%s %x ", bf->user_name, newbits); + } + } + + monitor_printf (".\r"); + monitor_expect_prompt (NULL, 0); +} + +static void +r3900_store_registers (regno) + int regno; +{ + switch (regno) + { + case PS_REGNUM: + r3900_store_bitmapped_register (PS_REGNUM, status_fields); + return; + case CAUSE_REGNUM: + r3900_store_bitmapped_register (CAUSE_REGNUM, cause_fields); + return; + default: + orig_monitor_store_registers (regno); + } +} + +static void +r3900_load (monops, filename, from_tty) + struct monitor_ops *monops; + char *filename; + int from_tty; +{ + extern int inferior_pid; + + generic_load (filename, from_tty); + + /* Finally, make the PC point at the start address */ + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_pid = 0; /* No process now */ +} + + +static struct target_ops r3900_ops; + +/* Commands to send to the monitor when first connecting: + * The bare carriage return forces a prompt from the monitor + (monitor doesn't prompt after a reset). + * The "Xtr" command causes subsequent "t" (trace) commands to display + the general registers only. + * The "Xxr" command does the same thing for the "x" (examine + registers) command. + * The "bx" command clears all breakpoints. +*/ + +static char *r3900_inits[] = {"\r", "Xtr\r", "Xxr\r", "bx\r", NULL}; + +static struct monitor_ops r3900_cmds; + +static void +r3900_open (args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &r3900_cmds, from_tty); +} + +void +_initialize_r3900_rom () +{ + r3900_cmds.flags = MO_HANDLE_NL | + MO_NO_ECHO_ON_OPEN | + MO_ADDR_BITS_REMOVE | + MO_CLR_BREAK_USES_ADDR; + + r3900_cmds.init = r3900_inits; + r3900_cmds.cont = "g\r"; + r3900_cmds.step = "t\r"; + r3900_cmds.set_break = "b %Lx\r"; /* COREADDR */ + r3900_cmds.clr_break = "b %Lx,0\r"; /* COREADDR */ + r3900_cmds.fill = "fx %Lx s %x %x\r"; /* COREADDR, len, val */ + + r3900_cmds.setmem.cmdb = "sx %Lx %x\r"; /* COREADDR, val */ + r3900_cmds.setmem.cmdw = "sh %Lx %x\r"; /* COREADDR, val */ + r3900_cmds.setmem.cmdl = "sw %Lx %x\r"; /* COREADDR, val */ + + r3900_cmds.getmem.cmdb = "dx %Lx s %x\r"; /* COREADDR, len */ + r3900_cmds.getmem.resp_delim = " : "; + + r3900_cmds.setreg.cmd = "x%s %x\r"; /* regname, val */ + + r3900_cmds.getreg.cmd = "x%s\r"; /* regname */ + r3900_cmds.getreg.resp_delim = "="; + r3900_cmds.getreg.term = " "; + r3900_cmds.getreg.term_cmd = ".\r"; + + r3900_cmds.dump_registers = "x\r"; + r3900_cmds.register_pattern = + "\\([a-zA-Z0-9_]+\\) *=\\([0-9a-f]+ [0-9a-f]+\\b\\)"; + r3900_cmds.supply_register = r3900_supply_register; + /* S-record download, via "keyboard port". */ + r3900_cmds.load = "r0\r"; +#if 0 /* FIXME - figure out how to get fast load to work */ + r3900_cmds.load_routine = r3900_load; +#endif + r3900_cmds.prompt = "#"; + r3900_cmds.line_term = "\r"; + r3900_cmds.target = &r3900_ops; + r3900_cmds.stopbits = SERIAL_1_STOPBITS; + r3900_cmds.regnames = r3900_regnames; + r3900_cmds.magic = MONITOR_OPS_MAGIC; + + init_monitor_ops (&r3900_ops); + + r3900_ops.to_shortname = "r3900"; + r3900_ops.to_longname = "R3900 monitor"; + r3900_ops.to_doc = "Debug using the DVE R3900 monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + r3900_ops.to_open = r3900_open; + + /* Override the functions to fetch and store registers. But save the + addresses of the default functions, because we will use those functions + for "normal" registers. */ + + orig_monitor_fetch_registers = r3900_ops.to_fetch_registers; + orig_monitor_store_registers = r3900_ops.to_store_registers; + r3900_ops.to_fetch_registers = r3900_fetch_registers; + r3900_ops.to_store_registers = r3900_store_registers; + + add_target (&r3900_ops); +} diff --git a/gdb/monitor.c b/gdb/monitor.c index b7a56aa57d3..97f5a504b4f 100644 --- a/gdb/monitor.c +++ b/gdb/monitor.c @@ -1,5 +1,5 @@ /* Remote debugging interface for boot monitors, for GDB. - Copyright 1990, 1991, 1992, 1993, 1995, 1996 + Copyright 1990, 1991, 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. Contributed by Cygnus Support. Written by Rob Savoye for Cygnus. Resurrected from the ashes by Stu Grossman. @@ -88,15 +88,17 @@ static void monitor_kill PARAMS ((void)); static void monitor_load PARAMS ((char *file, int from_tty)); static void monitor_mourn_inferior PARAMS ((void)); static void monitor_stop PARAMS ((void)); -static void monitor_debug PARAMS ((char *prefix, char *string, char *suffix)); static int monitor_read_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len)); static int monitor_write_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len)); static int monitor_expect_regexp PARAMS ((struct re_pattern_buffer *pat, char *buf, int buflen)); +#if 0 static int from_hex PARAMS ((int a)); static unsigned long get_hex_word PARAMS ((void)); +#endif +static void parse_register_dump PARAMS ((char *, int)); static struct monitor_ops *current_monitor; @@ -129,68 +131,18 @@ static DCACHE *remote_dcache; static int first_time=0; /* is this the first time we're executing after gaving created the child proccess? */ -/* monitor_debug is like fputs_unfiltered, except it prints special - characters in printable fashion. */ +/* Convert hex digit A to a number. */ -static void -monitor_debug (prefix, string, suffix) - char *prefix; - char *string; - char *suffix; +static int +fromhex (a) + int a; { - int ch; - - /* print prefix and suffix after each line */ - static int new_line=1; - static char *prev_prefix = ""; - static char *prev_suffix = ""; - - /* if the prefix is changing, print the previous suffix, a new line, - and the new prefix */ - if (strcmp(prev_prefix, prefix) != 0 && !new_line) - { - fputs_unfiltered (prev_suffix, gdb_stderr); - fputs_unfiltered ("\n", gdb_stderr); - fputs_unfiltered (prefix, gdb_stderr); - } - prev_prefix = prefix; - prev_suffix = suffix; - - /* print prefix if last char was a newline*/ - - if (new_line == 1) { - fputs_unfiltered (prefix, gdb_stderr); - new_line=0; - } - if (strchr(string,'\n')) /* save state for next call */ - new_line=1; - - while ((ch = *string++) != '\0') - { - switch (ch) { - default: - if (isprint (ch)) - fputc_unfiltered (ch, gdb_stderr); - - else - fprintf_unfiltered (gdb_stderr, "\\%03o", ch); - - break; - - case '\\': fputs_unfiltered ("\\\\", gdb_stderr); break; - case '\b': fputs_unfiltered ("\\b", gdb_stderr); break; - case '\f': fputs_unfiltered ("\\f", gdb_stderr); break; - case '\n': fputs_unfiltered ("\\n", gdb_stderr); break; - case '\r': fputs_unfiltered ("\\r", gdb_stderr); break; - case '\t': fputs_unfiltered ("\\t", gdb_stderr); break; - case '\v': fputs_unfiltered ("\\v", gdb_stderr); break; - } - } - - if (new_line==1) { /* print suffix if last char was a newline */ - fputs_unfiltered (suffix, gdb_stderr); - fputs_unfiltered ("\n", gdb_stderr); - } + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Invalid hex digit %d", a); } /* monitor_printf_noecho -- Send data to monitor, but don't expect an echo. @@ -219,7 +171,7 @@ monitor_printf_noecho (va_alist) vsprintf (sndbuf, pattern, args); if (remote_debug > 0) - monitor_debug ("sent -->", sndbuf, "<--"); + puts_debug ("sent -->", sndbuf, "<--"); len = strlen (sndbuf); @@ -256,7 +208,7 @@ monitor_printf (va_alist) vsprintf (sndbuf, pattern, args); if (remote_debug > 0) - monitor_debug ("sent -->", sndbuf, "<--"); + puts_debug ("sent -->", sndbuf, "<--"); len = strlen (sndbuf); @@ -297,7 +249,7 @@ readchar (timeout) char buf[2]; buf[0] = c; buf[1] = '\0'; - monitor_debug ("read -->", buf, "<--"); + puts_debug ("read -->", buf, "<--"); } } @@ -478,6 +430,7 @@ monitor_expect_prompt (buf, buflen) /* Get N 32-bit words from remote, each preceded by a space, and put them in registers starting at REGNO. */ +#if 0 static unsigned long get_hex_word () { @@ -501,6 +454,7 @@ get_hex_word () return val; } +#endif static void compile_pattern (pattern, compiled_pattern, fastmap) @@ -536,7 +490,6 @@ monitor_open (args, mon_ops, from_tty) int from_tty; { char *name; - int i; char **p; if (mon_ops->magic != MONITOR_OPS_MAGIC) @@ -725,7 +678,7 @@ monitor_resume (pid, step, sig) form REG=VAL. Each description is split up into a name and a value string which are passed down to monitor specific code. */ -static char * +static void parse_register_dump (buf, len) char *buf; int len; @@ -899,7 +852,13 @@ monitor_fetch_register (regno) searching from the start of the buf. */ if (current_monitor->getreg.resp_delim) - monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); + { + monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); + /* Handle case of first 32 registers listed in pairs. */ + if (current_monitor->flags & MO_32_REGS_PAIRED + && regno & 1 == 1 && regno < 32) + monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); + } /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set */ if (current_monitor->flags & MO_HEX_PREFIX) @@ -957,7 +916,8 @@ monitor_fetch_register (regno) /* Read the remote registers into the block regs. */ -static void monitor_dump_regs () +static void +monitor_dump_regs () { char buf[1024]; int resp_len; @@ -1007,19 +967,26 @@ monitor_store_register (regno) val = read_register (regno); - /* send the register deposit command */ + /* send the register deposit command */ if (current_monitor->flags & MO_REGISTER_VALUE_FIRST) monitor_printf (current_monitor->setreg.cmd, val, name); + else if (current_monitor->flags & MO_SETREG_INTERACTIVE) + monitor_printf (current_monitor->setreg.cmd, name); else monitor_printf (current_monitor->setreg.cmd, name, val); -/* It's possible that there are actually some monitors out there that - will prompt you when you set a register. In that case, you may - need to add some code here to deal with TERM and TERM_CMD (see - monitor_fetch_register to get an idea of what's needed...) */ + if (current_monitor->setreg.term) + { + monitor_expect (current_monitor->setreg.term, NULL, 0); - monitor_expect_prompt (NULL, 0); + if (current_monitor->flags & MO_SETREG_INTERACTIVE) + monitor_printf ("%x\r", val); + + monitor_expect_prompt (NULL, 0); + } + else + monitor_expect_prompt (NULL, 0); } /* Store the remote registers. */ @@ -1067,6 +1034,9 @@ monitor_write_memory (memaddr, myaddr, len) char *cmd; int i; + if (current_monitor->flags & MO_ADDR_BITS_REMOVE) + memaddr = ADDR_BITS_REMOVE (memaddr); + /* Use memory fill command for leading 0 bytes. */ if (current_monitor->fill) @@ -1117,6 +1087,19 @@ monitor_write_memory (memaddr, myaddr, len) if (current_monitor->flags & MO_NO_ECHO_ON_SETMEM) monitor_printf_noecho (cmd, memaddr, val); + else if (current_monitor->flags & MO_SETMEM_INTERACTIVE) + { + + monitor_printf_noecho (cmd, memaddr); + + if (current_monitor->setmem.term) + { + monitor_expect (current_monitor->setmem.term, NULL, 0); + + monitor_printf ("%x\r", val); + + } + } else monitor_printf (cmd, memaddr, val); @@ -1247,9 +1230,9 @@ monitor_read_memory_single (memaddr, myaddr, len) return len; } -/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory - at MEMADDR. Returns length moved. Currently, we only do one byte at a - time. */ +/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's + memory at MEMADDR. Returns length moved. Currently, we do no more + than 16 bytes at a time. */ static int monitor_read_memory (memaddr, myaddr, len) @@ -1258,18 +1241,22 @@ monitor_read_memory (memaddr, myaddr, len) int len; { unsigned int val; - unsigned char regbuf[MAX_REGISTER_RAW_SIZE]; char buf[512]; char *p, *p1; - char *name; int resp_len; int i; + CORE_ADDR dumpaddr; + + if (current_monitor->flags & MO_ADDR_BITS_REMOVE) + memaddr = ADDR_BITS_REMOVE (memaddr); if (current_monitor->flags & MO_GETMEM_READ_SINGLE) return monitor_read_memory_single (memaddr, myaddr, len); len = min (len, 16); + dumpaddr = memaddr & ~0xf; + /* See if xfer would cross a 16 byte boundary. If so, clip it. */ if (((memaddr ^ (memaddr + len - 1)) & ~0xf) != 0) len = ((memaddr + len) & ~0xf) - memaddr; @@ -1278,6 +1265,8 @@ monitor_read_memory (memaddr, myaddr, len) if (current_monitor->flags & MO_GETMEM_NEEDS_RANGE) monitor_printf (current_monitor->getmem.cmdb, memaddr, memaddr + len - 1); + else if (current_monitor->flags & MO_GETMEM_16_BOUNDARY) + monitor_printf (current_monitor->getmem.cmdb, dumpaddr); else monitor_printf (current_monitor->getmem.cmdb, memaddr, len); @@ -1333,6 +1322,27 @@ monitor_read_memory (memaddr, myaddr, len) #endif } + if (current_monitor->flags & MO_GETMEM_16_BOUNDARY) + { + i = len; + while (!(*p == '\000' || *p == '\n' || *p == '\r') && i > 0) + { + if (isxdigit (*p)) + { + if (dumpaddr >= memaddr && i > 0) + { + val = fromhex (*p) * 16 + fromhex (*(p+1)); + *myaddr++ = val; + --i; + } + ++dumpaddr; + ++p; + } + ++p; + } + return len; + } + for (i = len; i > 0; i--) { /* Skip non-hex chars, but bomb on end of string and newlines */ @@ -1341,6 +1351,7 @@ monitor_read_memory (memaddr, myaddr, len) { if (isxdigit (*p)) break; + if (*p == '\000' || *p == '\n' || *p == '\r') error ("monitor_read_memory (0x%x): badly terminated response from monitor: %.*s", memaddr, resp_len, buf); p++; @@ -1421,20 +1432,24 @@ monitor_insert_breakpoint (addr, shadow) char *shadow; { int i; - /* This is only used to compute the size of a breakpoint. */ -#ifdef BREAKPOINT - static unsigned char break_insn[] = BREAKPOINT; -#else - /* In the bi-endian case we assume breakpoints are the same size. */ - static unsigned char break_insn[] = BIG_BREAKPOINT; -#endif + unsigned char *bp; + int bplen; + + if (current_monitor->set_break == NULL) + error ("No set_break defined for this monitor"); + + if (current_monitor->flags & MO_ADDR_BITS_REMOVE) + addr = ADDR_BITS_REMOVE (addr); + + /* Determine appropriate breakpoint size for this address. */ + bp = memory_breakpoint_from_pc (&addr, &bplen); for (i = 0; i < NUM_MONITOR_BREAKPOINTS; i++) { if (breakaddr[i] == 0) { breakaddr[i] = addr; - monitor_read_memory (addr, shadow, sizeof (break_insn)); + monitor_read_memory (addr, shadow, bplen); monitor_printf (current_monitor->set_break, addr); monitor_expect_prompt (NULL, 0); return 0; @@ -1453,14 +1468,22 @@ monitor_remove_breakpoint (addr, shadow) { int i; + if (current_monitor->clr_break == NULL) + error ("No clr_break defined for this monitor"); + + if (current_monitor->flags & MO_ADDR_BITS_REMOVE) + addr = ADDR_BITS_REMOVE (addr); + for (i = 0; i < NUM_MONITOR_BREAKPOINTS; i++) { if (breakaddr[i] == addr) { breakaddr[i] = 0; /* some monitors remove breakpoints based on the address */ - if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR) + if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR) monitor_printf (current_monitor->clr_break, addr); + else if (current_monitor->flags & MO_CLR_BREAK_1_BASED) + monitor_printf (current_monitor->clr_break, i + 1); else monitor_printf (current_monitor->clr_break, i); monitor_expect_prompt (NULL, 0); @@ -1477,10 +1500,25 @@ monitor_remove_breakpoint (addr, shadow) static int monitor_wait_srec_ack () { - /* FIXME: eventually we'll want to be able to handle acknowledgements - of something other than a '+' character. Right now this is only - going to work for EST visionICE. */ - return readchar (timeout) == '+'; + int i, ch; + + if (current_monitor->flags & MO_SREC_ACK_PLUS) + { + return (readchar (timeout) == '+'); + } + else if (current_monitor->flags & MO_SREC_ACK_ROTATE) + { + /* Eat two backspaces, a "rotating" char (|/-\), and a space. */ + if ((ch = readchar (1)) < 0) + return 0; + if ((ch = readchar (1)) < 0) + return 0; + if ((ch = readchar (1)) < 0) + return 0; + if ((ch = readchar (1)) < 0) + return 0; + } + return 1; } /* monitor_load -- download a file. */ @@ -1496,12 +1534,23 @@ monitor_load (file, from_tty) current_monitor->load_routine (monitor_desc, file, hashmark); else { /* The default is ascii S-records */ + int n; + unsigned long load_offset; + char buf[128]; + + /* enable user to specify address for downloading as 2nd arg to load */ + n = sscanf (file, "%s 0x%lx", buf, &load_offset); + if (n > 1) + file = buf; + else + load_offset = 0; + monitor_printf (current_monitor->load); if (current_monitor->loadresp) monitor_expect (current_monitor->loadresp, NULL, 0); -/* FIXME Should add arg here for load_offset (already done for generic_load) */ - load_srec (monitor_desc, file, 32, SREC_ALL, hashmark, + load_srec (monitor_desc, file, (bfd_vma) load_offset, + 32, SREC_ALL, hashmark, current_monitor->flags & MO_SREC_ACK ? monitor_wait_srec_ack : NULL); @@ -1563,6 +1612,7 @@ monitor_command (args, from_tty) /* Convert hex digit A to a number. */ +#if 0 static int from_hex (a) int a; @@ -1576,6 +1626,13 @@ from_hex (a) error ("Reply contains invalid hex digit 0x%x", a); } +#endif + +char * +monitor_get_dev_name () +{ + return dev_name; +} static struct target_ops monitor_ops = { diff --git a/gdb/monitor.h b/gdb/monitor.h index cf1e0cef8f0..f6c22c67cdd 100644 --- a/gdb/monitor.h +++ b/gdb/monitor.h @@ -197,6 +197,10 @@ struct monitor_ops #define MO_SREC_ACK_ROTATE 0x80000 +/* If set, then remove useless address bits from memory addresses. */ + +#define MO_ADDR_BITS_REMOVE 0x100000 + #define SREC_SIZE 160 extern void monitor_open PARAMS ((char *args, struct monitor_ops *ops, diff --git a/gdb/utils.c b/gdb/utils.c index a2699d6f9f4..182ed34ba47 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -74,6 +74,7 @@ set_width_command PARAMS ((char *, int, struct cmd_list_element *)); static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ +static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */ /* Nonzero if we have job control. */ @@ -146,6 +147,13 @@ make_final_cleanup (function, arg) return make_my_cleanup (&final_cleanup_chain, function, arg); } struct cleanup * +make_run_cleanup (function, arg) + void (*function) PARAMS ((PTR)); + PTR arg; +{ + return make_my_cleanup (&run_cleanup_chain, function, arg); +} +struct cleanup * make_my_cleanup (pmy_chain, function, arg) struct cleanup **pmy_chain; void (*function) PARAMS ((PTR)); @@ -180,6 +188,13 @@ do_final_cleanups (old_chain) do_my_cleanups (&final_cleanup_chain, old_chain); } +void +do_run_cleanups (old_chain) + register struct cleanup *old_chain; +{ + do_my_cleanups (&run_cleanup_chain, old_chain); +} + void do_my_cleanups (pmy_chain, old_chain) register struct cleanup **pmy_chain; @@ -378,7 +393,6 @@ NORETURN void #ifdef ANSI_PROTOTYPES error (const char *string, ...) #else -void error (va_alist) va_dcl #endif @@ -678,12 +692,6 @@ request_quit (signo) about USG defines and stuff like that. */ signal (signo, request_quit); -/* start-sanitize-gm */ -#ifdef GENERAL_MAGIC - target_kill (); -#endif /* GENERAL_MAGIC */ -/* end-sanitize-gm */ - #ifdef REQUEST_QUIT REQUEST_QUIT; #else @@ -1560,6 +1568,80 @@ fputc_unfiltered (c, stream) } +/* puts_debug is like fputs_unfiltered, except it prints special + characters in printable fashion. */ + +void +puts_debug (prefix, string, suffix) + char *prefix; + char *string; + char *suffix; +{ + int ch; + + /* Print prefix and suffix after each line. */ + static int new_line = 1; + static int carriage_return = 0; + static char *prev_prefix = ""; + static char *prev_suffix = ""; + + if (*string == '\n') + carriage_return = 0; + + /* If the prefix is changing, print the previous suffix, a new line, + and the new prefix. */ + if ((carriage_return || (strcmp(prev_prefix, prefix) != 0)) && !new_line) + { + fputs_unfiltered (prev_suffix, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + fputs_unfiltered (prefix, gdb_stderr); + } + + /* Print prefix if we printed a newline during the previous call. */ + if (new_line) + { + new_line = 0; + fputs_unfiltered (prefix, gdb_stderr); + } + + prev_prefix = prefix; + prev_suffix = suffix; + + /* Output characters in a printable format. */ + while ((ch = *string++) != '\0') + { + switch (ch) + { + default: + if (isprint (ch)) + fputc_unfiltered (ch, gdb_stderr); + + else + fprintf_unfiltered (gdb_stderr, "\\%03o", ch); + break; + + case '\\': fputs_unfiltered ("\\\\", gdb_stderr); break; + case '\b': fputs_unfiltered ("\\b", gdb_stderr); break; + case '\f': fputs_unfiltered ("\\f", gdb_stderr); break; + case '\n': new_line = 1; + fputs_unfiltered ("\\n", gdb_stderr); break; + case '\r': fputs_unfiltered ("\\r", gdb_stderr); break; + case '\t': fputs_unfiltered ("\\t", gdb_stderr); break; + case '\v': fputs_unfiltered ("\\v", gdb_stderr); break; + } + + carriage_return = ch == '\r'; + } + + /* Print suffix if we printed a newline. */ + if (new_line) + { + fputs_unfiltered (suffix, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + } +} + + /* Print a variable number of ARGS using format FORMAT. If this information is going to put the amount written (since the last call to REINITIALIZE_MORE_FILTER or the last page break) over the page size, @@ -1876,6 +1958,9 @@ fprintf_symbol_filtered (stream, name, lang, arg_mode) case language_cplus: demangled = cplus_demangle (name, arg_mode); break; + case language_java: + demangled = cplus_demangle (name, arg_mode | DMGL_JAVA); + break; case language_chill: demangled = chill_demangle (name); break;