/* 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/gdb_sys_time.h"
-#include "event-loop.h"
+#include "gdbsupport/event-loop.h"
#include "event-top.h"
#include "inf-loop.h"
#include "gdbsupport/scoped_restore.h"
#include "gdbsupport/environ.h"
#include "gdbsupport/byte-vector.h"
+#include <algorithm>
#include <unordered_map>
+#include "async-event.h"
/* The remote target. */
/* 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;
const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;
bool augmented_libraries_svr4_read () override;
- int follow_fork (int, int) override;
+ bool follow_fork (bool, bool) override;
void follow_exec (struct inferior *, const char *) override;
int insert_fork_catchpoint (int) override;
int remove_fork_catchpoint (int) 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);
}
if (try_open_exec && get_exec_file (0) == NULL)
exec_file_locate_attach (pid, 0, 1);
+ /* Check for exec file mismatch, and let the user solve it. */
+ validate_exec_file (1);
+
return inf;
}
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);
- inferior_ptid = currthread;
+ thread_info *thr
+ = remote_add_thread (currthread, running, executing);
+ switch_to_thread (thr);
}
return;
}
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);
}
putpkt (pass_packet);
getpkt (&rs->buf, 0);
packet_ok (rs->buf, &remote_protocol_packets[PACKET_QPassSignals]);
- if (rs->last_pass_packet)
- xfree (rs->last_pass_packet);
+ xfree (rs->last_pass_packet);
rs->last_pass_packet = pass_packet;
}
else
/* 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. */
return 0;
}
+/* Return true if INF only has one non-exited thread. */
+
+static bool
+has_single_non_exited_thread (inferior *inf)
+{
+ int count = 0;
+ for (thread_info *tp ATTRIBUTE_UNUSED : inf->non_exited_threads ())
+ if (++count > 1)
+ break;
+ return count == 1;
+}
+
/* Implement the to_update_thread_list function for the remote
targets. */
target. */
for (thread_info *tp : all_threads_safe ())
{
+ if (tp->inf->process_target () != this)
+ continue;
+
if (!context.contains_thread (tp->ptid))
{
+ /* Do not remove the thread if it is the last thread in
+ the inferior. This situation happens when we have a
+ pending exit process status to process. Otherwise we
+ may end up with a seemingly live inferior (i.e. pid
+ != 0) that has no threads. */
+ if (has_single_non_exited_thread (tp->inf))
+ continue;
+
/* Not found. */
delete_thread (tp);
}
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)
return;
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);
+ symfile_segment_data_up data
+ = get_symfile_segment_data (symfile_objfile->obfd);
do_segments = (data != NULL);
do_sections = num_segments == 0;
by assuming that the .text and .data offsets apply to the whole
text and data segments. Convert the offsets given in the packet
to base addresses for symfile_map_offsets_to_segments. */
- else if (data && data->num_segments == 2)
+ else if (data != nullptr && data->segments.size () == 2)
{
- segments[0] = data->segment_bases[0] + text_addr;
- segments[1] = data->segment_bases[1] + data_addr;
+ segments[0] = data->segments[0].base + text_addr;
+ segments[1] = data->segments[1].base + data_addr;
num_segments = 2;
}
/* If the object file has only one segment, assume that it is text
but programs with no code are useless. Of course the code might
have ended up in the data segment... to detect that we would need
the permissions here. */
- else if (data && data->num_segments == 1)
+ else if (data && data->segments.size () == 1)
{
- segments[0] = data->segment_bases[0] + text_addr;
+ segments[0] = data->segments[0].base + text_addr;
num_segments = 1;
}
/* There's no way to relocate by segment. */
if (do_segments)
{
- int ret = symfile_map_offsets_to_segments (symfile_objfile->obfd, data,
- offs, num_segments, segments);
+ int ret = symfile_map_offsets_to_segments (symfile_objfile->obfd,
+ data.get (), offs,
+ num_segments, segments);
if (ret == 0 && !do_sections)
error (_("Can not handle qOffsets TextSeg "
do_sections = 0;
}
- if (data)
- free_symfile_segment_data (data);
-
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);
struct remote_state *rs = get_remote_state ();
bool fake_pid_p = false;
- inferior_ptid = null_ptid;
+ switch_to_no_thread ();
- /* Now, if we have thread information, update inferior_ptid. */
+ /* Now, if we have thread information, update the current thread's
+ ptid. */
ptid_t curr_ptid = get_current_thread (wait_status);
if (curr_ptid != null_ptid)
/* 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, false);
+ set_running (this, event_ptid, false);
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? ")))
/* Register extra event sources in the event loop. */
rs->remote_async_inferior_event_token
- = create_async_event_handler (remote_async_inferior_event_handler,
- remote);
+ = create_async_event_handler (remote_async_inferior_event_handler, NULL);
rs->notif_state = remote_notif_state_allocate (remote);
/* Reset the target state; these things will be queried either by
/* 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. */
}
else
{
- inferior_ptid = null_ptid;
+ switch_to_no_thread ();
detach_inferior (current_inferior ());
}
}
it is named remote_follow_fork in anticipation of using it for the
remote target as well. */
-int
-remote_target::follow_fork (int follow_child, int detach_fork)
+bool
+remote_target::follow_fork (bool follow_child, bool detach_fork)
{
struct remote_state *rs = get_remote_state ();
enum target_waitkind kind = inferior_thread ()->pending_follow.kind;
remote_detach_pid (child_pid);
}
}
- return 0;
+
+ return false;
}
/* Target follow-exec function for remote targets. Save EXECD_PATHNAME
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,
target_pid_to_str (ptid_t (pid)).c_str ());
}
- set_current_inferior (remote_add_inferior (false, pid, 1, 0));
+ switch_to_inferior_no_thread (remote_add_inferior (false, pid, 1, 0));
inferior_ptid = ptid_t (pid);
if (target_is_non_stop_p ())
{
- struct thread_info *thread;
-
/* Get list of threads. */
update_thread_list ();
- thread = first_thread_of_inferior (current_inferior ());
- if (thread)
- inferior_ptid = thread->ptid;
- else
- inferior_ptid = ptid_t (pid);
+ thread_info *thread = first_thread_of_inferior (current_inferior ());
+ if (thread != nullptr)
+ switch_to_thread (thread);
/* Invalidate our notion of the remote current thread. */
record_currthread (rs, minus_one_ptid);
}
else
{
- /* Now, if we have thread information, update inferior_ptid. */
- inferior_ptid = remote_current_thread (inferior_ptid);
+ /* Now, if we have thread information, update the main thread's
+ ptid. */
+ ptid_t curr_ptid = remote_current_thread (ptid_t (pid));
/* Add the main thread to the thread list. */
- thread_info *thr = add_thread_silent (inferior_ptid);
+ thread_info *thr = add_thread_silent (this, curr_ptid);
+
+ switch_to_thread (thr);
+
/* 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."));
}
}
tb[0] = c;
tb[1] = 0;
- fputs_unfiltered (tb, gdb_stdtarg);
+ gdb_stdtarg->puts (tb);
}
- gdb_flush (gdb_stdtarg);
+ gdb_stdtarg->flush ();
}
struct stop_reply : public notif_event
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
reported expedited registers. */
if (event->ptid == null_ptid)
{
+ /* If there is no thread-id information then leave
+ the event->ptid as null_ptid. Later in
+ process_stop_reply we will pick a suitable
+ thread. */
const char *thr = strstr (p1 + 1, ";thread:");
if (thr != NULL)
event->ptid = read_ptid (thr + strlen (";thread:"),
NULL);
- else
- {
- /* Either the current thread hasn't changed,
- or the inferior is not multi-threaded.
- The event must be for the thread we last
- set as (or learned as being) current. */
- event->ptid = event->rs->general_thread;
- }
}
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 == ';')
event->ptid = minus_one_ptid;
break;
}
-
- if (target_is_non_stop_p () && event->ptid == null_ptid)
- error (_("No process or thread specified in stop reply: %s"), buf);
}
/* When the stub wants to tell GDB about a new notification reply, it
<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
*status = stop_reply->ws;
ptid = stop_reply->ptid;
- /* If no thread/process was reported by the stub, assume the current
- inferior. */
+ /* If no thread/process was reported by the stub then use the first
+ non-exited thread in the current target. */
if (ptid == null_ptid)
- ptid = inferior_ptid;
+ {
+ /* Some stop events apply to all threads in an inferior, while others
+ only apply to a single thread. */
+ bool is_stop_for_all_threads
+ = (status->kind == TARGET_WAITKIND_EXITED
+ || status->kind == TARGET_WAITKIND_SIGNALLED);
+
+ for (thread_info *thr : all_non_exited_threads (this))
+ {
+ if (ptid != null_ptid
+ && (!is_stop_for_all_threads
+ || ptid.pid () != thr->ptid.pid ()))
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ /* If you are seeing this warning then the remote target
+ has stopped without specifying a thread-id, but the
+ target does have multiple threads (or inferiors), and
+ so GDB is having to guess which thread stopped.
+
+ Examples of what might cause this are the target
+ sending and 'S' stop packet, or a 'T' stop packet and
+ not including a thread-id.
+
+ Additionally, the target might send a 'W' or 'X
+ packet without including a process-id, when the target
+ has multiple running inferiors. */
+ if (is_stop_for_all_threads)
+ warning (_("multi-inferior target stopped without "
+ "sending a process-id, using first "
+ "non-exited inferior"));
+ else
+ warning (_("multi-threaded target stopped without "
+ "sending a thread-id, using first "
+ "non-exited thread"));
+ warned = true;
+ }
+ break;
+ }
+
+ /* If this is a stop for all threads then don't use a particular
+ threads ptid, instead create a new ptid where only the pid
+ field is set. */
+ if (is_stop_for_all_threads)
+ ptid = ptid_t (thr->ptid.pid ());
+ else
+ ptid = thr->ptid;
+ }
+ gdb_assert (ptid != null_ptid);
+ }
if (status->kind != TARGET_WAITKIND_EXITED
&& status->kind != TARGET_WAITKIND_SIGNALLED
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
remote_file_delete (argv[0], from_tty);
}
-static void
-remote_command (const char *args, int from_tty)
-{
- help_list (remote_cmdlist, "remote ", all_commands, gdb_stdout);
-}
-
bool
remote_target::can_execute_reverse ()
{
encode_actions_rsp (loc, &tdp_actions, &stepping_actions);
tpaddr = loc->address;
- sprintf_vma (addrbuf, tpaddr);
+ strcpy (addrbuf, phex (tpaddr, sizeof (CORE_ADDR)));
ret = snprintf (buf.data (), buf.size (), "QTDP:%x:%s:%c:%lx:%x",
b->number, addrbuf, /* address */
(b->enable_state == bp_enabled ? 'E' : 'D'),
remote_target::enable_tracepoint (struct bp_location *location)
{
struct remote_state *rs = get_remote_state ();
- char addr_buf[40];
- sprintf_vma (addr_buf, location->address);
xsnprintf (rs->buf.data (), get_remote_packet_size (), "QTEnable:%x:%s",
- location->owner->number, addr_buf);
+ location->owner->number,
+ phex (location->address, sizeof (CORE_ADDR)));
putpkt (rs->buf);
remote_get_noisy_reply ();
if (rs->buf[0] == '\0')
remote_target::disable_tracepoint (struct bp_location *location)
{
struct remote_state *rs = get_remote_state ();
- char addr_buf[40];
- sprintf_vma (addr_buf, location->address);
xsnprintf (rs->buf.data (), get_remote_packet_size (), "QTDisable:%x:%s",
- location->owner->number, addr_buf);
+ location->owner->number,
+ phex (location->address, sizeof (CORE_ADDR)));
putpkt (rs->buf);
remote_get_noisy_reply ();
if (rs->buf[0] == '\0')
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);
{
/* Don't propogate error information up to the client. Instead let
the client find out about the error by querying the target. */
- inferior_event_handler (INF_REG_EVENT, NULL);
+ inferior_event_handler (INF_REG_EVENT);
}
static void
remote_async_inferior_event_handler (gdb_client_data data)
{
- inferior_event_handler (INF_REG_EVENT, data);
+ inferior_event_handler (INF_REG_EVENT);
+}
+
+int
+remote_target::async_wait_fd ()
+{
+ struct remote_state *rs = get_remote_state ();
+ return rs->remote_desc->fd;
}
void
}
}
-static void
-set_remote_cmd (const char *args, int from_tty)
-{
- help_list (remote_set_cmdlist, "set remote ", all_commands, gdb_stdout);
-}
-
static void
show_remote_cmd (const char *args, int from_tty)
{
}
}
+void _initialize_remote ();
void
-_initialize_remote (void)
+_initialize_remote ()
{
struct cmd_list_element *cmd;
const char *cmd_name;
/* set/show remote ... */
- add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, _("\
+ add_basic_prefix_cmd ("remote", class_maintenance, _("\
Remote protocol specific variables.\n\
Configure various remote-protocol specific variables such as\n\
the packets being used."),
- &remote_set_cmdlist, "set remote ",
- 0 /* allow-unknown */, &setlist);
+ &remote_set_cmdlist, "set remote ",
+ 0 /* allow-unknown */, &setlist);
add_prefix_cmd ("remote", class_maintenance, show_remote_cmd, _("\
Remote protocol specific variables.\n\
Configure various remote-protocol specific variables such as\n\
set_remotebreak, show_remotebreak,
&setlist, &showlist);
cmd_name = "remotebreak";
- cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ cmd = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
deprecate_cmd (cmd, "set remote interrupt-sequence");
cmd_name = "remotebreak"; /* needed because lookup_cmd updates the pointer */
- cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1);
+ cmd = lookup_cmd (&cmd_name, showlist, "", NULL, -1, 1);
deprecate_cmd (cmd, "show remote interrupt-sequence");
add_setshow_enum_cmd ("interrupt-sequence", class_support,
`Z' packets is %s. */
&remote_set_cmdlist, &remote_show_cmdlist);
- add_prefix_cmd ("remote", class_files, remote_command, _("\
+ add_basic_prefix_cmd ("remote", class_files, _("\
Manipulate files on the remote system.\n\
Transfer files to and from the remote target system."),
- &remote_cmdlist, "remote ",
- 0 /* allow-unknown */, &cmdlist);
+ &remote_cmdlist, "remote ",
+ 0 /* allow-unknown */, &cmdlist);
add_cmd ("put", class_files, remote_put_command,
_("Copy a local file to the remote system."),
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);
+ initialize_remote_fileio (&remote_set_cmdlist, &remote_show_cmdlist);
}