/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 1998
+ Free Software Foundation, Inc.
This file is part of GDB.
static void remote_interrupt PARAMS ((int signo));
-static void remote_interrupt_twice PARAMS ((int signo));
-
static void interrupt_query PARAMS ((void));
static void set_thread PARAMS ((int, int));
static int hexnumlen PARAMS ((ULONGEST num));
+static void init_remote_ops PARAMS ((void));
+
+static void init_extended_remote_ops PARAMS ((void));
+
+static void remote_stop PARAMS ((void));
+
+static int hexnumstr PARAMS ((char *, ULONGEST));
+
+static CORE_ADDR remote_address_masked PARAMS ((CORE_ADDR));
+
+static void print_packet PARAMS ((char *));
+
+static unsigned long crc32 PARAMS ((unsigned char *, int, unsigned int));
+
+static void compare_sections_command PARAMS ((char *, int));
+
+static void packet_command PARAMS ((char *, int));
+
/* 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 */
+void remote_console_output PARAMS ((char *));
-static struct target_ops remote_ops ;
+void open_remote_target PARAMS ((char *, int, struct target_ops *, int));
-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 ;
-}
+void _initialize_remote PARAMS ((void));
+
+/* */
+static struct target_ops remote_ops;
+
+static struct target_ops extended_remote_ops;
/* This was 5 seconds, which is a long time to sit and wait.
Unless this is going though some terminal server or multiplexer or
static int remote_break;
+/* Has the user attempted to interrupt the target? If so, then offer
+ the user the opportunity to bail out completely if he interrupts
+ again. */
+static int interrupted_already = 0;
+
/* 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. */
static int remote_write_size = PBUFSIZ;
+/* This variable sets the number of bits in an address that are to be
+ sent in a memory ("M" or "m") packet. Normally, after stripping
+ leading zeros, the entire address would be sent. This variable
+ restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The
+ initial implementation of remote.c restricted the address sent in
+ memory packets to ``host::sizeof long'' bytes - (typically 32
+ bits). Consequently, for 64 bit targets, the upper 32 bits of an
+ address was never sent. Since fixing this bug may cause a break in
+ some remote targets this variable is principly provided to
+ facilitate backward compatibility. */
+
+static int remote_address_size;
+
/* 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
\f
/* Send ^C to target to halt it. Target will respond, and send us a
packet. */
+static void (*ofunc) PARAMS ((int));
static void
remote_interrupt (signo)
int signo;
{
- /* If this doesn't work, try more severe steps. */
- signal (signo, remote_interrupt_twice);
-
- if (remote_debug)
- printf_unfiltered ("remote_interrupt called\n");
-
- /* 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);
+ remote_stop ();
+ signal (signo, remote_interrupt);
}
-
-static void (*ofunc)();
-
-/* The user typed ^C twice. */
+
static void
-remote_interrupt_twice (signo)
- int signo;
+remote_stop ()
{
- signal (signo, ofunc);
-
- interrupt_query ();
+ if (!interrupted_already)
+ {
+ /* Send a break or a ^C, depending on user preference. */
+ interrupted_already = 1;
- signal (signo, remote_interrupt);
+ if (remote_debug)
+ printf_unfiltered ("remote_stop called\n");
+
+ if (remote_break)
+ SERIAL_SEND_BREAK (remote_desc);
+ else
+ SERIAL_WRITE (remote_desc, "\003", 1);
+ }
+ else
+ {
+ signal (SIGINT, ofunc);
+ interrupt_query ();
+ signal (SIGINT, remote_interrupt);
+ interrupted_already = 0;
+ }
}
/* Ask the user what to do when an interrupt is received. */
{
unsigned char *p;
- ofunc = (void (*)()) signal (SIGINT, remote_interrupt);
+ interrupted_already = 0;
+ ofunc = signal (SIGINT, remote_interrupt);
getpkt ((char *) buf, 1);
signal (SIGINT, ofunc);
in the buffer is not a hex character, assume that has happened
and try to fetch another packet to read. */
while ((buf[0] < '0' || buf[0] > '9')
- && (buf[0] < 'a' || buf[0] > 'f'))
+ && (buf[0] < 'a' || buf[0] > 'f')
+ && buf[0] != 'x') /* New: unavailable register value */
{
if (remote_debug)
printf_unfiltered ("Bad register packet; fetching a new packet\n");
print a second warning. */
goto supply_them;
}
- regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ if (p[0] == 'x' && p[1] == 'x')
+ regs[i] = 0; /* 'x' */
+ else
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
p += 2;
}
warning ("Remote reply is too short: %s", buf);
#endif
}
-
- supply_them:
+
+ supply_them:
for (i = 0; i < NUM_REGS; i++)
+ {
supply_register (i, ®s[REGISTER_BYTE(i)]);
+ if (buf[REGISTER_BYTE(i) * 2] == 'x')
+ register_valid[i] = -1; /* register value not available */
+ }
}
/* Prepare to store registers. Since we may send them all (using a
return max (i, 1);
}
+/* Set BUF to the hex digits representing NUM */
+
+static int
+hexnumstr (buf, num)
+ char *buf;
+ ULONGEST num;
+{
+ int i;
+ int len = hexnumlen (num);
+
+ buf[len] = '\0';
+
+ for (i = len - 1; i >= 0; i--)
+ {
+ buf[i] = "0123456789abcdef" [(num & 0xf)];
+ num >>= 4;
+ }
+
+ return len;
+}
+
+/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits */
+
+static CORE_ADDR
+remote_address_masked (addr)
+ CORE_ADDR addr;
+{
+ if (remote_address_size > 0
+ && remote_address_size < (sizeof (ULONGEST) * 8))
+ {
+ /* Only create a mask when that mask can safely be constructed
+ in a ULONGEST variable. */
+ ULONGEST mask = 1;
+ mask = (mask << remote_address_size) - 1;
+ addr &= mask;
+ }
+ return addr;
+}
+
/* 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.
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);
+ /* construct "M"<memaddr>","<len>":" */
+ /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
+ memaddr = remote_address_masked (memaddr);
+ p = buf;
+ *p++ = 'M';
+ p += hexnumstr (p, (ULONGEST) memaddr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) todo);
+ *p++ = ':';
+ *p = '\0';
/* 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);
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);
+ /* construct "m"<memaddr>","<len>" */
+ /* sprintf (buf, "m%lx,%x", (unsigned long) memaddr, todo); */
+ memaddr = remote_address_masked (memaddr);
+ p = buf;
+ *p++ = 'm';
+ p += hexnumstr (p, (ULONGEST) memaddr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) todo);
+ *p = '\0';
+
putpkt (buf);
getpkt (buf, 0);
error ("Remote failure reply: %s", buf);
}
+/* Display a null-terminated packet on stdout, for debugging, using C
+ string notation. */
+
+static void
+print_packet (buf)
+ char *buf;
+{
+ puts_filtered ("\"");
+ while (*buf)
+ gdb_printchar (*buf++, gdb_stdout, '"');
+ puts_filtered ("\"");
+}
+
+
/* Send a packet to the remote machine, with error checking.
The data of the packet is in BUF. */
Depends on the target understanding the new "qCRC:" request. */
static void
-remote_compare_command (args, from_tty)
+compare_sections_command (args, from_tty)
char *args;
int from_tty;
{
bfd_size_type size;
bfd_vma lma;
int matched = 0;
+ int mismatched = 0;
if (!exec_bfd)
error ("command cannot be used without an exec file");
if (host_crc == target_crc)
printf_filtered ("matched.\n");
else
- printf_filtered ("MIS-MATCHED!\n");
+ {
+ printf_filtered ("MIS-MATCHED!\n");
+ mismatched++;
+ }
do_cleanups (old_chain);
}
+ if (mismatched > 0)
+ warning ("One or more sections of the remote executable does not match\nthe loaded file\n");
if (args && !matched)
printf_filtered ("No loaded section named '%s'.\n", args);
}
+static void
+packet_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char buf[PBUFSIZ];
+
+ if (! remote_desc)
+ error ("command can only be used with remote target");
+
+ if (! args)
+ error ("remote-packet command requires packet text as argument");
+
+ puts_filtered ("sending: ");
+ print_packet (args);
+ puts_filtered ("\n");
+ putpkt (args);
+
+ getpkt (buf, 0);
+ puts_filtered ("received: ");
+ print_packet (buf);
+ puts_filtered ("\n");
+}
+
+static void
+init_remote_ops ()
+{
+ 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_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_kill = remote_kill;
+ remote_ops.to_load = generic_load;
+ remote_ops.to_mourn_inferior = remote_mourn;
+ remote_ops.to_thread_alive = remote_thread_alive;
+ remote_ops.to_stop = remote_stop;
+ remote_ops.to_stratum = process_stratum;
+ 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_magic = OPS_MAGIC;
+}
+
+static void
+init_extended_remote_ops ()
+{
+ extended_remote_ops = remote_ops;
+
+ 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_create_inferior = extended_remote_create_inferior;
+ extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
+}
+
void
_initialize_remote ()
{
- init_remote_ops() ;
- init_extended_remote_ops() ;
+ init_remote_ops ();
add_target (&remote_ops);
+
+ init_extended_remote_ops ();
add_target (&extended_remote_ops);
- add_cmd ("compare-sections", class_obscure, remote_compare_command,
- "Compare section data on remote target to the exec file.\n\
-Optional argument is a single section name (default: all loadable sections).",
+ add_cmd ("compare-sections", class_obscure, compare_sections_command,
+ "Compare section data on target to the exec file.\n\
+Argument is a single section name (default: all loaded sections).",
&cmdlist);
+ add_cmd ("packet", class_maintenance, packet_command,
+ "Send an arbitrary packet to a remote target.\n\
+ maintenance packet TEXT\n\
+If GDB is talking to an inferior via the GDB serial protocol, then\n\
+this command sends the string TEXT to the inferior, and displays the\n\
+response packet. GDB supplies the initial `$' character, and the\n\
+terminating `#' character and checksum.",
+ &maintenancelist);
+
add_show_from_set (add_set_cmd ("remotetimeout", no_class,
var_integer, (char *)&remote_timeout,
"Set timeout value for remote read.\n", &setlist),
var_integer, (char *)&remote_write_size,
"Set the maximum number of bytes in each memory write packet.\n", &setlist),
&showlist);
+
+ remote_address_size = TARGET_PTR_BIT;
+ add_show_from_set (add_set_cmd ("remoteaddresssize", class_obscure,
+ var_integer, (char *)&remote_address_size,
+ "Set the maximum size of the address (in bits) in a memory packet.\n", &setlist),
+ &showlist);
}