blob: 1c9367d2b0f569416588d3786d4a934e223d80a1 [file] [log] [blame]
/* Remote target communications for serial-line targets in custom GDB protocol
Copyright (C) 1988-2012 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 3 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, see <http://www.gnu.org/licenses/>. */
/* 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 "inferior.h"
#include "bfd.h"
#include "symfile.h"
#include "exceptions.h"
#include "target.h"
/*#include "terminal.h" */
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
#include "gdbthread.h"
#include "remote.h"
#include "regcache.h"
#include "value.h"
#include "gdb_assert.h"
#include "observer.h"
#include "solib.h"
#include "cli/cli-decode.h"
#include "cli/cli-setshow.h"
#include "target-descriptions.h"
#include <ctype.h>
#include <sys/time.h>
#include "event-loop.h"
#include "event-top.h"
#include "inf-loop.h"
#include <signal.h>
#include "serial.h"
#include "gdbcore.h" /* for exec_bfd */
#include "remote-fileio.h"
#include "gdb/fileio.h"
#include "gdb_stat.h"
#include "xml-support.h"
#include "memory-map.h"
#include "tracepoint.h"
#include "ax.h"
#include "ax-gdb.h"
#include "agent.h"
/* Temp hacks for tracepoint encoding migration. */
static char *target_buf;
static long target_buf_size;
/* The size to align memory write packets, when practical. The protocol
does not guarantee any alignment, and gdb will generate short
writes and unaligned writes, but even as a best-effort attempt this
can improve bulk transfers. For instance, if a write is misaligned
relative to the target's data bus, the stub may need to make an extra
round trip fetching data from the target. This doesn't make a
huge difference, but it's easy to do, so we try to be helpful.
The alignment chosen is arbitrary; usually data bus width is
important here, not the possibly larger cache line size. */
enum { REMOTE_ALIGN_WRITES = 16 };
/* 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 getpkt_or_notif_sane (char **buf, long *sizeof_buf,
int forever);
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 void remote_files_info (struct target_ops *ignore);
static void remote_prepare_to_store (struct regcache *regcache);
static void remote_open (char *name, int from_tty);
static void extended_remote_open (char *name, int from_tty);
static void remote_open_1 (char *, int, struct target_ops *, int extended_p);
static void remote_close (int quitting);
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
static void extended_remote_mourn (struct target_ops *);
static void remote_mourn_1 (struct target_ops *);
static void remote_send (char **buf, long *sizeof_buf_p);
static int readchar (int timeout);
static void remote_kill (struct target_ops *ops);
static int tohex (int nib);
static int remote_can_async_p (void);
static int remote_is_async_p (void);
static void remote_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context);
static void remote_detach (struct target_ops *ops, char *args, int from_tty);
static void remote_interrupt (int signo);
static void remote_interrupt_twice (int signo);
static void interrupt_query (void);
static void set_general_thread (struct ptid ptid);
static void set_continue_thread (struct ptid ptid);
static void get_offsets (void);
static void skip_frame (void);
static long read_frame (char **buf_p, long *sizeof_buf);
static int hexnumlen (ULONGEST num);
static void init_remote_ops (void);
static void init_extended_remote_ops (void);
static void remote_stop (ptid_t);
static int ishex (int ch, int *val);
static int stubhex (int ch);
static int hexnumstr (char *, ULONGEST);
static int hexnumnstr (char *, ULONGEST, int);
static CORE_ADDR remote_address_masked (CORE_ADDR);
static void print_packet (char *);
static void compare_sections_command (char *, int);
static void packet_command (char *, int);
static int stub_unpack_int (char *buff, int fieldlength);
static ptid_t remote_current_thread (ptid_t oldptid);
static void remote_find_new_threads (void);
static void record_currthread (ptid_t currthread);
static int fromhex (int a);
extern int hex2bin (const char *hex, gdb_byte *bin, int count);
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
static int putpkt_binary (char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
struct packet_config;
static void show_packet_config_cmd (struct packet_config *config);
static void update_packet_config (struct packet_config *config);
static void set_remote_protocol_packet_cmd (char *args, int from_tty,
struct cmd_list_element *c);
static void show_remote_protocol_packet_cmd (struct ui_file *file,
int from_tty,
struct cmd_list_element *c,
const char *value);
static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
static ptid_t read_ptid (char *buf, char **obuf);
static void remote_set_permissions (void);
struct remote_state;
static int remote_get_trace_status (struct trace_status *ts);
static int remote_upload_tracepoints (struct uploaded_tp **utpp);
static int remote_upload_trace_state_variables (struct uploaded_tsv **utsvp);
static void remote_query_supported (void);
static void remote_check_symbols (struct objfile *objfile);
void _initialize_remote (void);
struct stop_reply;
static struct stop_reply *stop_reply_xmalloc (void);
static void stop_reply_xfree (struct stop_reply *);
static void do_stop_reply_xfree (void *arg);
static void remote_parse_stop_reply (char *buf, struct stop_reply *);
static void push_stop_reply (struct stop_reply *);
static void remote_get_pending_stop_replies (void);
static void discard_pending_stop_replies (int pid);
static int peek_stop_reply (ptid_t ptid);
static void remote_async_inferior_event_handler (gdb_client_data);
static void remote_async_get_pending_events_handler (gdb_client_data);
static void remote_terminal_ours (void);
static int remote_read_description_p (struct target_ops *target);
static void remote_console_output (char *msg);
static int remote_supports_cond_breakpoints (void);
static int remote_can_run_breakpoint_commands (void);
/* The non-stop remote protocol provisions for one pending stop reply.
This is where we keep it until it is acknowledged. */
static struct stop_reply *pending_stop_reply = NULL;
/* For "remote". */
static struct cmd_list_element *remote_cmdlist;
/* For "set remote" and "show remote". */
static struct cmd_list_element *remote_set_cmdlist;
static struct cmd_list_element *remote_show_cmdlist;
/* Description of the remote protocol state for the currently
connected target. This is per-target state, and independent of the
selected architecture. */
struct remote_state
{
/* A buffer to use for incoming packets, and its current size. The
buffer is grown dynamically for larger incoming packets.
Outgoing packets may also be constructed in this buffer.
BUF_SIZE is always at least REMOTE_PACKET_SIZE;
REMOTE_PACKET_SIZE should be used to limit the length of outgoing
packets. */
char *buf;
long buf_size;
/* True if we're going through initial connection setup (finding out
about the remote side's threads, relocating symbols, etc.). */
int starting_up;
/* If we negotiated packet size explicitly (and thus can bypass
heuristics for the largest packet size that will not overflow
a buffer in the stub), this will be set to that packet size.
Otherwise zero, meaning to use the guessed size. */
long explicit_packet_size;
/* remote_wait is normally called when the target is running and
waits for a stop reply packet. But sometimes we need to call it
when the target is already stopped. We can send a "?" packet
and have remote_wait read the response. Or, if we already have
the response, we can stash it in BUF and tell remote_wait to
skip calling getpkt. This flag is set when BUF contains a
stop reply packet and the target is not waiting. */
int cached_wait_status;
/* True, if in no ack mode. That is, neither GDB nor the stub will
expect acks from each other. The connection is assumed to be
reliable. */
int noack_mode;
/* True if we're connected in extended remote mode. */
int extended;
/* True if the stub reported support for multi-process
extensions. */
int multi_process_aware;
/* True if we resumed the target and we're waiting for the target to
stop. In the mean time, we can't start another command/query.
The remote server wouldn't be ready to process it, so we'd
timeout waiting for a reply that would never come and eventually
we'd close the connection. This can happen in asynchronous mode
because we allow GDB commands while the target is running. */
int waiting_for_stop_reply;
/* True if the stub reports support for non-stop mode. */
int non_stop_aware;
/* True if the stub reports support for vCont;t. */
int support_vCont_t;
/* True if the stub reports support for conditional tracepoints. */
int cond_tracepoints;
/* True if the stub reports support for target-side breakpoint
conditions. */
int cond_breakpoints;
/* True if the stub reports support for target-side breakpoint
commands. */
int breakpoint_commands;
/* True if the stub reports support for fast tracepoints. */
int fast_tracepoints;
/* True if the stub reports support for static tracepoints. */
int static_tracepoints;
/* True if the stub reports support for installing tracepoint while
tracing. */
int install_in_trace;
/* True if the stub can continue running a trace while GDB is
disconnected. */
int disconnected_tracing;
/* True if the stub reports support for enabling and disabling
tracepoints while a trace experiment is running. */
int enable_disable_tracepoints;
/* True if the stub can collect strings using tracenz bytecode. */
int string_tracing;
/* Nonzero if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
int ctrlc_pending_p;
};
/* Private data that we'll store in (struct thread_info)->private. */
struct private_thread_info
{
char *extra;
int core;
};
static void
free_private_thread_info (struct private_thread_info *info)
{
xfree (info->extra);
xfree (info);
}
/* Returns true if the multi-process extensions are in effect. */
static int
remote_multi_process_p (struct remote_state *rs)
{
return rs->multi_process_aware;
}
/* This data could be associated with a target, but we do not always
have access to the current target when we need it, so for now it is
static. This will be fine for as long as only one target is in use
at a time. */
static struct remote_state remote_state;
static struct remote_state *
get_remote_state_raw (void)
{
return &remote_state;
}
/* Description of the remote protocol for a given architecture. */
struct packet_reg
{
long offset; /* Offset into G packet. */
long regnum; /* GDB's internal register number. */
LONGEST pnum; /* Remote protocol register number. */
int in_g_packet; /* Always part of G packet. */
/* long size in bytes; == register_size (target_gdbarch, regnum);
at present. */
/* char *name; == gdbarch_register_name (target_gdbarch, regnum);
at present. */
};
struct remote_arch_state
{
/* Description of the remote protocol registers. */
long sizeof_g_packet;
/* Description of the remote protocol registers indexed by REGNUM
(making an array gdbarch_num_regs in size). */
struct packet_reg *regs;
/* 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). */
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. */
long remote_packet_size;
};
long sizeof_pkt = 2000;
/* Utility: generate error from an incoming stub packet. */
static void
trace_error (char *buf)
{
if (*buf++ != 'E')
return; /* not an error msg */
switch (*buf)
{
case '1': /* malformed packet error */
if (*++buf == '0') /* general case: */
error (_("remote.c: error in outgoing packet."));
else
error (_("remote.c: error in outgoing packet at field #%ld."),
strtol (buf, NULL, 16));
case '2':
error (_("trace API error 0x%s."), ++buf);
default:
error (_("Target returns error code '%s'."), buf);
}
}
/* Utility: wait for reply from stub, while accepting "O" packets. */
static char *
remote_get_noisy_reply (char **buf_p,
long *sizeof_buf)
{
do /* Loop on reply from remote stub. */
{
char *buf;
QUIT; /* Allow user to bail out with ^C. */
getpkt (buf_p, sizeof_buf, 0);
buf = *buf_p;
if (buf[0] == 'E')
trace_error (buf);
else if (strncmp (buf, "qRelocInsn:", strlen ("qRelocInsn:")) == 0)
{
ULONGEST ul;
CORE_ADDR from, to, org_to;
char *p, *pp;
int adjusted_size = 0;
volatile struct gdb_exception ex;
p = buf + strlen ("qRelocInsn:");
pp = unpack_varlen_hex (p, &ul);
if (*pp != ';')
error (_("invalid qRelocInsn packet: %s"), buf);
from = ul;
p = pp + 1;
unpack_varlen_hex (p, &ul);
to = ul;
org_to = to;
TRY_CATCH (ex, RETURN_MASK_ALL)
{
gdbarch_relocate_instruction (target_gdbarch, &to, from);
}
if (ex.reason >= 0)
{
adjusted_size = to - org_to;
xsnprintf (buf, *sizeof_buf, "qRelocInsn:%x", adjusted_size);
putpkt (buf);
}
else if (ex.reason < 0 && ex.error == MEMORY_ERROR)
{
/* Propagate memory errors silently back to the target.
The stub may have limited the range of addresses we
can write to, for example. */
putpkt ("E01");
}
else
{
/* Something unexpectedly bad happened. Be verbose so
we can tell what, and propagate the error back to the
stub, so it doesn't get stuck waiting for a
response. */
exception_fprintf (gdb_stderr, ex,
_("warning: relocating instruction: "));
putpkt ("E01");
}
}
else if (buf[0] == 'O' && buf[1] != 'K')
remote_console_output (buf + 1); /* 'O' message from stub */
else
return buf; /* Here's the actual reply. */
}
while (1);
}
/* Handle for retreving the remote protocol data from gdbarch. */
static struct gdbarch_data *remote_gdbarch_data_handle;
static struct remote_arch_state *
get_remote_arch_state (void)
{
return gdbarch_data (target_gdbarch, remote_gdbarch_data_handle);
}
/* Fetch the global remote target state. */
static struct remote_state *
get_remote_state (void)
{
/* Make sure that the remote architecture state has been
initialized, because doing so might reallocate rs->buf. Any
function which calls getpkt also needs to be mindful of changes
to rs->buf, but this call limits the number of places which run
into trouble. */
get_remote_arch_state ();
return get_remote_state_raw ();
}
static int
compare_pnums (const void *lhs_, const void *rhs_)
{
const struct packet_reg * const *lhs = lhs_;
const struct packet_reg * const *rhs = rhs_;
if ((*lhs)->pnum < (*rhs)->pnum)
return -1;
else if ((*lhs)->pnum == (*rhs)->pnum)
return 0;
else
return 1;
}
static int
map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs)
{
int regnum, num_remote_regs, offset;
struct packet_reg **remote_regs;
for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++)
{
struct packet_reg *r = &regs[regnum];
if (register_size (gdbarch, regnum) == 0)
/* Do not try to fetch zero-sized (placeholder) registers. */
r->pnum = -1;
else
r->pnum = gdbarch_remote_register_number (gdbarch, regnum);
r->regnum = regnum;
}
/* Define the g/G packet format as the contents of each register
with a remote protocol number, in order of ascending protocol
number. */
remote_regs = alloca (gdbarch_num_regs (gdbarch)
* sizeof (struct packet_reg *));
for (num_remote_regs = 0, regnum = 0;
regnum < gdbarch_num_regs (gdbarch);
regnum++)
if (regs[regnum].pnum != -1)
remote_regs[num_remote_regs++] = &regs[regnum];
qsort (remote_regs, num_remote_regs, sizeof (struct packet_reg *),
compare_pnums);
for (regnum = 0, offset = 0; regnum < num_remote_regs; regnum++)
{
remote_regs[regnum]->in_g_packet = 1;
remote_regs[regnum]->offset = offset;
offset += register_size (gdbarch, remote_regs[regnum]->regnum);
}
return offset;
}
/* Given the architecture described by GDBARCH, return the remote
protocol register's number and the register's offset in the g/G
packets of GDB register REGNUM, in PNUM and POFFSET respectively.
If the target does not have a mapping for REGNUM, return false,
otherwise, return true. */
int
remote_register_number_and_offset (struct gdbarch *gdbarch, int regnum,
int *pnum, int *poffset)
{
int sizeof_g_packet;
struct packet_reg *regs;
struct cleanup *old_chain;
gdb_assert (regnum < gdbarch_num_regs (gdbarch));
regs = xcalloc (gdbarch_num_regs (gdbarch), sizeof (struct packet_reg));
old_chain = make_cleanup (xfree, regs);
sizeof_g_packet = map_regcache_remote_table (gdbarch, regs);
*pnum = regs[regnum].pnum;
*poffset = regs[regnum].offset;
do_cleanups (old_chain);
return *pnum != -1;
}
static void *
init_remote_state (struct gdbarch *gdbarch)
{
struct remote_state *rs = get_remote_state_raw ();
struct remote_arch_state *rsa;
rsa = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_arch_state);
/* Use the architecture to build a regnum<->pnum table, which will be
1:1 unless a feature set specifies otherwise. */
rsa->regs = GDBARCH_OBSTACK_CALLOC (gdbarch,
gdbarch_num_regs (gdbarch),
struct packet_reg);
/* Record the maximum possible size of the g packet - it may turn out
to be smaller. */
rsa->sizeof_g_packet = map_regcache_remote_table (gdbarch, rsa->regs);
/* 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). */
rsa->remote_packet_size = 400 - 1;
/* This one is filled in when a ``g'' packet is received. */
rsa->actual_register_packet_size = 0;
/* Should rsa->sizeof_g_packet 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 (rsa->sizeof_g_packet > ((rsa->remote_packet_size - 32) / 2))
rsa->remote_packet_size = (rsa->sizeof_g_packet * 2 + 32);
/* Make sure that the packet buffer is plenty big enough for
this architecture. */
if (rs->buf_size < rsa->remote_packet_size)
{
rs->buf_size = 2 * rsa->remote_packet_size;
rs->buf = xrealloc (rs->buf, rs->buf_size);
}
return rsa;
}
/* Return the current allowed size of a remote packet. This is
inferred from the current architecture, and should be used to
limit the length of outgoing packets. */
static long
get_remote_packet_size (void)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
if (rs->explicit_packet_size)
return rs->explicit_packet_size;
return rsa->remote_packet_size;
}
static struct packet_reg *
packet_reg_from_regnum (struct remote_arch_state *rsa, long regnum)
{
if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch))
return NULL;
else
{
struct packet_reg *r = &rsa->regs[regnum];
gdb_assert (r->regnum == regnum);
return r;
}
}
static struct packet_reg *
packet_reg_from_pnum (struct remote_arch_state *rsa, LONGEST pnum)
{
int i;
for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
{
struct packet_reg *r = &rsa->regs[i];
if (r->pnum == pnum)
return r;
}
return NULL;
}
/* FIXME: graces/2002-08-08: These variables should eventually be
bound to an instance of the target object (as in gdbarch-tdep()),
when such a thing exists. */
/* This is set to the data address of the access causing the target
to stop for a watchpoint. */
static CORE_ADDR remote_watch_data_address;
/* This is non-zero if target stopped for a watchpoint. */
static int remote_stopped_by_watchpoint_p;
static struct target_ops remote_ops;
static struct target_ops extended_remote_ops;
/* 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;
/* Allow the user to specify what sequence to send to the remote
when he requests a program interruption: Although ^C is usually
what remote systems expect (this is the default, here), it is
sometimes preferable to send a break. On other systems such
as the Linux kernel, a break followed by g, which is Magic SysRq g
is required in order to interrupt the execution. */
const char interrupt_sequence_control_c[] = "Ctrl-C";
const char interrupt_sequence_break[] = "BREAK";
const char interrupt_sequence_break_g[] = "BREAK-g";
static const char *const interrupt_sequence_modes[] =
{
interrupt_sequence_control_c,
interrupt_sequence_break,
interrupt_sequence_break_g,
NULL
};
static const char *interrupt_sequence_mode = interrupt_sequence_control_c;
static void
show_interrupt_sequence (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
if (interrupt_sequence_mode == interrupt_sequence_control_c)
fprintf_filtered (file,
_("Send the ASCII ETX character (Ctrl-c) "
"to the remote target to interrupt the "
"execution of the program.\n"));
else if (interrupt_sequence_mode == interrupt_sequence_break)
fprintf_filtered (file,
_("send a break signal to the remote target "
"to interrupt the execution of the program.\n"));
else if (interrupt_sequence_mode == interrupt_sequence_break_g)
fprintf_filtered (file,
_("Send a break signal and 'g' a.k.a. Magic SysRq g to "
"the remote target to interrupt the execution "
"of Linux kernel.\n"));
else
internal_error (__FILE__, __LINE__,
_("Invalid value for interrupt_sequence_mode: %s."),
interrupt_sequence_mode);
}
/* This boolean variable specifies whether interrupt_sequence is sent
to the remote target when gdb connects to it.
This is mostly needed when you debug the Linux kernel: The Linux kernel
expects BREAK g which is Magic SysRq g for connecting gdb. */
static int interrupt_on_connect = 0;
/* This variable is used to implement the "set/show remotebreak" commands.
Since these commands are now deprecated in favor of "set/show remote
interrupt-sequence", it no longer has any effect on the code. */
static int remote_break;
static void
set_remotebreak (char *args, int from_tty, struct cmd_list_element *c)
{
if (remote_break)
interrupt_sequence_mode = interrupt_sequence_break;
else
interrupt_sequence_mode = interrupt_sequence_control_c;
}
static void
show_remotebreak (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
}
/* 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 struct serial *remote_desc = NULL;
/* This variable sets the number of bits in an address that are to be
sent in a memory ("M" or "m") packet. Normally, after stripping
leading zeros, the entire address would be sent. This variable
restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The
initial implementation of remote.c restricted the address sent in
memory packets to ``host::sizeof long'' bytes - (typically 32
bits). Consequently, for 64 bit targets, the upper 32 bits of an
address was never sent. Since fixing this bug may cause a break in
some remote targets this variable is principly provided to
facilitate backward compatibility. */
static int remote_address_size;
/* Temporary to track who currently owns the terminal. See
remote_terminal_* for more details. */
static int remote_async_terminal_ours_p;
/* The executable file to use for "run" on the remote side. */
static char *remote_exec_file = "";
/* User configurable variables for the number of characters in a
memory read/write packet. MIN (rsa->remote_packet_size,
rsa->sizeof_g_packet) 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;
};
/* Compute the current size of a read/write packet. Since this makes
use of ``actual_register_packet_size'' the computation is dynamic. */
static long
get_memory_packet_size (struct memory_packet_config *config)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
/* 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: 20 ensures we can write at least one byte. */
#ifndef MIN_REMOTE_PACKET_SIZE
#define MIN_REMOTE_PACKET_SIZE 20
#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 = 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 unless we have
permission from the stub to use a larger packet size. */
if (rs->explicit_packet_size == 0
&& rsa->actual_register_packet_size > 0
&& what_they_get > rsa->actual_register_packet_size)
what_they_get = rsa->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;
/* Make sure there is room in the global buffer for this packet
(including its trailing NUL byte). */
if (rs->buf_size < what_they_get + 1)
{
rs->buf_size = 2 * what_they_get;
rs->buf = xrealloc (rs->buf, 2 * what_they_get);
}
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 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 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 memory_packet_config memory_write_packet_config =
{
"memory-write-packet-size",
};
static void
set_memory_write_packet_size (char *args, int from_tty)
{
set_memory_packet_size (args, &memory_write_packet_config);
}
static void
show_memory_write_packet_size (char *args, int from_tty)
{
show_memory_packet_size (&memory_write_packet_config);
}
static long
get_memory_write_packet_size (void)
{
return get_memory_packet_size (&memory_write_packet_config);
}
static struct memory_packet_config memory_read_packet_config =
{
"memory-read-packet-size",
};
static void
set_memory_read_packet_size (char *args, int from_tty)
{
set_memory_packet_size (args, &memory_read_packet_config);
}
static void
show_memory_read_packet_size (char *args, int from_tty)
{
show_memory_packet_size (&memory_read_packet_config);
}
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 this. */
if (size > get_remote_packet_size ())
size = get_remote_packet_size ();
return size;
}
/* 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
};
struct packet_config
{
const char *name;
const char *title;
enum auto_boolean detect;
enum packet_support support;
};
/* Analyze a packet's return value and update the packet config
accordingly. */
enum packet_result
{
PACKET_ERROR,
PACKET_OK,
PACKET_UNKNOWN
};
static void
update_packet_config (struct packet_config *config)
{
switch (config->detect)
{
case AUTO_BOOLEAN_TRUE:
config->support = PACKET_ENABLE;
break;
case AUTO_BOOLEAN_FALSE:
config->support = PACKET_DISABLE;
break;
case 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 AUTO_BOOLEAN_AUTO:
printf_filtered (_("Support for the `%s' packet "
"is auto-detected, currently %s.\n"),
config->name, support);
break;
case AUTO_BOOLEAN_TRUE:
case AUTO_BOOLEAN_FALSE:
printf_filtered (_("Support for the `%s' packet is currently %s.\n"),
config->name, support);
break;
}
}
static void
add_packet_config_cmd (struct packet_config *config, const char *name,
const char *title, int legacy)
{
char *set_doc;
char *show_doc;
char *cmd_name;
config->name = name;
config->title = title;
config->detect = AUTO_BOOLEAN_AUTO;
config->support = PACKET_SUPPORT_UNKNOWN;
set_doc = xstrprintf ("Set use of remote protocol `%s' (%s) packet",
name, title);
show_doc = xstrprintf ("Show current use of remote "
"protocol `%s' (%s) packet",
name, title);
/* set/show TITLE-packet {auto,on,off} */
cmd_name = xstrprintf ("%s-packet", title);
add_setshow_auto_boolean_cmd (cmd_name, class_obscure,
&config->detect, set_doc,
show_doc, NULL, /* help_doc */
set_remote_protocol_packet_cmd,
show_remote_protocol_packet_cmd,
&remote_set_cmdlist, &remote_show_cmdlist);
/* The command code copies the documentation strings. */
xfree (set_doc);
xfree (show_doc);
/* set/show remote NAME-packet {auto,on,off} -- legacy. */
if (legacy)
{
char *legacy_name;
legacy_name = xstrprintf ("%s-packet", name);
add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
&remote_set_cmdlist);
add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
&remote_show_cmdlist);
}
}
static enum packet_result
packet_check_result (const char *buf)
{
if (buf[0] != '\0')
{
/* The stub recognized the packet request. Check that the
operation succeeded. */
if (buf[0] == 'E'
&& isxdigit (buf[1]) && isxdigit (buf[2])
&& buf[3] == '\0')
/* "Enn" - definitly an error. */
return PACKET_ERROR;
/* Always treat "E." as an error. This will be used for
more verbose error messages, such as E.memtypes. */
if (buf[0] == 'E' && buf[1] == '.')
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. */
return PACKET_UNKNOWN;
}
static enum packet_result
packet_ok (const char *buf, struct packet_config *config)
{
enum packet_result result;
result = packet_check_result (buf);
switch (result)
{
case PACKET_OK:
case PACKET_ERROR:
/* The stub recognized the packet request. */
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 (__FILE__, __LINE__,
_("packet_ok: attempt to use a disabled packet"));
break;
case PACKET_ENABLE:
break;
}
break;
case PACKET_UNKNOWN:
/* The stub does not support the packet. */
switch (config->support)
{
case PACKET_ENABLE:
if (config->detect == 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;
}
break;
}
return result;
}
enum {
PACKET_vCont = 0,
PACKET_X,
PACKET_qSymbol,
PACKET_P,
PACKET_p,
PACKET_Z0,
PACKET_Z1,
PACKET_Z2,
PACKET_Z3,
PACKET_Z4,
PACKET_vFile_open,
PACKET_vFile_pread,
PACKET_vFile_pwrite,
PACKET_vFile_close,
PACKET_vFile_unlink,
PACKET_vFile_readlink,
PACKET_qXfer_auxv,
PACKET_qXfer_features,
PACKET_qXfer_libraries,
PACKET_qXfer_libraries_svr4,
PACKET_qXfer_memory_map,
PACKET_qXfer_spu_read,
PACKET_qXfer_spu_write,
PACKET_qXfer_osdata,
PACKET_qXfer_threads,
PACKET_qXfer_statictrace_read,
PACKET_qXfer_traceframe_info,
PACKET_qXfer_uib,
PACKET_qGetTIBAddr,
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
PACKET_QProgramSignals,
PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
PACKET_QStartNoAckMode,
PACKET_vKill,
PACKET_qXfer_siginfo_read,
PACKET_qXfer_siginfo_write,
PACKET_qAttached,
PACKET_ConditionalTracepoints,
PACKET_ConditionalBreakpoints,
PACKET_BreakpointCommands,
PACKET_FastTracepoints,
PACKET_StaticTracepoints,
PACKET_InstallInTrace,
PACKET_bc,
PACKET_bs,
PACKET_TracepointSource,
PACKET_QAllow,
PACKET_qXfer_fdpic,
PACKET_QDisableRandomization,
PACKET_QAgent,
PACKET_MAX
};
static struct packet_config remote_protocol_packets[PACKET_MAX];
static void
set_remote_protocol_packet_cmd (char *args, int from_tty,
struct cmd_list_element *c)
{
struct packet_config *packet;
for (packet = remote_protocol_packets;
packet < &remote_protocol_packets[PACKET_MAX];
packet++)
{
if (&packet->detect == c->var)
{
update_packet_config (packet);
return;
}
}
internal_error (__FILE__, __LINE__, _("Could not find config for %s"),
c->name);
}
static void
show_remote_protocol_packet_cmd (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
struct packet_config *packet;
for (packet = remote_protocol_packets;
packet < &remote_protocol_packets[PACKET_MAX];
packet++)
{
if (&packet->detect == c->var)
{
show_packet_config_cmd (packet);
return;
}
}
internal_error (__FILE__, __LINE__, _("Could not find config for %s"),
c->name);
}
/* 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
};
/* For compatibility with older distributions. Provide a ``set remote
Z-packet ...'' command that updates all the Z packet types. */
static enum 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_packets[PACKET_Z0 + i].detect = remote_Z_packet_detect;
update_packet_config (&remote_protocol_packets[PACKET_Z0 + i]);
}
}
static void
show_remote_protocol_Z_packet_cmd (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
int i;
for (i = 0; i < NR_Z_PACKET_TYPES; i++)
{
show_packet_config_cmd (&remote_protocol_packets[PACKET_Z0 + i]);
}
}
/* 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;
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
static struct async_signal_handler *sigint_remote_twice_token;
static struct async_signal_handler *sigint_remote_token;
/* Asynchronous signal handle registered as event loop source for
when we have pending events ready to be passed to the core. */
static struct async_event_handler *remote_async_inferior_event_token;
/* Asynchronous signal handle registered as event loop source for when
the remote sent us a %Stop notification. The registered callback
will do a vStopped sequence to pull the rest of the events out of
the remote side into our event queue. */
static struct async_event_handler *remote_async_get_pending_events_token;
static ptid_t magic_null_ptid;
static ptid_t not_sent_ptid;
static ptid_t any_thread_ptid;
/* These are the threads which we last sent to the remote system. The
TID member will be -1 for all or -2 for not sent yet. */
static ptid_t general_thread;
static ptid_t continue_thread;
/* This the traceframe which we last selected on the remote system.
It will be -1 if no traceframe is selected. */
static int remote_traceframe_number = -1;
/* Find out if the stub attached to PID (and hence GDB should offer to
detach instead of killing it when bailing out). */
static int
remote_query_attached (int pid)
{
struct remote_state *rs = get_remote_state ();
size_t size = get_remote_packet_size ();
if (remote_protocol_packets[PACKET_qAttached].support == PACKET_DISABLE)
return 0;
if (remote_multi_process_p (rs))
xsnprintf (rs->buf, size, "qAttached:%x", pid);
else
xsnprintf (rs->buf, size, "qAttached");
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
switch (packet_ok (rs->buf,
&remote_protocol_packets[PACKET_qAttached]))
{
case PACKET_OK:
if (strcmp (rs->buf, "1") == 0)
return 1;
break;
case PACKET_ERROR:
warning (_("Remote failure reply: %s"), rs->buf);
break;
case PACKET_UNKNOWN:
break;
}
return 0;
}
/* Add PID to GDB's inferior table. If FAKE_PID_P is true, then PID
has been invented by GDB, instead of reported by the target. Since
we can be connected to a remote system before before knowing about
any inferior, mark the target with execution when we find the first
inferior. If ATTACHED is 1, then we had just attached to this
inferior. If it is 0, then we just created this inferior. If it
is -1, then try querying the remote stub to find out if it had
attached to the inferior or not. */
static struct inferior *
remote_add_inferior (int fake_pid_p, int pid, int attached)
{
struct inferior *inf;
/* Check whether this process we're learning about is to be
considered attached, or if is to be considered to have been
spawned by the stub. */
if (attached == -1)
attached = remote_query_attached (pid);
if (gdbarch_has_global_solist (target_gdbarch))
{
/* If the target shares code across all inferiors, then every
attach adds a new inferior. */
inf = add_inferior (pid);
/* ... and every inferior is bound to the same program space.
However, each inferior may still have its own address
space. */
inf->aspace = maybe_new_address_space ();
inf->pspace = current_program_space;
}
else
{
/* In the traditional debugging scenario, there's a 1-1 match
between program/address spaces. We simply bind the inferior
to the program space's address space. */
inf = current_inferior ();
inferior_appeared (inf, pid);
}
inf->attach_flag = attached;
inf->fake_pid_p = fake_pid_p;
return inf;
}
/* Add thread PTID to GDB's thread list. Tag it as executing/running
according to RUNNING. */
static void
remote_add_thread (ptid_t ptid, int running)
{
add_thread (ptid);
set_executing (ptid, running);
set_running (ptid, running);
}
/* Come here when we learn about a thread id from the remote target.
It may be the first time we hear about such thread, so take the
opportunity to add it to GDB's thread list. In case this is the
first time we're noticing its corresponding inferior, add it to
GDB's inferior list as well. */
static void
remote_notice_new_inferior (ptid_t currthread, int running)
{
/* 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) && is_exited (currthread))
{
/* We're seeing an event on a thread id we knew had exited.
This has to be a new thread reusing the old id. Add it. */
remote_add_thread (currthread, running);
return;
}
if (!in_thread_list (currthread))
{
struct inferior *inf = NULL;
int pid = ptid_get_pid (currthread);
if (ptid_is_pid (inferior_ptid)
&& pid == ptid_get_pid (inferior_ptid))
{
/* inferior_ptid has no thread member yet. This can happen
with the vAttach -> remote_wait,"TAAthread:" path if the
stub doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
if (in_thread_list (pid_to_ptid (pid)))
thread_change_ptid (inferior_ptid, currthread);
else
{
remote_add_thread (currthread, running);
inferior_ptid = currthread;
}
return;
}
if (ptid_equal (magic_null_ptid, inferior_ptid))
{
/* inferior_ptid is not set yet. This can happen with the
vRun -> remote_wait,"TAAthread:" path if the stub
doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
thread_change_ptid (inferior_ptid, currthread);
return;
}
/* When connecting to a target remote, or to a target
extended-remote which already was debugging an inferior, we
may not know about it yet. Add it before adding its child
thread, so notifications are emitted in a sensible order. */
if (!in_inferior_list (ptid_get_pid (currthread)))
{
struct remote_state *rs = get_remote_state ();
int fake_pid_p = !remote_multi_process_p (rs);
inf = remote_add_inferior (fake_pid_p,
ptid_get_pid (currthread), -1);
}
/* This is really a new thread. Add it. */
remote_add_thread (currthread, running);
/* If we found a new inferior, let the common code do whatever
it needs to with it (e.g., read shared libraries, insert
breakpoints). */
if (inf != NULL)
notice_new_inferior (currthread, running, 0);
}
}
/* Return the private thread data, creating it if necessary. */
static struct private_thread_info *
demand_private_info (ptid_t ptid)
{
struct thread_info *info = find_thread_ptid (ptid);
gdb_assert (info);
if (!info->private)
{
info->private = xmalloc (sizeof (*(info->private)));
info->private_dtor = free_private_thread_info;
info->private->core = -1;
info->private->extra = 0;
}
return info->private;
}
/* Call this function as a result of
1) A halt indication (T packet) containing a thread id
2) A direct query of currthread
3) Successful execution of set thread */
static void
record_currthread (ptid_t currthread)
{
general_thread = currthread;
}
static char *last_pass_packet;
/* If 'QPassSignals' is supported, tell the remote stub what signals
it can simply pass through to the inferior without reporting. */
static void
remote_pass_signals (int numsigs, unsigned char *pass_signals)
{
if (remote_protocol_packets[PACKET_QPassSignals].support != PACKET_DISABLE)
{
char *pass_packet, *p;
int count = 0, i;
gdb_assert (numsigs < 256);
for (i = 0; i < numsigs; i++)
{
if (pass_signals[i])
count++;
}
pass_packet = xmalloc (count * 3 + strlen ("QPassSignals:") + 1);
strcpy (pass_packet, "QPassSignals:");
p = pass_packet + strlen (pass_packet);
for (i = 0; i < numsigs; i++)
{
if (pass_signals[i])
{
if (i >= 16)
*p++ = tohex (i >> 4);
*p++ = tohex (i & 15);
if (count)
*p++ = ';';
else
break;
count--;
}
}
*p = 0;
if (!last_pass_packet || strcmp (last_pass_packet, pass_packet))
{
struct remote_state *rs = get_remote_state ();
char *buf = rs->buf;
putpkt (pass_packet);
getpkt (&rs->buf, &rs->buf_size, 0);
packet_ok (buf, &remote_protocol_packets[PACKET_QPassSignals]);
if (last_pass_packet)
xfree (last_pass_packet);
last_pass_packet = pass_packet;
}
else
xfree (pass_packet);
}
}
/* The last QProgramSignals packet sent to the target. We bypass
sending a new program signals list down to the target if the new
packet is exactly the same as the last we sent. IOW, we only let
the target know about program signals list changes. */
static char *last_program_signals_packet;
/* If 'QProgramSignals' is supported, tell the remote stub what
signals it should pass through to the inferior when detaching. */
static void
remote_program_signals (int numsigs, unsigned char *signals)
{
if (remote_protocol_packets[PACKET_QProgramSignals].support != PACKET_DISABLE)
{
char *packet, *p;
int count = 0, i;
gdb_assert (numsigs < 256);
for (i = 0; i < numsigs; i++)
{
if (signals[i])
count++;
}
packet = xmalloc (count * 3 + strlen ("QProgramSignals:") + 1);
strcpy (packet, "QProgramSignals:");
p = packet + strlen (packet);
for (i = 0; i < numsigs; i++)
{
if (signal_pass_state (i))
{
if (i >= 16)
*p++ = tohex (i >> 4);
*p++ = tohex (i & 15);
if (count)
*p++ = ';';
else
break;
count--;
}
}
*p = 0;
if (!last_program_signals_packet
|| strcmp (last_program_signals_packet, packet) != 0)
{
struct remote_state *rs = get_remote_state ();
char *buf = rs->buf;
putpkt (packet);
getpkt (&rs->buf, &rs->buf_size, 0);
packet_ok (buf, &remote_protocol_packets[PACKET_QProgramSignals]);
xfree (last_program_signals_packet);
last_program_signals_packet = packet;
}
else
xfree (packet);
}
}
/* If PTID is MAGIC_NULL_PTID, don't set any thread. If PTID is
MINUS_ONE_PTID, set the thread to -1, so the stub returns the
thread. If GEN is set, set the general thread, if not, then set
the step/continue thread. */
static void
set_thread (struct ptid ptid, int gen)
{
struct remote_state *rs = get_remote_state ();
ptid_t state = gen ? general_thread : continue_thread;
char *buf = rs->buf;
char *endbuf = rs->buf + get_remote_packet_size ();
if (ptid_equal (state, ptid))
return;
*buf++ = 'H';
*buf++ = gen ? 'g' : 'c';
if (ptid_equal (ptid, magic_null_ptid))
xsnprintf (buf, endbuf - buf, "0");
else if (ptid_equal (ptid, any_thread_ptid))
xsnprintf (buf, endbuf - buf, "0");
else if (ptid_equal (ptid, minus_one_ptid))
xsnprintf (buf, endbuf - buf, "-1");
else
write_ptid (buf, endbuf, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (gen)
general_thread = ptid;
else
continue_thread = ptid;
}
static void
set_general_thread (struct ptid ptid)
{
set_thread (ptid, 1);
}
static void
set_continue_thread (struct ptid ptid)
{
set_thread (ptid, 0);
}
/* Change the remote current process. Which thread within the process
ends up selected isn't important, as long as it is the same process
as what INFERIOR_PTID points to.
This comes from that fact that there is no explicit notion of
"selected process" in the protocol. The selected process for
general operations is the process the selected general thread
belongs to. */
static void
set_general_process (void)
{
struct remote_state *rs = get_remote_state ();
/* If the remote can't handle multiple processes, don't bother. */
if (!rs->extended || !remote_multi_process_p (rs))
return;
/* We only need to change the remote current thread if it's pointing
at some other process. */
if (ptid_get_pid (general_thread) != ptid_get_pid (inferior_ptid))
set_general_thread (inferior_ptid);
}
/* Return nonzero if the thread PTID is still alive on the remote
system. */
static int
remote_thread_alive (struct target_ops *ops, ptid_t ptid)
{
struct remote_state *rs = get_remote_state ();
char *p, *endp;
if (ptid_equal (ptid, magic_null_ptid))
/* The main thread is always alive. */
return 1;
if (ptid_get_pid (ptid) != 0 && ptid_get_tid (ptid) == 0)
/* The main thread is always alive. This can happen after a
vAttach, if the remote side doesn't support
multi-threading. */
return 1;
p = rs->buf;
endp = rs->buf + get_remote_packet_size ();
*p++ = 'T';
write_ptid (p, endp, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
}
/* About these extended threadlist and threadinfo packets. They are
variable length packets but, the fields within them are often fixed
length. They are redundent enough to send over UDP as is the
remote protocol in general. There is a matching unit test module
in libstub. */
#define OPAQUETHREADBYTES 8
/* a 64 bit opaque identifier */
typedef unsigned char threadref[OPAQUETHREADBYTES];
/* WARNING: This threadref data structure comes from the remote O.S.,
libstub protocol encoding, and remote.c. It is not particularly
changable. */
/* 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
equivalent 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/suspended. */
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, ULONGEST *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 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);
/* Write a PTID to BUF. ENDBUF points to one-passed-the-end of the
buffer we're allowed to write to. Returns
BUF+CHARACTERS_WRITTEN. */
static char *
write_ptid (char *buf, const char *endbuf, ptid_t ptid)
{
int pid, tid;
struct remote_state *rs = get_remote_state ();
if (remote_multi_process_p (rs))
{
pid = ptid_get_pid (ptid);
if (pid < 0)
buf += xsnprintf (buf, endbuf - buf, "p-%x.", -pid);
else
buf += xsnprintf (buf, endbuf - buf, "p%x.", pid);
}
tid = ptid_get_tid (ptid);
if (tid < 0)
buf += xsnprintf (buf, endbuf - buf, "-%x", -tid);
else
buf += xsnprintf (buf, endbuf - buf, "%x", tid);
return buf;
}
/* Extract a PTID from BUF. If non-null, OBUF is set to the to one
passed the last parsed char. Returns null_ptid on error. */
static ptid_t
read_ptid (char *buf, char **obuf)
{
char *p = buf;
char *pp;
ULONGEST pid = 0, tid = 0;
if (*p == 'p')
{
/* Multi-process ptid. */
pp = unpack_varlen_hex (p + 1, &pid);
if (*pp != '.')
error (_("invalid remote ptid: %s"), p);
p = pp;
pp = unpack_varlen_hex (p + 1, &tid);
if (obuf)
*obuf = pp;
return ptid_build (pid, 0, tid);
}
/* No multi-process. Just a tid. */
pp = unpack_varlen_hex (p, &tid);
/* Since the stub is not sending a process id, then default to
what's in inferior_ptid, unless it's null at this point. If so,
then since there's no way to know the pid of the reported
threads, use the magic number. */
if (ptid_equal (inferior_ptid, null_ptid))
pid = ptid_get_pid (magic_null_ptid);
else
pid = ptid_get_pid (inferior_ptid);
if (obuf)
*obuf = pp;
return ptid_build (pid, 0, tid);
}
/* 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;
return 1;
}
if ((ch >= '0') && (ch <= '9'))
{
*val = ch - '0';
return 1;
}
return 0;
}
static int
stubhex (int ch)
{
if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
if (ch >= '0' && ch <= '9')
return ch - '0';
if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
return -1;
}
static int
stub_unpack_int (char *buff, int fieldlength)
{
int nibble;
int retval = 0;
while (fieldlength)
{
nibble = stubhex (*buff++);
retval |= nibble;
fieldlength--;
if (fieldlength)
retval = retval << 4;
}
return retval;
}
char *
unpack_varlen_hex (char *buff, /* packet to parse */
ULONGEST *result)
{
int nibble;
ULONGEST retval = 0;
while (ishex (*buff, &nibble))
{
buff++;
retval = retval << 4;
retval |= nibble & 0x0f;
}
*result = retval;
return buff;
}
static char *
unpack_nibble (char *buf, int *val)
{
*val = fromhex (*buf++);
return buf;
}
static char *
pack_nibble (char *buf, int nibble)
{
*buf++ = hexchars[(nibble & 0x0f)];
return buf;
}
static char *
pack_hex_byte (char *pkt, int byte)
{
*pkt++ = hexchars[(byte >> 4) & 0xf];
*pkt++ = hexchars[(byte & 0xf)];
return pkt;
}
static char *
unpack_byte (char *buf, int *value)
{
*value = stub_unpack_int (buf, 2);
return buf + 2;
}
static char *
pack_int (char *buf, int value)
{
buf = pack_hex_byte (buf, (value >> 24) & 0xff);
buf = pack_hex_byte (buf, (value >> 16) & 0xff);
buf = pack_hex_byte (buf, (value >> 8) & 0x0ff);
buf = pack_hex_byte (buf, (value & 0xff));
return buf;
}
static char *
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 (char *pkt, char *string);
static char *
pack_string (char *pkt, char *string)
{
char ch;
int len;
len = strlen (string);
if (len > 200)
len = 200; /* Bigger than most GDB packets, junk??? */
pkt = pack_hex_byte (pkt, len);
while (len-- > 0)
{
ch = *string++;
if ((ch == '\0') || (ch == '#'))
ch = '*'; /* Protect encapsulation. */
*pkt++ = ch;
}
return pkt;
}
#endif /* 0 (unused) */
static char *
unpack_string (char *src, char *dest, int length)
{
while (length--)
*dest++ = *src++;
*dest = '\0';
return src;
}
static char *
pack_threadid (char *pkt, threadref *id)
{
char *limit;
unsigned char *altid;
altid = (unsigned char *) id;
limit = pkt + BUF_THREAD_ID_SIZE;
while (pkt < limit)
pkt = pack_hex_byte (pkt, *altid++);
return pkt;
}
static char *
unpack_threadid (char *inbuf, threadref *id)
{
char *altref;
char *limit = inbuf + BUF_THREAD_ID_SIZE;
int x, y;
altref = (char *) id;
while (inbuf < limit)
{
x = stubhex (*inbuf++);
y = stubhex (*inbuf++);
*altref++ = (x << 4) | y;
}
return inbuf;
}
/* Externally, threadrefs are 64 bits but internally, they are still
ints. This is due to a mismatch of specifications. We would like
to use 64bit thread references internally. This is an adapter
function. */
void
int_to_threadref (threadref *id, int value)
{
unsigned char *scan;
scan = (unsigned char *) id;
{
int i = 4;
while (i--)
*scan++ = 0;
}
*scan++ = (value >> 24) & 0xff;
*scan++ = (value >> 16) & 0xff;
*scan++ = (value >> 8) & 0xff;
*scan++ = (value & 0xff);
}
static int
threadref_to_int (threadref *ref)
{
int i, value = 0;
unsigned char *scan;
scan = *ref;
scan += 4;
i = 4;
while (i-- > 0)
value = (value << 8) | ((*scan++) & 0xff);
return value;
}
static void
copy_threadref (threadref *dest, threadref *src)
{
int i;
unsigned char *csrc, *cdest;
csrc = (unsigned char *) src;
cdest = (unsigned char *) dest;
i = 8;
while (i--)
*cdest++ = *csrc++;
}
static int
threadmatch (threadref *dest, threadref *src)
{
/* Things are broken right now, so just assume we got a match. */
#if 0
unsigned char *srcp, *destp;
int i, result;
srcp = (char *) src;
destp = (char *) dest;
result = 1;
while (i-- > 0)
result &= (*srcp++ == *destp++) ? 1 : 0;
return result;
#endif
return 1;
}
/*
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 (char *pkt, int mode, threadref *id)
{
*pkt++ = 'q'; /* Info Query */
*pkt++ = 'P'; /* process or thread info */
pkt = pack_int (pkt, mode); /* mode */
pkt = pack_threadid (pkt, id); /* threadid */
*pkt = '\0'; /* terminate */
return pkt;
}
/* These values tag the fields in a thread info response packet. */
/* 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. */
static int
remote_unpack_thread_info_response (char *pkt, threadref *expectedref,
struct gdb_ext_thread_info *info)
{
struct remote_state *rs = get_remote_state ();
int mask, length;
int tag;
threadref ref;
char *limit = pkt + rs->buf_size; /* Plausible parsing limit. */
int retval = 1;
/* info->threadid = 0; FIXME: implement zero_threadref. */
info->active = 0;
info->display[0] = '\0';
info->shortname[0] = '\0';
info->more_display[0] = '\0';
/* Assume the characters indicating the packet type have been
stripped. */
pkt = unpack_int (pkt, &mask); /* arg mask */
pkt = unpack_threadid (pkt, &ref);
if (mask == 0)
warning (_("Incomplete response to threadinfo request."));
if (!threadmatch (&ref, expectedref))
{ /* This is an answer to a different request. */
warning (_("ERROR RMT Thread info mismatch."));
return 0;
}
copy_threadref (&info->threadid, &ref);
/* Loop on tagged fields , try to bail if somthing goes wrong. */
/* Packets are terminated with nulls. */
while ((pkt < limit) && mask && *pkt)
{
pkt = unpack_int (pkt, &tag); /* tag */
pkt = unpack_byte (pkt, &length); /* length */
if (!(tag & mask)) /* Tags out of synch with mask. */
{
warning (_("ERROR RMT: threadinfo tag mismatch."));
retval = 0;
break;
}
if (tag == TAG_THREADID)
{
if (length != 16)
{
warning (_("ERROR RMT: length of threadid is not 16."));
retval = 0;
break;
}
pkt = unpack_threadid (pkt, &ref);
mask = mask & ~TAG_THREADID;
continue;
}
if (tag == TAG_EXISTS)
{
info->active = stub_unpack_int (pkt, length);
pkt += length;
mask = mask & ~(TAG_EXISTS);
if (length > 8)
{
warning (_("ERROR RMT: 'exists' length too long."));
retval = 0;
break;
}
continue;
}
if (tag == TAG_THREADNAME)
{
pkt = unpack_string (pkt, &info->shortname[0], length);
mask = mask & ~TAG_THREADNAME;
continue;
}
if (tag == TAG_DISPLAY)
{
pkt = unpack_string (pkt, &info->display[0], length);
mask = mask & ~TAG_DISPLAY;
continue;
}
if (tag == TAG_MOREDISPLAY)
{
pkt = unpack_string (pkt, &info->more_display[0], length);
mask = mask & ~TAG_MOREDISPLAY;
continue;
}
warning (_("ERROR RMT: unknown thread info tag."));
break; /* Not a tag we know about. */
}
return retval;
}
static int
remote_get_threadinfo (threadref *threadid, int fieldset, /* TAG mask */
struct gdb_ext_thread_info *info)
{
struct remote_state *rs = get_remote_state ();
int result;
pack_threadinfo_request (rs->buf, fieldset, threadid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == '\0')
return 0;
result = remote_unpack_thread_info_response (rs->buf + 2,
threadid, info);
return result;
}
/* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */
static char *
pack_threadlist_request (char *pkt, int startflag, int threadcount,
threadref *nextthread)
{
*pkt++ = 'q'; /* info query packet */
*pkt++ = 'L'; /* Process LIST or threadLIST request */
pkt = pack_nibble (pkt, startflag); /* initflag 1 bytes */
pkt = pack_hex_byte (pkt, threadcount); /* threadcount 2 bytes */
pkt = pack_threadid (pkt, nextthread); /* 64 bit thread identifier */
*pkt = '\0';
return pkt;
}
/* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */
static int
parse_threadlist_response (char *pkt, int result_limit,
threadref *original_echo, threadref *resultlist,
int *doneflag)
{
struct remote_state *rs = get_remote_state ();
char *limit;
int count, resultcount, done;
resultcount = 0;
/* Assume the 'q' and 'M chars have been stripped. */
limit = pkt + (rs->buf_size - 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. */
pkt = unpack_threadid (pkt, original_echo); /* should match query packet */
while ((count-- > 0) && (pkt < limit))
{
pkt = unpack_threadid (pkt, resultlist++);
if (resultcount++ >= result_limit)
break;
}
if (doneflag)
*doneflag = done;
return resultcount;
}
static int
remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
int *done, int *result_count, threadref *threadlist)
{
struct remote_state *rs = get_remote_state ();
static threadref echo_nextthread;
int result = 1;
/* Trancate result limit to be smaller than the packet size. */
if ((((result_limit + 1) * BUF_THREAD_ID_SIZE) + 10)
>= get_remote_packet_size ())
result_limit = (get_remote_packet_size () / BUF_THREAD_ID_SIZE) - 2;
pack_threadlist_request (rs->buf, startflag, result_limit, nextthread);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (*rs->buf == '\0')
return 0;
else
*result_count =
parse_threadlist_response (rs->buf + 2, result_limit, &echo_nextthread,
threadlist, done);
if (!threadmatch (&echo_nextthread, nextthread))
{
/* FIXME: This is a good reason to drop the packet. */
/* Possably, there is a duplicate response. */
/* Possabilities :
retransmit immediatly - race conditions
retransmit after timeout - yes
exit
wait for packet, then exit
*/
warning (_("HMM: threadlist did not echo arg thread, dropping it."));
return 0; /* I choose simply exiting. */
}
if (*result_count <= 0)
{
if (*done != 1)
{
warning (_("RMT ERROR : failed to get remote thread list."));
result = 0;
}
return result; /* break; */
}
if (*result_count > result_limit)
{
*result_count = 0;
warning (_("RMT ERROR: threadlist response longer than requested."));
return 0;
}
return result;
}
/* This is the interface between remote and threads, remotes upper
interface. */
/* remote_find_new_threads retrieves the thread list and for each
thread in the list, looks up the thread in GDB's internal list,
adding the thread if it does not already exist. This involves
getting partial thread lists from the remote target so, polling the
quit_flag is required. */
/* About this many threadisds fit in a packet. */
#define MAXTHREADLISTRESULTS 32
static int
remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
int looplimit)
{
int done, i, result_count;
int startflag = 1;
int result = 1;
int loopcount = 0;
static threadref nextthread;
static threadref resultthreadlist[MAXTHREADLISTRESULTS];
done = 0;
while (!done)
{
if (loopcount++ > looplimit)
{
result = 0;
warning (_("Remote fetch threadlist -infinite loop-."));
break;
}
if (!remote_get_threadlist (startflag, &nextthread, MAXTHREADLISTRESULTS,
&done, &result_count, resultthreadlist))
{
result = 0;
break;
}
/* Clear for later iterations. */
startflag = 0;
/* Setup to resume next batch of thread references, set nextthread. */
if (result_count >= 1)
copy_threadref (&nextthread, &resultthreadlist[result_count - 1]);
i = 0;
while (result_count--)
if (!(result = (*stepfunction) (&resultthreadlist[i++], context)))
break;
}
return result;
}
static int
remote_newthread_step (threadref *ref, void *context)
{
int pid = ptid_get_pid (inferior_ptid);
ptid_t ptid = ptid_build (pid, 0, threadref_to_int (ref));
if (!in_thread_list (ptid))
add_thread (ptid);
return 1; /* continue iterator */
}
#define CRAZY_MAX_THREADS 1000
static ptid_t
remote_current_thread (ptid_t oldpid)
{
struct remote_state *rs = get_remote_state ();
putpkt ("qC");
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'Q' && rs->buf[1] == 'C')
return read_ptid (&rs->buf[2], NULL);
else
return oldpid;
}
/* Find new threads for info threads command.
* Original version, using John Metzler's thread protocol.
*/
static void
remote_find_new_threads (void)
{
remote_threadlist_iterator (remote_newthread_step, 0,
CRAZY_MAX_THREADS);
}
#if defined(HAVE_LIBEXPAT)
typedef struct thread_item
{
ptid_t ptid;
char *extra;
int core;
} thread_item_t;
DEF_VEC_O(thread_item_t);
struct threads_parsing_context
{
VEC (thread_item_t) *items;
};
static void
start_thread (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
struct threads_parsing_context *data = user_data;
struct thread_item item;
char *id;
struct gdb_xml_value *attr;
id = xml_find_attribute (attributes, "id")->value;
item.ptid = read_ptid (id, NULL);
attr = xml_find_attribute (attributes, "core");
if (attr != NULL)
item.core = *(ULONGEST *) attr->value;
else
item.core = -1;
item.extra = 0;
VEC_safe_push (thread_item_t, data->items, &item);
}
static void
end_thread (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
struct threads_parsing_context *data = user_data;
if (body_text && *body_text)
VEC_last (thread_item_t, data->items)->extra = xstrdup (body_text);
}
const struct gdb_xml_attribute thread_attributes[] = {
{ "id", GDB_XML_AF_NONE, NULL, NULL },
{ "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
const struct gdb_xml_element thread_children[] = {
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
const struct gdb_xml_element threads_children[] = {
{ "thread", thread_attributes, thread_children,
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
start_thread, end_thread },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
const struct gdb_xml_element threads_elements[] = {
{ "threads", NULL, threads_children,
GDB_XML_EF_NONE, NULL, NULL },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
/* Discard the contents of the constructed thread info context. */
static void
clear_threads_parsing_context (void *p)
{
struct threads_parsing_context *context = p;
int i;
struct thread_item *item;
for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
xfree (item->extra);
VEC_free (thread_item_t, context->items);
}
#endif
/*
* 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
remote_threads_info (struct target_ops *ops)
{
struct remote_state *rs = get_remote_state ();
char *bufp;
ptid_t new_thread;
if (remote_desc == 0) /* paranoia */
error (_("Command can only be used when connected to the remote target."));
#if defined(HAVE_LIBEXPAT)
if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
{
char *xml = target_read_stralloc (&current_target,
TARGET_OBJECT_THREADS, NULL);
struct cleanup *back_to = make_cleanup (xfree, xml);
if (xml && *xml)
{
struct threads_parsing_context context;
context.items = NULL;
make_cleanup (clear_threads_parsing_context, &context);
if (gdb_xml_parse_quick (_("threads"), "threads.dtd",
threads_elements, xml, &context) == 0)
{
int i;
struct thread_item *item;
for (i = 0;
VEC_iterate (thread_item_t, context.items, i, item);
++i)
{
if (!ptid_equal (item->ptid, null_ptid))
{
struct private_thread_info *info;
/* In non-stop mode, we assume new found threads
are running until proven otherwise with a
stop reply. In all-stop, we can only get
here if all threads are stopped. */
int running = non_stop ? 1 : 0;
remote_notice_new_inferior (item->ptid, running);
info = demand_private_info (item->ptid);
info->core = item->core;
info->extra = item->extra;
item->extra = NULL;
}
}
}
}
do_cleanups (back_to);
return;
}
#endif
if (use_threadinfo_query)
{
putpkt ("qfThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
bufp = rs->buf;
if (bufp[0] != '\0') /* q packet recognized */
{
while (*bufp++ == 'm') /* reply contains one or more TID */
{
do
{
new_thread = read_ptid (bufp, &bufp);
if (!ptid_equal (new_thread, null_ptid))
{
/* In non-stop mode, we assume new found threads
are running until proven otherwise with a
stop reply. In all-stop, we can only get
here if all threads are stopped. */
int running = non_stop ? 1 : 0;
remote_notice_new_inferior (new_thread, running);
}
}
while (*bufp++ == ','); /* comma-separated list */
putpkt ("qsThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
bufp = rs->buf;
}
return; /* done */
}
}
/* Only qfThreadInfo is supported in non-stop mode. */
if (non_stop)
return;
/* 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)
{
struct remote_state *rs = get_remote_state ();
int result;
int set;
threadref id;
struct gdb_ext_thread_info threadinfo;
static char display_buf[100]; /* arbitrary... */
int n = 0; /* position in display_buf */
if (remote_desc == 0) /* paranoia */
internal_error (__FILE__, __LINE__,
_("remote_threads_extra_info"));
if (ptid_equal (tp->ptid, magic_null_ptid)
|| (ptid_get_pid (tp->ptid) != 0 && ptid_get_tid (tp->ptid) == 0))
/* This is the main thread which was added by GDB. The remote
server doesn't know about it. */
return NULL;
if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
{
struct thread_info *info = find_thread_ptid (tp->ptid);
if (info && info->private)
return info->private->extra;
else
return NULL;
}
if (use_threadextra_query)
{
char *b = rs->buf;
char *endb = rs->buf + get_remote_packet_size ();
xsnprintf (b, endb - b, "qThreadExtraInfo,");
b += strlen (b);
write_ptid (b, endb, tp->ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 0)
{
n = min (strlen (rs->buf) / 2, sizeof (display_buf));
result = hex2bin (rs->buf, (gdb_byte *) display_buf, n);
display_buf [result] = '\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, ptid_get_tid (tp->ptid));
if (remote_get_threadinfo (&id, set, &threadinfo))
if (threadinfo.active)
{
if (*threadinfo.shortname)
n += xsnprintf (&display_buf[0], sizeof (display_buf) - n,
" Name: %s,", threadinfo.shortname);
if (*threadinfo.display)
n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
" State: %s,", threadinfo.display);
if (*threadinfo.more_display)
n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
" Priority: %s", threadinfo.more_display);
if (n > 0)
{
/* For purely cosmetic reasons, clear up trailing commas. */
if (','