/* Remote debugging interface for MIPS remote debugging protocol.
- Copyright 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by Ian Lance Taylor
<ian@cygnus.com>.
#include "remote-utils.h"
#include <signal.h>
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
#include <varargs.h>
+#endif
+
+extern char *mips_read_processor_type PARAMS ((void));
+
+extern void mips_set_processor_type_command PARAMS ((char *, int));
+
\f
/* Prototypes for local functions. */
-static int
-mips_readchar PARAMS ((int timeout));
+static int mips_readchar PARAMS ((int timeout));
-static int
-mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage, int ch,
- int timeout));
+static int mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage,
+ int ch, int timeout));
-static int
-mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage, int *pch,
- int timeout));
+static int mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage,
+ int *pch, int timeout));
static int mips_cksum PARAMS ((const unsigned char *hdr,
const unsigned char *data,
int len));
-static void
-mips_send_packet PARAMS ((const char *s, int get_ack));
+static void mips_send_packet PARAMS ((const char *s, int get_ack));
static int mips_receive_packet PARAMS ((char *buff, int throw_error,
int timeout));
-static int
-mips_request PARAMS ((char cmd, unsigned int addr, unsigned int data,
- int *perr, int timeout));
+static int mips_request PARAMS ((char cmd, unsigned int addr,
+ unsigned int data, int *perr, int timeout));
-static void
-mips_initialize PARAMS ((void));
+static void mips_initialize PARAMS ((void));
-static void
-mips_open PARAMS ((char *name, int from_tty));
+static void mips_open PARAMS ((char *name, int from_tty));
-static void
-mips_close PARAMS ((int quitting));
+static void mips_close PARAMS ((int quitting));
-static void
-mips_detach PARAMS ((char *args, int from_tty));
+static void mips_detach PARAMS ((char *args, int from_tty));
static void mips_resume PARAMS ((int pid, int step,
enum target_signal siggnal));
-static int
-mips_wait PARAMS ((int pid, struct target_waitstatus *status));
-
-static int
-mips_map_regno PARAMS ((int regno));
+static int mips_wait PARAMS ((int pid, struct target_waitstatus *status));
-static void
-mips_fetch_registers PARAMS ((int regno));
+static int mips_map_regno PARAMS ((int regno));
-static void
-mips_prepare_to_store PARAMS ((void));
+static void mips_fetch_registers PARAMS ((int regno));
-static void
-mips_store_registers PARAMS ((int regno));
+static void mips_prepare_to_store PARAMS ((void));
-static int
-mips_fetch_word PARAMS ((CORE_ADDR addr));
+static void mips_store_registers PARAMS ((int regno));
-static void
-mips_store_word PARAMS ((CORE_ADDR addr, int value));
+static int mips_fetch_word PARAMS ((CORE_ADDR addr));
-static int
-mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
- int write, struct target_ops *ignore));
+static int mips_store_word PARAMS ((CORE_ADDR addr, int value,
+ char *old_contents));
-static void
-mips_files_info PARAMS ((struct target_ops *ignore));
+static int mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct target_ops *ignore));
-static void
-mips_load PARAMS ((char *args, int from_tty));
+static void mips_files_info PARAMS ((struct target_ops *ignore));
-static void
-mips_create_inferior PARAMS ((char *execfile, char *args, char **env));
+static void mips_create_inferior PARAMS ((char *execfile, char *args,
+ char **env));
-static void
-mips_mourn_inferior PARAMS ((void));
+static void mips_mourn_inferior PARAMS ((void));
/* A forward declaration. */
extern struct target_ops mips_ops;
The value is
0x40 + seq
An acknowlegment packet contains the sequence number of the
- packet being acknowledged plus 1 module 64. Data packets are
+ packet being acknowledged plus 1 modulo 64. Data packets are
transmitted in sequence. There may only be one outstanding
unacknowledged data packet at a time. The sequence numbers
are independent in each direction. If an acknowledgement for
all hell to break loose--the rest of GDB will tend to get left in an
inconsistent state. */
-static void NORETURN
+static NORETURN void
+#ifdef ANSI_PROTOTYPES
+mips_error (char *string, ...)
+#else
mips_error (va_alist)
va_dcl
+#endif
{
va_list args;
- char *string;
+#ifdef ANSI_PROTOTYPES
+ va_start (args, string);
+#else
+ char *string;
va_start (args);
+ string = va_arg (args, char *);
+#endif
+
target_terminal_ours ();
wrap_here(""); /* Force out any buffered output */
gdb_flush (gdb_stdout);
if (error_pre_print)
fprintf_filtered (gdb_stderr, error_pre_print);
- string = va_arg (args, char *);
vfprintf_filtered (gdb_stderr, string, args);
fprintf_filtered (gdb_stderr, "\n");
va_end (args);
int ch;
static int state = 0;
static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
+#ifdef MAINTENANCE_CMDS
+ int i;
+
+ i = timeout;
+ if (i == -1 && watchdog > 0)
+ i = watchdog;
+#endif
+ if (state == 5)
+ timeout = 1;
ch = SERIAL_READCHAR (mips_desc, timeout);
+#ifdef MAINTENANCE_CMDS
+ if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+#endif
if (ch == SERIAL_EOF)
mips_error ("End of file from remote");
if (ch == SERIAL_ERROR)
mips_error ("Error reading from remote: %s", safe_strerror (errno));
if (sr_get_debug () > 1)
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
if (ch != SERIAL_TIMEOUT)
- printf_filtered ("Read '%c' %d 0x%x\n", ch, ch, ch);
+ printf_unfiltered ("Read '%c' %d 0x%x\n", ch, ch, ch);
else
- printf_filtered ("Timed out in read\n");
+ printf_unfiltered ("Timed out in read\n");
}
/* If we have seen <IDT> and we either time out, or we see a @
&& ! mips_initializing)
{
if (sr_get_debug () > 0)
- printf_filtered ("Reinitializing MIPS debugging mode\n");
- SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Reinitializing MIPS debugging mode\n");
+ SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
sleep (1);
mips_need_reply = 0;
state = 0;
- mips_error ("Remote board reset");
+ /* At this point, about the only thing we can do is abort the command
+ in progress and get back to command level as quickly as possible. */
+
+ error ("Remote board reset, debug protocol re-initialized.");
}
if (ch == nextstate[state])
{
/* Printing the character here lets the user of gdb see
what the program is outputting, if the debugging is
- being done on the console port. FIXME: Perhaps this
- should be filtered? */
+ being done on the console port. Don't use _filtered;
+ we can't deal with a QUIT out of target_wait. */
if (! mips_initializing || sr_get_debug () > 0)
{
- putchar_unfiltered (ch);
+ if (ch < 0x20 && ch != '\n')
+ {
+ putchar_unfiltered ('^');
+ putchar_unfiltered (ch + 0x40);
+ }
+ else
+ putchar_unfiltered (ch);
gdb_flush (gdb_stdout);
}
if (sr_get_debug () > 0)
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0';
- printf_filtered ("Writing \"%s\"\n", packet + 1);
+ printf_unfiltered ("Writing \"%s\"\n", packet + 1);
}
if (SERIAL_WRITE (mips_desc, packet,
{
hdr[HDR_LENGTH] = '\0';
trlr[TRLR_LENGTH] = '\0';
- printf_filtered ("Got ack %d \"%s%s\"\n",
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Got ack %d \"%s%s\"\n",
HDR_GET_SEQ (hdr), hdr + 1, trlr);
}
/* An acknowledgement is probably a duplicate; ignore it. */
if (! HDR_IS_DATA (hdr))
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
if (sr_get_debug () > 0)
- printf_filtered ("Ignoring unexpected ACK\n");
+ printf_unfiltered ("Ignoring unexpected ACK\n");
continue;
}
/* If this is the wrong sequence number, ignore it. */
if (HDR_GET_SEQ (hdr) != mips_receive_seq)
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
if (sr_get_debug () > 0)
- printf_filtered ("Ignoring sequence number %d (want %d)\n",
+ printf_unfiltered ("Ignoring sequence number %d (want %d)\n",
HDR_GET_SEQ (hdr), mips_receive_seq);
continue;
}
if (i < len)
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
if (sr_get_debug () > 0)
- printf_filtered ("Got new SYN after %d chars (wanted %d)\n",
+ printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n",
i, len);
continue;
}
}
if (err == -2)
{
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
if (sr_get_debug () > 0)
- printf_filtered ("Got SYN when wanted trailer\n");
+ printf_unfiltered ("Got SYN when wanted trailer\n");
continue;
}
break;
if (sr_get_debug () > 0)
- printf_filtered ("Bad checksum; data %d, trailer %d\n",
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
mips_cksum (hdr, buff, len),
TRLR_GET_CKSUM (trlr));
if (sr_get_debug () > 0)
{
ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
- printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
ack + 1);
}
if (sr_get_debug () > 0)
{
buff[len] = '\0';
- printf_filtered ("Got packet \"%s\"\n", buff);
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Got packet \"%s\"\n", buff);
}
/* We got the packet. Send an acknowledgement. */
if (sr_get_debug () > 0)
{
ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
- printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+ /* Don't use _filtered; we can't deal with a QUIT out of
+ target_wait, and I think this might be called from there. */
+ printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
ack + 1);
}
char rcmd;
int rerrflg;
int rresponse;
-
+
if (cmd != '\0')
{
if (mips_need_reply)
/* The board seems to want to send us a packet. I don't know what
it means. The packet seems to be triggered by a carriage return
character, although perhaps any character would do. */
- cr = '\r';
+ cr = '\015';
+ /* FIXME check the result from this */
SERIAL_WRITE (mips_desc, &cr, 1);
if (mips_receive_packet (buff, 0, 3) < 0)
cc = '\003';
SERIAL_WRITE (mips_desc, &cc, 1);
sleep (2);
- SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
+ SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
sleep (1);
- cr = '\r';
+ cr = '\015';
SERIAL_WRITE (mips_desc, &cr, 1);
}
mips_receive_packet (buff, 1, 3);
char *name;
int from_tty;
{
+ char *ptype;
+
if (name == 0)
error (
"To open a MIPS remote debugging connection, you need to specify what serial\n\
if (mips_desc == (serial_t) NULL)
perror_with_name (name);
+ if (baud_rate != -1)
+ {
+ if (SERIAL_SETBAUDRATE (mips_desc, baud_rate))
+ {
+ SERIAL_CLOSE (mips_desc);
+ perror_with_name (name);
+ }
+ }
+
SERIAL_RAW (mips_desc);
mips_is_open = 1;
if (from_tty)
printf_unfiltered ("Remote MIPS debugging using %s\n", name);
- push_target (&mips_ops); /* Switch to using remote target now */
+
+ /* Switch to using remote target now. */
+ push_target (&mips_ops);
/* FIXME: Should we call start_remote here? */
+
+ /* Try to figure out the processor model if possible. */
+ ptype = mips_read_processor_type ();
+ if (ptype)
+ mips_set_processor_type_command (strsave (ptype), 0);
+
+/* This is really the job of start_remote however, that makes an assumption
+ that the target is about to print out a status message of some sort. That
+ doesn't happen here (in fact, it may not be possible to get the monitor to
+ send the appropriate packet). */
+
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ set_current_frame (create_new_frame (read_fp (), stop_pc));
+ select_frame (get_current_frame (), 0);
+ print_stack_frame (selected_frame, -1, 1);
}
/* Close a connection to the remote board. */
return;
}
- val = mips_request ('r', (unsigned int) mips_map_regno (regno),
- (unsigned int) 0, &err, mips_receive_wait);
- if (err)
- mips_error ("Can't read register %d: %s", regno, safe_strerror (errno));
+ if (regno == FP_REGNUM || regno == ZERO_REGNUM)
+ /* FP_REGNUM on the mips is a hack which is just supposed to read
+ zero (see also mips-nat.c). */
+ val = 0;
+ else
+ {
+ val = mips_request ('r', (unsigned int) mips_map_regno (regno),
+ (unsigned int) 0, &err, mips_receive_wait);
+ if (err)
+ mips_error ("Can't read register %d: %s", regno,
+ safe_strerror (errno));
+ }
{
char buf[MAX_REGISTER_RAW_SIZE];
return val;
}
-/* Store a word to the target board. */
+/* Store a word to the target board. Returns errno code or zero for
+ success. If OLD_CONTENTS is non-NULL, put the old contents of that
+ memory location there. */
-static void
-mips_store_word (addr, val)
+static int
+mips_store_word (addr, val, old_contents)
CORE_ADDR addr;
int val;
+ char *old_contents;
{
int err;
+ unsigned int oldcontents;
- mips_request ('D', (unsigned int) addr, (unsigned int) val, &err,
- mips_receive_wait);
+ oldcontents = mips_request ('D', (unsigned int) addr, (unsigned int) val,
+ &err,
+ mips_receive_wait);
if (err)
{
/* Data space failed; try instruction space. */
- mips_request ('I', (unsigned int) addr, (unsigned int) val, &err,
- mips_receive_wait);
+ oldcontents = mips_request ('I', (unsigned int) addr,
+ (unsigned int) val, &err,
+ mips_receive_wait);
if (err)
- mips_error ("Can't write address 0x%x: %s", addr, safe_strerror (errno));
+ return errno;
}
+ if (old_contents != NULL)
+ store_unsigned_integer (old_contents, 4, oldcontents);
+ return 0;
}
/* Read or write LEN bytes from inferior memory at MEMADDR,
/* Allocate buffer of that many longwords. */
register char *buffer = alloca (count * 4);
+ int status;
+
if (write)
{
/* Fill start and end extra bytes of buffer with existing data. */
for (i = 0; i < count; i++, addr += 4)
{
- mips_store_word (addr, extract_unsigned_integer (&buffer[i*4], 4));
+ status = mips_store_word (addr,
+ extract_unsigned_integer (&buffer[i*4], 4),
+ NULL);
+ /* Report each kilobyte (we download 32-bit words at a time) */
+ if (i % 256 == 255)
+ {
+ printf_unfiltered ("*");
+ fflush (stdout);
+ }
+ if (status)
+ {
+ errno = status;
+ return 0;
+ }
/* FIXME: Do we want a QUIT here? */
}
+ if (count >= 256)
+ printf_unfiltered ("\n");
}
else
{
CORE_ADDR entry_pt;
if (args && *args)
- mips_error ("Can't pass arguments to remote MIPS board.");
+ {
+ warning ("\
+Can't pass arguments to remote MIPS board; arguments ignored.");
+ /* And don't try to use them on the next "run" command. */
+ execute_command ("set args", 0);
+ }
if (execfile == 0 || exec_bfd == 0)
- mips_error ("No exec file specified");
+ error ("No executable file specified");
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
generic_mourn_inferior ();
}
\f
+/* We can write a breakpoint and read the shadow contents in one
+ operation. */
+
+/* The IDT board uses an unusual breakpoint value, and sometimes gets
+ confused when it sees the usual MIPS breakpoint instruction. */
+
+#define BREAK_INSN (0x00000a0d)
+#define BREAK_INSN_SIZE (4)
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+ support. We read the contents of the target location and stash it,
+ then overwrite it with a breakpoint instruction. ADDR is the target
+ location in the target machine. CONTENTS_CACHE is a pointer to
+ memory allocated for saving the target contents. It is guaranteed
+ by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+ is accomplished via BREAKPOINT_MAX). */
+
+static int
+mips_insert_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ int status;
+
+ return mips_store_word (addr, BREAK_INSN, contents_cache);
+}
+
+static int
+mips_remove_breakpoint (addr, contents_cache)
+ CORE_ADDR addr;
+ char *contents_cache;
+{
+ return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE);
+}
+\f
/* The target vector. */
struct target_ops mips_ops =
mips_prepare_to_store, /* to_prepare_to_store */
mips_xfer_memory, /* to_xfer_memory */
mips_files_info, /* to_files_info */
- NULL, /* to_insert_breakpoint */
- NULL, /* to_remove_breakpoint */
+ mips_insert_breakpoint, /* to_insert_breakpoint */
+ mips_remove_breakpoint, /* to_remove_breakpoint */
NULL, /* to_terminal_init */
NULL, /* to_terminal_inferior */
NULL, /* to_terminal_ours_for_output */
mips_mourn_inferior, /* to_mourn_inferior */
NULL, /* to_can_run */
NULL, /* to_notice_signals */
+ 0, /* to_thread_alive */
+ 0, /* to_stop */
process_stratum, /* to_stratum */
NULL, /* to_next */
1, /* to_has_all_memory */