/* Remote debugging interface for boot monitors, for GDB.
- Copyright 1990, 1991, 1992, 1993, 1995, 1996
+ Copyright 1990, 1991, 1992, 1993, 1995, 1996, 1997
Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
Resurrected from the ashes by Stu Grossman.
static char *dev_name;
static struct target_ops *targ_ops;
+static void monitor_vsprintf PARAMS ((char *sndbuf, char *pattern, va_list args));
+
static int readchar PARAMS ((int timeout));
static void monitor_command PARAMS ((char *args, int fromtty));
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_write_memory_bytes PARAMS ((CORE_ADDR addr,
+ char *myaddr,int len));
+static int monitor_write_memory_block PARAMS((
+ CORE_ADDR memaddr ,
+ char * myaddr ,
+ int len)) ;
static int monitor_expect_regexp PARAMS ((struct re_pattern_buffer *pat,
char *buf, int buflen));
+static void monitor_dump_regs PARAMS((void)) ;
+#if 0
static int from_hex PARAMS ((int a));
static unsigned long get_hex_word PARAMS ((void));
+#endif
+static void parse_register_dump PARAMS ((char *, int));
static struct monitor_ops *current_monitor;
static void (*ofunc)(); /* Old SIGINT signal handler */
+/* Extra remote debugging for developing a new rom monitor variation */
+#if ! defined(EXTRA_RDEBUG)
+#define EXTRA_RDEBUG 1
+#endif
+#if EXTRA_RDEBUG
+#define RDEBUG(stuff) { if (remote_debug) printf stuff ; }
+#else
+#define RDEBUG(stuff) {}
+#endif
+
/* 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 first_time=0; /* is this the first time we're executing after
gaving created the child proccess? */
-/* monitor_debug is like fputs_unfiltered, except it prints special
- characters in printable fashion. */
+/* Convert hex digit A to a number. */
-static void
-monitor_debug (prefix, string, suffix)
- char *prefix;
- char *string;
- char *suffix;
+static int
+fromhex (a)
+ int a;
{
- int ch;
-
- /* print prefix and suffix after each line */
- static int new_line=1;
- static char *prev_prefix = "";
- static char *prev_suffix = "";
+ if (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);
+}
- /* 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;
+/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses
- /* print prefix if last char was a newline*/
+ This function exists to get around the problem that many host platforms
+ don't have a printf that can print 64-bit addresses. The %A format
+ specification is recognized as a special case, and causes the argument
+ to be printed as a 64-bit hexadecimal address.
- if (new_line == 1) {
- fputs_unfiltered (prefix, gdb_stderr);
- new_line=0;
- }
- if (strchr(string,'\n')) /* save state for next call */
- new_line=1;
+ Only format specifiers of the form "[0-9]*[a-z]" are recognized.
+ If it is a '%s' format, the argument is a string; otherwise the
+ argument is assumed to be a long integer.
+*/
+
+static void
+monitor_vsprintf (sndbuf, pattern, args)
+ 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;
- while ((ch = *string++) != '\0')
+ for (p = pattern; *p; p++)
{
- 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 (*p == '%')
+ {
+ /* Copy the format specifier to a separate buffer. */
+ 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';
+
+ /* Fetch the next argument and print it. */
+ switch (fmt)
+ {
+ 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;
}
-
- if (new_line==1) { /* print suffix if last char was a newline */
- fputs_unfiltered (suffix, gdb_stderr);
- fputs_unfiltered ("\n", gdb_stderr);
- }
+ *sndbuf = '\0';
}
+
/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo.
Works just like printf. */
pattern = va_arg (args, char *);
#endif
- vsprintf (sndbuf, pattern, args);
+ monitor_vsprintf (sndbuf, pattern, args);
+#if 0
if (remote_debug > 0)
- monitor_debug ("sent -->", sndbuf, "<--");
-
+ puts_debug ("sent -->", sndbuf, "<--");
+#endif
+ RDEBUG(("sent[%s]\n",sndbuf)) ;
+
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_write (sndbuf, len);
}
/* monitor_printf -- Send data to monitor and check the echo. Works just like
pattern = va_arg (args, char *);
#endif
- vsprintf (sndbuf, pattern, args);
+ monitor_vsprintf (sndbuf, pattern, args);
+#if 0
if (remote_debug > 0)
- monitor_debug ("sent -->", sndbuf, "<--");
-
+ puts_debug ("sent -->", sndbuf, "<--");
+#endif
+ RDEBUG(("sent[%s]\n",sndbuf))
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_write (sndbuf, len);
/* 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. */
+ RDEBUG(("ExpectEcho\n"))
monitor_expect (sndbuf, (char *)0, 0);
}
+
+/* Write characters to the remote system. */
+
+void
+monitor_write (buf, buflen)
+ char *buf;
+ int buflen;
+{
+ if (SERIAL_WRITE(monitor_desc, buf, buflen))
+ fprintf_unfiltered (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno));
+}
+
+
+/* Read a binary character from the remote system, doing all the fancy
+ timeout stuff, but without interpreting the character in any way,
+ and without printing remote debug information. */
+
+int
+monitor_readchar ()
+{
+ int c;
+ int looping;
+
+ do
+ {
+ looping = 0;
+ c = SERIAL_READCHAR (monitor_desc, timeout);
+
+ if (c >= 0)
+ c &= 0xff; /* don't lose bit 7 */
+ }
+ while (looping);
+
+ if (c >= 0)
+ return c;
+
+ if (c == SERIAL_TIMEOUT)
+ error ("Timeout reading from remote system.");
+
+ perror_with_name ("remote-monitor");
+}
+
+
/* Read a character from the remote system, doing all the fancy
timeout stuff. */
if (c >= 0)
{
c &= 0x7f;
+#if 0
+ /* This seems to interfere with proper function of the
+ input stream */
if (remote_debug > 0)
{
char buf[2];
buf[0] = c;
buf[1] = '\0';
- monitor_debug ("read -->", buf, "<--");
+ puts_debug ("read -->", buf, "<--");
}
+
+#endif
}
/* Canonicialize \n\r combinations into one \r */
return c;
if (c == SERIAL_TIMEOUT)
-#ifdef MAINTENANCE_CMDS
+#if 0 /* MAINTENANCE_CMDS */
+ /* I fail to see how detaching here can be useful
if (in_monitor_wait) /* Watchdog went off */
{
target_mourn_inferior ();
- error ("Watchdog has expired. Target detached.\n");
+ error ("GDB serial timeout has expired. Target detached.\n");
}
else
#endif
int obuflen = buflen;
int c;
extern struct target_ops *targ_ops;
+ RDEBUG(("MON Expecting '%s'\n",string)) ;
immediate_quit = 1;
while (1)
{
char *mybuf;
char *p;
-
+ RDEBUG(("MON Expecting regexp\n")) ;
if (buf)
mybuf = buf;
else
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 monitor_expect_prompt(). Exception: monitor_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 monitor_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. */
+ Thus the last thing that a procedure does with the serial line will
+ be an monitor_expect_prompt(). Exception: monitor_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 monitor_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. */
int
monitor_expect_prompt (buf, buflen)
char *buf;
int buflen;
{
+ RDEBUG(("MON Expecting prompt\n"))
return monitor_expect (current_monitor->prompt, buf, buflen);
}
/* Get N 32-bit words from remote, each preceded by a space, and put
them in registers starting at REGNO. */
+#if 0
static unsigned long
get_hex_word ()
{
return val;
}
+#endif
static void
compile_pattern (pattern, compiled_pattern, fastmap)
int from_tty;
{
char *name;
- int i;
char **p;
if (mon_ops->magic != MONITOR_OPS_MAGIC)
monitor_stop ();
if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0)
{
- monitor_expect_prompt (NULL, 0);
+ RDEBUG(("EXP Open echo\n")) ;
+ monitor_expect_prompt (NULL, 0);
}
}
monitor_printf (current_monitor->line_term);
- remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory);
-
+ if (current_monitor->flags & MO_HAS_BLOCKWRITES)
+ remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory_block);
+ else
+ remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory);
start_remote ();
}
char *p;
val = strtoul (valstr, &p, 16);
+ RDEBUG(("Supplying Register %d %s\n",regno,valstr)) ;
if (val == 0 && valstr == p)
error ("monitor_supply_register (%d): bad value from monitor: %s.",
/* Tell the remote machine to resume. */
+int flush_monitor_dcache(void) { dcache_flush (remote_dcache); }
+
static void
monitor_resume (pid, step, sig)
int pid, step;
enum target_signal sig;
{
/* Some monitors require a different command when starting a program */
+ RDEBUG(("MON resume\n")) ;
if (current_monitor->flags & MO_RUN_FIRST_TIME && first_time == 1)
{
first_time = 0;
monitor_printf (current_monitor->step);
else
{
- monitor_printf (current_monitor->cont);
+ 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;
}
form REG=VAL. Each description is split up into a name and a value
string which are passed down to monitor specific code. */
-static char *
+static void
parse_register_dump (buf, len)
char *buf;
int len;
{
+ RDEBUG(("MON Parsing register dump\n"))
while (1)
{
int regnamelen, vallen;
in_monitor_wait = 0;
}
+
+
+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);
+
+ /* Print any output characters that were preceded by ^O. */
+ /* FIXME - This would be great as a user settabgle flag */
+ if (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]);
+ }
+}
+
+
+
/* Wait until the remote machine stops, then return, storing status in
status just as `wait' would. */
status->value.integer = 0;
old_chain = make_cleanup (monitor_wait_cleanup, old_timeout);
+ RDEBUG(("MON wait\n"))
-#ifdef MAINTENANCE_CMDS
+#if 0 /* MAINTENANCE_CMDS */
+ /* This is somthing other than a maintenance command */
in_monitor_wait = 1;
timeout = watchdog > 0 ? watchdog : -1;
#else
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 /* Transferred to monitor wait filter */
do
{
resp_len = monitor_expect_prompt (buf, sizeof (buf));
}
while (resp_len < 0);
+ /* Print any output characters that were preceded by ^O. */
+ /* FIXME - This would be great as a user settabgle flag */
+ if (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
+ RDEBUG(("Wait fetching registers after stop\n")) ;
+ monitor_dump_regs() ;
+#endif
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
int i;
name = current_monitor->regnames[regno];
+ RDEBUG(("MON fetchreg %d '%s'\n",regno,name))
- if (!name)
- {
+ if (!name || (*name == '\0'))
+ { RDEBUG(("No register known for %d\n",regno))
supply_register (regno, zerobuf);
return;
}
searching from the start of the buf. */
if (current_monitor->getreg.resp_delim)
- monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
+ {
+ RDEBUG(("EXP getreg.resp_delim\n"))
+ monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
+ /* Handle case of first 32 registers listed in pairs. */
+ if (current_monitor->flags & MO_32_REGS_PAIRED
+ && regno & 1 == 1 && regno < 32)
+ { RDEBUG(("EXP getreg.resp_delim\n")) ;
+ 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)
}
regbuf[i] = '\000'; /* terminate the number */
+ RDEBUG(("REGVAL '%s'\n",regbuf)) ;
/* 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
if (current_monitor->getreg.term)
{
+ RDEBUG(("EXP getreg.term\n"))
monitor_expect (current_monitor->getreg.term, NULL, 0); /* get response */
+ }
- if (current_monitor->getreg.term_cmd)
- {
- monitor_printf (current_monitor->getreg.term_cmd);
- monitor_expect_prompt (NULL, 0);
- }
+ if (current_monitor->getreg.term_cmd)
+ { RDEBUG(("EMIT getreg.term.cmd\n"))
+ monitor_printf (current_monitor->getreg.term_cmd);
}
- else
+ if (! current_monitor->getreg.term || /* Already expected or */
+ current_monitor->getreg.term_cmd) /* ack expected */
monitor_expect_prompt (NULL, 0); /* get response */
monitor_supply_register (regno, regbuf);
}
+/* Sometimes, it takes several commands to dump the registers */
+/* This is a primitive for use by variations of monitor interfaces in
+ case they need to compose the operation.
+ */
+int monitor_dump_reg_block(char * block_cmd)
+{
+ char buf[1024];
+ int resp_len;
+ monitor_printf (block_cmd);
+ resp_len = monitor_expect_prompt (buf, sizeof (buf));
+ parse_register_dump (buf, resp_len);
+ return 1 ;
+}
+
+
/* Read the remote registers into the block regs. */
+/* Call the specific function if it has been provided */
-static void monitor_dump_regs ()
+static void
+monitor_dump_regs ()
{
char buf[1024];
int resp_len;
-
- if (current_monitor->dump_registers)
- {
- monitor_printf (current_monitor->dump_registers);
+ if (current_monitor->dumpregs)
+ (*(current_monitor->dumpregs))() ; /* call supplied function */
+ else
+ if (current_monitor->dump_registers) /* default version */
+ { monitor_printf (current_monitor->dump_registers);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
parse_register_dump (buf, resp_len);
}
monitor_fetch_registers (regno)
int regno;
{
+ RDEBUG(("MON fetchregs\n")) ;
if (current_monitor->getreg.cmd)
{
if (regno >= 0)
unsigned int val;
name = current_monitor->regnames[regno];
- if (!name)
- return;
+ if (!name || (*name == '\0'))
+ { RDEBUG(("MON Cannot store unknown register\n"))
+ return;
+ }
val = read_register (regno);
+ RDEBUG(("MON storeg %d %08x\n",regno,(unsigned int)val))
- /* send the register deposit command */
+ /* send the register deposit command */
if (current_monitor->flags & MO_REGISTER_VALUE_FIRST)
monitor_printf (current_monitor->setreg.cmd, val, name);
+ else if (current_monitor->flags & MO_SETREG_INTERACTIVE)
+ monitor_printf (current_monitor->setreg.cmd, name);
else
monitor_printf (current_monitor->setreg.cmd, name, val);
-/* It's possible that there are actually some monitors out there that
- will prompt you when you set a register. In that case, you may
- need to add some code here to deal with TERM and TERM_CMD (see
- monitor_fetch_register to get an idea of what's needed...) */
-
- monitor_expect_prompt (NULL, 0);
-}
+ if (current_monitor->setreg.term)
+ { RDEBUG(("EXP setreg.term\n"))
+ monitor_expect (current_monitor->setreg.term, NULL, 0);
+ if (current_monitor->flags & MO_SETREG_INTERACTIVE)
+ monitor_printf ("%x\r", val);
+ monitor_expect_prompt (NULL, 0);
+ }
+ else
+ monitor_expect_prompt (NULL, 0);
+ if (current_monitor->setreg.term_cmd) /* Mode exit required */
+ { RDEBUG(("EXP setreg_termcmd\n")) ;
+ monitor_printf("%s",current_monitor->setreg.term_cmd) ;
+ monitor_expect_prompt(NULL,0) ;
+ }
+} /* monitor_store_register */
/* Store the remote registers. */
char *myaddr;
int len;
{
- unsigned int val;
+ unsigned int val, hostval ;
char *cmd;
int i;
+ RDEBUG(("MON write %d %08x\n",len,(unsigned long)memaddr))
+
+ if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
+ memaddr = ADDR_BITS_REMOVE (memaddr);
+
/* Use memory fill command for leading 0 bytes. */
if (current_monitor->fill)
if (i > 4) /* More than 4 zeros is worth doing */
{
- if (current_monitor->flags & MO_FILL_USES_ADDR)
- monitor_printf (current_monitor->fill, memaddr, memaddr + i, 0);
- else
- monitor_printf (current_monitor->fill, memaddr, i, 0);
+ RDEBUG(("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);
}
val = extract_unsigned_integer (myaddr, len);
+
+ if (len == 4)
+ { hostval = * (unsigned int *) myaddr ;
+ RDEBUG(("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.term)
+ { RDEBUG(("EXP setmem.term")) ;
+ monitor_expect (current_monitor->setmem.term, NULL, 0);
+ monitor_printf ("%x\r", val);
+ }
+ if (current_monitor->setmem.term_cmd)
+ { /* Emit this to get out of the memory editing state */
+ monitor_printf("%s",current_monitor->setmem.term_cmd) ;
+ /* Drop through to expecting a prompt */
+ }
+ }
else
monitor_printf (cmd, memaddr, val);
return len;
}
+
+static monitor_write_even_block(memaddr,myaddr,len)
+ CORE_ADDR memaddr ;
+ char * myaddr ;
+ int len ;
+{
+ unsigned int val ;
+ int written = 0 ;;
+ /* Enter the sub mode */
+ monitor_printf(current_monitor->setmem.cmdl,memaddr) ;
+ monitor_expect_prompt(NULL,0) ;
+
+ while (len)
+ {
+ val = extract_unsigned_integer(myaddr,4) ; /* REALLY */
+ monitor_printf("%x\r",val) ;
+ myaddr += 4 ;
+ memaddr += 4 ;
+ written += 4 ;
+ RDEBUG((" @ %08x\n",memaddr))
+ /* If we wanted to, here we could validate the address */
+ monitor_expect_prompt(NULL,0) ;
+ }
+ /* Now exit the sub mode */
+ monitor_printf (current_monitor->getreg.term_cmd);
+ monitor_expect_prompt(NULL,0) ;
+ return written ;
+}
+
+
+static int monitor_write_memory_bytes(memaddr,myaddr,len)
+ CORE_ADDR memaddr ;
+ char * myaddr ;
+ int len ;
+{
+ unsigned char val ;
+ int written = 0 ;
+ if (len == 0) return 0 ;
+ /* Enter the sub mode */
+ monitor_printf(current_monitor->setmem.cmdb,memaddr) ;
+ monitor_expect_prompt(NULL,0) ;
+ while (len)
+ {
+ val = *myaddr ;
+ monitor_printf("%x\r",val) ;
+ myaddr++ ;
+ memaddr++ ;
+ written++ ;
+ /* If we wanted to, here we could validate the address */
+ monitor_expect_prompt(NULL,0) ;
+ len-- ;
+ }
+ /* Now exit the sub mode */
+ monitor_printf (current_monitor->getreg.term_cmd);
+ monitor_expect_prompt(NULL,0) ;
+ return written ;
+}
+
+
+static 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-- ;
+ }
+}
+/* Format 32 chars of long long value, advance the pointer */
+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] ; /* disassembly buffer */
+ unsigned char * scan , * limit ; /* loop controls */
+ 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) ; /* FIXME: ONly on big endian hosts */
+ while (scan < limit)
+ { c = *scan++ ; /* a byte of our long long value */
+ if (leadzero)
+ if (c == 0) continue ;
+ else leadzero = 0 ; /* henceforth we print even zeroes */
+ nib = c >> 4 ; /* high nibble bits */
+ *outbuff++ = hexlate[nib] ;
+ nib = c & 0x0f ; /* low nibble bits */
+ *outbuff++ = hexlate[nib] ;
+ }
+ return outbuff ;
+ }
+} /* longlong_hexchars */
+
+
+
+/* I am only going to call this when writing virtual byte streams.
+ Which possably entails endian conversions
+ */
+static int monitor_write_memory_longlongs(memaddr,myaddr,len)
+ CORE_ADDR memaddr ;
+ char * myaddr ;
+ int len ;
+{
+ static char hexstage[20] ; /* At least 16 digits required, plus null */
+ 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' ; /* NUll terminate for printf */
+ monitor_printf("%s\r",hexstage) ;
+ llptr++ ;
+ memaddr += 8 ;
+ written += 8 ;
+ /* If we wanted to, here we could validate the address */
+ monitor_expect_prompt(NULL,0) ;
+ len -= 8 ;
+ }
+ /* Now exit the sub mode */
+ monitor_printf (current_monitor->getreg.term_cmd);
+ monitor_expect_prompt(NULL,0) ;
+ return written ;
+} /* */
+
+
+
+/* ----- MONITOR_WRITE_MEMORY_BLOCK ---------------------------- */
+/* This is for the large blocks of memory which may occur in downloading.
+ And for monitors which use interactive entry,
+ And for monitors which do not have other downloading methods.
+ Without this, we will end up calling monitor_write_memory many times
+ and do the entry and exit of the sub mode many times
+ This currently assumes...
+ MO_SETMEM_INTERACTIVE
+ ! MO_NO_ECHO_ON_SETMEM
+ To use this, the you have to patch the monitor_cmds block with
+ this function. Otherwise, its not tuned up for use by all
+ monitor variations.
+ */
+
+static int monitor_write_memory_block(memaddr,myaddr,len)
+ CORE_ADDR memaddr ;
+ char * myaddr ;
+ int len ;
+{
+ int written ;
+ written = 0 ;
+ /* FIXME: This would be a good place to put the zero test */
+#if 1
+ if ((len > 8) && (((len & 0x07)) == 0) && current_monitor->setmem.cmdll)
+ {
+ return monitor_write_memory_longlongs(memaddr,myaddr,len) ;
+ }
+#endif
+#if 0
+ if (len > 4)
+ {
+ int sublen ;
+ written = monitor_write_even_block(memaddr,myaddr,len) ;
+ /* Adjust calling parameters by written amount */
+ memaddr += written ;
+ myaddr += written ;
+ len -= written ;
+ }
+#endif
+ written = monitor_write_memory_bytes(memaddr,myaddr,len) ;
+ return written ;
+}
+
/* 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. */
char *cmd;
int i;
+ RDEBUG(("MON read single\n")) ;
#if 0
/* Can't actually use long longs (nice idea, though). In fact, the
call to strtoul below will fail if it tries to convert a value
cmd = current_monitor->getmem.cmdb;
}
-/* Send the examine command. */
+ /* 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 RESP_DELIM is specified, we search for that as a leading
+ delimiter for the memory value. Otherwise, we just start
+ searching from the start of the buf. */
if (current_monitor->getmem.resp_delim)
- monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0);
+ { RDEBUG(("EXP getmem.resp_delim\n")) ;
+ monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0);
+ }
-/* Now, read the appropriate number of hex digits for this loc, skipping
- spaces. */
+ /* 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 */
+ /* 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);
+ error ("monitor_read_memory_single (0x%x): bad response from monitor: %.*s%c.",
+ memaddr, i, membuf, c);
}
for (i = 0; i < len * 2; i++)
{
return len;
}
-/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory
- at MEMADDR. Returns length moved. Currently, we only do one byte at a
- time. */
+/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
+ memory at MEMADDR. Returns length moved. Currently, we do no more
+ than 16 bytes at a time. */
static int
monitor_read_memory (memaddr, myaddr, len)
int len;
{
unsigned int val;
- unsigned char regbuf[MAX_REGISTER_RAW_SIZE];
char buf[512];
char *p, *p1;
- char *name;
int resp_len;
int i;
+ CORE_ADDR dumpaddr;
+
+ if (remote_debug) printf("MON read block ta(%08x) ha(%08x) %d\n",
+ (unsigned long) memaddr , (unsigned 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);
-/* See if xfer would cross a 16 byte boundary. If so, clip it. */
+ /* Some dumpers align the first data with the preceeding 16
+ byte boundary. Some print blanks and start at the
+ requested boundary. EXACT_DUMPADDR
+ */
+
+ dumpaddr = (current_monitor->flags & MO_EXACT_DUMPADDR)
+ ? memaddr : memaddr & ~ 0x0f ;
+
+ /* See if xfer would cross a 16 byte boundary. If so, clip it. */
if (((memaddr ^ (memaddr + len - 1)) & ~0xf) != 0)
len = ((memaddr + len) & ~0xf) - memaddr;
- /* send the memory examine command */
+ /* send the memory examine command */
if (current_monitor->flags & MO_GETMEM_NEEDS_RANGE)
monitor_printf (current_monitor->getmem.cmdb, memaddr, memaddr + len - 1);
+ else if (current_monitor->flags & MO_GETMEM_16_BOUNDARY)
+ monitor_printf (current_monitor->getmem.cmdb, dumpaddr);
else
monitor_printf (current_monitor->getmem.cmdb, memaddr, len);
-/* 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->getmem.term)
{
p = buf;
- /* 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.
- */
+ /* 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. */
if (current_monitor->getmem.resp_delim)
{
int retval, tmp;
struct re_registers resp_strings;
+ RDEBUG(("MON getmem.resp_delim %s\n",current_monitor->getmem.resp_delim)) ;
tmp = strlen (p);
retval = re_search (&getmem_resp_delim_pattern, p, tmp, 0, tmp,
p += strlen (current_monitor->getmem.resp_delim);
#endif
}
+ if (remote_debug) printf("MON scanning %d ,%08x '%s'\n",len,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 (remote_debug) printf("[%02x]",val) ;
+ --i;
+ fetched++ ;
+ }
+ ++dumpaddr;
+ ++p;
+ }
+ ++p; /* skip a blank or other non hex char */
+ c = *p ;
+ }
+ if (fetched == 0) error("Failed to read via monitor") ;
+ if (remote_debug) printf("\n") ;
+ return fetched ; /* Return the number of bytes actually read */
+ }
+ RDEBUG(("MON scanning bytes\n")) ;
for (i = len; i > 0; i--)
{
{
if (isxdigit (*p))
break;
+
if (*p == '\000' || *p == '\n' || *p == '\r')
error ("monitor_read_memory (0x%x): badly terminated response from monitor: %.*s", memaddr, resp_len, buf);
p++;
return len;
}
+/* This version supports very large reads by looping on multiline
+ dump bytes outputs. Beware of buffering limits.
+ */
+static int monotor_read_memory_block(memaddr,myaddr,len)
+ CORE_ADDR memaddr ;
+ char * myaddr ;
+ int len ;
+{
+}
+
static int
monitor_xfer_memory (memaddr, myaddr, len, write, target)
CORE_ADDR memaddr;
char *shadow;
{
int i;
- static unsigned char break_insn[] = BREAKPOINT;
+ unsigned char *bp;
+ int bplen;
+
+ RDEBUG(("MON inst bkpt %08x\n",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);
+
+ /* Determine appropriate breakpoint size for this address. */
+ bp = memory_breakpoint_from_pc (&addr, &bplen);
for (i = 0; i < NUM_MONITOR_BREAKPOINTS; i++)
{
if (breakaddr[i] == 0)
{
breakaddr[i] = addr;
- monitor_read_memory (addr, shadow, sizeof (break_insn));
+ monitor_read_memory (addr, shadow, bplen);
monitor_printf (current_monitor->set_break, addr);
monitor_expect_prompt (NULL, 0);
return 0;
{
int i;
+ RDEBUG(("MON rmbkpt %08x\n",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 < NUM_MONITOR_BREAKPOINTS; i++)
{
if (breakaddr[i] == addr)
{
breakaddr[i] = 0;
/* some monitors remove breakpoints based on the address */
- if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR)
+ if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR)
monitor_printf (current_monitor->clr_break, addr);
+ else if (current_monitor->flags & MO_CLR_BREAK_1_BASED)
+ monitor_printf (current_monitor->clr_break, i + 1);
else
monitor_printf (current_monitor->clr_break, i);
monitor_expect_prompt (NULL, 0);
static int
monitor_wait_srec_ack ()
{
- /* FIXME: eventually we'll want to be able to handle acknowledgements
- of something other than a '+' character. Right now this is only
- going to work for EST visionICE. */
- return readchar (timeout) == '+';
+ int i, ch;
+
+ if (current_monitor->flags & MO_SREC_ACK_PLUS)
+ {
+ return (readchar (timeout) == '+');
+ }
+ else if (current_monitor->flags & MO_SREC_ACK_ROTATE)
+ {
+ /* Eat two backspaces, a "rotating" char (|/-\), and a space. */
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ }
+ return 1;
}
/* monitor_load -- download a file. */
int from_tty;
{
dcache_flush (remote_dcache);
+ RDEBUG(("MON load\n"))
if (current_monitor->load_routine)
current_monitor->load_routine (monitor_desc, file, hashmark);
else
{ /* The default is ascii S-records */
+ int n;
+ unsigned long load_offset;
+ char buf[128];
+
+ /* enable user to specify address for downloading as 2nd arg to load */
+ n = sscanf (file, "%s 0x%lx", buf, &load_offset);
+ if (n > 1)
+ file = buf;
+ else
+ load_offset = 0;
+
monitor_printf (current_monitor->load);
if (current_monitor->loadresp)
monitor_expect (current_monitor->loadresp, NULL, 0);
-/* FIXME Should add arg here for load_offset (already done for generic_load) */
- load_srec (monitor_desc, file, 32, SREC_ALL, hashmark,
+ load_srec (monitor_desc, file, (bfd_vma) load_offset,
+ 32, SREC_ALL, hashmark,
current_monitor->flags & MO_SREC_ACK ?
monitor_wait_srec_ack : NULL);
static void
monitor_stop ()
{
+ RDEBUG(("MON stop\n")) ;
if ((current_monitor->flags & MO_SEND_BREAK_ON_STOP) != 0)
SERIAL_SEND_BREAK (monitor_desc);
if (current_monitor->stop)
/* Convert hex digit A to a number. */
+#if 0
static int
from_hex (a)
int a;
error ("Reply contains invalid hex digit 0x%x", a);
}
+#endif
+
+char *
+monitor_get_dev_name ()
+{
+ return dev_name;
+}
static struct target_ops monitor_ops =
{