Message ID | 1682414197-13173-2-git-send-email-alan.maguire@oracle.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp3275030vqo; Tue, 25 Apr 2023 02:21:11 -0700 (PDT) X-Google-Smtp-Source: AKy350aQ7YhvBU+yLhb9lFGQF0+R7ctKqe9rydbZvm2fG6MCD7RlaMJB6QEm5uE9fhgSLyZtkYEQ X-Received: by 2002:a17:90a:d985:b0:247:193b:ce84 with SMTP id d5-20020a17090ad98500b00247193bce84mr16792771pjv.15.1682414471574; Tue, 25 Apr 2023 02:21:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1682414471; cv=none; d=google.com; s=arc-20160816; b=Z22256HfBLloaR/LOuy31aDAVmqQpZxliiDU+dcAtWRwm1Qlq9qCVe44Jw3oKaakR7 J8Yi1sV8rv7DDqIGh9odpBQWFDLRMNCcCX93OLxHzR7KE4q9aygKbBxSLdKdqRZ90Gm4 20+YqPOOO/to2OPdAipCMhMMsEADlQGm/DAnuLYpPJapTf85zPT43rf/thYsmlT/kuLk Zus+hxX2+seR7v1faA3XNM6+HWZGACkmn3g3koFb2Q8Ssdswglt1E4OEGIS2dfxQXMUz xzqw1ImnGwYHVtBktEdOFfIvAFYLBGY3RdkQiA4WM8AVDvxUdZYYDlUeHSFbyoiZMnAn u/Mg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:dkim-signature; bh=uEvv3LAyU/zfvFvoOcm942rAaxSYCfXplaAMUlb7W6o=; b=SI8LPkr0UimygqQlZb6/3WuLCQGluQJK2fADJcmf1v4qZfpPxP0U2qBkI06iRUYgIQ F4fdMpd6s+U+C9fTh30WQkfefKP9dUH0tMdp6+JfC3q65cpQMznoPqBXM9GbKQbgQWZ/ YiAcLFfa7LG7yvS4TxGydK4O5NFsK4g3sEN7eLiWV/W3/qT8yr4CRicsKZ230coLOMBp EJ0zyrOVHkFIRMQYMe0p6yBdAmX0aHbQXJq/eTAgNgHQ2xg8hGzzigaDeqL1CkyW25Vd MsBPBz1MvZ70RbWCaKonynwJ74iZ4VPTp/mawz5kQgfKZm/H+r2UF+dw1i/q6yWcBi5D JtzQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@oracle.com header.s=corp-2023-03-30 header.b=1VMGomFV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=oracle.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 186-20020a6300c3000000b0051b8ab93411si12211356pga.767.2023.04.25.02.20.59; Tue, 25 Apr 2023 02:21:11 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@oracle.com header.s=corp-2023-03-30 header.b=1VMGomFV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=oracle.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233674AbjDYJQx (ORCPT <rfc822;zxc52fgh@gmail.com> + 99 others); Tue, 25 Apr 2023 05:16:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56556 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233428AbjDYJQu (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 25 Apr 2023 05:16:50 -0400 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC8AA2685; Tue, 25 Apr 2023 02:16:49 -0700 (PDT) Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 33P0i0ZW005234; Tue, 25 Apr 2023 09:16:45 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2023-03-30; bh=uEvv3LAyU/zfvFvoOcm942rAaxSYCfXplaAMUlb7W6o=; b=1VMGomFVkEsfbBS33eMP4Tk269b1nYwJ687E5J/zysOcG9XQzRAgMkRtDtZkEyfKywVi F0JY9WmLP5savx6SJ5bRNjDmuFASGEhf6WsNFrojt1lDsIegADlryCTiqSHs7lJZlrR+ ieiRbV63zbCfO2xyZEUBpWYZFDdoRF1IGN8izTJmwrXAD1h+wtdg9xFSQ0A2amrbOs+7 /XbJumwzi8VoghLwd5x64ZSMMX8zSfBz62B/mX0sdfMnXNjuBj0/OfNHx6UcjjRXTG98 TzAKQ1vLuuZoYui/tx5uNQ502dqmSCg9kRwuqtn9Gj4cKLaV6HBdihJytH2zn8cF2/02 1Q== Received: from iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta03.appoci.oracle.com [130.35.103.27]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3q476tvun9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Apr 2023 09:16:44 +0000 Received: from pps.filterd (iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 33P7roOg025226; Tue, 25 Apr 2023 09:16:44 GMT Received: from pps.reinject (localhost [127.0.0.1]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTPS id 3q461cdwcm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Apr 2023 09:16:44 +0000 Received: from iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 33P93LCR024482; Tue, 25 Apr 2023 09:16:43 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-181-126.vpn.oracle.com [10.175.181.126]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTP id 3q461cdwa1-2; Tue, 25 Apr 2023 09:16:43 +0000 From: Alan Maguire <alan.maguire@oracle.com> To: rostedt@goodmis.org, mhiramat@kernel.org Cc: corbet@lwn.net, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Alan Maguire <alan.maguire@oracle.com> Subject: [PATCH tracing 1/3] tracing: support > 8 byte array filter predicates Date: Tue, 25 Apr 2023 10:16:35 +0100 Message-Id: <1682414197-13173-2-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1682414197-13173-1-git-send-email-alan.maguire@oracle.com> References: <1682414197-13173-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.942,Hydra:6.0.573,FMLib:17.11.170.22 definitions=2023-04-25_03,2023-04-21_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxlogscore=999 suspectscore=0 malwarescore=0 mlxscore=0 spamscore=0 adultscore=0 phishscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2303200000 definitions=main-2304250082 X-Proofpoint-GUID: LZoWkMPiAxPu9ZSGPpVbSovH5u3HcKa6 X-Proofpoint-ORIG-GUID: LZoWkMPiAxPu9ZSGPpVbSovH5u3HcKa6 X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,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 lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1764139437001966440?= X-GMAIL-MSGID: =?utf-8?q?1764139437001966440?= |
Series |
tracing: support > 8 byte filter predicates
|
|
Commit Message
Alan Maguire
April 25, 2023, 9:16 a.m. UTC
For > 8 byte values, allow simple binary '==', '!=' predicates
where the user passes in a hex ASCII representation of the
desired value. This representation must match the field size
exactly, and a simple memory comparison between predicate and
actual values is carried out. This will allow predicates with
for example IPv6 addresses to be supported, such as filtering
on ::1
cd /sys/kernel/debug/tracing/events/tcp/tcp_receive_reset
echo "saddr_v6 == 0x00000000000000000000000000000001" > filter
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
kernel/trace/trace_events_filter.c | 55 +++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
Comments
Hi Alan, kernel test robot noticed the following build warnings: [auto build test WARNING on linus/master] [also build test WARNING on v6.3 next-20230424] [cannot apply to rostedt-trace/for-next rostedt-trace/for-next-urgent] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Alan-Maguire/tracing-support-8-byte-array-filter-predicates/20230425-171832 base: linus/master patch link: https://lore.kernel.org/r/1682414197-13173-2-git-send-email-alan.maguire%40oracle.com patch subject: [PATCH tracing 1/3] tracing: support > 8 byte array filter predicates config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20230425/202304251817.eCbqLbrw-lkp@intel.com/config) compiler: hppa-linux-gcc (GCC) 12.1.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/d49d8291984dc5ac8933ff406c9f5e56ebbdd4e7 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Alan-Maguire/tracing-support-8-byte-array-filter-predicates/20230425-171832 git checkout d49d8291984dc5ac8933ff406c9f5e56ebbdd4e7 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=parisc olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=parisc SHELL=/bin/bash kernel/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304251817.eCbqLbrw-lkp@intel.com/ All warnings (new ones prefixed by >>): kernel/trace/trace_events_filter.c: In function 'predicate_parse': >> kernel/trace/trace_events_filter.c:628:39: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 628 | kfree((u8 *)prog_stack[i].pred->val); | ^ kernel/trace/trace_events_filter.c: In function 'filter_pred_memcmp': kernel/trace/trace_events_filter.c:900:19: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 900 | u8 *cmp = (u8 *)(pred->val); | ^ kernel/trace/trace_events_filter.c: In function 'parse_pred': >> kernel/trace/trace_events_filter.c:1682:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] 1682 | pred->val = (u64)pred_val; | ^ vim +628 kernel/trace/trace_events_filter.c 189 190 /* 191 * Without going into a formal proof, this explains the method that is used in 192 * parsing the logical expressions. 193 * 194 * For example, if we have: "a && !(!b || (c && g)) || d || e && !f" 195 * The first pass will convert it into the following program: 196 * 197 * n1: r=a; l1: if (!r) goto l4; 198 * n2: r=b; l2: if (!r) goto l4; 199 * n3: r=c; r=!r; l3: if (r) goto l4; 200 * n4: r=g; r=!r; l4: if (r) goto l5; 201 * n5: r=d; l5: if (r) goto T 202 * n6: r=e; l6: if (!r) goto l7; 203 * n7: r=f; r=!r; l7: if (!r) goto F 204 * T: return TRUE 205 * F: return FALSE 206 * 207 * To do this, we use a data structure to represent each of the above 208 * predicate and conditions that has: 209 * 210 * predicate, when_to_branch, invert, target 211 * 212 * The "predicate" will hold the function to determine the result "r". 213 * The "when_to_branch" denotes what "r" should be if a branch is to be taken 214 * "&&" would contain "!r" or (0) and "||" would contain "r" or (1). 215 * The "invert" holds whether the value should be reversed before testing. 216 * The "target" contains the label "l#" to jump to. 217 * 218 * A stack is created to hold values when parentheses are used. 219 * 220 * To simplify the logic, the labels will start at 0 and not 1. 221 * 222 * The possible invert values are 1 and 0. The number of "!"s that are in scope 223 * before the predicate determines the invert value, if the number is odd then 224 * the invert value is 1 and 0 otherwise. This means the invert value only 225 * needs to be toggled when a new "!" is introduced compared to what is stored 226 * on the stack, where parentheses were used. 227 * 228 * The top of the stack and "invert" are initialized to zero. 229 * 230 * ** FIRST PASS ** 231 * 232 * #1 A loop through all the tokens is done: 233 * 234 * #2 If the token is an "(", the stack is push, and the current stack value 235 * gets the current invert value, and the loop continues to the next token. 236 * The top of the stack saves the "invert" value to keep track of what 237 * the current inversion is. As "!(a && !b || c)" would require all 238 * predicates being affected separately by the "!" before the parentheses. 239 * And that would end up being equivalent to "(!a || b) && !c" 240 * 241 * #3 If the token is an "!", the current "invert" value gets inverted, and 242 * the loop continues. Note, if the next token is a predicate, then 243 * this "invert" value is only valid for the current program entry, 244 * and does not affect other predicates later on. 245 * 246 * The only other acceptable token is the predicate string. 247 * 248 * #4 A new entry into the program is added saving: the predicate and the 249 * current value of "invert". The target is currently assigned to the 250 * previous program index (this will not be its final value). 251 * 252 * #5 We now enter another loop and look at the next token. The only valid 253 * tokens are ")", "&&", "||" or end of the input string "\0". 254 * 255 * #6 The invert variable is reset to the current value saved on the top of 256 * the stack. 257 * 258 * #7 The top of the stack holds not only the current invert value, but also 259 * if a "&&" or "||" needs to be processed. Note, the "&&" takes higher 260 * precedence than "||". That is "a && b || c && d" is equivalent to 261 * "(a && b) || (c && d)". Thus the first thing to do is to see if "&&" needs 262 * to be processed. This is the case if an "&&" was the last token. If it was 263 * then we call update_preds(). This takes the program, the current index in 264 * the program, and the current value of "invert". More will be described 265 * below about this function. 266 * 267 * #8 If the next token is "&&" then we set a flag in the top of the stack 268 * that denotes that "&&" needs to be processed, break out of this loop 269 * and continue with the outer loop. 270 * 271 * #9 Otherwise, if a "||" needs to be processed then update_preds() is called. 272 * This is called with the program, the current index in the program, but 273 * this time with an inverted value of "invert" (that is !invert). This is 274 * because the value taken will become the "when_to_branch" value of the 275 * program. 276 * Note, this is called when the next token is not an "&&". As stated before, 277 * "&&" takes higher precedence, and "||" should not be processed yet if the 278 * next logical operation is "&&". 279 * 280 * #10 If the next token is "||" then we set a flag in the top of the stack 281 * that denotes that "||" needs to be processed, break out of this loop 282 * and continue with the outer loop. 283 * 284 * #11 If this is the end of the input string "\0" then we break out of both 285 * loops. 286 * 287 * #12 Otherwise, the next token is ")", where we pop the stack and continue 288 * this inner loop. 289 * 290 * Now to discuss the update_pred() function, as that is key to the setting up 291 * of the program. Remember the "target" of the program is initialized to the 292 * previous index and not the "l" label. The target holds the index into the 293 * program that gets affected by the operand. Thus if we have something like 294 * "a || b && c", when we process "a" the target will be "-1" (undefined). 295 * When we process "b", its target is "0", which is the index of "a", as that's 296 * the predicate that is affected by "||". But because the next token after "b" 297 * is "&&" we don't call update_preds(). Instead continue to "c". As the 298 * next token after "c" is not "&&" but the end of input, we first process the 299 * "&&" by calling update_preds() for the "&&" then we process the "||" by 300 * calling updates_preds() with the values for processing "||". 301 * 302 * What does that mean? What update_preds() does is to first save the "target" 303 * of the program entry indexed by the current program entry's "target" 304 * (remember the "target" is initialized to previous program entry), and then 305 * sets that "target" to the current index which represents the label "l#". 306 * That entry's "when_to_branch" is set to the value passed in (the "invert" 307 * or "!invert"). Then it sets the current program entry's target to the saved 308 * "target" value (the old value of the program that had its "target" updated 309 * to the label). 310 * 311 * Looking back at "a || b && c", we have the following steps: 312 * "a" - prog[0] = { "a", X, -1 } // pred, when_to_branch, target 313 * "||" - flag that we need to process "||"; continue outer loop 314 * "b" - prog[1] = { "b", X, 0 } 315 * "&&" - flag that we need to process "&&"; continue outer loop 316 * (Notice we did not process "||") 317 * "c" - prog[2] = { "c", X, 1 } 318 * update_preds(prog, 2, 0); // invert = 0 as we are processing "&&" 319 * t = prog[2].target; // t = 1 320 * s = prog[t].target; // s = 0 321 * prog[t].target = 2; // Set target to "l2" 322 * prog[t].when_to_branch = 0; 323 * prog[2].target = s; 324 * update_preds(prog, 2, 1); // invert = 1 as we are now processing "||" 325 * t = prog[2].target; // t = 0 326 * s = prog[t].target; // s = -1 327 * prog[t].target = 2; // Set target to "l2" 328 * prog[t].when_to_branch = 1; 329 * prog[2].target = s; 330 * 331 * #13 Which brings us to the final step of the first pass, which is to set 332 * the last program entry's when_to_branch and target, which will be 333 * when_to_branch = 0; target = N; ( the label after the program entry after 334 * the last program entry processed above). 335 * 336 * If we denote "TRUE" to be the entry after the last program entry processed, 337 * and "FALSE" the program entry after that, we are now done with the first 338 * pass. 339 * 340 * Making the above "a || b && c" have a program of: 341 * prog[0] = { "a", 1, 2 } 342 * prog[1] = { "b", 0, 2 } 343 * prog[2] = { "c", 0, 3 } 344 * 345 * Which translates into: 346 * n0: r = a; l0: if (r) goto l2; 347 * n1: r = b; l1: if (!r) goto l2; 348 * n2: r = c; l2: if (!r) goto l3; // Which is the same as "goto F;" 349 * T: return TRUE; l3: 350 * F: return FALSE 351 * 352 * Although, after the first pass, the program is correct, it is 353 * inefficient. The simple sample of "a || b && c" could be easily been 354 * converted into: 355 * n0: r = a; if (r) goto T 356 * n1: r = b; if (!r) goto F 357 * n2: r = c; if (!r) goto F 358 * T: return TRUE; 359 * F: return FALSE; 360 * 361 * The First Pass is over the input string. The next too passes are over 362 * the program itself. 363 * 364 * ** SECOND PASS ** 365 * 366 * Which brings us to the second pass. If a jump to a label has the 367 * same condition as that label, it can instead jump to its target. 368 * The original example of "a && !(!b || (c && g)) || d || e && !f" 369 * where the first pass gives us: 370 * 371 * n1: r=a; l1: if (!r) goto l4; 372 * n2: r=b; l2: if (!r) goto l4; 373 * n3: r=c; r=!r; l3: if (r) goto l4; 374 * n4: r=g; r=!r; l4: if (r) goto l5; 375 * n5: r=d; l5: if (r) goto T 376 * n6: r=e; l6: if (!r) goto l7; 377 * n7: r=f; r=!r; l7: if (!r) goto F: 378 * T: return TRUE; 379 * F: return FALSE 380 * 381 * We can see that "l3: if (r) goto l4;" and at l4, we have "if (r) goto l5;". 382 * And "l5: if (r) goto T", we could optimize this by converting l3 and l4 383 * to go directly to T. To accomplish this, we start from the last 384 * entry in the program and work our way back. If the target of the entry 385 * has the same "when_to_branch" then we could use that entry's target. 386 * Doing this, the above would end up as: 387 * 388 * n1: r=a; l1: if (!r) goto l4; 389 * n2: r=b; l2: if (!r) goto l4; 390 * n3: r=c; r=!r; l3: if (r) goto T; 391 * n4: r=g; r=!r; l4: if (r) goto T; 392 * n5: r=d; l5: if (r) goto T; 393 * n6: r=e; l6: if (!r) goto F; 394 * n7: r=f; r=!r; l7: if (!r) goto F; 395 * T: return TRUE 396 * F: return FALSE 397 * 398 * In that same pass, if the "when_to_branch" doesn't match, we can simply 399 * go to the program entry after the label. That is, "l2: if (!r) goto l4;" 400 * where "l4: if (r) goto T;", then we can convert l2 to be: 401 * "l2: if (!r) goto n5;". 402 * 403 * This will have the second pass give us: 404 * n1: r=a; l1: if (!r) goto n5; 405 * n2: r=b; l2: if (!r) goto n5; 406 * n3: r=c; r=!r; l3: if (r) goto T; 407 * n4: r=g; r=!r; l4: if (r) goto T; 408 * n5: r=d; l5: if (r) goto T 409 * n6: r=e; l6: if (!r) goto F; 410 * n7: r=f; r=!r; l7: if (!r) goto F 411 * T: return TRUE 412 * F: return FALSE 413 * 414 * Notice, all the "l#" labels are no longer used, and they can now 415 * be discarded. 416 * 417 * ** THIRD PASS ** 418 * 419 * For the third pass we deal with the inverts. As they simply just 420 * make the "when_to_branch" get inverted, a simple loop over the 421 * program to that does: "when_to_branch ^= invert;" will do the 422 * job, leaving us with: 423 * n1: r=a; if (!r) goto n5; 424 * n2: r=b; if (!r) goto n5; 425 * n3: r=c: if (!r) goto T; 426 * n4: r=g; if (!r) goto T; 427 * n5: r=d; if (r) goto T 428 * n6: r=e; if (!r) goto F; 429 * n7: r=f; if (r) goto F 430 * T: return TRUE 431 * F: return FALSE 432 * 433 * As "r = a; if (!r) goto n5;" is obviously the same as 434 * "if (!a) goto n5;" without doing anything we can interpret the 435 * program as: 436 * n1: if (!a) goto n5; 437 * n2: if (!b) goto n5; 438 * n3: if (!c) goto T; 439 * n4: if (!g) goto T; 440 * n5: if (d) goto T 441 * n6: if (!e) goto F; 442 * n7: if (f) goto F 443 * T: return TRUE 444 * F: return FALSE 445 * 446 * Since the inverts are discarded at the end, there's no reason to store 447 * them in the program array (and waste memory). A separate array to hold 448 * the inverts is used and freed at the end. 449 */ 450 static struct prog_entry * 451 predicate_parse(const char *str, int nr_parens, int nr_preds, 452 parse_pred_fn parse_pred, void *data, 453 struct filter_parse_error *pe) 454 { 455 struct prog_entry *prog_stack; 456 struct prog_entry *prog; 457 const char *ptr = str; 458 char *inverts = NULL; 459 int *op_stack; 460 int *top; 461 int invert = 0; 462 int ret = -ENOMEM; 463 int len; 464 int N = 0; 465 int i; 466 467 nr_preds += 2; /* For TRUE and FALSE */ 468 469 op_stack = kmalloc_array(nr_parens, sizeof(*op_stack), GFP_KERNEL); 470 if (!op_stack) 471 return ERR_PTR(-ENOMEM); 472 prog_stack = kcalloc(nr_preds, sizeof(*prog_stack), GFP_KERNEL); 473 if (!prog_stack) { 474 parse_error(pe, -ENOMEM, 0); 475 goto out_free; 476 } 477 inverts = kmalloc_array(nr_preds, sizeof(*inverts), GFP_KERNEL); 478 if (!inverts) { 479 parse_error(pe, -ENOMEM, 0); 480 goto out_free; 481 } 482 483 top = op_stack; 484 prog = prog_stack; 485 *top = 0; 486 487 /* First pass */ 488 while (*ptr) { /* #1 */ 489 const char *next = ptr++; 490 491 if (isspace(*next)) 492 continue; 493 494 switch (*next) { 495 case '(': /* #2 */ 496 if (top - op_stack > nr_parens) { 497 ret = -EINVAL; 498 goto out_free; 499 } 500 *(++top) = invert; 501 continue; 502 case '!': /* #3 */ 503 if (!is_not(next)) 504 break; 505 invert = !invert; 506 continue; 507 } 508 509 if (N >= nr_preds) { 510 parse_error(pe, FILT_ERR_TOO_MANY_PREDS, next - str); 511 goto out_free; 512 } 513 514 inverts[N] = invert; /* #4 */ 515 prog[N].target = N-1; 516 517 len = parse_pred(next, data, ptr - str, pe, &prog[N].pred); 518 if (len < 0) { 519 ret = len; 520 goto out_free; 521 } 522 ptr = next + len; 523 524 N++; 525 526 ret = -1; 527 while (1) { /* #5 */ 528 next = ptr++; 529 if (isspace(*next)) 530 continue; 531 532 switch (*next) { 533 case ')': 534 case '\0': 535 break; 536 case '&': 537 case '|': 538 /* accepting only "&&" or "||" */ 539 if (next[1] == next[0]) { 540 ptr++; 541 break; 542 } 543 fallthrough; 544 default: 545 parse_error(pe, FILT_ERR_TOO_MANY_PREDS, 546 next - str); 547 goto out_free; 548 } 549 550 invert = *top & INVERT; 551 552 if (*top & PROCESS_AND) { /* #7 */ 553 update_preds(prog, N - 1, invert); 554 *top &= ~PROCESS_AND; 555 } 556 if (*next == '&') { /* #8 */ 557 *top |= PROCESS_AND; 558 break; 559 } 560 if (*top & PROCESS_OR) { /* #9 */ 561 update_preds(prog, N - 1, !invert); 562 *top &= ~PROCESS_OR; 563 } 564 if (*next == '|') { /* #10 */ 565 *top |= PROCESS_OR; 566 break; 567 } 568 if (!*next) /* #11 */ 569 goto out; 570 571 if (top == op_stack) { 572 ret = -1; 573 /* Too few '(' */ 574 parse_error(pe, FILT_ERR_TOO_MANY_CLOSE, ptr - str); 575 goto out_free; 576 } 577 top--; /* #12 */ 578 } 579 } 580 out: 581 if (top != op_stack) { 582 /* Too many '(' */ 583 parse_error(pe, FILT_ERR_TOO_MANY_OPEN, ptr - str); 584 goto out_free; 585 } 586 587 if (!N) { 588 /* No program? */ 589 ret = -EINVAL; 590 parse_error(pe, FILT_ERR_NO_FILTER, ptr - str); 591 goto out_free; 592 } 593 594 prog[N].pred = NULL; /* #13 */ 595 prog[N].target = 1; /* TRUE */ 596 prog[N+1].pred = NULL; 597 prog[N+1].target = 0; /* FALSE */ 598 prog[N-1].target = N; 599 prog[N-1].when_to_branch = false; 600 601 /* Second Pass */ 602 for (i = N-1 ; i--; ) { 603 int target = prog[i].target; 604 if (prog[i].when_to_branch == prog[target].when_to_branch) 605 prog[i].target = prog[target].target; 606 } 607 608 /* Third Pass */ 609 for (i = 0; i < N; i++) { 610 invert = inverts[i] ^ prog[i].when_to_branch; 611 prog[i].when_to_branch = invert; 612 /* Make sure the program always moves forward */ 613 if (WARN_ON(prog[i].target <= i)) { 614 ret = -EINVAL; 615 goto out_free; 616 } 617 } 618 619 kfree(op_stack); 620 kfree(inverts); 621 return prog; 622 out_free: 623 kfree(op_stack); 624 kfree(inverts); 625 if (prog_stack) { 626 for (i = 0; prog_stack[i].pred; i++) { 627 if (prog_stack[i].pred->fn_num == FILTER_PRED_FN_MEMCMP) > 628 kfree((u8 *)prog_stack[i].pred->val); 629 kfree(prog_stack[i].pred); 630 } 631 kfree(prog_stack); 632 } 633 return ERR_PTR(ret); 634 } 635
Hi Alan, kernel test robot noticed the following build warnings: [auto build test WARNING on linus/master] [also build test WARNING on v6.3 next-20230427] [cannot apply to rostedt-trace/for-next rostedt-trace/for-next-urgent] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Alan-Maguire/tracing-support-8-byte-array-filter-predicates/20230425-171832 base: linus/master patch link: https://lore.kernel.org/r/1682414197-13173-2-git-send-email-alan.maguire%40oracle.com patch subject: [PATCH tracing 1/3] tracing: support > 8 byte array filter predicates config: mips-randconfig-s053-20230427 (https://download.01.org/0day-ci/archive/20230428/202304280925.9oX4NgJI-lkp@intel.com/config) compiler: mipsel-linux-gcc (GCC) 12.1.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-39-gce1a6720-dirty # https://github.com/intel-lab-lkp/linux/commit/d49d8291984dc5ac8933ff406c9f5e56ebbdd4e7 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Alan-Maguire/tracing-support-8-byte-array-filter-predicates/20230425-171832 git checkout d49d8291984dc5ac8933ff406c9f5e56ebbdd4e7 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips SHELL=/bin/bash arch/mips/dec/ kernel/trace/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304280925.9oX4NgJI-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> kernel/trace/trace_events_filter.c:628:55: sparse: sparse: non size-preserving integer to pointer cast kernel/trace/trace_events_filter.c:900:26: sparse: sparse: non size-preserving integer to pointer cast kernel/trace/trace_events_filter.c:1146:20: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected struct event_filter * @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1146:20: sparse: expected struct event_filter * kernel/trace/trace_events_filter.c:1146:20: sparse: got struct event_filter [noderef] __rcu *filter kernel/trace/trace_events_filter.c:1216:34: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct event_filter *filter @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1216:34: sparse: expected struct event_filter *filter kernel/trace/trace_events_filter.c:1216:34: sparse: got struct event_filter [noderef] __rcu *filter kernel/trace/trace_events_filter.c:1233:27: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct event_filter *filter @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1233:27: sparse: expected struct event_filter *filter kernel/trace/trace_events_filter.c:1233:27: sparse: got struct event_filter [noderef] __rcu *filter >> kernel/trace/trace_events_filter.c:1682:34: sparse: sparse: non size-preserving pointer to integer cast kernel/trace/trace_events_filter.c:1146:20: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected struct event_filter * @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1146:20: sparse: expected struct event_filter * kernel/trace/trace_events_filter.c:1146:20: sparse: got struct event_filter [noderef] __rcu *filter kernel/trace/trace_events_filter.c:1146:20: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected struct event_filter * @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1146:20: sparse: expected struct event_filter * kernel/trace/trace_events_filter.c:1146:20: sparse: got struct event_filter [noderef] __rcu *filter kernel/trace/trace_events_filter.c:1146:20: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected struct event_filter * @@ got struct event_filter [noderef] __rcu *filter @@ kernel/trace/trace_events_filter.c:1146:20: sparse: expected struct event_filter * kernel/trace/trace_events_filter.c:1146:20: sparse: got struct event_filter [noderef] __rcu *filter vim +628 kernel/trace/trace_events_filter.c 189 190 /* 191 * Without going into a formal proof, this explains the method that is used in 192 * parsing the logical expressions. 193 * 194 * For example, if we have: "a && !(!b || (c && g)) || d || e && !f" 195 * The first pass will convert it into the following program: 196 * 197 * n1: r=a; l1: if (!r) goto l4; 198 * n2: r=b; l2: if (!r) goto l4; 199 * n3: r=c; r=!r; l3: if (r) goto l4; 200 * n4: r=g; r=!r; l4: if (r) goto l5; 201 * n5: r=d; l5: if (r) goto T 202 * n6: r=e; l6: if (!r) goto l7; 203 * n7: r=f; r=!r; l7: if (!r) goto F 204 * T: return TRUE 205 * F: return FALSE 206 * 207 * To do this, we use a data structure to represent each of the above 208 * predicate and conditions that has: 209 * 210 * predicate, when_to_branch, invert, target 211 * 212 * The "predicate" will hold the function to determine the result "r". 213 * The "when_to_branch" denotes what "r" should be if a branch is to be taken 214 * "&&" would contain "!r" or (0) and "||" would contain "r" or (1). 215 * The "invert" holds whether the value should be reversed before testing. 216 * The "target" contains the label "l#" to jump to. 217 * 218 * A stack is created to hold values when parentheses are used. 219 * 220 * To simplify the logic, the labels will start at 0 and not 1. 221 * 222 * The possible invert values are 1 and 0. The number of "!"s that are in scope 223 * before the predicate determines the invert value, if the number is odd then 224 * the invert value is 1 and 0 otherwise. This means the invert value only 225 * needs to be toggled when a new "!" is introduced compared to what is stored 226 * on the stack, where parentheses were used. 227 * 228 * The top of the stack and "invert" are initialized to zero. 229 * 230 * ** FIRST PASS ** 231 * 232 * #1 A loop through all the tokens is done: 233 * 234 * #2 If the token is an "(", the stack is push, and the current stack value 235 * gets the current invert value, and the loop continues to the next token. 236 * The top of the stack saves the "invert" value to keep track of what 237 * the current inversion is. As "!(a && !b || c)" would require all 238 * predicates being affected separately by the "!" before the parentheses. 239 * And that would end up being equivalent to "(!a || b) && !c" 240 * 241 * #3 If the token is an "!", the current "invert" value gets inverted, and 242 * the loop continues. Note, if the next token is a predicate, then 243 * this "invert" value is only valid for the current program entry, 244 * and does not affect other predicates later on. 245 * 246 * The only other acceptable token is the predicate string. 247 * 248 * #4 A new entry into the program is added saving: the predicate and the 249 * current value of "invert". The target is currently assigned to the 250 * previous program index (this will not be its final value). 251 * 252 * #5 We now enter another loop and look at the next token. The only valid 253 * tokens are ")", "&&", "||" or end of the input string "\0". 254 * 255 * #6 The invert variable is reset to the current value saved on the top of 256 * the stack. 257 * 258 * #7 The top of the stack holds not only the current invert value, but also 259 * if a "&&" or "||" needs to be processed. Note, the "&&" takes higher 260 * precedence than "||". That is "a && b || c && d" is equivalent to 261 * "(a && b) || (c && d)". Thus the first thing to do is to see if "&&" needs 262 * to be processed. This is the case if an "&&" was the last token. If it was 263 * then we call update_preds(). This takes the program, the current index in 264 * the program, and the current value of "invert". More will be described 265 * below about this function. 266 * 267 * #8 If the next token is "&&" then we set a flag in the top of the stack 268 * that denotes that "&&" needs to be processed, break out of this loop 269 * and continue with the outer loop. 270 * 271 * #9 Otherwise, if a "||" needs to be processed then update_preds() is called. 272 * This is called with the program, the current index in the program, but 273 * this time with an inverted value of "invert" (that is !invert). This is 274 * because the value taken will become the "when_to_branch" value of the 275 * program. 276 * Note, this is called when the next token is not an "&&". As stated before, 277 * "&&" takes higher precedence, and "||" should not be processed yet if the 278 * next logical operation is "&&". 279 * 280 * #10 If the next token is "||" then we set a flag in the top of the stack 281 * that denotes that "||" needs to be processed, break out of this loop 282 * and continue with the outer loop. 283 * 284 * #11 If this is the end of the input string "\0" then we break out of both 285 * loops. 286 * 287 * #12 Otherwise, the next token is ")", where we pop the stack and continue 288 * this inner loop. 289 * 290 * Now to discuss the update_pred() function, as that is key to the setting up 291 * of the program. Remember the "target" of the program is initialized to the 292 * previous index and not the "l" label. The target holds the index into the 293 * program that gets affected by the operand. Thus if we have something like 294 * "a || b && c", when we process "a" the target will be "-1" (undefined). 295 * When we process "b", its target is "0", which is the index of "a", as that's 296 * the predicate that is affected by "||". But because the next token after "b" 297 * is "&&" we don't call update_preds(). Instead continue to "c". As the 298 * next token after "c" is not "&&" but the end of input, we first process the 299 * "&&" by calling update_preds() for the "&&" then we process the "||" by 300 * calling updates_preds() with the values for processing "||". 301 * 302 * What does that mean? What update_preds() does is to first save the "target" 303 * of the program entry indexed by the current program entry's "target" 304 * (remember the "target" is initialized to previous program entry), and then 305 * sets that "target" to the current index which represents the label "l#". 306 * That entry's "when_to_branch" is set to the value passed in (the "invert" 307 * or "!invert"). Then it sets the current program entry's target to the saved 308 * "target" value (the old value of the program that had its "target" updated 309 * to the label). 310 * 311 * Looking back at "a || b && c", we have the following steps: 312 * "a" - prog[0] = { "a", X, -1 } // pred, when_to_branch, target 313 * "||" - flag that we need to process "||"; continue outer loop 314 * "b" - prog[1] = { "b", X, 0 } 315 * "&&" - flag that we need to process "&&"; continue outer loop 316 * (Notice we did not process "||") 317 * "c" - prog[2] = { "c", X, 1 } 318 * update_preds(prog, 2, 0); // invert = 0 as we are processing "&&" 319 * t = prog[2].target; // t = 1 320 * s = prog[t].target; // s = 0 321 * prog[t].target = 2; // Set target to "l2" 322 * prog[t].when_to_branch = 0; 323 * prog[2].target = s; 324 * update_preds(prog, 2, 1); // invert = 1 as we are now processing "||" 325 * t = prog[2].target; // t = 0 326 * s = prog[t].target; // s = -1 327 * prog[t].target = 2; // Set target to "l2" 328 * prog[t].when_to_branch = 1; 329 * prog[2].target = s; 330 * 331 * #13 Which brings us to the final step of the first pass, which is to set 332 * the last program entry's when_to_branch and target, which will be 333 * when_to_branch = 0; target = N; ( the label after the program entry after 334 * the last program entry processed above). 335 * 336 * If we denote "TRUE" to be the entry after the last program entry processed, 337 * and "FALSE" the program entry after that, we are now done with the first 338 * pass. 339 * 340 * Making the above "a || b && c" have a program of: 341 * prog[0] = { "a", 1, 2 } 342 * prog[1] = { "b", 0, 2 } 343 * prog[2] = { "c", 0, 3 } 344 * 345 * Which translates into: 346 * n0: r = a; l0: if (r) goto l2; 347 * n1: r = b; l1: if (!r) goto l2; 348 * n2: r = c; l2: if (!r) goto l3; // Which is the same as "goto F;" 349 * T: return TRUE; l3: 350 * F: return FALSE 351 * 352 * Although, after the first pass, the program is correct, it is 353 * inefficient. The simple sample of "a || b && c" could be easily been 354 * converted into: 355 * n0: r = a; if (r) goto T 356 * n1: r = b; if (!r) goto F 357 * n2: r = c; if (!r) goto F 358 * T: return TRUE; 359 * F: return FALSE; 360 * 361 * The First Pass is over the input string. The next too passes are over 362 * the program itself. 363 * 364 * ** SECOND PASS ** 365 * 366 * Which brings us to the second pass. If a jump to a label has the 367 * same condition as that label, it can instead jump to its target. 368 * The original example of "a && !(!b || (c && g)) || d || e && !f" 369 * where the first pass gives us: 370 * 371 * n1: r=a; l1: if (!r) goto l4; 372 * n2: r=b; l2: if (!r) goto l4; 373 * n3: r=c; r=!r; l3: if (r) goto l4; 374 * n4: r=g; r=!r; l4: if (r) goto l5; 375 * n5: r=d; l5: if (r) goto T 376 * n6: r=e; l6: if (!r) goto l7; 377 * n7: r=f; r=!r; l7: if (!r) goto F: 378 * T: return TRUE; 379 * F: return FALSE 380 * 381 * We can see that "l3: if (r) goto l4;" and at l4, we have "if (r) goto l5;". 382 * And "l5: if (r) goto T", we could optimize this by converting l3 and l4 383 * to go directly to T. To accomplish this, we start from the last 384 * entry in the program and work our way back. If the target of the entry 385 * has the same "when_to_branch" then we could use that entry's target. 386 * Doing this, the above would end up as: 387 * 388 * n1: r=a; l1: if (!r) goto l4; 389 * n2: r=b; l2: if (!r) goto l4; 390 * n3: r=c; r=!r; l3: if (r) goto T; 391 * n4: r=g; r=!r; l4: if (r) goto T; 392 * n5: r=d; l5: if (r) goto T; 393 * n6: r=e; l6: if (!r) goto F; 394 * n7: r=f; r=!r; l7: if (!r) goto F; 395 * T: return TRUE 396 * F: return FALSE 397 * 398 * In that same pass, if the "when_to_branch" doesn't match, we can simply 399 * go to the program entry after the label. That is, "l2: if (!r) goto l4;" 400 * where "l4: if (r) goto T;", then we can convert l2 to be: 401 * "l2: if (!r) goto n5;". 402 * 403 * This will have the second pass give us: 404 * n1: r=a; l1: if (!r) goto n5; 405 * n2: r=b; l2: if (!r) goto n5; 406 * n3: r=c; r=!r; l3: if (r) goto T; 407 * n4: r=g; r=!r; l4: if (r) goto T; 408 * n5: r=d; l5: if (r) goto T 409 * n6: r=e; l6: if (!r) goto F; 410 * n7: r=f; r=!r; l7: if (!r) goto F 411 * T: return TRUE 412 * F: return FALSE 413 * 414 * Notice, all the "l#" labels are no longer used, and they can now 415 * be discarded. 416 * 417 * ** THIRD PASS ** 418 * 419 * For the third pass we deal with the inverts. As they simply just 420 * make the "when_to_branch" get inverted, a simple loop over the 421 * program to that does: "when_to_branch ^= invert;" will do the 422 * job, leaving us with: 423 * n1: r=a; if (!r) goto n5; 424 * n2: r=b; if (!r) goto n5; 425 * n3: r=c: if (!r) goto T; 426 * n4: r=g; if (!r) goto T; 427 * n5: r=d; if (r) goto T 428 * n6: r=e; if (!r) goto F; 429 * n7: r=f; if (r) goto F 430 * T: return TRUE 431 * F: return FALSE 432 * 433 * As "r = a; if (!r) goto n5;" is obviously the same as 434 * "if (!a) goto n5;" without doing anything we can interpret the 435 * program as: 436 * n1: if (!a) goto n5; 437 * n2: if (!b) goto n5; 438 * n3: if (!c) goto T; 439 * n4: if (!g) goto T; 440 * n5: if (d) goto T 441 * n6: if (!e) goto F; 442 * n7: if (f) goto F 443 * T: return TRUE 444 * F: return FALSE 445 * 446 * Since the inverts are discarded at the end, there's no reason to store 447 * them in the program array (and waste memory). A separate array to hold 448 * the inverts is used and freed at the end. 449 */ 450 static struct prog_entry * 451 predicate_parse(const char *str, int nr_parens, int nr_preds, 452 parse_pred_fn parse_pred, void *data, 453 struct filter_parse_error *pe) 454 { 455 struct prog_entry *prog_stack; 456 struct prog_entry *prog; 457 const char *ptr = str; 458 char *inverts = NULL; 459 int *op_stack; 460 int *top; 461 int invert = 0; 462 int ret = -ENOMEM; 463 int len; 464 int N = 0; 465 int i; 466 467 nr_preds += 2; /* For TRUE and FALSE */ 468 469 op_stack = kmalloc_array(nr_parens, sizeof(*op_stack), GFP_KERNEL); 470 if (!op_stack) 471 return ERR_PTR(-ENOMEM); 472 prog_stack = kcalloc(nr_preds, sizeof(*prog_stack), GFP_KERNEL); 473 if (!prog_stack) { 474 parse_error(pe, -ENOMEM, 0); 475 goto out_free; 476 } 477 inverts = kmalloc_array(nr_preds, sizeof(*inverts), GFP_KERNEL); 478 if (!inverts) { 479 parse_error(pe, -ENOMEM, 0); 480 goto out_free; 481 } 482 483 top = op_stack; 484 prog = prog_stack; 485 *top = 0; 486 487 /* First pass */ 488 while (*ptr) { /* #1 */ 489 const char *next = ptr++; 490 491 if (isspace(*next)) 492 continue; 493 494 switch (*next) { 495 case '(': /* #2 */ 496 if (top - op_stack > nr_parens) { 497 ret = -EINVAL; 498 goto out_free; 499 } 500 *(++top) = invert; 501 continue; 502 case '!': /* #3 */ 503 if (!is_not(next)) 504 break; 505 invert = !invert; 506 continue; 507 } 508 509 if (N >= nr_preds) { 510 parse_error(pe, FILT_ERR_TOO_MANY_PREDS, next - str); 511 goto out_free; 512 } 513 514 inverts[N] = invert; /* #4 */ 515 prog[N].target = N-1; 516 517 len = parse_pred(next, data, ptr - str, pe, &prog[N].pred); 518 if (len < 0) { 519 ret = len; 520 goto out_free; 521 } 522 ptr = next + len; 523 524 N++; 525 526 ret = -1; 527 while (1) { /* #5 */ 528 next = ptr++; 529 if (isspace(*next)) 530 continue; 531 532 switch (*next) { 533 case ')': 534 case '\0': 535 break; 536 case '&': 537 case '|': 538 /* accepting only "&&" or "||" */ 539 if (next[1] == next[0]) { 540 ptr++; 541 break; 542 } 543 fallthrough; 544 default: 545 parse_error(pe, FILT_ERR_TOO_MANY_PREDS, 546 next - str); 547 goto out_free; 548 } 549 550 invert = *top & INVERT; 551 552 if (*top & PROCESS_AND) { /* #7 */ 553 update_preds(prog, N - 1, invert); 554 *top &= ~PROCESS_AND; 555 } 556 if (*next == '&') { /* #8 */ 557 *top |= PROCESS_AND; 558 break; 559 } 560 if (*top & PROCESS_OR) { /* #9 */ 561 update_preds(prog, N - 1, !invert); 562 *top &= ~PROCESS_OR; 563 } 564 if (*next == '|') { /* #10 */ 565 *top |= PROCESS_OR; 566 break; 567 } 568 if (!*next) /* #11 */ 569 goto out; 570 571 if (top == op_stack) { 572 ret = -1; 573 /* Too few '(' */ 574 parse_error(pe, FILT_ERR_TOO_MANY_CLOSE, ptr - str); 575 goto out_free; 576 } 577 top--; /* #12 */ 578 } 579 } 580 out: 581 if (top != op_stack) { 582 /* Too many '(' */ 583 parse_error(pe, FILT_ERR_TOO_MANY_OPEN, ptr - str); 584 goto out_free; 585 } 586 587 if (!N) { 588 /* No program? */ 589 ret = -EINVAL; 590 parse_error(pe, FILT_ERR_NO_FILTER, ptr - str); 591 goto out_free; 592 } 593 594 prog[N].pred = NULL; /* #13 */ 595 prog[N].target = 1; /* TRUE */ 596 prog[N+1].pred = NULL; 597 prog[N+1].target = 0; /* FALSE */ 598 prog[N-1].target = N; 599 prog[N-1].when_to_branch = false; 600 601 /* Second Pass */ 602 for (i = N-1 ; i--; ) { 603 int target = prog[i].target; 604 if (prog[i].when_to_branch == prog[target].when_to_branch) 605 prog[i].target = prog[target].target; 606 } 607 608 /* Third Pass */ 609 for (i = 0; i < N; i++) { 610 invert = inverts[i] ^ prog[i].when_to_branch; 611 prog[i].when_to_branch = invert; 612 /* Make sure the program always moves forward */ 613 if (WARN_ON(prog[i].target <= i)) { 614 ret = -EINVAL; 615 goto out_free; 616 } 617 } 618 619 kfree(op_stack); 620 kfree(inverts); 621 return prog; 622 out_free: 623 kfree(op_stack); 624 kfree(inverts); 625 if (prog_stack) { 626 for (i = 0; prog_stack[i].pred; i++) { 627 if (prog_stack[i].pred->fn_num == FILTER_PRED_FN_MEMCMP) > 628 kfree((u8 *)prog_stack[i].pred->val); 629 kfree(prog_stack[i].pred); 630 } 631 kfree(prog_stack); 632 } 633 return ERR_PTR(ret); 634 } 635
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 1dad64267878..4f4f53b7302d 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -67,6 +67,7 @@ enum filter_pred_fn { FILTER_PRED_FN_FUNCTION, FILTER_PRED_FN_, FILTER_PRED_TEST_VISITED, + FILTER_PRED_FN_MEMCMP, }; struct filter_pred { @@ -622,8 +623,11 @@ predicate_parse(const char *str, int nr_parens, int nr_preds, kfree(op_stack); kfree(inverts); if (prog_stack) { - for (i = 0; prog_stack[i].pred; i++) + for (i = 0; prog_stack[i].pred; i++) { + if (prog_stack[i].pred->fn_num == FILTER_PRED_FN_MEMCMP) + kfree((u8 *)prog_stack[i].pred->val); kfree(prog_stack[i].pred); + } kfree(prog_stack); } return ERR_PTR(ret); @@ -890,6 +894,14 @@ static int filter_pred_function(struct filter_pred *pred, void *event) return pred->op == OP_EQ ? ret : !ret; } +static int filter_pred_memcmp(struct filter_pred *pred, void *event) +{ + u8 *mem = (u8 *)(event + pred->offset); + u8 *cmp = (u8 *)(pred->val); + + return (memcmp(mem, cmp, pred->field->size) == 0) ^ pred->not; +} + /* * regex_match_foo - Basic regex callbacks * @@ -1353,6 +1365,8 @@ static int filter_pred_fn_call(struct filter_pred *pred, void *event) return filter_pred_function(pred, event); case FILTER_PRED_TEST_VISITED: return test_pred_visited_fn(pred, event); + case FILTER_PRED_FN_MEMCMP: + return filter_pred_memcmp(pred, event); default: return 0; } @@ -1631,6 +1645,45 @@ static int parse_pred(const char *str, void *data, /* go past the last quote */ i++; + } else if (str[i] == '0' && tolower(str[i + 1]) == 'x' && + field->size > 8) { + u8 *pred_val; + + /* For sizes > 8 bytes, we store a binary representation + * for comparison; only '==' and '!=' are supported. + * To keep things simple, the predicate value must specify + * a value that matches the field size exactly, with leading + * 0s if necessary. + */ + if (pred->op != OP_EQ && pred->op != OP_NE) { + parse_error(pe, FILT_ERR_ILLEGAL_FIELD_OP, pos + i); + goto err_free; + } + + /* skip required 0x */ + s += 2; + i += 2; + + while (isalnum(str[i])) + i++; + + len = i - s; + if (len != (field->size * 2)) { + parse_error(pe, FILT_ERR_ILLEGAL_FIELD_OP, pos + s); + goto err_free; + } + + pred_val = kzalloc(field->size, GFP_KERNEL); + if (hex2bin(pred_val, str + s, field->size)) { + parse_error(pe, FILT_ERR_ILLEGAL_INTVAL, pos + s); + kfree(pred_val); + goto err_free; + } + pred->val = (u64)pred_val; + pred->fn_num = FILTER_PRED_FN_MEMCMP; + if (pred->op == OP_NE) + pred->not = 1; + } else if (isdigit(str[i]) || str[i] == '-') { /* Make sure the field is not a string */