From patchwork Fri Nov 17 11:18:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandra Petlanova Hajkova X-Patchwork-Id: 80119 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9C0B23858438 for ; Fri, 17 Nov 2023 11:19:26 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 01357385840A for ; Fri, 17 Nov 2023 11:18:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 01357385840A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 01357385840A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700219932; cv=none; b=YO5ZBW095PA1JBoonyAbFkDrsX2JvSJl/W4zN/ycs8RtqIMJVvb2CKSswDXjtoVqhVcXin4rh+/Dvxi+s/nzs2xeBSZu+eTMa4x6bkmK4cxTMw//yJZrxGqTKZhasvMQJBMiAqVcXq9M8GHjwGwH9DqxgmosMvHaNCse6EfW1ug= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700219932; c=relaxed/simple; bh=YomGGVaBNmG8XtludhFc19PchU0Phvs0S9WbKd66xvU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=iIHbJpxJmRQk2HESObe170qwOthG9s2DDeZjFFjIHiV7Yf++AgUXera1dXS1dUzu061PtNwQdqIJJjkYCbjqYCs7W6sWr3lLcUN/5HE2aS9VaaoR1tMl02Lbjwymahm4eLZDc10bz+cl7ZGl+h18a12zTbX8qyowuLNTJjfOcwQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700219929; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R0F6CF18ktZFFXj+M49m5bE1CTkobiZh8V4mWgnOMsw=; b=fwqx5lij9IYe+Nwl+fTAucidOzj9B7LdZIK75Jj3vqELbmuF5tJKIogPB6w9YSajw1YIQV UhHqLx504V0bzU6BKBaVFyCX1gx+ZXdWjUIOtb8rRCTY1Ukm8HlkbE925JjowbwZgMpvqo Yf4hSzpzo0oZfyPqw6VPWWyWGob/BR0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-158-9Gt7VfM9Pt2q7fMI1wedXw-1; Fri, 17 Nov 2023 06:18:48 -0500 X-MC-Unique: 9Gt7VfM9Pt2q7fMI1wedXw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4AD18881E22 for ; Fri, 17 Nov 2023 11:18:48 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.45.242.6]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 47AA32026D4C; Fri, 17 Nov 2023 11:18:47 +0000 (UTC) From: =?utf-8?q?Alexandra_H=C3=A1jkov=C3=A1?= To: gdb-patches@sourceware.org Cc: ahajkova@redhat.com Subject: [PATCH 3/6] Add new vDefaultInferiorFd packet Date: Fri, 17 Nov 2023 12:18:37 +0100 Message-ID: <20231117111840.2040709-4-ahajkova@redhat.com> In-Reply-To: <20231117111840.2040709-1-ahajkova@redhat.com> References: <20231117111840.2040709-1-ahajkova@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Add a new DefaultInferiorFd feature and the corresponding packet. This feature allows GDB to send, to GDBserver, the file descriptor numbers of the terminal to which GDB is connected. The inferior is then started connected to the same terminal as GDB. This allows the inferior run by local GDBserver to read from GDB's STDIN and write its output to GDB's STOUT/ERR the same way as native target. Reviewed-By: Eli Zaretskii --- gdb/doc/gdb.texinfo | 32 +++++++++++ gdb/remote.c | 28 ++++++++++ gdbserver/server.cc | 132 +++++++++++++++++++++++++++++++++++++++++++- gdbserver/server.h | 12 ++++ 4 files changed, 201 insertions(+), 3 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e4c00143fd1..69f0d0499ef 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -23210,6 +23210,15 @@ If you specify the program to debug on the command line, then the resume using commands like @kbd{step} and @kbd{continue} as with @code{target remote} mode. +When GDBserver is run locally using stdio for example +@code{target remote | gdbserver - inferior}. +Inferior's STDIN is closed which means the inferior can't read any input. + +If GDBserver is run locally using stdio and supports the @xref{default inferior +file descriptors} feature, GDBserver will start inferior connected to the same +terminal as @value{GDBN} which enables the inferior to read from STDIN and +write to the STDOUT/ERR in the same fashion native target does. + @anchor{Attaching in Types of Remote Connections} @item Attaching @strong{With target remote mode:} The @value{GDBN} command @code{attach} is @@ -42934,6 +42943,29 @@ for success (@pxref{Stop Reply Packets}) @cindex @samp{vStopped} packet @xref{Notification Packets}. +@item vDefaultInferior;@var{fd0};@var{fd1};@var{fd2} +@item vDefaultInferiorFd +@anchor{default inferior file descriptors} +@cindex @samp{vDefaultInferiorFd} packet +@value{GDBN} would preserve the numbers of STDOUT/STDIN/STDERR file descriptors. +Preserved numbers of the file descriptors are then sent to GDBserver. +If GDBserver is run locally and will accept the numbers of the file +descriptors, it will start the inferior connected to the same STDIN/OUT/ERR +@value{GDBN} is connected to. This allows the inferior run under the local GDBserver +to read from the STDIN and write to STOUT/ERR. This makes a remote target (which is +run locally) to behave similarly to the native target. + +This packet is also available in extended mode (@pxref{extended mode}). +This feature does not support setting inferior tty. + +Reply: +@table @samp +@item OK +for success +@item E.errtext +for an error +@end table + @item X @var{addr},@var{length}:@var{XX@dots{}} @anchor{X packet} @cindex @samp{X} packet diff --git a/gdb/remote.c b/gdb/remote.c index ce5addade6f..27d053c367c 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -305,6 +305,10 @@ enum { packets and the tag violation stop replies. */ PACKET_memory_tagging_feature, + /* Support for connecting inferior to the same terminal as + GDB when running GDBserver locally. */ + PACKET_vDefaultInferiorFd, + PACKET_MAX }; @@ -726,6 +730,11 @@ struct remote_features bool remote_memory_tagging_p () const { return packet_support (PACKET_memory_tagging_feature) == PACKET_ENABLE; } + /* Returns true if connecting inferior to the same terminal as GDB is + supported, false otherwise. */ + bool remote_fd_switch_p () const + { return packet_support (PACKET_vDefaultInferiorFd) == PACKET_ENABLE; } + /* Reset all packets back to "unknown support". Called when opening a new connection to a remote target. */ void reset_all_packet_configs_support (); @@ -5010,6 +5019,18 @@ remote_target::start_remote_1 (int from_tty, int extended_p) which later probes to skip. */ remote_query_supported (); + if ((m_features.packet_support (PACKET_vDefaultInferiorFd) != PACKET_DISABLE) + && (rs->remote_desc->fds[0] != -1) && (rs->remote_desc->fds[1] != -1) + && (rs->remote_desc->fds[2] != -1)) + { + xsnprintf (rs->buf.data(), rs->buf.size (), "vDefaultInferiorFd;%d;%d;%d", + rs->remote_desc->fds[0], rs->remote_desc->fds[1], + rs->remote_desc->fds[2]); + + putpkt (rs->buf); + getpkt (&rs->buf, 0); + } + /* Check vCont support and set the remote state's vCont_action_support attribute. */ remote_vcont_probe (); @@ -5717,6 +5738,7 @@ static const struct protocol_feature remote_protocol_features[] = { { "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed }, { "memory-tagging", PACKET_DISABLE, remote_supported_packet, PACKET_memory_tagging_feature }, + { "vDefaultInferiorFd", PACKET_DISABLE, remote_supported_packet, PACKET_vDefaultInferiorFd }, }; static char *remote_support_xml; @@ -5828,6 +5850,10 @@ remote_target::remote_query_supported () != AUTO_BOOLEAN_FALSE) remote_query_supported_append (&q, "memory-tagging+"); + if (m_features.packet_set_cmd_state (PACKET_vDefaultInferiorFd) + != AUTO_BOOLEAN_FALSE) + remote_query_supported_append (&q, "vDefaultInferiorFd+"); + /* Keep this one last to work around a gdbserver <= 7.10 bug in the qSupported:xmlRegisters=i386 handling. */ if (remote_support_xml != NULL @@ -15984,6 +16010,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (PACKET_memory_tagging_feature, "memory-tagging-feature", "memory-tagging-feature", 0); + add_packet_config_cmd (PACKET_vDefaultInferiorFd, "vDefaultInferiorFd", "vDefaultInferiorFd", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { diff --git a/gdbserver/server.cc b/gdbserver/server.cc index a8e23561dcb..e69e5c125c4 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -81,6 +81,12 @@ static bool extended_protocol; static bool response_needed; static bool exit_requested; +/* To be able to connect the inferior to GDB's stdin/out/err, + when GDBserver is run locally, we need to wait with starting + the inferior to have time to recieve the vDefaultInferiorFd + packet. Set to true if need to postpone starting the inferior. */ +static bool deferred_inferior_startup = false; + /* --once: Exit after the first connection has closed. */ bool run_once; @@ -171,6 +177,34 @@ get_client_state () return cs; } +volatile int multi_mode = 0; + +/* To be able to connect the inferior to GDB's stdin/out/err, + when GDBserver is run locally, we need to wait with starting + the inferior to have time to recieve the vDefaultInferiorFd + packet. + + Can only be called when deferred_inferior_startup is true. + Starts the inferior and throws an error if startup fails. + If startup is successful then deferred_inferior_startup is + reset to false. Throw an error on failure. */ +static void +do_deferred_startup () +{ + gdb_assert (deferred_inferior_startup); + client_state &cs = get_client_state (); + target_create_inferior (program_path.get (), program_args); + + if (current_thread != nullptr) + current_process ()->dlls_changed = false; + + if ((cs.last_status.kind () == TARGET_WAITKIND_EXITED + || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED) + && !multi_mode) + error ("No program to debug"); + + deferred_inferior_startup = false; +} /* Put a stop reply to the stop reply queue. */ @@ -2274,6 +2308,45 @@ supported_btrace_packets (char *buf) strcat (buf, ";qXfer:btrace-conf:read+"); } +/* Parse a vDefaultInferiorFd packet from pkt + and save the received file descriptors into + fds. Return true on success, false otherwise. + Set the file descriptors to -1 on failure. */ +static bool +parse_vdefaultinf (const char *pkt, int *fds) +{ + char *end; + int ret = true; + errno = 0; + + if (*pkt != '\0') + { + fds[0] = (int) strtoul (pkt, &end, 10); + if ((pkt == end) || (*end != ';')) + ret = false; + pkt = end + 1; + fds[1] = (int) strtoul (pkt, &end, 10); + if ((pkt == end) || (*end != ';')) + ret = false; + pkt = end + 1; + fds[2] = (int) strtoul (pkt, &end, 10); + if ((pkt == end) || (*end != '\0')) + ret = false; + if (errno != 0) + ret = false; + } + else + ret = false; + if (!ret) + { + fds[0] = -1; + fds[1] = -1; + fds[2] = -1; + } + + return ret; +} + /* Handle all of the extended 'q' packets. */ static void @@ -2484,6 +2557,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_memory_tagging ()) cs.memory_tagging_feature = true; } + else if (feature == "vDefaultInferiorFd+") + cs.vDefaultInferiorFd_supported = 1; else { /* Move the unknown features all together. */ @@ -2613,6 +2688,17 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_memory_tagging ()) strcat (own_buf, ";memory-tagging+"); + if (cs.vDefaultInferiorFd_supported) + { + /* If GDB didn't advertise vDefaultInferiorFd then we don't mention + vDefaultInferiorFd in the reply. If GDB did mention vDefaultInferiorFd + then we only claim support if we are started as an stdio target. */ + if (remote_connection_is_stdio ()) + strcat (own_buf, ";vDefaultInferiorFd+"); + else + strcat (own_buf, ";vDefaultInferiorFd-"); + } + /* Reinitialize components as needed for the new connection. */ hostio_handle_new_gdb_connection (); target_handle_new_gdb_connection (); @@ -3316,6 +3402,19 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) return; } + if (startswith (own_buf, "vDefaultInferiorFd;")) + { + if (!parse_vdefaultinf (own_buf + 19, cs.fds)) + { + strcpy (own_buf, "E.invalid vDefaultInferiorFd packet"); + return; + } + + cs.vDefaultInferiorFd_accepted = true; + write_ok (own_buf); + return; + } + if (startswith (own_buf, "vKill;")) { if (!target_running ()) @@ -3807,7 +3906,6 @@ captured_main (int argc, char *argv[]) char *arg_end; const char *port = NULL; char **next_arg = &argv[1]; - volatile int multi_mode = 0; volatile int attach = 0; int was_running; bool selftest = false; @@ -4056,8 +4154,27 @@ captured_main (int argc, char *argv[]) for (i = 1; i < n; i++) program_args.push_back (xstrdup (next_arg[i])); - /* Wait till we are at first instruction in program. */ - target_create_inferior (program_path.get (), program_args); + if (remote_connection_is_stdio ()) + { + /* Debugger might want to set the default inferior + in/out/err file descriptors, in which case we need to + defer starting the inferior until this information + arrives. */ + deferred_inferior_startup = true; + multi_mode = 1; + + /* Only used when reporting the first stop to GDB. This + should be replaced when we start the inferior, but lets + be on the safe side and set this now just so we carry + around a sane state. */ + cs.last_status.set_exited (0); + cs.last_ptid = minus_one_ptid; + } + else + { + /* Wait till we are at first instruction in program. */ + target_create_inferior (program_path.get (), program_args); + } /* We are now (hopefully) stopped at the first instruction of the target process. This assumes that the target process was @@ -4107,6 +4224,7 @@ captured_main (int argc, char *argv[]) cs.hwbreak_feature = 0; cs.vCont_supported = 0; cs.memory_tagging_feature = false; + cs.vDefaultInferiorFd_supported = false; remote_open (port); @@ -4295,6 +4413,14 @@ process_serial_event (void) response_needed = true; char ch = cs.own_buf[0]; + if (deferred_inferior_startup) + { + /* Actually start the inferior if not a qSupported or + vDefaultInferiorFd packet. */ + if (!startswith(cs.own_buf, "qSupported") + && !startswith(cs.own_buf, "vDefaultInferiorFd")) + do_deferred_startup (); + } switch (ch) { case 'q': diff --git a/gdbserver/server.h b/gdbserver/server.h index 306d75d4e9b..7afdc9f6cd4 100644 --- a/gdbserver/server.h +++ b/gdbserver/server.h @@ -192,6 +192,18 @@ struct client_state /* If true, memory tagging features are supported. */ bool memory_tagging_feature = false; + /* If true, connecting the inferior to the terminal's + stdin/out/err when running GDBserver locally is supported. */ + bool vDefaultInferiorFd_supported = false; + + /* If true, GDBserver accepted file descriptors sent by GDB + and connecting the inferior to the same terminal as GDB + when running GDBserver locally is then supported. */ + bool vDefaultInferiorFd_accepted = false; + + /* File descriptors pointing to terminal's stdin/out/err + sent by GDB to GDBserver. */ + int fds[3]; }; client_state &get_client_state ();