From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id XBZPCol58V8CegAAWB0awg (envelope-from ) for ; Sun, 03 Jan 2021 03:00:09 -0500 Received: by simark.ca (Postfix, from userid 112) id 220E61F0AA; Sun, 3 Jan 2021 03:00:09 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,NORMAL_HTTP_TO_IP,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (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 simark.ca (Postfix) with ESMTPS id 7645C1E965 for ; Sun, 3 Jan 2021 03:00:02 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C17FC3851C31; Sun, 3 Jan 2021 08:00:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C17FC3851C31 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609660801; bh=MsEG+IBAliTFjSqqe0Otq3XHWwqRheTWHXmHEzGyOQY=; h=To:Subject:References:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:From; b=nYLQzEGkeYLSOQaOBTi7buoGevVKnH8x5GAbTlXvR9HNvZ0ULOg/LuI++EHxuWjNw iCLmig3QrSjU4kQUfygJeCXzAvsS6tpcXOs0l55BjrrVGTqQHz4Opoe3tVR9N/scsD 7058gayQBDuL7aX6SWeU9EjLvR88BAg8F/3oKMD4= Received: from mail.sergiodj.net (mail.sergiodj.net [167.114.15.217]) by sourceware.org (Postfix) with ESMTPS id 4ECBE3857004 for ; Sun, 3 Jan 2021 07:59:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4ECBE3857004 Received: from localhost (bras-base-toroon1016w-grc-31-76-64-52-221.dsl.bell.ca [76.64.52.221]) by mail.sergiodj.net (Postfix) with ESMTPSA id B58EDA00BB; Sun, 3 Jan 2021 02:59:57 -0500 (EST) To: Tom Tromey Subject: Re: [PATCH] Change handling of '!' operator in stap probes References: <20201231230205.264712-1-tom@tromey.com> X-URL: http://blog.sergiodj.net Date: Sun, 03 Jan 2021 02:59:57 -0500 Message-ID: <87h7ny30xu.fsf@paluero> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergio Durigan Junior via Gdb-patches Reply-To: Sergio Durigan Junior Cc: gdb-patches@sourceware.org Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" On Thursday, December 31 2020, Tom Tromey wrote: > While working on the expression rewrite, I noticed that the '!' > operator is handled as if it were a binary operator. However, this > seems incorrect. Instead, I think it should be handled alongside the > other unary operators in stap_parse_single_operand. > > This patch makes this change. Thanks for the patch, Tom. This code was written based on the information contained here: https://sourceware.org/binutils/docs/as/Infix-Ops.html You can see that it says: ! Bitwise Or Not The problem is that, when we examine gas' source code, we see that it doesn't treat '!' as "bitwise or not" (fortunately!), but as the "logical not": https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gas/symbols.c;h=f6e4b718ef719eef8a7e6e29dbadf3605058403d;hb=HEAD#l1128 OK, this means that our stap-probe.c is not completely wrong: the enum should indeed be named UNOP_LOGICAL_NOT. Now, when we check to see if the precedence assigned to UNOP_LOGICAL_NOT is the right one, we see that it is: https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gas/expr.c;h=1b420d928cde50456af0137529b8215294ba521d;hb=HEAD#l1481 /* Rank Examples 0 operand, (expression) 1 || 2 && 3 == <> < <= >= > 4 + - 5 used for * / % in MRI mode 6 & ^ ! | ... Huh, interesting. Anyway, this whole investigation (plus the fact that, as you mentioned, we don't have tests to exercise this part of the code) made me uncover a few latent bugs on the stap parser code, so I'm sending a patch that incorporates part of your changes and also fixes the issues I found. As a bonus, I'm proposing a new testcase (amd64-only) to make sure that we expand the coverage of this code. WDYT? -- Sergio GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36 Please send encrypted e-mail if possible https://sergiodj.net/ >From da02db7cacef62ce085d5715b1339b24d8f2260c Mon Sep 17 00:00:00 2001 From: Sergio Durigan Junior Date: Sun, 3 Jan 2021 02:42:52 -0500 Subject: [PATCH] Fix a few stap parser issues and add a new test for probe expressions The creation of this patch was motivated by Tom's "Change handling of '!' operator in stap probes" patch. While reviewing his patch, I stumbled upon a few issues with the stap expression parser. They are: - As it turns out, even with Tom's patch applied the parser doesn't properly handle the '!' operator. The underlying issue was the fact that stap_parse_argument_conditionally also needed to be patched in order to recognize '!' as an operator that is part of a single operand, and parse it accordingly. - While writing the testcase I'm proposing on this patch, I found that parenthesized sub-expressions were not being parsed correctly when there was another term after them. For example: 1 - (2 + 3) + 4 In this case, the parser was considering "1" to be the left-side of the expression, and "(2 + 3) + 4" to be the right-side. The patch fixes the parser by making it identify whether a parenthesized sub-expression has just been parsed, and act accordingly. I've tested this on my Debian testing amd64, and everything seems OK. gdb/ChangeLog: 2021-01-03 Sergio Durigan Junior Tom Tromey * stap-probe.c (stap_parse_single_operand): Handle '!' operator. (stap_parse_argument_conditionally): Likewise. Skip spaces after processing open-parenthesis sub-expression. (stap_parse_argument_1): Skip spaces after call to stap_parse_argument_conditionally. Handle case when right-side expression is a parenthesized sub-expression. Skip spaces after call to stap_parse_argument_1. gdb/testsuite/ChangeLog: 2021-01-03 Sergio Durigan Junior * gdb.arch/amd64-stap-expressions.S: New file. * gdb.arch/amd64-stap-expressions.exp: New file. --- gdb/stap-probe.c | 31 +++++++-- .../gdb.arch/amd64-stap-expressions.S | 43 ++++++++++++ .../gdb.arch/amd64-stap-expressions.exp | 68 +++++++++++++++++++ 3 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/amd64-stap-expressions.S create mode 100644 gdb/testsuite/gdb.arch/amd64-stap-expressions.exp diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c index c2ddd047f6..224dd5714f 100644 --- a/gdb/stap-probe.c +++ b/gdb/stap-probe.c @@ -870,7 +870,7 @@ stap_parse_single_operand (struct stap_parse_info *p) return; } - if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+') + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!') { char c = *p->arg; /* We use this variable to do a lookahead. */ @@ -924,6 +924,8 @@ stap_parse_single_operand (struct stap_parse_info *p) write_exp_elt_opcode (&p->pstate, UNOP_NEG); else if (c == '~') write_exp_elt_opcode (&p->pstate, UNOP_COMPLEMENT); + else if (c == '!') + write_exp_elt_opcode (&p->pstate, UNOP_LOGICAL_NOT); } } else if (isdigit (*p->arg)) @@ -1012,7 +1014,7 @@ stap_parse_argument_conditionally (struct stap_parse_info *p) { gdb_assert (gdbarch_stap_is_single_operand_p (p->gdbarch)); - if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */ + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!' || isdigit (*p->arg) || gdbarch_stap_is_single_operand (p->gdbarch, p->arg)) stap_parse_single_operand (p); @@ -1027,11 +1029,12 @@ stap_parse_argument_conditionally (struct stap_parse_info *p) stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE); - --p->inside_paren_p; + p->arg = skip_spaces (p->arg); if (*p->arg != ')') - error (_("Missign close-paren on expression `%s'."), + error (_("Missign close-parenthesis on expression `%s'."), p->saved_arg); + --p->inside_paren_p; ++p->arg; if (p->inside_paren_p) p->arg = skip_spaces (p->arg); @@ -1067,6 +1070,9 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs, stap_parse_argument_conditionally (p); } + if (p->inside_paren_p) + p->arg = skip_spaces (p->arg); + /* Start to parse the right-side, and to "join" left and right sides depending on the operation specified. @@ -1104,8 +1110,21 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs, if (p->inside_paren_p) p->arg = skip_spaces (p->arg); - /* Parse the right-side of the expression. */ + /* Parse the right-side of the expression. + + We save whether the right-side is a parenthesized + subexpression because, if it is, we will have to finish + processing this part of the expression before continuing. */ + bool paren_subexp = *p->arg == '('; + stap_parse_argument_conditionally (p); + if (p->inside_paren_p) + p->arg = skip_spaces (p->arg); + if (paren_subexp) + { + write_exp_elt_opcode (&p->pstate, opcode); + continue; + } /* While we still have operators, try to parse another right-side, but using the current right-side as a left-side. */ @@ -1130,6 +1149,8 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs, /* Parse the right-side of the expression, but since we already have a left-side at this point, set `has_lhs' to 1. */ stap_parse_argument_1 (p, 1, lookahead_prec); + if (p->inside_paren_p) + p->arg = skip_spaces (p->arg); } write_exp_elt_opcode (&p->pstate, opcode); diff --git a/gdb/testsuite/gdb.arch/amd64-stap-expressions.S b/gdb/testsuite/gdb.arch/amd64-stap-expressions.S new file mode 100644 index 0000000000..76a47aa9b5 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-stap-expressions.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + + .file "amd64-stap-expressions.S" + .text + .globl main +main: + /* We use a nop here because we don't want the first probe to + be placed at the same location as the main label. */ + nop + + /* Single operands. */ + STAP_PROBE1(probe, log_neg, 8@!($0+$1)) + STAP_PROBE1(probe, minus, -8@-($3+$4)) + STAP_PROBE1(probe, bit_neg, -8@~$22) + + /* Arithmetic expressions. */ + STAP_PROBE1(probe, plus1, 8@$3+($10-$8)-$1) + STAP_PROBE1(probe, plus2, 8@$100-( ($8+$10) -$50)+$3) + STAP_PROBE1(probe, plus3, 8@$100-(($8+$10)-$50)+((($8 - $9) + $40) - $4)+$4) + + /* Bitwise expressions. */ + STAP_PROBE1(probe, and, 8@$128&$128) + STAP_PROBE1(probe, or, 8@$8|$4) + + xor %rax,%rax + ret diff --git a/gdb/testsuite/gdb.arch/amd64-stap-expressions.exp b/gdb/testsuite/gdb.arch/amd64-stap-expressions.exp new file mode 100644 index 0000000000..5e3cb60a9e --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-stap-expressions.exp @@ -0,0 +1,68 @@ +# Copyright 2021 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +standard_testfile ".S" + +if { ![istarget "x86_64-*-*"] || ![is_lp64_target] } { + verbose "Skipping $testfile.exp" + return +} + +if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { + return -1 +} + +# Helper procedure to go to probe NAME + +proc goto_probe { name } { + global decimal hex + + gdb_test "break -pstap $name" "Breakpoint $decimal at $hex" + gdb_test "continue" "Breakpoint $decimal, main \\(\\) at .*\r\n.*STAP_PROBE1.*${name},.*\\)" +} + +# Helper procedure to test the probe's argument + +proc test_probe_value { value } { + gdb_test "print \$_probe_argc" "= 1" + gdb_test "print \$_probe_arg0" "= $value" +} + +if { ![runto_main] } { + return -1 +} + +# Name and expected value for each probe. +set probe_names_and_values { + { "log_neg" "0" } + { "minus" "-7" } + { "bit_neg" "-23" } + + { "plus1" "4" } + { "plus2" "135" } + { "plus3" "171" } + + { "and" "128" } + { "or" "12" } +} + +foreach probe_info $probe_names_and_values { + set name [lindex $probe_info 0] + set value [lindex $probe_info 1] + with_test_prefix $name { + goto_probe $name + test_probe_value $value + } +} -- 2.29.2