/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2019 Free Software Foundation, Inc.
+ Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbsupport/scoped_restore.h"
#include "gdbsupport/environ.h"
#include "gdbsupport/byte-vector.h"
+#include <algorithm>
#include <unordered_map>
/* The remote target. */
bool S = false;
};
-/* About this many threadisds fit in a packet. */
+/* About this many threadids fit in a packet. */
#define MAXTHREADLISTRESULTS 32
/* The status of the stub support for the various vCont actions. */
vCont_action_support supports_vCont;
+ /* Whether vCont support was probed already. This is a workaround
+ until packet_support is per-connection. */
+ bool supports_vCont_probed;
/* True if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
const target_info &info () const override
{ return remote_target_info; }
+ const char *connection_string () override;
+
thread_control_capabilities get_thread_control_capabilities () override
{ return tc_schedlock; }
void async (int) override;
+ int async_wait_fd () override;
+
void thread_events (int) override;
int can_do_single_step () override;
static void remote_btrace_reset (remote_state *rs);
-static void remote_unpush_and_throw (void);
+static void remote_unpush_and_throw (remote_target *target);
/* For "remote". */
static bool use_range_stepping = true;
-/* The max number of chars in debug output. The rest of chars are
- omitted. */
-
-#define REMOTE_DEBUG_MAX_CHAR 512
-
/* Private data that we'll store in (struct thread_info)->priv. */
struct remote_thread_info : public private_thread_info
{
show_remote_exec_file (struct ui_file *file, int from_tty,
struct cmd_list_element *cmd, const char *value)
{
- fprintf_filtered (file, "%s\n", remote_exec_file_var);
-}
-
-static int
-compare_pnums (const void *lhs_, const void *rhs_)
-{
- const struct packet_reg * const *lhs
- = (const struct packet_reg * const *) lhs_;
- const struct packet_reg * const *rhs
- = (const struct packet_reg * const *) rhs_;
-
- if ((*lhs)->pnum < (*rhs)->pnum)
- return -1;
- else if ((*lhs)->pnum == (*rhs)->pnum)
- return 0;
- else
- return 1;
+ fprintf_filtered (file, "%s\n", get_remote_exec_file ());
}
static int
if (regs[regnum].pnum != -1)
remote_regs[num_remote_regs++] = ®s[regnum];
- qsort (remote_regs, num_remote_regs, sizeof (struct packet_reg *),
- compare_pnums);
+ std::sort (remote_regs, remote_regs + num_remote_regs,
+ [] (const packet_reg *a, const packet_reg *b)
+ { return a->pnum < b->pnum; });
for (regnum = 0, offset = 0; regnum < num_remote_regs; regnum++)
{
static remote_target *
get_current_remote_target ()
{
- target_ops *proc_target = find_target_at (process_stratum);
+ target_ops *proc_target = current_inferior ()->process_target ();
return dynamic_cast<remote_target *> (proc_target);
}
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
+ some remote targets this variable is principally provided to
facilitate backward compatibility. */
static unsigned int remote_address_size;
}
}
+/* FIXME: needs to be per-remote-target. */
static struct memory_packet_config memory_write_packet_config =
{
"memory-write-packet-size",
"breakpoints is %s.\n"), value);
}
+/* Controls the maximum number of characters to display in the debug output
+ for each remote packet. The remaining characters are omitted. */
+
+static int remote_packet_max_chars = 512;
+
+/* Show the maximum number of characters to display for each remote packet
+ when remote debugging is enabled. */
+
+static void
+show_remote_packet_max_chars (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file, _("Number of remote packet characters to "
+ "display is %s.\n"), value);
+}
+
long
remote_target::get_memory_write_packet_size ()
{
return get_memory_packet_size (&memory_write_packet_config);
}
+/* FIXME: needs to be per-remote-target. */
static struct memory_packet_config memory_read_packet_config =
{
"memory-read-packet-size",
if (buf[0] == 'E'
&& isxdigit (buf[1]) && isxdigit (buf[2])
&& buf[3] == '\0')
- /* "Enn" - definitly an error. */
+ /* "Enn" - definitely an error. */
return PACKET_ERROR;
/* Always treat "E." as an error. This will be used for
PACKET_MAX
};
+/* FIXME: needs to be per-remote-target. Ignoring this for now,
+ assuming all remote targets are the same server (thus all support
+ the same packets). */
static struct packet_config remote_protocol_packets[PACKET_MAX];
/* Returns the packet's corresponding "set remote foo-packet" command
between program/address spaces. We simply bind the inferior
to the program space's address space. */
inf = current_inferior ();
+
+ /* However, if the current inferior is already bound to a
+ process, find some other empty inferior. */
+ if (inf->pid != 0)
+ {
+ inf = nullptr;
+ for (inferior *it : all_inferiors ())
+ if (it->pid == 0)
+ {
+ inf = it;
+ break;
+ }
+ }
+ if (inf == nullptr)
+ {
+ /* Since all inferiors were already bound to a process, add
+ a new inferior. */
+ inf = add_inferior_with_spaces ();
+ }
+ switch_to_inferior_no_thread (inf);
+ push_target (this);
inferior_appeared (inf, pid);
}
}
static remote_thread_info *get_remote_thread_info (thread_info *thread);
-static remote_thread_info *get_remote_thread_info (ptid_t ptid);
+static remote_thread_info *get_remote_thread_info (remote_target *target,
+ ptid_t ptid);
/* Add thread PTID to GDB's thread list. Tag it as executing/running
according to RUNNING. */
might be confusing to the user. Be silent then, preserving the
age old behavior. */
if (rs->starting_up)
- thread = add_thread_silent (ptid);
+ thread = add_thread_silent (this, ptid);
else
- thread = add_thread (ptid);
+ thread = add_thread (this, ptid);
get_remote_thread_info (thread)->vcont_resumed = executing;
- set_executing (ptid, executing);
- set_running (ptid, running);
+ set_executing (this, ptid, executing);
+ set_running (this, ptid, running);
return thread;
}
/* 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. */
- thread_info *tp = find_thread_ptid (currthread);
+ thread_info *tp = find_thread_ptid (this, currthread);
if (tp != NULL && tp->state == THREAD_EXITED)
{
/* We're seeing an event on a thread id we knew had exited.
return;
}
- if (!in_thread_list (currthread))
+ if (!in_thread_list (this, currthread))
{
struct inferior *inf = NULL;
int pid = currthread.pid ();
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 (ptid_t (pid)))
- thread_change_ptid (inferior_ptid, currthread);
+ if (in_thread_list (this, ptid_t (pid)))
+ thread_change_ptid (this, inferior_ptid, currthread);
else
{
remote_add_thread (currthread, running, executing);
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);
+ thread_change_ptid (this, inferior_ptid, currthread);
return;
}
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 (find_inferior_pid (currthread.pid ()) == NULL)
+ if (find_inferior_pid (this, currthread.pid ()) == NULL)
{
struct remote_state *rs = get_remote_state ();
bool fake_pid_p = !remote_multi_process_p (rs);
return static_cast<remote_thread_info *> (thread->priv.get ());
}
+/* Return PTID's private thread data, creating it if necessary. */
+
static remote_thread_info *
-get_remote_thread_info (ptid_t ptid)
+get_remote_thread_info (remote_target *target, ptid_t ptid)
{
- thread_info *thr = find_thread_ptid (ptid);
+ thread_info *thr = find_thread_ptid (target, ptid);
return get_remote_thread_info (thr);
}
/* 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
+ length. They are redundant enough to send over UDP as is the
remote protocol in general. There is a matching unit test module
in libstub. */
}
copy_threadref (&info->threadid, &ref);
- /* Loop on tagged fields , try to bail if somthing goes wrong. */
+ /* Loop on tagged fields , try to bail if something goes wrong. */
/* Packets are terminated with nulls. */
while ((pkt < limit) && mask && *pkt)
struct remote_state *rs = get_remote_state ();
int result = 1;
- /* Trancate result limit to be smaller than the packet size. */
+ /* Truncate 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;
if (!threadmatch (&rs->echo_nextthread, nextthread))
{
/* FIXME: This is a good reason to drop the packet. */
- /* Possably, there is a duplicate response. */
- /* Possabilities :
+ /* Possibly, there is a duplicate response. */
+ /* Possibilities :
retransmit immediatly - race conditions
retransmit after timeout - yes
exit
target. */
for (thread_info *tp : all_threads_safe ())
{
+ if (tp->inf->process_target () != this)
+ continue;
+
if (!context.contains_thread (tp->ptid))
{
/* Not found. */
remote_notice_new_inferior (item.ptid, executing);
- thread_info *tp = find_thread_ptid (item.ptid);
+ thread_info *tp = find_thread_ptid (this, item.ptid);
remote_thread_info *info = get_remote_thread_info (tp);
info->core = item.core;
info->extra = std::move (item.extra);
/* Make sure we leave stdin registered in the event loop. */
terminal_ours ();
- /* We don't have a connection to the remote stub anymore. Get rid
- of all the inferiors and their threads we were controlling.
- Reset inferior_ptid to null_ptid first, as otherwise has_stack_frame
- will be unable to find the thread corresponding to (pid, 0, 0). */
- inferior_ptid = null_ptid;
- discard_all_inferiors ();
-
trace_reset_local_state ();
delete this;
char *ptr;
int lose, num_segments = 0, do_sections, do_segments;
CORE_ADDR text_addr, data_addr, bss_addr, segments[2];
- struct section_offsets *offs;
struct symfile_segment_data *data;
if (symfile_objfile == NULL)
else if (*ptr != '\0')
warning (_("Target reported unsupported offsets: %s"), buf);
- offs = ((struct section_offsets *)
- alloca (SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections)));
- memcpy (offs, symfile_objfile->section_offsets,
- SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections));
+ section_offsets offs = symfile_objfile->section_offsets;
data = get_symfile_segment_data (symfile_objfile->obfd);
do_segments = (data != NULL);
if (do_sections)
{
- offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_addr;
+ offs[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. */
- offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr;
- offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr;
+ offs[SECT_OFF_DATA (symfile_objfile)] = data_addr;
+ offs[SECT_OFF_BSS (symfile_objfile)] = data_addr;
}
objfile_relocate (symfile_objfile, offs);
/* Add the main thread and switch to it. Don't try reading
registers yet, since we haven't fetched the target description
yet. */
- thread_info *tp = add_thread_silent (curr_ptid);
+ thread_info *tp = add_thread_silent (this, curr_ptid);
switch_to_thread_no_regs (tp);
}
if (ignore_event)
continue;
- struct thread_info *evthread = find_thread_ptid (event_ptid);
+ thread_info *evthread = find_thread_ptid (this, event_ptid);
if (ws.kind == TARGET_WAITKIND_STOPPED)
{
|| ws.value.sig != GDB_SIGNAL_0)
evthread->suspend.waitstatus_pending_p = 1;
- set_executing (event_ptid, 0);
- set_running (event_ptid, 0);
+ set_executing (this, event_ptid, 0);
+ set_running (this, event_ptid, 0);
get_remote_thread_info (evthread)->vcont_resumed = 0;
}
/* "Notice" the new inferiors before anything related to
registers/memory. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
inf->needs_setup = 1;
/* If all threads of an inferior were already stopped, we
haven't setup the inferior yet. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (inf->needs_setup)
{
/* Now go over all threads that are stopped, and print their current
frame. If all-stop, then if there's a signalled thread, pick
that as current. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
if (first == NULL)
first = thread;
/* For "info program". */
thread_info *thread = inferior_thread ();
if (thread->state == THREAD_STOPPED)
- set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
+ set_last_target_status (this, inferior_ptid, thread->suspend.waitstatus);
}
/* Start the remote connection and sync state. */
/* Let the stub know that we want it to return the thread. */
set_continue_thread (minus_one_ptid);
- if (thread_count () == 0)
+ if (thread_count (this) == 0)
{
/* Target has no concept of threads at all. GDB treats
non-threaded target as single-threaded; add a main
says should be current. If we're reconnecting to a
multi-threaded program, this will ideally be the thread
that last reported an event before GDB disconnected. */
- inferior_ptid = get_current_thread (wait_status);
- if (inferior_ptid == null_ptid)
+ ptid_t curr_thread = get_current_thread (wait_status);
+ if (curr_thread == null_ptid)
{
/* Odd... The target was able to list threads, but not
tell us which thread was current (no "thread"
"warning: couldn't determine remote "
"current thread; picking first in list.\n");
- inferior_ptid = inferior_list->thread_list->ptid;
+ for (thread_info *tp : all_non_exited_threads (this,
+ minus_one_ptid))
+ {
+ switch_to_thread (tp);
+ break;
+ }
}
+ else
+ switch_to_thread (find_thread_ptid (this, curr_thread));
}
/* init_wait_for_inferior should be called before get_offsets in order
remote_notif_get_pending_events (notif);
}
- if (thread_count () == 0)
+ if (thread_count (this) == 0)
{
if (!extended_p)
error (_("The target is not running (try extended-remote?)"));
insert_breakpoints ();
}
+const char *
+remote_target::connection_string ()
+{
+ remote_state *rs = get_remote_state ();
+
+ if (rs->remote_desc->name != NULL)
+ return rs->remote_desc->name;
+ else
+ return NULL;
+}
+
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
rs->explicit_packet_size = packet_size;
}
-void
+static void
remote_packet_size (remote_target *remote, const protocol_feature *feature,
enum packet_support support, const char *value)
{
else
{
char *copy = xstrdup (remote_support_xml + 13);
- char *p = strtok (copy, ",");
+ char *saveptr;
+ char *p = strtok_r (copy, ",", &saveptr);
do
{
return;
}
}
- while ((p = strtok (NULL, ",")) != NULL);
+ while ((p = strtok_r (NULL, ",", &saveptr)) != NULL);
xfree (copy);
remote_support_xml = reconcat (remote_support_xml,
{
if (query (_("The target is not responding to GDB commands.\n"
"Stop debugging it? ")))
- remote_unpush_and_throw ();
+ remote_unpush_and_throw (this);
}
/* If ^C has already been sent once, offer to disconnect. */
else if (!target_terminal::is_ours () && rs->ctrlc_pending_p)
curr_quit_handler_target->remote_serial_quit_handler ();
}
-/* Remove any of the remote.c targets from target stack. Upper targets depend
- on it so remove them first. */
+/* Remove the remote target from the target stack of each inferior
+ that is using it. Upper targets depend on it so remove them
+ first. */
static void
-remote_unpush_target (void)
+remote_unpush_target (remote_target *target)
{
- pop_all_targets_at_and_above (process_stratum);
+ /* We have to unpush the target from all inferiors, even those that
+ aren't running. */
+ scoped_restore_current_inferior restore_current_inferior;
+
+ for (inferior *inf : all_inferiors (target))
+ {
+ switch_to_inferior_no_thread (inf);
+ pop_all_targets_at_and_above (process_stratum);
+ generic_mourn_inferior ();
+ }
}
static void
-remote_unpush_and_throw (void)
+remote_unpush_and_throw (remote_target *target)
{
- remote_unpush_target ();
+ remote_unpush_target (target);
throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target."));
}
/* If we're connected to a running target, target_preopen will kill it.
Ask this question first, before target_preopen has a chance to kill
anything. */
- if (curr_remote != NULL && !have_inferiors ())
+ if (curr_remote != NULL && !target_has_execution)
{
if (from_tty
&& !query (_("Already connected to a remote target. Disconnect? ")))
/* Pop the partially set up target - unless something else did
already before throwing the exception. */
if (ex.error != TARGET_CLOSE_ERROR)
- remote_unpush_target ();
+ remote_unpush_target (remote);
throw;
}
}
remote_detach_pid (pid);
/* Exit only if this is the only active inferior. */
- if (from_tty && !rs->extended && number_of_live_inferiors () == 1)
+ if (from_tty && !rs->extended && number_of_live_inferiors (this) == 1)
puts_filtered (_("Ending remote debugging.\n"));
- struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ thread_info *tp = find_thread_ptid (this, inferior_ptid);
/* Check to see if we are detaching a fork parent. Note that if we
are detaching a fork child, tp == NULL. */
error (_("Argument given to \"disconnect\" when remotely debugging."));
/* Make sure we unpush even the extended remote targets. Calling
- target_mourn_inferior won't unpush, and remote_mourn won't
- unpush if there is more than one inferior left. */
- unpush_target (this);
- generic_mourn_inferior ();
+ target_mourn_inferior won't unpush, and
+ remote_target::mourn_inferior won't unpush if there is more than
+ one inferior left. */
+ remote_unpush_target (this);
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
if (from_tty)
{
- char *exec_file = get_exec_file (0);
+ const char *exec_file = get_exec_file (0);
if (exec_file)
printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
inferior_ptid = remote_current_thread (inferior_ptid);
/* Add the main thread to the thread list. */
- thread_info *thr = add_thread_silent (inferior_ptid);
+ thread_info *thr = add_thread_silent (this, inferior_ptid);
/* Don't consider the thread stopped until we've processed the
saved stop reply. */
- set_executing (thr->ptid, true);
+ set_executing (this, thr->ptid, true);
}
/* Next, if the target can specify a description, read it. We do
}
packet_ok (rs->buf, &remote_protocol_packets[PACKET_vCont]);
+ rs->supports_vCont_probed = true;
}
/* Helper function for building "vCont" resumptions. Write a
{
/* If we don't know about the target thread's tid, then
we're resuming magic_null_ptid (see caller). */
- tp = find_thread_ptid (magic_null_ptid);
+ tp = find_thread_ptid (this, magic_null_ptid);
}
else
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (this, ptid);
gdb_assert (tp != NULL);
if (tp->control.may_range_step)
remote_target::append_pending_thread_resumptions (char *p, char *endp,
ptid_t ptid)
{
- for (thread_info *thread : all_non_exited_threads (ptid))
+ for (thread_info *thread : all_non_exited_threads (this, ptid))
if (inferior_ptid != thread->ptid
&& thread->suspend.stop_signal != GDB_SIGNAL_0)
{
else
set_continue_thread (ptid);
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
resume_clear_thread_private_info (thread);
buf = rs->buf.data ();
remote_thread_info *remote_thr;
if (minus_one_ptid == ptid || ptid.is_pid ())
- remote_thr = get_remote_thread_info (inferior_ptid);
+ remote_thr = get_remote_thread_info (this, inferior_ptid);
else
- remote_thr = get_remote_thread_info (ptid);
+ remote_thr = get_remote_thread_info (this, ptid);
remote_thr->last_resume_step = step;
remote_thr->last_resume_sig = siggnal;
may_global_wildcard_vcont = 1;
/* And assume every process is individually wildcard-able too. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
remote_inferior *priv = get_remote_inferior (inf);
disable process and global wildcard resumes appropriately. */
check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont);
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
/* If a thread of a process is not meant to be resumed, then we
can't wildcard that process. */
struct vcont_builder vcont_builder (this);
/* Threads first. */
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
remote_thread_info *remote_thr = get_remote_thread_info (tp);
supposed to be resumed. */
any_process_wildcard = 0;
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (get_remote_inferior (inf)->may_wildcard_vcont)
{
}
else
{
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (get_remote_inferior (inf)->may_wildcard_vcont)
{
char *p = rs->buf.data ();
char *endp = p + get_remote_packet_size ();
- if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN)
+ /* FIXME: This supports_vCont_probed check is a workaround until
+ packet_support is per-connection. */
+ if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN
+ || !rs->supports_vCont_probed)
remote_vcont_probe ();
if (!rs->supports_vCont.t)
if (query (_("The target is not responding to interrupt requests.\n"
"Stop debugging it? ")))
{
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target."));
}
}
return rs->stop_reply_queue.size ();
}
-void
+static void
remote_notif_stop_parse (remote_target *remote,
struct notif_client *self, const char *buf,
struct notif_event *event)
/* For any threads stopped at a fork event, remove the corresponding
fork child threads from the CONTEXT list. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
struct target_waitstatus *ws = thread_pending_fork_status (thread);
|| event->ws.kind == TARGET_WAITKIND_VFORKED)
*may_global_wildcard = 0;
- struct inferior *inf = find_inferior_ptid (event->ptid);
+ struct inferior *inf = find_inferior_ptid (this, event->ptid);
/* This may be the first time we heard about this process.
Regardless, we must not do a global wildcard resume, otherwise
if (rsa == NULL)
{
- inferior *inf = (event->ptid == null_ptid
- ? NULL
- : find_inferior_ptid (event->ptid));
+ inferior *inf
+ = (event->ptid == null_ptid
+ ? NULL
+ : find_inferior_ptid (this, event->ptid));
/* If this is the first time we learn anything
about this process, skip the registers
included in this packet, since we don't yet
case 'W': /* Target exited. */
case 'X':
{
- int pid;
ULONGEST value;
/* GDB used to accept only 2 hex chars here. Stubs should
event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
}
- /* If no process is specified, assume inferior_ptid. */
- pid = inferior_ptid.pid ();
+ /* If no process is specified, return null_ptid, and let the
+ caller figure out the right process to use. */
+ int pid = 0;
if (*p == '\0')
;
else if (*p == ';')
<GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
2.5) <-- (registers reply to step #2.3)
- Eventualy after step #2.5, we return to the event loop, which
+ Eventually after step #2.5, we return to the event loop, which
notices there's an event on the
REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN event and calls the
associated callback --- the function below. At this point, we're
if (!stop_reply->regcache.empty ())
{
struct regcache *regcache
- = get_thread_arch_regcache (ptid, stop_reply->arch);
+ = get_thread_arch_regcache (this, ptid, stop_reply->arch);
for (cached_reg_t ® : stop_reply->regcache)
{
}
remote_notice_new_inferior (ptid, 0);
- remote_thread_info *remote_thr = get_remote_thread_info (ptid);
+ remote_thread_info *remote_thr = get_remote_thread_info (this, ptid);
remote_thr->core = stop_reply->core;
remote_thr->stop_reason = stop_reply->stop_reason;
remote_thr->watch_data_address = stop_reply->watch_data_address;
}
}
+/* Return the first resumed thread. */
+
+static ptid_t
+first_remote_resumed_thread (remote_target *target)
+{
+ for (thread_info *tp : all_non_exited_threads (target, minus_one_ptid))
+ if (tp->resumed)
+ return tp->ptid;
+ return null_ptid;
+}
+
/* Wait until the remote machine stops, then return, storing status in
STATUS just as `wait' would. */
if (event_ptid != null_ptid)
record_currthread (rs, event_ptid);
else
- event_ptid = inferior_ptid;
+ event_ptid = first_remote_resumed_thread (this);
}
else
- /* A process exit. Invalidate our notion of current thread. */
- record_currthread (rs, minus_one_ptid);
+ {
+ /* A process exit. Invalidate our notion of current thread. */
+ record_currthread (rs, minus_one_ptid);
+ /* It's possible that the packet did not include a pid. */
+ if (event_ptid == null_ptid)
+ event_ptid = first_remote_resumed_thread (this);
+ /* EVENT_PTID could still be NULL_PTID. Double-check. */
+ if (event_ptid == null_ptid)
+ event_ptid = magic_null_ptid;
+ }
return event_ptid;
}
for output compatibility with throw_perror_with_name. */
static void
-unpush_and_perror (const char *string)
+unpush_and_perror (remote_target *target, const char *string)
{
int saved_errno = errno;
- remote_unpush_target ();
+ remote_unpush_target (target);
throw_error (TARGET_CLOSE_ERROR, "%s: %s.", string,
safe_strerror (saved_errno));
}
switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR, _("Remote connection closed"));
/* no return */
case SERIAL_ERROR:
- unpush_and_perror (_("Remote communication error. "
- "Target disconnected."));
+ unpush_and_perror (this, _("Remote communication error. "
+ "Target disconnected."));
/* no return */
case SERIAL_TIMEOUT:
break;
if (serial_write (rs->remote_desc, str, len))
{
- unpush_and_perror (_("Remote communication error. "
- "Target disconnected."));
+ unpush_and_perror (this, _("Remote communication error. "
+ "Target disconnected."));
}
if (rs->got_ctrlc_during_io)
*p = '\0';
int len = (int) (p - buf2);
+ int max_chars;
+
+ if (remote_packet_max_chars < 0)
+ max_chars = len;
+ else
+ max_chars = remote_packet_max_chars;
std::string str
- = escape_buffer (buf2, std::min (len, REMOTE_DEBUG_MAX_CHAR));
+ = escape_buffer (buf2, std::min (len, max_chars));
fprintf_unfiltered (gdb_stdlog, "Sending packet: %s", str.c_str ());
- if (len > REMOTE_DEBUG_MAX_CHAR)
+ if (len > max_chars)
fprintf_unfiltered (gdb_stdlog, "[%d bytes omitted]",
- len - REMOTE_DEBUG_MAX_CHAR);
+ len - max_chars);
fprintf_unfiltered (gdb_stdlog, "...");
if (forever) /* Watchdog went off? Kill the target. */
{
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR,
_("Watchdog timeout has expired. "
"Target detached."));
{
if (remote_debug)
{
+ int max_chars;
+
+ if (remote_packet_max_chars < 0)
+ max_chars = val;
+ else
+ max_chars = remote_packet_max_chars;
+
std::string str
= escape_buffer (buf->data (),
- std::min (val, REMOTE_DEBUG_MAX_CHAR));
+ std::min (val, max_chars));
fprintf_unfiltered (gdb_stdlog, "Packet received: %s",
str.c_str ());
- if (val > REMOTE_DEBUG_MAX_CHAR)
+ if (val > max_chars)
fprintf_unfiltered (gdb_stdlog, "[%d bytes omitted]",
- val - REMOTE_DEBUG_MAX_CHAR);
+ val - max_chars);
fprintf_unfiltered (gdb_stdlog, "\n");
}
/* Kill the fork child threads of any threads in process PID
that are stopped at a fork event. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
struct target_waitstatus *ws = &thread->pending_follow;
inferior, then we will tell gdbserver to exit and unpush the
target. */
if (res == -1 && !remote_multi_process_p (rs)
- && number_of_live_inferiors () == 1)
+ && number_of_live_inferiors (this) == 1)
{
remote_kill_k ();
discard_pending_stop_replies (current_inferior ());
/* In 'target remote' mode with one inferior, we close the connection. */
- if (!rs->extended && number_of_live_inferiors () <= 1)
+ if (!rs->extended && number_of_live_inferiors (this) <= 1)
{
- unpush_target (this);
-
- /* remote_close takes care of doing most of the clean up. */
- generic_mourn_inferior ();
+ remote_unpush_target (this);
return;
}
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
-
- if (!have_inferiors ())
- {
- if (!remote_multi_process_p (rs))
- {
- /* Check whether the target is running now - some remote stubs
- automatically restart after kill. */
- putpkt ("?");
- getpkt (&rs->buf, 0);
-
- if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
- {
- /* Assume that the target has been restarted. Set
- inferior_ptid so that bits of core GDB realizes
- there's something here, e.g., so that the user can
- say "kill" again. */
- inferior_ptid = magic_null_ptid;
- }
- }
- }
}
bool
{
char hexid[20];
- pack_threadid (&hexid[0], ref); /* Convert threead id into hex. */
+ pack_threadid (&hexid[0], ref); /* Convert thread id into hex. */
hexid[16] = 0;
printf_filtered ("%s %s\n", title, (&hexid[0]));
}
{
/* Initialize it just to avoid a GCC false warning. */
char *p = NULL;
- /* FIXME we need to get register block size some other way. */
- extern int trace_regblock_size;
enum packet_result result;
struct remote_state *rs = get_remote_state ();
if (packet_support (PACKET_qTStatus) == PACKET_DISABLE)
return -1;
+ /* FIXME we need to get register block size some other way. */
trace_regblock_size
= rs->get_remote_arch_state (target_gdbarch ())->sizeof_g_packet;
int
remote_target::core_of_thread (ptid_t ptid)
{
- struct thread_info *info = find_thread_ptid (ptid);
+ thread_info *info = find_thread_ptid (this, ptid);
if (info != NULL && info->priv != NULL)
return get_remote_thread_info (info)->core;
scoped_restore_current_thread restore_thread;
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
set_general_thread (tp->ptid);
remote_target::pid_to_exec_file (int pid)
{
static gdb::optional<gdb::char_vector> filename;
- struct inferior *inf;
char *annex = NULL;
if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
return NULL;
- inf = find_inferior_pid (pid);
+ inferior *inf = find_inferior_pid (this, pid);
if (inf == NULL)
internal_error (__FILE__, __LINE__,
_("not currently attached to process %d"), pid);
int handle_len,
inferior *inf)
{
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
remote_thread_info *priv = get_remote_thread_info (tp);
inferior_event_handler (INF_REG_EVENT, data);
}
+int
+remote_target::async_wait_fd ()
+{
+ struct remote_state *rs = get_remote_state ();
+ return rs->remote_desc->fd;
+}
+
void
remote_target::async (int enable)
{
show_watchdog,
&setlist, &showlist);
+ add_setshow_zuinteger_unlimited_cmd ("remote-packet-max-chars", no_class,
+ &remote_packet_max_chars, _("\
+Set the maximum number of characters to display for each remote packet."), _("\
+Show the maximum number of characters to display for each remote packet."), _("\
+Specify \"unlimited\" to display all the characters."),
+ NULL, show_remote_packet_max_chars,
+ &setdebuglist, &showdebuglist);
+
/* Eventually initialize fileio. See fileio.c */
initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
}