/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GDB.
If AA..AA is omitted,
resume at same address.
- continue with Csig;AA Continue with signal sig (hex signal
- signal number).
+ continue with Csig;AA..AA Continue with signal sig (hex signal
+ signal number). If ;AA..AA is omitted, resume
+ at same address.
- step with Ssig;AA Like 'C' but step not continue.
+ step with Ssig;AA..AA Like 'C' but step not continue.
signal
last signal ? Reply the current reason for stopping.
for step or cont : SAA where AA is the
signal number.
+ detach D Reply OK.
+
There is no immediate reply to step or cont.
The reply comes when the machine stops.
It is SAA AA is the signal number.
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
-#include "thread.h"
+#include "gdbthread.h"
#include "dcache.h"
static void interrupt_query PARAMS ((void));
-extern struct target_ops remote_ops; /* Forward decl */
-extern struct target_ops extended_remote_ops; /* Forward decl */
+static void set_thread PARAMS ((int, int));
+
+static int remote_thread_alive PARAMS ((int));
+
+static void get_offsets PARAMS ((void));
+
+static int read_frame PARAMS ((char *));
+
+static int remote_insert_breakpoint PARAMS ((CORE_ADDR, char *));
+
+static int remote_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+
+static struct target_ops remote_ops; /* Forward decl */
+static struct target_ops extended_remote_ops; /* Forward decl */
/* This was 5 seconds, which is a long time to sit and wait.
Unless this is going though some terminal server or multiplexer or
other form of hairy serial connection, I would think 2 seconds would
be plenty. */
-static int remote_timeout = 2;
+/* Changed to allow option to set timeout value.
+ was static int remote_timeout = 2; */
+extern int remote_timeout;
+
+/* This variable chooses whether to send a ^C or a break when the user
+ requests program interruption. Although ^C is usually what remote
+ systems expect, and that is the default here, sometimes a break is
+ preferable instead. */
+
+static int remote_break;
/* Descriptor for I/O to remote machine. Initialize it to NULL so that
remote_open knows that we don't have a file open when the program
starts. */
-serial_t remote_desc = NULL;
+static serial_t remote_desc = NULL;
/* Having this larger than 400 causes us to be incompatible with m68k-stub.c
and i386-stub.c. Normally, no one would notice because it only matters
#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
#endif
+/* This variable sets the number of bytes to be written to the target
+ in a single packet. Normally PBUFSIZ is satisfactory, but some
+ targets need smaller values (perhaps because the receiving end
+ is slow). */
+
+static int remote_write_size = PBUFSIZ;
+
+/* This is the size (in chars) of the first response to the `g' command. This
+ is used to limit the size of the memory read and write commands to prevent
+ stub buffers from overflowing. */
+
+static int remote_register_buf_size = 0;
+
/* Should we try the 'P' request? If this is set to one when the stub
doesn't support 'P', the only consequence is some unnecessary traffic. */
static int stub_supports_P = 1;
+/* These are pointers to hook functions that may be set in order to
+ modify resume/wait behavior for a particular architecture. */
+
+void (*target_resume_hook) PARAMS ((void));
+void (*target_wait_loop_hook) PARAMS ((void));
+
\f
/* These are the threads which we last sent to the remote system. -1 for all
or -2 for not sent yet. */
pop_target();
}
-/* remote_detach()
- takes a program previously attached to and detaches it.
- We better not have left any breakpoints
- in the program or it'll die when it hits one.
- Close the open connection to the remote debugger.
- Use this when you want to detach and do something else
- with your gdb. */
+/* This takes a program previously attached to and detaches it. After
+ this is done, GDB can be used to debug some other program. We
+ better not have left any breakpoints in the target program or it'll
+ die when it hits one. */
static void
remote_detach (args, from_tty)
char *args;
int from_tty;
{
+ char buf[PBUFSIZ];
+
if (args)
error ("Argument given to \"detach\" when remotely debugging.");
-
+
+ /* Tell the remote target to detach. */
+ strcpy (buf, "D");
+ remote_send (buf);
+
pop_target ();
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
last_sent_signal = siggnal;
last_sent_step = step;
+ /* A hook for when we need to do something at the last moment before
+ resumption. */
+ if (target_resume_hook)
+ (*target_resume_hook) ();
+
if (siggnal != TARGET_SIGNAL_0)
{
buf[0] = step ? 'S' : 'C';
if (remote_debug)
printf_unfiltered ("remote_interrupt called\n");
- SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */
+ /* Send a break or a ^C, depending on user preference. */
+ if (remote_break)
+ SERIAL_SEND_BREAK (remote_desc);
+ else
+ SERIAL_WRITE (remote_desc, "\003", 1);
}
static void (*ofunc)();
getpkt ((char *) buf, 1);
signal (SIGINT, ofunc);
+ /* This is a hook for when we need to do something (perhaps the
+ collection of trace data) every time the target stops. */
+ if (target_wait_loop_hook)
+ (*target_wait_loop_hook) ();
+
switch (buf[0])
{
case 'E': /* Error of some sort */
sprintf (buf, "g");
remote_send (buf);
+ if (remote_register_buf_size == 0)
+ remote_register_buf_size = strlen (buf);
+
/* Unimplemented registers read as all bits zero. */
memset (regs, 0, REGISTER_BYTES);
#endif /* 0 (unused?) */
\f
+
+/* Return the number of hex digits in num. */
+
+static int
+hexnumlen (num)
+ ULONGEST num;
+{
+ int i;
+
+ for (i = 0; num != 0; i++)
+ num >>= 4;
+
+ return min (i, 1);
+}
+
/* Write memory data directly to the remote machine.
This does not inform the data cache; the data cache uses this.
MEMADDR is the address in the remote memory space.
char *myaddr;
int len;
{
- char buf[PBUFSIZ];
- int i;
- char *p;
- int done;
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
+
/* Chop the transfer down if necessary */
- done = 0;
- while (done < len)
+ max_buf_size = min (remote_write_size, PBUFSIZ);
+ max_buf_size = min (max_buf_size, remote_register_buf_size);
+
+#define PACKET_OVERHEAD (1 + 1 + 1 + 2) /* $x#xx - Overhead for all types of packets */
+
+ /* packet overhead + <memaddr>,<len>: */
+ max_buf_size -= PACKET_OVERHEAD + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 1;
+
+ origlen = len;
+ while (len > 0)
{
- int todo = len - done;
- int cando = PBUFSIZ /2 - 32; /* number of bytes that will fit. */
- if (todo > cando)
- todo = cando;
+ char buf[PBUFSIZ];
+ char *p;
+ int todo;
+ int i;
+
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
/* FIXME-32x64: Need a version of print_address_numeric which puts the
result in a buffer like sprintf. */
- sprintf (buf, "M%lx,%x:", (unsigned long) memaddr + done, todo);
+ sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo);
/* We send target system values byte by byte, in increasing byte addresses,
each byte encoded as two hex characters. */
p = buf + strlen (buf);
for (i = 0; i < todo; i++)
{
- *p++ = tohex ((myaddr[i + done] >> 4) & 0xf);
- *p++ = tohex (myaddr[i + done] & 0xf);
+ *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
}
*p = '\0';
errno = EIO;
return 0;
}
- done += todo;
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
}
- return len;
+ return origlen;
}
/* Read memory data directly from the remote machine.
char *myaddr;
int len;
{
- char buf[PBUFSIZ];
- int i;
- char *p;
- int done;
- /* Chop transfer down if neccessary */
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
-#if 0
- /* FIXME: This is wrong for larger packets */
- if (len > PBUFSIZ / 2 - 1)
- abort ();
-#endif
- done = 0;
- while (done < len)
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = min (remote_write_size, PBUFSIZ);
+ max_buf_size = min (max_buf_size, remote_register_buf_size);
+
+ /* packet overhead */
+ max_buf_size -= PACKET_OVERHEAD;
+
+ origlen = len;
+ while (len > 0)
{
- int todo = len - done;
- int cando = PBUFSIZ / 2 - 32; /* number of bytes that will fit. */
- if (todo > cando)
- todo = cando;
+ char buf[PBUFSIZ];
+ char *p;
+ int todo;
+ int i;
+
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
/* FIXME-32x64: Need a version of print_address_numeric which puts the
result in a buffer like sprintf. */
if (p[0] == 0 || p[1] == 0)
/* Reply is short. This means that we were able to read only part
of what we wanted to. */
- break;
- myaddr[i + done] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ return i + (origlen - len);
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
p += 2;
}
- done += todo;
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
}
- return len;
+ return origlen;
}
\f
/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
/* Copy the packet into buffer BUF2, encapsulating it
and giving it a checksum. */
- if (cnt > sizeof(buf2) - 5) /* Prosanity check */
+ if (cnt > (int) sizeof (buf2) - 5) /* Prosanity check */
abort();
p = buf2;
}
\f
-#ifdef REMOTE_BREAKPOINT
-
/* On some machines, e.g. 68k, we may use a different breakpoint instruction
- than other targets. */
-static unsigned char break_insn[] = REMOTE_BREAKPOINT;
+ than other targets; in those use REMOTE_BREAKPOINT instead of just
+ BREAKPOINT. Also, bi-endian targets may define LITTLE_REMOTE_BREAKPOINT
+ and BIG_REMOTE_BREAKPOINT. If none of these are defined, we just call
+ the standard routines that are in mem-break.c. */
+
+/* FIXME, these ought to be done in a more dynamic fashion. For instance,
+ the choice of breakpoint instruction affects target program design and
+ vice versa, and by making it user-tweakable, the special code here
+ goes away and we need fewer special GDB configurations. */
+
+#if defined (LITTLE_REMOTE_BREAKPOINT) && defined (BIG_REMOTE_BREAKPOINT) && !defined(REMOTE_BREAKPOINT)
+#define REMOTE_BREAKPOINT
+#endif
-#else /* No REMOTE_BREAKPOINT. */
+#ifdef REMOTE_BREAKPOINT
+
+/* If the target isn't bi-endian, just pretend it is. */
+#if !defined (LITTLE_REMOTE_BREAKPOINT) && !defined (BIG_REMOTE_BREAKPOINT)
+#define LITTLE_REMOTE_BREAKPOINT REMOTE_BREAKPOINT
+#define BIG_REMOTE_BREAKPOINT REMOTE_BREAKPOINT
+#endif
-/* Same old breakpoint instruction. This code does nothing different
- than mem-break.c. */
-static unsigned char break_insn[] = BREAKPOINT;
+static unsigned char big_break_insn[] = BIG_REMOTE_BREAKPOINT;
+static unsigned char little_break_insn[] = LITTLE_REMOTE_BREAKPOINT;
-#endif /* No REMOTE_BREAKPOINT. */
+#endif /* REMOTE_BREAKPOINT */
/* Insert a breakpoint on targets that don't have any better breakpoint
support. We read the contents of the target location and stash it,
CORE_ADDR addr;
char *contents_cache;
{
+#ifdef REMOTE_BREAKPOINT
int val;
- val = target_read_memory (addr, contents_cache, sizeof break_insn);
+ val = target_read_memory (addr, contents_cache, sizeof big_break_insn);
if (val == 0)
- val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ val = target_write_memory (addr, (char *) big_break_insn,
+ sizeof big_break_insn);
+ else
+ val = target_write_memory (addr, (char *) little_break_insn,
+ sizeof little_break_insn);
+ }
return val;
+#else
+ return memory_insert_breakpoint (addr, contents_cache);
+#endif /* REMOTE_BREAKPOINT */
}
static int
CORE_ADDR addr;
char *contents_cache;
{
- return target_write_memory (addr, contents_cache, sizeof break_insn);
+#ifdef REMOTE_BREAKPOINT
+ return target_write_memory (addr, contents_cache, sizeof big_break_insn);
+#else
+ return memory_remove_breakpoint (addr, contents_cache);
+#endif /* REMOTE_BREAKPOINT */
}
\f
/* Define the target subroutine names */
-struct target_ops remote_ops = {
+static struct target_ops remote_ops =
+{
"remote", /* to_shortname */
"Remote serial target in gdb-specific protocol", /* to_longname */
"Use a remote computer via a serial line, using a gdb-specific protocol.\n\
remote_prepare_to_store, /* to_prepare_to_store */
remote_xfer_memory, /* to_xfer_memory */
remote_files_info, /* to_files_info */
-
remote_insert_breakpoint, /* to_insert_breakpoint */
remote_remove_breakpoint, /* to_remove_breakpoint */
-
NULL, /* to_terminal_init */
NULL, /* to_terminal_inferior */
NULL, /* to_terminal_ours_for_output */
OPS_MAGIC /* to_magic */
};
-struct target_ops extended_remote_ops = {
+static struct target_ops extended_remote_ops =
+{
"extended-remote", /* to_shortname */
"Extended remote serial target in gdb-specific protocol",/* to_longname */
"Use a remote computer via a serial line, using a gdb-specific protocol.\n\
OPS_MAGIC /* to_magic */
};
+/* Some targets are only capable of doing downloads, and afterwards they switch
+ to the remote serial protocol. This function provides a clean way to get
+ from the download target to the remote target. It's basically just a
+ wrapper so that we don't have to expose any of the internal workings of
+ remote.c.
+
+ Prior to calling this routine, you should shutdown the current target code,
+ else you will get the "A program is being debugged already..." message.
+ Usually a call to pop_target() suffices.
+*/
+
+void
+push_remote_target (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ printf_filtered ("Switching to remote protocol\n");
+ remote_open (name, from_tty);
+}
+
void
_initialize_remote ()
{
var_integer, (char *)&remote_timeout,
"Set timeout value for remote read.\n", &setlist),
&showlist);
+
+ add_show_from_set (add_set_cmd ("remotebreak", no_class,
+ var_integer, (char *)&remote_break,
+ "Set whether to send break if interrupted.\n", &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("remotewritesize", no_class,
+ var_integer, (char *)&remote_write_size,
+ "Set the maximum number of bytes in each memory write packet.\n", &setlist),
+ &showlist);
}