#include "defs.h"
#include "inferior.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>
\f
int len));
static void
-mips_send_packet PARAMS ((const char *s));
+mips_send_packet PARAMS ((const char *s, int get_ack));
static int
mips_receive_packet PARAMS ((char *buff));
mips_request PARAMS ((char cmd, unsigned int addr, unsigned int data,
int *perr));
+static void
+mips_initialize PARAMS ((void));
+
static void
mips_open PARAMS ((char *name, int from_tty));
mips_detach PARAMS ((char *args, int from_tty));
static void
-mips_resume PARAMS ((int step, int siggnal));
+mips_resume PARAMS ((int pid, int step, int siggnal));
static int
mips_wait PARAMS ((WAITTYPE *status));
/* Set to 1 if the target is open. */
static int mips_is_open;
+/* Set to 1 while the connection is being initialized. */
+static int mips_initializing;
+
/* The next sequence number to send. */
static int mips_send_seq;
static int mips_syn_garbage = 1050;
/* The time to wait for a packet, in seconds. */
-static int mips_receive_wait = 30;
+static int mips_receive_wait = 5;
/* Set if we have sent a packet to the board but have not yet received
a reply. */
static int mips_need_reply = 0;
-/* This can be set to get debugging with ``set remotedebug''. */
-static int mips_debug = 0;
-
-/* Read a character from the remote, aborting on error. Returns -2 on
- timeout (since that's what serial_readchar returns). */
+/* Handle used to access serial I/O stream. */
+static serial_t mips_desc;
+
+/* 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
+ we are debugging on the main console port, and we have somehow
+ dropped out of remote debugging mode. In this case, we
+ automatically go back in to remote debugging mode. This is a hack,
+ put in because I can't find any way for a program running on the
+ remote board to terminate without also ending remote debugging
+ mode. I assume users won't have any trouble with this; for one
+ thing, the IDT documentation generally assumes that the remote
+ debugging port is not the console port. This is, however, very
+ convenient for DejaGnu when you only have one connected serial
+ port. */
static int
mips_readchar (timeout)
int timeout;
{
int ch;
+ static int state = 0;
+ static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
- ch = serial_readchar (timeout);
- if (ch == EOF)
+ ch = SERIAL_READCHAR (mips_desc, timeout);
+ if (ch == SERIAL_EOF)
error ("End of file from remote");
- if (ch == -3)
+ if (ch == SERIAL_ERROR)
error ("Error reading from remote: %s", safe_strerror (errno));
- if (mips_debug > 1)
+ if (sr_get_debug () > 1)
{
- if (ch != -2)
+ if (ch != SERIAL_TIMEOUT)
printf_filtered ("Read '%c' %d 0x%x\n", ch, ch, ch);
else
printf_filtered ("Timed out in read\n");
}
+
+ /* If we have seen <IDT> and we either time out, or we see a @
+ (which was echoed from a packet we sent), reset the board as
+ described above. The first character in a packet after the SYN
+ (which is not echoed) is always an @ unless the packet is more
+ than 64 characters long, which ours never are. */
+ if ((ch == SERIAL_TIMEOUT || ch == '@')
+ && state == 5
+ && ! 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);
+ sleep (1);
+
+ mips_need_reply = 0;
+ mips_initialize ();
+
+ state = 0;
+
+ error ("Remote board reset");
+ }
+
+ if (ch == nextstate[state])
+ ++state;
+ else
+ state = 0;
+
return ch;
}
while (ch != SYN)
{
ch = mips_readchar (timeout);
- if (ch == -2)
+ if (ch == SERIAL_TIMEOUT)
return -1;
if (ch != SYN)
{
what the program is outputting, if the debugging is
being done on the console port. FIXME: Perhaps this
should be filtered? */
- putchar (ch);
+ if (! mips_initializing || sr_get_debug () > 0)
+ {
+ putchar (ch);
+ fflush (stdout);
+ }
++*pgarbage;
if (*pgarbage > mips_syn_garbage)
for (i = 1; i < HDR_LENGTH; i++)
{
ch = mips_readchar (timeout);
- if (ch == -2)
+ if (ch == SERIAL_TIMEOUT)
return -1;
/* Make sure this is a header byte. */
{
ch = mips_readchar (timeout);
*pch = ch;
- if (ch == -2)
+ if (ch == SERIAL_TIMEOUT)
return -1;
if (! TRLR_CHECK (ch))
return -2;
/* Send a packet containing the given ASCII string. */
static void
-mips_send_packet (s)
+mips_send_packet (s, get_ack)
const char *s;
+ int get_ack;
{
unsigned int len;
unsigned char *packet;
the sequence number we expect in the acknowledgement. */
mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS;
+ if (! get_ack)
+ return;
+
/* We can only have one outstanding data packet, so we just wait for
the acknowledgement here. Keep retransmitting the packet until
we get one, or until we've tried too many times. */
int garbage;
int ch;
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
{
packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0';
printf_filtered ("Writing \"%s\"\n", packet + 1);
}
- if (serial_write (packet, HDR_LENGTH + len + TRLR_LENGTH) == 0)
+ if (SERIAL_WRITE (mips_desc, packet,
+ HDR_LENGTH + len + TRLR_LENGTH) != 0)
error ("write to target failed: %s", safe_strerror (errno));
garbage = 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",
- HDR_GET_SEQ (hdr), hdr, trlr);
+ HDR_GET_SEQ (hdr), hdr + 1, trlr);
}
/* If this ack is for the current packet, we're done. */
/* An acknowledgement is probably a duplicate; ignore it. */
if (! HDR_IS_DATA (hdr))
{
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
printf_filtered ("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)
+ if (sr_get_debug () > 0)
printf_filtered ("Ignoring sequence number %d (want %d)\n",
HDR_GET_SEQ (hdr), mips_receive_seq);
continue;
ch = SYN;
break;
}
- if (rch == -2)
+ if (rch == SERIAL_TIMEOUT)
error ("Timed out waiting for remote packet");
buff[i] = rch;
}
if (i < len)
{
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
printf_filtered ("Got new SYN after %d chars (wanted %d)\n",
i, len);
continue;
error ("Timed out waiting for packet");
if (err == -2)
{
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
printf_filtered ("Got SYN when wanted trailer\n");
continue;
}
if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr))
break;
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
printf_filtered ("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,
ack + 1);
}
- if (serial_write (ack, HDR_LENGTH + TRLR_LENGTH) == 0)
+ if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
error ("write to target failed: %s", safe_strerror (errno));
}
- if (mips_debug > 0)
+ if (sr_get_debug () > 0)
{
buff[len] = '\0';
printf_filtered ("Got packet \"%s\"\n", buff);
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,
ack + 1);
}
- if (serial_write (ack, HDR_LENGTH + TRLR_LENGTH) == 0)
+ if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
error ("write to target failed: %s", safe_strerror (errno));
return len;
if (mips_need_reply)
fatal ("mips_request: Trying to send command before reply");
sprintf (buff, "0x0 %c 0x%x 0x%x", cmd, addr, data);
- mips_send_packet (buff);
+ mips_send_packet (buff, 1);
mips_need_reply = 1;
}
if (sscanf (buff, "0x%x %c 0x%x 0x%x",
&rpid, &rcmd, &rerrflg, &rresponse) != 4
- || rpid != 0
|| (cmd != '\0' && rcmd != cmd))
error ("Bad response from remote board");
return rresponse;
}
+/* Initialize a new connection to the MIPS board, and make sure we are
+ really connected. */
+
+static void
+mips_initialize ()
+{
+ char cr;
+ int hold_wait;
+ int tries;
+ char buff[DATA_MAXLEN + 1];
+ int err;
+
+ if (mips_initializing)
+ return;
+
+ mips_initializing = 1;
+
+ mips_send_seq = 0;
+ mips_receive_seq = 0;
+
+ /* 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';
+ 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)
+ {
+ 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);
+ sleep (1);
+ cr = '\r';
+ SERIAL_WRITE (mips_desc, &cr, 1);
+ }
+
+ mips_receive_wait = hold_wait;
+ mips_initializing = 0;
+
+ /* 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);
+}
+
/* Open a connection to the remote board. */
static void
char *name;
int from_tty;
{
- int err;
- char cr;
- char buff[DATA_MAXLEN + 1];
-
if (name == 0)
error (
"To open a MIPS remote debugging connection, you need to specify what serial\n\
target_preopen (from_tty);
if (mips_is_open)
- mips_close (0);
+ unpush_target (&mips_ops);
- if (serial_open (name) == 0)
+ mips_desc = SERIAL_OPEN (name);
+ if (mips_desc == (serial_t) NULL)
perror_with_name (name);
- mips_is_open = 1;
+ SERIAL_RAW (mips_desc);
- /* The board seems to want to send us a packet. I don't know what
- it means. */
- cr = '\r';
- serial_write (&cr, 1);
- mips_receive_packet (buff);
+ mips_is_open = 1;
- /* 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_initialize ();
if (from_tty)
printf ("Remote MIPS debugging using %s\n", name);
push_target (&mips_ops); /* Switch to using remote target now */
- start_remote (); /* Initialize gdb process mechanisms */
+ /* FIXME: Should we call start_remote here? */
}
/* Close a connection to the remote board. */
{
if (mips_is_open)
{
- /* Get the board out of remote debugging mode. */
- mips_request ('x', (unsigned int) 0, (unsigned int) 0,
- (int *) NULL);
- serial_close ();
+ int err;
+
mips_is_open = 0;
+
+ /* Get the board out of remote debugging mode. */
+ mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err);
+
+ SERIAL_CLOSE (mips_desc);
}
}
from the board. */
static void
-mips_resume (step, siggnal)
- int step, siggnal;
+mips_resume (pid, step, siggnal)
+ int pid, step, siggnal;
{
if (siggnal)
error ("Can't send signals to a remote system. Try `handle %d ignore'.",
siggnal);
mips_request (step ? 's' : 'c',
- (unsigned int) read_register (PC_REGNUM),
+ (unsigned int) 1,
(unsigned int) 0,
(int *) NULL);
}
if (err)
error ("Can't read register %d: %s", regno, safe_strerror (errno));
- /* 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);
+ {
+ 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. */
+ store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val);
+ supply_register (regno, buf);
+ }
}
/* Prepare to store registers. The MIPS protocol can store individual
/* 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);
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]);
+ mips_store_word (addr, extract_unsigned_integer (&buffer[i*4], 4));
+ /* FIXME: Do we want a QUIT here? */
}
}
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;
}
printf ("Debugging a MIPS board over a serial line.\n");
}
-/* Load an executable onto the board. */
+/* Kill the process running on the board. This will actually only
+ work if we are doing remote debugging over the console input. I
+ think that if IDT/sim had the remote debug interrupt enabled on the
+ right port, we could interrupt the process with a break signal. */
static void
-mips_load (args, from_tty)
- char *args;
- int from_tty;
+mips_kill ()
{
- bfd *abfd;
- asection *s;
- int err;
-
- abfd = bfd_openr (args, 0);
- if (abfd == (bfd *) NULL)
- error ("Unable to open file %s", args);
-
- if (bfd_check_format (abfd, bfd_object) == 0)
- error ("%s: Not an object file", args);
-
- for (s = abfd->sections; s != (asection *) NULL; s = s->next)
+#if 0
+ if (mips_is_open)
{
- if ((s->flags & SEC_LOAD) != 0)
- {
- bfd_size_type size;
-
- size = bfd_get_section_size_before_reloc (s);
- if (size > 0)
- {
- char *buffer;
- struct cleanup *old_chain;
- bfd_vma vma;
-
- buffer = xmalloc (size);
- old_chain = make_cleanup (free, buffer);
-
- vma = bfd_get_section_vma (abfd, s);
- printf_filtered ("Loading section %s, size 0x%x vma 0x%x\n",
- bfd_get_section_name (abfd, s), size, vma);
- bfd_get_section_contents (abfd, s, buffer, 0, size);
- mips_xfer_memory (vma, buffer, size, 1, &mips_ops);
+ char cc;
- do_cleanups (old_chain);
- }
- }
+ /* Send a ^C. */
+ cc = '\003';
+ SERIAL_WRITE (mips_desc, &cc, 1);
+ sleep (1);
+ target_mourn_inferior ();
}
-
- mips_request ('R', (unsigned int) mips_map_regno (PC_REGNUM),
- (unsigned int) abfd->start_address,
- &err);
- if (err)
- error ("Can't write PC register: %s", safe_strerror (errno));
-
- bfd_close (abfd);
-
- /* FIXME: Should we call symbol_file_add here? */
+#endif
}
/* Start running on the target board. */
{
CORE_ADDR entry_pt;
- /* FIXME: Actually, we probably could pass arguments. */
if (args && *args)
error ("Can't pass arguments to remote MIPS board.");
init_wait_for_inferior ();
+ /* FIXME: Should we set inferior_pid here? */
+
proceed (entry_pt, -1, 0);
}
static void
mips_mourn_inferior ()
{
+ unpush_target (&mips_ops);
generic_mourn_inferior ();
}
\f
NULL, /* to_terminal_ours_for_output */
NULL, /* to_terminal_ours */
NULL, /* to_terminal_info */
- NULL, /* to_kill */
- mips_load, /* to_load */
+ mips_kill, /* to_kill */
+ generic_load, /* to_load */
NULL, /* to_lookup_symbol */
mips_create_inferior, /* to_create_inferior */
mips_mourn_inferior, /* to_mourn_inferior */
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);
}