/* Remote debugging interface for MIPS remote debugging protocol.
- Copyright 1993 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 "defs.h"
#include "inferior.h"
-#include "symfile.h"
#include "bfd.h"
+#include "symfile.h"
#include "wait.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "serial.h"
#include "target.h"
+#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));
+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));
+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 step, int siggnal));
+static void mips_resume PARAMS ((int pid, int step,
+ enum target_signal siggnal));
-static int
-mips_wait PARAMS ((WAITTYPE *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
a reply. */
static int mips_need_reply = 0;
-/* This can be set to get debugging with ``set remotedebug''. */
-static int mips_debug = 0;
-
/* Handle used to access serial I/O stream. */
static serial_t mips_desc;
+/* Handle low-level error that we can't recover from. Note that just
+ error()ing out from target_wait or some such low-level place will cause
+ all hell to break loose--the rest of GDB will tend to get left in an
+ inconsistent state. */
+
+static NORETURN void
+#ifdef ANSI_PROTOTYPES
+mips_error (char *string, ...)
+#else
+mips_error (va_alist)
+ va_dcl
+#endif
+{
+ va_list args;
+
+#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);
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ va_end (args);
+
+ /* Clean up in such a way that mips_close won't try to talk to the
+ board (it almost surely won't work since we weren't able to talk to
+ it). */
+ mips_is_open = 0;
+ SERIAL_CLOSE (mips_desc);
+
+ printf_unfiltered ("Ending remote MIPS debugging.\n");
+ target_mourn_inferior ();
+
+ return_to_top_level (RETURN_ERROR);
+}
+
/* Read a character from the remote, aborting on error. Returns
SERIAL_TIMEOUT on timeout (since that's what SERIAL_READCHAR
returns). FIXME: If we see the string "<IDT>" from the board, then
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)
- error ("End of file from remote");
+ mips_error ("End of file from remote");
if (ch == SERIAL_ERROR)
- error ("Error reading from remote: %s", safe_strerror (errno));
- if (mips_debug > 1)
+ 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 @
&& state == 5
&& ! mips_initializing)
{
- if (mips_debug > 0)
- printf_filtered ("Reinitializing MIPS debugging mode\n");
- SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
+ 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. */
+ 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;
- 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? */
- if (! mips_initializing || mips_debug > 0)
+ 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 (ch);
- fflush (stdout);
+ if (ch < 0x20 && ch != '\n')
+ {
+ putchar_unfiltered ('^');
+ putchar_unfiltered (ch + 0x40);
+ }
+ else
+ putchar_unfiltered (ch);
+ gdb_flush (gdb_stdout);
}
++*pgarbage;
if (*pgarbage > mips_syn_garbage)
- error ("Remote debugging protocol failure");
+ mips_error ("Remote debugging protocol failure");
}
}
len = strlen (s);
if (len > DATA_MAXLEN)
- error ("MIPS protocol data packet too long: %s", s);
+ mips_error ("MIPS protocol data packet too long: %s", s);
packet = (unsigned char *) alloca (HDR_LENGTH + len + TRLR_LENGTH + 1);
int garbage;
int ch;
- if (mips_debug > 0)
+ 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_LENGTH + len + TRLR_LENGTH) != 0)
- error ("write to target failed: %s", safe_strerror (errno));
+ mips_error ("write to target failed: %s", safe_strerror (errno));
garbage = 0;
ch = 0;
!= TRLR_GET_CKSUM (trlr))
continue;
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
{
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);
}
}
}
- error ("Remote did not acknowledge packet");
+ mips_error ("Remote did not acknowledge packet");
}
/* Receive and acknowledge a packet, returning the data in BUFF (which
should be DATA_MAXLEN + 1 bytes). The protocol documentation
implies that only the sender retransmits packets, so this code just
waits silently for a packet. It returns the length of the received
- packet. */
+ packet. If THROW_ERROR is nonzero, call error() on errors. If not,
+ don't print an error message and return -1. */
static int
-mips_receive_packet (buff)
+mips_receive_packet (buff, throw_error, timeout)
char *buff;
+ int throw_error;
+ int timeout;
{
int ch;
int garbage;
int i;
int err;
- if (mips_receive_header (hdr, &garbage, ch, mips_receive_wait) != 0)
- error ("Timed out waiting for remote packet");
+ if (mips_receive_header (hdr, &garbage, ch, timeout) != 0)
+ {
+ if (throw_error)
+ mips_error ("Timed out waiting for remote packet");
+ else
+ return -1;
+ }
ch = 0;
/* An acknowledgement is probably a duplicate; ignore it. */
if (! HDR_IS_DATA (hdr))
{
- if (mips_debug > 0)
- printf_filtered ("Ignoring unexpected ACK\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. */
+ if (sr_get_debug () > 0)
+ printf_unfiltered ("Ignoring unexpected ACK\n");
continue;
}
/* If this is the wrong sequence number, ignore it. */
if (HDR_GET_SEQ (hdr) != mips_receive_seq)
{
- if (mips_debug > 0)
- printf_filtered ("Ignoring sequence number %d (want %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. */
+ if (sr_get_debug () > 0)
+ printf_unfiltered ("Ignoring sequence number %d (want %d)\n",
HDR_GET_SEQ (hdr), mips_receive_seq);
continue;
}
{
int rch;
- rch = mips_readchar (mips_receive_wait);
+ rch = mips_readchar (timeout);
if (rch == SYN)
{
ch = SYN;
break;
}
if (rch == SERIAL_TIMEOUT)
- error ("Timed out waiting for remote packet");
+ {
+ if (throw_error)
+ mips_error ("Timed out waiting for remote packet");
+ else
+ return -1;
+ }
buff[i] = rch;
}
if (i < len)
{
- if (mips_debug > 0)
- printf_filtered ("Got new SYN after %d chars (wanted %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. */
+ if (sr_get_debug () > 0)
+ printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n",
i, len);
continue;
}
- err = mips_receive_trailer (trlr, &garbage, &ch, mips_receive_wait);
+ err = mips_receive_trailer (trlr, &garbage, &ch, timeout);
if (err == -1)
- error ("Timed out waiting for packet");
+ {
+ if (throw_error)
+ mips_error ("Timed out waiting for packet");
+ else
+ return -1;
+ }
if (err == -2)
{
- if (mips_debug > 0)
- printf_filtered ("Got SYN when wanted trailer\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. */
+ if (sr_get_debug () > 0)
+ printf_unfiltered ("Got SYN when wanted trailer\n");
continue;
}
if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr))
break;
- if (mips_debug > 0)
- printf_filtered ("Bad checksum; data %d, trailer %d\n",
+ 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. */
+ printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
mips_cksum (hdr, buff, len),
TRLR_GET_CKSUM (trlr));
ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
- if (mips_debug > 0)
+ 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 (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
- error ("write to target failed: %s", safe_strerror (errno));
+ {
+ if (throw_error)
+ mips_error ("write to target failed: %s", safe_strerror (errno));
+ else
+ return -1;
+ }
}
- if (mips_debug > 0)
+ 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. */
ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
- if (mips_debug > 0)
+ 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 (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
- error ("write to target failed: %s", safe_strerror (errno));
+ {
+ if (throw_error)
+ mips_error ("write to target failed: %s", safe_strerror (errno));
+ else
+ return -1;
+ }
return len;
}
target board reports. */
static int
-mips_request (cmd, addr, data, perr)
+mips_request (cmd, addr, data, perr, timeout)
char cmd;
unsigned int addr;
unsigned int data;
int *perr;
+ int timeout;
{
char buff[DATA_MAXLEN + 1];
int len;
char rcmd;
int rerrflg;
int rresponse;
-
+
if (cmd != '\0')
{
if (mips_need_reply)
mips_need_reply = 0;
- len = mips_receive_packet (buff);
+ len = mips_receive_packet (buff, 1, timeout);
buff[len] = '\0';
if (sscanf (buff, "0x%x %c 0x%x 0x%x",
&rpid, &rcmd, &rerrflg, &rresponse) != 4
|| (cmd != '\0' && rcmd != cmd))
- error ("Bad response from remote board");
+ mips_error ("Bad response from remote board");
if (rerrflg != 0)
{
return rresponse;
}
+static void
+mips_initialize_cleanups (arg)
+ PTR arg;
+{
+ mips_initializing = 0;
+}
+
/* Initialize a new connection to the MIPS board, and make sure we are
really connected. */
mips_initialize ()
{
char cr;
- int hold_wait;
- int tries;
char buff[DATA_MAXLEN + 1];
int err;
+ struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL);
+ /* What is this code doing here? I don't see any way it can happen, and
+ it might mean mips_initializing didn't get cleared properly.
+ So I'll make it a warning. */
if (mips_initializing)
- return;
+ {
+ warning ("internal error: mips_initialize called twice");
+ return;
+ }
mips_initializing = 1;
/* 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);
- hold_wait = mips_receive_wait;
- mips_receive_wait = 3;
-
- tries = 0;
- while (catch_errors (mips_receive_packet, buff, (char *) NULL,
- RETURN_MASK_ALL)
- == 0)
+ if (mips_receive_packet (buff, 0, 3) < 0)
{
char cc;
- if (tries > 0)
- error ("Could not connect to target");
- ++tries;
-
/* We did not receive the packet we expected; try resetting the
board and trying again. */
printf_filtered ("Failed to initialize; trying to reset board\n");
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);
- mips_receive_wait = hold_wait;
- mips_initializing = 0;
+ do_cleanups (old_cleanups);
/* If this doesn't call error, we have connected; we don't care if
the request itself succeeds or fails. */
- mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err);
+ mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err,
+ mips_receive_wait);
}
/* Open a connection to the remote board. */
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;
mips_initialize ();
if (from_tty)
- printf ("Remote MIPS debugging using %s\n", name);
- push_target (&mips_ops); /* Switch to using remote target now */
+ printf_unfiltered ("Remote MIPS debugging using %s\n", name);
+
+ /* 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. */
mips_is_open = 0;
/* Get the board out of remote debugging mode. */
- mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err);
+ mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
+ mips_receive_wait);
SERIAL_CLOSE (mips_desc);
}
pop_target ();
if (from_tty)
- printf ("Ending remote MIPS debugging.\n");
+ printf_unfiltered ("Ending remote MIPS debugging.\n");
}
/* Tell the target board to resume. This does not wait for a reply
from the board. */
static void
-mips_resume (step, siggnal)
- int step, siggnal;
+mips_resume (pid, step, siggnal)
+ int pid, step;
+ enum target_signal siggnal;
{
- if (siggnal)
- error ("Can't send signals to a remote system. Try `handle %d ignore'.",
- siggnal);
+ if (siggnal != TARGET_SIGNAL_0)
+ warning
+ ("Can't send signals to a remote system. Try `handle %s ignore'.",
+ target_signal_to_name (siggnal));
mips_request (step ? 's' : 'c',
(unsigned int) 1,
(unsigned int) 0,
- (int *) NULL);
+ (int *) NULL,
+ mips_receive_wait);
+}
+
+/* Return the signal corresponding to SIG, where SIG is the number which
+ the MIPS protocol uses for the signal. */
+enum target_signal
+mips_signal_from_protocol (sig)
+ int sig;
+{
+ /* We allow a few more signals than the IDT board actually returns, on
+ the theory that there is at least *some* hope that perhaps the numbering
+ for these signals is widely agreed upon. */
+ if (sig <= 0
+ || sig > 31)
+ return TARGET_SIGNAL_UNKNOWN;
+
+ /* Don't want to use target_signal_from_host because we are converting
+ from MIPS signal numbers, not host ones. Our internal numbers
+ match the MIPS numbers for the signals the board can return, which
+ are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP. */
+ return (enum target_signal) sig;
}
/* Wait until the remote stops, and return a wait status. */
static int
-mips_wait (status)
- WAITTYPE *status;
+mips_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
{
int rstatus;
int err;
indicating that it is stopped. */
if (! mips_need_reply)
{
- WSETSTOP (*status, SIGTRAP);
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
return 0;
}
- rstatus = mips_request ('\0', (unsigned int) 0, (unsigned int) 0, &err);
+ /* No timeout; we sit here as long as the program continues to execute. */
+ rstatus = mips_request ('\0', (unsigned int) 0, (unsigned int) 0, &err, -1);
if (err)
- error ("Remote failure: %s", safe_strerror (errno));
+ mips_error ("Remote failure: %s", safe_strerror (errno));
- /* FIXME: The target board uses numeric signal values which are
- those used on MIPS systems. If the host uses different signal
- values, we need to translate here. I believe all Unix systems
- use the same values for the signals the board can return, which
- are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP. */
-
- /* FIXME: The target board uses a standard Unix wait status int. If
- the host system does not, we must translate here. */
-
- *status = rstatus;
+ /* Translate a MIPS waitstatus. We use constants here rather than WTERMSIG
+ and so on, because the constants we want here are determined by the
+ MIPS protocol and have nothing to do with what host we are running on. */
+ if ((rstatus & 0377) == 0)
+ {
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = (((rstatus) >> 8) & 0377);
+ }
+ else if ((rstatus & 0377) == 0177)
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0377);
+ }
+ else
+ {
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+ status->value.sig = mips_signal_from_protocol (rstatus & 0177);
+ }
return 0;
}
mips_fetch_registers (regno)
int regno;
{
- REGISTER_TYPE val;
+ unsigned LONGEST val;
int err;
if (regno == -1)
return;
}
- val = mips_request ('r', (unsigned int) mips_map_regno (regno),
- (unsigned int) 0, &err);
- if (err)
- 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];
- /* We got the number the register holds, but gdb expects to see a
- value in the target byte ordering. */
- SWAP_TARGET_AND_HOST (&val, sizeof (REGISTER_TYPE));
- supply_register (regno, (char *) &val);
+ /* We got the number the register holds, but gdb expects to see a
+ value in the target byte ordering. */
+ store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val);
+ supply_register (regno, buf);
+ }
}
/* Prepare to store registers. The MIPS protocol can store individual
mips_request ('R', (unsigned int) mips_map_regno (regno),
(unsigned int) read_register (regno),
- &err);
+ &err, mips_receive_wait);
if (err)
- error ("Can't write register %d: %s", regno, safe_strerror (errno));
+ mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
}
/* Fetch a word from the target board. */
int val;
int err;
- val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err);
+ val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err,
+ mips_receive_wait);
if (err)
{
/* Data space failed; try instruction space. */
- val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err);
+ val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err,
+ mips_receive_wait);
if (err)
- error ("Can't read address 0x%x: %s", addr, safe_strerror (errno));
+ mips_error ("Can't read address 0x%x: %s", addr, safe_strerror (errno));
}
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);
+ 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);
+ oldcontents = mips_request ('I', (unsigned int) addr,
+ (unsigned int) val, &err,
+ mips_receive_wait);
if (err)
- 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,
/* Round ending address up; get number of longwords that makes. */
register int count = (((memaddr + len) - addr) + 3) / 4;
/* Allocate buffer of that many longwords. */
- register unsigned int *buffer = (unsigned int *) alloca (count * 4);
+ register char *buffer = alloca (count * 4);
+
+ int status;
if (write)
{
if (addr != memaddr || len < 4)
{
/* Need part of initial word -- fetch it. */
- buffer[0] = mips_fetch_word (addr);
- SWAP_TARGET_AND_HOST (buffer, 4);
+ store_unsigned_integer (&buffer[0], 4, mips_fetch_word (addr));
}
- if (count > 1) /* FIXME, avoid if even boundary */
+ if (count > 1)
{
- buffer[count - 1] = mips_fetch_word (addr + (count - 1) * 4);
- SWAP_TARGET_AND_HOST (buffer + (count - 1) * 4, 4);
+ /* Need part of last word -- fetch it. FIXME: we do this even
+ if we don't need it. */
+ store_unsigned_integer (&buffer[(count - 1) * 4], 4,
+ mips_fetch_word (addr + (count - 1) * 4));
}
/* Copy data to be written over corresponding part of buffer */
for (i = 0; i < count; i++, addr += 4)
{
- SWAP_TARGET_AND_HOST (buffer + i, 4);
- mips_store_word (addr, buffer[i]);
+ 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
{
/* Read all the longwords */
for (i = 0; i < count; i++, addr += 4)
{
- buffer[i] = mips_fetch_word (addr);
- SWAP_TARGET_AND_HOST (buffer + i, 4);
+ store_unsigned_integer (&buffer[i*4], 4, mips_fetch_word (addr));
QUIT;
}
/* Copy appropriate bytes out of the buffer. */
- memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+ memcpy (myaddr, buffer + (memaddr & 3), len);
}
return len;
}
mips_files_info (ignore)
struct target_ops *ignore;
{
- printf ("Debugging a MIPS board over a serial line.\n");
+ printf_unfiltered ("Debugging a MIPS board over a serial line.\n");
}
/* Kill the process running on the board. This will actually only
CORE_ADDR entry_pt;
if (args && *args)
- 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)
- error ("No exec file specified");
+ error ("No executable file specified");
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
/* FIXME: Should we set inferior_pid here? */
- proceed (entry_pt, -1, 0);
+ proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
}
/* Clean up after a process. Actually nothing to do. */
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", /* to_shortname */
"Remote MIPS debugging over serial line", /* to_longname */
- "Debug a board using the MIPS remote debugging protocol over a serial line.\n\
-Specify the serial device it is connected to (e.g., /dev/ttya).", /* to_doc */
+ "\
+Debug a board using the MIPS remote debugging protocol over a serial line.\n\
+The argument is the device it is connected to or, if it contains a colon,\n\
+HOST:PORT to access a board over a network", /* to_doc */
mips_open, /* to_open */
mips_close, /* to_close */
NULL, /* to_attach */
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 */
add_target (&mips_ops);
add_show_from_set (
- add_set_cmd ("remotedebug", no_class, var_zinteger, (char *) &mips_debug,
- "Set debugging of remote MIPS serial I/O.\n\
-When non-zero, each packet sent or received with the remote target\n\
-is displayed. Higher numbers produce more debugging.", &setlist),
+ add_set_cmd ("timeout", no_class, var_zinteger,
+ (char *) &mips_receive_wait,
+ "Set timeout in seconds for remote MIPS serial I/O.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("retransmit-timeout", no_class, var_zinteger,
+ (char *) &mips_retransmit_wait,
+ "Set retransmit timeout in seconds for remote MIPS serial I/O.\n\
+This is the number of seconds to wait for an acknowledgement to a packet\n\
+before resending the packet.", &setlist),
&showlist);
}