#include "gdbcore.h"
#include "target.h"
#include "wait.h"
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
#include <varargs.h>
+#endif
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include "gdbcmd.h"
#include "inferior.h"
#include "regex.h"
+#include "dcache.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 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_interrupt_twice PARAMS ((int signo));
+static void monitor_interrupt_query PARAMS ((void));
+static void monitor_wait_cleanup PARAMS ((int old_timeout));
+
static int monitor_wait PARAMS ((int pid, struct target_waitstatus *status));
static void monitor_fetch_registers PARAMS ((int regno));
static void monitor_store_registers PARAMS ((int regno));
static void monitor_mourn_inferior PARAMS ((void));
static void monitor_stop PARAMS ((void));
+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 from_hex PARAMS ((int a));
static unsigned long get_hex_word PARAMS ((void));
static int timeout = 30;
+static int in_monitor_wait = 0; /* Non-zero means we are in monitor_wait() */
+
+static void (*ofunc)(); /* Old SIGINT signal handler */
+
/* Descriptor for I/O to remote machine. Initialize it to NULL so
that monitor_open knows that we don't have a file open when the
program starts. */
static int dump_reg_flag; /* Non-zero means do a dump_registers cmd when
monitor_wait wakes up. */
-/* monitor_printf -- send data to monitor. Works just like printf. */
+static DCACHE *remote_dcache;
+
+/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo.
+ Works just like printf. */
void
-monitor_printf (va_alist)
+#ifdef ANSI_PROTOTYPES
+monitor_printf_noecho (char *pattern, ...)
+#else
+monitor_printf_noecho (va_alist)
va_dcl
+#endif
{
va_list args;
- char *pattern;
- char buf[2000];
+ char sndbuf[2000];
int len;
+#if ANSI_PROTOTYPES
+ va_start (args, pattern);
+#else
+ char *pattern;
va_start (args);
+ pattern = va_arg (args, char *);
+#endif
+
+ vsprintf (sndbuf, pattern, args);
+
+ if (remote_debug > 0)
+ fputs_unfiltered (sndbuf, gdb_stderr);
+
+ len = strlen (sndbuf);
+
+ if (len + 1 > sizeof sndbuf)
+ abort ();
+
+ if (SERIAL_WRITE(monitor_desc, sndbuf, len))
+ fprintf_unfiltered (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno));
+}
+
+/* monitor_printf -- Send data to monitor and check the echo. Works just like
+ printf. */
+
+void
+#ifdef ANSI_PROTOTYPES
+monitor_printf (char *pattern, ...)
+#else
+monitor_printf (va_alist)
+ va_dcl
+#endif
+{
+ va_list args;
+ char sndbuf[2000];
+ int len;
+ int i, c;
+#ifdef ANSI_PROTOTYPES
+ va_start (args, pattern);
+#else
+ char *pattern;
+ va_start (args);
pattern = va_arg (args, char *);
+#endif
- vsprintf (buf, pattern, args);
+ vsprintf (sndbuf, pattern, args);
if (remote_debug > 0)
- fputs_unfiltered (buf, gdb_stderr);
+ fputs_unfiltered (sndbuf, gdb_stderr);
- len = strlen (buf);
+ len = strlen (sndbuf);
- if (len + 1 > sizeof buf)
+ if (len + 1 > sizeof sndbuf)
abort ();
- if (SERIAL_WRITE(monitor_desc, buf, len))
+ 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);
+ }
+ }
}
/* Read a character from the remote system, doing all the fancy
return c & 0x7f;
if (c == SERIAL_TIMEOUT)
- error ("Timeout reading from remote system.");
+#ifdef MAINTENANCE_CMDS
+ if (in_monitor_wait) /* Watchdog went off */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+ else
+#endif
+ error ("Timeout reading from remote system.");
perror_with_name ("remote-monitor");
}
/* See if we can wake up the monitor. First, try sending a stop sequence,
then send the init strings. Last, remove all breakpoints. */
- monitor_stop ();
+ if (current_monitor->stop)
+ {
+ monitor_stop ();
+ monitor_expect_prompt (NULL, 0);
+ }
/* wake up the monitor and see if it's alive */
for (p = mon_ops->init; *p != NULL; p++)
monitor_expect_prompt (NULL, 0);
}
+ SERIAL_FLUSH_INPUT (monitor_desc);
+
/* Remove all breakpoints */
if (mon_ops->clr_all_break)
inferior_pid = 42000; /* Make run command think we are busy... */
- monitor_printf ("\r"); /* Give monitor_wait something to read */
+ /* Give monitor_wait something to read */
+
+ monitor_printf (current_monitor->line_term);
+
+ remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory);
start_remote ();
}
int pid, step;
enum target_signal sig;
{
+ dcache_flush (remote_dcache);
if (step)
monitor_printf (STEP_CMD);
else
}
}
+/* Send ^C to target to halt it. Target will respond, and send us a
+ packet. */
+
+static void
+monitor_interrupt (signo)
+ int signo;
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, monitor_interrupt_twice);
+
+ if (remote_debug)
+ printf_unfiltered ("monitor_interrupt called\n");
+
+ target_stop ();
+}
+
+/* The user typed ^C twice. */
+
+static void
+monitor_interrupt_twice (signo)
+ int signo;
+{
+ signal (signo, ofunc);
+
+ monitor_interrupt_query ();
+
+ signal (signo, monitor_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+monitor_interrupt_query ()
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ return_to_top_level (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+static void
+monitor_wait_cleanup (old_timeout)
+ int old_timeout;
+{
+ timeout = old_timeout;
+ signal (SIGINT, ofunc);
+ in_monitor_wait = 0;
+}
+
/* Wait until the remote machine stops, then return, storing status in
status just as `wait' would. */
int old_timeout = timeout;
char buf[1024];
int resp_len;
+ struct cleanup *old_chain;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
+ old_chain = make_cleanup (monitor_wait_cleanup, old_timeout);
+
+#ifdef MAINTENANCE_CMDS
+ in_monitor_wait = 1;
+ timeout = watchdog > 0 ? watchdog : -1;
+#else
timeout = -1; /* Don't time out -- user program is running. */
+#endif
+
+ ofunc = (void (*)()) signal (SIGINT, monitor_interrupt);
do
{
}
while (resp_len < 0);
+ signal (SIGINT, ofunc);
+
timeout = old_timeout;
if (dump_reg_flag && current_monitor->dump_registers)
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
+ discard_cleanups (old_chain);
+
+ in_monitor_wait = 0;
+
return inferior_pid;
}
monitor_fetch_register (regno)
int regno;
{
- char buf[200];
- char *p;
char *name;
- int resp_len;
static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
+ char regbuf[MAX_REGISTER_RAW_SIZE * 2 + 1];
+ int i;
name = REGNAMES (regno);
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 (current_monitor->getreg.resp_delim)
+ monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
+
+/* Now, read the appropriate number of hex digits for this register, skipping
+ spaces. */
+
+ for (i = 0; i < REGISTER_RAW_SIZE (regno) * 2; i++)
+ {
+ int c;
+
+ while (1)
+ {
+ c = readchar (timeout);
+ if (isxdigit (c))
+ break;
+ if (c == ' ')
+ continue;
+
+ error ("monitor_fetch_register (%d): bad response from monitor: %.*s%c.",
+ regno, i, regbuf, c);
+ }
+
+ regbuf[i] = c;
+ }
+
+ 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 (current_monitor->getreg.term)
{
- resp_len = monitor_expect (current_monitor->getreg.term, buf, sizeof buf); /* get response */
-
- if (resp_len <= 0)
- error ("monitor_fetch_register (%d): excessive response from monitor: %.*s.",
- regno, resp_len, buf);
+ monitor_expect (current_monitor->getreg.term, NULL, 0); /* get response */
if (current_monitor->getreg.term_cmd)
{
- SERIAL_WRITE (monitor_desc, current_monitor->getreg.term_cmd,
- strlen (current_monitor->getreg.term_cmd));
+ monitor_printf (current_monitor->getreg.term_cmd);
monitor_expect_prompt (NULL, 0);
}
}
else
- resp_len = monitor_expect_prompt (buf, sizeof buf); /* get response */
+ monitor_expect_prompt (NULL, 0); /* get response */
+ monitor_supply_register (regno, regbuf);
+}
- /* 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. */
+/* Read the remote registers into the block regs. */
- if (current_monitor->getreg.resp_delim)
+static void monitor_dump_regs ()
+{
+ if (current_monitor->dump_registers)
{
- p = strstr (buf, current_monitor->getreg.resp_delim);
- if (!p)
- error ("monitor_fetch_register (%d): bad response from monitor: %.*s.",
- regno, resp_len, buf);
- p += strlen (current_monitor->getreg.resp_delim);
+ 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);
}
else
- p = buf;
-
- monitor_supply_register (regno, p);
+ abort(); /* Need some way to read registers */
}
-/* Read the remote registers into the block regs. */
-
static void
monitor_fetch_registers (regno)
int regno;
{
- if (regno >= 0)
+ if (current_monitor->getreg.cmd)
{
- monitor_fetch_register (regno);
- return;
- }
+ if (regno >= 0)
+ {
+ monitor_fetch_register (regno);
+ return;
+ }
- for (regno = 0; regno < NUM_REGS; regno++)
- monitor_fetch_register (regno);
+ for (regno = 0; regno < NUM_REGS; regno++)
+ monitor_fetch_register (regno);
+ }
+ else {
+ monitor_dump_regs ();
+ }
}
/* Store register REGNO, or all if REGNO == 0. Return errno value. */
return len;
}
+/* This is an alternate form of monitor_read_memory which is used for monitors
+ which can only read a single byte/word/etc. at a time. */
+
+static int
+monitor_read_memory_single (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ unsigned LONGEST val;
+ char membuf[sizeof(LONGEST) * 2 + 1];
+ char *p;
+ char *cmd;
+ int i;
+
+ if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->getmem.cmdll)
+ {
+ len = 8;
+ cmd = current_monitor->getmem.cmdll;
+ }
+ else if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->getmem.cmdl)
+ {
+ len = 4;
+ cmd = current_monitor->getmem.cmdl;
+ }
+ else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->getmem.cmdw)
+ {
+ len = 2;
+ cmd = current_monitor->getmem.cmdw;
+ }
+ else
+ {
+ len = 1;
+ cmd = current_monitor->getmem.cmdb;
+ }
+
+/* Send the examine command. */
+
+ monitor_printf (cmd, memaddr);
+
+/* 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->getmem.resp_delim)
+ monitor_expect (current_monitor->getmem.resp_delim, NULL, 0);
+
+/* Now, read the appropriate number of hex digits for this loc, skipping
+ spaces. */
+
+ for (i = 0; i < len * 2; i++)
+ {
+ int c;
+
+ while (1)
+ {
+ c = readchar (timeout);
+ if (isxdigit (c))
+ break;
+ if (c == ' ')
+ continue;
+
+ error ("monitor_read_memory_single (0x%x): bad response from monitor: %.*s%c.",
+ memaddr, i, membuf, c);
+ }
+
+ membuf[i] = c;
+ }
+
+ membuf[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 (current_monitor->getmem.term)
+ {
+ monitor_expect (current_monitor->getmem.term, NULL, 0); /* get response */
+
+ if (current_monitor->getmem.term_cmd)
+ {
+ monitor_printf (current_monitor->getmem.term_cmd);
+ monitor_expect_prompt (NULL, 0);
+ }
+ }
+ else
+ monitor_expect_prompt (NULL, 0); /* get response */
+
+ p = membuf;
+ val = strtoul (membuf, &p, 16);
+
+ if (val == 0 && membuf == p)
+ error ("monitor_read_memory_single (0x%x): bad value from monitor: %s.",
+ memaddr, membuf);
+
+ /* supply register stores in target byte order, so swap here */
+
+ store_unsigned_integer (myaddr, len, val);
+
+ 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. */
int resp_len;
int i;
+ if (current_monitor->flags & MO_GETMEM_READ_SINGLE)
+ return monitor_read_memory_single (memaddr, myaddr, len);
+
len = min (len, 16);
/* See if xfer would cross a 16 byte boundary. If so, clip it. */
p = buf;
- while (*p != '\r') /* Skip command echo and line delim */
- p++;
-
/* If RESP_DELIM is specified, we search for that as a leading delimiter for
the values. Otherwise, we just start searching from the start of the buf.
*/
return len;
}
-/* FIXME-someday! merge these two. */
-
static int
monitor_xfer_memory (memaddr, myaddr, len, write, target)
CORE_ADDR memaddr;
int write;
struct target_ops *target; /* ignored */
{
- if (write)
- return monitor_write_memory (memaddr, myaddr, len);
- else
- return monitor_read_memory (memaddr, myaddr, len);
+ return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, write);
}
static void
char *file;
int from_tty;
{
+ dcache_flush (remote_dcache);
+
if (current_monitor->load_routine)
current_monitor->load_routine (monitor_desc, file, hashmark);
else
/* Finally, make the PC point at the start address */
- write_pc (bfd_get_start_address (exec_bfd));
+ if (exec_bfd)
+ write_pc (bfd_get_start_address (exec_bfd));
inferior_pid = 0; /* No process now */
static void
monitor_stop ()
{
- if (!current_monitor->stop)
- return;
-
- monitor_printf(current_monitor->stop);
- monitor_expect_prompt (NULL, 0);
+ if (current_monitor->stop)
+ monitor_printf_noecho (current_monitor->stop);
}
/* Put a command string, in args, out to MONITOR. Output from MONITOR
asection *s;
char *buffer, srec[1024];
int i;
- int srec_frame = 128;
+ int srec_frame = 32;
int reclen;
buffer = alloca (srec_frame * 2 + 256);
return;
}
- monitor_printf (LOAD_CMD); /* tell the monitor to load */
+ 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)
- {
- printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
- s->vma + s->_raw_size);
- gdb_flush (gdb_stdout);
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ int numbytes;
- for (i = 0; i < s->_raw_size; i += srec_frame)
- {
- int numbytes;
+ printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
+ s->vma + s->_raw_size);
+ gdb_flush (gdb_stdout);
- numbytes = min (srec_frame, s->_raw_size - i);
+ 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);
+ bfd_get_section_contents (abfd, s, buffer, i, numbytes);
- reclen = monitor_make_srec (srec, 3, s->vma + i, buffer, numbytes);
+ reclen = monitor_make_srec (srec, 'd', s->vma + i, buffer, numbytes);
- monitor_printf ("%.*s\r", reclen, srec);
+ monitor_printf_noecho ("%.*s\r", reclen, srec);
- if (hashmark)
- {
- putchar_unfiltered ('#');
- gdb_flush (gdb_stdout);
- }
- } /* Per-packet (or S-record) loop */
+ if (hashmark)
+ {
+ putchar_unfiltered ('#');
+ gdb_flush (gdb_stdout);
+ }
+ } /* Per-packet (or S-record) loop */
- putchar_unfiltered ('\n');
- } /* Loadable sections */
-
+ 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, 7, abfd->start_address, NULL, 0);
+ reclen = monitor_make_srec (srec, 't', abfd->start_address, NULL, 0);
- monitor_printf ("%.*s\r", reclen, srec);
+ monitor_printf_noecho ("%.*s\r", reclen, srec);
- monitor_printf ("\r\r"); /* Some monitors need these to wake up */
+ monitor_printf_noecho ("\r\r"); /* Some monitors need these to wake up */
monitor_expect_prompt (NULL, 0);
+
+ SERIAL_FLUSH_INPUT (monitor_desc);
}
/*
unsigned char checksum;
int i;
char *buf;
- static char hextab[] = "0123456789ABCDEF";
-
+ static char hextab[16] = "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;
- /* Create the header for the srec. 4 is the number of bytes in the address,
+ addr_size = 2;
+ if (memaddr >= 0xffffff)
+ addr_size = 4;
+ else if (memaddr >= 0xffffff)
+ 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. */
- sprintf (buf, "S%d%02X%08X", type, len + 4 + 1, memaddr);
- buf += 12;
-
+ 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 + 4 + 1 /* Packet length */
+ checksum += (len + addr_size + 1 /* Packet length */
+ (memaddr & 0xff) /* Address... */
+ ((memaddr >> 8) & 0xff)
+ ((memaddr >> 16) & 0xff)