/* Remote debugging interface for boot monitors, for GDB.
- Copyright 1990, 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
- Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
+ Copyright 1990, 1991, 1992, 1993, 1995, 1996
+ Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
+ Resurrected from the ashes by Stu Grossman.
This file is part of GDB.
(or possibly TELNET) stream to a terminal multiplexor,
which in turn talks to the target board. */
+/* FIXME 32x64: This code assumes that registers and addresses are at
+ most 32 bits long. If they can be larger, you will need to declare
+ values as LONGEST and use %llx or some such to print values when
+ building commands to send to the monitor. Since we don't know of
+ any actual 64-bit targets with ROM monitors that use this code,
+ it's not an issue right now. -sts 4/18/96 */
+
#include "defs.h"
#include "gdbcore.h"
#include "target.h"
#include <varargs.h>
#endif
#include <signal.h>
+#include <ctype.h>
#include "gdb_string.h"
#include <sys/types.h>
#include "command.h"
#include "monitor.h"
#include "gdbcmd.h"
#include "inferior.h"
-#include "regex.h"
+#include "gnu-regex.h"
#include "dcache.h"
+#include "srec.h"
static int readchar PARAMS ((int timeout));
static void monitor_command PARAMS ((char *args, int fromtty));
-static void monitor_load_srec PARAMS ((char *args));
-
-static int monitor_make_srec PARAMS ((char *buffer, int type,
- CORE_ADDR memaddr,
- unsigned char *myaddr, int len));
static void monitor_fetch_register PARAMS ((int regno));
static void monitor_store_register PARAMS ((int regno));
-static void monitor_close PARAMS ((int quitting));
static void monitor_detach PARAMS ((char *args, int from_tty));
static void monitor_resume PARAMS ((int pid, int step, enum target_signal sig));
static void monitor_interrupt PARAMS ((int signo));
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));
static int from_hex PARAMS ((int a));
static unsigned long get_hex_word PARAMS ((void));
monitor_wait wakes up. */
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. */
+
+static void
+monitor_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 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);
+ }
+}
/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo.
Works just like printf. */
vsprintf (sndbuf, pattern, args);
if (remote_debug > 0)
- fputs_unfiltered (sndbuf, gdb_stderr);
+ monitor_debug ("sent -->", sndbuf, "<--");
len = strlen (sndbuf);
va_list args;
char sndbuf[2000];
int len;
- int i, c;
#ifdef ANSI_PROTOTYPES
va_start (args, pattern);
vsprintf (sndbuf, pattern, args);
if (remote_debug > 0)
- fputs_unfiltered (sndbuf, gdb_stderr);
+ monitor_debug ("sent -->", sndbuf, "<--");
len = strlen (sndbuf);
if (SERIAL_WRITE(monitor_desc, sndbuf, len))
fprintf_unfiltered (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno));
- for (i = 0; i < len; i++)
- {
- trycr:
- c = readchar (timeout);
-
- if (c != sndbuf[i])
- {
- /* Don't fail if we sent a ^C, they're never echoed */
- if (sndbuf[i] == '\003')
- continue;
-#if 0
- if (sndbuf[i] == '\r'
- && c == '\n')
- goto trycr;
-#endif
- warning ("monitor_printf: Bad echo. Sent: \"%s\", Got: \"%.*s%c\".",
- sndbuf, i, sndbuf, c);
- }
- }
+ /* We used to expect that the next immediate output was the characters we
+ just output, but sometimes some extra junk appeared before the characters
+ we expected, like an extra prompt, or a portmaster sending telnet negotiations.
+ So, just start searching for what we sent, and skip anything unknown. */
+ monitor_expect (sndbuf, (char *)0, 0);
}
/* Read a character from the remote system, doing all the fancy
int timeout;
{
int c;
+ static enum { last_random, last_nl, last_cr, last_crnl } state = last_random;
+ int looping;
- c = SERIAL_READCHAR (monitor_desc, timeout);
+ do
+ {
+ looping = 0;
+ c = SERIAL_READCHAR (monitor_desc, timeout);
- if (remote_debug > 0)
- fputc_unfiltered (c, gdb_stderr);
+ if (c >= 0)
+ {
+ c &= 0x7f;
+ if (remote_debug > 0)
+ {
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ monitor_debug ("read -->", buf, "<--");
+ }
+ }
+
+ /* Canonicialize \n\r combinations into one \r */
+ if ((current_monitor->flags & MO_HANDLE_NL) != 0)
+ {
+ if ((c == '\r' && state == last_nl)
+ || (c == '\n' && state == last_cr))
+ {
+ state = last_crnl;
+ looping = 1;
+ }
+ else if (c == '\r')
+ state = last_cr;
+ else if (c != '\n')
+ state = last_random;
+ else
+ {
+ state = last_nl;
+ c = '\r';
+ }
+ }
+ }
+ while (looping);
if (c >= 0)
- return c & 0x7f;
+ return c;
if (c == SERIAL_TIMEOUT)
#ifdef MAINTENANCE_CMDS
else
c = readchar (timeout);
- if (c == *p++)
+ /* Don't expect any ^C sent to be echoed */
+
+ if (*p == '\003' || c == *p)
{
+ p++;
if (*p == '\0')
{
immediate_quit = 0;
/* Search for a regexp. */
-int
+static int
monitor_expect_regexp (pat, buf, buflen)
struct re_pattern_buffer *pat;
char *buf;
char *buf;
int buflen;
{
- return monitor_expect (PROMPT, buf, buflen);
+ return monitor_expect (current_monitor->prompt, buf, buflen);
}
/* Get N 32-bit words from remote, each preceded by a space, and put
if (current_monitor->stop)
{
monitor_stop ();
- monitor_expect_prompt (NULL, 0);
+ if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0)
+ {
+ monitor_expect_prompt (NULL, 0);
+ }
}
/* wake up the monitor and see if it's alive */
for (p = mon_ops->init; *p != NULL; p++)
{
- monitor_printf (*p);
+ /* Some of the characters we send may not be echoed,
+ but we hope to get a prompt at the end of it all. */
+
+ if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0)
+ monitor_printf(*p);
+ else
+ monitor_printf_noecho (*p);
monitor_expect_prompt (NULL, 0);
}
/* Close out all files and local state before this target loses
control. */
-static void
+void
monitor_close (quitting)
int quitting;
{
int regno;
char *valstr;
{
- unsigned LONGEST val;
+ unsigned int val;
unsigned char regbuf[MAX_REGISTER_RAW_SIZE];
char *p;
int pid, step;
enum target_signal sig;
{
+ /* Some monitors require a different command when starting a program */
+ if (current_monitor->flags & MO_RUN_FIRST_TIME && first_time == 1)
+ {
+ first_time = 0;
+ monitor_printf ("run\r");
+ if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT)
+ dump_reg_flag = 1;
+ return;
+ }
dcache_flush (remote_dcache);
if (step)
- monitor_printf (STEP_CMD);
+ monitor_printf (current_monitor->step);
else
{
- monitor_printf (CONT_CMD);
+ monitor_printf (current_monitor->cont);
if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT)
dump_reg_flag = 1;
}
}
-/* Parse the output of a register dump command. A monitor specific regexp is
- used to extract individual register descriptions of the form REG=VAL. Each
- description is split up into a name and a value string which are passed down
- to monitor specific code. */
+/* Parse the output of a register dump command. A monitor specific
+ regexp is used to extract individual register descriptions of the
+ 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 *
parse_register_dump (buf, len)
{
int regnamelen, vallen;
char *regname, *val;
-/* Element 0 points to start of register name, and element 1 points to the
- start of the register value. */
+ /* Element 0 points to start of register name, and element 1
+ points to the start of the register value. */
struct re_registers register_strings;
if (re_search (®ister_pattern, buf, len, 0, len,
char regbuf[MAX_REGISTER_RAW_SIZE * 2 + 1];
int i;
- name = REGNAMES (regno);
+ name = current_monitor->regnames[regno];
if (!name)
{
monitor_printf (current_monitor->getreg.cmd, name);
- /* If RESP_DELIM is specified, we search for that as a leading delimiter for
- the register value. Otherwise, we just start searching from the start of
- the buf. */
+ /* If RESP_DELIM is specified, we search for that as a leading
+ delimiter for the register value. Otherwise, we just start
+ searching from the start of the buf. */
if (current_monitor->getreg.resp_delim)
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)
+ {
+ int c;
+ c = readchar (timeout);
+ while (c == ' ')
+ c = readchar (timeout);
+ if ((c == '0') && ((c = readchar (timeout)) == 'x'))
+ ;
+ else
+ error ("Bad value returned from monitor while fetching register %x.",
+ regno);
+ }
+
/* Read upto the maximum number of hex digits for this register, skipping
spaces, but stop reading if something else is seen. Some monitors
like to drop leading zeros. */
regbuf[i] = '\000'; /* terminate the number */
- /* If TERM is present, we wait for that to show up. Also, (if TERM is
- present), we will send TERM_CMD if that is present. In any case, we collect
- all of the output into buf, and then wait for the normal prompt. */
+ /* If TERM is present, we wait for that to show up. Also, (if TERM
+ is present), we will send TERM_CMD if that is present. In any
+ case, we collect all of the output into buf, and then wait for
+ the normal prompt. */
if (current_monitor->getreg.term)
{
{
char buf[200];
int resp_len;
+
monitor_printf (current_monitor->dump_registers);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
parse_register_dump (buf, resp_len);
int regno;
{
char *name;
- unsigned LONGEST val;
+ unsigned int val;
- name = REGNAMES (regno);
+ name = current_monitor->regnames[regno];
if (!name)
return;
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...) */
+/* 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...) */
monitor_expect_prompt (NULL, 0);
}
char *myaddr;
int len;
{
- unsigned LONGEST val;
+ unsigned int val;
char *cmd;
int i;
val = extract_unsigned_integer (myaddr, len);
- monitor_printf (cmd, memaddr, val);
+ if (current_monitor->flags & MO_NO_ECHO_ON_SETMEM)
+ monitor_printf_noecho (cmd, memaddr, val);
+ else
+ monitor_printf (cmd, memaddr, val);
monitor_expect_prompt (NULL, 0);
char *myaddr;
int len;
{
- unsigned LONGEST val;
- char membuf[sizeof(LONGEST) * 2 + 1];
+ unsigned int val;
+ char membuf[sizeof(int) * 2 + 1];
char *p;
char *cmd;
int i;
the buf. */
if (current_monitor->getmem.resp_delim)
- monitor_expect_regexp (getmem_resp_delim_pattern, NULL, 0);
+ monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0);
/* Now, read the appropriate number of hex digits for this loc, skipping
spaces. */
+ /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set */
+ if (current_monitor->flags & MO_HEX_PREFIX)
+ {
+ int c;
+ c = readchar (timeout);
+ while (c == ' ')
+ c = readchar (timeout);
+ if ((c == '0') && ((c = readchar (timeout)) == 'x'))
+ ;
+ else
+ error ("monitor_read_memory_single (0x%x): bad response from monitor: %.*s%c.",
+ memaddr, i, membuf, c);
+ }
for (i = 0; i < len * 2; i++)
{
int c;
char *myaddr;
int len;
{
- unsigned LONGEST val;
+ unsigned int val;
unsigned char regbuf[MAX_REGISTER_RAW_SIZE];
char buf[512];
char *p, *p1;
if (args && (*args != '\000'))
error ("Args are not supported by the monitor.");
+ first_time = 1;
clear_proceed_status ();
proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
}
{
breakaddr[i] = addr;
monitor_read_memory (addr, shadow, sizeof (break_insn));
- monitor_printf (SET_BREAK_CMD, addr);
+ monitor_printf (current_monitor->set_break, addr);
monitor_expect_prompt (NULL, 0);
return 0;
}
breakaddr[i] = 0;
/* some monitors remove breakpoints based on the address */
if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR)
- monitor_printf (CLR_BREAK_CMD, addr);
+ monitor_printf (current_monitor->clr_break, addr);
else
- monitor_printf (CLR_BREAK_CMD, i);
+ monitor_printf (current_monitor->clr_break, i);
monitor_expect_prompt (NULL, 0);
return 0;
}
return 1;
}
+/* monitor_wait_srec_ack -- wait for the target to send an acknowledgement for
+ an S-record. Return non-zero if the ACK is received properly. */
+
+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) == '+';
+}
+
/* monitor_load -- download a file. */
static void
if (current_monitor->load_routine)
current_monitor->load_routine (monitor_desc, file, hashmark);
else
- monitor_load_srec (file);
+ { /* The default is ascii S-records */
+ 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,
+ current_monitor->flags & MO_SREC_ACK ?
+ monitor_wait_srec_ack : NULL);
+
+ monitor_expect_prompt (NULL, 0);
+ }
/* Finally, make the PC point at the start address */
static void
monitor_stop ()
{
+ if ((current_monitor->flags & MO_SEND_BREAK_ON_STOP) != 0)
+ SERIAL_SEND_BREAK (monitor_desc);
if (current_monitor->stop)
monitor_printf_noecho (current_monitor->stop);
}
if (monitor_desc == NULL)
error ("monitor target not open.");
- p = PROMPT;
+ p = current_monitor->prompt;
/* Send the command. Note that if no args were supplied, then we're
just sending the monitor a newline, which is sometimes useful. */
fputs_unfiltered (buf, gdb_stdout); /* Output the response */
}
-/* Download a binary file by converting it to S records. */
-
-static void
-monitor_load_srec (args)
- char *args;
-{
- bfd *abfd;
- asection *s;
- char *buffer, srec[1024];
- int i;
- int srec_frame = 32;
- int reclen;
-
- buffer = alloca (srec_frame * 2 + 256);
-
- abfd = bfd_openr (args, 0);
- if (!abfd)
- {
- printf_filtered ("Unable to open file %s\n", args);
- return;
- }
-
- if (bfd_check_format (abfd, bfd_object) == 0)
- {
- printf_filtered ("File is not an object file\n");
- return;
- }
-
- monitor_printf (LOAD_CMD); /* tell the monitor to load */
- if (current_monitor->loadresp)
- monitor_expect (current_monitor->loadresp, NULL, 0);
-
- 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)
- {
- numbytes = min (srec_frame, s->_raw_size - i);
-
- bfd_get_section_contents (abfd, s, buffer, i, numbytes);
-
- reclen = monitor_make_srec (srec, 'd', s->vma + i, buffer, numbytes);
-
- monitor_printf_noecho ("%.*s\r", reclen, srec);
-
- 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 = monitor_make_srec (srec, 't', abfd->start_address, NULL, 0);
-
- monitor_printf_noecho ("%.*s\r", reclen, srec);
-
- monitor_printf_noecho ("\r\r"); /* Some monitors need these to wake up */
-
- monitor_expect_prompt (NULL, 0);
-
- SERIAL_FLUSH_INPUT (monitor_desc);
-}
-
-/*
- * monitor_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<type><length><address><data><checksum>
- *
- * 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
-monitor_make_srec (buffer, type, memaddr, myaddr, len)
- char *buffer;
- int type;
- CORE_ADDR memaddr;
- unsigned char *myaddr;
- int len;
-{
- unsigned char checksum;
- int i;
- char *buf;
- static char hextab[] = "0123456789ABCDEF";
- static char data_code_table[] = { 0,0,1,2,3};
- static char term_code_table[] = { 0,0,9,8,7};
- int addr_size; /* Number of bytes in the record */
- int type_code;
- buf = buffer;
-
- checksum = 0;
-
- addr_size = 2;
- if (memaddr > 0xffffff)
- addr_size = 4;
- else if (memaddr > 0xffff)
- addr_size = 3;
- else
- addr_size = 2;
-
- switch (type)
- {
- case 't':
- type_code = term_code_table[addr_size];
- break;
- case 'd':
- type_code = data_code_table[addr_size];
- break;
- default:
- abort();
- }
- /* Create the header for the srec. addr_size is the number of bytes in the address,
- and 1 is the number of bytes in the count. */
-
- switch (addr_size)
- {
- case 4:
- sprintf (buf, "S%d%02X%08X", type_code, len + addr_size + 1, memaddr);
- buf += 12;
- break;
- case 3:
- sprintf (buf, "S%d%02X%06X", type_code, len + addr_size + 1, memaddr);
- buf += 10;
- break;
- case 2:
- sprintf (buf, "S%d%02X%04X", type_code, len + addr_size + 1, memaddr);
- buf += 8;
- break;
- }
-
-/* 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 += (len + addr_size + 1 /* Packet length */
- + (memaddr & 0xff) /* Address... */
- + ((memaddr >> 8) & 0xff)
- + ((memaddr >> 16) & 0xff)
- + ((memaddr >> 24) & 0xff));
-
- /* build the srecord */
- for (i = 0; i < len; i++)
- {
- *buf++ = hextab [myaddr[i] >> 4];
- *buf++ = hextab [myaddr[i] & 0xf];
- checksum += myaddr[i];
- }
-
- checksum = ~checksum;
-
- *buf++ = hextab[checksum >> 4];
- *buf++ = hextab[checksum & 0xf];
-
- return buf - buffer;
-}
-
/* Convert hex digit A to a number. */
static int