/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 1998
- Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Remote communication protocol.
-
- A debug packet whose contents are <data>
- is encapsulated for transmission in the form:
-
- $ <data> # CSUM1 CSUM2
-
- <data> must be ASCII alphanumeric and cannot include characters
- '$' or '#'. If <data> starts with two characters followed by
- ':', then the existing stubs interpret this as a sequence number.
-
- CSUM1 and CSUM2 are ascii hex representation of an 8-bit
- checksum of <data>, the most significant nibble is sent first.
- the hex digits 0-9,a-f are used.
-
- Receiver responds with:
-
- + - if CSUM is correct and ready for next packet
- - - if CSUM is incorrect
-
- <data> is as follows:
- 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.
- Registers are in the internal order
- for GDB, and the bytes in a register
- are in the same order the machine uses.
- or ENN for an error.
-
- write regs GXX..XX Each byte of register data
- is described by two hex digits.
- reply OK for success
- ENN for an error
-
- write reg Pn...=r... Write register n... with value r...,
- which contains two hex digits for each
- byte in the register (target byte
- order).
- reply OK for success
- ENN for an error
- (not supported by all stubs).
-
- read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
- reply XX..XX XX..XX is mem contents
- Can be fewer bytes than requested
- if able to read only part of the data.
- or ENN NN is errno
-
- write mem MAA..AA,LLLL:XX..XX
- AA..AA is address,
- LLLL is number of bytes,
- XX..XX is data
- reply OK for success
- ENN for an error (this includes the case
- where only part of the data was
- written).
-
- continue cAA..AA AA..AA is address to resume
- If AA..AA is omitted,
- resume at same address.
-
- step sAA..AA AA..AA is address to resume
- 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.
-
- or... TAAn...:r...;n...:r...;n...:r...;
- AA = signal number
- 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)
- reset r reset -- see sparc stub.
- reserved <other> On other requests, the stub should
- ignore the request and send an empty
- response ($#<checksum>). This way
- we can extend the protocol and GDB
- can tell whether the stub it is
- talking to uses the old or the new.
- search tAA:PP,MM Search backwards starting at address
- AA for a match with pattern PP and
- mask MM. PP and MM are 4 bytes.
- Not supported by all stubs.
-
- general query qXXXX Request info about XXXX.
- 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
-
- Responses can be run-length encoded to save space. A '*' means that
- the next character is an ASCII encoding giving a repeat count which
- stands for that many repititions of the character preceding the '*'.
- 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". */
+ Copyright 1988, 1991-2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* See the GDB User Guide for details of the GDB remote protocol. */
#include "defs.h"
#include "gdb_string.h"
+#include <ctype.h>
#include <fcntl.h>
#include "frame.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
#include "target.h"
-#include "wait.h"
-/*#include "terminal.h"*/
+#include "gdb_wait.h"
+/*#include "terminal.h" */
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
#include "gdbthread.h"
+#include "remote.h"
-#include "dcache.h"
-
+#include <ctype.h>
+#include <sys/time.h>
#ifdef USG
#include <sys/types.h>
#endif
+#include "event-loop.h"
+#include "event-top.h"
+#include "inf-loop.h"
+
#include <signal.h>
#include "serial.h"
/* Prototypes for local functions */
+static void cleanup_sigint_signal_handler (void *dummy);
+static void initialize_sigint_signal_handler (void);
+static int getpkt_sane (char *buf, long sizeof_buf, int forever);
-static int remote_write_bytes PARAMS ((CORE_ADDR memaddr,
- char *myaddr, int len));
+static void handle_remote_sigint (int);
+static void handle_remote_sigint_twice (int);
+static void async_remote_interrupt (gdb_client_data);
+void async_remote_interrupt_twice (gdb_client_data);
-static int remote_read_bytes PARAMS ((CORE_ADDR memaddr,
- char *myaddr, int len));
+static void build_remote_gdbarch_data (void);
-static void remote_files_info PARAMS ((struct target_ops *ignore));
+static int remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len);
-static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char * myaddr,
- int len, int should_write,
- struct target_ops * target));
+static int remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len);
-static void remote_prepare_to_store PARAMS ((void));
+static void remote_files_info (struct target_ops *ignore);
-static void remote_fetch_registers PARAMS ((int regno));
+static int remote_xfer_memory (CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
-static void remote_resume PARAMS ((int pid, int step,
- enum target_signal siggnal));
+static void remote_prepare_to_store (void);
-static int remote_start_remote PARAMS ((char *dummy));
+static void remote_fetch_registers (int regno);
-static void remote_open PARAMS ((char *name, int from_tty));
+static void remote_resume (int pid, int step, enum target_signal siggnal);
+static void remote_async_resume (int pid, int step,
+ enum target_signal siggnal);
+static int remote_start_remote (PTR);
-static void extended_remote_open PARAMS ((char *name, int from_tty));
+static void remote_open (char *name, int from_tty);
+static void remote_async_open (char *name, int from_tty);
-static void remote_open_1 PARAMS ((char *, int, struct target_ops *,
- int extended_p));
+static void extended_remote_open (char *name, int from_tty);
+static void extended_remote_async_open (char *name, int from_tty);
-static void remote_close PARAMS ((int quitting));
+static void remote_open_1 (char *, int, struct target_ops *, int extended_p);
+static void remote_async_open_1 (char *, int, struct target_ops *,
+ int extended_p);
-static void remote_store_registers PARAMS ((int regno));
+static void remote_close (int quitting);
-static void remote_mourn PARAMS ((void));
+static void remote_store_registers (int regno);
-static void extended_remote_restart PARAMS ((void));
+static void remote_mourn (void);
+static void remote_async_mourn (void);
-static void extended_remote_mourn PARAMS ((void));
+static void extended_remote_restart (void);
-static void extended_remote_create_inferior PARAMS ((char *, char *, char **));
+static void extended_remote_mourn (void);
-static void remote_mourn_1 PARAMS ((struct target_ops *));
+static void extended_remote_create_inferior (char *, char *, char **);
+static void extended_remote_async_create_inferior (char *, char *, char **);
-static void remote_send PARAMS ((char *buf));
+static void remote_mourn_1 (struct target_ops *);
-static int readchar PARAMS ((int timeout));
+static void remote_send (char *buf, long sizeof_buf);
-static int remote_wait PARAMS ((int pid, struct target_waitstatus * status));
+static int readchar (int timeout);
-static void remote_kill PARAMS ((void));
+static int remote_wait (int pid, struct target_waitstatus *status);
+static int remote_async_wait (int pid, struct target_waitstatus *status);
-static int tohex PARAMS ((int nib));
+static void remote_kill (void);
+static void remote_async_kill (void);
-static void remote_detach PARAMS ((char *args, int from_tty));
+static int tohex (int nib);
-static void remote_interrupt PARAMS ((int signo));
+static void remote_detach (char *args, int from_tty);
+static void remote_async_detach (char *args, int from_tty);
-static void interrupt_query PARAMS ((void));
+static void remote_interrupt (int signo);
-static void set_thread PARAMS ((int, int));
+static void remote_interrupt_twice (int signo);
-static int remote_thread_alive PARAMS ((int));
+static void interrupt_query (void);
-static void get_offsets PARAMS ((void));
+static void set_thread (int, int);
-static int read_frame PARAMS ((char *));
+static int remote_thread_alive (int);
-static int remote_insert_breakpoint PARAMS ((CORE_ADDR, char *));
+static void get_offsets (void);
-static int remote_remove_breakpoint PARAMS ((CORE_ADDR, char *));
+static long read_frame (char *buf, long sizeof_buf);
-static int hexnumlen PARAMS ((ULONGEST num));
+static int remote_insert_breakpoint (CORE_ADDR, char *);
-static void init_remote_ops PARAMS ((void));
+static int remote_remove_breakpoint (CORE_ADDR, char *);
-static void init_extended_remote_ops PARAMS ((void));
+static int hexnumlen (ULONGEST num);
-static void remote_stop PARAMS ((void));
+static void init_remote_ops (void);
-static int ishex PARAMS ((int ch, int *val));
+static void init_extended_remote_ops (void);
-static int stubhex PARAMS ((int ch));
+static void init_remote_cisco_ops (void);
-static int hexnumstr PARAMS ((char *, ULONGEST));
+static struct target_ops remote_cisco_ops;
-static CORE_ADDR remote_address_masked PARAMS ((CORE_ADDR));
+static void remote_stop (void);
-static void print_packet PARAMS ((char *));
+static int ishex (int ch, int *val);
-static unsigned long crc32 PARAMS ((unsigned char *, int, unsigned int));
+static int stubhex (int ch);
-static void compare_sections_command PARAMS ((char *, int));
+static int remote_query (int /*char */ , char *, char *, int *);
-static void packet_command PARAMS ((char *, int));
+static int hexnumstr (char *, ULONGEST);
-static int stub_unpack_int PARAMS ((char *buff, int fieldlength));
+static int hexnumnstr (char *, ULONGEST, int);
-char *unpack_varlen_hex PARAMS ((char *buff, int *result));
+static CORE_ADDR remote_address_masked (CORE_ADDR);
-static char *unpack_nibble PARAMS ((char *buf, int *val));
+static void print_packet (char *);
-static char *pack_nibble PARAMS ((char *buf, int nibble));
+static unsigned long crc32 (unsigned char *, int, unsigned int);
-static char *pack_hex_byte PARAMS ((char *pkt, unsigned char byte));
+static void compare_sections_command (char *, int);
-static char *unpack_byte PARAMS ((char *buf, int *value));
+static void packet_command (char *, int);
-static char *pack_int PARAMS ((char *buf, int value));
+static int stub_unpack_int (char *buff, int fieldlength);
-static char *unpack_int PARAMS ((char *buf, int *value));
+static int remote_current_thread (int oldpid);
-static char *unpack_string PARAMS ((char *src, char *dest, int length));
+static void remote_find_new_threads (void);
-static char *pack_threadid PARAMS ((char *pkt, threadref *id));
+static void record_currthread (int currthread);
-static char *unpack_threadid PARAMS ((char *inbuf, threadref *id));
+/* exported functions */
-void int_to_threadref PARAMS ((threadref *id, int value));
+extern int fromhex (int a);
-static int threadref_to_int PARAMS ((threadref *ref));
+static int putpkt_binary (char *buf, int cnt);
-static void copy_threadref PARAMS ((threadref *dest, threadref *src));
+static void check_binary_download (CORE_ADDR addr);
-static int threadmatch PARAMS ((threadref *dest, threadref *src));
+struct packet_config;
-static char *pack_threadinfo_request PARAMS ((char *pkt, int mode,
- threadref *id));
+static void show_packet_config_cmd (struct packet_config *config);
-static int remote_unpack_thread_info_response PARAMS ((char *pkt,
- threadref *expectedref,
- struct gdb_ext_thread_info *info));
+static void update_packet_config (struct packet_config *config);
+/* Define the target subroutine names */
-static int remote_get_threadinfo PARAMS ((threadref *threadid,
- int fieldset, /*TAG mask */
- struct gdb_ext_thread_info *info));
+void open_remote_target (char *, int, struct target_ops *, int);
-static int adapt_remote_get_threadinfo PARAMS ((gdb_threadref *ref,
- int selection,
- struct gdb_ext_thread_info *info));
+void _initialize_remote (void);
-static char *pack_threadlist_request PARAMS ((char *pkt, int startflag,
- int threadcount,
- threadref *nextthread));
+/* */
-static int parse_threadlist_response PARAMS ((char *pkt,
- int result_limit,
- threadref *original_echo,
- threadref *resultlist,
- int *doneflag));
+static struct target_ops remote_ops;
-static int remote_get_threadlist PARAMS ((int startflag,
- threadref *nextthread,
- int result_limit,
- int *done,
- int *result_count,
- threadref *threadlist));
+static struct target_ops extended_remote_ops;
-typedef int (*rmt_thread_action) (threadref *ref, void *context);
+/* Temporary target ops. Just like the remote_ops and
+ extended_remote_ops, but with asynchronous support. */
+static struct target_ops remote_async_ops;
-static int remote_threadlist_iterator PARAMS ((rmt_thread_action stepfunction,
- void *context, int looplimit));
+static struct target_ops extended_async_remote_ops;
-static int remote_newthread_step PARAMS ((threadref *ref, void *context));
+/* FIXME: cagney/1999-09-23: Even though getpkt was called with
+ ``forever'' still use the normal timeout mechanism. This is
+ currently used by the ASYNC code to guarentee that target reads
+ during the initial connect always time-out. Once getpkt has been
+ modified to return a timeout indication and, in turn
+ remote_wait()/wait_for_inferior() have gained a timeout parameter
+ this can go away. */
+static int wait_forever_enabled_p = 1;
-static int remote_current_thread PARAMS ((int oldpid));
-int remote_find_new_threads PARAMS ((void));
+/* 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 void record_currthread PARAMS ((int currthread));
+static int remote_break;
-static void init_remote_threads PARAMS ((void));
+/* 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 serial_t remote_desc = NULL;
-/* exported functions */
+/* This is set by the target (thru the 'S' message)
+ to denote that the target is in kernel mode. */
+static int cisco_kernel_mode = 0;
-extern int fromhex PARAMS ((int a));
+/* 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. */
-extern void getpkt PARAMS ((char *buf, int forever));
+static int remote_address_size;
-extern int putpkt PARAMS ((char *buf));
+/* Tempoary to track who currently owns the terminal. See
+ target_async_terminal_* for more details. */
-void remote_console_output PARAMS ((char *));
+static int remote_async_terminal_ours_p;
-/* Define the target subroutine names */
+\f
+/* This is the size (in chars) of the first response to the ``g''
+ packet. It is used as a heuristic when determining the maximum
+ size of memory-read and memory-write packets. A target will
+ typically only reserve a buffer large enough to hold the ``g''
+ packet. The size does not include packet overhead (headers and
+ trailers). */
+
+static long actual_register_packet_size;
+
+/* This is the maximum size (in chars) of a non read/write packet. It
+ is also used as a cap on the size of read/write packets. */
+
+static long remote_packet_size;
+/* compatibility. */
+#define PBUFSIZ (remote_packet_size)
+
+/* User configurable variables for the number of characters in a
+ memory read/write packet. MIN (PBUFSIZ, g-packet-size) is the
+ default. Some targets need smaller values (fifo overruns, et.al.)
+ and some users need larger values (speed up transfers). The
+ variables ``preferred_*'' (the user request), ``current_*'' (what
+ was actually set) and ``forced_*'' (Positive - a soft limit,
+ negative - a hard limit). */
+
+struct memory_packet_config
+{
+ char *name;
+ long size;
+ int fixed_p;
+};
-void open_remote_target PARAMS ((char *, int, struct target_ops *, int));
+/* Compute the current size of a read/write packet. Since this makes
+ use of ``actual_register_packet_size'' the computation is dynamic. */
-void _initialize_remote PARAMS ((void));
+static long
+get_memory_packet_size (struct memory_packet_config *config)
+{
+ /* NOTE: The somewhat arbitrary 16k comes from the knowledge (folk
+ law?) that some hosts don't cope very well with large alloca()
+ calls. Eventually the alloca() code will be replaced by calls to
+ xmalloc() and make_cleanups() allowing this restriction to either
+ be lifted or removed. */
+#ifndef MAX_REMOTE_PACKET_SIZE
+#define MAX_REMOTE_PACKET_SIZE 16384
+#endif
+ /* NOTE: 16 is just chosen at random. */
+#ifndef MIN_REMOTE_PACKET_SIZE
+#define MIN_REMOTE_PACKET_SIZE 16
+#endif
+ long what_they_get;
+ if (config->fixed_p)
+ {
+ if (config->size <= 0)
+ what_they_get = MAX_REMOTE_PACKET_SIZE;
+ else
+ what_they_get = config->size;
+ }
+ else
+ {
+ what_they_get = remote_packet_size;
+ /* Limit the packet to the size specified by the user. */
+ if (config->size > 0
+ && what_they_get > config->size)
+ what_they_get = config->size;
+ /* Limit it to the size of the targets ``g'' response. */
+ if (actual_register_packet_size > 0
+ && what_they_get > actual_register_packet_size)
+ what_they_get = actual_register_packet_size;
+ }
+ if (what_they_get > MAX_REMOTE_PACKET_SIZE)
+ what_they_get = MAX_REMOTE_PACKET_SIZE;
+ if (what_they_get < MIN_REMOTE_PACKET_SIZE)
+ what_they_get = MIN_REMOTE_PACKET_SIZE;
+ return what_they_get;
+}
-/* */
+/* Update the size of a read/write packet. If they user wants
+ something really big then do a sanity check. */
-static struct target_ops remote_ops;
+static void
+set_memory_packet_size (char *args, struct memory_packet_config *config)
+{
+ int fixed_p = config->fixed_p;
+ long size = config->size;
+ if (args == NULL)
+ error ("Argument required (integer, `fixed' or `limited').");
+ else if (strcmp (args, "hard") == 0
+ || strcmp (args, "fixed") == 0)
+ fixed_p = 1;
+ else if (strcmp (args, "soft") == 0
+ || strcmp (args, "limit") == 0)
+ fixed_p = 0;
+ else
+ {
+ char *end;
+ size = strtoul (args, &end, 0);
+ if (args == end)
+ error ("Invalid %s (bad syntax).", config->name);
+#if 0
+ /* Instead of explicitly capping the size of a packet to
+ MAX_REMOTE_PACKET_SIZE or dissallowing it, the user is
+ instead allowed to set the size to something arbitrarily
+ large. */
+ if (size > MAX_REMOTE_PACKET_SIZE)
+ error ("Invalid %s (too large).", config->name);
+#endif
+ }
+ /* Extra checks? */
+ if (fixed_p && !config->fixed_p)
+ {
+ if (! query ("The target may not be able to correctly handle a %s\n"
+ "of %ld bytes. Change the packet size? ",
+ config->name, size))
+ error ("Packet size not changed.");
+ }
+ /* Update the config. */
+ config->fixed_p = fixed_p;
+ config->size = size;
+}
-static struct target_ops extended_remote_ops;
+static void
+show_memory_packet_size (struct memory_packet_config *config)
+{
+ printf_filtered ("The %s is %ld. ", config->name, config->size);
+ if (config->fixed_p)
+ printf_filtered ("Packets are fixed at %ld bytes.\n",
+ get_memory_packet_size (config));
+ else
+ printf_filtered ("Packets are limited to %ld bytes.\n",
+ get_memory_packet_size (config));
+}
-static struct target_thread_vector remote_thread_vec;
+static struct memory_packet_config memory_write_packet_config =
+{
+ "memory-write-packet-size",
+};
-/* 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 void
+set_memory_write_packet_size (char *args, int from_tty)
+{
+ set_memory_packet_size (args, &memory_write_packet_config);
+}
-/* Changed to allow option to set timeout value.
- was static int remote_timeout = 2; */
-extern int remote_timeout;
+static void
+show_memory_write_packet_size (char *args, int from_tty)
+{
+ show_memory_packet_size (&memory_write_packet_config);
+}
-/* 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 long
+get_memory_write_packet_size (void)
+{
+ return get_memory_packet_size (&memory_write_packet_config);
+}
-static int remote_break;
+static struct memory_packet_config memory_read_packet_config =
+{
+ "memory-read-packet-size",
+};
-/* 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;
+static void
+set_memory_read_packet_size (char *args, int from_tty)
+{
+ set_memory_packet_size (args, &memory_read_packet_config);
+}
-/* 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 serial_t remote_desc = NULL;
+static void
+show_memory_read_packet_size (char *args, int from_tty)
+{
+ show_memory_packet_size (&memory_read_packet_config);
+}
-/* 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
- for writing large chunks of memory (e.g. in downloads). Also, this needs
- to be more than 400 if required to hold the registers (see below, where
- we round it up based on REGISTER_BYTES). */
-#define PBUFSIZ 400
+static long
+get_memory_read_packet_size (void)
+{
+ long size = get_memory_packet_size (&memory_read_packet_config);
+ /* FIXME: cagney/1999-11-07: Functions like getpkt() need to get an
+ extra buffer size argument before the memory read size can be
+ increased beyond PBUFSIZ. */
+ if (size > PBUFSIZ)
+ size = PBUFSIZ;
+ return size;
+}
-/* Maximum number of bytes to read/write at once. The value here
- is chosen to fill up a packet (the headers account for the 32). */
-#define MAXBUFBYTES ((PBUFSIZ-32)/2)
+/* Register packet size initialization. Since the bounds change when
+ the architecture changes (namely REGISTER_BYTES) this all needs to
+ be multi-arched. */
-/* Round up PBUFSIZ to hold all the registers, at least. */
-/* The blank line after the #if seems to be required to work around a
- bug in HP's PA compiler. */
-#if REGISTER_BYTES > MAXBUFBYTES
+static void
+register_remote_packet_sizes (void)
+{
+ REGISTER_GDBARCH_SWAP (remote_packet_size);
+ REGISTER_GDBARCH_SWAP (actual_register_packet_size);
+}
-#undef PBUFSIZ
-#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
-#endif
+static void
+build_remote_packet_sizes (void)
+{
+ /* Default maximum number of characters in a packet body. Many
+ remote stubs have a hardwired buffer size of 400 bytes
+ (c.f. BUFMAX in m68k-stub.c and i386-stub.c). BUFMAX-1 is used
+ as the maximum packet-size to ensure that the packet and an extra
+ NUL character can always fit in the buffer. This stops GDB
+ trashing stubs that try to squeeze an extra NUL into what is
+ already a full buffer (As of 1999-12-04 that was most stubs. */
+ remote_packet_size = 400 - 1;
+ /* Should REGISTER_BYTES needs more space than the default, adjust
+ the size accordingly. Remember that each byte is encoded as two
+ characters. 32 is the overhead for the packet header /
+ footer. NOTE: cagney/1999-10-26: I suspect that 8
+ (``$NN:G...#NN'') is a better guess, the below has been padded a
+ little. */
+ if (REGISTER_BYTES > ((remote_packet_size - 32) / 2))
+ remote_packet_size = (REGISTER_BYTES * 2 + 32);
+
+ /* This one is filled in when a ``g'' packet is received. */
+ actual_register_packet_size = 0;
+}
+\f
+/* Generic configuration support for packets the stub optionally
+ supports. Allows the user to specify the use of the packet as well
+ as allowing GDB to auto-detect support in the remote stub. */
+enum packet_support
+ {
+ PACKET_SUPPORT_UNKNOWN = 0,
+ PACKET_ENABLE,
+ PACKET_DISABLE
+ };
-/* 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). */
+struct packet_config
+ {
+ char *name;
+ char *title;
+ enum cmd_auto_boolean detect;
+ enum packet_support support;
+ };
-static int remote_write_size = PBUFSIZ;
+/* Analyze a packet's return value and update the packet config
+ accordingly. */
-/* 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. */
+enum packet_result
+{
+ PACKET_ERROR,
+ PACKET_OK,
+ PACKET_UNKNOWN
+};
-static int remote_address_size;
+static void
+update_packet_config (struct packet_config *config)
+{
+ switch (config->detect)
+ {
+ case CMD_AUTO_BOOLEAN_TRUE:
+ config->support = PACKET_ENABLE;
+ break;
+ case CMD_AUTO_BOOLEAN_FALSE:
+ config->support = PACKET_DISABLE;
+ break;
+ case CMD_AUTO_BOOLEAN_AUTO:
+ config->support = PACKET_SUPPORT_UNKNOWN;
+ break;
+ }
+}
+
+static void
+show_packet_config_cmd (struct packet_config *config)
+{
+ char *support = "internal-error";
+ switch (config->support)
+ {
+ case PACKET_ENABLE:
+ support = "enabled";
+ break;
+ case PACKET_DISABLE:
+ support = "disabled";
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ support = "unknown";
+ break;
+ }
+ switch (config->detect)
+ {
+ case CMD_AUTO_BOOLEAN_AUTO:
+ printf_filtered ("Support for remote protocol `%s' (%s) packet is auto-detected, currently %s.\n",
+ config->name, config->title, support);
+ break;
+ case CMD_AUTO_BOOLEAN_TRUE:
+ case CMD_AUTO_BOOLEAN_FALSE:
+ printf_filtered ("Support for remote protocol `%s' (%s) packet is currently %s.\n",
+ config->name, config->title, support);
+ break;
+ }
+}
+
+static void
+add_packet_config_cmd (struct packet_config *config,
+ char *name,
+ char *title,
+ void (*set_func) (char *args, int from_tty,
+ struct cmd_list_element *
+ c),
+ void (*show_func) (char *name,
+ int from_tty),
+ struct cmd_list_element **set_remote_list,
+ struct cmd_list_element **show_remote_list,
+ int legacy)
+{
+ struct cmd_list_element *set_cmd;
+ struct cmd_list_element *show_cmd;
+ char *set_doc;
+ char *show_doc;
+ char *cmd_name;
+ config->name = name;
+ config->title = title;
+ config->detect = CMD_AUTO_BOOLEAN_AUTO;
+ config->support = PACKET_SUPPORT_UNKNOWN;
+ xasprintf (&set_doc, "Set use of remote protocol `%s' (%s) packet",
+ name, title);
+ xasprintf (&show_doc, "Show current use of remote protocol `%s' (%s) packet",
+ name, title);
+ /* set/show TITLE-packet {auto,on,off} */
+ xasprintf (&cmd_name, "%s-packet", title);
+ set_cmd = add_set_auto_boolean_cmd (cmd_name, class_obscure,
+ &config->detect, set_doc,
+ set_remote_list);
+ set_cmd->function.sfunc = set_func;
+ show_cmd = add_cmd (cmd_name, class_obscure, show_func, show_doc,
+ show_remote_list);
+ /* set/show remote NAME-packet {auto,on,off} -- legacy */
+ if (legacy)
+ {
+ char *legacy_name;
+ xasprintf (&legacy_name, "%s-packet", name);
+ add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
+ set_remote_list);
+ add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
+ show_remote_list);
+ }
+}
+
+static enum packet_result
+packet_ok (const char *buf, struct packet_config *config)
+{
+ if (buf[0] != '\0')
+ {
+ /* The stub recognized the packet request. Check that the
+ operation succeeded. */
+ switch (config->support)
+ {
+ case PACKET_SUPPORT_UNKNOWN:
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Packet %s (%s) is supported\n",
+ config->name, config->title);
+ config->support = PACKET_ENABLE;
+ break;
+ case PACKET_DISABLE:
+ internal_error ("packet_ok: attempt to use a disabled packet");
+ break;
+ case PACKET_ENABLE:
+ break;
+ }
+ if (buf[0] == 'O' && buf[1] == 'K' && buf[2] == '\0')
+ /* "OK" - definitly OK. */
+ return PACKET_OK;
+ if (buf[0] == 'E'
+ && isxdigit (buf[1]) && isxdigit (buf[2])
+ && buf[3] == '\0')
+ /* "Enn" - definitly an error. */
+ return PACKET_ERROR;
+ /* The packet may or may not be OK. Just assume it is */
+ return PACKET_OK;
+ }
+ else
+ {
+ /* The stub does not support the packet. */
+ switch (config->support)
+ {
+ case PACKET_ENABLE:
+ if (config->detect == CMD_AUTO_BOOLEAN_AUTO)
+ /* If the stub previously indicated that the packet was
+ supported then there is a protocol error.. */
+ error ("Protocol error: %s (%s) conflicting enabled responses.",
+ config->name, config->title);
+ else
+ /* The user set it wrong. */
+ error ("Enabled packet %s (%s) not recognized by stub",
+ config->name, config->title);
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Packet %s (%s) is NOT supported\n",
+ config->name, config->title);
+ config->support = PACKET_DISABLE;
+ break;
+ case PACKET_DISABLE:
+ break;
+ }
+ return PACKET_UNKNOWN;
+ }
+}
+
+/* Should we try the 'P' (set register) request? */
+
+static struct packet_config remote_protocol_P;
+
+static void
+set_remote_protocol_P_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_P);
+}
+
+static void
+show_remote_protocol_P_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_P);
+}
+
+/* Should we try one of the 'Z' requests? */
+
+enum Z_packet_type
+{
+ Z_PACKET_SOFTWARE_BP,
+ Z_PACKET_HARDWARE_BP,
+ Z_PACKET_WRITE_WP,
+ Z_PACKET_READ_WP,
+ Z_PACKET_ACCESS_WP,
+ NR_Z_PACKET_TYPES
+};
+
+static struct packet_config remote_protocol_Z[NR_Z_PACKET_TYPES];
+
+/* FIXME: Instead of having all these boiler plate functions, the
+ command callback should include a context argument. */
+
+static void
+set_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]);
+}
+
+static void
+show_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]);
+}
+
+static void
+set_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]);
+}
+
+static void
+show_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]);
+}
+
+static void
+set_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_WRITE_WP]);
+}
+
+static void
+show_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP]);
+}
-/* 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 void
+set_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_READ_WP]);
+}
+
+static void
+show_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP]);
+}
+
+static void
+set_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_ACCESS_WP]);
+}
+
+static void
+show_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP]);
+}
+
+/* For compatibility with older distributions. Provide a ``set remote
+ Z-packet ...'' command that updates all the Z packet types. */
+
+static enum cmd_auto_boolean remote_Z_packet_detect;
+
+static void
+set_remote_protocol_Z_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ int i;
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ {
+ remote_protocol_Z[i].detect = remote_Z_packet_detect;
+ update_packet_config (&remote_protocol_Z[i]);
+ }
+}
+
+static void
+show_remote_protocol_Z_packet_cmd (char *args, int from_tty)
+{
+ int i;
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ {
+ show_packet_config_cmd (&remote_protocol_Z[i]);
+ }
+}
+
+/* Should we try the 'X' (remote binary download) packet?
-static int remote_register_buf_size = 0;
+ This variable (available to the user via "set remote X-packet")
+ dictates whether downloads are sent in binary (via the 'X' packet).
+ We assume that the stub can, and attempt to do it. This will be
+ cleared if the stub does not understand it. This switch is still
+ needed, though in cases when the packet is supported in the stub,
+ but the connection does not allow it (i.e., 7-bit serial connection
+ only). */
-/* 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;
+static struct packet_config remote_protocol_binary_download;
+
+/* Should we try the 'ThreadInfo' query packet?
+
+ This variable (NOT available to the user: auto-detect only!)
+ determines whether GDB will use the new, simpler "ThreadInfo"
+ query or the older, more complex syntax for thread queries.
+ This is an auto-detect variable (set to true at each connect,
+ and set to false when the target fails to recognize it). */
+
+static int use_threadinfo_query;
+static int use_threadextra_query;
+
+static void
+set_remote_protocol_binary_download_cmd (char *args,
+ int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_binary_download);
+}
+
+static void
+show_remote_protocol_binary_download_cmd (char *args,
+ int from_tty)
+{
+ show_packet_config_cmd (&remote_protocol_binary_download);
+}
+
+
+/* Tokens for use by the asynchronous signal handlers for SIGINT */
+PTR sigint_remote_twice_token;
+PTR sigint_remote_token;
/* 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));
-
+void (*target_resume_hook) (void);
+void (*target_wait_loop_hook) (void);
\f
+
/* These are the threads which we last sent to the remote system.
-1 for all or -2 for not sent yet. */
static int general_thread;
-static int cont_thread;
+static int continue_thread;
/* Call this function as a result of
1) A halt indication (T packet) containing a thread id
*/
static void
-record_currthread (currthread)
- int currthread;
+record_currthread (int currthread)
{
-#if 0 /* target_wait must not modify inferior_pid! */
- inferior_pid = currthread;
-#endif
general_thread = currthread;
-#if 0 /* setting cont_thread has a different meaning
- from having the target report its thread id. */
- cont_thread = currthread;
-#endif
+
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
if (!in_thread_list (currthread))
- add_thread (currthread);
+ {
+ add_thread (currthread);
+#ifdef UI_OUT
+ ui_out_text (uiout, "[New ");
+ ui_out_text (uiout, target_pid_to_str (currthread));
+ ui_out_text (uiout, "]\n");
+#else
+ printf_filtered ("[New %s]\n", target_pid_to_str (currthread));
+#endif
+ }
}
#define MAGIC_NULL_PID 42000
static void
-set_thread (th, gen)
- int th;
- int gen;
+set_thread (int th, int gen)
{
- char buf[PBUFSIZ];
- int state = gen ? general_thread : cont_thread;
+ char *buf = alloca (PBUFSIZ);
+ int state = gen ? general_thread : continue_thread;
if (state == th)
return;
else
sprintf (&buf[2], "%x", th);
putpkt (buf);
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
if (gen)
general_thread = th;
else
- cont_thread = th;
+ continue_thread = th;
}
\f
/* Return nonzero if the thread TH is still alive on the remote system. */
static int
-remote_thread_alive (th)
- int th;
+remote_thread_alive (int tid)
{
- char buf[PBUFSIZ];
+ char buf[16];
- buf[0] = 'T';
- if (th < 0)
- sprintf (&buf[1], "-%08x", -th);
+ if (tid < 0)
+ sprintf (buf, "T-%08x", -tid);
else
- sprintf (&buf[1], "%08x", th);
+ sprintf (buf, "T%08x", tid);
putpkt (buf);
- getpkt (buf, 0);
+ getpkt (buf, sizeof (buf), 0);
return (buf[0] == 'O' && buf[1] == 'K');
}
remote protocol in general. There is a matching unit test module
in libstub. */
-#define BUF_THREAD_ID_SIZE (OPAQUETHREADBYTES*2)
+#define OPAQUETHREADBYTES 8
-/* encode 64 bits in 16 chars of hex */
+/* a 64 bit opaque identifier */
+typedef unsigned char threadref[OPAQUETHREADBYTES];
-static const char hexchars[] = "0123456789abcdef";
+/* WARNING: This threadref data structure comes from the remote O.S., libstub
+ protocol encoding, and remote.c. it is not particularly changable */
-static int
-ishex (ch, val)
- int ch;
- int *val;
-{
- if ((ch >= 'a') && (ch <= 'f'))
- {
- *val = ch - 'a' + 10;
- return 1;
- }
+/* Right now, the internal structure is int. We want it to be bigger.
+ Plan to fix this.
+ */
+
+typedef int gdb_threadref; /* internal GDB thread reference */
+
+/* gdb_ext_thread_info is an internal GDB data structure which is
+ equivalint to the reply of the remote threadinfo packet */
+
+struct gdb_ext_thread_info
+ {
+ threadref threadid; /* External form of thread reference */
+ int active; /* Has state interesting to GDB? , regs, stack */
+ char display[256]; /* Brief state display, name, blocked/syspended */
+ char shortname[32]; /* To be used to name threads */
+ char more_display[256]; /* Long info, statistics, queue depth, whatever */
+ };
+
+/* The volume of remote transfers can be limited by submitting
+ a mask containing bits specifying the desired information.
+ Use a union of these values as the 'selection' parameter to
+ get_thread_info. FIXME: Make these TAG names more thread specific.
+ */
+
+#define TAG_THREADID 1
+#define TAG_EXISTS 2
+#define TAG_DISPLAY 4
+#define TAG_THREADNAME 8
+#define TAG_MOREDISPLAY 16
+
+#define BUF_THREAD_ID_SIZE (OPAQUETHREADBYTES*2)
+
+char *unpack_varlen_hex (char *buff, int *result);
+
+static char *unpack_nibble (char *buf, int *val);
+
+static char *pack_nibble (char *buf, int nibble);
+
+static char *pack_hex_byte (char *pkt, int /*unsigned char */ byte);
+
+static char *unpack_byte (char *buf, int *value);
+
+static char *pack_int (char *buf, int value);
+
+static char *unpack_int (char *buf, int *value);
+
+static char *unpack_string (char *src, char *dest, int length);
+
+static char *pack_threadid (char *pkt, threadref * id);
+
+static char *unpack_threadid (char *inbuf, threadref * id);
+
+void int_to_threadref (threadref * id, int value);
+
+static int threadref_to_int (threadref * ref);
+
+static void copy_threadref (threadref * dest, threadref * src);
+
+static int threadmatch (threadref * dest, threadref * src);
+
+static char *pack_threadinfo_request (char *pkt, int mode, threadref * id);
+
+static int remote_unpack_thread_info_response (char *pkt,
+ threadref * expectedref,
+ struct gdb_ext_thread_info
+ *info);
+
+
+static int remote_get_threadinfo (threadref * threadid, int fieldset, /*TAG mask */
+ struct gdb_ext_thread_info *info);
+
+static int adapt_remote_get_threadinfo (gdb_threadref * ref,
+ int selection,
+ struct gdb_ext_thread_info *info);
+
+static char *pack_threadlist_request (char *pkt, int startflag,
+ int threadcount,
+ threadref * nextthread);
+
+static int parse_threadlist_response (char *pkt,
+ int result_limit,
+ threadref * original_echo,
+ threadref * resultlist, int *doneflag);
+
+static int remote_get_threadlist (int startflag,
+ threadref * nextthread,
+ int result_limit,
+ int *done,
+ int *result_count, threadref * threadlist);
+
+typedef int (*rmt_thread_action) (threadref * ref, void *context);
+
+static int remote_threadlist_iterator (rmt_thread_action stepfunction,
+ void *context, int looplimit);
+
+static int remote_newthread_step (threadref * ref, void *context);
+
+/* encode 64 bits in 16 chars of hex */
+
+static const char hexchars[] = "0123456789abcdef";
+
+static int
+ishex (int ch, int *val)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ {
+ *val = ch - 'a' + 10;
+ return 1;
+ }
if ((ch >= 'A') && (ch <= 'F'))
{
*val = ch - 'A' + 10;
}
static int
-stubhex (ch)
- int ch;
+stubhex (int ch)
{
if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
}
static int
-stub_unpack_int (buff, fieldlength)
- char *buff;
- int fieldlength;
+stub_unpack_int (char *buff, int fieldlength)
{
int nibble;
int retval = 0;
}
char *
-unpack_varlen_hex (buff, result)
- char *buff; /* packet to parse */
- int *result;
+unpack_varlen_hex (char *buff, /* packet to parse */
+ int *result)
{
int nibble;
int retval = 0;
}
static char *
-unpack_nibble (buf, val)
- char *buf;
- int *val;
+unpack_nibble (char *buf, int *val)
{
ishex (*buf++, val);
return buf;
}
static char *
-pack_nibble (buf, nibble)
- char *buf;
- int nibble;
+pack_nibble (char *buf, int nibble)
{
*buf++ = hexchars[(nibble & 0x0f)];
return buf;
}
static char *
-pack_hex_byte (pkt, byte)
- char *pkt;
- unsigned char byte;
+pack_hex_byte (char *pkt, int byte)
{
*pkt++ = hexchars[(byte >> 4) & 0xf];
*pkt++ = hexchars[(byte & 0xf)];
}
static char *
-unpack_byte (buf, value)
- char *buf;
- int *value;
+unpack_byte (char *buf, int *value)
{
*value = stub_unpack_int (buf, 2);
return buf + 2;
}
static char *
-pack_int (buf, value)
- char *buf;
- int value;
+pack_int (char *buf, int value)
{
buf = pack_hex_byte (buf, (value >> 24) & 0xff);
buf = pack_hex_byte (buf, (value >> 16) & 0xff);
}
static char *
-unpack_int (buf, value)
- char *buf;
- int *value;
+unpack_int (char *buf, int *value)
{
*value = stub_unpack_int (buf, 8);
return buf + 8;
}
-#if 0 /* currently unused, uncomment when needed */
-static char *pack_string PARAMS ((char *pkt, char *string));
+#if 0 /* currently unused, uncomment when needed */
+static char *pack_string (char *pkt, char *string);
static char *
-pack_string (pkt, string)
- char *pkt;
- char *string;
+pack_string (char *pkt, char *string)
{
char ch;
int len;
#endif /* 0 (unused) */
static char *
-unpack_string (src, dest, length)
- char *src;
- char *dest;
- int length;
+unpack_string (char *src, char *dest, int length)
{
while (length--)
*dest++ = *src++;
}
static char *
-pack_threadid (pkt, id)
- char *pkt;
- threadref *id;
+pack_threadid (char *pkt, threadref *id)
{
char *limit;
unsigned char *altid;
static char *
-unpack_threadid (inbuf, id)
- char *inbuf;
- threadref *id;
+unpack_threadid (char *inbuf, threadref *id)
{
char *altref;
char *limit = inbuf + BUF_THREAD_ID_SIZE;
function. */
void
-int_to_threadref (id, value)
- threadref *id;
- int value;
+int_to_threadref (threadref *id, int value)
{
unsigned char *scan;
}
static int
-threadref_to_int (ref)
- threadref *ref;
+threadref_to_int (threadref *ref)
{
int i, value = 0;
unsigned char *scan;
}
static void
-copy_threadref (dest, src)
- threadref *dest;
- threadref *src;
+copy_threadref (threadref *dest, threadref *src)
{
int i;
unsigned char *csrc, *cdest;
}
static int
-threadmatch (dest, src)
- threadref *dest;
- threadref *src;
+threadmatch (threadref *dest, threadref *src)
{
/* things are broken right now, so just assume we got a match */
#if 0
}
/*
- threadid:1, # always request threadid
- context_exists:2,
- display:4,
- unique_name:8,
- more_display:16
-*/
+ threadid:1, # always request threadid
+ context_exists:2,
+ display:4,
+ unique_name:8,
+ more_display:16
+ */
/* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */
static char *
-pack_threadinfo_request (pkt, mode, id)
- char *pkt;
- int mode;
- threadref *id;
+pack_threadinfo_request (char *pkt, int mode, threadref *id)
{
*pkt++ = 'q'; /* Info Query */
*pkt++ = 'P'; /* process or thread info */
/* Tagging the fields allows us to request specific fields and to
add more fields as time goes by */
-#define TAG_THREADID 1 /* Echo the thread identifier */
-#define TAG_EXISTS 2 /* Is this process defined enough to
- fetch registers and its stack */
-#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */
-#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */
-#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about
- the process*/
+#define TAG_THREADID 1 /* Echo the thread identifier */
+#define TAG_EXISTS 2 /* Is this process defined enough to
+ fetch registers and its stack */
+#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */
+#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */
+#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about
+ the process */
static int
-remote_unpack_thread_info_response (pkt, expectedref, info)
- char *pkt;
- threadref *expectedref;
- struct gdb_ext_thread_info *info;
+remote_unpack_thread_info_response (char *pkt, threadref *expectedref,
+ struct gdb_ext_thread_info *info)
{
int mask, length;
unsigned int tag;
threadref ref;
- char *limit = pkt + PBUFSIZ; /* plausable parsing limit */
+ char *limit = pkt + PBUFSIZ; /* plausable parsing limit */
int retval = 1;
/* info->threadid = 0; FIXME: implement zero_threadref */
/* Loop on tagged fields , try to bail if somthing goes wrong */
- while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
+ while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
{
pkt = unpack_int (pkt, &tag); /* tag */
pkt = unpack_byte (pkt, &length); /* length */
}
static int
-remote_get_threadinfo (threadid, fieldset, info)
- threadref *threadid;
- int fieldset; /* TAG mask */
- struct gdb_ext_thread_info *info;
+remote_get_threadinfo (threadref *threadid, int fieldset, /* TAG mask */
+ struct gdb_ext_thread_info *info)
{
int result;
- char threadinfo_pkt[PBUFSIZ];
+ char *threadinfo_pkt = alloca (PBUFSIZ);
pack_threadinfo_request (threadinfo_pkt, fieldset, threadid);
putpkt (threadinfo_pkt);
- getpkt (threadinfo_pkt, 0);
+ getpkt (threadinfo_pkt, PBUFSIZ, 0);
result = remote_unpack_thread_info_response (threadinfo_pkt + 2, threadid,
info);
return result;
representation of a threadid. */
static int
-adapt_remote_get_threadinfo (ref, selection, info)
- gdb_threadref *ref;
- int selection;
- struct gdb_ext_thread_info *info;
+adapt_remote_get_threadinfo (gdb_threadref *ref, int selection,
+ struct gdb_ext_thread_info *info)
{
threadref lclref;
/* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */
static char *
-pack_threadlist_request (pkt, startflag, threadcount, nextthread)
- char *pkt;
- int startflag;
- int threadcount;
- threadref *nextthread;
+pack_threadlist_request (char *pkt, int startflag, int threadcount,
+ threadref *nextthread)
{
*pkt++ = 'q'; /* info query packet */
*pkt++ = 'L'; /* Process LIST or threadLIST request */
/* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */
static int
-parse_threadlist_response (pkt, result_limit, original_echo, resultlist,
- doneflag)
- char *pkt;
- int result_limit;
- threadref *original_echo;
- threadref *resultlist;
- int *doneflag;
+parse_threadlist_response (char *pkt, int result_limit,
+ threadref *original_echo, threadref *resultlist,
+ int *doneflag)
{
char *limit;
int count, resultcount, done;
resultcount = 0;
/* Assume the 'q' and 'M chars have been stripped. */
- limit = pkt + (PBUFSIZ - BUF_THREAD_ID_SIZE); /* done parse past here */
+ limit = pkt + (PBUFSIZ - BUF_THREAD_ID_SIZE); /* done parse past here */
pkt = unpack_byte (pkt, &count); /* count field */
pkt = unpack_nibble (pkt, &done);
/* The first threadid is the argument threadid. */
}
static int
-remote_get_threadlist (startflag, nextthread, result_limit,
- done, result_count, threadlist)
- int startflag;
- threadref *nextthread;
- int result_limit;
- int *done;
- int *result_count;
- threadref *threadlist;
-
+remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
+ int *done, int *result_count, threadref *threadlist)
{
static threadref echo_nextthread;
- char threadlist_packet[PBUFSIZ];
- char t_response[PBUFSIZ];
+ char *threadlist_packet = alloca (PBUFSIZ);
+ char *t_response = alloca (PBUFSIZ);
int result = 1;
/* Trancate result limit to be smaller than the packet size */
pack_threadlist_request (threadlist_packet,
startflag, result_limit, nextthread);
putpkt (threadlist_packet);
- getpkt (t_response, 0);
+ getpkt (t_response, PBUFSIZ, 0);
*result_count =
parse_threadlist_response (t_response + 2, result_limit, &echo_nextthread,
#define MAXTHREADLISTRESULTS 32
static int
-remote_threadlist_iterator (stepfunction, context, looplimit)
- rmt_thread_action stepfunction;
- void *context;
- int looplimit;
+remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
+ int looplimit)
{
int done, i, result_count;
int startflag = 1;
}
static int
-remote_newthread_step (ref, context)
- threadref *ref;
- void *context;
+remote_newthread_step (threadref *ref, void *context)
{
int pid;
#define CRAZY_MAX_THREADS 1000
static int
-remote_current_thread (oldpid)
- int oldpid;
+remote_current_thread (int oldpid)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
putpkt ("qC");
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
if (buf[0] == 'Q' && buf[1] == 'C')
return strtol (&buf[2], NULL, 16);
else
return oldpid;
}
-int
-remote_find_new_threads ()
-{
- int ret;
+/* Find new threads for info threads command.
+ * Original version, using John Metzler's thread protocol.
+ */
- ret = remote_threadlist_iterator (remote_newthread_step, 0,
- CRAZY_MAX_THREADS);
+static void
+remote_find_new_threads (void)
+{
+ remote_threadlist_iterator (remote_newthread_step, 0,
+ CRAZY_MAX_THREADS);
if (inferior_pid == MAGIC_NULL_PID) /* ack ack ack */
inferior_pid = remote_current_thread (inferior_pid);
- return ret;
}
-/* Initialize the thread vector which is used by threads.c */
-/* The thread stub is a package, it has an initializer */
+/*
+ * Find all threads for info threads command.
+ * Uses new thread protocol contributed by Cisco.
+ * Falls back and attempts to use the older method (above)
+ * if the target doesn't respond to the new method.
+ */
static void
-init_remote_threads ()
+remote_threads_info (void)
{
- remote_thread_vec.find_new_threads = remote_find_new_threads;
- remote_thread_vec.get_thread_info = adapt_remote_get_threadinfo;
+ char *buf = alloca (PBUFSIZ);
+ char *bufp;
+ int tid;
+
+ if (remote_desc == 0) /* paranoia */
+ error ("Command can only be used when connected to the remote target.");
+
+ if (use_threadinfo_query)
+ {
+ putpkt ("qfThreadInfo");
+ bufp = buf;
+ getpkt (bufp, PBUFSIZ, 0);
+ if (bufp[0] != '\0') /* q packet recognized */
+ {
+ while (*bufp++ == 'm') /* reply contains one or more TID */
+ {
+ do
+ {
+ tid = strtol (bufp, &bufp, 16);
+ if (tid != 0 && !in_thread_list (tid))
+ add_thread (tid);
+ }
+ while (*bufp++ == ','); /* comma-separated list */
+ putpkt ("qsThreadInfo");
+ bufp = buf;
+ getpkt (bufp, PBUFSIZ, 0);
+ }
+ return; /* done */
+ }
+ }
+
+ /* Else fall back to old method based on jmetzler protocol. */
+ use_threadinfo_query = 0;
+ remote_find_new_threads ();
+ return;
+}
+
+/*
+ * Collect a descriptive string about the given thread.
+ * The target may say anything it wants to about the thread
+ * (typically info about its blocked / runnable state, name, etc.).
+ * This string will appear in the info threads display.
+ *
+ * Optional: targets are not required to implement this function.
+ */
+
+static char *
+remote_threads_extra_info (struct thread_info *tp)
+{
+ int result;
+ int set;
+ threadref id;
+ struct gdb_ext_thread_info threadinfo;
+ static char display_buf[100]; /* arbitrary... */
+ char *bufp = alloca (PBUFSIZ);
+ int n = 0; /* position in display_buf */
+
+ if (remote_desc == 0) /* paranoia */
+ internal_error ("remote_threads_extra_info");
+
+ if (use_threadextra_query)
+ {
+ sprintf (bufp, "qThreadExtraInfo,%x", tp->pid);
+ putpkt (bufp);
+ getpkt (bufp, PBUFSIZ, 0);
+ if (bufp[0] != 0)
+ {
+ char *p;
+
+ for (p = display_buf;
+ p < display_buf + sizeof(display_buf) - 1 &&
+ bufp[0] != 0 &&
+ bufp[1] != 0;
+ p++, bufp+=2)
+ {
+ *p = fromhex (bufp[0]) * 16 + fromhex (bufp[1]);
+ }
+ *p = 0;
+ return display_buf;
+ }
+ }
+
+ /* If the above query fails, fall back to the old method. */
+ use_threadextra_query = 0;
+ set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
+ | TAG_MOREDISPLAY | TAG_DISPLAY;
+ int_to_threadref (&id, tp->pid);
+ if (remote_get_threadinfo (&id, set, &threadinfo))
+ if (threadinfo.active)
+ {
+ if (*threadinfo.shortname)
+ n += sprintf(&display_buf[0], " Name: %s,", threadinfo.shortname);
+ if (*threadinfo.display)
+ n += sprintf(&display_buf[n], " State: %s,", threadinfo.display);
+ if (*threadinfo.more_display)
+ n += sprintf(&display_buf[n], " Priority: %s",
+ threadinfo.more_display);
+
+ if (n > 0)
+ {
+ /* for purely cosmetic reasons, clear up trailing commas */
+ if (',' == display_buf[n-1])
+ display_buf[n-1] = ' ';
+ return display_buf;
+ }
+ }
+ return NULL;
}
\f
+
/* Restart the remote side; this is an extended protocol operation. */
static void
-extended_remote_restart ()
+extended_remote_restart (void)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
/* Send the restart command; for reasons I don't understand the
remote side really expects a number after the "R". */
/* Now query for status so this looks just like we restarted
gdbserver from scratch. */
putpkt ("?");
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
}
\f
/* Clean up connection to a remote debugger. */
/* ARGSUSED */
static void
-remote_close (quitting)
- int quitting;
+remote_close (int quitting)
{
if (remote_desc)
SERIAL_CLOSE (remote_desc);
/* Query the remote side for the text, data and bss offsets. */
static void
-get_offsets ()
+get_offsets (void)
{
- char buf[PBUFSIZ], *ptr;
+ char *buf = alloca (PBUFSIZ);
+ char *ptr;
int lose;
CORE_ADDR text_addr, data_addr, bss_addr;
struct section_offsets *offs;
putpkt ("qOffsets");
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
if (buf[0] == '\000')
return; /* Return silently. Stub doesn't support
if (symfile_objfile == NULL)
return;
- offs = (struct section_offsets *) alloca (sizeof (struct section_offsets)
- + symfile_objfile->num_sections
- * sizeof (offs->offsets));
- memcpy (offs, symfile_objfile->section_offsets,
- sizeof (struct section_offsets)
- + symfile_objfile->num_sections
- * sizeof (offs->offsets));
+ offs = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
+ memcpy (offs, symfile_objfile->section_offsets, SIZEOF_SECTION_OFFSETS);
- ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
+ offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_addr;
/* This is a temporary kludge to force data and bss to use the same offsets
because that's what nlmconv does now. The real solution requires changes
to the stub and remote.c that I don't have time to do right now. */
- ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
- ANOFFSET (offs, SECT_OFF_BSS) = data_addr;
+ offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr;
+ offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr;
objfile_relocate (symfile_objfile, offs);
}
+/*
+ * Cisco version of section offsets:
+ *
+ * Instead of having GDB query the target for the section offsets,
+ * Cisco lets the target volunteer the information! It's also in
+ * a different format, so here are the functions that will decode
+ * a section offset packet from a Cisco target.
+ */
+
+/*
+ * Function: remote_cisco_section_offsets
+ *
+ * Returns: zero for success, non-zero for failure
+ */
+
+static int
+remote_cisco_section_offsets (bfd_vma text_addr,
+ bfd_vma data_addr,
+ bfd_vma bss_addr,
+ bfd_signed_vma *text_offs,
+ bfd_signed_vma *data_offs,
+ bfd_signed_vma *bss_offs)
+{
+ bfd_vma text_base, data_base, bss_base;
+ struct minimal_symbol *start;
+ asection *sect;
+ bfd *abfd;
+ int len;
+ char *p;
+
+ if (symfile_objfile == NULL)
+ return -1; /* no can do nothin' */
+
+ start = lookup_minimal_symbol ("_start", NULL, NULL);
+ if (start == NULL)
+ return -1; /* Can't find "_start" symbol */
+
+ data_base = bss_base = 0;
+ text_base = SYMBOL_VALUE_ADDRESS (start);
+
+ abfd = symfile_objfile->obfd;
+ for (sect = abfd->sections;
+ sect != 0;
+ sect = sect->next)
+ {
+ p = (unsigned char *) bfd_get_section_name (abfd, sect);
+ len = strlen (p);
+ if (strcmp (p + len - 4, "data") == 0) /* ends in "data" */
+ if (data_base == 0 ||
+ data_base > bfd_get_section_vma (abfd, sect))
+ data_base = bfd_get_section_vma (abfd, sect);
+ if (strcmp (p + len - 3, "bss") == 0) /* ends in "bss" */
+ if (bss_base == 0 ||
+ bss_base > bfd_get_section_vma (abfd, sect))
+ bss_base = bfd_get_section_vma (abfd, sect);
+ }
+ *text_offs = text_addr - text_base;
+ *data_offs = data_addr - data_base;
+ *bss_offs = bss_addr - bss_base;
+ if (remote_debug)
+ {
+ char tmp[128];
+
+ sprintf (tmp, "VMA: text = 0x");
+ sprintf_vma (tmp + strlen (tmp), text_addr);
+ sprintf (tmp + strlen (tmp), " data = 0x");
+ sprintf_vma (tmp + strlen (tmp), data_addr);
+ sprintf (tmp + strlen (tmp), " bss = 0x");
+ sprintf_vma (tmp + strlen (tmp), bss_addr);
+ fprintf_filtered (gdb_stdlog, tmp);
+ fprintf_filtered (gdb_stdlog,
+ "Reloc offset: text = 0x%s data = 0x%s bss = 0x%s\n",
+ paddr_nz (*text_offs),
+ paddr_nz (*data_offs),
+ paddr_nz (*bss_offs));
+ }
+
+ return 0;
+}
+
+/*
+ * Function: remote_cisco_objfile_relocate
+ *
+ * Relocate the symbol file for a remote target.
+ */
+
+void
+remote_cisco_objfile_relocate (bfd_signed_vma text_off, bfd_signed_vma data_off,
+ bfd_signed_vma bss_off)
+{
+ struct section_offsets *offs;
+
+ if (text_off != 0 || data_off != 0 || bss_off != 0)
+ {
+ /* 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. */
+
+ offs = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
+ memcpy (offs, symfile_objfile->section_offsets, SIZEOF_SECTION_OFFSETS);
+
+ offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_off;
+ offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_off;
+ offs->offsets[SECT_OFF_BSS (symfile_objfile)] = bss_off;
+
+ /* First call the standard objfile_relocate. */
+ objfile_relocate (symfile_objfile, offs);
+
+ /* Now we need to fix up the section entries already attached to
+ the exec target. These entries will control memory transfers
+ from the exec file. */
+
+ exec_set_section_offsets (text_off, data_off, bss_off);
+ }
+}
+
/* Stub for catch_errors. */
static int
-remote_start_remote (dummy)
- char *dummy;
+remote_start_remote_dummy (void *dummy)
{
- immediate_quit = 1; /* Allow user to interrupt it */
+ start_remote (); /* Initialize gdb process mechanisms */
+ return 1;
+}
+
+static int
+remote_start_remote (PTR dummy)
+{
+ immediate_quit++; /* Allow user to interrupt it */
/* Ack any packet which the remote side has already sent. */
SERIAL_WRITE (remote_desc, "+", 1);
get_offsets (); /* Get text, data & bss offsets */
putpkt ("?"); /* initiate a query from remote machine */
- immediate_quit = 0;
+ immediate_quit--;
- start_remote (); /* Initialize gdb process mechanisms */
- return 1;
+ return remote_start_remote_dummy (dummy);
}
/* 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 (char *name, int from_tty)
{
remote_open_1 (name, from_tty, &remote_ops, 0);
}
+/* Just like remote_open, but with asynchronous support. */
+static void
+remote_async_open (char *name, int from_tty)
+{
+ remote_async_open_1 (name, from_tty, &remote_async_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;
+extended_remote_open (char *name, int from_tty)
{
- remote_open_1 (name, from_tty, &extended_remote_ops, 1/*extended_p*/);
+ remote_open_1 (name, from_tty, &extended_remote_ops, 1 /*extended_p */ );
+}
+
+/* Just like extended_remote_open, but with asynchronous support. */
+static void
+extended_remote_async_open (char *name, int from_tty)
+{
+ remote_async_open_1 (name, from_tty, &extended_async_remote_ops, 1 /*extended_p */ );
}
/* Generic code for opening a connection to a remote target. */
-static DCACHE *remote_dcache;
+static void
+init_all_packet_configs (void)
+{
+ int i;
+ update_packet_config (&remote_protocol_P);
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ update_packet_config (&remote_protocol_Z[i]);
+ /* Force remote_write_bytes to check whether target supports binary
+ downloading. */
+ update_packet_config (&remote_protocol_binary_download);
+}
static void
-remote_open_1 (name, from_tty, target, extended_p)
- char *name;
- int from_tty;
- struct target_ops *target;
- int extended_p;
+remote_open_1 (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\n\
-serial device is attached to the remote system (e.g. /dev/ttya).");
+serial device is attached to the remote system\n\
+(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.).");
+
+ /* See FIXME above */
+ wait_forever_enabled_p = 1;
target_preopen (from_tty);
unpush_target (target);
- remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
-
remote_desc = SERIAL_OPEN (name);
if (!remote_desc)
perror_with_name (name);
}
}
+ SERIAL_RAW (remote_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (remote_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (target); /* Switch to using remote target now */
+
+ init_all_packet_configs ();
+
+ general_thread = -2;
+ continue_thread = -2;
+
+ /* Probe for ability to use "ThreadInfo" query, as required. */
+ use_threadinfo_query = 1;
+ use_threadextra_query = 1;
+
+ /* 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 = MAGIC_NULL_PID;
+ /* 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, NULL,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ {
+ pop_target ();
+ return;
+ }
+
+ if (extended_p)
+ {
+ /* tell the remote that we're using the extended protocol. */
+ char *buf = alloca (PBUFSIZ);
+ putpkt ("!");
+ getpkt (buf, PBUFSIZ, 0);
+ }
+}
+
+/* Just like remote_open but with asynchronous support. */
+static void
+remote_async_open_1 (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\n\
+serial device is attached to the remote system\n\
+(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.).");
+
+ target_preopen (from_tty);
+
+ unpush_target (target);
+
+ remote_desc = SERIAL_OPEN (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
+ }
SERIAL_RAW (remote_desc);
puts_filtered (name);
puts_filtered ("\n");
}
- push_target (target); /* Switch to using remote target now */
- /* The target vector does not have the thread functions in it yet,
- so we use this function to call back into the thread module and
- register the thread vector and its contained functions. */
- bind_target_thread_vector (&remote_thread_vec);
+ 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;
+ init_all_packet_configs ();
general_thread = -2;
- cont_thread = -2;
+ continue_thread = -2;
+
+ /* Probe for ability to use "ThreadInfo" query, as required. */
+ use_threadinfo_query = 1;
+ use_threadextra_query = 1;
/* Without this, some commands which require an active target (such
as kill) won't work. This variable serves (at least) double duty
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 = MAGIC_NULL_PID;
+
+ /* With this target we start out by owning the terminal. */
+ remote_async_terminal_ours_p = 1;
+
+ /* FIXME: cagney/1999-09-23: During the initial connection it is
+ assumed that the target is already ready and able to respond to
+ requests. Unfortunately remote_start_remote() eventually calls
+ wait_for_inferior() with no timeout. wait_forever_enabled_p gets
+ around this. Eventually a mechanism that allows
+ wait_for_inferior() to expect/get timeouts will be
+ implemented. */
+ wait_forever_enabled_p = 0;
+
/* 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",
+ if (!catch_errors (remote_start_remote, NULL,
+ "Couldn't establish connection to remote target\n",
RETURN_MASK_ALL))
{
pop_target ();
+ wait_forever_enabled_p = 1;
return;
}
+ wait_forever_enabled_p = 1;
+
if (extended_p)
{
/* tell the remote that we're using the extended protocol. */
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
putpkt ("!");
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
}
}
die when it hits one. */
static void
-remote_detach (args, from_tty)
- char *args;
- int from_tty;
+remote_detach (char *args, int from_tty)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
if (args)
error ("Argument given to \"detach\" when remotely debugging.");
/* Tell the remote target to detach. */
strcpy (buf, "D");
- remote_send (buf);
+ remote_send (buf, PBUFSIZ);
- pop_target ();
+ target_mourn_inferior ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+
+}
+
+/* Same as remote_detach, but with async support. */
+static void
+remote_async_detach (char *args, int from_tty)
+{
+ char *buf = alloca (PBUFSIZ);
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ /* Tell the remote target to detach. */
+ strcpy (buf, "D");
+ remote_send (buf, PBUFSIZ);
+
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ SERIAL_ASYNC (remote_desc, NULL, 0);
+
+ target_mourn_inferior ();
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
}
/* Convert hex digit A to a number. */
int
-fromhex (a)
- int a;
+fromhex (int a)
{
if (a >= '0' && a <= '9')
return a - '0';
return a - 'a' + 10;
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
- else
+ else
error ("Reply contains invalid hex digit %d", a);
}
/* Convert number NIB to a hex digit. */
static int
-tohex (nib)
- int nib;
+tohex (int nib)
{
if (nib < 10)
- return '0'+nib;
+ return '0' + nib;
else
- return 'a'+nib-10;
+ return 'a' + nib - 10;
}
\f
/* Tell the remote machine to resume. */
static int last_sent_step;
static void
-remote_resume (pid, step, siggnal)
- int pid, step;
- enum target_signal siggnal;
+remote_resume (int pid, int step, enum target_signal siggnal)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
if (pid == -1)
set_thread (0, 0); /* run any thread */
else
set_thread (pid, 0); /* run this thread */
- dcache_flush (remote_dcache);
-
last_sent_signal = siggnal;
last_sent_step = step;
if (siggnal != TARGET_SIGNAL_0)
{
buf[0] = step ? 'S' : 'C';
- buf[1] = tohex (((int)siggnal >> 4) & 0xf);
- buf[2] = tohex ((int)siggnal & 0xf);
+ buf[1] = tohex (((int) siggnal >> 4) & 0xf);
+ buf[2] = tohex ((int) siggnal & 0xf);
buf[3] = '\0';
}
else
- strcpy (buf, step ? "s": "c");
+ strcpy (buf, step ? "s" : "c");
+
+ putpkt (buf);
+}
+
+/* Same as remote_resume, but with async support. */
+static void
+remote_async_resume (int pid, int step, enum target_signal siggnal)
+{
+ char *buf = alloca (PBUFSIZ);
+
+ if (pid == -1)
+ set_thread (0, 0); /* run any thread */
+ else
+ set_thread (pid, 0); /* run this thread */
+
+ 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");
+
+ /* We are about to start executing the inferior, let's register it
+ with the event loop. NOTE: this is the one place where all the
+ execution commands end up. We could alternatively do this in each
+ of the execution commands in infcmd.c.*/
+ /* FIXME: ezannoni 1999-09-28: We may need to move this out of here
+ into infcmd.c in order to allow inferior function calls to work
+ NOT asynchronously. */
+ if (event_loop_p && target_can_async_p ())
+ target_async (inferior_event_handler, 0);
+ /* Tell the world that the target is now executing. */
+ /* FIXME: cagney/1999-09-23: Is it the targets responsibility to set
+ this? Instead, should the client of target just assume (for
+ async targets) that the target is going to start executing? Is
+ this information already found in the continuation block? */
+ if (target_is_async_p ())
+ target_executing = 1;
putpkt (buf);
}
\f
+
+/* Set up the signal handler for SIGINT, while the target is
+ executing, ovewriting the 'regular' SIGINT signal handler. */
+static void
+initialize_sigint_signal_handler (void)
+{
+ sigint_remote_token =
+ create_async_signal_handler (async_remote_interrupt, NULL);
+ signal (SIGINT, handle_remote_sigint);
+}
+
+/* Signal handler for SIGINT, while the target is executing. */
+static void
+handle_remote_sigint (int sig)
+{
+ signal (sig, handle_remote_sigint_twice);
+ sigint_remote_twice_token =
+ create_async_signal_handler (async_remote_interrupt_twice, NULL);
+ mark_async_signal_handler_wrapper (sigint_remote_token);
+}
+
+/* Signal handler for SIGINT, installed after SIGINT has already been
+ sent once. It will take effect the second time that the user sends
+ a ^C. */
+static void
+handle_remote_sigint_twice (int sig)
+{
+ signal (sig, handle_sigint);
+ sigint_remote_twice_token =
+ create_async_signal_handler (inferior_event_handler_wrapper, NULL);
+ mark_async_signal_handler_wrapper (sigint_remote_twice_token);
+}
+
+/* Perform the real interruption of the target execution, in response
+ to a ^C. */
+static void
+async_remote_interrupt (gdb_client_data arg)
+{
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+ target_stop ();
+}
+
+/* Perform interrupt, if the first attempt did not succeed. Just give
+ up on the target alltogether. */
+void
+async_remote_interrupt_twice (gdb_client_data arg)
+{
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n");
+ /* Do something only if the target was not killed by the previous
+ cntl-C. */
+ if (target_executing)
+ {
+ interrupt_query ();
+ signal (SIGINT, handle_remote_sigint);
+ }
+}
+
+/* Reinstall the usual SIGINT handlers, after the target has
+ stopped. */
+static void
+cleanup_sigint_signal_handler (void *dummy)
+{
+ signal (SIGINT, handle_sigint);
+ if (sigint_remote_twice_token)
+ delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_twice_token);
+ if (sigint_remote_token)
+ delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_token);
+}
+
/* Send ^C to target to halt it. Target will respond, and send us a
packet. */
+static void (*ofunc) (int);
+
+/* The command line interface's stop routine. This function is installed
+ as a signal handler for SIGINT. The first time a user requests a
+ stop, we call remote_stop to send a break or ^C. If there is no
+ response from the target (it didn't stop when the user requested it),
+ we ask the user if he'd like to detach from the target. */
+static void
+remote_interrupt (int signo)
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, remote_interrupt_twice);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+ target_stop ();
+}
+
+/* The user typed ^C twice. */
+
+static void
+remote_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+ interrupt_query ();
+ signal (signo, remote_interrupt);
+}
+
+/* This is the generic stop called via the target vector. When a target
+ interrupt is requested, either by the command line or the GUI, we
+ will eventually end up here. */
+static void
+remote_stop (void)
+{
+ /* Send a break or a ^C, depending on user preference. */
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
+
+ if (remote_break)
+ SERIAL_SEND_BREAK (remote_desc);
+ else
+ SERIAL_WRITE (remote_desc, "\003", 1);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ return_to_top_level (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* Enable/disable target terminal ownership. Most targets can use
+ terminal groups to control terminal ownership. Remote targets are
+ different in that explicit transfer of ownership to/from GDB/target
+ is required. */
+
+static void
+remote_async_terminal_inferior (void)
+{
+ /* FIXME: cagney/1999-09-27: Shouldn't need to test for
+ sync_execution here. This function should only be called when
+ GDB is resuming the inferior in the forground. A background
+ resume (``run&'') should leave GDB in control of the terminal and
+ consequently should not call this code. */
+ if (!sync_execution)
+ return;
+ /* FIXME: cagney/1999-09-27: Closely related to the above. Make
+ calls target_terminal_*() idenpotent. The event-loop GDB talking
+ to an asynchronous target with a synchronous command calls this
+ function from both event-top.c and infrun.c/infcmd.c. Once GDB
+ stops trying to transfer the terminal to the target when it
+ shouldn't this guard can go away. */
+ if (!remote_async_terminal_ours_p)
+ return;
+ delete_file_handler (input_fd);
+ remote_async_terminal_ours_p = 0;
+ initialize_sigint_signal_handler ();
+ /* NOTE: At this point we could also register our selves as the
+ recipient of all input. Any characters typed could then be
+ passed on down to the target. */
+}
+
+static void
+remote_async_terminal_ours (void)
+{
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (!sync_execution)
+ return;
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (remote_async_terminal_ours_p)
+ return;
+ cleanup_sigint_signal_handler (NULL);
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ remote_async_terminal_ours_p = 1;
+}
+
+/* If nonzero, ignore the next kill. */
+
+int kill_kludge;
+
+void
+remote_console_output (char *msg)
+{
+ char *p;
+
+ for (p = msg; p[0] && p[1]; p += 2)
+ {
+ char tb[2];
+ char c = fromhex (p[0]) * 16 + fromhex (p[1]);
+ tb[0] = c;
+ tb[1] = 0;
+ fputs_unfiltered (tb, gdb_stdtarg);
+ }
+ gdb_flush (gdb_stdtarg);
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would.
+ Returns "pid", which in the case of a multi-threaded
+ remote OS, is the thread-id. */
+
+static int
+remote_wait (int pid, struct target_waitstatus *status)
+{
+ unsigned char *buf = alloca (PBUFSIZ);
+ int thread_num = -1;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ while (1)
+ {
+ unsigned char *p;
+
+ ofunc = signal (SIGINT, remote_interrupt);
+ getpkt (buf, PBUFSIZ, 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 */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ long regno;
+ char regs[MAX_REGISTER_RAW_SIZE];
+
+ /* Expedited reply, containing Signal, {regno, reg} repeat */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
+ p = &buf[3]; /* after Txx */
+
+ while (*p)
+ {
+ unsigned char *p1;
+ char *p_temp;
+
+ /* Read the register number */
+ regno = strtol ((const char *) p, &p_temp, 16);
+ p1 = (unsigned char *) p_temp;
+
+ if (p1 == p) /* No register number present here */
+ {
+ p1 = (unsigned char *) strchr ((const char *) p, ':');
+ if (p1 == NULL)
+ warning ("Malformed packet(a) (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+ if (strncmp ((const char *) p, "thread", p1 - p) == 0)
+ {
+ p_temp = unpack_varlen_hex (++p1, &thread_num);
+ record_currthread (thread_num);
+ p = (unsigned char *) p_temp;
+ }
+ }
+ else
+ {
+ p = p1;
-static void (*ofunc) PARAMS ((int));
+ if (*p++ != ':')
+ warning ("Malformed packet(b) (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
-static void
-remote_interrupt (signo)
- int signo;
-{
- remote_stop ();
- signal (signo, remote_interrupt);
-}
-
-static void
-remote_stop ()
-{
- if (!interrupted_already)
- {
- /* Send a break or a ^C, depending on user preference. */
- interrupted_already = 1;
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %ld: %s\n\
+Packet: '%s'\n",
+ regno, p, buf);
- if (remote_debug)
- printf_unfiltered ("remote_stop called\n");
+ 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 (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;
- }
-}
+ if (*p++ != ';')
+ {
+ warning ("Remote register badly formatted: %s", buf);
+ warning (" here: %s", p);
+ }
+ }
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
-/* Ask the user what to do when an interrupt is received. */
+ if (buf[3] == 'p')
+ {
+ /* Export Cisco kernel mode as a convenience variable
+ (so that it can be used in the GDB prompt if desired). */
+
+ if (cisco_kernel_mode == 1)
+ set_internalvar (lookup_internalvar ("cisco_kernel_mode"),
+ value_from_string ("PDEBUG-"));
+ cisco_kernel_mode = 0;
+ thread_num = strtol ((const char *) &buf[4], NULL, 16);
+ record_currthread (thread_num);
+ }
+ else if (buf[3] == 'k')
+ {
+ /* Export Cisco kernel mode as a convenience variable
+ (so that it can be used in the GDB prompt if desired). */
-static void
-interrupt_query ()
-{
- target_terminal_ours ();
+ if (cisco_kernel_mode == 1)
+ set_internalvar (lookup_internalvar ("cisco_kernel_mode"),
+ value_from_string ("KDEBUG-"));
+ cisco_kernel_mode = 1;
+ }
+ goto got_status;
+ case 'N': /* Cisco special: status and offsets */
+ {
+ bfd_vma text_addr, data_addr, bss_addr;
+ bfd_signed_vma text_off, data_off, bss_off;
+ unsigned char *p1;
- if (query ("Interrupted while waiting for the program.\n\
-Give up (and stop debugging it)? "))
- {
- target_mourn_inferior ();
- return_to_top_level (RETURN_QUIT);
- }
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- target_terminal_inferior ();
-}
+ if (symfile_objfile == NULL)
+ {
+ warning ("Relocation packet received with no symbol file. \
+Packet Dropped");
+ goto got_status;
+ }
-/* If nonzero, ignore the next kill. */
+ /* Relocate object file. Buffer format is NAATT;DD;BB
+ * where AA is the signal number, TT is the new text
+ * address, DD * is the new data address, and BB is the
+ * new bss address. */
+
+ p = &buf[3];
+ text_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ data_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ bss_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p)
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+
+ if (remote_cisco_section_offsets (text_addr, data_addr, bss_addr,
+ &text_off, &data_off, &bss_off)
+ == 0)
+ if (text_off != 0 || data_off != 0 || bss_off != 0)
+ remote_cisco_objfile_relocate (text_off, data_off, bss_off);
-int kill_kludge;
+ 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]);
+ 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;
-void
-remote_console_output (msg)
- char *msg;
-{
- char *p;
+ goto got_status;
+ case 'O': /* Console output */
+ 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 ();
- for (p = msg; *p; p +=2)
+ strcpy ((char *) buf, last_sent_step ? "s" : "c");
+ putpkt ((char *) buf);
+ continue;
+ }
+ /* else fallthrough */
+ default:
+ warning ("Invalid remote reply: %s", buf);
+ continue;
+ }
+ }
+got_status:
+ if (thread_num != -1)
{
- 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);
+ return thread_num;
}
+ return inferior_pid;
}
-/* 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 means in the case of this target). */
-
+/* Async version of remote_wait. */
static int
-remote_wait (pid, status)
- int pid;
- struct target_waitstatus *status;
+remote_async_wait (int pid, struct target_waitstatus *status)
{
- unsigned char buf[PBUFSIZ];
+ unsigned char *buf = alloca (PBUFSIZ);
int thread_num = -1;
status->kind = TARGET_WAITKIND_EXITED;
{
unsigned char *p;
- interrupted_already = 0;
- ofunc = signal (SIGINT, remote_interrupt);
- getpkt ((char *) buf, 1);
- signal (SIGINT, ofunc);
+ if (!target_is_async_p ())
+ ofunc = signal (SIGINT, remote_interrupt);
+ /* FIXME: cagney/1999-09-27: If we're in async mode we should
+ _never_ wait for ever -> test on target_is_async_p().
+ However, before we do that we need to ensure that the caller
+ knows how to take the target into/out of async mode. */
+ getpkt (buf, PBUFSIZ, wait_forever_enabled_p);
+ if (!target_is_async_p ())
+ 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. */
+ collection of trace data) every time the target stops. */
if (target_wait_loop_hook)
(*target_wait_loop_hook) ();
/* Expedited reply, containing Signal, {regno, reg} repeat */
/* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
- ss = signal number
- n... = register number
- r... = register contents
- */
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
p = &buf[3]; /* after Txx */
while (*p)
/* Read the register number */
regno = strtol ((const char *) p, &p_temp, 16);
- p1 = (unsigned char *)p_temp;
+ p1 = (unsigned char *) p_temp;
- if (p1 == p) /* No register number present here */
+ if (p1 == p) /* No register number present here */
{
p1 = (unsigned char *) strchr ((const char *) p, ':');
if (p1 == NULL)
if (*p++ != ';')
{
warning ("Remote register badly formatted: %s", buf);
- warning (" here: %s",p);
+ warning (" here: %s", p);
}
}
}
status->value.sig = (enum target_signal)
(((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ if (buf[3] == 'p')
+ {
+ /* Export Cisco kernel mode as a convenience variable
+ (so that it can be used in the GDB prompt if desired). */
+
+ if (cisco_kernel_mode == 1)
+ set_internalvar (lookup_internalvar ("cisco_kernel_mode"),
+ value_from_string ("PDEBUG-"));
+ cisco_kernel_mode = 0;
+ thread_num = strtol ((const char *) &buf[4], NULL, 16);
+ record_currthread (thread_num);
+ }
+ else if (buf[3] == 'k')
+ {
+ /* Export Cisco kernel mode as a convenience variable
+ (so that it can be used in the GDB prompt if desired). */
+
+ if (cisco_kernel_mode == 1)
+ set_internalvar (lookup_internalvar ("cisco_kernel_mode"),
+ value_from_string ("KDEBUG-"));
+ cisco_kernel_mode = 1;
+ }
goto got_status;
+ case 'N': /* Cisco special: status and offsets */
+ {
+ bfd_vma text_addr, data_addr, bss_addr;
+ bfd_signed_vma text_off, data_off, bss_off;
+ unsigned char *p1;
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+
+ if (symfile_objfile == NULL)
+ {
+ warning ("Relocation packet recieved with no symbol file. \
+Packet Dropped");
+ goto got_status;
+ }
+
+ /* Relocate object file. Buffer format is NAATT;DD;BB
+ * where AA is the signal number, TT is the new text
+ * address, DD * is the new data address, and BB is the
+ * new bss address. */
+
+ p = &buf[3];
+ text_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ data_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ bss_addr = strtoul (p, (char **) &p1, 16);
+ if (p1 == p)
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+
+ if (remote_cisco_section_offsets (text_addr, data_addr, bss_addr,
+ &text_off, &data_off, &bss_off)
+ == 0)
+ if (text_off != 0 || data_off != 0 || bss_off != 0)
+ remote_cisco_objfile_relocate (text_off, data_off, bss_off);
+
+ goto got_status;
+ }
case 'W': /* Target exited */
{
/* The remote process exited. */
goto got_status;
case 'O': /* Console output */
remote_console_output (buf + 1);
- continue;
+ /* Return immediately to the event loop. The event loop will
+ still be waiting on the inferior afterwards. */
+ status->kind = TARGET_WAITKIND_IGNORE;
+ goto got_status;
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. */
+ 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",
continue;
}
}
- got_status:
+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 == MAGIC_NULL_PID)
- {
- inferior_pid = thread_num;
- if (!in_thread_list (inferior_pid))
- add_thread (inferior_pid);
- }
return thread_num;
}
return inferior_pid;
/* ARGSUSED */
static void
-remote_fetch_registers (regno)
- int regno;
+remote_fetch_registers (int regno)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
int i;
char *p;
- char regs[REGISTER_BYTES];
+ char *regs = alloca (REGISTER_BYTES);
set_thread (inferior_pid, 1);
sprintf (buf, "g");
- remote_send (buf);
+ remote_send (buf, PBUFSIZ);
- if (remote_register_buf_size == 0)
- remote_register_buf_size = strlen (buf);
+ /* Save the size of the packet sent to us by the target. Its used
+ as a heuristic when determining the max size of packets that the
+ target can safely receive. */
+ if (actual_register_packet_size == 0)
+ actual_register_packet_size = strlen (buf);
/* Unimplemented registers read as all bits zero. */
memset (regs, 0, REGISTER_BYTES);
&& buf[0] != 'x') /* New: unavailable register value */
{
if (remote_debug)
- printf_unfiltered ("Bad register packet; fetching a new packet\n");
- getpkt (buf, 0);
+ fprintf_unfiltered (gdb_stdlog,
+ "Bad register packet; fetching a new packet\n");
+ getpkt (buf, PBUFSIZ, 0);
}
/* Reply describes registers byte by byte, each byte encoded as two
goto supply_them;
}
if (p[0] == 'x' && p[1] == 'x')
- regs[i] = 0; /* 'x' */
+ regs[i] = 0; /* 'x' */
else
regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
p += 2;
if (i != register_bytes_found)
{
register_bytes_found = i;
-#ifdef REGISTER_BYTES_OK
- if (!REGISTER_BYTES_OK (i))
+ if (REGISTER_BYTES_OK_P ()
+ && !REGISTER_BYTES_OK (i))
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 */
- }
+ {
+ supply_register (i, ®s[REGISTER_BYTE (i)]);
+ if (buf[REGISTER_BYTE (i) * 2] == 'x')
+ set_register_cached (i, -1);
+ }
}
/* Prepare to store registers. Since we may send them all (using a
'G' request), we have to read out the ones we don't want to change
first. */
-static void
-remote_prepare_to_store ()
+static void
+remote_prepare_to_store (void)
{
/* Make sure the entire registers array is valid. */
- read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+ switch (remote_protocol_P.support)
+ {
+ case PACKET_DISABLE:
+ case PACKET_SUPPORT_UNKNOWN:
+ read_register_bytes (0, (char *) NULL, REGISTER_BYTES);
+ break;
+ case PACKET_ENABLE:
+ break;
+ }
+}
+
+/* Helper: Attempt to store REGNO using the P packet. Return fail IFF
+ packet was not recognized. */
+
+static int
+store_register_using_P (int regno)
+{
+ /* Try storing a single register. */
+ char *buf = alloca (PBUFSIZ);
+ char *regp;
+ char *p;
+ int i;
+
+ sprintf (buf, "P%x=", regno);
+ p = buf + strlen (buf);
+ regp = register_buffer (regno);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i)
+ {
+ *p++ = tohex ((regp[i] >> 4) & 0xf);
+ *p++ = tohex (regp[i] & 0xf);
+ }
+ *p = '\0';
+ remote_send (buf, PBUFSIZ);
+
+ return buf[0] != '\0';
}
+
/* Store register REGNO, or all registers if REGNO == -1, from the contents
- of REGISTERS. FIXME: ignores errors. */
+ of the register cache buffer. FIXME: ignores errors. */
static void
-remote_store_registers (regno)
- int regno;
+remote_store_registers (int regno)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
int i;
char *p;
+ char *regs;
set_thread (inferior_pid, 1);
- if (regno >= 0 && stub_supports_P)
+ if (regno >= 0)
{
- /* Try storing a single register. */
- char *regp;
-
- sprintf (buf, "P%x=", regno);
- p = buf + strlen (buf);
- regp = ®isters[REGISTER_BYTE (regno)];
- for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i)
- {
- *p++ = tohex ((regp[i] >> 4) & 0xf);
- *p++ = tohex (regp[i] & 0xf);
- }
- *p = '\0';
- remote_send (buf);
- if (buf[0] != '\0')
+ switch (remote_protocol_P.support)
{
- /* The stub understands the 'P' request. We are done. */
- return;
+ case PACKET_DISABLE:
+ break;
+ case PACKET_ENABLE:
+ if (store_register_using_P (regno))
+ return;
+ else
+ error ("Protocol error: P packet not recognized by stub");
+ case PACKET_SUPPORT_UNKNOWN:
+ if (store_register_using_P (regno))
+ {
+ /* The stub recognized the 'P' packet. Remember this. */
+ remote_protocol_P.support = PACKET_ENABLE;
+ return;
+ }
+ else
+ {
+ /* The stub does not support the 'P' packet. Use 'G'
+ instead, and don't try using 'P' in the future (it
+ will just waste our time). */
+ remote_protocol_P.support = PACKET_DISABLE;
+ break;
+ }
}
-
- /* The stub does not support the 'P' request. Use 'G' instead,
- and don't try using 'P' in the future (it will just waste our
- time). */
- stub_supports_P = 0;
}
buf[0] = 'G';
/* Command describes registers byte by byte,
each byte encoded as two hex characters. */
+ regs = register_buffer (-1);
p = buf + 1;
/* remote_prepare_to_store insures that register_bytes_found gets set. */
for (i = 0; i < register_bytes_found; i++)
{
- *p++ = tohex ((registers[i] >> 4) & 0xf);
- *p++ = tohex (registers[i] & 0xf);
+ *p++ = tohex ((regs[i] >> 4) & 0xf);
+ *p++ = tohex (regs[i] & 0xf);
}
*p = '\0';
- remote_send (buf);
-}
-
-/* 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. 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;
-{
- return dcache_fetch (remote_dcache, addr);
-}
-
-/* Write a word WORD into remote address ADDR.
- This goes through the data cache. */
-
-static void
-remote_store_word (addr, word)
- CORE_ADDR addr;
- int word;
-{
- dcache_poke (remote_dcache, addr, word);
+ remote_send (buf, PBUFSIZ);
}
-#endif /* 0 (unused?) */
-
\f
/* Return the number of hex digits in num. */
static int
-hexnumlen (num)
- ULONGEST num;
+hexnumlen (ULONGEST num)
{
int i;
return max (i, 1);
}
-/* Set BUF to the hex digits representing NUM. */
+/* Set BUF to the minimum number of hex digits representing NUM. */
static int
-hexnumstr (buf, num)
- char *buf;
- ULONGEST num;
+hexnumstr (char *buf, ULONGEST num)
{
- int i;
int len = hexnumlen (num);
+ return hexnumnstr (buf, num, len);
+}
+
+
+/* Set BUF to the hex digits representing NUM, padded to WIDTH characters. */
+
+static int
+hexnumnstr (char *buf, ULONGEST num, int width)
+{
+ int i;
- buf[len] = '\0';
+ buf[width] = '\0';
- for (i = len - 1; i >= 0; i--)
+ for (i = width - 1; i >= 0; i--)
{
- buf[i] = "0123456789abcdef" [(num & 0xf)];
+ buf[i] = "0123456789abcdef"[(num & 0xf)];
num >>= 4;
}
- return len;
+ return width;
}
/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */
static CORE_ADDR
-remote_address_masked (addr)
- CORE_ADDR addr;
+remote_address_masked (CORE_ADDR addr)
{
if (remote_address_size > 0
&& remote_address_size < (sizeof (ULONGEST) * 8))
return addr;
}
+/* Determine whether the remote target supports binary downloading.
+ This is accomplished by sending a no-op memory write of zero length
+ to the target at the specified address. It does not suffice to send
+ the whole packet, since many stubs strip the eighth bit and subsequently
+ compute a wrong checksum, which causes real havoc with remote_write_bytes.
+
+ NOTE: This can still lose if the serial line is not eight-bit
+ clean. In cases like this, the user should clear "remote
+ X-packet". */
+
+static void
+check_binary_download (CORE_ADDR addr)
+{
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_DISABLE:
+ break;
+ case PACKET_ENABLE:
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ {
+ char *buf = alloca (PBUFSIZ);
+ char *p;
+
+ p = buf;
+ *p++ = 'X';
+ p += hexnumstr (p, (ULONGEST) addr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) 0);
+ *p++ = ':';
+ *p = '\0';
+
+ putpkt_binary (buf, (int) (p - buf));
+ getpkt (buf, PBUFSIZ, 0);
+
+ if (buf[0] == '\0')
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading NOT suppported by target\n");
+ remote_protocol_binary_download.support = PACKET_DISABLE;
+ }
+ else
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading suppported by target\n");
+ remote_protocol_binary_download.support = PACKET_ENABLE;
+ }
+ break;
+ }
+ }
+}
+
/* 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.
MYADDR is the address of the buffer in our space.
LEN is the number of bytes.
- Returns number of bytes transferred, or 0 for error. */
+ Returns number of bytes transferred, or 0 (setting errno) for
+ error. Only transfer a single packet. */
static int
-remote_write_bytes (memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
+remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
{
+ unsigned char *buf;
int max_buf_size; /* Max size of packet output buffer */
- int origlen;
+ unsigned char *p;
+ unsigned char *plen;
+ long sizeof_buf;
+ int plenlen;
+ int todo;
+ int nr_bytes;
- /* Chop the transfer down if necessary */
+ /* Verify that the target can support a binary download */
+ check_binary_download (memaddr);
- 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);
+ /* Determine the max packet size. */
+ max_buf_size = get_memory_write_packet_size ();
+ sizeof_buf = max_buf_size + 1; /* Space for trailing NUL */
+ buf = alloca (sizeof_buf);
/* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */
max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4;
- origlen = len;
- while (len > 0)
- {
- char buf[PBUFSIZ];
- char *p;
- int todo;
- int i;
-
- todo = min (len, max_buf_size / 2); /* num bytes that will fit */
+ /* construct "M"<memaddr>","<len>":" */
+ /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
+ p = buf;
- /* construct "M"<memaddr>","<len>":" */
- /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
- memaddr = remote_address_masked (memaddr);
- p = buf;
+ /* Append [XM]. Compute a best guess of the number of bytes
+ actually transfered. */
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_ENABLE:
+ *p++ = 'X';
+ /* Best guess at number of bytes that will fit. */
+ todo = min (len, max_buf_size);
+ break;
+ case PACKET_DISABLE:
*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. */
-
- for (i = 0; i < todo; i++)
+ /* num bytes that will fit */
+ todo = min (len, max_buf_size / 2);
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error ("%s:%d: remote_write_bytes: bad internal state",
+ __FILE__, __LINE__);
+ default:
+ internal_error ("%s:%d: bad switch", __FILE__, __LINE__);
+ }
+
+ /* Append <memaddr> */
+ memaddr = remote_address_masked (memaddr);
+ p += hexnumstr (p, (ULONGEST) memaddr);
+ *p++ = ',';
+
+ /* Append <len>. Retain the location/size of <len>. It may
+ need to be adjusted once the packet body has been created. */
+ plen = p;
+ plenlen = hexnumstr (p, (ULONGEST) todo);
+ p += plenlen;
+ *p++ = ':';
+ *p = '\0';
+
+ /* Append the packet body. */
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_ENABLE:
+ /* Binary mode. Send target system values byte by byte, in
+ increasing byte addresses. Only escape certain critical
+ characters. */
+ for (nr_bytes = 0;
+ (nr_bytes < todo) && (p - buf) < (max_buf_size - 2);
+ nr_bytes++)
{
- *p++ = tohex ((myaddr[i] >> 4) & 0xf);
- *p++ = tohex (myaddr[i] & 0xf);
+ switch (myaddr[nr_bytes] & 0xff)
+ {
+ case '$':
+ case '#':
+ case 0x7d:
+ /* These must be escaped */
+ *p++ = 0x7d;
+ *p++ = (myaddr[nr_bytes] & 0xff) ^ 0x20;
+ break;
+ default:
+ *p++ = myaddr[nr_bytes] & 0xff;
+ break;
+ }
}
- *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;
+ if (nr_bytes < todo)
+ {
+ /* Escape chars have filled up the buffer prematurely,
+ and we have actually sent fewer bytes than planned.
+ Fix-up the length field of the packet. Use the same
+ number of characters as before. */
+
+ plen += hexnumnstr (plen, (ULONGEST) nr_bytes, plenlen);
+ *plen = ':'; /* overwrite \0 from hexnumnstr() */
}
- myaddr += todo;
- memaddr += todo;
- len -= todo;
+ break;
+ case PACKET_DISABLE:
+ /* Normal mode: Send target system values byte by byte, in
+ increasing byte addresses. Each byte is encoded as a two hex
+ value. */
+ for (nr_bytes = 0; nr_bytes < todo; nr_bytes++)
+ {
+ *p++ = tohex ((myaddr[nr_bytes] >> 4) & 0xf);
+ *p++ = tohex (myaddr[nr_bytes] & 0xf);
+ }
+ *p = '\0';
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error ("%s:%d: remote_write_bytes: bad internal state",
+ __FILE__, __LINE__);
+ default:
+ internal_error ("%s:%d: bad switch", __FILE__, __LINE__);
}
- return origlen;
+
+ putpkt_binary (buf, (int) (p - buf));
+ getpkt (buf, sizeof_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;
+ }
+
+ /* Return NR_BYTES, not TODO, in case escape chars caused us to send fewer
+ bytes than we'd planned. */
+ return nr_bytes;
}
/* Read memory data directly from the remote machine.
Returns number of bytes transferred, or 0 for error. */
+/* NOTE: cagney/1999-10-18: This function (and its siblings in other
+ remote targets) shouldn't attempt to read the entire buffer.
+ Instead it should read a single packet worth of data and then
+ return the byte size of that packet to the caller. The caller (its
+ caller and its callers caller ;-) already contains code for
+ handling partial reads. */
+
static int
-remote_read_bytes (memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
+remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
{
+ char *buf;
int max_buf_size; /* Max size of packet output buffer */
+ long sizeof_buf;
int origlen;
- /* Chop the transfer down if necessary */
-
- 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);
+ /* Create a buffer big enough for this packet. */
+ max_buf_size = get_memory_read_packet_size ();
+ sizeof_buf = max_buf_size + 1; /* Space for trailing NUL */
+ buf = alloca (sizeof_buf);
origlen = len;
while (len > 0)
{
- char buf[PBUFSIZ];
char *p;
int todo;
int i;
- todo = min (len, max_buf_size / 2); /* num bytes that will fit */
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
/* construct "m"<memaddr>","<len>" */
/* sprintf (buf, "m%lx,%x", (unsigned long) memaddr, todo); */
*p = '\0';
putpkt (buf);
- getpkt (buf, 0);
+ getpkt (buf, sizeof_buf, 0);
if (buf[0] == 'E')
{
return 0;
}
- /* Reply describes memory byte by byte,
- each byte encoded as two hex characters. */
+ /* Reply describes memory byte by byte,
+ each byte encoded as two hex characters. */
p = buf;
for (i = 0; i < todo; i++)
}
\f
/* Read or write LEN bytes from inferior memory at MEMADDR,
- transferring to or from debugger address MYADDR. Write to inferior
- if SHOULD_WRITE is nonzero. Returns length of data written or
- read; 0 for error. */
+ transferring to or from debugger address BUFFER. Write to inferior if
+ SHOULD_WRITE is nonzero. Returns length of data written or read; 0
+ for error. TARGET is unused. */
/* ARGSUSED */
static int
-remote_xfer_memory (memaddr, myaddr, len, should_write, target)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
- int should_write;
- struct target_ops *target; /* ignored */
-{
-#ifdef REMOTE_TRANSLATE_XFER_ADDRESS
- CORE_ADDR targaddr;
- int targlen;
- REMOTE_TRANSLATE_XFER_ADDRESS (memaddr, len, targaddr, targlen);
- if (targlen == 0)
+remote_xfer_memory (CORE_ADDR mem_addr, char *buffer, int mem_len,
+ int should_write,
+ struct mem_attrib *attrib ATTRIBUTE_UNUSED,
+ struct target_ops *target)
+{
+ CORE_ADDR targ_addr;
+ int targ_len;
+ int res;
+
+ REMOTE_TRANSLATE_XFER_ADDRESS (mem_addr, mem_len, &targ_addr, &targ_len);
+ if (targ_len <= 0)
return 0;
- memaddr = targaddr;
- len = targlen;
-#endif
- return dcache_xfer_memory (remote_dcache, memaddr, myaddr,
- len, should_write);
+ if (should_write)
+ res = remote_write_bytes (targ_addr, buffer, targ_len);
+ else
+ res = remote_read_bytes (targ_addr, buffer, targ_len);
+
+ return res;
}
-
+
#if 0
/* Enable after 4.12. */
void
-remote_search (len, data, mask, startaddr, increment, lorange, hirange
- addr_found, data_found)
- int len;
- char *data;
- char *mask;
- CORE_ADDR startaddr;
- int increment;
- CORE_ADDR lorange;
- CORE_ADDR hirange;
- CORE_ADDR *addr_found;
- char *data_found;
+remote_search (int len, char *data, char *mask, CORE_ADDR startaddr,
+ int increment, CORE_ADDR lorange, CORE_ADDR hirange,
+ CORE_ADDR *addr_found, char *data_found)
{
if (increment == -4 && len == 4)
{
long mask_long, data_long;
long data_found_long;
CORE_ADDR addr_we_found;
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
long returned_long[2];
char *p;
data_long = extract_unsigned_integer (data, len);
sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long);
putpkt (buf);
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
if (buf[0] == '\0')
{
/* The stub doesn't support the 't' request. We might want to
#endif /* 0 */
\f
static void
-remote_files_info (ignore)
- struct target_ops *ignore;
+remote_files_info (struct target_ops *ignore)
{
puts_filtered ("Debugging a target over a serial line.\n");
}
/* Read a single character from the remote end, masking it down to 7 bits. */
static int
-readchar (timeout)
- int timeout;
+readchar (int timeout)
{
int ch;
ch = SERIAL_READCHAR (remote_desc, timeout);
- switch (ch)
+ if (ch >= 0)
+ return (ch & 0x7f);
+
+ switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
+ target_mourn_inferior ();
error ("Remote connection closed");
+ /* no return */
case SERIAL_ERROR:
perror_with_name ("Remote communication error");
+ /* no return */
case SERIAL_TIMEOUT:
- return ch;
- default:
- return ch & 0x7f;
+ break;
}
+ return ch;
}
/* Send the command in BUF to the remote machine, and read the reply
into BUF. Report an error if we get an error reply. */
static void
-remote_send (buf)
- char *buf;
+remote_send (char *buf,
+ long sizeof_buf)
{
putpkt (buf);
- getpkt (buf, 0);
+ getpkt (buf, sizeof_buf, 0);
if (buf[0] == 'E')
error ("Remote failure reply: %s", buf);
string notation. */
static void
-print_packet (buf)
- char *buf;
+print_packet (char *buf)
{
puts_filtered ("\"");
- while (*buf)
- gdb_printchar (*buf++, gdb_stdout, '"');
+ fputstr_filtered (buf, '"', gdb_stdout);
puts_filtered ("\"");
}
+int
+putpkt (char *buf)
+{
+ return putpkt_binary (buf, strlen (buf));
+}
/* Send a packet to the remote machine, with error checking. The data
- of the packet is in BUF. */
+ of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5
+ to account for the $, # and checksum, and for a possible /0 if we are
+ debugging (remote_debug) and want to print the sent packet as a string */
-int
-putpkt (buf)
- char *buf;
+static int
+putpkt_binary (char *buf, int cnt)
{
int i;
unsigned char csum = 0;
- char buf2[PBUFSIZ];
- int cnt = strlen (buf);
+ char *buf2 = alloca (cnt + 6);
+ long sizeof_junkbuf = PBUFSIZ;
+ char *junkbuf = alloca (sizeof_junkbuf);
+
int ch;
int tcount = 0;
char *p;
/* Copy the packet into buffer BUF2, encapsulating it
and giving it a checksum. */
- if (cnt > (int) sizeof (buf2) - 5) /* Prosanity check */
- abort ();
-
p = buf2;
*p++ = '$';
if (remote_debug)
{
*p = '\0';
- printf_unfiltered ("Sending packet: %s...", buf2);
- gdb_flush (gdb_stdout);
+ fprintf_unfiltered (gdb_stdlog, "Sending packet: ");
+ fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "...");
+ gdb_flush (gdb_stdlog);
}
if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
perror_with_name ("putpkt: write failed");
{
ch = readchar (remote_timeout);
- if (remote_debug)
+ if (remote_debug)
{
switch (ch)
{
case '+':
+ case '-':
case SERIAL_TIMEOUT:
case '$':
if (started_error_output)
{
case '+':
if (remote_debug)
- printf_unfiltered ("Ack\n");
+ fprintf_unfiltered (gdb_stdlog, "Ack\n");
return 1;
+ case '-':
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Nak\n");
case SERIAL_TIMEOUT:
- tcount ++;
+ tcount++;
if (tcount > 3)
return 0;
break; /* Retransmit buffer */
case '$':
{
- char junkbuf[PBUFSIZ];
-
- /* It's probably an old response, and we're out of sync.
- Just gobble up the packet and ignore it. */
- getpkt (junkbuf, 0);
- continue; /* Now, go look for + */
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Packet instead of Ack, ignoring it\n");
+ /* It's probably an old response, and we're out of sync.
+ Just gobble up the packet and ignore it. */
+ read_frame (junkbuf, sizeof_junkbuf);
+ continue; /* Now, go look for + */
}
default:
if (remote_debug)
if (!started_error_output)
{
started_error_output = 1;
- printf_unfiltered ("putpkt: Junk: ");
+ fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: ");
}
- putchar_unfiltered (ch & 0177);
+ fputc_unfiltered (ch & 0177, gdb_stdlog);
}
continue;
}
#if 0
/* This is wrong. If doing a long backtrace, the user should be
- able to get out next time we call QUIT, without anything as
- violent as interrupt_query. If we want to provide a way out of
- here without getting to the next QUIT, it should be based on
- hitting ^C twice as in remote_wait. */
+ able to get out next time we call QUIT, without anything as
+ violent as interrupt_query. If we want to provide a way out of
+ here without getting to the next QUIT, it should be based on
+ hitting ^C twice as in remote_wait. */
if (quit_flag)
{
quit_flag = 0;
}
}
+static int remote_cisco_mode;
+
/* Come here after finding the start of the frame. Collect the rest
into BUF, verifying the checksum, length, and handling run-length
- compression. Returns 0 on any error, 1 on success. */
+ compression. No more than sizeof_buf-1 characters are read so that
+ the buffer can be NUL terminated.
-static int
-read_frame (buf)
- char *buf;
+ Returns -1 on error, number of characters in buffer (ignoring the
+ trailing NULL) on success. (could be extended to return one of the
+ SERIAL status indications). */
+
+static long
+read_frame (char *buf,
+ long sizeof_buf)
{
unsigned char csum;
- char *bp;
+ long bc;
int c;
csum = 0;
- bp = buf;
+ bc = 0;
while (1)
{
+ /* ASSERT (bc < sizeof_buf - 1) - space for trailing NUL */
c = readchar (remote_timeout);
-
switch (c)
{
case SERIAL_TIMEOUT:
if (remote_debug)
- puts_filtered ("Timeout in mid-packet, retrying\n");
- return 0;
+ fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog);
+ return -1;
case '$':
if (remote_debug)
- puts_filtered ("Saw new packet start in middle of old one\n");
- return 0; /* Start a new packet, count retries */
+ fputs_filtered ("Saw new packet start in middle of old one\n",
+ gdb_stdlog);
+ return -1; /* Start a new packet, count retries */
case '#':
{
unsigned char pktcsum;
+ int check_0 = 0;
+ int check_1 = 0;
- *bp = '\000';
+ buf[bc] = '\0';
- pktcsum = fromhex (readchar (remote_timeout)) << 4;
- pktcsum |= fromhex (readchar (remote_timeout));
+ check_0 = readchar (remote_timeout);
+ if (check_0 >= 0)
+ check_1 = readchar (remote_timeout);
+
+ if (check_0 == SERIAL_TIMEOUT || check_1 == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ fputs_filtered ("Timeout in checksum, retrying\n", gdb_stdlog);
+ return -1;
+ }
+ else if (check_0 < 0 || check_1 < 0)
+ {
+ if (remote_debug)
+ fputs_filtered ("Communication error in checksum\n", gdb_stdlog);
+ return -1;
+ }
+ pktcsum = (fromhex (check_0) << 4) | fromhex (check_1);
if (csum == pktcsum)
- return 1;
+ return bc;
- if (remote_debug)
+ if (remote_debug)
{
- printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
- pktcsum, csum);
- puts_filtered (buf);
- puts_filtered ("\n");
+ fprintf_filtered (gdb_stdlog,
+ "Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ fputs_filtered (buf, gdb_stdlog);
+ fputs_filtered ("\n", gdb_stdlog);
}
- return 0;
+ /* Number of characters in buffer ignoring trailing
+ NUL. */
+ return -1;
}
case '*': /* Run length encoding */
- csum += c;
- c = readchar (remote_timeout);
- csum += c;
- c = c - ' ' + 3; /* Compute repeat count */
+ {
+ int repeat;
+ csum += c;
+ if (remote_cisco_mode == 0)
+ {
+ c = readchar (remote_timeout);
+ csum += c;
+ repeat = c - ' ' + 3; /* Compute repeat count */
+ }
+ else
+ {
+ /* Cisco's run-length encoding variant uses two
+ hex chars to represent the repeat count. */
+
+ c = readchar (remote_timeout);
+ csum += c;
+ repeat = fromhex (c) << 4;
+ c = readchar (remote_timeout);
+ csum += c;
+ repeat += fromhex (c);
+ }
- if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1)
- {
- memset (bp, *(bp - 1), c);
- bp += c;
- continue;
- }
+ /* The character before ``*'' is repeated. */
- *bp = '\0';
- printf_filtered ("Repeat count %d too large for buffer: ", c);
- puts_filtered (buf);
- puts_filtered ("\n");
- return 0;
+ if (repeat > 0 && repeat <= 255
+ && bc > 0
+ && bc + repeat < sizeof_buf - 1)
+ {
+ memset (&buf[bc], buf[bc - 1], repeat);
+ bc += repeat;
+ continue;
+ }
+ buf[bc] = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", repeat);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ return -1;
+ }
default:
- if (bp < buf + PBUFSIZ - 1)
+ if (bc < sizeof_buf - 1)
{
- *bp++ = c;
+ buf[bc++] = c;
csum += c;
continue;
}
- *bp = '\0';
+ buf[bc] = '\0';
puts_filtered ("Remote packet too long: ");
puts_filtered (buf);
puts_filtered ("\n");
- return 0;
+ return -1;
}
}
}
/* Read a packet from the remote machine, with error checking, and
- store it in BUF. BUF is expected to be of size PBUFSIZ. If
- FOREVER, wait forever rather than timing out; this is used while
- the target is executing user code. */
-
+ store it in BUF. If FOREVER, wait forever rather than timing out;
+ this is used (in synchronous mode) to wait for a target that is is
+ executing user code to stop. */
+/* FIXME: ezannoni 2000-02-01 this wrapper is necessary so that we
+ don't have to change all the calls to getpkt to deal with the
+ return value, because at the moment I don't know what the right
+ thing to do it for those. */
void
-getpkt (buf, forever)
- char *buf;
- int forever;
+getpkt (char *buf,
+ long sizeof_buf,
+ int forever)
+{
+ int timed_out;
+
+ timed_out = getpkt_sane (buf, sizeof_buf, forever);
+}
+
+
+/* Read a packet from the remote machine, with error checking, and
+ store it in BUF. If FOREVER, wait forever rather than timing out;
+ this is used (in synchronous mode) to wait for a target that is is
+ executing user code to stop. If FOREVER == 0, this function is
+ allowed to time out gracefully and return an indication of this to
+ the caller. */
+int
+getpkt_sane (char *buf,
+ long sizeof_buf,
+ int forever)
{
int c;
int tries;
int timeout;
int val;
- strcpy (buf,"timeout");
+ strcpy (buf, "timeout");
if (forever)
{
-#ifdef MAINTENANCE_CMDS
timeout = watchdog > 0 ? watchdog : -1;
-#else
- timeout = -1;
-#endif
}
else
for (tries = 1; tries <= MAX_TRIES; tries++)
{
/* This can loop forever if the remote side sends us characters
- continuously, but if it pauses, we'll get a zero from readchar
- because of timeout. Then we'll count that as a retry. */
+ continuously, but if it pauses, we'll get a zero from readchar
+ because of timeout. Then we'll count that as a retry. */
/* Note that we will only wait forever prior to the start of a packet.
- After that, we expect characters to arrive at a brisk pace. They
- should show up within remote_timeout intervals. */
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within remote_timeout intervals. */
do
{
if (c == SERIAL_TIMEOUT)
{
-#ifdef MAINTENANCE_CMDS
- if (forever) /* Watchdog went off. Kill the target. */
+ if (forever) /* Watchdog went off? Kill the target. */
{
+ QUIT;
target_mourn_inferior ();
error ("Watchdog has expired. Target detached.\n");
}
-#endif
if (remote_debug)
- puts_filtered ("Timed out.\n");
+ fputs_filtered ("Timed out.\n", gdb_stdlog);
goto retry;
}
}
/* We've found the start of a packet, now collect the data. */
- val = read_frame (buf);
+ val = read_frame (buf, sizeof_buf);
- if (val == 1)
+ if (val >= 0)
{
if (remote_debug)
- fprintf_unfiltered (gdb_stdout, "Packet received: %s\n", buf);
+ {
+ fprintf_unfiltered (gdb_stdlog, "Packet received: ");
+ fputstr_unfiltered (buf, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
SERIAL_WRITE (remote_desc, "+", 1);
- return;
+ return 0;
}
/* Try the whole thing again. */
printf_unfiltered ("Ignoring packet error, continuing...\n");
SERIAL_WRITE (remote_desc, "+", 1);
+ return 1;
}
\f
static void
-remote_kill ()
+remote_kill (void)
+{
+ /* 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 ((catch_errors_ftype *) 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 ();
+}
+
+/* Async version of remote_kill. */
+static void
+remote_async_kill (void)
{
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ SERIAL_ASYNC (remote_desc, NULL, 0);
+
/* For some mysterious reason, wait_for_inferior calls kill instead of
mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */
if (kill_kludge)
/* 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);
+ catch_errors ((catch_errors_ftype *) 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. */
}
static void
-remote_mourn ()
+remote_mourn (void)
{
remote_mourn_1 (&remote_ops);
}
static void
-extended_remote_mourn ()
+remote_async_mourn (void)
+{
+ remote_mourn_1 (&remote_async_ops);
+}
+
+static void
+extended_remote_mourn (void)
{
/* We do _not_ want to mourn the target like this; this will
remove the extended remote target from the target stack,
/* Worker function for remote_mourn. */
static void
-remote_mourn_1 (target)
- struct target_ops *target;
+remote_mourn_1 (struct target_ops *target)
{
unpush_target (target);
generic_mourn_inferior ();
we're debugging, arguments and an environment. */
static void
-extended_remote_create_inferior (exec_file, args, env)
- char *exec_file;
- char *args;
- char **env;
+extended_remote_create_inferior (char *exec_file, char *args, char **env)
{
/* Rip out the breakpoints; we'll reinsert them after restarting
the remote server. */
proceed (-1, TARGET_SIGNAL_0, 0);
}
+/* Async version of extended_remote_create_inferior. */
+static void
+extended_remote_async_create_inferior (char *exec_file, char *args, char **env)
+{
+ /* Rip out the breakpoints; we'll reinsert them after restarting
+ the remote server. */
+ remove_breakpoints ();
+
+ /* If running asynchronously, register the target file descriptor
+ with the event loop. */
+ if (event_loop_p && target_can_async_p ())
+ target_async (inferior_event_handler, 0);
+
+ /* 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; in those use REMOTE_BREAKPOINT instead of just
BREAKPOINT. Also, bi-endian targets may define LITTLE_REMOTE_BREAKPOINT
is accomplished via BREAKPOINT_MAX). */
static int
-remote_insert_breakpoint (addr, contents_cache)
- CORE_ADDR addr;
- char *contents_cache;
+remote_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
{
#ifdef REMOTE_BREAKPOINT
int val;
+#endif
+ int bp_size;
+
+ /* Try the "Z" s/w breakpoint packet if it is not already disabled.
+ If it succeeds, then set the support to PACKET_ENABLE. If it
+ fails, and the user has explicitly requested the Z support then
+ report an error, otherwise, mark it disabled and go on. */
+
+ if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE)
+ {
+ char *buf = alloca (PBUFSIZ);
+ char *p = buf;
+
+ addr = remote_address_masked (addr);
+ *(p++) = 'Z';
+ *(p++) = '0';
+ *(p++) = ',';
+ p += hexnumstr (p, (ULONGEST) addr);
+ BREAKPOINT_FROM_PC (&addr, &bp_size);
+ sprintf (p, ",%d", bp_size);
+
+ putpkt (buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_SOFTWARE_BP]))
+ {
+ case PACKET_ERROR:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ case PACKET_UNKNOWN:
+ break;
+ }
+ }
+#ifdef REMOTE_BREAKPOINT
val = target_read_memory (addr, contents_cache, sizeof big_break_insn);
if (val == 0)
}
static int
-remote_remove_breakpoint (addr, contents_cache)
- CORE_ADDR addr;
- char *contents_cache;
+remote_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
+ int bp_size;
+
+ if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE)
+ {
+ char *buf = alloca (PBUFSIZ);
+ char *p = buf;
+
+ *(p++) = 'z';
+ *(p++) = '0';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ BREAKPOINT_FROM_PC (&addr, &bp_size);
+ sprintf (p, ",%d", bp_size);
+
+ putpkt (buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ return (buf[0] == 'E');
+ }
+
#ifdef REMOTE_BREAKPOINT
return target_write_memory (addr, contents_cache, sizeof big_break_insn);
#else
#endif /* REMOTE_BREAKPOINT */
}
+static int
+watchpoint_to_Z_packet (int type)
+{
+ switch (type)
+ {
+ case hw_write:
+ return 2;
+ break;
+ case hw_read:
+ return 3;
+ break;
+ case hw_access:
+ return 4;
+ break;
+ default:
+ internal_error ("hw_bp_to_z: bad watchpoint type %d", type);
+ }
+}
+
+/* FIXME: This function should be static and a member of the remote
+ target vector. */
+
+int
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ char *buf = alloca (PBUFSIZ);
+ char *p;
+ enum Z_packet_type packet = watchpoint_to_Z_packet (type);
+
+ if (remote_protocol_Z[packet].support == PACKET_DISABLE)
+ error ("Can't set hardware watchpoints without the '%s' (%s) packet\n",
+ remote_protocol_Z[packet].name,
+ remote_protocol_Z[packet].title);
+
+ sprintf (buf, "Z%x,", packet);
+ p = strchr (buf, '\0');
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt (buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[packet]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error ("remote_insert_watchpoint: reached end of function");
+}
+
+/* FIXME: This function should be static and a member of the remote
+ target vector. */
+
+int
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ char *buf = alloca (PBUFSIZ);
+ char *p;
+ enum Z_packet_type packet = watchpoint_to_Z_packet (type);
+
+ if (remote_protocol_Z[packet].support == PACKET_DISABLE)
+ error ("Can't clear hardware watchpoints without the '%s' (%s) packet\n",
+ remote_protocol_Z[packet].name,
+ remote_protocol_Z[packet].title);
+
+ sprintf (buf, "z%x,", packet);
+ p = strchr (buf, '\0');
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+ putpkt (buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[packet]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error ("remote_remove_watchpoint: reached end of function");
+}
+
+/* FIXME: This function should be static and a member of the remote
+ target vector. */
+
+int
+remote_insert_hw_breakpoint (CORE_ADDR addr, int len)
+{
+ char *buf = alloca (PBUFSIZ);
+ char *p = buf;
+
+ if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE)
+ error ("Can't set hardware breakpoint without the '%s' (%s) packet\n",
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].name,
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].title);
+
+ *(p++) = 'Z';
+ *(p++) = '1';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt (buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error ("remote_remove_watchpoint: reached end of function");
+}
+
+/* FIXME: This function should be static and a member of the remote
+ target vector. */
+
+int
+remote_remove_hw_breakpoint (CORE_ADDR addr, int len)
+{
+ char *buf = alloca (PBUFSIZ);
+ char *p = buf;
+
+ if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE)
+ error ("Can't clear hardware breakpoint without the '%s' (%s) packet\n",
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].name,
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].title);
+
+ *(p++) = 'z';
+ *(p++) = '1';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt(buf);
+ getpkt (buf, PBUFSIZ, 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error ("remote_remove_watchpoint: reached end of function");
+}
+
/* 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.
already..." message. Usually a call to pop_target() suffices. */
void
-push_remote_target (name, from_tty)
- char *name;
- int from_tty;
+push_remote_target (char *name, int from_tty)
{
printf_filtered ("Switching to remote protocol\n");
remote_open (name, from_tty);
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;
+open_remote_target (char *name, int from_tty, struct target_ops *target,
+ int extended_p)
{
printf_filtered ("Selecting the %sremote protocol\n",
(extended_p ? "extended-" : ""));
/* Table used by the crc32 function to calcuate the checksum. */
-static unsigned long crc32_table[256] = {0, 0};
+static unsigned long crc32_table[256] =
+{0, 0};
static unsigned long
-crc32 (buf, len, crc)
- unsigned char *buf;
- int len;
- unsigned int crc;
+crc32 (unsigned char *buf, int len, unsigned int crc)
{
- if (! crc32_table[1])
+ if (!crc32_table[1])
{
/* Initialize the CRC table and the decoding table. */
int i, j;
unsigned int c;
for (i = 0; i < 256; i++)
- {
- for (c = i << 24, j = 8; j > 0; --j)
- c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
- crc32_table[i] = c;
- }
+ {
+ for (c = i << 24, j = 8; j > 0; --j)
+ c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
+ crc32_table[i] = c;
+ }
}
while (len--)
Useful for verifying the image on the target against the exec file.
Depends on the target understanding the new "qCRC:" request. */
+/* FIXME: cagney/1999-10-26: This command should be broken down into a
+ target method (target verify memory) and generic version of the
+ actual command. This will allow other high-level code (especially
+ generic_load()) to make use of this target functionality. */
+
static void
-compare_sections_command (args, from_tty)
- char *args;
- int from_tty;
+compare_sections_command (char *args, int from_tty)
{
asection *s;
unsigned long host_crc, target_crc;
extern bfd *exec_bfd;
struct cleanup *old_chain;
- char *tmp, *sectdata, *sectname, buf[PBUFSIZ];
+ char *tmp;
+ char *sectdata;
+ char *sectname;
+ char *buf = alloca (PBUFSIZ);
bfd_size_type size;
bfd_vma lma;
int matched = 0;
strcmp (current_target.to_shortname, "remote") != 0)
error ("command can only be used with remote target");
- for (s = exec_bfd->sections; s; s = s->next)
+ for (s = exec_bfd->sections; s; s = s->next)
{
if (!(s->flags & SEC_LOAD))
- continue; /* skip non-loadable section */
+ continue; /* skip non-loadable section */
size = bfd_get_section_size_before_reloc (s);
if (size == 0)
- continue; /* skip zero-length section */
+ continue; /* skip zero-length section */
sectname = (char *) bfd_get_section_name (exec_bfd, s);
if (args && strcmp (args, sectname) != 0)
- continue; /* not the section selected by user */
+ continue; /* not the section selected by user */
- matched = 1; /* do this section */
+ matched = 1; /* do this section */
lma = s->lma;
/* FIXME: assumes lma can fit into long */
sprintf (buf, "qCRC:%lx,%lx", (long) lma, (long) size);
/* be clever; compute the host_crc before waiting for target reply */
sectdata = xmalloc (size);
- old_chain = make_cleanup (free, sectdata);
+ old_chain = make_cleanup (xfree, sectdata);
bfd_get_section_contents (exec_bfd, s, sectdata, 0, size);
host_crc = crc32 ((unsigned char *) sectdata, size, 0xffffffff);
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
if (buf[0] == 'E')
error ("target memory fault, section %s, range 0x%08x -- 0x%08x",
sectname, lma, lma + size);
for (target_crc = 0, tmp = &buf[1]; *tmp; tmp++)
target_crc = target_crc * 16 + fromhex (*tmp);
- printf_filtered ("Section %s, range 0x%08x -- 0x%08x: ",
- sectname, lma, lma + size);
+ printf_filtered ("Section %s, range 0x%s -- 0x%s: ",
+ sectname, paddr (lma), paddr (lma + size));
if (host_crc == target_crc)
printf_filtered ("matched.\n");
else
- {
- printf_filtered ("MIS-MATCHED!\n");
- mismatched++;
- }
+ {
+ 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\n\
-the loaded file\n");
- if (args && !matched)
- printf_filtered ("No loaded section named '%s'.\n", args);
+ if (mismatched > 0)
+ warning ("One or more sections of the remote executable does not match\n\
+the loaded file\n");
+ if (args && !matched)
+ printf_filtered ("No loaded section named '%s'.\n", args);
+}
+
+static int
+remote_query (int query_type, char *buf, char *outbuf, int *bufsiz)
+{
+ int i;
+ char *buf2 = alloca (PBUFSIZ);
+ char *p2 = &buf2[0];
+
+ if (!bufsiz)
+ error ("null pointer to remote bufer size specified");
+
+ /* minimum outbuf size is PBUFSIZ - if bufsiz is not large enough let
+ the caller know and return what the minimum size is */
+ /* Note: a zero bufsiz can be used to query the minimum buffer size */
+ if (*bufsiz < PBUFSIZ)
+ {
+ *bufsiz = PBUFSIZ;
+ return -1;
+ }
+
+ /* except for querying the minimum buffer size, target must be open */
+ if (!remote_desc)
+ error ("remote query is only available after target open");
+
+ /* we only take uppercase letters as query types, at least for now */
+ if ((query_type < 'A') || (query_type > 'Z'))
+ error ("invalid remote query type");
+
+ if (!buf)
+ error ("null remote query specified");
+
+ if (!outbuf)
+ error ("remote query requires a buffer to receive data");
+
+ outbuf[0] = '\0';
+
+ *p2++ = 'q';
+ *p2++ = query_type;
+
+ /* we used one buffer char for the remote protocol q command and another
+ for the query type. As the remote protocol encapsulation uses 4 chars
+ plus one extra in case we are debugging (remote_debug),
+ we have PBUFZIZ - 7 left to pack the query string */
+ i = 0;
+ while (buf[i] && (i < (PBUFSIZ - 8)))
+ {
+ /* bad caller may have sent forbidden characters */
+ if ((!isprint (buf[i])) || (buf[i] == '$') || (buf[i] == '#'))
+ error ("illegal characters in query string");
+
+ *p2++ = buf[i];
+ i++;
+ }
+ *p2 = buf[i];
+
+ if (buf[i])
+ error ("query larger than available buffer");
+
+ i = putpkt (buf2);
+ if (i < 0)
+ return i;
+
+ getpkt (outbuf, *bufsiz, 0);
+
+ return 0;
+}
+
+static void
+remote_rcmd (char *command,
+ struct ui_file *outbuf)
+{
+ int i;
+ char *buf = alloca (PBUFSIZ);
+ char *p = buf;
+
+ if (!remote_desc)
+ error ("remote rcmd is only available after target open");
+
+ /* Send a NULL command across as an empty command */
+ if (command == NULL)
+ command = "";
+
+ /* The query prefix */
+ strcpy (buf, "qRcmd,");
+ p = strchr (buf, '\0');
+
+ if ((strlen (buf) + strlen (command) * 2 + 8/*misc*/) > PBUFSIZ)
+ error ("\"monitor\" command ``%s'' is too long\n", command);
+
+ /* Encode the actual command */
+ for (i = 0; command[i]; i++)
+ {
+ *p++ = tohex ((command[i] >> 4) & 0xf);
+ *p++ = tohex (command[i] & 0xf);
+ }
+ *p = '\0';
+
+ if (putpkt (buf) < 0)
+ error ("Communication problem with target\n");
+
+ /* get/display the response */
+ while (1)
+ {
+ /* XXX - see also tracepoint.c:remote_get_noisy_reply() */
+ buf[0] = '\0';
+ getpkt (buf, PBUFSIZ, 0);
+ if (buf[0] == '\0')
+ error ("Target does not support this command\n");
+ if (buf[0] == 'O' && buf[1] != 'K')
+ {
+ remote_console_output (buf + 1); /* 'O' message from stub */
+ continue;
+ }
+ if (strcmp (buf, "OK") == 0)
+ break;
+ if (strlen (buf) == 3 && buf[0] == 'E'
+ && isdigit (buf[1]) && isdigit (buf[2]))
+ {
+ error ("Protocol error with Rcmd");
+ }
+ for (p = buf; p[0] != '\0' && p[1] != '\0'; p += 2)
+ {
+ char c = (fromhex (p[0]) << 4) + fromhex (p[1]);
+ fputc_unfiltered (c, outbuf);
+ }
+ break;
+ }
}
static void
-packet_command (args, from_tty)
- char *args;
- int from_tty;
+packet_command (char *args, int from_tty)
{
- char buf[PBUFSIZ];
+ char *buf = alloca (PBUFSIZ);
- if (! remote_desc)
+ if (!remote_desc)
error ("command can only be used with remote target");
- if (! args)
+ if (!args)
error ("remote-packet command requires packet text as argument");
puts_filtered ("sending: ");
puts_filtered ("\n");
putpkt (args);
- getpkt (buf, 0);
+ getpkt (buf, PBUFSIZ, 0);
puts_filtered ("received: ");
print_packet (buf);
puts_filtered ("\n");
#if 0
/* --------- UNIT_TEST for THREAD oriented PACKETS ------------------------- */
-static void display_thread_info PARAMS ((struct gdb_ext_thread_info *info));
+static void display_thread_info (struct gdb_ext_thread_info *info);
-static void threadset_test_cmd PARAMS ((char *cmd, int tty));
+static void threadset_test_cmd (char *cmd, int tty);
-static void threadalive_test PARAMS ((char *cmd, int tty));
+static void threadalive_test (char *cmd, int tty);
-static void threadlist_test_cmd PARAMS ((char *cmd, int tty));
+static void threadlist_test_cmd (char *cmd, int tty);
-int get_and_display_threadinfo PARAMS ((threadref *ref));
+int get_and_display_threadinfo (threadref * ref);
-static void threadinfo_test_cmd PARAMS ((char *cmd, int tty));
+static void threadinfo_test_cmd (char *cmd, int tty);
-static int thread_display_step PARAMS ((threadref *ref, void *context));
+static int thread_display_step (threadref * ref, void *context);
-static void threadlist_update_test_cmd PARAMS ((char *cmd, int tty));
+static void threadlist_update_test_cmd (char *cmd, int tty);
-static void init_remote_threadtests PARAMS ((void));
+static void init_remote_threadtests (void);
-#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */
+#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */
static void
-threadset_test_cmd (cmd, tty)
- char *cmd;
- int tty;
+threadset_test_cmd (char *cmd, int tty)
{
int sample_thread = SAMPLE_THREAD;
static void
-threadalive_test (cmd, tty)
- char *cmd;
- int tty;
+threadalive_test (char *cmd, int tty)
{
int sample_thread = SAMPLE_THREAD;
printf_filtered ("FAIL: Thread alive test\n");
}
-void output_threadid PARAMS ((char *title, threadref * ref));
+void output_threadid (char *title, threadref * ref);
void
-output_threadid (title, ref)
- char *title;
- threadref *ref;
+output_threadid (char *title, threadref *ref)
{
char hexid[20];
}
static void
-threadlist_test_cmd (cmd, tty)
- char *cmd;
- int tty;
+threadlist_test_cmd (char *cmd, int tty)
{
int startflag = 1;
threadref nextthread;
}
void
-display_thread_info (info)
- struct gdb_ext_thread_info *info;
+display_thread_info (struct gdb_ext_thread_info *info)
{
output_threadid ("Threadid: ", &info->threadid);
printf_filtered ("Name: %s\n ", info->shortname);
}
int
-get_and_display_threadinfo (ref)
- threadref *ref;
+get_and_display_threadinfo (threadref *ref)
{
int result;
int set;
}
static void
-threadinfo_test_cmd (cmd, tty)
- char *cmd;
- int tty;
+threadinfo_test_cmd (char *cmd, int tty)
{
int athread = SAMPLE_THREAD;
threadref thread;
}
static int
-thread_display_step (ref, context)
- threadref *ref;
- void *context;
+thread_display_step (threadref *ref, void *context)
{
/* output_threadid(" threadstep ",ref); *//* simple test */
return get_and_display_threadinfo (ref);
}
static void
-threadlist_update_test_cmd (cmd, tty)
- char *cmd;
- int tty;
+threadlist_update_test_cmd (char *cmd, int tty)
{
printf_filtered ("Remote Threadlist update test\n");
remote_threadlist_iterator (thread_display_step, 0, CRAZY_MAX_THREADS);
#endif /* 0 */
static void
-init_remote_ops ()
+init_remote_ops (void)
{
- remote_ops.to_shortname = "remote";
+ remote_ops.to_shortname = "remote";
remote_ops.to_longname = "Remote serial target in gdb-specific protocol";
- remote_ops.to_doc =
+ 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;
+Specify the serial device it is connected to\n\
+(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.).";
+ 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_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_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_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_find_new_threads = remote_threads_info;
+ remote_ops.to_extra_thread_info = remote_threads_extra_info;
remote_ops.to_stop = remote_stop;
+ remote_ops.to_query = remote_query;
+ remote_ops.to_rcmd = remote_rcmd;
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;
+ 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_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_ops.to_magic = OPS_MAGIC;
}
/* Set up the extended remote vector by making a copy of the standard
remote vector and adding to it. */
static void
-init_extended_remote_ops ()
+init_extended_remote_ops (void)
{
extended_remote_ops = remote_ops;
- extended_remote_ops.to_shortname = "extended-remote";
- extended_remote_ops.to_longname =
+ 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 =
+ 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_open = extended_remote_open;
extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
-}
+}
+
+/*
+ * Command: info remote-process
+ *
+ * This implements Cisco's version of the "info proc" command.
+ *
+ * This query allows the target stub to return an arbitrary string
+ * (or strings) giving arbitrary information about the target process.
+ * This is optional; the target stub isn't required to implement it.
+ *
+ * Syntax: qfProcessInfo request first string
+ * qsProcessInfo request subsequent string
+ * reply: 'O'<hex-encoded-string>
+ * 'l' last reply (empty)
+ */
+
+static void
+remote_info_process (char *args, int from_tty)
+{
+ char *buf = alloca (PBUFSIZ);
+
+ if (remote_desc == 0)
+ error ("Command can only be used when connected to the remote target.");
+
+ putpkt ("qfProcessInfo");
+ getpkt (buf, PBUFSIZ, 0);
+ if (buf[0] == 0)
+ return; /* Silently: target does not support this feature. */
+
+ if (buf[0] == 'E')
+ error ("info proc: target error.");
+
+ while (buf[0] == 'O') /* Capitol-O packet */
+ {
+ remote_console_output (&buf[1]);
+ putpkt ("qsProcessInfo");
+ getpkt (buf, PBUFSIZ, 0);
+ }
+}
+
+/*
+ * Target Cisco
+ */
+
+static void
+remote_cisco_open (char *name, int from_tty)
+{
+ if (name == 0)
+ error (
+ "To open a remote debug connection, you need to specify what \n\
+device is attached to the remote system (e.g. host:port).");
+
+ /* See FIXME above */
+ wait_forever_enabled_p = 1;
+
+ target_preopen (from_tty);
+
+ unpush_target (&remote_cisco_ops);
+
+ remote_desc = SERIAL_OPEN (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ /*
+ * If a baud rate was specified on the gdb command line it will
+ * be greater than the initial value of -1. If it is, use it otherwise
+ * default to 9600
+ */
+
+ baud_rate = (baud_rate > 0) ? baud_rate : 9600;
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
+
+ SERIAL_RAW (remote_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (remote_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+
+ remote_cisco_mode = 1;
+
+ push_target (&remote_cisco_ops); /* Switch to using cisco target now */
+
+ init_all_packet_configs ();
+
+ general_thread = -2;
+ continue_thread = -2;
+
+ /* Probe for ability to use "ThreadInfo" query, as required. */
+ use_threadinfo_query = 1;
+ use_threadextra_query = 1;
+
+ /* 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 = MAGIC_NULL_PID;
+
+ /* Start the remote connection; if error (0), discard this target. */
+
+ if (!catch_errors (remote_start_remote_dummy, (char *) 0,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ {
+ pop_target ();
+ return;
+ }
+}
+
+static void
+remote_cisco_close (int quitting)
+{
+ remote_cisco_mode = 0;
+ remote_close (quitting);
+}
+
+static void
+remote_cisco_mourn (void)
+{
+ remote_mourn_1 (&remote_cisco_ops);
+}
+
+enum
+{
+ READ_MORE,
+ FATAL_ERROR,
+ ENTER_DEBUG,
+ DISCONNECT_TELNET
+}
+minitelnet_return;
+
+/* shared between readsocket() and readtty() */
+static char *tty_input;
+
+static int escape_count;
+static int echo_check;
+extern int quit_flag;
+
+static int
+readsocket (void)
+{
+ int data;
+
+ /* Loop until the socket doesn't have any more data */
+
+ while ((data = readchar (0)) >= 0)
+ {
+ /* Check for the escape sequence */
+ if (data == '|')
+ {
+ /* If this is the fourth escape, get out */
+ if (++escape_count == 4)
+ {
+ return ENTER_DEBUG;
+ }
+ else
+ { /* This is a '|', but not the fourth in a row.
+ Continue without echoing it. If it isn't actually
+ one of four in a row, it'll be echoed later. */
+ continue;
+ }
+ }
+ else
+ /* Not a '|' */
+ {
+ /* Ensure any pending '|'s are flushed. */
+
+ for (; escape_count > 0; escape_count--)
+ putchar ('|');
+ }
+
+ if (data == '\r') /* If this is a return character, */
+ continue; /* - just supress it. */
+
+ if (echo_check != -1) /* Check for echo of user input. */
+ {
+ if (tty_input[echo_check] == data)
+ {
+ echo_check++; /* Character matched user input: */
+ continue; /* Continue without echoing it. */
+ }
+ else if ((data == '\n') && (tty_input[echo_check] == '\r'))
+ { /* End of the line (and of echo checking). */
+ echo_check = -1; /* No more echo supression */
+ continue; /* Continue without echoing. */
+ }
+ else
+ { /* Failed check for echo of user input.
+ We now have some suppressed output to flush! */
+ int j;
+
+ for (j = 0; j < echo_check; j++)
+ putchar (tty_input[j]);
+ echo_check = -1;
+ }
+ }
+ putchar (data); /* Default case: output the char. */
+ }
+
+ if (data == SERIAL_TIMEOUT) /* Timeout returned from readchar. */
+ return READ_MORE; /* Try to read some more */
+ else
+ return FATAL_ERROR; /* Trouble, bail out */
+}
+
+static int
+readtty (void)
+{
+ int tty_bytecount;
+
+ /* First, read a buffer full from the terminal */
+ tty_bytecount = read (fileno (stdin), tty_input, sizeof (tty_input) - 1);
+ if (tty_bytecount == -1)
+ {
+ perror ("readtty: read failed");
+ return FATAL_ERROR;
+ }
+
+ /* Remove a quoted newline. */
+ if (tty_input[tty_bytecount - 1] == '\n' &&
+ tty_input[tty_bytecount - 2] == '\\') /* line ending in backslash */
+ {
+ tty_input[--tty_bytecount] = 0; /* remove newline */
+ tty_input[--tty_bytecount] = 0; /* remove backslash */
+ }
+
+ /* Turn trailing newlines into returns */
+ if (tty_input[tty_bytecount - 1] == '\n')
+ tty_input[tty_bytecount - 1] = '\r';
+
+ /* If the line consists of a ~, enter debugging mode. */
+ if ((tty_input[0] == '~') && (tty_bytecount == 2))
+ return ENTER_DEBUG;
+
+ /* Make this a zero terminated string and write it out */
+ tty_input[tty_bytecount] = 0;
+ if (SERIAL_WRITE (remote_desc, tty_input, tty_bytecount))
+ {
+ perror_with_name ("readtty: write failed");
+ return FATAL_ERROR;
+ }
+
+ return READ_MORE;
+}
+
+static int
+minitelnet (void)
+{
+ fd_set input; /* file descriptors for select */
+ int tablesize; /* max number of FDs for select */
+ int status;
+ int quit_count = 0;
+
+ extern int escape_count; /* global shared by readsocket */
+ extern int echo_check; /* ditto */
+
+ escape_count = 0;
+ echo_check = -1;
+
+ tablesize = 8 * sizeof (input);
+
+ for (;;)
+ {
+ /* Check for anything from our socket - doesn't block. Note that
+ this must be done *before* the select as there may be
+ buffered I/O waiting to be processed. */
+
+ if ((status = readsocket ()) == FATAL_ERROR)
+ {
+ error ("Debugging terminated by communications error");
+ }
+ else if (status != READ_MORE)
+ {
+ return (status);
+ }
+
+ fflush (stdout); /* Flush output before blocking */
+
+ /* Now block on more socket input or TTY input */
+
+ FD_ZERO (&input);
+ FD_SET (fileno (stdin), &input);
+ FD_SET (DEPRECATED_SERIAL_FD (remote_desc), &input);
+
+ status = select (tablesize, &input, 0, 0, 0);
+ if ((status == -1) && (errno != EINTR))
+ {
+ error ("Communications error on select %d", errno);
+ }
+
+ /* Handle Control-C typed */
+
+ if (quit_flag)
+ {
+ if ((++quit_count) == 2)
+ {
+ if (query ("Interrupt GDB? "))
+ {
+ printf_filtered ("Interrupted by user.\n");
+ return_to_top_level (RETURN_QUIT);
+ }
+ quit_count = 0;
+ }
+ quit_flag = 0;
+
+ if (remote_break)
+ SERIAL_SEND_BREAK (remote_desc);
+ else
+ SERIAL_WRITE (remote_desc, "\003", 1);
+
+ continue;
+ }
+
+ /* Handle console input */
+
+ if (FD_ISSET (fileno (stdin), &input))
+ {
+ quit_count = 0;
+ echo_check = 0;
+ status = readtty ();
+ if (status == READ_MORE)
+ continue;
+
+ return status; /* telnet session ended */
+ }
+ }
+}
+
+static int
+remote_cisco_wait (int pid, struct target_waitstatus *status)
+{
+ if (minitelnet () != ENTER_DEBUG)
+ {
+ error ("Debugging session terminated by protocol error");
+ }
+ putpkt ("?");
+ return remote_wait (pid, status);
+}
+
+static void
+init_remote_cisco_ops (void)
+{
+ remote_cisco_ops.to_shortname = "cisco";
+ remote_cisco_ops.to_longname = "Remote serial target in cisco-specific protocol";
+ remote_cisco_ops.to_doc =
+ "Use a remote machine via TCP, using a cisco-specific protocol.\n\
+Specify the serial device it is connected to (e.g. host:2020).";
+ remote_cisco_ops.to_open = remote_cisco_open;
+ remote_cisco_ops.to_close = remote_cisco_close;
+ remote_cisco_ops.to_detach = remote_detach;
+ remote_cisco_ops.to_resume = remote_resume;
+ remote_cisco_ops.to_wait = remote_cisco_wait;
+ remote_cisco_ops.to_fetch_registers = remote_fetch_registers;
+ remote_cisco_ops.to_store_registers = remote_store_registers;
+ remote_cisco_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_cisco_ops.to_xfer_memory = remote_xfer_memory;
+ remote_cisco_ops.to_files_info = remote_files_info;
+ remote_cisco_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_cisco_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_cisco_ops.to_kill = remote_kill;
+ remote_cisco_ops.to_load = generic_load;
+ remote_cisco_ops.to_mourn_inferior = remote_cisco_mourn;
+ remote_cisco_ops.to_thread_alive = remote_thread_alive;
+ remote_cisco_ops.to_find_new_threads = remote_threads_info;
+ remote_ops.to_extra_thread_info = remote_threads_extra_info;
+ remote_cisco_ops.to_stratum = process_stratum;
+ remote_cisco_ops.to_has_all_memory = 1;
+ remote_cisco_ops.to_has_memory = 1;
+ remote_cisco_ops.to_has_stack = 1;
+ remote_cisco_ops.to_has_registers = 1;
+ remote_cisco_ops.to_has_execution = 1;
+ remote_cisco_ops.to_magic = OPS_MAGIC;
+}
+
+static int
+remote_can_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return (current_target.to_async_mask_value) && SERIAL_CAN_ASYNC_P (remote_desc);
+}
+
+static int
+remote_is_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return (current_target.to_async_mask_value) && SERIAL_IS_ASYNC_P (remote_desc);
+}
+
+/* Pass the SERIAL event on and up to the client. One day this code
+ will be able to delay notifying the client of an event until the
+ point where an entire packet has been received. */
+
+static void (*async_client_callback) (enum inferior_event_type event_type, void *context);
+static void *async_client_context;
+static serial_event_ftype remote_async_serial_handler;
+
+static void
+remote_async_serial_handler (serial_t scb, void *context)
+{
+ /* Don't propogate error information up to the client. Instead let
+ the client find out about the error by querying the target. */
+ async_client_callback (INF_REG_EVENT, async_client_context);
+}
+
+static void
+remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context)
+{
+ if (current_target.to_async_mask_value == 0)
+ internal_error ("Calling remote_async when async is masked");
+
+ if (callback != NULL)
+ {
+ SERIAL_ASYNC (remote_desc, remote_async_serial_handler, NULL);
+ async_client_callback = callback;
+ async_client_context = context;
+ }
+ else
+ SERIAL_ASYNC (remote_desc, NULL, NULL);
+}
+
+/* Target async and target extended-async.
+
+ This are temporary targets, until it is all tested. Eventually
+ async support will be incorporated int the usual 'remote'
+ target. */
+
+static void
+init_remote_async_ops (void)
+{
+ remote_async_ops.to_shortname = "async";
+ remote_async_ops.to_longname = "Remote serial target in async version of the gdb-specific protocol";
+ remote_async_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_async_ops.to_open = remote_async_open;
+ remote_async_ops.to_close = remote_close;
+ remote_async_ops.to_detach = remote_async_detach;
+ remote_async_ops.to_resume = remote_async_resume;
+ remote_async_ops.to_wait = remote_async_wait;
+ remote_async_ops.to_fetch_registers = remote_fetch_registers;
+ remote_async_ops.to_store_registers = remote_store_registers;
+ remote_async_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_async_ops.to_xfer_memory = remote_xfer_memory;
+ remote_async_ops.to_files_info = remote_files_info;
+ remote_async_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_async_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_async_ops.to_terminal_inferior = remote_async_terminal_inferior;
+ remote_async_ops.to_terminal_ours = remote_async_terminal_ours;
+ remote_async_ops.to_kill = remote_async_kill;
+ remote_async_ops.to_load = generic_load;
+ remote_async_ops.to_mourn_inferior = remote_async_mourn;
+ remote_async_ops.to_thread_alive = remote_thread_alive;
+ remote_async_ops.to_find_new_threads = remote_threads_info;
+ remote_ops.to_extra_thread_info = remote_threads_extra_info;
+ remote_async_ops.to_stop = remote_stop;
+ remote_async_ops.to_query = remote_query;
+ remote_async_ops.to_rcmd = remote_rcmd;
+ remote_async_ops.to_stratum = process_stratum;
+ remote_async_ops.to_has_all_memory = 1;
+ remote_async_ops.to_has_memory = 1;
+ remote_async_ops.to_has_stack = 1;
+ remote_async_ops.to_has_registers = 1;
+ remote_async_ops.to_has_execution = 1;
+ remote_async_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_async_ops.to_can_async_p = remote_can_async_p;
+ remote_async_ops.to_is_async_p = remote_is_async_p;
+ remote_async_ops.to_async = remote_async;
+ remote_async_ops.to_async_mask_value = 1;
+ remote_async_ops.to_magic = OPS_MAGIC;
+}
+
+/* Set up the async extended remote vector by making a copy of the standard
+ remote vector and adding to it. */
+
+static void
+init_extended_async_remote_ops (void)
+{
+ extended_async_remote_ops = remote_async_ops;
+
+ extended_async_remote_ops.to_shortname = "extended-async";
+ extended_async_remote_ops.to_longname =
+ "Extended remote serial target in async gdb-specific protocol";
+ extended_async_remote_ops.to_doc =
+ "Use a remote computer via a serial line, using an async gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).",
+ extended_async_remote_ops.to_open = extended_remote_async_open;
+ extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior;
+ extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn;
+}
+
+static void
+set_remote_cmd (char *args, int from_tty)
+{
+
+}
+
+static void
+show_remote_cmd (char *args, int from_tty)
+{
+ show_remote_protocol_Z_packet_cmd (args, from_tty);
+ show_remote_protocol_P_packet_cmd (args, from_tty);
+ show_remote_protocol_binary_download_cmd (args, from_tty);
+}
+
+static void
+build_remote_gdbarch_data (void)
+{
+ build_remote_packet_sizes ();
+
+ /* Cisco stuff */
+ tty_input = xmalloc (PBUFSIZ);
+ remote_address_size = TARGET_PTR_BIT;
+}
void
-_initialize_remote ()
+_initialize_remote (void)
{
+ static struct cmd_list_element *remote_set_cmdlist;
+ static struct cmd_list_element *remote_show_cmdlist;
+ struct cmd_list_element *tmpcmd;
+
+ /* architecture specific data */
+ build_remote_gdbarch_data ();
+ register_gdbarch_swap (&tty_input, sizeof (&tty_input), NULL);
+ register_remote_packet_sizes ();
+ register_gdbarch_swap (&remote_address_size,
+ sizeof (&remote_address_size), NULL);
+ register_gdbarch_swap (NULL, 0, build_remote_gdbarch_data);
+
init_remote_ops ();
add_target (&remote_ops);
init_extended_remote_ops ();
add_target (&extended_remote_ops);
- init_remote_threads ();
+
+ init_remote_async_ops ();
+ add_target (&remote_async_ops);
+
+ init_extended_async_remote_ops ();
+ add_target (&extended_async_remote_ops);
+
+ init_remote_cisco_ops ();
+ add_target (&remote_cisco_ops);
+
#if 0
init_remote_threadtests ();
#endif
- add_cmd ("compare-sections", class_obscure, compare_sections_command,
+ /* set/show remote ... */
+
+ add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, "\
+Remote protocol specific variables\n\
+Configure various remote-protocol specific variables such as\n\
+the packets being used",
+ &remote_set_cmdlist, "set remote ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("remote", class_maintenance, show_remote_cmd, "\
+Remote protocol specific variables\n\
+Configure various remote-protocol specific variables such as\n\
+the packets being used",
+ &remote_show_cmdlist, "show remote ",
+ 0/*allow-unknown*/, &showlist);
+
+ 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).",
+Argument is a single section name (default: all loaded sections).",
&cmdlist);
add_cmd ("packet", class_maintenance, packet_command,
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),
- &showlist);
-
- add_show_from_set
+ add_show_from_set
(add_set_cmd ("remotebreak", no_class,
- var_integer, (char *)&remote_break,
+ var_boolean, (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 per memory write packet.\n",
- &setlist),
- &showlist);
-
- remote_address_size = TARGET_PTR_BIT;
- add_show_from_set
+ /* Install commands for configuring memory read/write packets. */
+
+ add_cmd ("remotewritesize", no_class, set_memory_write_packet_size,
+ "Set the maximum number of bytes per memory write packet (deprecated).\n",
+ &setlist);
+ add_cmd ("remotewritesize", no_class, show_memory_write_packet_size,
+ "Show the maximum number of bytes per memory write packet (deprecated).\n",
+ &showlist);
+ add_cmd ("memory-write-packet-size", no_class,
+ set_memory_write_packet_size,
+ "Set the maximum number of bytes per memory-write packet.\n"
+ "Specify the number of bytes in a packet or 0 (zero) for the\n"
+ "default packet size. The actual limit is further reduced\n"
+ "dependent on the target. Specify ``fixed'' to disable the\n"
+ "further restriction and ``limit'' to enable that restriction\n",
+ &remote_set_cmdlist);
+ add_cmd ("memory-read-packet-size", no_class,
+ set_memory_read_packet_size,
+ "Set the maximum number of bytes per memory-read packet.\n"
+ "Specify the number of bytes in a packet or 0 (zero) for the\n"
+ "default packet size. The actual limit is further reduced\n"
+ "dependent on the target. Specify ``fixed'' to disable the\n"
+ "further restriction and ``limit'' to enable that restriction\n",
+ &remote_set_cmdlist);
+ add_cmd ("memory-write-packet-size", no_class,
+ show_memory_write_packet_size,
+ "Show the maximum number of bytes per memory-write packet.\n",
+ &remote_show_cmdlist);
+ add_cmd ("memory-read-packet-size", no_class,
+ show_memory_read_packet_size,
+ "Show the maximum number of bytes per memory-read packet.\n",
+ &remote_show_cmdlist);
+
+ add_show_from_set
(add_set_cmd ("remoteaddresssize", class_obscure,
- var_integer, (char *)&remote_address_size,
+ var_integer, (char *) &remote_address_size,
"Set the maximum size of the address (in bits) \
in a memory packet.\n",
&setlist),
- &showlist);
+ &showlist);
+
+ add_packet_config_cmd (&remote_protocol_binary_download,
+ "X", "binary-download",
+ set_remote_protocol_binary_download_cmd,
+ show_remote_protocol_binary_download_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 1);
+#if 0
+ /* XXXX - should ``set remotebinarydownload'' be retained for
+ compatibility. */
+ add_show_from_set
+ (add_set_cmd ("remotebinarydownload", no_class,
+ var_boolean, (char *) &remote_binary_download,
+ "Set binary downloads.\n", &setlist),
+ &showlist);
+#endif
+
+ add_info ("remote-process", remote_info_process,
+ "Query the remote system for process info.");
+
+ add_packet_config_cmd (&remote_protocol_P,
+ "P", "set-register",
+ set_remote_protocol_P_packet_cmd,
+ show_remote_protocol_P_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 1);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP],
+ "Z0", "software-breakpoint",
+ set_remote_protocol_Z_software_bp_packet_cmd,
+ show_remote_protocol_Z_software_bp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP],
+ "Z1", "hardware-breakpoint",
+ set_remote_protocol_Z_hardware_bp_packet_cmd,
+ show_remote_protocol_Z_hardware_bp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP],
+ "Z2", "write-watchpoint",
+ set_remote_protocol_Z_write_wp_packet_cmd,
+ show_remote_protocol_Z_write_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP],
+ "Z3", "read-watchpoint",
+ set_remote_protocol_Z_read_wp_packet_cmd,
+ show_remote_protocol_Z_read_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP],
+ "Z4", "access-watchpoint",
+ set_remote_protocol_Z_access_wp_packet_cmd,
+ show_remote_protocol_Z_access_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ /* Keep the old ``set remote Z-packet ...'' working. */
+ tmpcmd = add_set_auto_boolean_cmd ("Z-packet", class_obscure,
+ &remote_Z_packet_detect,
+ "\
+Set use of remote protocol `Z' packets", &remote_set_cmdlist);
+ tmpcmd->function.sfunc = set_remote_protocol_Z_packet_cmd;
+ add_cmd ("Z-packet", class_obscure, show_remote_protocol_Z_packet_cmd,
+ "Show use of remote protocol `Z' packets ",
+ &remote_show_cmdlist);
}