#include "defs.h"
#include "gdbcore.h"
#include "target.h"
#include "exceptions.h"
#include <signal.h>
#include <ctype.h>
#include "gdb_string.h"
#include <sys/types.h>
#include "command.h"
#include "serial.h"
#include "monitor.h"
#include "gdbcmd.h"
#include "inferior.h"
#include "gdb_regex.h"
#include "srec.h"
#include "regcache.h"
static char *dev_name;
static struct target_ops *targ_ops;
static void monitor_vsprintf (char *sndbuf, char *pattern, va_list args);
static int readchar (int timeout);
static void monitor_fetch_register (int regno);
static void monitor_store_register (int regno);
static void monitor_printable_string (char *newstr, char *oldstr, int len);
static void monitor_error (char *function, char *message, CORE_ADDR memaddr, int len, char *string, int final_char);
static void monitor_detach (char *args, int from_tty);
static void monitor_resume (ptid_t ptid, int step, enum target_signal sig);
static void monitor_interrupt (int signo);
static void monitor_interrupt_twice (int signo);
static void monitor_interrupt_query (void);
static void monitor_wait_cleanup (void *old_timeout);
static ptid_t monitor_wait (ptid_t ptid, struct target_waitstatus *status);
static void monitor_fetch_registers (int regno);
static void monitor_store_registers (int regno);
static void monitor_prepare_to_store (void);
static int monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
int write,
struct mem_attrib *attrib,
struct target_ops *target);
static void monitor_files_info (struct target_ops *ops);
static int monitor_insert_breakpoint (CORE_ADDR addr, char *shadow);
static int monitor_remove_breakpoint (CORE_ADDR addr, char *shadow);
static void monitor_kill (void);
static void monitor_load (char *file, int from_tty);
static void monitor_mourn_inferior (void);
static void monitor_stop (void);
static int monitor_read_memory (CORE_ADDR addr, char *myaddr, int len);
static int monitor_write_memory (CORE_ADDR addr, char *myaddr, int len);
static int monitor_write_memory_bytes (CORE_ADDR addr, char *myaddr, int len);
static int monitor_write_memory_block (CORE_ADDR memaddr,
char *myaddr, int len);
static int monitor_expect_regexp (struct re_pattern_buffer *pat,
char *buf, int buflen);
static void monitor_dump_regs (void);
#if 0
static int from_hex (int a);
static unsigned long get_hex_word (void);
#endif
static void parse_register_dump (char *, int);
static struct monitor_ops *current_monitor;
static int hashmark;
static int timeout = 30;
static int in_monitor_wait = 0;
static void (*ofunc) ();
static CORE_ADDR *breakaddr;
static struct serial *monitor_desc = NULL;
static struct re_pattern_buffer register_pattern;
static char register_fastmap[256];
static struct re_pattern_buffer getmem_resp_delim_pattern;
static char getmem_resp_delim_fastmap[256];
static struct re_pattern_buffer setmem_resp_delim_pattern;
static char setmem_resp_delim_fastmap[256];
static struct re_pattern_buffer setreg_resp_delim_pattern;
static char setreg_resp_delim_fastmap[256];
static int dump_reg_flag;
static int first_time = 0;
#define TARGET_BUF_SIZE 2048
static void monitor_debug (const char *fmt, ...) ATTR_FORMAT(printf, 1, 2);
static int monitor_debug_p = 0;
static void
monitor_debug (const char *fmt, ...)
{
if (monitor_debug_p)
{
va_list args;
va_start (args, fmt);
vfprintf_filtered (gdb_stdlog, fmt, args);
va_end (args);
}
}
static void
monitor_printable_string (char *newstr, char *oldstr, int len)
{
int ch;
int i;
if (len <= 0)
len = strlen (oldstr);
for (i = 0; i < len; i++)
{
ch = oldstr[i];
switch (ch)
{
default:
if (isprint (ch))
*newstr++ = ch;
else
{
sprintf (newstr, "\\x%02x", ch & 0xff);
newstr += 4;
}
break;
case '\\':
*newstr++ = '\\';
*newstr++ = '\\';
break;
case '\b':
*newstr++ = '\\';
*newstr++ = 'b';
break;
case '\f':
*newstr++ = '\\';
*newstr++ = 't';
break;
case '\n':
*newstr++ = '\\';
*newstr++ = 'n';
break;
case '\r':
*newstr++ = '\\';
*newstr++ = 'r';
break;
case '\t':
*newstr++ = '\\';
*newstr++ = 't';
break;
case '\v':
*newstr++ = '\\';
*newstr++ = 'v';
break;
}
}
*newstr++ = '\0';
}
static void
monitor_error (char *function, char *message,
CORE_ADDR memaddr, int len, char *string, int final_char)
{
int real_len = (len == 0 && string != (char *) 0) ? strlen (string) : len;
char *safe_string = alloca ((real_len * 4) + 1);
monitor_printable_string (safe_string, string, real_len);
if (final_char)
error (_("%s (0x%s): %s: %s%c"), function, paddr_nz (memaddr), message, safe_string, final_char);
else
error (_("%s (0x%s): %s: %s"), function, paddr_nz (memaddr), message, safe_string);
}
static int
fromhex (int a)
{
if (a >= '0' && a <= '9')
return a - '0';
else if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else
error (_("Invalid hex digit %d"), a);
}
static void
monitor_vsprintf (char *sndbuf, char *pattern, va_list args)
{
char format[10];
char fmt;
char *p;
int i;
long arg_int;
CORE_ADDR arg_addr;
char *arg_string;
for (p = pattern; *p; p++)
{
if (*p == '%')
{
format[0] = *p++;
for (i = 1; *p >= '0' && *p <= '9' && i < (int) sizeof (format) - 2;
i++, p++)
format[i] = *p;
format[i] = fmt = *p;
format[i + 1] = '\0';
switch (fmt)
{
case '%':
strcpy (sndbuf, "%");
break;
case 'A':
arg_addr = va_arg (args, CORE_ADDR);
strcpy (sndbuf, paddr_nz (arg_addr));
break;
case 's':
arg_string = va_arg (args, char *);
sprintf (sndbuf, format, arg_string);
break;
default:
arg_int = va_arg (args, long);
sprintf (sndbuf, format, arg_int);
break;
}
sndbuf += strlen (sndbuf);
}
else
*sndbuf++ = *p;
}
*sndbuf = '\0';
}
void
monitor_printf_noecho (char *pattern,...)
{
va_list args;
char sndbuf[2000];
int len;
va_start (args, pattern);
monitor_vsprintf (sndbuf, pattern, args);
len = strlen (sndbuf);
if (len + 1 > sizeof sndbuf)
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
if (monitor_debug_p)
{
char *safe_string = (char *) alloca ((strlen (sndbuf) * 4) + 1);
monitor_printable_string (safe_string, sndbuf, 0);
fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string);
}
monitor_write (sndbuf, len);
}
void
monitor_printf (char *pattern,...)
{
va_list args;
char sndbuf[2000];
int len;
va_start (args, pattern);
monitor_vsprintf (sndbuf, pattern, args);
len = strlen (sndbuf);
if (len + 1 > sizeof sndbuf)
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
if (monitor_debug_p)
{
char *safe_string = (char *) alloca ((len * 4) + 1);
monitor_printable_string (safe_string, sndbuf, 0);
fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string);
}
monitor_write (sndbuf, len);
monitor_debug ("ExpectEcho\n");
monitor_expect (sndbuf, (char *) 0, 0);
}
void
monitor_write (char *buf, int buflen)
{
if (serial_write (monitor_desc, buf, buflen))
fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n",
safe_strerror (errno));
}
int
monitor_readchar (void)
{
int c;
int looping;
do
{
looping = 0;
c = serial_readchar (monitor_desc, timeout);
if (c >= 0)
c &= 0xff;
}
while (looping);
if (c >= 0)
return c;
if (c == SERIAL_TIMEOUT)
error (_("Timeout reading from remote system."));
perror_with_name (_("remote-monitor"));
}
static int
readchar (int timeout)
{
int c;
static enum
{
last_random, last_nl, last_cr, last_crnl
}
state = last_random;
int looping;
do
{
looping = 0;
c = serial_readchar (monitor_desc, timeout);
if (c >= 0)
{
c &= 0x7f;
if (monitor_debug_p || remote_debug)
{
char buf[2];
buf[0] = c;
buf[1] = '\0';
puts_debug ("read -->", buf, "<--");
}
}
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;
if (c == SERIAL_TIMEOUT)
#if 0
if (in_monitor_wait)
{
target_mourn_inferior ();
error (_("GDB serial timeout has expired. Target detached."));
}
else
#endif
error (_("Timeout reading from remote system."));
perror_with_name (_("remote-monitor"));
}
int
monitor_expect (char *string, char *buf, int buflen)
{
char *p = string;
int obuflen = buflen;
int c;
if (monitor_debug_p)
{
char *safe_string = (char *) alloca ((strlen (string) * 4) + 1);
monitor_printable_string (safe_string, string, 0);
fprintf_unfiltered (gdb_stdlog, "MON Expecting '%s'\n", safe_string);
}
immediate_quit++;
while (1)
{
if (buf)
{
if (buflen < 2)
{
*buf = '\000';
immediate_quit--;
return -1;
}
c = readchar (timeout);
if (c == '\000')
continue;
*buf++ = c;
buflen--;
}
else
c = readchar (timeout);
if (*p == '\003' || c == *p)
{
p++;
if (*p == '\0')
{
immediate_quit--;
if (buf)
{
*buf++ = '\000';
return obuflen - buflen;
}
else
return 0;
}
}
else
{
int i;
for (i = (p - string) - 1; i >= 0; i--)
if (string[i] == c)
{
if (! memcmp (string, p - i, i))
{
p = string + i + 1;
break;
}
}
if (i < 0)
p = string;
}
}
}
static int
monitor_expect_regexp (struct re_pattern_buffer *pat, char *buf, int buflen)
{
char *mybuf;
char *p;
monitor_debug ("MON Expecting regexp\n");
if (buf)
mybuf = buf;
else
{
mybuf = alloca (TARGET_BUF_SIZE);
buflen = TARGET_BUF_SIZE;
}
p = mybuf;
while (1)
{
int retval;
if (p - mybuf >= buflen)
{
memcpy (mybuf, mybuf + buflen / 2, buflen / 2);
p = mybuf + buflen / 2;
}
*p++ = readchar (timeout);
retval = re_search (pat, mybuf, p - mybuf, 0, p - mybuf, NULL);
if (retval >= 0)
return 1;
}
}
int
monitor_expect_prompt (char *buf, int buflen)
{
monitor_debug ("MON Expecting prompt\n");
return monitor_expect (current_monitor->prompt, buf, buflen);
}
#if 0
static unsigned long
get_hex_word (void)
{
unsigned long val;
int i;
int ch;
do
ch = readchar (timeout);
while (isspace (ch));
val = from_hex (ch);
for (i = 7; i >= 1; i--)
{
ch = readchar (timeout);
if (!isxdigit (ch))
break;
val = (val << 4) | from_hex (ch);
}
return val;
}
#endif
static void
compile_pattern (char *pattern, struct re_pattern_buffer *compiled_pattern,
char *fastmap)
{
int tmp;
const char *val;
compiled_pattern->fastmap = fastmap;
tmp = re_set_syntax (RE_SYNTAX_EMACS);
val = re_compile_pattern (pattern,
strlen (pattern),
compiled_pattern);
re_set_syntax (tmp);
if (val)
error (_("compile_pattern: Can't compile pattern string `%s': %s!"), pattern, val);
if (fastmap)
re_compile_fastmap (compiled_pattern);
}
void
monitor_open (char *args, struct monitor_ops *mon_ops, int from_tty)
{
char *name;
char **p;
if (mon_ops->magic != MONITOR_OPS_MAGIC)
error (_("Magic number of monitor_ops struct wrong."));
targ_ops = mon_ops->target;
name = targ_ops->to_shortname;
if (!args)
error (_("Use `target %s DEVICE-NAME' to use a serial port, or \n\
`target %s HOST-NAME:PORT-NUMBER' to use a network connection."), name, name);
target_preopen (from_tty);
if (mon_ops->register_pattern)
compile_pattern (mon_ops->register_pattern, ®ister_pattern,
register_fastmap);
if (mon_ops->getmem.resp_delim)
compile_pattern (mon_ops->getmem.resp_delim, &getmem_resp_delim_pattern,
getmem_resp_delim_fastmap);
if (mon_ops->setmem.resp_delim)
compile_pattern (mon_ops->setmem.resp_delim, &setmem_resp_delim_pattern,
setmem_resp_delim_fastmap);
if (mon_ops->setreg.resp_delim)
compile_pattern (mon_ops->setreg.resp_delim, &setreg_resp_delim_pattern,
setreg_resp_delim_fastmap);
unpush_target (targ_ops);
if (dev_name)
xfree (dev_name);
dev_name = xstrdup (args);
monitor_desc = serial_open (dev_name);
if (!monitor_desc)
perror_with_name (dev_name);
if (baud_rate != -1)
{
if (serial_setbaudrate (monitor_desc, baud_rate))
{
serial_close (monitor_desc);
perror_with_name (dev_name);
}
}
serial_raw (monitor_desc);
serial_flush_input (monitor_desc);
serial_setstopbits (monitor_desc, mon_ops->stopbits);
current_monitor = mon_ops;
if (current_monitor->stop)
{
monitor_stop ();
if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0)
{
monitor_debug ("EXP Open echo\n");
monitor_expect_prompt (NULL, 0);
}
}
for (p = mon_ops->init; *p != NULL; p++)
{
if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0)
monitor_printf (*p);
else
monitor_printf_noecho (*p);
monitor_expect_prompt (NULL, 0);
}
serial_flush_input (monitor_desc);
if (mon_ops->set_break != NULL)
{
if (mon_ops->num_breakpoints == 0)
mon_ops->num_breakpoints = 8;
breakaddr = (CORE_ADDR *) xmalloc (mon_ops->num_breakpoints * sizeof (CORE_ADDR));
memset (breakaddr, 0, mon_ops->num_breakpoints * sizeof (CORE_ADDR));
}
if (mon_ops->clr_all_break)
{
monitor_printf (mon_ops->clr_all_break);
monitor_expect_prompt (NULL, 0);
}
if (from_tty)
printf_unfiltered (_("Remote target %s connected to %s\n"), name, dev_name);
push_target (targ_ops);
inferior_ptid = pid_to_ptid (42000);
monitor_printf (current_monitor->line_term);
start_remote ();
}
void
monitor_close (int quitting)
{
if (monitor_desc)
serial_close (monitor_desc);
if (breakaddr != NULL)
{
xfree (breakaddr);
breakaddr = NULL;
}
monitor_desc = NULL;
}
static void
monitor_detach (char *args, int from_tty)
{
pop_target ();
if (from_tty)
printf_unfiltered (_("Ending remote %s debugging\n"), target_shortname);
}
char *
monitor_supply_register (int regno, char *valstr)
{
ULONGEST val;
unsigned char regbuf[MAX_REGISTER_SIZE];
char *p;
val = 0;
p = valstr;
while (p && *p != '\0')
{
if (*p == '\r' || *p == '\n')
{
while (*p != '\0')
p++;
break;
}
if (isspace (*p))
{
p++;
continue;
}
if (!isxdigit (*p) && *p != 'x')
{
break;
}
val <<= 4;
val += fromhex (*p++);
}
monitor_debug ("Supplying Register %d %s\n", regno, valstr);
if (val == 0 && valstr == p)
error (_("monitor_supply_register (%d): bad value from monitor: %s."),
regno, valstr);
store_unsigned_integer (regbuf, register_size (current_gdbarch, regno), val);
regcache_raw_supply (current_regcache, regno, regbuf);
return p;
}
static void
monitor_resume (ptid_t ptid, int step, enum target_signal sig)
{
monitor_debug ("MON resume\n");
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;
}
if (step)
monitor_printf (current_monitor->step);
else
{
if (current_monitor->continue_hook)
(*current_monitor->continue_hook) ();
else
monitor_printf (current_monitor->cont);
if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT)
dump_reg_flag = 1;
}
}
static void
parse_register_dump (char *buf, int len)
{
monitor_debug ("MON Parsing register dump\n");
while (1)
{
int regnamelen, vallen;
char *regname, *val;
struct re_registers register_strings;
memset (®ister_strings, 0, sizeof (struct re_registers));
if (re_search (®ister_pattern, buf, len, 0, len,
®ister_strings) == -1)
break;
regnamelen = register_strings.end[1] - register_strings.start[1];
regname = buf + register_strings.start[1];
vallen = register_strings.end[2] - register_strings.start[2];
val = buf + register_strings.start[2];
current_monitor->supply_register (regname, regnamelen, val, vallen);
buf += register_strings.end[0];
len -= register_strings.end[0];
}
}
static void
monitor_interrupt (int signo)
{
signal (signo, monitor_interrupt_twice);
if (monitor_debug_p || remote_debug)
fprintf_unfiltered (gdb_stdlog, "monitor_interrupt called\n");
target_stop ();
}
static void
monitor_interrupt_twice (int signo)
{
signal (signo, ofunc);
monitor_interrupt_query ();
signal (signo, monitor_interrupt);
}
static void
monitor_interrupt_query (void)
{
target_terminal_ours ();
if (query ("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? "))
{
target_mourn_inferior ();
deprecated_throw_reason (RETURN_QUIT);
}
target_terminal_inferior ();
}
static void
monitor_wait_cleanup (void *old_timeout)
{
timeout = *(int *) old_timeout;
signal (SIGINT, ofunc);
in_monitor_wait = 0;
}
static void
monitor_wait_filter (char *buf,
int bufmax,
int *ext_resp_len,
struct target_waitstatus *status)
{
int resp_len;
do
{
resp_len = monitor_expect_prompt (buf, bufmax);
*ext_resp_len = resp_len;
if (resp_len <= 0)
fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf);
}
while (resp_len < 0);
if (monitor_debug_p || remote_debug
|| current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT)
{
int i;
for (i = 0; i < resp_len - 1; i++)
if (buf[i] == 0x0f)
putchar_unfiltered (buf[++i]);
}
}
static ptid_t
monitor_wait (ptid_t ptid, struct target_waitstatus *status)
{
int old_timeout = timeout;
char buf[TARGET_BUF_SIZE];
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);
monitor_debug ("MON wait\n");
#if 0
in_monitor_wait = 1;
timeout = watchdog > 0 ? watchdog : -1;
#else
timeout = -1;
#endif
ofunc = (void (*)()) signal (SIGINT, monitor_interrupt);
if (current_monitor->wait_filter)
(*current_monitor->wait_filter) (buf, sizeof (buf), &resp_len, status);
else
monitor_wait_filter (buf, sizeof (buf), &resp_len, status);
#if 0
do
{
resp_len = monitor_expect_prompt (buf, sizeof (buf));
if (resp_len <= 0)
fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf);
}
while (resp_len < 0);
if (monitor_debug_p || remote_debug
|| current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT)
{
int i;
for (i = 0; i < resp_len - 1; i++)
if (buf[i] == 0x0f)
putchar_unfiltered (buf[++i]);
}
#endif
signal (SIGINT, ofunc);
timeout = old_timeout;
#if 0
if (dump_reg_flag && current_monitor->dump_registers)
{
dump_reg_flag = 0;
monitor_printf (current_monitor->dump_registers);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
}
if (current_monitor->register_pattern)
parse_register_dump (buf, resp_len);
#else
monitor_debug ("Wait fetching registers after stop\n");
monitor_dump_regs ();
#endif
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
discard_cleanups (old_chain);
in_monitor_wait = 0;
return inferior_ptid;
}
static void
monitor_fetch_register (int regno)
{
const char *name;
char *zerobuf;
char *regbuf;
int i;
regbuf = alloca (MAX_REGISTER_SIZE * 2 + 1);
zerobuf = alloca (MAX_REGISTER_SIZE);
memset (zerobuf, 0, MAX_REGISTER_SIZE);
if (current_monitor->regname != NULL)
name = current_monitor->regname (regno);
else
name = current_monitor->regnames[regno];
monitor_debug ("MON fetchreg %d '%s'\n", regno, name ? name : "(null name)");
if (!name || (*name == '\0'))
{
monitor_debug ("No register known for %d\n", regno);
regcache_raw_supply (current_regcache, regno, zerobuf);
return;
}
monitor_printf (current_monitor->getreg.cmd, name);
if (current_monitor->getreg.resp_delim)
{
monitor_debug ("EXP getreg.resp_delim\n");
monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
if (current_monitor->flags & MO_32_REGS_PAIRED
&& (regno & 1) != 0 && regno < 32)
{
monitor_debug ("EXP getreg.resp_delim\n");
monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
}
}
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);
}
for (i = 0; i < register_size (current_gdbarch, regno) * 2; i++)
{
int c;
c = readchar (timeout);
while (c == ' ')
c = readchar (timeout);
if (!isxdigit (c))
break;
regbuf[i] = c;
}
regbuf[i] = '\000';
monitor_debug ("REGVAL '%s'\n", regbuf);
if (current_monitor->getreg.term)
{
monitor_debug ("EXP getreg.term\n");
monitor_expect (current_monitor->getreg.term, NULL, 0);
}
if (current_monitor->getreg.term_cmd)
{
monitor_debug ("EMIT getreg.term.cmd\n");
monitor_printf (current_monitor->getreg.term_cmd);
}
if (!current_monitor->getreg.term ||
current_monitor->getreg.term_cmd)
monitor_expect_prompt (NULL, 0);
monitor_supply_register (regno, regbuf);
}
int
monitor_dump_reg_block (char *block_cmd)
{
char buf[TARGET_BUF_SIZE];
int resp_len;
monitor_printf (block_cmd);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
parse_register_dump (buf, resp_len);
return 1;
}
static void
monitor_dump_regs (void)
{
char buf[TARGET_BUF_SIZE];
int resp_len;
if (current_monitor->dumpregs)
(*(current_monitor->dumpregs)) ();
else if (current_monitor->dump_registers)
{
monitor_printf (current_monitor->dump_registers);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
parse_register_dump (buf, resp_len);
}
else
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
static void
monitor_fetch_registers (int regno)
{
monitor_debug ("MON fetchregs\n");
if (current_monitor->getreg.cmd)
{
if (regno >= 0)
{
monitor_fetch_register (regno);
return;
}
for (regno = 0; regno < NUM_REGS; regno++)
monitor_fetch_register (regno);
}
else
{
monitor_dump_regs ();
}
}
static void
monitor_store_register (int regno)
{
const char *name;
ULONGEST val;
if (current_monitor->regname != NULL)
name = current_monitor->regname (regno);
else
name = current_monitor->regnames[regno];
if (!name || (*name == '\0'))
{
monitor_debug ("MON Cannot store unknown register\n");
return;
}
val = read_register (regno);
monitor_debug ("MON storeg %d %s\n", regno,
phex (val, register_size (current_gdbarch, regno)));
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);
if (current_monitor->setreg.resp_delim)
{
monitor_debug ("EXP setreg.resp_delim\n");
monitor_expect_regexp (&setreg_resp_delim_pattern, NULL, 0);
if (current_monitor->flags & MO_SETREG_INTERACTIVE)
monitor_printf ("%s\r", paddr_nz (val));
}
if (current_monitor->setreg.term)
{
monitor_debug ("EXP setreg.term\n");
monitor_expect (current_monitor->setreg.term, NULL, 0);
if (current_monitor->flags & MO_SETREG_INTERACTIVE)
monitor_printf ("%s\r", paddr_nz (val));
monitor_expect_prompt (NULL, 0);
}
else
monitor_expect_prompt (NULL, 0);
if (current_monitor->setreg.term_cmd)
{
monitor_debug ("EXP setreg_termcmd\n");
monitor_printf ("%s", current_monitor->setreg.term_cmd);
monitor_expect_prompt (NULL, 0);
}
}
static void
monitor_store_registers (int regno)
{
if (regno >= 0)
{
monitor_store_register (regno);
return;
}
for (regno = 0; regno < NUM_REGS; regno++)
monitor_store_register (regno);
}
static void
monitor_prepare_to_store (void)
{
}
static void
monitor_files_info (struct target_ops *ops)
{
printf_unfiltered (_("\tAttached to %s at %d baud.\n"), dev_name, baud_rate);
}
static int
monitor_write_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
unsigned int val, hostval;
char *cmd;
int i;
monitor_debug ("MON write %d %s\n", len, paddr (memaddr));
if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
memaddr = ADDR_BITS_REMOVE (memaddr);
if (current_monitor->fill)
{
for (i = 0; i < len; i++)
if (myaddr[i] != 0)
break;
if (i > 4)
{
monitor_debug ("MON FILL %d\n", i);
if (current_monitor->flags & MO_FILL_USES_ADDR)
monitor_printf (current_monitor->fill, memaddr, (memaddr + i) - 1, 0);
else
monitor_printf (current_monitor->fill, memaddr, i, 0);
monitor_expect_prompt (NULL, 0);
return i;
}
}
#if 0
if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->setmem.cmdll)
{
len = 8;
cmd = current_monitor->setmem.cmdll;
}
else
#endif
if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->setmem.cmdl)
{
len = 4;
cmd = current_monitor->setmem.cmdl;
}
else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->setmem.cmdw)
{
len = 2;
cmd = current_monitor->setmem.cmdw;
}
else
{
len = 1;
cmd = current_monitor->setmem.cmdb;
}
val = extract_unsigned_integer (myaddr, len);
if (len == 4)
{
hostval = *(unsigned int *) myaddr;
monitor_debug ("Hostval(%08x) val(%08x)\n", hostval, val);
}
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.resp_delim)
{
monitor_debug ("EXP setmem.resp_delim");
monitor_expect_regexp (&setmem_resp_delim_pattern, NULL, 0);
monitor_printf ("%x\r", val);
}
if (current_monitor->setmem.term)
{
monitor_debug ("EXP setmem.term");
monitor_expect (current_monitor->setmem.term, NULL, 0);
monitor_printf ("%x\r", val);
}
if (current_monitor->setmem.term_cmd)
{
monitor_printf ("%s", current_monitor->setmem.term_cmd);
}
}
else
monitor_printf (cmd, memaddr, val);
monitor_expect_prompt (NULL, 0);
return len;
}
static int
monitor_write_memory_bytes (CORE_ADDR memaddr, char *myaddr, int len)
{
unsigned char val;
int written = 0;
if (len == 0)
return 0;
monitor_printf (current_monitor->setmem.cmdb, memaddr);
monitor_expect_prompt (NULL, 0);
while (len)
{
val = *myaddr;
monitor_printf ("%x\r", val);
myaddr++;
memaddr++;
written++;
monitor_expect_prompt (NULL, 0);
len--;
}
monitor_printf (current_monitor->getreg.term_cmd);
monitor_expect_prompt (NULL, 0);
return written;
}
static void
longlongendswap (unsigned char *a)
{
int i, j;
unsigned char x;
i = 0;
j = 7;
while (i < 4)
{
x = *(a + i);
*(a + i) = *(a + j);
*(a + j) = x;
i++, j--;
}
}
static char *hexlate = "0123456789abcdef";
static char *
longlong_hexchars (unsigned long long value,
char *outbuff)
{
if (value == 0)
{
*outbuff++ = '0';
return outbuff;
}
else
{
static unsigned char disbuf[8];
unsigned char *scan, *limit;
unsigned char c, nib;
int leadzero = 1;
scan = disbuf;
limit = scan + 8;
{
unsigned long long *dp;
dp = (unsigned long long *) scan;
*dp = value;
}
longlongendswap (disbuf);
while (scan < limit)
{
c = *scan++;
if (leadzero)
{
if (c == 0)
continue;
else
leadzero = 0;
}
nib = c >> 4;
*outbuff++ = hexlate[nib];
nib = c & 0x0f;
*outbuff++ = hexlate[nib];
}
return outbuff;
}
}
static int
monitor_write_memory_longlongs (CORE_ADDR memaddr, char *myaddr, int len)
{
static char hexstage[20];
char *endstring;
long long *llptr;
long long value;
int written = 0;
llptr = (unsigned long long *) myaddr;
if (len == 0)
return 0;
monitor_printf (current_monitor->setmem.cmdll, memaddr);
monitor_expect_prompt (NULL, 0);
while (len >= 8)
{
value = *llptr;
endstring = longlong_hexchars (*llptr, hexstage);
*endstring = '\0';
monitor_printf ("%s\r", hexstage);
llptr++;
memaddr += 8;
written += 8;
monitor_expect_prompt (NULL, 0);
len -= 8;
}
monitor_printf (current_monitor->getreg.term_cmd);
monitor_expect_prompt (NULL, 0);
return written;
}
static int
monitor_write_memory_block (CORE_ADDR memaddr, char *myaddr, int len)
{
int written;
written = 0;
#if 1
if ((len > 8) && (((len & 0x07)) == 0) && current_monitor->setmem.cmdll)
{
return monitor_write_memory_longlongs (memaddr, myaddr, len);
}
#endif
written = monitor_write_memory_bytes (memaddr, myaddr, len);
return written;
}
static int
monitor_read_memory_single (CORE_ADDR memaddr, char *myaddr, int len)
{
unsigned int val;
char membuf[sizeof (int) * 2 + 1];
char *p;
char *cmd;
monitor_debug ("MON read single\n");
#if 0
if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->getmem.cmdll)
{
len = 8;
cmd = current_monitor->getmem.cmdll;
}
else
#endif
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;
}
monitor_printf (cmd, memaddr);
if (current_monitor->getmem.resp_delim)
{
monitor_debug ("EXP getmem.resp_delim\n");
monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0);
}
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
monitor_error ("monitor_read_memory_single",
"bad response from monitor",
memaddr, 0, NULL, 0);
}
{
int i;
for (i = 0; i < len * 2; i++)
{
int c;
while (1)
{
c = readchar (timeout);
if (isxdigit (c))
break;
if (c == ' ')
continue;
monitor_error ("monitor_read_memory_single",
"bad response from monitor",
memaddr, i, membuf, 0);
}
membuf[i] = c;
}
membuf[i] = '\000';
}
if (current_monitor->getmem.term)
{
monitor_expect (current_monitor->getmem.term, NULL, 0);
if (current_monitor->getmem.term_cmd)
{
monitor_printf (current_monitor->getmem.term_cmd);
monitor_expect_prompt (NULL, 0);
}
}
else
monitor_expect_prompt (NULL, 0);
p = membuf;
val = strtoul (membuf, &p, 16);
if (val == 0 && membuf == p)
monitor_error ("monitor_read_memory_single",
"bad value from monitor",
memaddr, 0, membuf, 0);
store_unsigned_integer (myaddr, len, val);
return len;
}
static int
monitor_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
unsigned int val;
char buf[512];
char *p, *p1;
int resp_len;
int i;
CORE_ADDR dumpaddr;
if (len <= 0)
{
monitor_debug ("Zero length call to monitor_read_memory\n");
return 0;
}
monitor_debug ("MON read block ta(%s) ha(%lx) %d\n",
paddr_nz (memaddr), (long) myaddr, len);
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 = (current_monitor->flags & MO_EXACT_DUMPADDR)
? memaddr : memaddr & ~0x0f;
if (((memaddr ^ (memaddr + len - 1)) & ~0xf) != 0)
len = ((memaddr + len) & ~0xf) - memaddr;
if (current_monitor->flags & MO_GETMEM_NEEDS_RANGE)
monitor_printf (current_monitor->getmem.cmdb, memaddr, memaddr + len);
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);
if (current_monitor->getmem.term)
{
resp_len = monitor_expect (current_monitor->getmem.term, buf, sizeof buf);
if (resp_len <= 0)
monitor_error ("monitor_read_memory",
"excessive response from monitor",
memaddr, resp_len, buf, 0);
if (current_monitor->getmem.term_cmd)
{
serial_write (monitor_desc, current_monitor->getmem.term_cmd,
strlen (current_monitor->getmem.term_cmd));
monitor_expect_prompt (NULL, 0);
}
}
else
resp_len = monitor_expect_prompt (buf, sizeof buf);
p = buf;
if (current_monitor->getmem.resp_delim)
{
int retval, tmp;
struct re_registers resp_strings;
monitor_debug ("MON getmem.resp_delim %s\n", current_monitor->getmem.resp_delim);
memset (&resp_strings, 0, sizeof (struct re_registers));
tmp = strlen (p);
retval = re_search (&getmem_resp_delim_pattern, p, tmp, 0, tmp,
&resp_strings);
if (retval < 0)
monitor_error ("monitor_read_memory",
"bad response from monitor",
memaddr, resp_len, buf, 0);
p += resp_strings.end[0];
#if 0
p = strstr (p, current_monitor->getmem.resp_delim);
if (!p)
monitor_error ("monitor_read_memory",
"bad response from monitor",
memaddr, resp_len, buf, 0);
p += strlen (current_monitor->getmem.resp_delim);
#endif
}
monitor_debug ("MON scanning %d ,%lx '%s'\n", len, (long) p, p);
if (current_monitor->flags & MO_GETMEM_16_BOUNDARY)
{
char c;
int fetched = 0;
i = len;
c = *p;
while (!(c == '\000' || c == '\n' || c == '\r') && i > 0)
{
if (isxdigit (c))
{
if ((dumpaddr >= memaddr) && (i > 0))
{
val = fromhex (c) * 16 + fromhex (*(p + 1));
*myaddr++ = val;
if (monitor_debug_p || remote_debug)
fprintf_unfiltered (gdb_stdlog, "[%02x]", val);
--i;
fetched++;
}
++dumpaddr;
++p;
}
++p;
c = *p;
}
if (fetched == 0)
error (_("Failed to read via monitor"));
if (monitor_debug_p || remote_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
return fetched;
}
monitor_debug ("MON scanning bytes\n");
for (i = len; i > 0; i--)
{
while (1)
{
if (isxdigit (*p))
break;
if (*p == '\000' || *p == '\n' || *p == '\r')
monitor_error ("monitor_read_memory",
"badly terminated response from monitor",
memaddr, resp_len, buf, 0);
p++;
}
val = strtoul (p, &p1, 16);
if (val == 0 && p == p1)
monitor_error ("monitor_read_memory",
"bad value from monitor",
memaddr, resp_len, buf, 0);
*myaddr++ = val;
if (i == 1)
break;
p = p1;
}
return len;
}
static int
monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct mem_attrib *attrib, struct target_ops *target)
{
int res;
if (write)
{
if (current_monitor->flags & MO_HAS_BLOCKWRITES)
res = monitor_write_memory_block(memaddr, myaddr, len);
else
res = monitor_write_memory(memaddr, myaddr, len);
}
else
{
res = monitor_read_memory(memaddr, myaddr, len);
}
return res;
}
static void
monitor_kill (void)
{
return;
}
static void
monitor_create_inferior (char *exec_file, char *args, char **env,
int from_tty)
{
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);
}
static void
monitor_mourn_inferior (void)
{
unpush_target (targ_ops);
generic_mourn_inferior ();
}
static int
monitor_insert_breakpoint (CORE_ADDR addr, char *shadow)
{
int i;
const unsigned char *bp;
int bplen;
monitor_debug ("MON inst bkpt %s\n", paddr (addr));
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);
bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen);
for (i = 0; i < current_monitor->num_breakpoints; i++)
{
if (breakaddr[i] == 0)
{
breakaddr[i] = addr;
monitor_read_memory (addr, shadow, bplen);
monitor_printf (current_monitor->set_break, addr);
monitor_expect_prompt (NULL, 0);
return 0;
}
}
error (_("Too many breakpoints (> %d) for monitor."), current_monitor->num_breakpoints);
}
static int
monitor_remove_breakpoint (CORE_ADDR addr, char *shadow)
{
int i;
monitor_debug ("MON rmbkpt %s\n", paddr (addr));
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 < current_monitor->num_breakpoints; i++)
{
if (breakaddr[i] == addr)
{
breakaddr[i] = 0;
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);
return 0;
}
}
fprintf_unfiltered (gdb_stderr,
"Can't find breakpoint associated with 0x%s\n",
paddr_nz (addr));
return 1;
}
static int
monitor_wait_srec_ack (void)
{
int ch;
if (current_monitor->flags & MO_SREC_ACK_PLUS)
{
return (readchar (timeout) == '+');
}
else if (current_monitor->flags & MO_SREC_ACK_ROTATE)
{
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;
}
static void
monitor_load (char *file, int from_tty)
{
monitor_debug ("MON load\n");
if (current_monitor->load_routine)
current_monitor->load_routine (monitor_desc, file, hashmark);
else
{
int n;
unsigned long load_offset;
char buf[128];
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);
load_srec (monitor_desc, file, (bfd_vma) load_offset,
32, SREC_ALL, hashmark,
current_monitor->flags & MO_SREC_ACK ?
monitor_wait_srec_ack : NULL);
monitor_expect_prompt (NULL, 0);
}
if (exec_bfd)
write_pc (bfd_get_start_address (exec_bfd));
}
static void
monitor_stop (void)
{
monitor_debug ("MON stop\n");
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);
}
static void
monitor_rcmd (char *command,
struct ui_file *outbuf)
{
char *p;
int resp_len;
char buf[1000];
if (monitor_desc == NULL)
error (_("monitor target not open."));
p = current_monitor->prompt;
monitor_printf ("%s\r", (command ? command : ""));
resp_len = monitor_expect_prompt (buf, sizeof buf);
fputs_unfiltered (buf, outbuf);
}
#if 0
static int
from_hex (int a)
{
if (a >= '0' && a <= '9')
return a - '0';
if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
error (_("Reply contains invalid hex digit 0x%x"), a);
}
#endif
char *
monitor_get_dev_name (void)
{
return dev_name;
}
static struct target_ops monitor_ops;
static void
init_base_monitor_ops (void)
{
monitor_ops.to_close = monitor_close;
monitor_ops.to_detach = monitor_detach;
monitor_ops.to_resume = monitor_resume;
monitor_ops.to_wait = monitor_wait;
monitor_ops.to_fetch_registers = monitor_fetch_registers;
monitor_ops.to_store_registers = monitor_store_registers;
monitor_ops.to_prepare_to_store = monitor_prepare_to_store;
monitor_ops.deprecated_xfer_memory = monitor_xfer_memory;
monitor_ops.to_files_info = monitor_files_info;
monitor_ops.to_insert_breakpoint = monitor_insert_breakpoint;
monitor_ops.to_remove_breakpoint = monitor_remove_breakpoint;
monitor_ops.to_kill = monitor_kill;
monitor_ops.to_load = monitor_load;
monitor_ops.to_create_inferior = monitor_create_inferior;
monitor_ops.to_mourn_inferior = monitor_mourn_inferior;
monitor_ops.to_stop = monitor_stop;
monitor_ops.to_rcmd = monitor_rcmd;
monitor_ops.to_stratum = process_stratum;
monitor_ops.to_has_all_memory = 1;
monitor_ops.to_has_memory = 1;
monitor_ops.to_has_stack = 1;
monitor_ops.to_has_registers = 1;
monitor_ops.to_has_execution = 1;
monitor_ops.to_magic = OPS_MAGIC;
}
void
init_monitor_ops (struct target_ops *ops)
{
if (monitor_ops.to_magic != OPS_MAGIC)
init_base_monitor_ops ();
memcpy (ops, &monitor_ops, sizeof monitor_ops);
}
extern initialize_file_ftype _initialize_remote_monitors;
void
_initialize_remote_monitors (void)
{
init_base_monitor_ops ();
add_setshow_boolean_cmd ("hash", no_class, &hashmark, _("\
Set display of activity while downloading a file."), _("\
Show display of activity while downloading a file."), _("\
When enabled, a hashmark \'#\' is displayed."),
NULL,
NULL,
&setlist, &showlist);
add_setshow_zinteger_cmd ("monitor", no_class, &monitor_debug_p, _("\
Set debugging of remote monitor communication."), _("\
Show debugging of remote monitor communication."), _("\
When enabled, communication between GDB and the remote monitor\n\
is displayed."),
NULL,
NULL,
&setdebuglist, &showdebuglist);
}