diff options
Diffstat (limited to 'gdb/remote-hms.c')
-rw-r--r-- | gdb/remote-hms.c | 1500 |
1 files changed, 1500 insertions, 0 deletions
diff --git a/gdb/remote-hms.c b/gdb/remote-hms.c new file mode 100644 index 00000000000..3ca8455d979 --- /dev/null +++ b/gdb/remote-hms.c @@ -0,0 +1,1500 @@ +/* Remote debugging interface for Hitachi HMS Monitor Version 1.0 + Copyright 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Steve Chamberlain + (sac@cygnus.com). + + 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 hms_open PARAMS ((char *args, int from_tty)); +static void +hms_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno; + + if (regnamelen != 2) + return; + if (regname[0] != 'P') + return; + /* We scan off all the registers in one go */ + + val = monitor_supply_register (PC_REGNUM, val); + /* Skip the ccr string */ + while (*val != '=' && *val) + val++; + + val = monitor_supply_register (CCR_REGNUM, val + 1); + + /* Skip up to rest of regs */ + while (*val != '=' && *val) + val++; + + for (regno = 0; regno < 7; regno++) + { + val = monitor_supply_register (regno, val + 1); + } +} + +/* + * 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. So, typing "info reg sp" becomes a "r30". + */ + +static char *hms_regnames[NUM_REGS] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "CCR", "PC" +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops hms_ops; + +static char *hms_inits[] = +{"\003", /* Resets the prompt, and clears repeated cmds */ + NULL}; + +static struct monitor_ops hms_cmds ; + +static void +init_hms_cmds(void) +{ + hms_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_GETMEM_NEEDS_RANGE; + hms_cmds.init = hms_inits; /* Init strings */ + hms_cmds.cont = "g\r"; /* continue command */ + hms_cmds.step = "s\r"; /* single step */ + hms_cmds.stop = "\003"; /* ^C interrupts the program */ + hms_cmds.set_break = "b %x\r"; /* set a breakpoint */ + hms_cmds.clr_break = "b - %x\r"; /* clear a breakpoint */ + hms_cmds.clr_all_break = "b -\r"; /* clear all breakpoints */ + hms_cmds.fill = "f %x %x %x\r"; /* fill (start end val) */ + hms_cmds.setmem.cmdb = "m.b %x=%x\r"; /* setmem.cmdb (addr, value) */ + hms_cmds.setmem.cmdw = "m.w %x=%x\r"; /* setmem.cmdw (addr, value) */ + hms_cmds.setmem.cmdl = NULL; /* setmem.cmdl (addr, value) */ + hms_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */ + hms_cmds.setmem.resp_delim = NULL;/* setreg.resp_delim */ + hms_cmds.setmem.term = NULL; /* setreg.term */ + hms_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */ + hms_cmds.getmem.cmdb = "m.b %x %x\r"; /* getmem.cmdb (addr, addr) */ + hms_cmds.getmem.cmdw = "m.w %x %x\r"; /* getmem.cmdw (addr, addr) */ + hms_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, addr) */ + hms_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, addr) */ + hms_cmds.getmem.resp_delim = ": ";/* getmem.resp_delim */ + hms_cmds.getmem.term = ">"; /* getmem.term */ + hms_cmds.getmem.term_cmd = "\003";/* getmem.term_cmd */ + hms_cmds.setreg.cmd = "r %s=%x\r";/* setreg.cmd (name, value) */ + hms_cmds.setreg.resp_delim = NULL;/* setreg.resp_delim */ + hms_cmds.setreg.term = NULL; /* setreg.term */ + hms_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */ + hms_cmds.getreg.cmd = "r %s\r"; /* getreg.cmd (name) */ + hms_cmds.getreg.resp_delim = " (";/* getreg.resp_delim */ + hms_cmds.getreg.term = ":"; /* getreg.term */ + hms_cmds.getreg.term_cmd = "\003";/* getreg.term_cmd */ + hms_cmds.dump_registers = "r\r"; /* dump_registers */ + hms_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\)"; /* register_pattern */ + hms_cmds.supply_register = hms_supply_register; /* supply_register */ + hms_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */ + hms_cmds.load = "tl\r"; /* download command */ + hms_cmds.loadresp = NULL; /* load response */ + hms_cmds.prompt = ">"; /* monitor command prompt */ + hms_cmds.line_term = "\r"; /* end-of-command delimitor */ + hms_cmds.cmd_end = NULL; /* optional command terminator */ + hms_cmds.target = &hms_ops; /* target operations */ + hms_cmds.stopbits = SERIAL_1_STOPBITS;/* number of stop bits */ + hms_cmds.regnames = hms_regnames; /* registers names */ + hms_cmds.magic = MONITOR_OPS_MAGIC; /* magic */ +} /* init_hms-cmds */ + +static void +hms_open (args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &hms_cmds, from_tty); +} + +int write_dos_tick_delay; + +void +_initialize_remote_hms () +{ + init_hms_cmds() ; + init_monitor_ops (&hms_ops); + + hms_ops.to_shortname = "hms"; + hms_ops.to_longname = "Hitachi Microsystems H8/300 debug monitor"; + hms_ops.to_doc = "Debug via the HMS monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + hms_ops.to_open = hms_open; + /* By trial and error I've found that this delay doesn't break things */ + write_dos_tick_delay = 1; + add_target (&hms_ops); +} + +#if 0 +/* This is kept here because we used to support the H8/500 in this module, + and I haven't done the H8/500 yet */ +#include "defs.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include "gdb_string.h" +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <setjmp.h> +#include <errno.h> +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" +#include "serial.h" +#include "remote-utils.h" +/* External data declarations */ +extern int stop_soon_quietly; /* for wait_for_inferior */ + +/* Forward data declarations */ +extern struct target_ops hms_ops; /* Forward declaration */ + +/* Forward function declarations */ +static void hms_fetch_registers (); +static int hms_store_registers (); +static void hms_close (); +static int hms_clear_breakpoints (); + +extern struct target_ops hms_ops; +static void hms_drain (); +static void add_commands (); +static void remove_commands (); + +static int quiet = 1; /* FIXME - can be removed after Dec '94 */ + + + +/*********************************************************************** + * I/O stuff stolen from remote-eb.c + ***********************************************************************/ + +static int timeout = 2; + +static const char *dev_name; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + hms_open knows that we don't have a file open when the program + starts. */ + +static int before = 0xdead; +static int is_open = 0; +static int after = 0xdead; +int +check_open () +{ + if (before != 0xdead + || after != 0xdead) + printf ("OUTCH! \n"); + if (!is_open) + { + error ("remote device not open"); + } +} + +#define ON 1 +#define OFF 0 + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ +static int +readchar () +{ + int buf; + + buf = SERIAL_READCHAR (desc, timeout); + + if (buf == SERIAL_TIMEOUT) + { + hms_write (".\r\n", 3); + error ("Timeout reading from remote system."); + } + if (buf == SERIAL_ERROR) + { + error ("Serial port error!"); + } + + if (!quiet || remote_debug) + printf_unfiltered ("%c", buf); + + return buf & 0x7f; +} + +static void +flush () +{ + while (1) + { + int b = SERIAL_READCHAR (desc, 0); + if (b == SERIAL_TIMEOUT) + return; + } +} + +static int +readchar_nofail () +{ + int buf; + + buf = SERIAL_READCHAR (desc, timeout); + if (buf == SERIAL_TIMEOUT) + buf = 0; + if (!quiet || remote_debug) + printf_unfiltered ("%c", buf); + + return buf & 0x7f; + +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +static void +expect (string) + char *string; +{ + char *p = string; + char c; + immediate_quit = 1; + while (1) + { + c = readchar (); + if (c == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + { + p = string; + if (c == *p) + p++; + } + } +} + +/* Keep discarding input until we see the hms prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: hms_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a hms_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt () +{ + expect ("HMS>"); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + + while (1) + { + ch = readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from hms_desc and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Read a 32-bit hex word from the hms, preceded by a space */ +static long +get_hex_word () +{ + long val; + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + return val; +} + +/* Called when SIGALRM signal sent due to alarm() timeout. */ + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to hms_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +void +hms_kill (arg, from_tty) + char *arg; + int from_tty; +{ + +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +hms_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + char buffer[100]; + + if (args && *args) + error ("Can't pass arguments to remote hms process."); + + if (execfile == 0 || exec_bfd == 0) + error ("No executable file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + check_open (); + + hms_kill (NULL, NULL); + hms_clear_breakpoints (); + init_wait_for_inferior (); + hms_write_cr (""); + expect_prompt (); + + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication, then a space, + then the baud rate. + */ + +static char * +find_end_of_word (s) + char *s; +{ + while (*s && !isspace (*s)) + s++; + return s; +} + +static char * +get_word (p) + char **p; +{ + char *s = *p; + char *word; + char *copy; + size_t len; + + while (isspace (*s)) + s++; + + word = s; + + len = 0; + + while (*s && !isspace (*s)) + { + s++; + len++; + + } + copy = xmalloc (len + 1); + memcpy (copy, word, len); + copy[len] = 0; + *p = s; + return copy; +} + +static int baudrate = 9600; + +static int +is_baudrate_right () +{ + int ok; + + /* Put this port into NORMAL mode, send the 'normal' character */ + + hms_write ("\001", 1); /* Control A */ + hms_write ("\r\n", 2); /* Cr */ + + while (1) + { + ok = SERIAL_READCHAR (desc, timeout); + if (ok < 0) + break; + } + + hms_write ("r", 1); + + if (readchar_nofail () == 'r') + return 1; + + /* Not the right baudrate, or the board's not on */ + return 0; +} +static void +set_rate () +{ + if (!SERIAL_SETBAUDRATE (desc, baudrate)) + error ("Can't set baudrate"); +} + + + +/* Close out all files and local state before this target loses control. */ + +static void +hms_close (quitting) + int quitting; +{ + /* Clear any break points */ + remove_commands (); + hms_clear_breakpoints (); + sleep (1); /* Let any output make it all the way back */ + if (is_open) + { + SERIAL_WRITE (desc, "R\r\n", 3); + SERIAL_CLOSE (desc); + } + is_open = 0; +} + +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ void +hms_detach (args, from_tty) + char *args; + int from_tty; +{ + if (is_open) + { + hms_clear_breakpoints (); + } + + pop_target (); /* calls hms_close to do the real work + */ + if (from_tty) + printf_filtered ("Ending remote %s debugging\n", + target_shortname); +} + +/* Tell the remote machine to resume. */ + +void +hms_resume (pid, step, sig) + int pid, step; + enum target_signal + sig; +{ + if (step) + { + hms_write_cr ("s"); + expect ("Step>"); + + /* Force the next hms_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type "continue" + to see any. FIXME, this should be fixed. */ + need_artificial_trap = 1; + } + else + { + hms_write_cr ("g"); + expect ("g"); + } +} + +/* Wait until the remote machine stops, then return, storing status in + STATUS just as `wait' would. */ + +int +hms_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + /* Strings to look for. '?' means match any single character. Note + that with the algorithm we use, the initial character of the string + cannot recur in the string, or we will not find some cases of the + string in the input. */ + + static char bpt[] = "At breakpoint:"; + + /* It would be tempting to look for "\n[__exit + 0x8]\n" but that + requires loading symbols with "yc i" and even if we did do that we + don't know that the file has symbols. */ + static char exitmsg[] = "HMS>"; + char *bp = bpt; + char *ep = exitmsg; + + /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. + */ + char swallowed[50]; + + /* Current position in swallowed. */ + char *swallowed_p = swallowed; + + int ch; + int ch_handled; + int old_timeout = timeout; + int + old_immediate_quit = immediate_quit; + int swallowed_cr = 0; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + if (need_artificial_trap != 0) + { + status->kind = + TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + need_artificial_trap--; + return 0; + } + + timeout = 5; /* Don't time out for a while - user program is running. + */ + immediate_quit = 1; /* Helps ability to QUIT */ + while (1) + { + QUIT; /* Let user quit and leave process running */ + ch_handled = 0; + ch = readchar (); + if (ch == *bp) + { + bp++; + if (*bp == '\0') + break; + ch_handled = 1; + + *swallowed_p++ = ch; + } + else + { + bp = bpt; + } + if + (ch == *ep || *ep == '?') + { + ep++; + if (*ep == '\0') + break; + + if (!ch_handled) + *swallowed_p++ = ch; + ch_handled = + 1; + } + else + { + ep = exitmsg; + } + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + for (p = swallowed; p < swallowed_p; ++p) + putchar_unfiltered (*p); + swallowed_p = swallowed; + + if ((ch != '\r' && ch != '\n') || swallowed_cr > 10) + { + putchar_unfiltered (ch); + swallowed_cr = 10; + } + swallowed_cr++; + + } + } + if (*bp == '\0') + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + expect_prompt (); + } + else + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = + TARGET_SIGNAL_STOP; + } + + timeout = old_timeout; + immediate_quit = old_immediate_quit; + return + 0; +} + +/* Return the name of register number REGNO in the form input and + output by hms. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char *rn[] = + REGISTER_NAMES; + + return rn[regno]; +} + +/* Read the remote registers. */ + +static int +gethex (length, start, ok) + unsigned int length; + char *start; + int *ok; +{ + int result = 0; + + while (length--) + { + result <<= 4; + if (*start >= 'a' && *start <= 'f') + { + result += *start - 'a' + 10; + } + else if (*start >= 'A' && + *start <= 'F') + { + result += *start - 'A' + 10; + } + else if + (*start >= '0' && *start <= '9') + { + result += *start - '0'; + } + else + *ok = 0; + start++; + + } + return result; +} +static int +timed_read (buf, n, timeout) + char + *buf; + +{ + int i; + char c; + + i = 0; + while (i < n) + { + c = readchar (); + + if (c == 0) + return i; + buf[i] = c; + i++; + + } + return i; +} + +hms_write (a, l) + char *a; +{ + int i; + + SERIAL_WRITE (desc, a, l); + + if (!quiet || remote_debug) + { + printf_unfiltered ("<"); + for (i = 0; i < l; i++) + { + printf_unfiltered ("%c", a[i]); + } + printf_unfiltered (">"); + } +} + +hms_write_cr (s) + char *s; +{ + hms_write (s, strlen (s)); + hms_write ("\r\n", 2); +} + +#ifdef GDB_TARGET_IS_H8500 + +/* H8/500 monitor reg dump looks like: + + HMS>r + PC:8000 SR:070C .7NZ.. CP:00 DP:00 EP:00 TP:00 BR:00 + R0-R7: FF5A 0001 F4FE F500 0000 F528 F528 F4EE + HMS> + + + */ + +supply_val (n, size, ptr, segptr) + int n; + int size; + char *ptr; + char *segptr; +{ + int ok; + char raw[4]; + switch (size) + { + case 2: + raw[0] = gethex (2, ptr, &ok); + raw[1] = gethex (2, ptr + 2, &ok); + supply_register (n, raw); + break; + case 1: + raw[0] = gethex (2, ptr, &ok); + supply_register (n, raw); + break; + case 4: + { + int v = gethex (4, ptr, &ok); + v |= gethex (2, segptr, &ok) << 16; + raw[0] = 0; + raw[1] = (v >> 16) & 0xff; + raw[2] = (v >> 8) & 0xff; + raw[3] = (v >> 0) & 0xff; + supply_register (n, raw); + } + } + +} +static void +hms_fetch_register (dummy) + int dummy; +{ +#define REGREPLY_SIZE 108 + char linebuf[REGREPLY_SIZE + 1]; + int i; + int s; + int gottok; + + LONGEST reg[NUM_REGS]; + check_open (); + + do + { + + hms_write_cr ("r"); + expect ("r"); + s = timed_read (linebuf + 1, REGREPLY_SIZE, 1); + + linebuf[REGREPLY_SIZE] = 0; + gottok = 0; + if (linebuf[3] == 'P' && + linebuf[4] == 'C' && + linebuf[5] == ':' && + linebuf[105] == 'H' && + linebuf[106] == 'M' && + linebuf[107] == 'S') + { + + /* + 012 + r** + -------1---------2---------3---------4---------5----- + 345678901234567890123456789012345678901234567890123456 + PC:8000 SR:070C .7NZ.. CP:00 DP:00 EP:00 TP:00 BR:00** + ---6---------7---------8---------9--------10---- + 789012345678901234567890123456789012345678901234 + R0-R7: FF5A 0001 F4FE F500 0000 F528 F528 F4EE** + + 56789 + HMS> + */ + gottok = 1; + + + supply_val (PC_REGNUM, 4, linebuf + 6, linebuf + 29); + + supply_val (CCR_REGNUM, 2, linebuf + 14); + supply_val (SEG_C_REGNUM, 1, linebuf + 29); + supply_val (SEG_D_REGNUM, 1, linebuf + 35); + supply_val (SEG_E_REGNUM, 1, linebuf + 41); + supply_val (SEG_T_REGNUM, 1, linebuf + 47); + for (i = 0; i < 8; i++) + { + static int sr[8] = + {35, 35, 35, 35, + 41, 41, 47, 47}; + + char raw[4]; + char *src = linebuf + 64 + 5 * i; + char *segsrc = linebuf + sr[i]; + supply_val (R0_REGNUM + i, 2, src); + supply_val (PR0_REGNUM + i, 4, src, segsrc); + } + } + if (!gottok) + { + hms_write_cr (""); + expect ("HMS>"); + } + } + while (!gottok); +} +#endif + +#ifdef GDB_TARGET_IS_H8300 +static void +hms_fetch_register (dummy) + int dummy; +{ +#define REGREPLY_SIZE 79 + char linebuf[REGREPLY_SIZE + 1]; + int i; + int s; + int gottok; + + ULONGEST reg[NUM_REGS]; + + check_open (); + + do + { + hms_write_cr ("r"); + + s = timed_read (linebuf, 1, 1); + + while (linebuf[0] != 'r') + s = timed_read (linebuf, 1, 1); + + s = timed_read (linebuf + 1, REGREPLY_SIZE - 1, 1); + + linebuf[REGREPLY_SIZE] = 0; + gottok = 0; + if (linebuf[0] == 'r' && + linebuf[3] == 'P' && + linebuf[4] == 'C' && + linebuf[5] == '=' && + linebuf[75] == 'H' && + linebuf[76] == 'M' && + linebuf[77] == 'S') + { + /* + PC=XXXX CCR=XX:XXXXXXXX R0-R7= XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX + 5436789012345678901234567890123456789012345678901234567890123456789012 + 0 1 2 3 4 5 6 + */ + gottok = 1; + + reg[PC_REGNUM] = gethex (4, linebuf + 6, &gottok); + reg[CCR_REGNUM] = gethex (2, linebuf + 15, &gottok); + for (i = 0; i < 8; i++) + { + reg[i] = gethex (4, linebuf + 34 + 5 * i, &gottok); + } + } + } + while (!gottok); + for (i = 0; i < NUM_REGS; i++) + { + char swapped[2]; + + swapped[1] = reg[i]; + swapped[0] = (reg[i]) >> 8; + + supply_register (i, swapped); + } +} +#endif +/* Store register REGNO, or all if REGNO == -1. + Return errno value. */ +static void +hms_store_register (regno) + int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + { + hms_store_register (regno); + } + } + else + { + char *name = get_reg_name (regno); + char buffer[100]; + /* Some regs dont really exist */ + if (!(name[0] == 'p' && name[1] == 'r') + && !(name[0] == 'c' && name[1] == 'y') + && !(name[0] == 't' && name[1] == 'i') + && !(name[0] == 'i' && name[1] == 'n')) + { + sprintf (buffer, "r %s=%x", name, read_register (regno)); + hms_write_cr (buffer); + expect_prompt (); + } + } +} + + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +hms_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static CORE_ADDR +translate_addr (addr) + CORE_ADDR addr; +{ + + return (addr); + +} + + +int +hms_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + + return len; +} + +int +hms_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + bfd_vma addr; + int done; + int todo; + char buffer[100]; + done = 0; + hms_write_cr ("."); + expect_prompt (); + while (done < len) + { + char *ptr = buffer; + int thisgo; + int idx; + + thisgo = len - done; + if (thisgo > 20) + thisgo = 20; + + sprintf (ptr, "M.B %4x =", memaddr + done); + ptr += 10; + for (idx = 0; idx < thisgo; idx++) + { + sprintf (ptr, "%2x ", myaddr[idx + done]); + ptr += 3; + } + hms_write_cr (buffer); + expect_prompt (); + done += thisgo; + } +} + +void +hms_files_info () +{ + char *file = "nothing"; + + if (exec_bfd) + file = bfd_get_filename (exec_bfd); + + if (exec_bfd) +#ifdef __GO32__ + printf_filtered ("\tAttached to DOS asynctsr and running program %s\n", file); +#else + printf_filtered ("\tAttached to %s at %d baud and running program %s\n", dev_name, baudrate, file); +#endif + printf_filtered ("\ton an H8/300 processor.\n"); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. + * sb/sh instructions don't work on unaligned addresses, when TU=1. + */ + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +int +hms_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + /* Align to nearest low 16 bits */ + int i; + + CORE_ADDR start = memaddr; + CORE_ADDR end = memaddr + len - 1; + + int ok = 1; + + /* + AAAA: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX '................' + 012345678901234567890123456789012345678901234567890123456789012345 + 0 1 2 3 4 5 6 + */ + char buffer[66]; + + if (memaddr & 0xf) + abort (); + if (len != 16) + abort (); + + sprintf (buffer, "m %4x %4x", start & 0xffff, end & 0xffff); + + flush (); + hms_write_cr (buffer); + /* drop the echo and newline */ + for (i = 0; i < 13; i++) + readchar (); + + /* Grab the lines as they come out and fill the area */ + /* Skip over cr */ + while (1) + { + int p; + int i; + int addr; + size_t idx; + + char byte[16]; + + buffer[0] = readchar (); + while (buffer[0] == '\r' + || buffer[0] == '\n') + buffer[0] = readchar (); + + if (buffer[0] == 'M') + break; + + for (i = 1; i < 50; i++) + { + buffer[i] = readchar (); + } + /* sometimes we loose characters in the ascii representation of the + data. I don't know where. So just scan for the end of line */ + i = readchar (); + while (i != '\n' && i != '\r') + i = readchar (); + + /* Now parse the line */ + + addr = gethex (4, buffer, &ok); + idx = 6; + for (p = 0; p < 16; p += 2) + { + byte[p] = gethex (2, buffer + idx, &ok); + byte[p + 1] = gethex (2, buffer + idx + 2, &ok); + idx += 5; + } + + for (p = 0; p < 16; p++) + { + if (addr + p >= memaddr && + addr + p < memaddr + len) + { + myaddr[(addr + p) - memaddr] = byte[p]; + + } + + } + } +#ifdef GDB_TARGET_IS_H8500 + expect ("ore>"); +#endif +#ifdef GDB_TARGET_IS_H8300 + expect ("emory>"); +#endif + hms_write_cr ("."); + + expect_prompt (); + return len; +} + + + +#define MAX_BREAKS 16 +static int num_brkpts = 0; +static int +hms_insert_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let hms save instructions */ +{ + check_open (); + + if (num_brkpts < MAX_BREAKS) + { + char buffer[100]; + + num_brkpts++; + sprintf (buffer, "b %x", addr & 0xffff); + hms_write_cr (buffer); + expect_prompt (); + return (0); + } + else + { + fprintf_filtered (gdb_stderr, + "Too many break points, break point not installed\n"); + return (1); + } + +} +static int +hms_remove_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let hms save instructions */ +{ + if (num_brkpts > 0) + { + char buffer[100]; + + num_brkpts--; + sprintf (buffer, "b - %x", addr & 0xffff); + hms_write_cr (buffer); + expect_prompt (); + + } + return (0); +} + +/* Clear the hmss notion of what the break points are */ +static int +hms_clear_breakpoints () +{ + + if (is_open) + { + hms_write_cr ("b -"); + expect_prompt (); + } + num_brkpts = 0; +} +static void +hms_mourn () +{ + hms_clear_breakpoints (); + unpush_target (&hms_ops); + generic_mourn_inferior (); +} + +/* Put a command string, in args, out to the hms. The hms is assumed to + be in raw mode, all writing/reading done through desc. + Ouput from the hms is placed on the users terminal until the + prompt from the hms is seen. + FIXME: Can't handle commands that take input. */ + +void +hms_com (args, fromtty) + char *args; + int fromtty; +{ + check_open (); + + if (!args) + return; + + /* Clear all input so only command relative output is displayed */ + + hms_write_cr (args); +/* hms_write ("\030", 1); */ + expect_prompt (); +} + +static void +hms_open (name, from_tty) + char *name; + int from_tty; +{ + unsigned int prl; + char *p; + + if (name == 0) + { + name = ""; + } + if (is_open) + hms_close (0); + dev_name = strdup (name); + + if (!(desc = SERIAL_OPEN (dev_name))) + perror_with_name ((char *) dev_name); + + SERIAL_RAW (desc); + is_open = 1; + push_target (&hms_ops); + dcache_ptr = dcache_init (hms_read_inferior_memory, + hms_write_inferior_memory); + remote_dcache = 1; + /* Hello? Are you there? */ + SERIAL_WRITE (desc, "\r\n", 2); + expect_prompt (); + + /* Clear any break points */ + hms_clear_breakpoints (); + + printf_filtered ("Connected to remote board running HMS monitor.\n"); + add_commands (); +/* hms_drain (); */ +} + +/* Define the target subroutine names */ + +struct target_ops hms_ops ; + +static void +init_hms_ops(void) +{ + hms_ops.to_shortname = "hms"; + hms_ops.to_longname = "Remote HMS monitor"; + hms_ops.to_doc = "Use the H8 evaluation board running the HMS monitor connected\n\ +by a serial line."; + hms_ops.to_open = hms_open; + hms_ops.to_close = hms_close; + hms_ops.to_attach = 0; + hms_ops.to_post_attach = NULL; + hms_ops.to_require_attach = NULL; + hms_ops.to_detach = hms_detach; + hms_ops.to_require_detach = NULL; + hms_ops.to_resume = hms_resume; + hms_ops.to_wait = hms_wait; + hms_ops.to_post_wait = NULL; + hms_ops.to_fetch_registers = hms_fetch_register; + hms_ops.to_store_registers = hms_store_register; + hms_ops.to_prepare_to_store = hms_prepare_to_store; + hms_ops.to_xfer_memory = hms_xfer_inferior_memory; + hms_ops.to_files_info = hms_files_info; + hms_ops.to_insert_breakpoint = hms_insert_breakpoint; + hms_ops.to_remove_breakpoint = hms_remove_breakpoint; + hms_ops.to_terminal_init = 0; + hms_ops.to_terminal_inferior = 0; + hms_ops.to_terminal_ours_for_output = 0; + hms_ops.to_terminal_ours = 0; + hms_ops.to_terminal_info = 0; + hms_ops.to_kill = hms_kill; + hms_ops.to_load = generic_load; + hms_ops.to_lookup_symbol = 0; + hms_ops.to_create_inferior = hms_create_inferior; + hms_ops.to_post_startup_inferior = NULL; + hms_ops.to_acknowledge_created_inferior = NULL; + hms_ops.to_clone_and_follow_inferior = NULL; + hms_ops.to_post_follow_inferior_by_clone = NULL; + hms_ops.to_insert_fork_catchpoint = NULL; + hms_ops.to_remove_fork_catchpoint = NULL; + hms_ops.to_insert_vfork_catchpoint = NULL; + hms_ops.to_remove_vfork_catchpoint = NULL; + hms_ops.to_has_forked = NULL; + hms_ops.to_has_vforked = NULL; + hms_ops.to_can_follow_vfork_prior_to_exec = NULL; + hms_ops.to_post_follow_vfork = NULL; + hms_ops.to_insert_exec_catchpoint = NULL; + hms_ops.to_remove_exec_catchpoint = NULL; + hms_ops.to_has_execd = NULL; + hms_ops.to_reported_exec_events_per_exec_call = NULL; + hms_ops.to_has_exited = NULL; + hms_ops.to_mourn_inferior = hms_mourn; + hms_ops.to_can_run = 0; + hms_ops.to_notice_signals = 0; + hms_ops.to_thread_alive = 0; + hms_ops.to_stop = 0; + hms_ops.to_pid_to_exec_file = NULL; + hms_ops.to_core_file_to_sym_file = NULL; + hms_ops.to_stratum = process_stratum; + hms_ops.DONT_USE = 0; + hms_ops.to_has_all_memory = 1; + hms_ops.to_has_memory = 1; + hms_ops.to_has_stack = 1; + hms_ops.to_has_registers = 1; + hms_ops.to_has_execution = 1; + hms_ops.to_sections = 0; + hms_ops.to_sections_end = 0; + hms_ops.to_magic = OPS_MAGIC; +}; + +hms_quiet () /* FIXME - this routine can be removed after Dec '94 */ +{ + quiet = !quiet; + if (quiet) + printf_filtered ("Snoop disabled\n"); + else + printf_filtered ("Snoop enabled\n"); + + printf_filtered ("`snoop' is obsolete, please use `set remotedebug'.\n"); +} + +hms_device (s) + char *s; +{ + if (s) + { + dev_name = get_word (&s); + } +} + +static +hms_speed (s) + char *s; +{ + check_open (); + + if (s) + { + char buffer[100]; + int newrate = atoi (s); + int which = 0; + + if (SERIAL_SETBAUDRATE (desc, newrate)) + error ("Can't use %d baud\n", newrate); + + printf_filtered ("Checking target is in sync\n"); + + printf_filtered ("Sending commands to set target to %d\n", + baudrate); + + sprintf (buffer, "tm %d. N 8 1", baudrate); + hms_write_cr (buffer); + } +} + +/***********************************************************************/ + +static void +hms_drain (args, fromtty) + char *args; + int fromtty; +{ + int c; + while (1) + { + c = SERIAL_READCHAR (desc, 1); + if (c == SERIAL_TIMEOUT) + break; + if (c == SERIAL_ERROR) + break; + if (c > ' ' && c < 127) + printf ("%c", c & 0xff); + else + printf ("<%x>", c & 0xff); + } +} + +static void +add_commands () +{ + + add_com ("hms_drain", class_obscure, hms_drain, + "Drain pending hms text buffers."); +} + +static void +remove_commands () +{ + extern struct cmd_list_element *cmdlist; + delete_cmd ("hms-drain", &cmdlist); +} + + +void +_initialize_remote_hms () +{ + init_hms_ops() ; + add_target (&hms_ops); + + add_com ("hms <command>", class_obscure, hms_com, + "Send a command to the HMS monitor."); + + /* FIXME - hms_quiet and `snoop' can be removed after Dec '94 */ + add_com ("snoop", class_obscure, hms_quiet, + "Show what commands are going to the monitor (OBSOLETE - see 'set remotedebug')"); + + add_com ("device", class_obscure, hms_device, + "Set the terminal line for HMS communications"); + + add_com ("speed", class_obscure, hms_speed, + "Set the terminal line speed for HMS communications"); + + dev_name = NULL; +} +#endif + |