From patchwork Sun Apr 6 01:38:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Rische X-Patchwork-Id: 109919 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 E18C438560AB for ; Sun, 6 Apr 2025 01:44:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E18C438560AB Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (2048-bit key, secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=t8LLbs2f X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-4325.protonmail.ch (mail-4325.protonmail.ch [185.70.43.25]) by sourceware.org (Postfix) with ESMTPS id 98A54385B52C for ; Sun, 6 Apr 2025 01:39:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 98A54385B52C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 98A54385B52C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=185.70.43.25 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903552; cv=none; b=GDjO8ihpA3LkVD3G7Nn6Gtzt2c0mETj93vFgQ3fzxHe24Ola+zAeUOzDmvUv0RBUJiKnRiGXXP1KLEeBAdZ+ydJbybLLwa1xLGBWeyD0BPWd0Nnsboi7GJMuBy0iAa2B639H+5CAmXQbTZe8rEbdfVmv9ZouekF/088kLRqTL9Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903552; c=relaxed/simple; bh=EDMpJHOPCX3d20CxnOxDkv18/pacH0hcfftl0Kzv2Fc=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=CP869/AiYDUITid/Pv/DQNOQZryWUylXLVqrwcKM14OSEdGvVsPCWvgWulvrXiEEqi4J6HKl2ribcbxm9t6MM5wpQ83dg/alsNTgdMWh4oNs4Obi5VVSOejKeE9cYfpEbGMWA7tlPWWd79WGB+nwgDURQpdNZzSMduJHOn7MMZo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 98A54385B52C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1743903550; x=1744162750; bh=eEL3XD4+PvcnnipskUCG1UcacMMvkwWM8ZS+4BGM8O0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=t8LLbs2fvGvdLlhhJu+VtQueSFXKb+cK9Xdoxc9vdqpk1v9G0dsYKA7jr49b7GZFJ iURcEMt0b9J4yEbqBEMN3FT4J8bDnfbvth9dL8w3/1pFDLU8BR1GEqVON4Ht5sEnWn kl22sc8yAp6nhXWhLaK9QaAGuJd7/Bf5toV75+vXcknvKnISVa5axLGQbvIj/Aqbk7 WmNPNxJ+edPj8KLIKlauJ8W6/cXOe8xDAC5Ir14lGxjr6n5keGTY2OwYqpCybpPa0f AekBq3DSK0ZbQKQ+6hZgOLpHDgpBbr7AcN9+xM0FPmPAMwr/N6fwI0FJLt3+YFCkw9 wT1tiTtQdHTQw== Date: Sun, 06 Apr 2025 01:38:59 +0000 To: gdb-patches@sourceware.org From: Antonio Rische Cc: Antonio Rische Subject: [PATCH v6 1/3] gdb: Do not create variables when parsing expressions Message-ID: <20250406013809.230156-2-nt8r@protonmail.com> In-Reply-To: <20250406013809.230156-1-nt8r@protonmail.com> References: <20250406013809.230156-1-nt8r@protonmail.com> Feedback-ID: 21706885:user:proton X-Pm-Message-ID: d7cd508a922891108c361cfa1fe62f1f3037986d MIME-Version: 1.0 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP 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 We do this by introducing a new type of expression for internalvars that had not been given a value at parse time. This is not particularly useful on its own, but allows us to parse expressions without having side-effects on the set of internalvars. This will then allow us to tab-complete internalvars in expressions without creating new internalvars, which would otherwise defeat the purpose of tab completion (completing only variables that have been set). In addition, this allows us to make the 'init-if-undefined' command behave as it is documented to: previously, it treated convenience vars that have been set (or re-set) to void as undefined. Now, it only initialized variables that have actually never been defined. The old behavior can be accessed by instead guarding assignment to a convenience variable with 'if($_isvoid($var))'. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 5 ++++ gdb/ada-exp.h | 12 +++++++-- gdb/ax-gdb.c | 61 +++++++++++++++++++++++++++++++++++++-------- gdb/cli/cli-utils.c | 2 +- gdb/expop.h | 55 +++++++++++++++++++++++++++++++++++++++- gdb/parse.c | 7 +++--- gdb/value.c | 23 ++++++++--------- 7 files changed, 135 insertions(+), 30 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 6a557bb4a..07c1193d8 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -116,6 +116,11 @@ qXfer:threads:read subsystem to be disabled at configure time, in the form of --disable-gdb-compile. +* The =init-if-undefined command now strictly obeys its documentation to + initialize only convenience variables that have not been set. It + previously treated variables set to void as having never been set (see + the $_isvoid convenience function for this behavior). + *** Changes in GDB 16 * Support for Nios II targets has been removed as this architecture diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h index 0c8161ea8..7120563a3 100644 --- a/gdb/ada-exp.h +++ b/gdb/ada-exp.h @@ -544,8 +544,16 @@ class ada_assign_operation assignment. */ value *eval_for_resolution (struct expression *exp) { - return std::get<0> (m_storage)->evaluate (nullptr, exp, - EVAL_AVOID_SIDE_EFFECTS); + operation *lhs_op = std::get<0> (m_storage).get (); + + /* If the operation is an internalvar that was not initialized at + parse time, ensure that it exists. */ + auto *uninit_var_op = dynamic_cast + (lhs_op); + if (uninit_var_op != nullptr) + lookup_internalvar (uninit_var_op->get_name ()); + + return lhs_op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS); } /* The parser must construct the assignment node before parsing the diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c index 2b7d6cef6..5330bc563 100644 --- a/gdb/ax-gdb.c +++ b/gdb/ax-gdb.c @@ -1668,6 +1668,33 @@ register_operation::do_generate_ax (struct expression *exp, value->type = register_type (ax->gdbarch, reg); } +/* Generate remote agent bytecode for the operation that accesses a + yet-to-be-initialized internalvar. */ +void +uninit_internalvar_operation::do_generate_ax (struct expression *exp, + struct agent_expr *ax, + struct axs_value *value, + struct type *cast_type) +{ + const char *name = get_name (); + struct internalvar *var = lookup_only_internalvar (name); + struct trace_state_variable *tsv; + + tsv = find_trace_state_variable (name); + if (tsv != nullptr) + { + ax_tsv (ax, aop_getv, tsv->number); + if (ax->tracing) + ax_tsv (ax, aop_tracev, tsv->number); + /* Trace state variables are always 64-bit integers. */ + value->kind = axs_rvalue; + value->type = builtin_type (ax->gdbarch)->builtin_long_long; + } + else if (!compile_internalvar_to_ax (var, ax, value)) + error (_("$%s is not a trace state variable; GDB agent " + "expressions cannot use convenience variables."), name); +} + void internalvar_operation::do_generate_ax (struct expression *exp, struct agent_expr *ax, @@ -1679,7 +1706,7 @@ internalvar_operation::do_generate_ax (struct expression *exp, struct trace_state_variable *tsv; tsv = find_trace_state_variable (name); - if (tsv) + if (tsv != nullptr) { ax_tsv (ax, aop_getv, tsv->number); if (ax->tracing) @@ -1688,7 +1715,7 @@ internalvar_operation::do_generate_ax (struct expression *exp, value->kind = axs_rvalue; value->type = builtin_type (ax->gdbarch)->builtin_long_long; } - else if (! compile_internalvar_to_ax (var, ax, value)) + else if (!compile_internalvar_to_ax (var, ax, value)) error (_("$%s is not a trace state variable; GDB agent " "expressions cannot use convenience variables."), name); } @@ -1911,6 +1938,26 @@ op_this_operation::do_generate_ax (struct expression *exp, sym->print_name ()); } +/* Get the name of the internalvar referenced by an operation, or + nullptr if the operation does not reference an internalvar. */ +static const char * +internalvar_op_name (operation *op) +{ + gdb_assert (op->opcode () == OP_INTERNALVAR); + + internalvar_operation *ivar_op + = dynamic_cast (op); + if (ivar_op != nullptr) + return internalvar_name (ivar_op->get_internalvar ()); + + uninit_internalvar_operation *uninit_ivar_op + = dynamic_cast (op); + if (uninit_ivar_op != nullptr) + return uninit_ivar_op->get_name (); + + return nullptr; +} + void assign_operation::do_generate_ax (struct expression *exp, struct agent_expr *ax, @@ -1921,10 +1968,7 @@ assign_operation::do_generate_ax (struct expression *exp, if (subop->opcode () != OP_INTERNALVAR) error (_("May only assign to trace state variables")); - internalvar_operation *ivarop - = gdb::checked_static_cast (subop); - - const char *name = internalvar_name (ivarop->get_internalvar ()); + const char *name = internalvar_op_name (subop); struct trace_state_variable *tsv; std::get<1> (m_storage)->generate_ax (exp, ax, value); @@ -1950,10 +1994,7 @@ assign_modify_operation::do_generate_ax (struct expression *exp, if (subop->opcode () != OP_INTERNALVAR) error (_("May only assign to trace state variables")); - internalvar_operation *ivarop - = gdb::checked_static_cast (subop); - - const char *name = internalvar_name (ivarop->get_internalvar ()); + const char *name = internalvar_op_name (subop); struct trace_state_variable *tsv; tsv = find_trace_state_variable (name); diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c index 152fee96f..ca19f4766 100644 --- a/gdb/cli/cli-utils.c +++ b/gdb/cli/cli-utils.c @@ -49,7 +49,7 @@ get_ulongest (const char **pp, int trailer) while (isalnum (*p) || *p == '_') p++; std::string varname (start, p - start); - if (!get_internalvar_integer (lookup_internalvar (varname.c_str ()), + if (!get_internalvar_integer (lookup_only_internalvar (varname.c_str ()), &retval)) error (_("Convenience variable $%s does not have integer value."), varname.c_str ()); diff --git a/gdb/expop.h b/gdb/expop.h index 580a71e94..fbcfdf03c 100644 --- a/gdb/expop.h +++ b/gdb/expop.h @@ -877,6 +877,42 @@ class bool_operation { return true; } }; +/* Reference to a variable that had not been defined at parse time. */ +class uninit_internalvar_operation + : public tuple_holding_operation +{ +public: + + using tuple_holding_operation::tuple_holding_operation; + + value *evaluate (struct type *expect_type, + struct expression *exp, + enum noside noside) override + { + internalvar *iv = lookup_only_internalvar (std::get<0> (m_storage).c_str ()); + if (iv == nullptr) + return value::allocate (builtin_type (exp->gdbarch)->builtin_void); + + return value_of_internalvar (exp->gdbarch, iv); + } + + const char *get_name () const + { + return std::get<0> (m_storage).c_str (); + } + + enum exp_opcode opcode () const override + { return OP_INTERNALVAR; } + +protected: + + void do_generate_ax (struct expression *exp, + struct agent_expr *ax, + struct axs_value *value, + struct type *cast_type) + override; +}; + class internalvar_operation : public tuple_holding_operation { @@ -1895,7 +1931,16 @@ class assign_operation struct expression *exp, enum noside noside) override { - value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); + operation *lhs_op = std::get<0> (m_storage).get (); + + /* If the operation is an internalvar that was not initialized at + parse time, ensure that it exists. */ + auto *uninit_var_op = dynamic_cast (lhs_op); + if (uninit_var_op != nullptr) + lookup_internalvar (uninit_var_op->get_name ()); + + value *lhs = lhs_op->evaluate (nullptr, exp, noside); + /* Special-case assignments where the left-hand-side is a convenience variable -- in these, don't bother setting an expected type. This avoids a weird case where re-assigning a @@ -1944,6 +1989,14 @@ class assign_modify_operation struct expression *exp, enum noside noside) override { + operation *lhs_op = std::get<1> (m_storage).get (); + + /* If the operation is an internalvar that was not initialized at + parse time, ensure that it exists. */ + auto *uninit_var_op = dynamic_cast (lhs_op); + if (uninit_var_op != nullptr) + lookup_internalvar (uninit_var_op->get_name ()); + value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); value *rhs = std::get<2> (m_storage)->evaluate (expect_type, exp, noside); return eval_binop_assign_modify (expect_type, exp, noside, diff --git a/gdb/parse.c b/gdb/parse.c index ffefe6fee..8de3e19d2 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -240,10 +240,9 @@ parser_state::push_dollar (struct stoken str) return; } - /* Any other names are assumed to be debugger internal variables. */ - - push_new - (create_internalvar (copy.c_str () + 1)); + /* Any other names are assumed to be debugger internal variables which + have not yet been initialized. */ + push_new (copy.c_str () + 1); } /* See parser-defs.h. */ diff --git a/gdb/value.c b/gdb/value.c index d4548b876..0fa13f54e 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1908,8 +1908,6 @@ static std::map internalvars; static void init_if_undefined_command (const char* args, int from_tty) { - struct internalvar *intvar = nullptr; - /* Parse the expression - this is taken from set_command(). */ expression_up expr = parse_expression (args); @@ -1927,18 +1925,19 @@ init_if_undefined_command (const char* args, int from_tty) expr::operation *lhs = assign->get_lhs (); expr::internalvar_operation *ivarop = dynamic_cast (lhs); + /* If the lvalue is already a defined variable, return + without evaluating the expression. */ if (ivarop != nullptr) - intvar = ivarop->get_internalvar (); - } - - if (intvar == nullptr) - error (_("The first parameter to init-if-undefined " - "should be a GDB variable.")); + return; - /* Only evaluate the expression if the lvalue is void. - This may still fail if the expression is invalid. */ - if (intvar->kind == INTERNALVAR_VOID) - expr->evaluate (); + expr::uninit_internalvar_operation *uninit_ivarop + = dynamic_cast (lhs); + if (uninit_ivarop != nullptr) + expr->evaluate (); + else + error (_("The first parameter to init-if-undefined " + "should be a GDB variable.")); + } } From patchwork Sun Apr 6 01:39:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Rische X-Patchwork-Id: 109920 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 74F27385B52C for ; Sun, 6 Apr 2025 01:48:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 74F27385B52C Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (2048-bit key, secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=kj0JRK8A X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-106103.protonmail.ch (mail-106103.protonmail.ch [79.135.106.103]) by sourceware.org (Postfix) with ESMTPS id BF2E4385B524 for ; Sun, 6 Apr 2025 01:39:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BF2E4385B524 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BF2E4385B524 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=79.135.106.103 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903550; cv=none; b=AnzCjmdMgNyQYosu20UKTq4XCRfVEggoFQxtuKyGXAx9wuXwxTlVNr6zbgY3tvezBY66FaV2VQAC7fSWzZSEjgyE5M8GugTn/oCoDDdpftWVmjv8+n2Gc2uFQSynCoiSvbnd/Q7njfPnLmtlZxiq9Ji/pTFdr5JGxbjCJg5ykhs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903550; c=relaxed/simple; bh=JIaMl6vXTu4+qtzFg2KYiQ5Lgr+UAtIPC294f65BQwE=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=qVwWrjCLh9oVehhJ34aCTcn7/V0ycrfaGdzmo/fCaYdkf12d8/E98NbepUW/iajXQp81TQzsMDhqGC+BDGyeLa4y6R7/RD7XchS99x63XEJpHkoj3Bb77KJ4KRxTzQ/2Ja2x+PMoA8Z36qlPNnOEmnQbzRXAXj+B8Z7NU341Sk8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BF2E4385B524 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1743903547; x=1744162747; bh=Byftgs3powyizJYdUCqynmUb8rcatZiFe1mIEade7EI=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=kj0JRK8AbjpyfAHsLqlLDrt0Pf5MDyboObEWax1HkCgqWsqFRDrawO1SCtH48LhNM Gi1paUXbqb7jVLBJeiyhVYu4X3GGEe5kRXzLe4zk2Edff0qIMbwjyTF0J3LOrhaEZm tJiIgNP5xufQR5pfVuT/cBb9Rau1OdJ1WvGF6dD206kUzTOGYUOEjxHQL2owlKxBGg SRsHcfSLKc4Rg1bIcdd8rUMHU7ZtpTyncIhwHoKyIyv0LFzbzSs7MH5IdXgcGlIFLa 1iqRbj53L4aSJoyyLFA2W9PVV58zUTvhnRsro3NP1ndXHiJL5ded7Lz961zPs6hQNE T1OPksszKUtyw== Date: Sun, 06 Apr 2025 01:39:04 +0000 To: gdb-patches@sourceware.org From: Antonio Rische Cc: Antonio Rische Subject: [PATCH v6 2/3] gdb: Tab complete internalvars in expressions Message-ID: <20250406013809.230156-3-nt8r@protonmail.com> In-Reply-To: <20250406013809.230156-1-nt8r@protonmail.com> References: <20250406013809.230156-1-nt8r@protonmail.com> Feedback-ID: 21706885:user:proton X-Pm-Message-ID: d8254d02470641cf8221837255b1e119980e453d MIME-Version: 1.0 X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP 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 For example, 'print $f' or 'print $fo+$foo' after running 'set $foo=0' now tab completes. 'print $_siginf' also now tab completes. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=7353 Reviewed-By: Eli Zaretskii Reviewed-By: Keith Seitz --- gdb/NEWS | 3 +++ gdb/completer.c | 9 ++++++++ gdb/doc/gdb.texinfo | 4 ++-- gdb/testsuite/gdb.base/completion.exp | 33 +++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 07c1193d8..7069f3b4b 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -121,6 +121,9 @@ qXfer:threads:read previously treated variables set to void as having never been set (see the $_isvoid convenience function for this behavior). +* Tab completion now suggests convenience variables when tab completing after + the '$' symbol in expressions. + *** Changes in GDB 16 * Support for Nios II targets has been removed as this architecture diff --git a/gdb/completer.c b/gdb/completer.c index 0a8409b44..f94d467ee 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -1497,6 +1497,15 @@ complete_expression (completion_tracker &tracker, && expr_completer->complete (exp.get (), tracker)) return; + /* If the text is non-empty, see if the word is preceded by '$'. */ + if (text[0] != '\0' && text[strlen (text) - strlen (word) - 1] == '$') + { + /* We don't support completion of history indices. */ + if (!isdigit (word[0])) + complete_internalvar (tracker, word); + return; + } + complete_files_symbols (tracker, text, word); } diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e034ac532..f18fe049b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1908,8 +1908,8 @@ limit of 10 elements to print for arrays and strings. @value{GDBN} can fill in the rest of a word in a command for you, if there is only one possibility; it can also show you what the valid possibilities are for the next word in a command, at any time. This works for @value{GDBN} -commands, @value{GDBN} subcommands, command options, and the names of symbols -in your program. +commands, @value{GDBN} subcommands, command options, convenience variables, and +the names of symbols in your program. Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest of a word. If there is only one possibility, @value{GDBN} fills in the diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp index 571d714b7..5b04b62ed 100644 --- a/gdb/testsuite/gdb.base/completion.exp +++ b/gdb/testsuite/gdb.base/completion.exp @@ -1005,3 +1005,36 @@ foreach_with_prefix spc { " " "" } { } } } + +# Test command completion with convenience variables. +test_gdb_complete_unique \ + "print \$_sigin" \ + "print \$_siginfo" + +test_gdb_complete_unique \ + "print \$_siginfo" \ + "print \$_siginfo" + +test_gdb_complete_unique \ + "print \$_gdb_maj" \ + "print \$_gdb_major" + +test_gdb_complete_unique "print \$_gdb_maint_setting_str" "print \$_gdb_maint_setting_str" + +test_gdb_complete_tab_multiple "print \$_gdb_mai" "nt_setting" { + "_gdb_maint_setting" + "_gdb_maint_setting_str" + } + +test_gdb_complete_cmd_multiple "" "print \$_gdb_maint_setting" { + "print \$_gdb_maint_setting" + "print \$_gdb_maint_setting_str" + } + +# Check that a nonexisting convenience variable is not completed. +test_gdb_complete_none "print \$unique_variable_1234567" +test_gdb_complete_none "set \$unique_variable_1234567" + +# Check that after defining the convenience variable it is completed. +gdb_test_no_output "set \$unique_variable_1234567=4" +test_gdb_complete_unique "print \$unique_variable_123456" "print \$unique_variable_1234567" From patchwork Sun Apr 6 01:39:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Rische X-Patchwork-Id: 109918 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 3D420385B532 for ; Sun, 6 Apr 2025 01:44:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3D420385B532 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (2048-bit key, secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=Wsogkwxt X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-106104.protonmail.ch (mail-106104.protonmail.ch [79.135.106.104]) by sourceware.org (Postfix) with ESMTPS id BF2ED3861856 for ; Sun, 6 Apr 2025 01:39:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BF2ED3861856 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BF2ED3861856 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=79.135.106.104 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903558; cv=none; b=AtbFs3xjyt2vt+Y/6guZEKtJqfZJEGax0SbwJhscs+B7bSAeFWl9GBph068UViORWHDVDs4xBLEXMenYGaNZ51/FYNsghSKvanIwTdzISCtiDZmRC8DgrJJxzjzHOshqobb2V6dsqxWPzJpV+1ocOxN5cvmRBaj5OkDPZpeyodY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743903558; c=relaxed/simple; bh=iQYQEjZ0sQXMsB9y3ckLxMxIrHA/gdo0RASQ49meZhg=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=h4kwz+KSX3ZjROOx6MNCnWCEhHOGlUAjmE2cO3fj6WjlK6vGtjcPlsnjZfmeZhsg6IfgtYpsVxeOh8D2P9eiST4AR8+lyAnGZi4j3rRKi5YMvToeVi0aQ3CB6OEs9v/SxWVIX6gPLT3IBv5MTd2Tw4eaftcWGNzdGZQlSLOFGWg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BF2ED3861856 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1743903557; x=1744162757; bh=Ji1icBPvQ3PvbHsNGuF4TGa8VFe6Q5bKYaBzvmYqZT4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=WsogkwxtKzfpIwaJ07ClGHjw7BjW/UrrV0D12vwpi8dLYcZDNVdXgVZHYuvSydQo9 rCjG3/eH1oIgnxTEkCtDqLL9v5I8Z4UBNcHvuFe6AxMl3UjVO33dFsZdXdsENiNNN5 nb6G82UjD3q1BLyK5f2BkgtgLzGKUz23Zit4tyQGlXhEUG+75PpWVtxQVrePx5TdAP UOZ1TccJpUOrhOxwTfRRa/bI8sOEK+IVS/qmo8Yn6ZZDJewDPFUD1yL8U+XcTt5jCO JhVqE+1HywkKTPv57ERshGrT+qujarQlbaTAoZoQ6C3riuVdU6ARrrR7F+qOVY7SpK WGdQkAh2ApNQQ== Date: Sun, 06 Apr 2025 01:39:12 +0000 To: gdb-patches@sourceware.org From: Antonio Rische Cc: Antonio Rische , Guinevere Larsen Subject: [PATCH v6 3/3] gdb: Tab-complete registers in expressions Message-ID: <20250406013809.230156-4-nt8r@protonmail.com> In-Reply-To: <20250406013809.230156-1-nt8r@protonmail.com> References: <20250406013809.230156-1-nt8r@protonmail.com> Feedback-ID: 21706885:user:proton X-Pm-Message-ID: 33627c5db3db2d63e9294ba91a82c8b899cb8ecb MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP 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 For example, "print $ea" completes to "print $eax" on x86. Tested-By: Guinevere Larsen Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=7353 Reviewed-By: Eli Zaretskii Reviewed-By: Keith Seitz --- gdb/NEWS | 4 ++-- gdb/completer.c | 18 +++++++++++++++++- gdb/doc/gdb.texinfo | 4 ++-- gdb/testsuite/gdb.base/completion.exp | 26 +++++++++++++++++++++----- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 7069f3b4b..28c1fe74a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -121,8 +121,8 @@ qXfer:threads:read previously treated variables set to void as having never been set (see the $_isvoid convenience function for this behavior). -* Tab completion now suggests convenience variables when tab completing after - the '$' symbol in expressions. +* Tab completion now suggests convenience variables and registers when tab + completing after the '$' symbol in expressions. *** Changes in GDB 16 diff --git a/gdb/completer.c b/gdb/completer.c index f94d467ee..4c4f3484c 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -54,6 +54,9 @@ static const char *completion_find_completion_word (completion_tracker &tracker, static void set_rl_completer_word_break_characters (const char *break_chars); +static void complete_register (completion_tracker &tracker, + const char *text, const char *word); + static bool gdb_path_isdir (const char *filename); /* See completer.h. */ @@ -1502,7 +1505,10 @@ complete_expression (completion_tracker &tracker, { /* We don't support completion of history indices. */ if (!isdigit (word[0])) - complete_internalvar (tracker, word); + { + complete_internalvar (tracker, word); + complete_register (tracker, text, word); + } return; } @@ -2293,6 +2299,16 @@ reggroup_completer (struct cmd_list_element *ignore, complete_reggroup_names); } +/* Perform completion on register names. */ + +void +complete_register (completion_tracker &tracker, + const char *text, const char *word) +{ + reg_or_group_completer_1 (tracker, text, word, + complete_register_names); +} + /* The default completer_handle_brkchars implementation. */ static void diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index f18fe049b..1c42f0066 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1908,8 +1908,8 @@ limit of 10 elements to print for arrays and strings. @value{GDBN} can fill in the rest of a word in a command for you, if there is only one possibility; it can also show you what the valid possibilities are for the next word in a command, at any time. This works for @value{GDBN} -commands, @value{GDBN} subcommands, command options, convenience variables, and -the names of symbols in your program. +commands, @value{GDBN} subcommands, command options, convenience variables, +machine registers, and the names of symbols in your program. Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest of a word. If there is only one possibility, @value{GDBN} fills in the diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp index 5b04b62ed..2c9d77421 100644 --- a/gdb/testsuite/gdb.base/completion.exp +++ b/gdb/testsuite/gdb.base/completion.exp @@ -139,17 +139,24 @@ gdb_test "complete set trace-buffer-size unl" "set trace-buffer-size unlimited" set regs_output [capture_command_output "mt print registers" \ ".*Name.*Nr.*Rel.*Offset.*Size.*Type.\[^\n\]*\n"] append regs_output "\n" -append regs_output [capture_command_output "mt print reggroups" \ - ".*Group.*Type\[^\n]*\n"] -append regs_output "\n" append regs_output [capture_command_output "mt print user-registers" \ ".*Name.*Nr\[^\n]*\n"] +set reg_groups_output [capture_command_output "mt print reggroups" \ + ".*Group.*Type\[^\n]*\n"] +append reg_groups_output "\n" + set all_regs {} foreach {- reg} [regexp -all -inline -line {^(\w+)} $regs_output] { lappend all_regs $reg } -set all_regs [join [lsort -unique $all_regs]] +set all_reg_groups {} +foreach {- group} [regexp -all -inline -line {^\s*(\w+)} $reg_groups_output] { + lappend all_reg_groups $group +} + +set all_regs_and_groups [concat $all_regs $all_reg_groups] +set all_regs_and_groups [join [lsort -unique $all_regs_and_groups]] # ... and then compare them to the completion of "info registers". @@ -159,7 +166,7 @@ foreach {-> reg} [regexp -all -inline -line {^info registers (\w+\S*)} $regs_out lappend completed_regs $reg } set completed_regs [join [lsort $completed_regs]] -gdb_assert {$all_regs eq $completed_regs} "complete 'info registers '" +gdb_assert {$all_regs_and_groups eq $completed_regs} "complete 'info registers '" # Tests below are about tab-completion, which doesn't work if readline # library isn't used. Check it first. @@ -168,6 +175,15 @@ if { ![readline_is_used] } { return -1 } +# Test "print $" completion +set complete_dollar_output [capture_command_output "complete print $" ""] + +set found_all_regs true +foreach {- reg} $all_regs { + set found_all_regs [expr $found_all_regs && [string first $reg $complete_dollar_output] != -1] +} +gdb_assert $found_all_regs "complete 'print \$' contained all registers" + # The bulk of this test script pre-dates the completion-support # library, and should probably (where possible) be converted. # However, for now, new tests are being added using this library.