X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fremote.c;h=aa6a67a96e0a5be78243729611566358a20e96f4;hb=29ef4c0699e1b46d41ade00ae07a54f979ea21cc;hp=1fe6ed44fdf30995a5885c2c7f0274783eefed6e;hpb=2c2e7f87a81cb3834a31a81c48e37ea9bd469490;p=binutils-gdb.git diff --git a/gdb/remote.c b/gdb/remote.c index 1fe6ed44fdf..aa6a67a96e0 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1,6 +1,6 @@ /* Remote target communications for serial-line targets in custom GDB protocol - Copyright (C) 1988-2021 Free Software Foundation, Inc. + Copyright (C) 1988-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -79,6 +79,7 @@ #include #include #include "async-event.h" +#include "gdbsupport/selftest.h" /* The remote target. */ @@ -257,15 +258,6 @@ public: /* data */ Otherwise zero, meaning to use the guessed size. */ long explicit_packet_size = 0; - /* 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 = 0; - /* 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. */ @@ -399,7 +391,7 @@ private: static const target_info remote_target_info = { "remote", - N_("Remote serial target in gdb-specific protocol"), + N_("Remote target using gdb-specific protocol"), remote_doc }; @@ -425,16 +417,15 @@ public: void detach (inferior *, int) override; void disconnect (const char *, int) override; - void commit_resume () override; + void commit_resumed () override; void resume (ptid_t, int, enum gdb_signal) override; ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override; + bool has_pending_events () override; void fetch_registers (struct regcache *, int) override; void store_registers (struct regcache *, int) override; void prepare_to_store (struct regcache *) override; - void files_info () override; - int insert_breakpoint (struct gdbarch *, struct bp_target_info *) override; int remove_breakpoint (struct gdbarch *, struct bp_target_info *, @@ -491,7 +482,7 @@ public: const char *extra_thread_info (struct thread_info *) override; - ptid_t get_ada_task_ptid (long lwp, long thread) override; + ptid_t get_ada_task_ptid (long lwp, ULONGEST thread) override; thread_info *thread_handle_to_thread_info (const gdb_byte *thread_handle, int handle_len, @@ -667,8 +658,8 @@ public: bool use_agent (bool use) override; bool can_use_agent () override; - struct btrace_target_info *enable_btrace (ptid_t ptid, - const struct btrace_config *conf) override; + struct btrace_target_info * + enable_btrace (thread_info *tp, const struct btrace_config *conf) override; void disable_btrace (struct btrace_target_info *tinfo) override; @@ -680,8 +671,8 @@ public: const struct btrace_config *btrace_conf (const struct btrace_target_info *) override; bool augmented_libraries_svr4_read () override; - bool follow_fork (bool, bool) override; - void follow_exec (struct inferior *, const char *) override; + void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override; + void follow_exec (inferior *, ptid_t, const char *) override; int insert_fork_catchpoint (int) override; int remove_fork_catchpoint (int) override; int insert_vfork_catchpoint (int) override; @@ -760,25 +751,27 @@ public: /* Remote specific methods. */ target_waitstatus *status); ptid_t select_thread_for_ambiguous_stop_reply - (const struct target_waitstatus *status); + (const struct target_waitstatus &status); - void remote_notice_new_inferior (ptid_t currthread, int executing); + void remote_notice_new_inferior (ptid_t currthread, bool executing); + void print_one_stopped_thread (thread_info *thread); void process_initial_stop_replies (int from_tty); - thread_info *remote_add_thread (ptid_t ptid, bool running, bool executing); + thread_info *remote_add_thread (ptid_t ptid, bool running, bool executing, + bool silent_p); void btrace_sync_conf (const btrace_config *conf); void remote_btrace_maybe_reopen (); void remove_new_fork_children (threads_listing_context *context); - void kill_new_fork_children (int pid); + void kill_new_fork_children (inferior *inf); void discard_pending_stop_replies (struct inferior *inf); int stop_reply_queue_length (); void check_pending_events_prevent_wildcard_vcont - (int *may_global_wildcard_vcont); + (bool *may_global_wildcard_vcont); void discard_pending_stop_replies_in_queue (); struct stop_reply *remote_notif_remove_queued_reply (ptid_t ptid); @@ -953,9 +946,9 @@ public: /* Remote specific methods. */ bool vcont_r_supported (); - void packet_command (const char *args, int from_tty); +private: -private: /* data fields */ + bool start_remote_1 (int from_tty, int extended_p); /* The remote state. Don't reference this directly. Use the get_remote_state method instead. */ @@ -964,7 +957,7 @@ private: /* data fields */ static const target_info extended_remote_target_info = { "extended-remote", - N_("Extended remote serial target in gdb-specific protocol"), + N_("Extended remote target using gdb-specific protocol"), remote_doc }; @@ -993,6 +986,45 @@ public: bool supports_disable_randomization () override; }; +struct stop_reply : public notif_event +{ + ~stop_reply (); + + /* The identifier of the thread about this event */ + ptid_t ptid; + + /* The remote state this event is associated with. When the remote + connection, represented by a remote_state object, is closed, + all the associated stop_reply events should be released. */ + struct remote_state *rs; + + struct target_waitstatus ws; + + /* The architecture associated with the expedited registers. */ + gdbarch *arch; + + /* Expedited registers. This makes remote debugging a bit more + efficient for those targets that provide critical registers as + part of their normal status mechanism (as another roundtrip to + fetch them is avoided). */ + std::vector regcache; + + enum target_stop_reason stop_reason; + + CORE_ADDR watch_data_address; + + int core; +}; + +/* See remote.h. */ + +bool +is_remote_target (process_stratum_target *target) +{ + remote_target *rt = dynamic_cast (target); + return rt != nullptr; +} + /* Per-program-space data key. */ static const struct program_space_key> remote_pspace_data; @@ -1001,7 +1033,7 @@ static const struct program_space_key> remote exec-file commands. While the remote exec-file setting is per-program-space, the set/show machinery uses this as the location of the remote exec-file value. */ -static char *remote_exec_file_var; +static std::string remote_exec_file_var; /* The size to align memory write packets, when practical. The protocol does not guarantee any alignment, and gdb will generate short @@ -1027,14 +1059,10 @@ static int hexnumnstr (char *, ULONGEST, int); static CORE_ADDR remote_address_masked (CORE_ADDR); -static void print_packet (const char *); - static int stub_unpack_int (const char *buff, int fieldlength); struct packet_config; -static void show_packet_config_cmd (struct packet_config *config); - static void show_remote_protocol_packet_cmd (struct ui_file *file, int from_tty, struct cmd_list_element *c, @@ -1352,8 +1380,8 @@ static void set_remote_exec_file (const char *ignored, int from_tty, struct cmd_list_element *c) { - gdb_assert (remote_exec_file_var != NULL); - set_pspace_remote_exec_file (current_program_space, remote_exec_file_var); + set_pspace_remote_exec_file (current_program_space, + remote_exec_file_var.c_str ()); } /* The "set/show remote exec-file" show command hook. */ @@ -1870,6 +1898,9 @@ struct packet_config have an associated command always have this set to auto. */ enum auto_boolean detect; + /* The "show remote foo-packet" command created for this packet. */ + cmd_list_element *show_cmd; + /* Does the target support this packet? */ enum packet_support support; }; @@ -1878,7 +1909,7 @@ static enum packet_support packet_config_support (struct packet_config *config); static enum packet_support packet_support (int packet); static void -show_packet_config_cmd (struct packet_config *config) +show_packet_config_cmd (ui_file *file, struct packet_config *config) { const char *support = "internal-error"; @@ -1897,14 +1928,16 @@ show_packet_config_cmd (struct packet_config *config) switch (config->detect) { case AUTO_BOOLEAN_AUTO: - printf_filtered (_("Support for the `%s' packet " - "is auto-detected, currently %s.\n"), - config->name, support); + fprintf_filtered (file, + _("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); + fprintf_filtered (file, + _("Support for the `%s' packet is currently %s.\n"), + config->name, support); break; } } @@ -1913,37 +1946,36 @@ 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; - 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); + gdb::unique_xmalloc_ptr set_doc + = xstrprintf ("Set use of remote protocol `%s' (%s) packet.", + name, title); + gdb::unique_xmalloc_ptr 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 */ - NULL, - show_remote_protocol_packet_cmd, - &remote_set_cmdlist, &remote_show_cmdlist); - /* The command code copies the documentation strings. */ - xfree (set_doc); - xfree (show_doc); + gdb::unique_xmalloc_ptr cmd_name = xstrprintf ("%s-packet", title); + set_show_commands cmds + = add_setshow_auto_boolean_cmd (cmd_name.release (), class_obscure, + &config->detect, set_doc.get (), + show_doc.get (), NULL, /* help_doc */ + NULL, + show_remote_protocol_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist); + config->show_cmd = cmds.show; + /* 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, + /* It's not clear who should take ownership of this string, so, for + now, make it static, and give copies to each of the add_alias_cmd + calls below. */ + static gdb::unique_xmalloc_ptr legacy_name + = xstrprintf ("%s-packet", name); + add_alias_cmd (legacy_name.get (), cmds.set, class_obscure, 0, &remote_set_cmdlist); - add_alias_cmd (legacy_name, cmd_name, class_obscure, 0, + add_alias_cmd (legacy_name.get (), cmds.show, class_obscure, 0, &remote_show_cmdlist); } } @@ -2212,7 +2244,7 @@ packet_config_support (struct packet_config *config) case AUTO_BOOLEAN_AUTO: return config->support; default: - gdb_assert_not_reached (_("bad switch")); + gdb_assert_not_reached ("bad switch"); } } @@ -2233,14 +2265,15 @@ show_remote_protocol_packet_cmd (struct ui_file *file, int from_tty, const char *value) { struct packet_config *packet; + gdb_assert (c->var.has_value ()); for (packet = remote_protocol_packets; packet < &remote_protocol_packets[PACKET_MAX]; packet++) { - if (&packet->detect == c->var) + if (c == packet->show_cmd) { - show_packet_config_cmd (packet); + show_packet_config_cmd (file, packet); return; } } @@ -2284,7 +2317,7 @@ show_remote_protocol_Z_packet_cmd (struct ui_file *file, int from_tty, for (i = 0; i < NR_Z_PACKET_TYPES; i++) { - show_packet_config_cmd (&remote_protocol_packets[PACKET_Z0 + i]); + show_packet_config_cmd (file, &remote_protocol_packets[PACKET_Z0 + i]); } } @@ -2517,10 +2550,13 @@ 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. */ + according to EXECUTING and RUNNING respectively. If SILENT_P (or the + remote_state::starting_up flag) is true then the new thread is added + silently, otherwise the new thread will be announced to the user. */ thread_info * -remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing) +remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing, + bool silent_p) { struct remote_state *rs = get_remote_state (); struct thread_info *thread; @@ -2531,7 +2567,7 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing) consider that a single-threaded target, mentioning a new thread might be confusing to the user. Be silent then, preserving the age old behavior. */ - if (rs->starting_up) + if (rs->starting_up || silent_p) thread = add_thread_silent (this, ptid); else thread = add_thread (this, ptid); @@ -2554,12 +2590,12 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing) thread is (internally) executing or stopped. */ void -remote_target::remote_notice_new_inferior (ptid_t currthread, int executing) +remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing) { /* In non-stop mode, we assume new found threads are (externally) running until proven otherwise with a stop reply. In all-stop, we can only get here if all threads are stopped. */ - int running = target_is_non_stop_p () ? 1 : 0; + bool running = target_is_non_stop_p (); /* 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. */ @@ -2569,7 +2605,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing) { /* 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, executing); + remote_add_thread (currthread, running, executing, false); return; } @@ -2591,7 +2627,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing) else { thread_info *thr - = remote_add_thread (currthread, running, executing); + = remote_add_thread (currthread, running, executing, false); switch_to_thread (thr); } return; @@ -2623,7 +2659,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing) /* This is really a new thread. Add it. */ thread_info *new_thr - = remote_add_thread (currthread, running, executing); + = remote_add_thread (currthread, running, executing, false); /* If we found a new inferior, let the common code do whatever it needs to with it (e.g., read shared libraries, insert @@ -3095,7 +3131,7 @@ read_ptid (const char *buf, const char **obuf) pp = unpack_varlen_hex (p + 1, &tid); if (obuf) *obuf = pp; - return ptid_t (pid, tid, 0); + return ptid_t (pid, tid); } /* No multi-process. Just a tid. */ @@ -3120,7 +3156,7 @@ read_ptid (const char *buf, const char **obuf) if (obuf) *obuf = pp; - return ptid_t (pid, tid, 0); + return ptid_t (pid, tid); } static int @@ -3953,7 +3989,7 @@ remote_target::update_thread_list () executing until proven otherwise with a stop reply. In all-stop, we can only get here if all threads are stopped. */ - int executing = target_is_non_stop_p () ? 1 : 0; + bool executing = target_is_non_stop_p (); remote_notice_new_inferior (item.ptid, executing); @@ -4130,9 +4166,9 @@ remote_target::static_tracepoint_markers_by_strid (const char *strid) /* Implement the to_get_ada_task_ptid function for the remote targets. */ ptid_t -remote_target::get_ada_task_ptid (long lwp, long thread) +remote_target::get_ada_task_ptid (long lwp, ULONGEST thread) { - return ptid_t (inferior_ptid.pid (), lwp, 0); + return ptid_t (inferior_ptid.pid (), lwp); } @@ -4474,20 +4510,35 @@ remote_target::add_current_inferior_and_thread (const char *wait_status) /* Print info about a thread that was found already stopped on connection. */ -static void -print_one_stopped_thread (struct thread_info *thread) +void +remote_target::print_one_stopped_thread (thread_info *thread) { - struct target_waitstatus *ws = &thread->suspend.waitstatus; + target_waitstatus ws; + + /* If there is a pending waitstatus, use it. If there isn't it's because + the thread's stop was reported with TARGET_WAITKIND_STOPPED / GDB_SIGNAL_0 + and process_initial_stop_replies decided it wasn't interesting to save + and report to the core. */ + if (thread->has_pending_waitstatus ()) + { + ws = thread->pending_waitstatus (); + thread->clear_pending_waitstatus (); + } + else + { + ws.set_stopped (GDB_SIGNAL_0); + } switch_to_thread (thread); - thread->suspend.stop_pc = get_frame_pc (get_current_frame ()); + thread->set_stop_pc (get_frame_pc (get_current_frame ())); set_current_sal_from_frame (get_current_frame ()); - thread->suspend.waitstatus_pending_p = 0; + /* For "info program". */ + set_last_target_status (this, thread->ptid, ws); - if (ws->kind == TARGET_WAITKIND_STOPPED) + if (ws.kind () == TARGET_WAITKIND_STOPPED) { - enum gdb_signal sig = ws->value.sig; + enum gdb_signal sig = ws.sig (); if (signal_print_state (sig)) gdb::observers::signal_received.notify (sig); @@ -4508,6 +4559,9 @@ remote_target::process_initial_stop_replies (int from_tty) struct thread_info *lowest_stopped = NULL; struct thread_info *first = NULL; + /* This is only used when the target is non-stop. */ + gdb_assert (target_is_non_stop_p ()); + /* Consume the initial pending events. */ while (pending_stop_replies-- > 0) { @@ -4516,12 +4570,11 @@ remote_target::process_initial_stop_replies (int from_tty) struct target_waitstatus ws; int ignore_event = 0; - memset (&ws, 0, sizeof (ws)); event_ptid = target_wait (waiton_ptid, &ws, TARGET_WNOHANG); if (remote_debug) - print_target_wait_results (waiton_ptid, event_ptid, &ws); + print_target_wait_results (waiton_ptid, event_ptid, ws); - switch (ws.kind) + switch (ws.kind ()) { case TARGET_WAITKIND_IGNORE: case TARGET_WAITKIND_NO_RESUMED: @@ -4532,9 +4585,6 @@ remote_target::process_initial_stop_replies (int from_tty) ignore_event = 1; break; - case TARGET_WAITKIND_EXECD: - xfree (ws.value.execd_pathname); - break; default: break; } @@ -4544,23 +4594,21 @@ remote_target::process_initial_stop_replies (int from_tty) thread_info *evthread = find_thread_ptid (this, event_ptid); - if (ws.kind == TARGET_WAITKIND_STOPPED) + if (ws.kind () == TARGET_WAITKIND_STOPPED) { - enum gdb_signal sig = ws.value.sig; + enum gdb_signal sig = ws.sig (); /* Stubs traditionally report SIGTRAP as initial signal, instead of signal 0. Suppress it. */ if (sig == GDB_SIGNAL_TRAP) sig = GDB_SIGNAL_0; - evthread->suspend.stop_signal = sig; - ws.value.sig = sig; + evthread->set_stop_signal (sig); + ws.set_stopped (sig); } - evthread->suspend.waitstatus = ws; - - if (ws.kind != TARGET_WAITKIND_STOPPED - || ws.value.sig != GDB_SIGNAL_0) - evthread->suspend.waitstatus_pending_p = 1; + if (ws.kind () != TARGET_WAITKIND_STOPPED + || ws.sig () != GDB_SIGNAL_0) + evthread->set_pending_waitstatus (ws); set_executing (this, event_ptid, false); set_running (this, event_ptid, false); @@ -4586,7 +4634,15 @@ remote_target::process_initial_stop_replies (int from_tty) the inferiors. */ if (!non_stop) { - stop_all_threads (); + { + /* At this point, the remote target is not async. It needs to be for + the poll in stop_all_threads to consider events from it, so enable + it temporarily. */ + gdb_assert (!this->is_async_p ()); + SCOPE_EXIT { target_async (0); }; + target_async (1); + stop_all_threads (); + } /* If all threads of an inferior were already stopped, we haven't setup the inferior yet. */ @@ -4614,8 +4670,7 @@ remote_target::process_initial_stop_replies (int from_tty) else if (thread->state != THREAD_STOPPED) continue; - if (selected == NULL - && thread->suspend.waitstatus_pending_p) + if (selected == nullptr && thread->has_pending_waitstatus ()) selected = thread; if (lowest_stopped == NULL @@ -4639,17 +4694,47 @@ remote_target::process_initial_stop_replies (int from_tty) print_one_stopped_thread (thread); } - - /* For "info program". */ - thread_info *thread = inferior_thread (); - if (thread->state == THREAD_STOPPED) - set_last_target_status (this, inferior_ptid, thread->suspend.waitstatus); } -/* Start the remote connection and sync state. */ +/* Mark a remote_target as marking (by setting the starting_up flag within + its remote_state) for the lifetime of this object. The reference count + on the remote target is temporarily incremented, to prevent the target + being deleted under our feet. */ -void -remote_target::start_remote (int from_tty, int extended_p) +struct scoped_mark_target_starting +{ + /* Constructor, TARGET is the target to be marked as starting, its + reference count will be incremented. */ + scoped_mark_target_starting (remote_target *target) + : m_remote_target (target) + { + m_remote_target->incref (); + remote_state *rs = m_remote_target->get_remote_state (); + rs->starting_up = true; + } + + /* Destructor, mark the target being worked on as no longer starting, and + decrement the reference count. */ + ~scoped_mark_target_starting () + { + remote_state *rs = m_remote_target->get_remote_state (); + rs->starting_up = false; + decref_target (m_remote_target); + } + +private: + + /* The target on which we are operating. */ + remote_target *m_remote_target; +}; + +/* Helper for remote_target::start_remote, start the remote connection and + sync state. Return true if everything goes OK, otherwise, return false. + This function exists so that the scoped_restore created within it will + expire before we return to remote_target::start_remote. */ + +bool +remote_target::start_remote_1 (int from_tty, int extended_p) { REMOTE_SCOPED_DEBUG_ENTER_EXIT; @@ -4662,7 +4747,7 @@ remote_target::start_remote (int from_tty, int extended_p) Ctrl-C before we're connected and synced up can't interrupt the target. Instead, it offers to drop the (potentially wedged) connection. */ - rs->starting_up = 1; + scoped_mark_target_starting target_is_starting (this); QUIT; @@ -4800,11 +4885,7 @@ remote_target::start_remote (int from_tty, int extended_p) { if (!extended_p) error (_("The target is not running (try extended-remote?)")); - - /* We're connected, but not running. Drop out before we - call start_remote. */ - rs->starting_up = 0; - return; + return false; } else { @@ -4881,8 +4962,9 @@ remote_target::start_remote (int from_tty, int extended_p) /* Use the previously fetched status. */ gdb_assert (wait_status != NULL); - strcpy (rs->buf.data (), wait_status); - rs->cached_wait_status = 1; + struct notif_event *reply + = remote_notif_parse (this, ¬if_client_stop, wait_status); + push_stop_reply ((struct stop_reply *) reply); ::start_remote (from_tty); /* Initialize gdb process mechanisms. */ } @@ -4915,11 +4997,7 @@ remote_target::start_remote (int from_tty, int extended_p) { if (!extended_p) error (_("The target is not running (try extended-remote?)")); - - /* We're connected, but not running. Drop out before we - call start_remote. */ - rs->starting_up = 0; - return; + return false; } /* Report all signals during attach/startup. */ @@ -4959,14 +5037,16 @@ remote_target::start_remote (int from_tty, int extended_p) previously; find out where things are at. */ remote_btrace_maybe_reopen (); - /* The thread and inferior lists are now synchronized with the - target, our symbols have been relocated, and we're merged the - target's tracepoints with ours. We're done with basic start - up. */ - rs->starting_up = 0; + return true; +} + +/* Start the remote connection and sync state. */ - /* Maybe breakpoints are global and need to be inserted now. */ - if (breakpoints_should_be_inserted_now ()) +void +remote_target::start_remote (int from_tty, int extended_p) +{ + if (start_remote_1 (from_tty, extended_p) + && breakpoints_should_be_inserted_now ()) insert_breakpoints (); } @@ -5078,9 +5158,8 @@ remote_target::remote_check_symbols () /* If this is a function address, return the start of code instead of any data function descriptor. */ - sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), - sym_addr, - current_top_target ()); + sym_addr = gdbarch_convert_from_func_ptr_addr + (target_gdbarch (), sym_addr, current_inferior ()->top_target ()); xsnprintf (msg.data (), get_remote_packet_size (), "qSymbol:%s:%s", phex_nz (sym_addr, addr_size), &reply[8]); @@ -5620,6 +5699,15 @@ remote_unpush_target (remote_target *target) pop_all_targets_at_and_above (process_stratum); generic_mourn_inferior (); } + + /* Don't rely on target_close doing this when the target is popped + from the last remote inferior above, because something may be + holding a reference to the target higher up on the stack, meaning + target_close won't be called yet. We lost the connection to the + target, so clear these now, otherwise we may later throw + TARGET_CLOSE_ERROR while trying to tell the remote target to + close the file. */ + fileio_handles_invalidate_target (target); } static void @@ -5654,7 +5742,7 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p) remote_fileio_reset (); reopen_exec_file (); - reread_symbols (); + reread_symbols (from_tty); remote_target *remote = (extended_p ? new extended_remote_target () : new remote_target ()); @@ -5710,7 +5798,6 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p) /* Reset the target state; these things will be queried either by remote_query_supported or as they are needed. */ reset_all_packet_configs_support (); - rs->cached_wait_status = 0; rs->explicit_packet_size = 0; rs->noack_mode = 0; rs->extended = extended_p; @@ -5782,6 +5869,32 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p) rs->wait_forever_enabled_p = 1; } +/* Determine if WS represents a fork status. */ + +static bool +is_fork_status (target_waitkind kind) +{ + return (kind == TARGET_WAITKIND_FORKED + || kind == TARGET_WAITKIND_VFORKED); +} + +/* Return THREAD's pending status if it is a pending fork parent, else + return nullptr. */ + +static const target_waitstatus * +thread_pending_fork_status (struct thread_info *thread) +{ + const target_waitstatus &ws + = (thread->has_pending_waitstatus () + ? thread->pending_waitstatus () + : thread->pending_follow); + + if (!is_fork_status (ws.kind ())) + return nullptr; + + return &ws; +} + /* Detach the specified process. */ void @@ -5848,12 +5961,38 @@ remote_target::remote_detach_1 (inferior *inf, int from_tty) if (from_tty && !rs->extended && number_of_live_inferiors (this) == 1) puts_filtered (_("Ending remote debugging.\n")); + /* See if any thread of the inferior we are detaching has a pending fork + status. In that case, we must detach from the child resulting from + that fork. */ + for (thread_info *thread : inf->non_exited_threads ()) + { + const target_waitstatus *ws = thread_pending_fork_status (thread); + + if (ws == nullptr) + continue; + + remote_detach_pid (ws->child_ptid ().pid ()); + } + + /* Check also for any pending fork events in the stop reply queue. */ + remote_notif_get_pending_events (¬if_client_stop); + for (stop_reply_up &reply : rs->stop_reply_queue) + { + if (reply->ptid.pid () != pid) + continue; + + if (!is_fork_status (reply->ws.kind ())) + continue; + + remote_detach_pid (reply->ws.child_ptid ().pid ()); + } + 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. */ is_fork_parent = (tp != NULL - && tp->pending_follow.kind == TARGET_WAITKIND_FORKED); + && tp->pending_follow.kind () == TARGET_WAITKIND_FORKED); /* If doing detach-on-fork, we don't mourn, because that will delete breakpoints that should be available for the followed inferior. */ @@ -5894,14 +6033,18 @@ extended_remote_target::detach (inferior *inf, int from_tty) it is named remote_follow_fork in anticipation of using it for the remote target as well. */ -bool -remote_target::follow_fork (bool follow_child, bool detach_fork) +void +remote_target::follow_fork (inferior *child_inf, ptid_t child_ptid, + target_waitkind fork_kind, bool follow_child, + bool detach_fork) { + process_stratum_target::follow_fork (child_inf, child_ptid, + fork_kind, follow_child, detach_fork); + struct remote_state *rs = get_remote_state (); - enum target_waitkind kind = inferior_thread ()->pending_follow.kind; - if ((kind == TARGET_WAITKIND_FORKED && remote_fork_event_p (rs)) - || (kind == TARGET_WAITKIND_VFORKED && remote_vfork_event_p (rs))) + if ((fork_kind == TARGET_WAITKIND_FORKED && remote_fork_event_p (rs)) + || (fork_kind == TARGET_WAITKIND_VFORKED && remote_vfork_event_p (rs))) { /* When following the parent and detaching the child, we detach the child here. For the case of following the child and @@ -5912,34 +6055,26 @@ remote_target::follow_fork (bool follow_child, bool detach_fork) if (detach_fork && !follow_child) { /* Detach the fork child. */ - ptid_t child_ptid; - pid_t child_pid; - - child_ptid = inferior_thread ()->pending_follow.value.related_pid; - child_pid = child_ptid.pid (); - - remote_detach_pid (child_pid); + remote_detach_pid (child_ptid.pid ()); } } - - return false; } /* Target follow-exec function for remote targets. Save EXECD_PATHNAME - in the program space of the new inferior. On entry and at return the - current inferior is the exec'ing inferior. INF is the new exec'd - inferior, which may be the same as the exec'ing inferior unless - follow-exec-mode is "new". */ + in the program space of the new inferior. */ void -remote_target::follow_exec (struct inferior *inf, const char *execd_pathname) +remote_target::follow_exec (inferior *follow_inf, ptid_t ptid, + const char *execd_pathname) { + process_stratum_target::follow_exec (follow_inf, ptid, execd_pathname); + /* We know that this is a target file name, so if it has the "target:" prefix we strip it off before saving it in the program space. */ if (is_target_filename (execd_pathname)) execd_pathname += strlen (TARGET_SYSROOT_PREFIX); - set_pspace_remote_exec_file (inf->pspace, execd_pathname); + set_pspace_remote_exec_file (follow_inf->pspace, execd_pathname); } /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ @@ -5978,17 +6113,7 @@ extended_remote_target::attach (const char *args, int from_tty) if (packet_support (PACKET_vAttach) == PACKET_DISABLE) error (_("This target does not support attaching to a process")); - if (from_tty) - { - 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 ()); - else - printf_unfiltered (_("Attaching to %s\n"), - target_pid_to_str (ptid_t (pid)).c_str ()); - } + target_announce_attach (from_tty, pid); xsnprintf (rs->buf.data (), get_remote_packet_size (), "vAttach;%x", pid); putpkt (rs->buf); @@ -6038,14 +6163,11 @@ extended_remote_target::attach (const char *args, int from_tty) 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 (this, curr_ptid); + /* Add the main thread to the thread list. We add the thread + silently in this case (the final true parameter). */ + thread_info *thr = remote_add_thread (curr_ptid, true, true, true); switch_to_thread (thr); - - /* Don't consider the thread stopped until we've processed the - saved stop reply. */ - set_executing (this, thr->ptid, true); } /* Next, if the target can specify a description, read it. We do @@ -6057,28 +6179,16 @@ extended_remote_target::attach (const char *args, int from_tty) /* Use the previously fetched status. */ gdb_assert (wait_status != NULL); - if (target_can_async_p ()) - { - struct notif_event *reply - = remote_notif_parse (this, ¬if_client_stop, wait_status); - - push_stop_reply ((struct stop_reply *) reply); + struct notif_event *reply + = remote_notif_parse (this, ¬if_client_stop, wait_status); - target_async (1); - } - else - { - gdb_assert (wait_status != NULL); - strcpy (rs->buf.data (), wait_status); - rs->cached_wait_status = 1; - } + push_stop_reply ((struct stop_reply *) reply); } else { gdb_assert (wait_status == NULL); gdb_assert (target_can_async_p ()); - target_async (1); } } @@ -6221,7 +6331,7 @@ remote_target::append_resumption (char *p, char *endp, ptid_t nptid; /* All (-1) threads of process. */ - nptid = ptid_t (ptid.pid (), -1, 0); + nptid = ptid_t (ptid.pid (), -1); p += xsnprintf (p, endp - p, ":"); p = write_ptid (p, endp, nptid); @@ -6258,11 +6368,11 @@ remote_target::append_pending_thread_resumptions (char *p, char *endp, { for (thread_info *thread : all_non_exited_threads (this, ptid)) if (inferior_ptid != thread->ptid - && thread->suspend.stop_signal != GDB_SIGNAL_0) + && thread->stop_signal () != GDB_SIGNAL_0) { p = append_resumption (p, endp, thread->ptid, - 0, thread->suspend.stop_signal); - thread->suspend.stop_signal = GDB_SIGNAL_0; + 0, thread->stop_signal ()); + thread->set_stop_signal (GDB_SIGNAL_0); resume_clear_thread_private_info (thread); } @@ -6457,16 +6567,6 @@ remote_target::resume (ptid_t ptid, int step, enum gdb_signal siggnal) for (thread_info *tp : all_non_exited_threads (this, ptid)) get_remote_thread_info (tp)->set_resumed (); - /* We are about to start executing the inferior, let's register it - with the event loop. NOTE: this is the one place where all the - execution commands end up. We could alternatively do this in each - of the execution commands in infcmd.c. */ - /* FIXME: ezannoni 1999-09-28: We may need to move this out of here - into infcmd.c in order to allow inferior function calls to work - NOT asynchronously. */ - if (target_can_async_p ()) - target_async (1); - /* We've just told the target to resume. The remote server will wait for the inferior to stop, and then send a stop reply. In the mean time, we can't start another command/query ourselves @@ -6478,8 +6578,6 @@ remote_target::resume (ptid_t ptid, int step, enum gdb_signal siggnal) rs->waiting_for_stop_reply = 1; } -static int is_pending_fork_parent_thread (struct thread_info *thread); - /* Private per-inferior info for target remote processes. */ struct remote_inferior : public private_inferior @@ -6603,11 +6701,8 @@ vcont_builder::push_action (ptid_t ptid, bool step, gdb_signal siggnal) /* to_commit_resume implementation. */ void -remote_target::commit_resume () +remote_target::commit_resumed () { - int any_process_wildcard; - int may_global_wildcard_vcont; - /* If connected in all-stop mode, we'd send the remote resume request directly from remote_resume. Likewise if reverse-debugging, as there are no defined vCont actions for @@ -6664,7 +6759,7 @@ remote_target::commit_resume () (vCont;c). We can still send process-wide wildcards though. */ /* Start by assuming a global wildcard (vCont;c) is possible. */ - may_global_wildcard_vcont = 1; + bool may_global_wildcard_vcont = true; /* And assume every process is individually wildcard-able too. */ for (inferior *inf : all_non_exited_inferiors (this)) @@ -6678,6 +6773,8 @@ remote_target::commit_resume () disable process and global wildcard resumes appropriately. */ check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont); + bool any_pending_vcont_resume = false; + for (thread_info *tp : all_non_exited_threads (this)) { remote_thread_info *priv = get_remote_thread_info (tp); @@ -6690,17 +6787,25 @@ remote_target::commit_resume () /* And if we can't wildcard a process, we can't wildcard everything either. */ - may_global_wildcard_vcont = 0; + may_global_wildcard_vcont = false; continue; } + if (priv->get_resume_state () == resume_state::RESUMED_PENDING_VCONT) + any_pending_vcont_resume = true; + /* If a thread is the parent of an unfollowed fork, then we can't do a global wildcard, as that would resume the fork child. */ - if (is_pending_fork_parent_thread (tp)) - may_global_wildcard_vcont = 0; + if (thread_pending_fork_status (tp) != nullptr) + may_global_wildcard_vcont = false; } + /* We didn't have any resumed thread pending a vCont resume, so nothing to + do. */ + if (!any_pending_vcont_resume) + return; + /* Now let's build the vCont packet(s). Actions must be appended from narrower to wider scopes (thread -> process -> global). If we end up with too many actions for a single packet vcont_builder @@ -6721,6 +6826,13 @@ remote_target::commit_resume () gdb_assert (!thread_is_in_step_over_chain (tp)); + /* We should never be commit-resuming a thread that has a stop reply. + Otherwise, we would end up reporting a stop event for a thread while + it is running on the remote target. */ + remote_state *rs = get_remote_state (); + for (const auto &stop_reply : rs->stop_reply_queue) + gdb_assert (stop_reply->ptid != tp->ptid); + const resumed_pending_vcont_info &info = remote_thr->resumed_pending_vcont_info (); @@ -6736,13 +6848,13 @@ remote_target::commit_resume () /* Now check whether we can send any process-wide wildcard. This is to avoid sending a global wildcard in the case nothing is supposed to be resumed. */ - any_process_wildcard = 0; + bool any_process_wildcard = false; for (inferior *inf : all_non_exited_inferiors (this)) { if (get_remote_inferior (inf)->may_wildcard_vcont) { - any_process_wildcard = 1; + any_process_wildcard = true; break; } } @@ -6773,6 +6885,26 @@ remote_target::commit_resume () vcont_builder.flush (); } +/* Implementation of target_has_pending_events. */ + +bool +remote_target::has_pending_events () +{ + if (target_can_async_p ()) + { + remote_state *rs = get_remote_state (); + + if (async_event_handler_marked (rs->remote_async_inferior_event_token)) + return true; + + /* Note that BUFCNT can be negative, indicating sticky + error. */ + if (rs->remote_desc->bufcnt != 0) + return true; + } + return false; +} + /* Non-stop version of target_stop. Uses `vCont;t' to stop a remote @@ -6786,6 +6918,74 @@ remote_target::remote_stop_ns (ptid_t ptid) char *p = rs->buf.data (); char *endp = p + get_remote_packet_size (); + /* If any thread that needs to stop was resumed but pending a vCont + resume, generate a phony stop_reply. However, first check + whether the thread wasn't resumed with a signal. Generating a + phony stop in that case would result in losing the signal. */ + bool needs_commit = false; + for (thread_info *tp : all_non_exited_threads (this, ptid)) + { + remote_thread_info *remote_thr = get_remote_thread_info (tp); + + if (remote_thr->get_resume_state () + == resume_state::RESUMED_PENDING_VCONT) + { + const resumed_pending_vcont_info &info + = remote_thr->resumed_pending_vcont_info (); + if (info.sig != GDB_SIGNAL_0) + { + /* This signal must be forwarded to the inferior. We + could commit-resume just this thread, but its simpler + to just commit-resume everything. */ + needs_commit = true; + break; + } + } + } + + if (needs_commit) + commit_resumed (); + else + for (thread_info *tp : all_non_exited_threads (this, ptid)) + { + remote_thread_info *remote_thr = get_remote_thread_info (tp); + + if (remote_thr->get_resume_state () + == resume_state::RESUMED_PENDING_VCONT) + { + remote_debug_printf ("Enqueueing phony stop reply for thread pending " + "vCont-resume (%d, %ld, %s)", tp->ptid.pid(), + tp->ptid.lwp (), + pulongest (tp->ptid.tid ())); + + /* Check that the thread wasn't resumed with a signal. + Generating a phony stop would result in losing the + signal. */ + const resumed_pending_vcont_info &info + = remote_thr->resumed_pending_vcont_info (); + gdb_assert (info.sig == GDB_SIGNAL_0); + + stop_reply *sr = new stop_reply (); + sr->ptid = tp->ptid; + sr->rs = rs; + sr->ws.set_stopped (GDB_SIGNAL_0); + sr->arch = tp->inf->gdbarch; + sr->stop_reason = TARGET_STOPPED_BY_NO_REASON; + sr->watch_data_address = 0; + sr->core = 0; + this->push_stop_reply (sr); + + /* Pretend that this thread was actually resumed on the + remote target, then stopped. If we leave it in the + RESUMED_PENDING_VCONT state and the commit_resumed + method is called while the stop reply is still in the + queue, we'll end up reporting a stop event to the core + for that thread while it is running on the remote + target... that would be bad. */ + remote_thr->set_resumed (); + } + } + /* FIXME: This supports_vCont_probed check is a workaround until packet_support is per-connection. */ if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN @@ -6806,7 +7006,7 @@ remote_target::remote_stop_ns (ptid_t ptid) if (ptid.is_pid ()) /* All (-1) threads of process. */ - nptid = ptid_t (ptid.pid (), -1, 0); + nptid = ptid_t (ptid.pid (), -1); else { /* Small optimization: if we already have a stop reply for @@ -6842,9 +7042,9 @@ remote_target::remote_interrupt_as () rs->ctrlc_pending_p = 1; /* If the inferior is stopped already, but the core didn't know - about it yet, just ignore the request. The cached wait status + about it yet, just ignore the request. The pending stop events will be collected in remote_wait. */ - if (rs->cached_wait_status) + if (stop_reply_queue_length () > 0) return; /* Send interrupt_sequence to remote target. */ @@ -6990,36 +7190,6 @@ remote_console_output (const char *msg) gdb_stdtarg->flush (); } -struct stop_reply : public notif_event -{ - ~stop_reply (); - - /* The identifier of the thread about this event */ - ptid_t ptid; - - /* The remote state this event is associated with. When the remote - connection, represented by a remote_state object, is closed, - all the associated stop_reply events should be released. */ - struct remote_state *rs; - - struct target_waitstatus ws; - - /* The architecture associated with the expedited registers. */ - gdbarch *arch; - - /* Expedited registers. This makes remote debugging a bit more - efficient for those targets that provide critical registers as - part of their normal status mechanism (as another roundtrip to - fetch them is avoided). */ - std::vector regcache; - - enum target_stop_reason stop_reason; - - CORE_ADDR watch_data_address; - - int core; -}; - /* Return the length of the stop reply queue. */ int @@ -7050,7 +7220,7 @@ remote_notif_stop_ack (remote_target *remote, /* Kind can be TARGET_WAITKIND_IGNORE if we have meanwhile discarded the notification. It was left in the queue because we need to acknowledge it and pull the rest of the notifications out. */ - if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE) + if (stop_reply->ws.kind () != TARGET_WAITKIND_IGNORE) remote->push_stop_reply (stop_reply); } @@ -7093,47 +7263,6 @@ struct notif_client notif_client_stop = REMOTE_NOTIF_STOP, }; -/* Determine if THREAD_PTID is a pending fork parent thread. ARG contains - the pid of the process that owns the threads we want to check, or - -1 if we want to check all threads. */ - -static int -is_pending_fork_parent (struct target_waitstatus *ws, int event_pid, - ptid_t thread_ptid) -{ - if (ws->kind == TARGET_WAITKIND_FORKED - || ws->kind == TARGET_WAITKIND_VFORKED) - { - if (event_pid == -1 || event_pid == thread_ptid.pid ()) - return 1; - } - - return 0; -} - -/* Return the thread's pending status used to determine whether the - thread is a fork parent stopped at a fork event. */ - -static struct target_waitstatus * -thread_pending_fork_status (struct thread_info *thread) -{ - if (thread->suspend.waitstatus_pending_p) - return &thread->suspend.waitstatus; - else - return &thread->pending_follow; -} - -/* Determine if THREAD is a pending fork parent thread. */ - -static int -is_pending_fork_parent_thread (struct thread_info *thread) -{ - struct target_waitstatus *ws = thread_pending_fork_status (thread); - int pid = -1; - - return is_pending_fork_parent (ws, pid, thread->ptid); -} - /* If CONTEXT contains any fork child threads that have not been reported yet, remove them from the CONTEXT list. If such a thread exists it is because we are stopped at a fork catchpoint @@ -7143,17 +7272,18 @@ is_pending_fork_parent_thread (struct thread_info *thread) void remote_target::remove_new_fork_children (threads_listing_context *context) { - int pid = -1; struct notif_client *notif = ¬if_client_stop; /* 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 (this)) { - struct target_waitstatus *ws = thread_pending_fork_status (thread); + const target_waitstatus *ws = thread_pending_fork_status (thread); - if (is_pending_fork_parent (ws, pid, thread->ptid)) - context->remove_thread (ws->value.related_pid); + if (ws == nullptr) + continue; + + context->remove_thread (ws->child_ptid ()); } /* Check for any pending fork events (not reported or processed yet) @@ -7161,43 +7291,45 @@ remote_target::remove_new_fork_children (threads_listing_context *context) CONTEXT list as well. */ remote_notif_get_pending_events (notif); for (auto &event : get_remote_state ()->stop_reply_queue) - if (event->ws.kind == TARGET_WAITKIND_FORKED - || event->ws.kind == TARGET_WAITKIND_VFORKED - || event->ws.kind == TARGET_WAITKIND_THREAD_EXITED) - context->remove_thread (event->ws.value.related_pid); + if (event->ws.kind () == TARGET_WAITKIND_FORKED + || event->ws.kind () == TARGET_WAITKIND_VFORKED + || event->ws.kind () == TARGET_WAITKIND_THREAD_EXITED) + context->remove_thread (event->ws.child_ptid ()); } -/* Check whether any event pending in the vStopped queue would prevent - a global or process wildcard vCont action. Clear - *may_global_wildcard if we can't do a global wildcard (vCont;c), - and clear the event inferior's may_wildcard_vcont flag if we can't - do a process-wide wildcard resume (vCont;c:pPID.-1). */ +/* Check whether any event pending in the vStopped queue would prevent a + global or process wildcard vCont action. Set *may_global_wildcard to + false if we can't do a global wildcard (vCont;c), and clear the event + inferior's may_wildcard_vcont flag if we can't do a process-wide + wildcard resume (vCont;c:pPID.-1). */ void remote_target::check_pending_events_prevent_wildcard_vcont - (int *may_global_wildcard) + (bool *may_global_wildcard) { struct notif_client *notif = ¬if_client_stop; remote_notif_get_pending_events (notif); for (auto &event : get_remote_state ()->stop_reply_queue) { - if (event->ws.kind == TARGET_WAITKIND_NO_RESUMED - || event->ws.kind == TARGET_WAITKIND_NO_HISTORY) + if (event->ws.kind () == TARGET_WAITKIND_NO_RESUMED + || event->ws.kind () == TARGET_WAITKIND_NO_HISTORY) continue; - if (event->ws.kind == TARGET_WAITKIND_FORKED - || event->ws.kind == TARGET_WAITKIND_VFORKED) - *may_global_wildcard = 0; - - struct inferior *inf = find_inferior_ptid (this, event->ptid); + if (event->ws.kind () == TARGET_WAITKIND_FORKED + || event->ws.kind () == TARGET_WAITKIND_VFORKED) + *may_global_wildcard = false; /* This may be the first time we heard about this process. Regardless, we must not do a global wildcard resume, otherwise we'd resume this process too. */ - *may_global_wildcard = 0; - if (inf != NULL) - get_remote_inferior (inf)->may_wildcard_vcont = false; + *may_global_wildcard = false; + if (event->ptid != null_ptid) + { + inferior *inf = find_inferior_ptid (this, event->ptid); + if (inf != NULL) + get_remote_inferior (inf)->may_wildcard_vcont = false; + } } } @@ -7223,11 +7355,11 @@ remote_target::discard_pending_stop_replies (struct inferior *inf) /* Leave the notification pending, since the server expects that we acknowledge it with vStopped. But clear its contents, so that later on when we acknowledge it, we also discard it. */ - reply->ws.kind = TARGET_WAITKIND_IGNORE; - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, - "discarded in-flight notification\n"); + remote_debug_printf + ("discarding in-flight notification: ptid: %s, ws: %s\n", + reply->ptid.to_string().c_str(), + reply->ws.to_string ().c_str ()); + reply->ws.set_ignore (); } /* Discard the stop replies we have already pulled with @@ -7238,6 +7370,11 @@ remote_target::discard_pending_stop_replies (struct inferior *inf) { return event->ptid.pid () == inf->pid; }); + for (auto it = iter; it != rs->stop_reply_queue.end (); ++it) + remote_debug_printf + ("discarding queued stop reply: ptid: %s, ws: %s\n", + reply->ptid.to_string().c_str(), + reply->ws.to_string ().c_str ()); rs->stop_reply_queue.erase (iter, rs->stop_reply_queue.end ()); } @@ -7285,7 +7422,7 @@ remote_target::remote_notif_remove_queued_reply (ptid_t ptid) if (notif_debug) fprintf_unfiltered (gdb_stdlog, "notif: discard queued event: 'Stop' in %s\n", - target_pid_to_str (ptid).c_str ()); + ptid.to_string ().c_str ()); return result; } @@ -7301,7 +7438,7 @@ remote_target::queued_stop_reply (ptid_t ptid) remote_state *rs = get_remote_state (); struct stop_reply *r = remote_notif_remove_queued_reply (ptid); - if (!rs->stop_reply_queue.empty ()) + if (!rs->stop_reply_queue.empty () && target_can_async_p ()) { /* There's still at least an event left. */ mark_async_event_handler (rs->remote_async_inferior_event_token); @@ -7323,10 +7460,15 @@ remote_target::push_stop_reply (struct stop_reply *new_event) if (notif_debug) fprintf_unfiltered (gdb_stdlog, "notif: push 'Stop' %s to queue %d\n", - target_pid_to_str (new_event->ptid).c_str (), + new_event->ptid.to_string ().c_str (), int (rs->stop_reply_queue.size ())); - mark_async_event_handler (rs->remote_async_inferior_event_token); + /* Mark the pending event queue only if async mode is currently enabled. + If async mode is not currently enabled, then, if it later becomes + enabled, and there are events in this queue, we will mark the event + token at that point, see remote_target::async. */ + if (target_is_async_p ()) + mark_async_event_handler (rs->remote_async_inferior_event_token); } /* Returns true if we have a stop reply for PTID. */ @@ -7337,7 +7479,7 @@ remote_target::peek_stop_reply (ptid_t ptid) remote_state *rs = get_remote_state (); for (auto &event : rs->stop_reply_queue) if (ptid == event->ptid - && event->ws.kind == TARGET_WAITKIND_STOPPED) + && event->ws.kind () == TARGET_WAITKIND_STOPPED) return 1; return 0; } @@ -7367,8 +7509,7 @@ remote_target::remote_parse_stop_reply (const char *buf, stop_reply *event) event->ptid = null_ptid; event->rs = get_remote_state (); - event->ws.kind = TARGET_WAITKIND_IGNORE; - event->ws.value.integer = 0; + event->ws.set_ignore (); event->stop_reason = TARGET_STOPPED_BY_NO_REASON; event->regcache.clear (); event->core = -1; @@ -7412,17 +7553,15 @@ Packet: '%s'\n"), { ULONGEST sysno; - event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; p = unpack_varlen_hex (++p1, &sysno); - event->ws.value.syscall_number = (int) sysno; + event->ws.set_syscall_entry ((int) sysno); } else if (strprefix (p, p1, "syscall_return")) { ULONGEST sysno; - event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; p = unpack_varlen_hex (++p1, &sysno); - event->ws.value.syscall_number = (int) sysno; + event->ws.set_syscall_return ((int) sysno); } else if (strprefix (p, p1, "watch") || strprefix (p, p1, "rwatch") @@ -7460,12 +7599,12 @@ Packet: '%s'\n"), } else if (strprefix (p, p1, "library")) { - event->ws.kind = TARGET_WAITKIND_LOADED; + event->ws.set_loaded (); p = strchrnul (p1 + 1, ';'); } else if (strprefix (p, p1, "replaylog")) { - event->ws.kind = TARGET_WAITKIND_NO_HISTORY; + event->ws.set_no_history (); /* p1 will indicate "begin" or "end", but it makes no difference for now, so ignore it. */ p = strchrnul (p1 + 1, ';'); @@ -7478,18 +7617,12 @@ Packet: '%s'\n"), event->core = c; } else if (strprefix (p, p1, "fork")) - { - event->ws.value.related_pid = read_ptid (++p1, &p); - event->ws.kind = TARGET_WAITKIND_FORKED; - } + event->ws.set_forked (read_ptid (++p1, &p)); else if (strprefix (p, p1, "vfork")) - { - event->ws.value.related_pid = read_ptid (++p1, &p); - event->ws.kind = TARGET_WAITKIND_VFORKED; - } + event->ws.set_vforked (read_ptid (++p1, &p)); else if (strprefix (p, p1, "vforkdone")) { - event->ws.kind = TARGET_WAITKIND_VFORK_DONE; + event->ws.set_vfork_done (); p = strchrnul (p1 + 1, ';'); } else if (strprefix (p, p1, "exec")) @@ -7503,14 +7636,13 @@ Packet: '%s'\n"), /* Save the pathname for event reporting and for the next run command. */ - gdb::unique_xmalloc_ptr pathname + gdb::unique_xmalloc_ptr pathname ((char *) xmalloc (pathlen + 1)); hex2bin (p1, (gdb_byte *) pathname.get (), pathlen); - pathname[pathlen] = '\0'; + pathname.get ()[pathlen] = '\0'; /* This is freed during event handling. */ - event->ws.value.execd_pathname = pathname.release (); - event->ws.kind = TARGET_WAITKIND_EXECD; + event->ws.set_execd (std::move (pathname)); /* Skip the registers included in this packet, since they may be for an architecture different from the @@ -7519,7 +7651,7 @@ Packet: '%s'\n"), } else if (strprefix (p, p1, "create")) { - event->ws.kind = TARGET_WAITKIND_THREAD_CREATED; + event->ws.set_thread_created (); p = strchrnul (p1 + 1, ';'); } else @@ -7618,7 +7750,7 @@ Packet: '%s'\n"), ++p; } - if (event->ws.kind != TARGET_WAITKIND_IGNORE) + if (event->ws.kind () != TARGET_WAITKIND_IGNORE) break; /* fall through */ @@ -7626,21 +7758,19 @@ Packet: '%s'\n"), { int sig; - event->ws.kind = TARGET_WAITKIND_STOPPED; sig = (fromhex (buf[1]) << 4) + fromhex (buf[2]); if (GDB_SIGNAL_FIRST <= sig && sig < GDB_SIGNAL_LAST) - event->ws.value.sig = (enum gdb_signal) sig; + event->ws.set_stopped ((enum gdb_signal) sig); else - event->ws.value.sig = GDB_SIGNAL_UNKNOWN; + event->ws.set_stopped (GDB_SIGNAL_UNKNOWN); } break; case 'w': /* Thread exited. */ { ULONGEST value; - event->ws.kind = TARGET_WAITKIND_THREAD_EXITED; p = unpack_varlen_hex (&buf[1], &value); - event->ws.value.integer = value; + event->ws.set_thread_exited (value); if (*p != ';') error (_("stop reply packet badly formatted: %s"), buf); event->ptid = read_ptid (++p, NULL); @@ -7659,17 +7789,15 @@ Packet: '%s'\n"), if (buf[0] == 'W') { /* The remote process exited. */ - event->ws.kind = TARGET_WAITKIND_EXITED; - event->ws.value.integer = value; + event->ws.set_exited (value); } else { /* The remote process exited with a signal. */ - event->ws.kind = TARGET_WAITKIND_SIGNALLED; if (GDB_SIGNAL_FIRST <= value && value < GDB_SIGNAL_LAST) - event->ws.value.sig = (enum gdb_signal) value; + event->ws.set_signalled ((enum gdb_signal) value); else - event->ws.value.sig = GDB_SIGNAL_UNKNOWN; + event->ws.set_signalled (GDB_SIGNAL_UNKNOWN); } /* If no process is specified, return null_ptid, and let the @@ -7700,7 +7828,7 @@ Packet: '%s'\n"), } break; case 'N': - event->ws.kind = TARGET_WAITKIND_NO_RESUMED; + event->ws.set_no_resumed (); event->ptid = minus_one_ptid; break; } @@ -7826,13 +7954,17 @@ remote_notif_get_pending_events (remote_target *remote, notif_client *nc) ptid_t remote_target::select_thread_for_ambiguous_stop_reply - (const struct target_waitstatus *status) + (const target_waitstatus &status) { + REMOTE_SCOPED_DEBUG_ENTER_EXIT; + /* Some stop events apply to all threads in an inferior, while others only apply to a single thread. */ bool process_wide_stop - = (status->kind == TARGET_WAITKIND_EXITED - || status->kind == TARGET_WAITKIND_SIGNALLED); + = (status.kind () == TARGET_WAITKIND_EXITED + || status.kind () == TARGET_WAITKIND_SIGNALLED); + + remote_debug_printf ("process_wide_stop = %d", process_wide_stop); thread_info *first_resumed_thread = nullptr; bool ambiguous = false; @@ -7855,6 +7987,10 @@ remote_target::select_thread_for_ambiguous_stop_reply gdb_assert (first_resumed_thread != nullptr); + remote_debug_printf ("first resumed thread is %s", + pid_to_str (first_resumed_thread->ptid).c_str ()); + remote_debug_printf ("is this guess ambiguous? = %d", ambiguous); + /* Warn if the remote target is sending ambiguous stop replies. */ if (ambiguous) { @@ -7908,12 +8044,12 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply, /* If no thread/process was reported by the stub then select a suitable thread/process. */ if (ptid == null_ptid) - ptid = select_thread_for_ambiguous_stop_reply (status); + ptid = select_thread_for_ambiguous_stop_reply (*status); gdb_assert (ptid != null_ptid); - if (status->kind != TARGET_WAITKIND_EXITED - && status->kind != TARGET_WAITKIND_SIGNALLED - && status->kind != TARGET_WAITKIND_NO_RESUMED) + if (status->kind () != TARGET_WAITKIND_EXITED + && status->kind () != TARGET_WAITKIND_SIGNALLED + && status->kind () != TARGET_WAITKIND_NO_RESUMED) { /* Expedited registers. */ if (!stop_reply->regcache.empty ()) @@ -7930,7 +8066,7 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply, stop_reply->regcache.clear (); } - remote_notice_new_inferior (ptid, 0); + remote_notice_new_inferior (ptid, false); 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; @@ -8003,7 +8139,7 @@ remote_target::wait_ns (ptid_t ptid, struct target_waitstatus *status, return to the event loop. */ if (options & TARGET_WNOHANG) { - status->kind = TARGET_WAITKIND_IGNORE; + status->set_ignore (); return minus_one_ptid; } @@ -8018,7 +8154,7 @@ 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) + if (tp->resumed ()) return tp->ptid; return null_ptid; } @@ -8037,26 +8173,24 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, again: - status->kind = TARGET_WAITKIND_IGNORE; - status->value.integer = 0; + status->set_ignore (); stop_reply = queued_stop_reply (ptid); if (stop_reply != NULL) - return process_stop_reply (stop_reply, status); - - if (rs->cached_wait_status) - /* Use the cached wait status, but only once. */ - rs->cached_wait_status = 0; + { + /* None of the paths that push a stop reply onto the queue should + have set the waiting_for_stop_reply flag. */ + gdb_assert (!rs->waiting_for_stop_reply); + event_ptid = process_stop_reply (stop_reply, status); + } else { - int ret; - int is_notif; int forever = ((options & TARGET_WNOHANG) == 0 && rs->wait_forever_enabled_p); if (!rs->waiting_for_stop_reply) { - status->kind = TARGET_WAITKIND_NO_RESUMED; + status->set_no_resumed (); return minus_one_ptid; } @@ -8064,7 +8198,8 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, _never_ wait for ever -> test on target_is_async_p(). However, before we do that we need to ensure that the caller knows how to take the target into/out of async mode. */ - ret = getpkt_or_notif_sane (&rs->buf, forever, &is_notif); + int is_notif; + int ret = getpkt_or_notif_sane (&rs->buf, forever, &is_notif); /* GDB gets a notification. Return to core as this event is not interesting. */ @@ -8073,79 +8208,78 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, if (ret == -1 && (options & TARGET_WNOHANG) != 0) return minus_one_ptid; - } - buf = rs->buf.data (); + buf = rs->buf.data (); - /* Assume that the target has acknowledged Ctrl-C unless we receive - an 'F' or 'O' packet. */ - if (buf[0] != 'F' && buf[0] != 'O') - rs->ctrlc_pending_p = 0; + /* Assume that the target has acknowledged Ctrl-C unless we receive + an 'F' or 'O' packet. */ + if (buf[0] != 'F' && buf[0] != 'O') + rs->ctrlc_pending_p = 0; - switch (buf[0]) - { - case 'E': /* Error of some sort. */ - /* We're out of sync with the target now. Did it continue or - not? Not is more likely, so report a stop. */ - rs->waiting_for_stop_reply = 0; + switch (buf[0]) + { + case 'E': /* Error of some sort. */ + /* We're out of sync with the target now. Did it continue or + not? Not is more likely, so report a stop. */ + rs->waiting_for_stop_reply = 0; - warning (_("Remote failure reply: %s"), buf); - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = GDB_SIGNAL_0; - break; - case 'F': /* File-I/O request. */ - /* GDB may access the inferior memory while handling the File-I/O - request, but we don't want GDB accessing memory while waiting - for a stop reply. See the comments in putpkt_binary. Set - waiting_for_stop_reply to 0 temporarily. */ - rs->waiting_for_stop_reply = 0; - remote_fileio_request (this, buf, rs->ctrlc_pending_p); - rs->ctrlc_pending_p = 0; - /* GDB handled the File-I/O request, and the target is running - again. Keep waiting for events. */ - rs->waiting_for_stop_reply = 1; - break; - case 'N': case 'T': case 'S': case 'X': case 'W': - { - /* There is a stop reply to handle. */ - rs->waiting_for_stop_reply = 0; + warning (_("Remote failure reply: %s"), buf); + status->set_stopped (GDB_SIGNAL_0); + break; + case 'F': /* File-I/O request. */ + /* GDB may access the inferior memory while handling the File-I/O + request, but we don't want GDB accessing memory while waiting + for a stop reply. See the comments in putpkt_binary. Set + waiting_for_stop_reply to 0 temporarily. */ + rs->waiting_for_stop_reply = 0; + remote_fileio_request (this, buf, rs->ctrlc_pending_p); + rs->ctrlc_pending_p = 0; + /* GDB handled the File-I/O request, and the target is running + again. Keep waiting for events. */ + rs->waiting_for_stop_reply = 1; + break; + case 'N': case 'T': case 'S': case 'X': case 'W': + { + /* There is a stop reply to handle. */ + rs->waiting_for_stop_reply = 0; - stop_reply - = (struct stop_reply *) remote_notif_parse (this, - ¬if_client_stop, - rs->buf.data ()); + stop_reply + = (struct stop_reply *) remote_notif_parse (this, + ¬if_client_stop, + rs->buf.data ()); - event_ptid = process_stop_reply (stop_reply, status); - break; - } - case 'O': /* Console output. */ - remote_console_output (buf + 1); - break; - case '\0': - if (rs->last_sent_signal != GDB_SIGNAL_0) - { - /* Zero length reply means that we tried 'S' or 'C' and the - remote system doesn't support it. */ - target_terminal::ours_for_output (); - printf_filtered - ("Can't send signals to this remote system. %s not sent.\n", - gdb_signal_to_name (rs->last_sent_signal)); - rs->last_sent_signal = GDB_SIGNAL_0; - target_terminal::inferior (); - - strcpy (buf, rs->last_sent_step ? "s" : "c"); - putpkt (buf); + event_ptid = process_stop_reply (stop_reply, status); + break; + } + case 'O': /* Console output. */ + remote_console_output (buf + 1); + break; + case '\0': + if (rs->last_sent_signal != GDB_SIGNAL_0) + { + /* Zero length reply means that we tried 'S' or 'C' and the + remote system doesn't support it. */ + target_terminal::ours_for_output (); + printf_filtered + ("Can't send signals to this remote system. %s not sent.\n", + gdb_signal_to_name (rs->last_sent_signal)); + rs->last_sent_signal = GDB_SIGNAL_0; + target_terminal::inferior (); + + strcpy (buf, rs->last_sent_step ? "s" : "c"); + putpkt (buf); + break; + } + /* fallthrough */ + default: + warning (_("Invalid remote reply: %s"), buf); break; } - /* fallthrough */ - default: - warning (_("Invalid remote reply: %s"), buf); - break; } - if (status->kind == TARGET_WAITKIND_NO_RESUMED) + if (status->kind () == TARGET_WAITKIND_NO_RESUMED) return minus_one_ptid; - else if (status->kind == TARGET_WAITKIND_IGNORE) + else if (status->kind () == TARGET_WAITKIND_IGNORE) { /* Nothing interesting happened. If we're doing a non-blocking poll, we're done. Otherwise, go back to waiting. */ @@ -8154,8 +8288,8 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, else goto again; } - else if (status->kind != TARGET_WAITKIND_EXITED - && status->kind != TARGET_WAITKIND_SIGNALLED) + else if (status->kind () != TARGET_WAITKIND_EXITED + && status->kind () != TARGET_WAITKIND_SIGNALLED) { if (event_ptid != null_ptid) record_currthread (rs, event_ptid); @@ -8189,9 +8323,13 @@ remote_target::wait (ptid_t ptid, struct target_waitstatus *status, remote_state *rs = get_remote_state (); /* Start by clearing the flag that asks for our wait method to be called, - we'll mark it again at the end if needed. */ + we'll mark it again at the end if needed. If the target is not in + async mode then the async token should not be marked. */ if (target_is_async_p ()) clear_async_event_handler (rs->remote_async_inferior_event_token); + else + gdb_assert (!async_event_handler_marked + (rs->remote_async_inferior_event_token)); ptid_t event_ptid; @@ -9266,11 +9404,6 @@ remote_target::flash_done () } } -void -remote_target::files_info () -{ - puts_filtered ("Debugging a target over a serial line.\n"); -} /* Stuff for dealing with the packets which are part of this protocol. See comment at top of file for details. */ @@ -9372,18 +9505,7 @@ escape_buffer (const char *buf, int n) string_file stb; stb.putstrn (buf, n, '\\'); - return std::move (stb.string ()); -} - -/* Display a null-terminated packet on stdout, for debugging, using C - string notation. */ - -static void -print_packet (const char *buf) -{ - puts_filtered ("\""); - fputstr_filtered (buf, '"', gdb_stdout); - puts_filtered ("\""); + return stb.release (); } int @@ -9436,10 +9558,6 @@ remote_target::putpkt_binary (const char *buf, int cnt) "and then try again.")); } - /* We're sending out a new packet. Make sure we don't look at a - stale cached response. */ - rs->cached_wait_status = 0; - /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ @@ -9684,7 +9802,7 @@ remote_target::read_frame (gdb::char_vector *buf_p) { int repeat; - csum += c; + csum += c; c = readchar (remote_timeout); csum += c; repeat = c - ' ' + 3; /* Compute repeat count. */ @@ -9777,10 +9895,6 @@ remote_target::getpkt_or_notif_sane_1 (gdb::char_vector *buf, int timeout; int val = -1; - /* We're reading a new response. Make sure we don't look at a - previously cached response. */ - rs->cached_wait_status = 0; - strcpy (buf->data (), "timeout"); if (forever) @@ -9923,45 +10037,48 @@ remote_target::getpkt_or_notif_sane (gdb::char_vector *buf, int forever, return getpkt_or_notif_sane_1 (buf, forever, 1, is_notif); } -/* Kill any new fork children of process PID that haven't been +/* Kill any new fork children of inferior INF that haven't been processed by follow_fork. */ void -remote_target::kill_new_fork_children (int pid) +remote_target::kill_new_fork_children (inferior *inf) { remote_state *rs = get_remote_state (); struct notif_client *notif = ¬if_client_stop; - /* 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 (this)) + /* Kill the fork child threads of any threads in inferior INF that are stopped + at a fork event. */ + for (thread_info *thread : inf->non_exited_threads ()) { - struct target_waitstatus *ws = &thread->pending_follow; + const target_waitstatus *ws = thread_pending_fork_status (thread); - if (is_pending_fork_parent (ws, pid, thread->ptid)) - { - int child_pid = ws->value.related_pid.pid (); - int res; + if (ws == nullptr) + continue; - res = remote_vkill (child_pid); - if (res != 0) - error (_("Can't kill fork child process %d"), child_pid); - } + int child_pid = ws->child_ptid ().pid (); + int res = remote_vkill (child_pid); + + if (res != 0) + error (_("Can't kill fork child process %d"), child_pid); } /* Check for any pending fork events (not reported or processed yet) - in process PID and kill those fork child threads as well. */ + in inferior INF and kill those fork child threads as well. */ remote_notif_get_pending_events (notif); for (auto &event : rs->stop_reply_queue) - if (is_pending_fork_parent (&event->ws, pid, event->ptid)) - { - int child_pid = event->ws.value.related_pid.pid (); - int res; + { + if (event->ptid.pid () != inf->pid) + continue; - res = remote_vkill (child_pid); - if (res != 0) - error (_("Can't kill fork child process %d"), child_pid); - } + if (!is_fork_status (event->ws.kind ())) + continue; + + int child_pid = event->ws.child_ptid ().pid (); + int res = remote_vkill (child_pid); + + if (res != 0) + error (_("Can't kill fork child process %d"), child_pid); + } } @@ -9971,18 +10088,20 @@ void remote_target::kill () { int res = -1; - int pid = inferior_ptid.pid (); + inferior *inf = find_inferior_pid (this, inferior_ptid.pid ()); struct remote_state *rs = get_remote_state (); + gdb_assert (inf != nullptr); + if (packet_support (PACKET_vKill) != PACKET_DISABLE) { /* If we're stopped while forking and we haven't followed yet, kill the child task. We need to do this before killing the parent task because if this is a vfork then the parent will be sleeping. */ - kill_new_fork_children (pid); + kill_new_fork_children (inf); - res = remote_vkill (pid); + res = remote_vkill (inf->pid); if (res == 0) { target_mourn_inferior (inferior_ptid); @@ -10196,7 +10315,7 @@ remote_target::extended_remote_run (const std::string &args) error (_("Running \"%s\" on the remote target failed"), remote_exec_file); default: - gdb_assert_not_reached (_("bad switch")); + gdb_assert_not_reached ("bad switch"); } } @@ -10262,13 +10381,14 @@ remote_target::extended_remote_set_inferior_cwd () { if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE) { - const char *inferior_cwd = get_inferior_cwd (); + const std::string &inferior_cwd = current_inferior ()->cwd (); remote_state *rs = get_remote_state (); - if (inferior_cwd != NULL) + if (!inferior_cwd.empty ()) { - std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd, - strlen (inferior_cwd)); + std::string hexpath + = bin2hex ((const gdb_byte *) inferior_cwd.data (), + inferior_cwd.size ()); xsnprintf (rs->buf.data (), get_remote_packet_size (), "QSetWorkingDir:%s", hexpath.c_str ()); @@ -11462,7 +11582,8 @@ remote_target::memory_map () { std::vector result; gdb::optional text - = target_read_stralloc (current_top_target (), TARGET_OBJECT_MEMORY_MAP, NULL); + = target_read_stralloc (current_inferior ()->top_target (), + TARGET_OBJECT_MEMORY_MAP, NULL); if (text) result = parse_memory_map (text->data ()); @@ -11470,34 +11591,87 @@ remote_target::memory_map () return result; } -static void -packet_command (const char *args, int from_tty) +/* Set of callbacks used to implement the 'maint packet' command. */ + +struct cli_packet_command_callbacks : public send_remote_packet_callbacks { - remote_target *remote = get_current_remote_target (); + /* Called before the packet is sent. BUF is the packet content before + the protocol specific prefix, suffix, and escaping is added. */ - if (remote == nullptr) - error (_("command can only be used with remote target")); + void sending (gdb::array_view &buf) override + { + puts_filtered ("sending: "); + print_packet (buf); + puts_filtered ("\n"); + } - remote->packet_command (args, from_tty); -} + /* Called with BUF, the reply from the remote target. */ + + void received (gdb::array_view &buf) override + { + puts_filtered ("received: \""); + print_packet (buf); + puts_filtered ("\"\n"); + } + +private: + + /* Print BUF o gdb_stdout. Any non-printable bytes in BUF are printed as + '\x??' with '??' replaced by the hexadecimal value of the byte. */ + + static void + print_packet (gdb::array_view &buf) + { + string_file stb; + + for (int i = 0; i < buf.size (); ++i) + { + gdb_byte c = buf[i]; + if (isprint (c)) + fputc_unfiltered (c, &stb); + else + fprintf_unfiltered (&stb, "\\x%02x", (unsigned char) c); + } + + puts_filtered (stb.string ().c_str ()); + } +}; + +/* See remote.h. */ void -remote_target::packet_command (const char *args, int from_tty) +send_remote_packet (gdb::array_view &buf, + send_remote_packet_callbacks *callbacks) { - if (!args) - error (_("remote-packet command requires packet text as argument")); + if (buf.size () == 0 || buf.data ()[0] == '\0') + error (_("a remote packet must not be empty")); - puts_filtered ("sending: "); - print_packet (args); - puts_filtered ("\n"); - putpkt (args); + remote_target *remote = get_current_remote_target (); + if (remote == nullptr) + error (_("packets can only be sent to a remote target")); - remote_state *rs = get_remote_state (); + callbacks->sending (buf); - getpkt (&rs->buf, 0); - puts_filtered ("received: "); - print_packet (rs->buf.data ()); - puts_filtered ("\n"); + remote->putpkt_binary (buf.data (), buf.size ()); + remote_state *rs = remote->get_remote_state (); + int bytes = remote->getpkt_sane (&rs->buf, 0); + + if (bytes < 0) + error (_("error while fetching packet from remote target")); + + gdb::array_view view (&rs->buf[0], bytes); + callbacks->received (view); +} + +/* Entry point for the 'maint packet' command. */ + +static void +cli_packet_command (const char *args, int from_tty) +{ + cli_packet_command_callbacks cb; + gdb::array_view view + = gdb::make_array_view (args, args == nullptr ? 0 : strlen (args)); + send_remote_packet (view, &cb); } #if 0 @@ -12483,7 +12657,7 @@ remote_target::filesystem_is_local () this case we treat the remote filesystem as local if the sysroot is exactly TARGET_SYSROOT_PREFIX and if the stub does not support vFile:open. */ - if (strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) == 0) + if (gdb_sysroot == TARGET_SYSROOT_PREFIX) { enum packet_support ps = packet_support (PACKET_vFile_open); @@ -13111,7 +13285,7 @@ remote_target::download_tracepoint (struct bp_location *loc) "ignoring tp %d cond"), b->number); } - if (b->commands || *default_collect) + if (b->commands || !default_collect.empty ()) { size_left = buf.size () - strlen (buf.data ()); @@ -13199,7 +13373,7 @@ remote_target::download_tracepoint (struct bp_location *loc) error ("%s", err_msg); encode_source_string (b->number, loc->address, - "cond", b->cond_string, + "cond", b->cond_string.get (), buf.data () + strlen (buf.data ()), buf.size () - strlen (buf.data ())); putpkt (buf.data ()); @@ -13414,7 +13588,6 @@ remote_target::get_tracepoint_status (struct breakpoint *bp, { struct remote_state *rs = get_remote_state (); char *reply; - struct bp_location *loc; struct tracepoint *tp = (struct tracepoint *) bp; size_t size = get_remote_packet_size (); @@ -13422,7 +13595,7 @@ remote_target::get_tracepoint_status (struct breakpoint *bp, { tp->hit_count = 0; tp->traceframe_usage = 0; - for (loc = tp->loc; loc; loc = loc->next) + for (bp_location *loc : tp->locations ()) { /* If the tracepoint was never downloaded, don't go asking for any status. */ @@ -13693,7 +13866,8 @@ traceframe_info_up remote_target::traceframe_info () { gdb::optional text - = target_read_stralloc (current_top_target (), TARGET_OBJECT_TRACEFRAME_INFO, + = target_read_stralloc (current_inferior ()->top_target (), + TARGET_OBJECT_TRACEFRAME_INFO, NULL); if (text) return parse_traceframe_info (text->data ()); @@ -13915,14 +14089,18 @@ remote_target::btrace_sync_conf (const btrace_config *conf) } } -/* Read the current thread's btrace configuration from the target and - store it into CONF. */ +/* Read TP's btrace configuration from the target and store it into CONF. */ static void -btrace_read_config (struct btrace_config *conf) +btrace_read_config (thread_info *tp, struct btrace_config *conf) { + /* target_read_stralloc relies on INFERIOR_PTID. */ + scoped_restore_current_thread restore_thread; + switch_to_thread (tp); + gdb::optional xml - = target_read_stralloc (current_top_target (), TARGET_OBJECT_BTRACE_CONF, ""); + = target_read_stralloc (current_inferior ()->top_target (), + TARGET_OBJECT_BTRACE_CONF, ""); if (xml) parse_xml_btrace_conf (conf, xml->data ()); } @@ -13943,14 +14121,10 @@ remote_target::remote_btrace_maybe_reopen () if (packet_support (PACKET_qXfer_btrace_conf) != PACKET_ENABLE) return; - scoped_restore_current_thread restore_thread; - for (thread_info *tp : all_non_exited_threads (this)) { - set_general_thread (tp->ptid); - memset (&rs->btrace_config, 0x00, sizeof (struct btrace_config)); - btrace_read_config (&rs->btrace_config); + btrace_read_config (tp, &rs->btrace_config); if (rs->btrace_config.format == BTRACE_FORMAT_NONE) continue; @@ -13989,7 +14163,8 @@ remote_target::remote_btrace_maybe_reopen () /* Enable branch tracing. */ struct btrace_target_info * -remote_target::enable_btrace (ptid_t ptid, const struct btrace_config *conf) +remote_target::enable_btrace (thread_info *tp, + const struct btrace_config *conf) { struct btrace_target_info *tinfo = NULL; struct packet_config *packet = NULL; @@ -14013,6 +14188,7 @@ remote_target::enable_btrace (ptid_t ptid, const struct btrace_config *conf) btrace_sync_conf (conf); + ptid_t ptid = tp->ptid; set_general_thread (ptid); buf += xsnprintf (buf, endbuf - buf, "%s", packet->name); @@ -14036,7 +14212,7 @@ remote_target::enable_btrace (ptid_t ptid, const struct btrace_config *conf) tracing itself is not impacted. */ try { - btrace_read_config (&tinfo->conf); + btrace_read_config (tp, &tinfo->conf); } catch (const gdb_exception_error &err) { @@ -14123,7 +14299,8 @@ remote_target::read_btrace (struct btrace_data *btrace, } gdb::optional xml - = target_read_stralloc (current_top_target (), TARGET_OBJECT_BTRACE, annex); + = target_read_stralloc (current_inferior ()->top_target (), + TARGET_OBJECT_BTRACE, annex); if (!xml) return BTRACE_ERR_UNKNOWN; @@ -14179,7 +14356,7 @@ remote_target::pid_to_exec_file (int pid) xsnprintf (annex, annex_size, "%x", pid); } - filename = target_read_stralloc (current_top_target (), + filename = target_read_stralloc (current_inferior ()->top_target (), TARGET_OBJECT_EXEC_FILE, annex); return filename ? filename->data () : nullptr; @@ -14255,27 +14432,19 @@ remote_target::thread_info_to_thread_handle (struct thread_info *tp) bool remote_target::can_async_p () { - struct remote_state *rs = get_remote_state (); - - /* We don't go async if the user has explicitly prevented it with the - "maint set target-async" command. */ - if (!target_async_permitted) - return false; + /* This flag should be checked in the common target.c code. */ + gdb_assert (target_async_permitted); - /* We're async whenever the serial device is. */ + /* We're async whenever the serial device can. */ + struct remote_state *rs = get_remote_state (); return serial_can_async_p (rs->remote_desc); } bool remote_target::is_async_p () { - struct remote_state *rs = get_remote_state (); - - if (!target_async_permitted) - /* We only enable async when the user specifically asks for it. */ - return false; - /* We're async whenever the serial device is. */ + struct remote_state *rs = get_remote_state (); return serial_is_async_p (rs->remote_desc); } @@ -14405,8 +14574,26 @@ remote_new_objfile (struct objfile *objfile) { remote_target *remote = get_current_remote_target (); - if (remote != NULL) /* Have a remote connection. */ - remote->remote_check_symbols (); + /* First, check whether the current inferior's process target is a remote + target. */ + if (remote == nullptr) + return; + + /* When we are attaching or handling a fork child and the shared library + subsystem reads the list of loaded libraries, we receive new objfile + events in between each found library. The libraries are read in an + undefined order, so if we gave the remote side a chance to look up + symbols between each objfile, we might give it an inconsistent picture + of the inferior. It could appear that a library A appears loaded but + a library B does not, even though library A requires library B. That + would present a state that couldn't normally exist in the inferior. + + So, skip these events, we'll give the remote a chance to look up symbols + once all the loaded libraries and their symbols are known to GDB. */ + if (current_inferior ()->in_initial_library_scan) + return; + + remote->remote_check_symbols (); } /* Pull all the tracepoints defined on the target and create local @@ -14620,13 +14807,107 @@ remote_target::store_memtags (CORE_ADDR address, size_t len, return packet_check_result (rs->buf.data ()) == PACKET_OK; } +/* Return true if remote target T is non-stop. */ + +bool +remote_target_is_non_stop_p (remote_target *t) +{ + scoped_restore_current_thread restore_thread; + switch_to_target_no_thread (t); + + return target_is_non_stop_p (); +} + +#if GDB_SELF_TEST + +namespace selftests { + +static void +test_memory_tagging_functions () +{ + remote_target remote; + + struct packet_config *config + = &remote_protocol_packets[PACKET_memory_tagging_feature]; + + scoped_restore restore_memtag_support_ + = make_scoped_restore (&config->support); + + /* Test memory tagging packet support. */ + config->support = PACKET_SUPPORT_UNKNOWN; + SELF_CHECK (remote.supports_memory_tagging () == false); + config->support = PACKET_DISABLE; + SELF_CHECK (remote.supports_memory_tagging () == false); + config->support = PACKET_ENABLE; + SELF_CHECK (remote.supports_memory_tagging () == true); + + /* Setup testing. */ + gdb::char_vector packet; + gdb::byte_vector tags, bv; + std::string expected, reply; + packet.resize (32000); + + /* Test creating a qMemTags request. */ + + expected = "qMemTags:0,0:0"; + create_fetch_memtags_request (packet, 0x0, 0x0, 0); + SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0); + + expected = "qMemTags:deadbeef,10:1"; + create_fetch_memtags_request (packet, 0xdeadbeef, 16, 1); + SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0); + + /* Test parsing a qMemTags reply. */ + + /* Error reply, tags vector unmodified. */ + reply = "E00"; + strcpy (packet.data (), reply.c_str ()); + tags.resize (0); + SELF_CHECK (parse_fetch_memtags_reply (packet, tags) == false); + SELF_CHECK (tags.size () == 0); + + /* Valid reply, tags vector updated. */ + tags.resize (0); + bv.resize (0); + + for (int i = 0; i < 5; i++) + bv.push_back (i); + + reply = "m" + bin2hex (bv.data (), bv.size ()); + strcpy (packet.data (), reply.c_str ()); + + SELF_CHECK (parse_fetch_memtags_reply (packet, tags) == true); + SELF_CHECK (tags.size () == 5); + + for (int i = 0; i < 5; i++) + SELF_CHECK (tags[i] == i); + + /* Test creating a QMemTags request. */ + + /* Empty tag data. */ + tags.resize (0); + expected = "QMemTags:0,0:0:"; + create_store_memtags_request (packet, 0x0, 0x0, 0, tags); + SELF_CHECK (memcmp (packet.data (), expected.c_str (), + expected.length ()) == 0); + + /* Non-empty tag data. */ + tags.resize (0); + for (int i = 0; i < 5; i++) + tags.push_back (i); + expected = "QMemTags:deadbeef,ff:1:0001020304"; + create_store_memtags_request (packet, 0xdeadbeef, 255, 1, tags); + SELF_CHECK (memcmp (packet.data (), expected.c_str (), + expected.length ()) == 0); +} + +} // namespace selftests +#endif /* GDB_SELF_TEST */ + void _initialize_remote (); void _initialize_remote () { - struct cmd_list_element *cmd; - const char *cmd_name; - /* architecture specific data */ remote_g_packet_data_handle = gdbarch_data_register_pre_init (remote_g_packet_data_init); @@ -14635,7 +14916,7 @@ _initialize_remote () add_target (extended_remote_target_info, extended_remote_target::open); /* Hook into new objfile notification. */ - gdb::observers::new_objfile.attach (remote_new_objfile); + gdb::observers::new_objfile.attach (remote_new_objfile, "remote"); #if 0 init_remote_threadtests (); @@ -14647,13 +14928,13 @@ _initialize_remote () Remote protocol specific variables.\n\ Configure various remote-protocol specific variables such as\n\ the packets being used."), - &remote_set_cmdlist, "set remote ", + &remote_set_cmdlist, 0 /* allow-unknown */, &setlist); add_prefix_cmd ("remote", class_maintenance, show_remote_cmd, _("\ Remote protocol specific variables.\n\ Configure various remote-protocol specific variables such as\n\ the packets being used."), - &remote_show_cmdlist, "show remote ", + &remote_show_cmdlist, 0 /* allow-unknown */, &showlist); add_cmd ("compare-sections", class_obscure, compare_sections_command, _("\ @@ -14662,7 +14943,7 @@ Argument is a single section name (default: all loaded sections).\n\ To compare only read-only loaded sections, specify the -r option."), &cmdlist); - add_cmd ("packet", class_maintenance, packet_command, _("\ + add_cmd ("packet", class_maintenance, cli_packet_command, _("\ Send an arbitrary packet to a remote target.\n\ maintenance packet TEXT\n\ If GDB is talking to an inferior via the GDB serial protocol, then\n\ @@ -14671,18 +14952,15 @@ response packet. GDB supplies the initial `$' character, and the\n\ terminating `#' character and checksum."), &maintenancelist); - add_setshow_boolean_cmd ("remotebreak", no_class, &remote_break, _("\ + set_show_commands remotebreak_cmds + = add_setshow_boolean_cmd ("remotebreak", no_class, &remote_break, _("\ Set whether to send break if interrupted."), _("\ Show whether to send break if interrupted."), _("\ If set, a break, instead of a cntrl-c, is sent to the remote target."), - set_remotebreak, show_remotebreak, - &setlist, &showlist); - cmd_name = "remotebreak"; - 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, "", NULL, -1, 1); - deprecate_cmd (cmd, "show remote interrupt-sequence"); + set_remotebreak, show_remotebreak, + &setlist, &showlist); + deprecate_cmd (remotebreak_cmds.set, "set remote interrupt-sequence"); + deprecate_cmd (remotebreak_cmds.show, "show remote interrupt-sequence"); add_setshow_enum_cmd ("interrupt-sequence", class_support, interrupt_sequence_modes, &interrupt_sequence_mode, @@ -15075,7 +15353,7 @@ packets."), 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 ", + &remote_cmdlist, 0 /* allow-unknown */, &cmdlist); add_cmd ("put", class_files, remote_put_command, @@ -15153,4 +15431,9 @@ from the target."), /* Eventually initialize fileio. See fileio.c */ initialize_remote_fileio (&remote_set_cmdlist, &remote_show_cmdlist); + +#if GDB_SELF_TEST + selftests::register_test ("remote_memory_tagging", + selftests::test_memory_tagging_functions); +#endif }