/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Remote communication protocol.
- - if CSUM is incorrect
<data> is as follows:
- All values are encoded in ascii hex digits.
+ Most values are encoded in ascii hex digits. Signal numbers are according
+ to the numbering in target.h.
Request Packet
+ set thread Hct... Set thread for subsequent operations.
+ c = 'c' for thread used in step and
+ continue; t... can be -1 for all
+ threads.
+ c = 'g' for thread used in other
+ operations. If zero, pick a thread,
+ any thread.
+ reply OK for success
+ ENN for an error.
+
read registers g
reply XX....X Each byte of register data
is described by two hex digits.
where only part of the data was
written).
- cont cAA..AA AA..AA is address to resume
+ continue cAA..AA AA..AA is address to resume
If AA..AA is omitted,
resume at same address.
If AA..AA is omitted,
resume at same address.
+ 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..AA Like 'C' but step not continue.
+ signal
+
last signal ? Reply the current reason for stopping.
This is the same reply as is generated
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"
+ It is SAA AA is the signal number.
- or... TAAn...:r...;n:r...;n...:r...;
+ or... TAAn...:r...;n...:r...;n...:r...;
AA = signal number
- n... = register number
- r... = register contents
+ n... = register number (hex)
+ r... = register contents
+ n... = `thread'
+ r... = thread process ID. This is
+ a hex integer.
+ n... = other string not starting
+ with valid hex digit.
+ gdb should ignore this n,r pair
+ and go on to the next. This way
+ we can extend the protocol.
or... WAA The process exited, and AA is
the exit status. This is only
applicable for certains sorts of
targets.
+ or... XAA The process terminated with signal
+ AA.
+ or... OXX..XX XX..XX is hex encoding of ASCII data. This
+ can happen at any time while the program is
+ running and the debugger should
+ continue to wait for 'W', 'T', etc.
+
+ thread alive TXX Find out if the thread XX is alive.
+ reply OK thread is still alive
+ ENN thread is dead
+
+ remote restart RXX Restart the remote server
+
+ extended ops ! Use the extended remote protocol.
+ Sticky -- only needs to be set once.
+
kill request k
toggle debug d toggle debug flag (see 386 & 68k stubs)
general set QXXXX=yyyy Set value of XXXX to yyyy.
query sect offs qOffsets Get section offsets. Reply is
Text=xxx;Data=yyy;Bss=zzz
- console output Otext Send text to stdout. Only comes from
- remote target.
Responses can be run-length encoded to save space. A '*' means that
- the next two characters are hex digits giving a repeat count which
+ the next character is an ASCII encoding giving a repeat count which
stands for that many repititions of the character preceding the '*'.
- Note that this means that responses cannot contain '*'. Example:
- "0*03" means the same as "0000". */
+ The encoding is n+29, yielding a printable character where n >=3
+ (which is where rle starts to win). Don't use an n > 126.
+
+ So
+ "0* " means the same as "0000". */
#include "defs.h"
-#include <string.h>
+#include "gdb_string.h"
#include <fcntl.h>
#include "frame.h"
#include "inferior.h"
#include "symfile.h"
#include "target.h"
#include "wait.h"
-#include "terminal.h"
+/*#include "terminal.h"*/
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
+#include "gdbthread.h"
#include "dcache.h"
/* Prototypes for local functions */
-static int
-remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_write_bytes PARAMS ((CORE_ADDR memaddr,
+ char *myaddr, int len));
-static int
-remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_read_bytes PARAMS ((CORE_ADDR memaddr,
+ char *myaddr, int len));
-static void
-remote_files_info PARAMS ((struct target_ops *ignore));
+static void remote_files_info PARAMS ((struct target_ops *ignore));
-static int
-remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
- int should_write, struct target_ops *target));
+static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct target_ops *target));
-static void
-remote_prepare_to_store PARAMS ((void));
+static void remote_prepare_to_store PARAMS ((void));
-static void
-remote_fetch_registers PARAMS ((int regno));
+static void remote_fetch_registers PARAMS ((int regno));
-static void
-remote_resume PARAMS ((int pid, int step, enum target_signal siggnal));
+static void remote_resume PARAMS ((int pid, int step,
+ enum target_signal siggnal));
-static int
-remote_start_remote PARAMS ((char *dummy));
+static int remote_start_remote PARAMS ((char *dummy));
-static void
-remote_open PARAMS ((char *name, int from_tty));
+static void remote_open PARAMS ((char *name, int from_tty));
-static void
-remote_close PARAMS ((int quitting));
+static void extended_remote_open PARAMS ((char *name, int from_tty));
-static void
-remote_store_registers PARAMS ((int regno));
+static void remote_open_1 PARAMS ((char *, int, struct target_ops *, int extended_p));
-static void
-getpkt PARAMS ((char *buf, int forever));
+static void remote_close PARAMS ((int quitting));
-static void
-putpkt PARAMS ((char *buf));
+static void remote_store_registers PARAMS ((int regno));
-static void
-remote_send PARAMS ((char *buf));
+static void remote_mourn PARAMS ((void));
-static int
-readchar PARAMS ((int timeout));
+static void extended_remote_restart PARAMS ((void));
+
+static void extended_remote_mourn PARAMS ((void));
+
+static void extended_remote_create_inferior PARAMS ((char *, char *, char **));
+
+static void remote_mourn_1 PARAMS ((struct target_ops *));
+
+static void remote_send PARAMS ((char *buf));
+
+static int readchar PARAMS ((int timeout));
static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
-static int
-tohex PARAMS ((int nib));
+static void remote_kill PARAMS ((void));
-static int
-fromhex PARAMS ((int a));
+static int tohex PARAMS ((int nib));
-static void
-remote_detach PARAMS ((char *args, int from_tty));
+static void remote_detach PARAMS ((char *args, int from_tty));
-static void
-remote_interrupt PARAMS ((int signo));
+static void remote_interrupt PARAMS ((int signo));
-static void
-remote_interrupt_twice PARAMS ((int signo));
+static void remote_interrupt_twice PARAMS ((int signo));
-static void
-interrupt_query PARAMS ((void));
+static void interrupt_query PARAMS ((void));
+
+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 int hexnumlen PARAMS ((ULONGEST num));
+
+/* exported functions */
+
+extern int fromhex PARAMS ((int a));
+extern void getpkt PARAMS ((char *buf, int forever));
+extern int putpkt PARAMS ((char *buf));
+
+/* Define the target subroutine names */
+
+static struct target_ops remote_ops ;
+
+static void init_remote_ops(void)
+{
+ remote_ops.to_shortname = "remote";
+ remote_ops.to_longname = "Remote serial target in gdb-specific protocol";
+ remote_ops.to_doc = "Use a remote computer via a serial line; using a gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya)." ;
+ remote_ops.to_open = remote_open;
+ remote_ops.to_close = remote_close;
+ remote_ops.to_attach = NULL;
+ remote_ops.to_detach = remote_detach;
+ remote_ops.to_resume = remote_resume;
+ remote_ops.to_wait = remote_wait;
+ remote_ops.to_fetch_registers = remote_fetch_registers;
+ remote_ops.to_store_registers = remote_store_registers;
+ remote_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_ops.to_xfer_memory = remote_xfer_memory;
+ remote_ops.to_files_info = remote_files_info;
+ remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_ops.to_terminal_init = NULL;
+ remote_ops.to_terminal_inferior = NULL;
+ remote_ops.to_terminal_ours_for_output = NULL;
+ remote_ops.to_terminal_ours = NULL;
+ remote_ops.to_terminal_info = NULL;
+ remote_ops.to_kill = remote_kill;
+ remote_ops.to_load = generic_load;
+ remote_ops.to_lookup_symbol = NULL;
+ remote_ops.to_create_inferior = NULL;
+ remote_ops.to_mourn_inferior = remote_mourn;
+ remote_ops.to_can_run = 0;
+ remote_ops.to_notice_signals = 0;
+ remote_ops.to_thread_alive = remote_thread_alive;
+ remote_ops.to_stop = 0;
+ remote_ops.to_stratum = process_stratum;
+ remote_ops.DONT_USE = NULL;
+ remote_ops.to_has_all_memory = 1;
+ remote_ops.to_has_memory = 1;
+ remote_ops.to_has_stack = 1;
+ remote_ops.to_has_registers = 1;
+ remote_ops.to_has_execution = 1;
+ remote_ops.to_sections = NULL;
+ remote_ops.to_sections_end = NULL;
+ remote_ops.to_magic = OPS_MAGIC ;
+} /* init_remote_ops */
+
+static struct target_ops extended_remote_ops ;
+
+static void init_extended_remote_ops(void)
+{
+ extended_remote_ops.to_shortname = "extended-remote";
+ extended_remote_ops.to_longname = "Extended remote serial target in gdb-specific protocol";
+ extended_remote_ops.to_doc = "Use a remote computer via a serial line; using a gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).",
+ extended_remote_ops.to_open = extended_remote_open;
+ extended_remote_ops.to_close = remote_close;
+ extended_remote_ops.to_attach = NULL;
+ extended_remote_ops.to_detach = remote_detach;
+ extended_remote_ops.to_resume = remote_resume;
+ extended_remote_ops.to_wait = remote_wait;
+ extended_remote_ops.to_fetch_registers = remote_fetch_registers;
+ extended_remote_ops.to_store_registers = remote_store_registers;
+ extended_remote_ops.to_prepare_to_store = remote_prepare_to_store;
+ extended_remote_ops.to_xfer_memory = remote_xfer_memory;
+ extended_remote_ops.to_files_info = remote_files_info;
+ extended_remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ extended_remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ extended_remote_ops.to_terminal_init = NULL;
+ extended_remote_ops.to_terminal_inferior = NULL;
+ extended_remote_ops.to_terminal_ours_for_output = NULL;
+ extended_remote_ops.to_terminal_ours = NULL;
+ extended_remote_ops.to_terminal_info = NULL;
+ extended_remote_ops.to_kill = remote_kill;
+ extended_remote_ops.to_load = generic_load;
+ extended_remote_ops.to_lookup_symbol = NULL;
+ extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
+ extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
+ extended_remote_ops.to_can_run = 0;
+ extended_remote_ops.to_notice_signals = 0;
+ extended_remote_ops.to_thread_alive = remote_thread_alive;
+ extended_remote_ops.to_stop = 0;
+ extended_remote_ops.to_stratum = process_stratum;
+ extended_remote_ops.DONT_USE = NULL;
+ extended_remote_ops.to_has_all_memory = 1;
+ extended_remote_ops.to_has_memory = 1;
+ extended_remote_ops.to_has_stack = 1;
+ extended_remote_ops.to_has_registers = 1;
+ extended_remote_ops.to_has_execution = 1;
+ extended_remote_ops.to_sections = NULL;
+ extended_remote_ops.to_sections_end = NULL;
+ extended_remote_ops.to_magic = OPS_MAGIC ;
+}
-extern struct target_ops 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;
-#if 0
-int icache;
-#endif
+/* 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. The size does not include headers and
+ trailers, it is only the payload size. */
+
+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. */
+int general_thread;
+int cont_thread;
+
+static void
+set_thread (th, gen)
+ int th;
+ int gen;
+{
+ char buf[PBUFSIZ];
+ int state = gen ? general_thread : cont_thread;
+ if (state == th)
+ return;
+ buf[0] = 'H';
+ buf[1] = gen ? 'g' : 'c';
+ if (th == 42000)
+ {
+ buf[2] = '0';
+ buf[3] = '\0';
+ }
+ else if (th < 0)
+ sprintf (&buf[2], "-%x", -th);
+ else
+ sprintf (&buf[2], "%x", th);
+ putpkt (buf);
+ getpkt (buf, 0);
+ if (gen)
+ general_thread = th;
+ else
+ cont_thread = th;
+}
+\f
+/* Return nonzero if the thread TH is still alive on the remote system. */
+
+static int
+remote_thread_alive (th)
+ int th;
+{
+ char buf[PBUFSIZ];
+
+ buf[0] = 'T';
+ if (th < 0)
+ sprintf (&buf[1], "-%x", -th);
+ else
+ sprintf (&buf[1], "%x", th);
+ putpkt (buf);
+ getpkt (buf, 0);
+ return (buf[0] == 'O' && buf[1] == 'K');
+}
+
+/* Restart the remote side; this is an extended protocol operation. */
+
+static void
+extended_remote_restart ()
+{
+ char buf[PBUFSIZ];
+
+ /* Send the restart command; for reasons I don't understand the
+ remote side really expects a number after the "R". */
+ buf[0] = 'R';
+ sprintf (&buf[1], "%x", 0);
+ putpkt (buf);
+
+ /* Now query for status so this looks just like we restarted
+ gdbserver from scratch. */
+ putpkt ("?");
+ getpkt (buf, 0);
+}
\f
/* Clean up connection to a remote debugger. */
static void
get_offsets ()
{
- unsigned char buf[PBUFSIZ];
- int nvals;
+ char buf[PBUFSIZ], *ptr;
+ int lose;
CORE_ADDR text_addr, data_addr, bss_addr;
struct section_offsets *offs;
return;
}
- nvals = sscanf (buf, "Text=%lx;Data=%lx;Bss=%lx", &text_addr, &data_addr,
- &bss_addr);
- if (nvals != 3)
+ /* Pick up each field in turn. This used to be done with scanf, but
+ scanf will make trouble if CORE_ADDR size doesn't match
+ conversion directives correctly. The following code will work
+ with any size of CORE_ADDR. */
+ text_addr = data_addr = bss_addr = 0;
+ ptr = buf;
+ lose = 0;
+
+ if (strncmp (ptr, "Text=", 5) == 0)
+ {
+ ptr += 5;
+ /* Don't use strtol, could lose on big values. */
+ while (*ptr && *ptr != ';')
+ text_addr = (text_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (!lose && strncmp (ptr, ";Data=", 6) == 0)
+ {
+ ptr += 6;
+ while (*ptr && *ptr != ';')
+ data_addr = (data_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+ {
+ ptr += 5;
+ while (*ptr && *ptr != ';')
+ bss_addr = (bss_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (lose)
error ("Malformed response to offset query, %s", buf);
if (symfile_objfile == NULL)
+ symfile_objfile->num_sections
* sizeof (offs->offsets));
- /* FIXME: This code assumes gdb-stabs.h is being used; it's broken
- for xcoff, dwarf, sdb-coff, etc. But there is no simple
- canonical representation for this stuff. (Just what does "text"
- as seen by the stub mean, anyway? I think it means all sections
- with SEC_CODE set, but we currently have no way to deal with that). */
-
ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
/* This is a temporary kludge to force data and bss to use the same offsets
immediate_quit = 1; /* Allow user to interrupt it */
/* Ack any packet which the remote side has already sent. */
-
SERIAL_WRITE (remote_desc, "+", 1);
+ /* Let the stub know that we want it to return the thread. */
+ set_thread (-1, 0);
+
get_offsets (); /* Get text, data & bss offsets */
putpkt ("?"); /* initiate a query from remote machine */
immediate_quit = 0;
start_remote (); /* Initialize gdb process mechanisms */
-
return 1;
}
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
+static void
+remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ remote_open_1 (name, from_tty, &remote_ops, 0);
+}
+
+/* Open a connection to a remote debugger using the extended
+ remote gdb protocol. NAME is the filename used for communication. */
+
+static void
+extended_remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ remote_open_1 (name, from_tty, &extended_remote_ops, 1/*extended_p*/);
+}
+
+/* Generic code for opening a connection to a remote target. */
static DCACHE *remote_dcache;
static void
-remote_open (name, from_tty)
+remote_open_1 (name, from_tty, target, extended_p)
char *name;
int from_tty;
+ struct target_ops *target;
+ int extended_p;
{
if (name == 0)
- error (
-"To open a remote debug connection, you need to specify what serial\n\
+ error ("To open a remote debug connection, you need to specify what serial\n\
device is attached to the remote system (e.g. /dev/ttya).");
target_preopen (from_tty);
- unpush_target (&remote_ops);
+ unpush_target (target);
remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
}
}
+
SERIAL_RAW (remote_desc);
/* If there is something sitting in the buffer we might take it as a
puts_filtered (name);
puts_filtered ("\n");
}
- push_target (&remote_ops); /* Switch to using remote target now */
+ push_target (target); /* Switch to using remote target now */
/* Start out by trying the 'P' request to set registers. We set this each
time that we open a new target so that if the user switches from one
stub to another, we can (if the target is closed and reopened) cope. */
stub_supports_P = 1;
+ general_thread = -2;
+ cont_thread = -2;
+
+ /* Without this, some commands which require an active target (such as kill)
+ won't work. This variable serves (at least) double duty as both the pid
+ of the target process (if it has such), and as a flag indicating that a
+ target is active. These functions should be split out into seperate
+ variables, especially since GDB will someday have a notion of debugging
+ several processes. */
+
+ inferior_pid = 42000;
/* Start the remote connection; if error (0), discard this target.
In particular, if the user quits, be sure to discard it
(we'd be in an inconsistent state otherwise). */
if (!catch_errors (remote_start_remote, (char *)0,
- "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
pop_target();
+
+
+ if (extended_p)
+ {
+ /* tell the remote that we're using the extended protocol. */
+ char buf[PBUFSIZ];
+ putpkt ("!");
+ getpkt (buf, 0);
+ }
}
-/* 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");
/* Convert hex digit A to a number. */
-static int
+int
fromhex (a)
int a;
{
return a - '0';
else if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
- else
- error ("Reply contains invalid hex digit");
+ else if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else
+ error ("Reply contains invalid hex digit %d", a);
}
/* Convert number NIB to a hex digit. */
\f
/* Tell the remote machine to resume. */
+static enum target_signal last_sent_signal = TARGET_SIGNAL_0;
+int last_sent_step;
+
static void
remote_resume (pid, step, siggnal)
int pid, step;
{
char buf[PBUFSIZ];
- if (siggnal)
- {
- target_terminal_ours_for_output ();
- printf_filtered
- ("Can't send signals to a remote system. %s not sent.\n",
- target_signal_to_name (siggnal));
- target_terminal_inferior ();
- }
+ if (pid == -1)
+ set_thread (inferior_pid, 0);
+ else
+ set_thread (pid, 0);
dcache_flush (remote_dcache);
- strcpy (buf, step ? "s": "c");
+ 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';
+ buf[1] = tohex (((int)siggnal >> 4) & 0xf);
+ buf[2] = tohex ((int)siggnal & 0xf);
+ buf[3] = '\0';
+ }
+ else
+ strcpy (buf, step ? "s": "c");
putpkt (buf);
}
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)();
target_terminal_inferior ();
}
+/* If nonzero, ignore the next kill. */
+int kill_kludge;
+
+void
+remote_console_output (msg)
+ char *msg;
+{
+ char *p;
+
+ for (p = msg; *p; p +=2)
+ {
+ char tb[2];
+ char c = fromhex (p[0]) * 16 + fromhex (p[1]);
+ tb[0] = c;
+ tb[1] = 0;
+ if (target_output_hook)
+ target_output_hook (tb);
+ else
+ fputs_filtered (tb, gdb_stdout);
+ }
+}
+
/* Wait until the remote machine stops, then return,
storing status in STATUS just as `wait' would.
Returns "pid" (though it's not clear what, if anything, that
struct target_waitstatus *status;
{
unsigned char buf[PBUFSIZ];
+ int thread_num = -1;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
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 */
n... = register number
r... = register contents
*/
-
p = &buf[3]; /* after Txx */
while (*p)
{
unsigned char *p1;
+ char *p_temp;
- regno = strtol (p, &p1, 16); /* Read the register number */
+ regno = strtol ((const char *) p, &p_temp, 16); /* Read the register number */
+ p1 = (unsigned char *)p_temp;
if (p1 == p)
- warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
- p1, buf);
-
- p = p1;
-
- if (*p++ != ':')
- warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
- p, buf);
-
- if (regno >= NUM_REGS)
- warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
- regno, p, buf);
-
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
{
- if (p[0] == 0 || p[1] == 0)
- warning ("Remote reply is too short: %s", buf);
- regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
- p += 2;
+ p1 = (unsigned char *) strchr ((const char *) p, ':');
+ if (p1 == NULL)
+ warning ("Malformed packet (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+ if (strncmp ((const char *) p, "thread", p1 - p) == 0)
+ {
+ thread_num = strtol ((const char *) ++p1, &p_temp, 16);
+ p = (unsigned char *)p_temp;
+ }
+ }
+ else
+ {
+ p = p1;
+
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %ld: %s\n\
+Packet: '%s'\n",
+ regno, p, buf);
+
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ warning ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+ supply_register (regno, regs);
}
if (*p++ != ';')
warning ("Remote register badly formatted: %s", buf);
-
- supply_register (regno, regs);
}
}
/* fall through */
status->value.sig = (enum target_signal)
(((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- return 0;
+ goto got_status;
case 'W': /* Target exited */
{
/* The remote process exited. */
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
- return 0;
+ goto got_status;
}
+ case 'X':
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ kill_kludge = 1;
+
+ goto got_status;
case 'O': /* Console output */
- fputs_filtered (buf + 1, gdb_stdout);
+ remote_console_output (buf + 1);
continue;
+ case '\0':
+ if (last_sent_signal != TARGET_SIGNAL_0)
+ {
+ /* Zero length reply means that we tried 'S' or 'C' and
+ the remote system doesn't support it. */
+ target_terminal_ours_for_output ();
+ printf_filtered
+ ("Can't send signals to this remote system. %s not sent.\n",
+ target_signal_to_name (last_sent_signal));
+ last_sent_signal = TARGET_SIGNAL_0;
+ target_terminal_inferior ();
+
+ strcpy ((char *) buf, last_sent_step ? "s" : "c");
+ putpkt ((char *) buf);
+ continue;
+ }
+ /* else fallthrough */
default:
warning ("Invalid remote reply: %s", buf);
continue;
}
}
- return 0;
+ got_status:
+ if (thread_num != -1)
+ {
+ /* Initial thread value can only be acquired via wait, so deal with
+ this marker which is used before the first thread value is
+ acquired. */
+ if (inferior_pid == 42000)
+ {
+ inferior_pid = thread_num;
+ add_thread (inferior_pid);
+ }
+ return thread_num;
+ }
+ return inferior_pid;
}
/* Number of bytes of registers this stub implements. */
char *p;
char regs[REGISTER_BYTES];
+ set_thread (inferior_pid, 1);
+
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);
int i;
char *p;
+ set_thread (inferior_pid, 1);
+
if (regno >= 0 && stub_supports_P)
{
/* Try storing a single register. */
remote_send (buf);
}
-#if 0
-
-/* Use of the data cache is disabled because it loses for looking at
+/*
+ Use of the data cache *used* to be disabled because it loses for looking at
and changing hardware I/O ports and the like. Accepting `volatile'
- would perhaps be one way to fix it, but a better way which would
- win for more cases would be to use the executable file for the text
- segment, like the `icache' code below but done cleanly (in some
- target-independent place, perhaps in target_xfer_memory, perhaps
- based on assigning each target a speed or perhaps by some simpler
- mechanism). */
+ would perhaps be one way to fix it. Another idea would be to use the
+ executable file for the text segment (for all SEC_CODE sections?
+ For all SEC_READONLY sections?). This has problems if you want to
+ actually see what the memory contains (e.g. self-modifying code,
+ clobbered memory, user downloaded the wrong thing).
+
+ Because it speeds so much up, it's now enabled, if you're playing
+ with registers you turn it of (set remotecache 0)
+*/
/* Read a word from remote address ADDR and return it.
This goes through the data cache. */
+#if 0 /* unused? */
static int
remote_fetch_word (addr)
CORE_ADDR addr;
{
-#if 0
- if (icache)
- {
- extern CORE_ADDR text_start, text_end;
-
- if (addr >= text_start && addr < text_end)
- {
- int buffer;
- xfer_core_file (addr, &buffer, sizeof (int));
- return buffer;
- }
- }
-#endif
return dcache_fetch (remote_dcache, addr);
}
{
dcache_poke (remote_dcache, addr, word);
}
-#endif /* 0 */
+#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 max (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.
static int
remote_write_bytes (memaddr, myaddr, len)
CORE_ADDR memaddr;
- unsigned char *myaddr;
+ char *myaddr;
int len;
{
- char buf[PBUFSIZ];
- int i;
- char *p;
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
- /* 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, len);
+ /* Chop the transfer down if necessary */
- /* We send target system values byte by byte, in increasing byte addresses,
- each byte encoded as two hex characters. */
+ max_buf_size = min (remote_write_size, PBUFSIZ);
+ if (remote_register_buf_size != 0)
+ max_buf_size = min (max_buf_size, remote_register_buf_size);
+
+ /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */
+ max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4;
- p = buf + strlen (buf);
- for (i = 0; i < len; i++)
+ origlen = len;
+ while (len > 0)
{
- *p++ = tohex ((myaddr[i] >> 4) & 0xf);
- *p++ = tohex (myaddr[i] & 0xf);
- }
- *p = '\0';
+ char buf[PBUFSIZ];
+ char *p;
+ int todo;
+ int i;
- putpkt (buf);
- getpkt (buf, 0);
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
- if (buf[0] == 'E')
- {
- /* There is no correspondance between what the remote protocol uses
- for errors and errno codes. We would like a cleaner way of
- representing errors (big enough to include errno codes, bfd_error
- codes, and others). But for now just return EIO. */
- errno = EIO;
- return 0;
+ /* 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, 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] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
+ }
+ *p = '\0';
+
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
}
- return len;
+ return origlen;
}
/* Read memory data directly from the remote machine.
static int
remote_read_bytes (memaddr, myaddr, len)
CORE_ADDR memaddr;
- unsigned char *myaddr;
+ char *myaddr;
int len;
{
- char buf[PBUFSIZ];
- int i;
- char *p;
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
- if (len > PBUFSIZ / 2 - 1)
- abort ();
+ /* Chop the transfer down if necessary */
- /* 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, len);
- putpkt (buf);
- getpkt (buf, 0);
+ max_buf_size = min (remote_write_size, PBUFSIZ);
+ if (remote_register_buf_size != 0)
+ max_buf_size = min (max_buf_size, remote_register_buf_size);
- if (buf[0] == 'E')
+ origlen = len;
+ while (len > 0)
{
- /* There is no correspondance between what the remote protocol uses
- for errors and errno codes. We would like a cleaner way of
- representing errors (big enough to include errno codes, bfd_error
- codes, and others). But for now just return EIO. */
- errno = EIO;
- return 0;
- }
+ 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, todo);
+ putpkt (buf);
+ getpkt (buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
/* Reply describes memory byte by byte,
each byte encoded as two hex characters. */
- p = buf;
- for (i = 0; i < len; i++)
- {
- 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] = fromhex (p[0]) * 16 + fromhex (p[1]);
- p += 2;
+ p = buf;
+ for (i = 0; i < todo; i++)
+ {
+ 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. */
+ return i + (origlen - len);
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
}
- return i;
+ return origlen;
}
\f
/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
int should_write;
struct target_ops *target; /* ignored */
{
- int xfersize;
- int bytes_xferred;
- int total_xferred = 0;
-
- while (len > 0)
- {
- if (len > MAXBUFBYTES)
- xfersize = MAXBUFBYTES;
- else
- xfersize = len;
-
- if (should_write)
- bytes_xferred = remote_write_bytes (memaddr,
- (unsigned char *)myaddr, xfersize);
- else
- bytes_xferred = remote_read_bytes (memaddr,
- (unsigned char *)myaddr, xfersize);
-
- /* If we get an error, we are done xferring. */
- if (bytes_xferred == 0)
- break;
+#ifdef REMOTE_TRANSLATE_XFER_ADDRESS
+ CORE_ADDR targaddr;
+ int targlen;
+ REMOTE_TRANSLATE_XFER_ADDRESS (memaddr, len, targaddr, targlen);
+ if (targlen == 0)
+ return 0;
+ memaddr = targaddr;
+ len = targlen;
+#endif
- memaddr += bytes_xferred;
- myaddr += bytes_xferred;
- len -= bytes_xferred;
- total_xferred += bytes_xferred;
- }
- return total_xferred;
+ return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, should_write);
}
+
#if 0
/* Enable after 4.12. */
remote_send (buf)
char *buf;
{
-
putpkt (buf);
getpkt (buf, 0);
/* Send a packet to the remote machine, with error checking.
The data of the packet is in BUF. */
-static void
+int
putpkt (buf)
char *buf;
{
char buf2[PBUFSIZ];
int cnt = strlen (buf);
int ch;
+ int tcount = 0;
char *p;
/* 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;
{
ch = readchar (remote_timeout);
- if (remote_debug)
+ if (remote_debug)
{
switch (ch)
{
case '$':
if (started_error_output)
{
- putc_unfiltered ('\n');
+ putchar_unfiltered ('\n');
started_error_output = 0;
}
}
case '+':
if (remote_debug)
printf_unfiltered("Ack\n");
- return;
+ return 1;
case SERIAL_TIMEOUT:
+ tcount ++;
+ if (tcount > 3)
+ return 0;
break; /* Retransmit buffer */
case '$':
{
- unsigned char junkbuf[PBUFSIZ];
+ char junkbuf[PBUFSIZ];
/* It's probably an old response, and we're out of sync. Just
gobble up the packet and ignore it. */
started_error_output = 1;
printf_unfiltered ("putpkt: Junk: ");
}
- putc_unfiltered (ch & 0177);
+ putchar_unfiltered (ch & 0177);
}
continue;
}
*bp = '\000';
- pktcsum = fromhex (readchar (remote_timeout)) << 4
- | fromhex (readchar (remote_timeout));
+ pktcsum = fromhex (readchar (remote_timeout)) << 4;
+ pktcsum |= fromhex (readchar (remote_timeout));
if (csum == pktcsum)
return 1;
- printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
- pktcsum, csum);
- puts_filtered (buf);
- puts_filtered ("\n");
-
+ if (remote_debug)
+ {
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ }
return 0;
}
case '*': /* Run length encoding */
+ csum += c;
c = readchar (remote_timeout);
csum += c;
c = c - ' ' + 3; /* Compute repeat count */
- if (bp + c - 1 < buf + PBUFSIZ - 1)
+
+ if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1)
{
memset (bp, *(bp - 1), c);
bp += c;
printf_filtered ("Repeat count %d too large for buffer: ", c);
puts_filtered (buf);
puts_filtered ("\n");
-
return 0;
+
default:
if (bp < buf + PBUFSIZ - 1)
{
If FOREVER, wait forever rather than timing out; this is used
while the target is executing user code. */
-static void
+void
getpkt (buf, forever)
char *buf;
int forever;
{
- char *bp;
int c;
int tries;
int timeout;
int val;
+ strcpy (buf,"timeout");
+
if (forever)
- timeout = -1;
+ {
+#ifdef MAINTENANCE_CMDS
+ timeout = watchdog > 0 ? watchdog : -1;
+#else
+ timeout = -1;
+#endif
+ }
+
else
timeout = remote_timeout;
-#define MAX_TRIES 10
+#define MAX_TRIES 3
for (tries = 1; tries <= MAX_TRIES; tries++)
{
if (c == SERIAL_TIMEOUT)
{
+#ifdef MAINTENANCE_CMDS
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+#endif
if (remote_debug)
puts_filtered ("Timed out.\n");
goto retry;
if (val == 1)
{
if (remote_debug)
- fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
+ fprintf_unfiltered (gdb_stdout, "Packet received: %s\n", buf);
SERIAL_WRITE (remote_desc, "+", 1);
return;
}
/* Try the whole thing again. */
-retry:
+ retry:
SERIAL_WRITE (remote_desc, "-", 1);
}
static void
remote_kill ()
{
- putpkt ("k");
+ /* For some mysterious reason, wait_for_inferior calls kill instead of
+ mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */
+ if (kill_kludge)
+ {
+ kill_kludge = 0;
+ target_mourn_inferior ();
+ return;
+ }
+
+ /* Use catch_errors so the user can quit from gdb even when we aren't on
+ speaking terms with the remote system. */
+ catch_errors (putpkt, "k", "", RETURN_MASK_ERROR);
+
/* Don't wait for it to die. I'm not really sure it matters whether
we do or not. For the existing stubs, kill is a noop. */
target_mourn_inferior ();
static void
remote_mourn ()
{
- unpush_target (&remote_ops);
+ remote_mourn_1 (&remote_ops);
+}
+
+static void
+extended_remote_mourn ()
+{
+ /* We do _not_ want to mourn the target like this; this will
+ remove the extended remote target from the target stack,
+ and the next time the user says "run" it'll fail.
+
+ FIXME: What is the right thing to do here? */
+#if 0
+ remote_mourn_1 (&extended_remote_ops);
+#endif
+}
+
+/* Worker function for remote_mourn. */
+static void
+remote_mourn_1 (target)
+ struct target_ops *target;
+{
+ unpush_target (target);
generic_mourn_inferior ();
}
-\f
-#ifdef REMOTE_BREAKPOINT
+/* In the extended protocol we want to be able to do things like
+ "run" and have them basically work as expected. So we need
+ a special create_inferior function.
+
+ FIXME: One day add support for changing the exec file
+ we're debugging, arguments and an environment. */
+
+static void
+extended_remote_create_inferior (exec_file, args, env)
+ char *exec_file;
+ char *args;
+ char **env;
+{
+ /* Rip out the breakpoints; we'll reinsert them after restarting
+ the remote server. */
+ remove_breakpoints ();
+
+ /* Now restart the remote server. */
+ extended_remote_restart ();
+
+ /* Now put the breakpoints back in. This way we're safe if the
+ restart function works via a unix fork on the remote side. */
+ insert_breakpoints ();
+
+ /* Clean up from the last time we were running. */
+ clear_proceed_status ();
+
+ /* Let the remote process run. */
+ proceed (-1, TARGET_SIGNAL_0, 0);
+}
+
+\f
/* 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
-/* Check that it fits in BREAKPOINT_MAX bytes. */
-static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT;
+#ifdef REMOTE_BREAKPOINT
-#else /* No 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 */
+}
+
+/* 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);
+}
+
+/* Other targets want to use the entire remote serial module but with
+ certain remote_ops overridden. */
+
+void
+open_remote_target (name, from_tty, target, extended_p)
+ char *name;
+ int from_tty;
+ struct target_ops *target;
+ int extended_p;
+{
+ printf_filtered ("Selecting the %sremote protocol\n",
+ (extended_p ? "extended-" : ""));
+ remote_open_1 (name, from_tty, target, extended_p);
}
-\f
-/* Define the target subroutine names */
-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\
-Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */
- remote_open, /* to_open */
- remote_close, /* to_close */
- NULL, /* to_attach */
- remote_detach, /* to_detach */
- remote_resume, /* to_resume */
- remote_wait, /* to_wait */
- remote_fetch_registers, /* to_fetch_registers */
- remote_store_registers, /* to_store_registers */
- 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 */
- NULL, /* to_terminal_ours */
- NULL, /* to_terminal_info */
- remote_kill, /* to_kill */
- generic_load, /* to_load */
- NULL, /* to_lookup_symbol */
- NULL, /* to_create_inferior */
- remote_mourn, /* to_mourn_inferior */
- 0, /* to_can_run */
- 0, /* to_notice_signals */
- process_stratum, /* to_stratum */
- NULL, /* to_next */
- 1, /* to_has_all_memory */
- 1, /* to_has_memory */
- 1, /* to_has_stack */
- 1, /* to_has_registers */
- 1, /* to_has_execution */
- NULL, /* sections */
- NULL, /* sections_end */
- OPS_MAGIC /* to_magic */
-};
void
_initialize_remote ()
{
+ init_remote_ops() ;
+ init_extended__remote_ops() ;
add_target (&remote_ops);
+ add_target (&extended_remote_ops);
+
+ add_show_from_set (add_set_cmd ("remotetimeout", no_class,
+ 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);
}