From nobody Sat Jul 25 20:46:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C199357D09; Tue, 14 Jul 2026 01:09:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991381; cv=none; b=dXPDLtj3lduTg+5HYrS0a0vTJrjAi+CgkYvyHc2ggw0h2NOqlbNa2EG3RyjrANWPWnDvvVud1udaEqlCHk+/Wc+5mcy4bzVqVeK8lssm6qkelOeSO1imucfXg+t1THSsW96xDVsjfiVM8oXsB/XTmRoXRaYrqvFLPxXJ70vSEP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991381; c=relaxed/simple; bh=aAWxbpBiZPGebHF9stH6l/gs8j+Os4yg4PXoWGQhY58=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GWgPVu9QeESOsHI8KvyvJPKhocV5POgcLoHcvg04kec39q3yJs4iCR8O7Jq4qdbxOU1KZTOG/qiQ5I7ns1n31XnAL+bFqdyp/Bac8iP38+1XbVC9ye/Qc9FMQwK718+m/FJ3Fhdadzoo75EM6plHUg62Df16sg4zGQWnzhGxWVE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=B5ZyEBNb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="B5ZyEBNb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 60A061F000E9; Tue, 14 Jul 2026 01:09:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783991380; bh=+OT/874fdAI7aXO7+JscTbts10vAI7o7zqy5+UWPWEI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=B5ZyEBNbYUoBhd+S9byIpFztrUD79Ilvo1gu99f5q8HIPmTzR7ytXH1w4HCjIQMMV K8ThaX4b47rikaVdan2ohWut+uik1e9B56BJciVFRvhD+AcLMT0Y56THmwGV5u/YOj DhL4Pdk8oKNEZ6IuEaIYH3qAoZ1jgqsT3C/VOwmoD5e5NsCXwjBhsBPBxclKPBN+CP WNESX7/Wns9txdw0qS6h/aoi8yV69XFbuBTGDsZmez+m84sRcLM8cRPvQsWyY/VJaz OLdHBOD+z71xokUTFa85dFOvYZ6nlpYtNNzkVaMGSHr0/VhTi/HpJcN6+U+a4pmzTh wKY4c7+df8jqQ== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Masami Hiramatsu , Shuah Khan Cc: Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 1/5] tracing/probes: Refactor parse_probe_vars() Date: Tue, 14 Jul 2026 10:09:36 +0900 Message-ID: <178399137612.27810.14869178899276413372.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178399136606.27810.4469135881050354189.stgit@devnote2> References: <178399136606.27810.4469135881050354189.stgit@devnote2> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu Decompose parse_probe_vars() by extracting retval, stack, current task struct, and function argument parsing logic into dedicated static helper functions (parse_probe_var_retval, parse_probe_var_stack, parse_probe_var_current, and parse_probe_var_arg). This simplifies parse_probe_vars() and improves its readability. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- Changes in v2: - Fix double error logging by removing err code passing, but just record errors inside subfunctions. - Simplify parse_probe_vars(). --- kernel/trace/trace_probe.c | 237 ++++++++++++++++++++++++++--------------= ---- 1 file changed, 140 insertions(+), 97 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 18c212122344..8af97e29f096 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1319,132 +1319,175 @@ NOKPROBE_SYMBOL(store_trace_entry_data) =20 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) =20 -/* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */ -static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, - struct fetch_insn **pcode, - struct fetch_insn *end, - struct traceprobe_parse_context *ctx) +static int parse_probe_var_retval(char *orig_arg, char *arg, + struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) { struct fetch_insn *code =3D *pcode; - int err =3D TP_ERR_BAD_VAR; - char *arg =3D orig_arg + 1; + + if (!(ctx->flags & TPARG_FL_RETURN)) { + trace_probe_log_err(ctx->offset, RETVAL_ON_PROBE); + return -EINVAL; + } + if (!(ctx->flags & TPARG_FL_KERNEL) || + !IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) { + code->op =3D FETCH_OP_RETVAL; + return 0; + } + return parse_btf_arg(orig_arg, pcode, end, ctx); +} + +static int parse_probe_var_stack(char *arg, int len, struct fetch_insn *co= de, + struct traceprobe_parse_context *ctx) +{ unsigned long param; - int ret =3D 0; - int len; + int ret; =20 - if (ctx->flags & TPARG_FL_TEVENT) { - if (parse_trace_event(arg, code, ctx) < 0) { - /* 'comm' should be checked after field parsing. */ - if (strcmp(arg, "comm") =3D=3D 0 || strcmp(arg, "COMM") =3D=3D 0) { - code->op =3D FETCH_OP_COMM; - return 0; - } - goto inval; - } + if (arg[len] =3D=3D '\0') { + code->op =3D FETCH_OP_STACKP; return 0; } =20 - if (str_has_prefix(arg, "retval")) { - if (!(ctx->flags & TPARG_FL_RETURN)) { - err =3D TP_ERR_RETVAL_ON_PROBE; - goto inval; + if (isdigit(arg[len])) { + ret =3D kstrtoul(arg + len, 10, ¶m); + if (ret) { + trace_probe_log_err(ctx->offset, BAD_VAR); + return ret; } - if (!(ctx->flags & TPARG_FL_KERNEL) || - !IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) { - code->op =3D FETCH_OP_RETVAL; - return 0; + + if ((ctx->flags & TPARG_FL_KERNEL) && + param > PARAM_MAX_STACK) { + trace_probe_log_err(ctx->offset, BAD_STACK_NUM); + return -EINVAL; } + code->op =3D FETCH_OP_STACK; + code->param =3D (unsigned int)param; + return 0; + } + + trace_probe_log_err(ctx->offset, BAD_VAR); + return -EINVAL; +} + +static int parse_probe_var_current(char *orig_arg, char *arg, + struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ + struct fetch_insn *code =3D *pcode; + + /* $current is only supported by kernel probe. */ + if (!(ctx->flags & TPARG_FL_KERNEL)) { + trace_probe_log_err(ctx->offset, BAD_VAR); + return -EINVAL; + } + arg +=3D strlen("current"); + if (*arg =3D=3D '-' && IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) return parse_btf_arg(orig_arg, pcode, end, ctx); + + if (*arg !=3D '\0') { + trace_probe_log_err(ctx->offset, BAD_VAR); + return -EINVAL; } =20 - len =3D str_has_prefix(arg, "stack"); - if (len) { + code->op =3D FETCH_OP_CURRENT; + return 0; +} =20 - if (arg[len] =3D=3D '\0') { - code->op =3D FETCH_OP_STACKP; - return 0; - } +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API +static int parse_probe_var_arg(char *arg, int len, struct fetch_insn *code, + struct traceprobe_parse_context *ctx) +{ + unsigned long param; + int ret; =20 - if (isdigit(arg[len])) { - ret =3D kstrtoul(arg + len, 10, ¶m); - if (ret) - goto inval; + ret =3D kstrtoul(arg + len, 10, ¶m); + if (ret) { + trace_probe_log_err(ctx->offset, BAD_VAR); + return ret; + } =20 - if ((ctx->flags & TPARG_FL_KERNEL) && - param > PARAM_MAX_STACK) { - err =3D TP_ERR_BAD_STACK_NUM; - goto inval; - } - code->op =3D FETCH_OP_STACK; - code->param =3D (unsigned int)param; - return 0; - } - goto inval; + if (!param || param > PARAM_MAX_STACK) { + trace_probe_log_err(ctx->offset, BAD_ARG_NUM); + return -EINVAL; } + param--; /* argN starts from 1, but internal arg[N] starts from 0 */ =20 - if (strcmp(arg, "comm") =3D=3D 0 || strcmp(arg, "COMM") =3D=3D 0) { - code->op =3D FETCH_OP_COMM; - return 0; + if (tparg_is_function_entry(ctx->flags)) { + code->op =3D FETCH_OP_ARG; + code->param =3D (unsigned int)param; + /* + * The tracepoint probe will probe a stub function, and the + * first parameter of the stub is a dummy and should be ignored. + */ + if (ctx->flags & TPARG_FL_TPOINT) + code->param++; + } else if (tparg_is_function_return(ctx->flags)) { + /* function entry argument access from return probe */ + ret =3D __store_entry_arg(ctx->tp, param); + if (ret < 0) /* This error should be an internal error */ + return ret; + + code->op =3D FETCH_OP_EDATA; + code->offset =3D ret; + } else { + trace_probe_log_err(ctx->offset, NOFENTRY_ARGS); + return -EINVAL; } + return 0; +} +#else +static int parse_probe_var_arg(char *arg, int len, struct fetch_insn *code, + struct traceprobe_parse_context *ctx) +{ + trace_probe_log_err(ctx->offset, BAD_VAR); + return -EINVAL; +} +#endif =20 - /* $current returns the address of the current task_struct. */ - if (str_has_prefix(arg, "current")) { - /* $current is only supported by kernel probe. */ - if (!(ctx->flags & TPARG_FL_KERNEL)) { - err =3D TP_ERR_BAD_VAR; - goto inval; - } - arg +=3D strlen("current"); - if (*arg =3D=3D '-' && IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) - return parse_btf_arg(orig_arg, pcode, end, ctx); +/* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */ +static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, + struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ + struct fetch_insn *code =3D *pcode; + char *arg =3D orig_arg + 1; + int len, ret; =20 - if (*arg !=3D '\0') - goto inval; + if (ctx->flags & TPARG_FL_TEVENT) { + ret =3D parse_trace_event(arg, code, ctx); + if (!ret) + return 0; + } =20 - code->op =3D FETCH_OP_CURRENT; + if (strcmp(arg, "comm") =3D=3D 0 || strcmp(arg, "COMM") =3D=3D 0) { + code->op =3D FETCH_OP_COMM; return 0; } =20 -#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API - len =3D str_has_prefix(arg, "arg"); - if (len) { - ret =3D kstrtoul(arg + len, 10, ¶m); - if (ret) - goto inval; + /* eprobe only support event fields or '$comm'. */ + if (ctx->flags & TPARG_FL_TEVENT) + goto inval; =20 - if (!param || param > PARAM_MAX_STACK) { - err =3D TP_ERR_BAD_ARG_NUM; - goto inval; - } - param--; /* argN starts from 1, but internal arg[N] starts from 0 */ + if (str_has_prefix(arg, "retval")) + return parse_probe_var_retval(orig_arg, arg, pcode, end, ctx); =20 - if (tparg_is_function_entry(ctx->flags)) { - code->op =3D FETCH_OP_ARG; - code->param =3D (unsigned int)param; - /* - * The tracepoint probe will probe a stub function, and the - * first parameter of the stub is a dummy and should be ignored. - */ - if (ctx->flags & TPARG_FL_TPOINT) - code->param++; - } else if (tparg_is_function_return(ctx->flags)) { - /* function entry argument access from return probe */ - ret =3D __store_entry_arg(ctx->tp, param); - if (ret < 0) /* This error should be an internal error */ - return ret; + len =3D str_has_prefix(arg, "stack"); + if (len) + return parse_probe_var_stack(arg, len, code, ctx); =20 - code->op =3D FETCH_OP_EDATA; - code->offset =3D ret; - } else { - err =3D TP_ERR_NOFENTRY_ARGS; - goto inval; - } - return 0; - } -#endif + /* $current returns the address of the current task_struct. */ + if (str_has_prefix(arg, "current")) + return parse_probe_var_current(orig_arg, arg, pcode, end, ctx); + + len =3D str_has_prefix(arg, "arg"); + if (len) + return parse_probe_var_arg(arg, len, code, ctx); =20 inval: - __trace_probe_log_err(ctx->offset, err); + trace_probe_log_err(ctx->offset, BAD_VAR); return -EINVAL; } From nobody Sat Jul 25 20:46:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 28376357D18; Tue, 14 Jul 2026 01:09:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991391; cv=none; b=O16iim5Vosn+B4tCwrd7XouZx1gfi+DqtiTejmyVW6d/6Kc/UGRHS/8Qbj6gtvWtrFzuhGsuYwqY36auOooMhFmvubNM+hgpn2qytntWHykqNpyC0TlMkyy+XPNrnLT7s2F3e84vYlU1bIV62muVQGdhzWrRV5p+TjxVx+KMH58= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991391; c=relaxed/simple; bh=LE+AnQ24huGg63zUmwQarBgmLBHfJWh6PywE7q6APls=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=IlIF5c4auwToWghlhD6aTRzCEyBFV/T6NOToO5OoDf4mKx9GQ0UWROcUvu6Vute5ojK1QFeJroBFfvxpKngMlFrQtujErdvnUBGjo+iis715jbJQdj5+vRCfbiZRTvmVB6O/+MnQvP8FIK899fHklxMqyfpBBHW9opwnFVpCwcE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LS8LexvS; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LS8LexvS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E01ED1F000E9; Tue, 14 Jul 2026 01:09:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783991389; bh=6/heml6maRPFbbnCNFYbo/qzvnxE/Beejn0YYEkdEd0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=LS8LexvSzva2ww98xJ9xNKdJI4ok63uhlN+Zw1Hrvn197FYKToSsCegQJyZS5WZO4 rMNvkvLO68q7G7Lru4LR2cp0NvwSn3I6FAygqdtiIVjUPXfgO+DOTwfqIY8H9koTE/ htQo90lfEcgtEScWRaQq6TEpIJ9xVTFmozlWIbwTqmWKClizIPeoeUgi18js1YNW7U m9KRECiFloalKCyjNYFQU0QuVjPyZH4ZbczRU4RiZxfDE4YVAvUaWQ6t8+I7W1f87E UhuXbSfO6tpinw8m3FPh5sns/YAoVbZ++Nj/nXmA5RrgEB6cZ8ZMVRyGpGVLGiCT1S HW8XwDBQFE7wA== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Masami Hiramatsu , Shuah Khan Cc: Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 2/5] tracing/probes: Refactor parse_probe_arg() Date: Tue, 14 Jul 2026 10:09:45 +0900 Message-ID: <178399138581.27810.9471730417467607229.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178399136606.27810.4469135881050354189.stgit@devnote2> References: <178399136606.27810.4469135881050354189.stgit@devnote2> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu Decompose parse_probe_arg() by extracting register, memory/symbol, dereference, immediate, and default BTF/CPU parsing handlers into dedicated static helper functions (parse_probe_arg_register, parse_probe_arg_mem_symbol, parse_probe_arg_deref, parse_probe_arg_imm, and parse_probe_arg_default). This modularizes the recursive argument parser and improves readability. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- kernel/trace/trace_probe.c | 300 ++++++++++++++++++++++++++--------------= ---- 1 file changed, 174 insertions(+), 126 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8af97e29f096..eb9f7bd13c19 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1516,158 +1516,206 @@ static int __parse_imm_string(char *str, char **p= buf, int offs) return 0; } =20 -/* Recursive argument parser */ -static int -parse_probe_arg(char *arg, const struct fetch_type *type, - struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) +static int parse_probe_arg_register(char *arg, struct fetch_insn *code, + struct traceprobe_parse_context *ctx) +{ + int ret; + + if (ctx->flags & (TPARG_FL_TEVENT | TPARG_FL_FPROBE)) { + /* eprobe and fprobe do not handle registers */ + trace_probe_log_err(ctx->offset, BAD_VAR); + return -EINVAL; + } + ret =3D regs_query_register_offset(arg + 1); + if (ret >=3D 0) { + code->op =3D FETCH_OP_REG; + code->param =3D (unsigned int)ret; + return 0; + } + trace_probe_log_err(ctx->offset, BAD_REG_NAME); + return -EINVAL; +} + +static int parse_probe_arg_mem_symbol(char *arg, struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) { struct fetch_insn *code =3D *pcode; unsigned long param; + long offset =3D 0; + int ret; + + if (isdigit(arg[1])) { + ret =3D kstrtoul(arg + 1, 0, ¶m); + if (ret) { + trace_probe_log_err(ctx->offset, BAD_MEM_ADDR); + return ret; + } + /* load address */ + code->op =3D FETCH_OP_IMM; + code->immediate =3D param; + } else if (arg[1] =3D=3D '+') { + /* Kernel probes do not support file offsets */ + if (ctx->flags & TPARG_FL_KERNEL) { + trace_probe_log_err(ctx->offset, FILE_ON_KPROBE); + return -EINVAL; + } + ret =3D kstrtol(arg + 2, 0, &offset); + if (ret) { + trace_probe_log_err(ctx->offset, BAD_FILE_OFFS); + return ret; + } + + code->op =3D FETCH_OP_FOFFS; + code->immediate =3D (unsigned long)offset; + offset =3D 0; + } else { + /* uprobes don't support symbols */ + if (!(ctx->flags & TPARG_FL_KERNEL)) { + trace_probe_log_err(ctx->offset, SYM_ON_UPROBE); + return -EINVAL; + } + /* Preserve symbol for updating */ + code->op =3D FETCH_NOP_SYMBOL; + code->data =3D kstrdup(arg + 1, GFP_KERNEL); + if (!code->data) + return -ENOMEM; + if (++code =3D=3D end) { + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + return -EINVAL; + } + code->op =3D FETCH_OP_IMM; + code->immediate =3D 0; + } + /* These are fetching from memory */ + if (++code =3D=3D end) { + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + return -EINVAL; + } + *pcode =3D code; + code->op =3D FETCH_OP_DEREF; + code->offset =3D offset; + return 0; +} + +static int parse_probe_arg_deref(char *arg, struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ int deref =3D FETCH_OP_DEREF; long offset =3D 0; char *tmp; - int ret =3D 0; + int ret; =20 - switch (arg[0]) { - case '$': - ret =3D parse_probe_vars(arg, type, pcode, end, ctx); - break; + if (arg[1] =3D=3D 'u') { + deref =3D FETCH_OP_UDEREF; + arg[1] =3D arg[0]; + arg++; + } + if (arg[0] =3D=3D '+') + arg++; /* Skip '+', because kstrtol() rejects it. */ + tmp =3D strchr(arg, '('); + if (!tmp) { + trace_probe_log_err(ctx->offset, DEREF_NEED_BRACE); + return -EINVAL; + } + *tmp =3D '\0'; + ret =3D kstrtol(arg, 0, &offset); + if (ret) { + trace_probe_log_err(ctx->offset, BAD_DEREF_OFFS); + return ret; + } + ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); + arg =3D tmp + 1; + return handle_dereference(arg, pcode, end, ctx, deref, offset); +} =20 - case '%': /* named register */ - if (ctx->flags & (TPARG_FL_TEVENT | TPARG_FL_FPROBE)) { - /* eprobe and fprobe do not handle registers */ - trace_probe_log_err(ctx->offset, BAD_VAR); - break; +static int parse_probe_arg_imm(char *arg, struct fetch_insn *code, + struct traceprobe_parse_context *ctx) +{ + char *tmp; + int ret; + + if (arg[1] =3D=3D '"') { /* Immediate string */ + ret =3D __parse_imm_string(arg + 2, &tmp, ctx->offset + 2); + if (ret) + return ret; + code->op =3D FETCH_OP_IMMSTR; + code->data =3D tmp; + } else { + ret =3D str_to_immediate(arg + 1, &code->immediate); + if (ret) { + trace_probe_log_err(ctx->offset + 1, BAD_IMM); + return ret; } - ret =3D regs_query_register_offset(arg + 1); - if (ret >=3D 0) { - code->op =3D FETCH_OP_REG; - code->param =3D (unsigned int)ret; - ret =3D 0; - } else - trace_probe_log_err(ctx->offset, BAD_REG_NAME); - break; + code->op =3D FETCH_OP_IMM; + } + return 0; +} =20 - case '@': /* memory, file-offset or symbol */ - if (isdigit(arg[1])) { - ret =3D kstrtoul(arg + 1, 0, ¶m); - if (ret) { - trace_probe_log_err(ctx->offset, BAD_MEM_ADDR); - break; - } - /* load address */ - code->op =3D FETCH_OP_IMM; - code->immediate =3D param; - } else if (arg[1] =3D=3D '+') { - /* Kernel probes do not support file offsets */ - if (ctx->flags & TPARG_FL_KERNEL) { - trace_probe_log_err(ctx->offset, FILE_ON_KPROBE); - return -EINVAL; - } - ret =3D kstrtol(arg + 2, 0, &offset); - if (ret) { - trace_probe_log_err(ctx->offset, BAD_FILE_OFFS); - break; - } +static int parse_probe_arg_default(char *arg, struct fetch_insn **pcode, + struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ + int ret; =20 - code->op =3D FETCH_OP_FOFFS; - code->immediate =3D (unsigned long)offset; // imm64? - offset =3D 0; - } else { - /* uprobes don't support symbols */ - if (!(ctx->flags & TPARG_FL_KERNEL)) { - trace_probe_log_err(ctx->offset, SYM_ON_UPROBE); - return -EINVAL; - } - /* Preserve symbol for updating */ - code->op =3D FETCH_NOP_SYMBOL; - code->data =3D kstrdup(arg + 1, GFP_KERNEL); - if (!code->data) - return -ENOMEM; - if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + if (str_has_prefix(arg, THIS_CPU_PTR_PREFIX) || + str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { + return parse_this_cpu(arg, pcode, end, ctx); + } + + if (isalpha(arg[0]) || arg[0] =3D=3D '_') { + /* BTF variable or event field */ + if (ctx->flags & TPARG_FL_TEVENT) { + ret =3D parse_trace_event(arg, *pcode, ctx); + if (ret < 0) { + trace_probe_log_err(ctx->offset, NO_EVENT_FIELD); return -EINVAL; } - code->op =3D FETCH_OP_IMM; - code->immediate =3D 0; + return 0; } - /* These are fetching from memory */ - if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + if (!tparg_is_function_entry(ctx->flags) && + !tparg_is_function_return(ctx->flags)) { + trace_probe_log_err(ctx->offset, NOSUP_BTFARG); return -EINVAL; } - *pcode =3D code; - code->op =3D FETCH_OP_DEREF; - code->offset =3D offset; - break; + return parse_btf_arg(arg, pcode, end, ctx); + } =20 + return 0; +} + +/* Recursive argument parser */ +static int +parse_probe_arg(char *arg, const struct fetch_type *type, + struct fetch_insn **pcode, struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ + struct fetch_insn *code =3D *pcode; + int ret; + + switch (arg[0]) { + case '$': + ret =3D parse_probe_vars(arg, type, pcode, end, ctx); + break; + case '%': /* named register */ + ret =3D parse_probe_arg_register(arg, code, ctx); + break; + case '@': /* memory, file-offset or symbol */ + ret =3D parse_probe_arg_mem_symbol(arg, pcode, end, ctx); + break; case '+': /* deref memory */ case '-': - if (arg[1] =3D=3D 'u') { - deref =3D FETCH_OP_UDEREF; - arg[1] =3D arg[0]; - arg++; - } - if (arg[0] =3D=3D '+') - arg++; /* Skip '+', because kstrtol() rejects it. */ - tmp =3D strchr(arg, '('); - if (!tmp) { - trace_probe_log_err(ctx->offset, DEREF_NEED_BRACE); - return -EINVAL; - } - *tmp =3D '\0'; - ret =3D kstrtol(arg, 0, &offset); - if (ret) { - trace_probe_log_err(ctx->offset, BAD_DEREF_OFFS); - break; - } - ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); - arg =3D tmp + 1; - ret =3D handle_dereference(arg, pcode, end, ctx, deref, offset); - if (ret < 0) - return ret; + ret =3D parse_probe_arg_deref(arg, pcode, end, ctx); break; case '\\': /* Immediate value */ - if (arg[1] =3D=3D '"') { /* Immediate string */ - ret =3D __parse_imm_string(arg + 2, &tmp, ctx->offset + 2); - if (ret) - break; - code->op =3D FETCH_OP_IMMSTR; - code->data =3D tmp; - } else { - ret =3D str_to_immediate(arg + 1, &code->immediate); - if (ret) - trace_probe_log_err(ctx->offset + 1, BAD_IMM); - else - code->op =3D FETCH_OP_IMM; - } + ret =3D parse_probe_arg_imm(arg, code, ctx); break; case '(': ret =3D handle_typecast(arg, pcode, end, ctx); break; default: - if (str_has_prefix(arg, THIS_CPU_PTR_PREFIX) || - str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { - ret =3D parse_this_cpu(arg, pcode, end, ctx); - } else if (isalpha(arg[0]) || arg[0] =3D=3D '_') { - /* BTF variable or event field*/ - if (ctx->flags & TPARG_FL_TEVENT) { - ret =3D parse_trace_event(arg, *pcode, ctx); - if (ret < 0) { - trace_probe_log_err(ctx->offset, - NO_EVENT_FIELD); - return -EINVAL; - } - break; - } - if (!tparg_is_function_entry(ctx->flags) && - !tparg_is_function_return(ctx->flags)) { - trace_probe_log_err(ctx->offset, NOSUP_BTFARG); - return -EINVAL; - } - ret =3D parse_btf_arg(arg, pcode, end, ctx); - } + ret =3D parse_probe_arg_default(arg, pcode, end, ctx); break; } if (!ret && code->op =3D=3D FETCH_OP_NOP) { From nobody Sat Jul 25 20:46:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E2743596F8; Tue, 14 Jul 2026 01:09:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991400; cv=none; b=eUKNkFkLEuvCUImfuOjc8kHc3CC3AuyDwcoShLuLiKU621sONLJVOhqM5TlbIybiOfNUdkb1gvk6jp3cPaxo3cFvYRZu4wSwWAP1hdtWsffayRBl8whnhOyVYAPwBTZIBYkQ899fd2BcVaH4GCipHGAQenc9nn5jLEqEi7COilA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991400; c=relaxed/simple; bh=hqELA/fl1LAqzz8E8IRdPGy8XOdMNte2Dui+FJdM+aA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tyyL6WvZRaSj26sIV2iqZJZ71zlUSqgxtKOzRhllNOhNEsfgyMF5YOaQvVwUPecEBE5Ut6dl8mvTDGeLear61vE0zP91EyPi6lBtoOVattN1j25+xSIIUfxDFLlCrPaR5o3/whBKf72waUjdxSnhxnT6tRyEihYbUFCD5u2k8AM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OjPCW9Gt; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OjPCW9Gt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5326F1F000E9; Tue, 14 Jul 2026 01:09:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783991399; bh=ykkygFjoUseT4cJdY6LDUUSLsLeCSFMWe0Bi0JBfXDY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=OjPCW9GtL7QbYSzkHI380R/7m34a30LojS9b43U0wcoULZx6QXfl6lutksPT0VDkn qd8b5u96tq1bJFcQfrb70Sn489V9f3GXMDAm8JIHymPVgpgUE+dj6S7p0/fid9YLOj zL4deBogTXHjmQUoQARbGpdpOiOvqlibmfeGGmfqA5WDhYW+266ZGqNjvri/tCznmB oVOQcKqV5hMUcVwGFxf1NhTeq27/gNpAepv/iEgLwYuvhBjax17Lgh7T36NgtTrG2l Wna8OkZ9oT/yXw/oSMkAd9zmc5s0YrjdT30kKLM9hWMWlXEKXsQ/1lxvMgNHWPt5o7 RsB2IO67o85Gw== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Masami Hiramatsu , Shuah Khan Cc: Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 3/5] tracing/probes: Sort ERRORS list in trace_probe.h alphabetically Date: Tue, 14 Jul 2026 10:09:55 +0900 Message-ID: <178399139516.27810.14930549550788208142.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178399136606.27810.4469135881050354189.stgit@devnote2> References: <178399136606.27810.4469135881050354189.stgit@devnote2> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu Sort the C-macro ERRORS list alphabetically in trace_probe.h to make it easier to find and maintain error entries. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- kernel/trace/trace_probe.h | 160 ++++++++++++++++++++++------------------= ---- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index e6268a8dc378..e64e323244a5 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -512,95 +512,95 @@ extern int traceprobe_define_arg_fields(struct trace_= event_call *event_call, =20 #undef ERRORS #define ERRORS \ - C(FILE_NOT_FOUND, "Failed to find the given file"), \ - C(NO_REGULAR_FILE, "Not a regular file"), \ - C(BAD_REFCNT, "Invalid reference counter offset"), \ - C(REFCNT_OPEN_BRACE, "Reference counter brace is not closed"), \ - C(BAD_REFCNT_SUFFIX, "Reference counter has wrong suffix"), \ - C(BAD_UPROBE_OFFS, "Invalid uprobe offset"), \ - C(BAD_MAXACT_TYPE, "Maxactive is only for function exit"), \ - C(BAD_MAXACT, "Invalid maxactive number"), \ - C(MAXACT_TOO_BIG, "Maxactive is too big"), \ - C(BAD_PROBE_ADDR, "Invalid probed address or symbol"), \ - C(NON_UNIQ_SYMBOL, "The symbol is not unique"), \ - C(BAD_RETPROBE, "Retprobe address must be an function entry"), \ - C(NO_TRACEPOINT, "Tracepoint is not found"), \ - C(BAD_TP_NAME, "Invalid character in tracepoint name"),\ - C(BAD_ADDR_SUFFIX, "Invalid probed address suffix"), \ - C(NO_GROUP_NAME, "Group name is not specified"), \ - C(GROUP_TOO_LONG, "Group name is too long"), \ - C(BAD_GROUP_NAME, "Group name must follow the same rules as C identifiers= "), \ - C(NO_EVENT_NAME, "Event name is not specified"), \ - C(EVENT_TOO_LONG, "Event name is too long"), \ - C(BAD_EVENT_NAME, "Event name must follow the same rules as C identifiers= "), \ - C(EVENT_EXIST, "Given group/event name is already used by another event"= ), \ - C(RETVAL_ON_PROBE, "$retval is not available on probe"), \ - C(NO_RETVAL, "This function returns 'void' type"), \ - C(BAD_STACK_NUM, "Invalid stack number"), \ + C(ARGIDX_2BIG, "$argN index is too big"), \ + C(ARGS_2LONG, "$arg* failed because the argument list is too long"), \ + C(ARG_NAME_TOO_LONG, "Argument name is too long"), \ + C(ARG_TOO_LONG, "Argument expression is too long"), \ + C(ARRAY_NO_CLOSE, "Array is not closed"), \ + C(ARRAY_TOO_BIG, "Array number is too big"), \ + C(BAD_ADDR_SUFFIX, "Invalid probed address suffix"), \ + C(BAD_ARG_NAME, "Argument name must follow the same rules as C identifie= rs"), \ C(BAD_ARG_NUM, "Invalid argument number"), \ - C(BAD_VAR, "Invalid $-variable specified"), \ - C(BAD_REG_NAME, "Invalid register name"), \ - C(BAD_MEM_ADDR, "Invalid memory address"), \ - C(BAD_IMM, "Invalid immediate value"), \ - C(IMMSTR_NO_CLOSE, "String is not closed with '\"'"), \ - C(FILE_ON_KPROBE, "File offset is not available for kernel probes"), \ - C(BAD_FILE_OFFS, "Invalid file offset value"), \ - C(SYM_ON_UPROBE, "Symbol is not available with uprobe"), \ - C(TOO_MANY_OPS, "Dereference is too much nested"), \ - C(DEREF_NEED_BRACE, "Dereference needs a brace"), \ + C(BAD_ARRAY_NUM, "Invalid array size"), \ + C(BAD_ARRAY_SUFFIX, "Array has wrong suffix"), \ + C(BAD_ATTACH_ARG, "Attached event does not have this field"), \ + C(BAD_ATTACH_EVENT, "Attached event does not exist"), \ + C(BAD_BITFIELD, "Invalid bitfield"), \ + C(BAD_BTF_TID, "Failed to get BTF type info."), \ C(BAD_DEREF_OFFS, "Invalid dereference offset"), \ - C(DEREF_OPEN_BRACE, "Dereference brace is not closed"), \ - C(COMM_CANT_DEREF, "$comm can not be dereferenced"), \ + C(BAD_EVENT_NAME, "Event name must follow the same rules as C identifiers= "), \ C(BAD_FETCH_ARG, "Invalid fetch argument"), \ - C(ARRAY_NO_CLOSE, "Array is not closed"), \ - C(BAD_ARRAY_SUFFIX, "Array has wrong suffix"), \ - C(BAD_ARRAY_NUM, "Invalid array size"), \ - C(ARRAY_TOO_BIG, "Array number is too big"), \ - C(BAD_TYPE, "Unknown type is specified"), \ - C(BAD_STRING, "String accepts only memory argument"), \ + C(BAD_FILE_OFFS, "Invalid file offset value"), \ + C(BAD_GROUP_NAME, "Group name must follow the same rules as C identifiers= "), \ + C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \ + C(BAD_IMM, "Invalid immediate value"), \ + C(BAD_INSN_BNDRY, "Probe point is not an instruction boundary"), \ + C(BAD_MAXACT, "Invalid maxactive number"), \ + C(BAD_MAXACT_TYPE, "Maxactive is only for function exit"), \ + C(BAD_MEM_ADDR, "Invalid memory address"), \ + C(BAD_PROBE_ADDR, "Invalid probed address or symbol"), \ + C(BAD_REFCNT, "Invalid reference counter offset"), \ + C(BAD_REFCNT_SUFFIX, "Reference counter has wrong suffix"), \ + C(BAD_REG_NAME, "Invalid register name"), \ + C(BAD_RETPROBE, "Retprobe address must be an function entry"), \ + C(BAD_STACK_NUM, "Invalid stack number"), \ + C(BAD_STRING, "String accepts only memory argument"), \ C(BAD_SYMSTRING, "Symbol String doesn't accept data/userdata"), \ - C(BAD_BITFIELD, "Invalid bitfield"), \ - C(ARG_NAME_TOO_LONG, "Argument name is too long"), \ - C(NO_ARG_NAME, "Argument name is not specified"), \ - C(BAD_ARG_NAME, "Argument name must follow the same rules as C identifie= rs"), \ - C(USED_ARG_NAME, "This argument name is already used"), \ - C(ARG_TOO_LONG, "Argument expression is too long"), \ + C(BAD_TP_NAME, "Invalid character in tracepoint name"), \ + C(BAD_TYPE, "Unknown type is specified"), \ + C(BAD_TYPE4STR, "This type does not fit for string."), \ + C(BAD_UPROBE_OFFS, "Invalid uprobe offset"), \ + C(BAD_VAR, "Invalid $-variable specified"), \ + C(BAD_VAR_ARGS, "$arg* must be an independent parameter without name etc= ."), \ + C(COMM_CANT_DEREF, "$comm can not be dereferenced"), \ + C(DEREF_NEED_BRACE, "Dereference needs a brace"), \ + C(DEREF_OPEN_BRACE, "Dereference brace is not closed"), \ + C(DIFF_ARG_TYPE, "Argument type or name is different from existing probe"= ), \ + C(DIFF_PROBE_TYPE, "Probe type is different from existing probe"), \ + C(DOUBLE_ARGS, "$arg* can be used only once in the parameters"), \ + C(EVENT_EXIST, "Given group/event name is already used by another event"= ), \ + C(EVENT_TOO_BIG, "Event too big (too many fields?)"), \ + C(EVENT_TOO_LONG, "Event name is too long"), \ + C(FAIL_REG_PROBE, "Failed to register probe event"), \ + C(FILE_NOT_FOUND, "Failed to find the given file"), \ + C(FILE_ON_KPROBE, "File offset is not available for kernel probes"), \ + C(GROUP_TOO_LONG, "Group name is too long"), \ + C(IMMSTR_NO_CLOSE, "String is not closed with '\"'"), \ + C(MAXACT_TOO_BIG, "Maxactive is too big"), \ + C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"= ), \ + C(NOFENTRY_ARGS, "$arg* can be used only on function entry or exit"), \ + C(NON_UNIQ_SYMBOL, "The symbol is not unique"), \ + C(NOSUP_BTFARG, "BTF is not available or not supported"), \ + C(NOSUP_DAT_ARG, "Non pointer structure/union argument is not supported."= ), \ + C(NOSUP_PERCPU, "Per-cpu variable access is only for kernel probes"), \ C(NO_ARG_BODY, "No argument expression"), \ - C(BAD_INSN_BNDRY, "Probe point is not an instruction boundary"),\ - C(FAIL_REG_PROBE, "Failed to register probe event"),\ - C(DIFF_PROBE_TYPE, "Probe type is different from existing probe"),\ - C(DIFF_ARG_TYPE, "Argument type or name is different from existing probe"= ),\ - C(SAME_PROBE, "There is already the exact same probe event"),\ - C(NO_EVENT_INFO, "This requires both group and event name to attach"),\ - C(BAD_ATTACH_EVENT, "Attached event does not exist"),\ - C(BAD_ATTACH_ARG, "Attached event does not have this field"),\ + C(NO_ARG_NAME, "Argument name is not specified"), \ + C(NO_BTFARG, "This variable is not found at this probe point"), \ + C(NO_BTF_ENTRY, "No BTF entry for this probe point"), \ + C(NO_BTF_FIELD, "This field is not found."), \ C(NO_EP_FILTER, "No filter rule after 'if'"), \ - C(NOSUP_BTFARG, "BTF is not available or not supported"), \ - C(NO_BTFARG, "This variable is not found at this probe point"),\ - C(NO_BTF_ENTRY, "No BTF entry for this probe point"), \ - C(BAD_VAR_ARGS, "$arg* must be an independent parameter without name etc= ."),\ - C(NOFENTRY_ARGS, "$arg* can be used only on function entry or exit"), \ - C(DOUBLE_ARGS, "$arg* can be used only once in the parameters"), \ - C(ARGS_2LONG, "$arg* failed because the argument list is too long"), \ - C(ARGIDX_2BIG, "$argN index is too big"), \ + C(NO_EVENT_FIELD, "This event field is not found."), \ + C(NO_EVENT_INFO, "This requires both group and event name to attach"), \ + C(NO_EVENT_NAME, "Event name is not specified"), \ + C(NO_GROUP_NAME, "Group name is not specified"), \ C(NO_PTR_STRCT, "This is not a pointer to union/structure."), \ - C(NOSUP_DAT_ARG, "Non pointer structure/union argument is not supported."= ),\ - C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \ - C(NO_EVENT_FIELD, "This event field is not found."), \ - C(NO_BTF_FIELD, "This field is not found."), \ - C(BAD_BTF_TID, "Failed to get BTF type info."),\ - C(BAD_TYPE4STR, "This type does not fit for string."),\ - C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"= ),\ - C(TOO_MANY_ARGS, "Too many arguments are specified"), \ + C(NO_REGULAR_FILE, "Not a regular file"), \ + C(NO_RETVAL, "This function returns 'void' type"), \ + C(NO_TRACEPOINT, "Tracepoint is not found"), \ + C(REFCNT_OPEN_BRACE, "Reference counter brace is not closed"), \ + C(RETVAL_ON_PROBE, "$retval is not available on probe"), \ + C(SAME_PROBE, "There is already the exact same probe event"), \ + C(SYM_ON_UPROBE, "Symbol is not available with uprobe"), \ + C(TOO_MANY_ARGS, "Too many arguments are specified"), \ C(TOO_MANY_EARGS, "Too many entry arguments specified"), \ - C(EVENT_TOO_BIG, "Event too big (too many fields?)"), \ - C(TYPECAST_NOT_EVENT, "Typecasts are only for eprobe fields"), \ + C(TOO_MANY_NESTED, "Too many nested typecasts/dereferences"), \ + C(TOO_MANY_OPS, "Dereference is too much nested"), \ + C(TYPECAST_BAD_ARROW, "Typecast field option does not support -> operator= "), \ + C(TYPECAST_NOT_ALIGNED, "Typecast field option is not byte-aligned"), \ + C(TYPECAST_NOT_EVENT, "Typecasts are only for eprobe fields"), \ C(TYPECAST_REQ_FIELD, "Typecast requires a field access"), \ - C(TOO_MANY_NESTED, "Too many nested typecasts/dereferences"), \ - C(TYPECAST_SYM_OFFSET, "@SYM+/-OFFSET with typecast needs parentheses"), \ - C(TYPECAST_NOT_ALIGNED, "Typecast field option is not byte-aligned"), \ - C(TYPECAST_BAD_ARROW, "Typecast field option does not support -> operator= "), \ - C(NOSUP_PERCPU, "Per-cpu variable access is only for kernel probes"), + C(TYPECAST_SYM_OFFSET, "@SYM+/-OFFSET with typecast needs parentheses"), \ + C(USED_ARG_NAME, "This argument name is already used"), =20 #undef C #define C(a, b) TP_ERR_##a From nobody Sat Jul 25 20:46:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F11F83596F8; Tue, 14 Jul 2026 01:10:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991410; cv=none; b=i7Xtt5N4feyUaRUr86oR4s+Gl13koyWRgnKCNTUElvUToFGsQXBRR5QRMkdQ0Qh84aC2FHxM9Psykgo5xPZXikY2m0hGU95R4Iu2/3GyZzVOTItHO8iBj8567niexWoeHwb+irPWzoNsW4FYl9xXjBBrluFoQ4lB0nEtLLnIpa4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991410; c=relaxed/simple; bh=ANvE8llAdzDP9c8mDycRInCbne15+pbtq+cxKv+VHMc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nXrQWWAt4s6K4pR8DCGLj8gOcP71sg92EjpmiCDokQ24pIRDV701oMeKf+0WWeR2hIAqFSw64C+j7pyWDDUdLFDSZ5SnuRsJWuX2FagWFnGy9sUpUQA1fntJ59l5VdfCrd/OrE38mHaqbNBwm2gFxP8q6vdKlhPV2blxwOTt9e0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=j2eLtbla; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="j2eLtbla" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B9F691F000E9; Tue, 14 Jul 2026 01:10:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783991408; bh=Egqhsjf9ud4/qwjC3GdkEb3I7uHVjH2JTBx2h3IYAic=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=j2eLtblaybMmhkZix3Lc340P4azCBIEXvgOpRvzafZagnaJMhOl/9sdE+bF6XpdkQ kog0Q8GdGKq5YhbNJSWxEwGpZyctZbF0UyUlkCwy3qsoyb+ze6VpHVnXH/KKrwxbDx k36NPzWt/od2FkMmpn/L7wX+j/6FrZzuIkdFqQbM/oWWj572WJGFc+29ZoYUD5LBX+ BEd01hU4JgNiiOfCxojiXPZ1sUvGfP3VcxMA6GKuC2rCYpBHbkywKFE+J2q/Ohkw8h INPA+ujj/QevIJYRKFKzIfm5BjKHjCN7jJ7UU7YZ4fvsHWbmPOfXpOU5air5VrzUgT hePosdmMMnknQ== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Masami Hiramatsu , Shuah Khan Cc: Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 4/5] tracing/probes: Extend max length of argument string Date: Tue, 14 Jul 2026 10:10:04 +0900 Message-ID: <178399140457.27810.11387684872148824707.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178399136606.27810.4469135881050354189.stgit@devnote2> References: <178399136606.27810.4469135881050354189.stgit@devnote2> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu To support BTF argument parsing (such as accessing fields within nested structures via typecasting), the maximum argument string length needs to be extended. Extend MAX_ARGSTR_LEN from 63 to 255. Since MAX_ARGSTR_LEN was previously reused to format command heads in trace_*probe_match_command_head() functions, introduce a dedicated MAX_COMMON_HEAD_LEN (63) macro for matching command heads and switch these functions to use the new macro. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- Changes in v2: - Make the MAX_ARGSTR_LEN to 255 instead of 256. --- kernel/trace/trace_fprobe.c | 2 +- kernel/trace/trace_kprobe.c | 2 +- kernel/trace/trace_probe.h | 3 ++- kernel/trace/trace_uprobe.c | 2 +- .../ftrace/test.d/dynevent/fprobe_syntax_errors.tc | 2 +- .../ftrace/test.d/dynevent/tprobe_syntax_errors.tc | 2 +- .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc | 2 +- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c index 536781cd4c47..5638a90e61cc 100644 --- a/kernel/trace/trace_fprobe.c +++ b/kernel/trace/trace_fprobe.c @@ -238,7 +238,7 @@ static bool trace_fprobe_is_busy(struct dyn_event *ev) static bool trace_fprobe_match_command_head(struct trace_fprobe *tf, int argc, const char **argv) { - char buf[MAX_ARGSTR_LEN + 1]; + char buf[MAX_COMMON_HEAD_LEN + 1]; =20 if (!argc) return true; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index cfa807d8e760..cc24e992732c 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -149,7 +149,7 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev) static bool trace_kprobe_match_command_head(struct trace_kprobe *tk, int argc, const char **argv) { - char buf[MAX_ARGSTR_LEN + 1]; + char buf[MAX_COMMON_HEAD_LEN + 1]; =20 if (!argc) return true; diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index e64e323244a5..e6d427910c4f 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -32,7 +32,8 @@ #include "trace_output.h" =20 #define MAX_TRACE_ARGS 128 -#define MAX_ARGSTR_LEN 63 +#define MAX_ARGSTR_LEN 255 +#define MAX_COMMON_HEAD_LEN 63 #define MAX_ARRAY_LEN 64 #define MAX_ARG_NAME_LEN 32 #define MAX_BTF_ARGS_LEN 128 diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index b2e264a4b96c..67bd8fd91e3e 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -281,7 +281,7 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev) static bool trace_uprobe_match_command_head(struct trace_uprobe *tu, int argc, const char **argv) { - char buf[MAX_ARGSTR_LEN + 1]; + char buf[MAX_COMMON_HEAD_LEN + 1]; int len; =20 if (!argc) diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_e= rrors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_err= ors.tc index e9d7e6919c7f..984ab94df213 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc @@ -75,7 +75,7 @@ check_error 'f vfs_read ^arg12345678901234567890123456789= 0=3D@11' # ARG_NAME_TOO_L check_error 'f vfs_read ^=3D@11' # NO_ARG_NAME check_error 'f vfs_read ^var.1=3D@11' # BAD_ARG_NAME check_error 'f vfs_read var1=3D@11 ^var1=3D@12' # USED_ARG_NAME -check_error 'f vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+123= 4567(@1234))))))' # ARG_TOO_LONG +check_error 'f vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+123= 4567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+123456= 7(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+= 1234567(+1234567(+1234567(+1234567(@1234))))))))))))))))))))))))))' # ARG_T= OO_LONG check_error 'f vfs_read arg1=3D^' # NO_ARG_BODY =20 =20 diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_e= rrors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_err= ors.tc index ffe8ffef4027..2d0905b2c8b7 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc @@ -61,7 +61,7 @@ check_error 't kfree ^arg123456789012345678901234567890= =3D@11' # ARG_NAME_TOO_LOG check_error 't kfree ^=3D@11' # NO_ARG_NAME check_error 't kfree ^var.1=3D@11' # BAD_ARG_NAME check_error 't kfree var1=3D@11 ^var1=3D@12' # USED_ARG_NAME -check_error 't kfree ^+1234567(+1234567(+1234567(+1234567(+1234567(+123456= 7(@1234))))))' # ARG_TOO_LONG +check_error 't kfree ^+1234567(+1234567(+1234567(+1234567(+1234567(+123456= 7(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+= 1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+123= 4567(+1234567(+1234567(+1234567(@1234))))))))))))))))))))))))))' # ARG_TOO_= LONG check_error 't kfree arg1=3D^' # NO_ARG_BODY =20 =20 diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_err= ors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.= tc index 21ce8414459f..d28f63b7e8a9 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc @@ -71,7 +71,7 @@ check_error 'p vfs_read ^arg12345678901234567890123456789= 0=3D@11' # ARG_NAME_TOO_L check_error 'p vfs_read ^=3D@11' # NO_ARG_NAME check_error 'p vfs_read ^var.1=3D@11' # BAD_ARG_NAME check_error 'p vfs_read var1=3D@11 ^var1=3D@12' # USED_ARG_NAME -check_error 'p vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+123= 4567(@1234))))))' # ARG_TOO_LONG +check_error 'p vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+123= 4567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+123456= 7(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(+= 1234567(+1234567(+1234567(+1234567(@1234))))))))))))))))))))))))))' # ARG_T= OO_LONG check_error 'p vfs_read arg1=3D^' # NO_ARG_BODY =20 # instruction boundary check is valid on x86 (at this moment) From nobody Sat Jul 25 20:46:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5DE9E2DB7B4; Tue, 14 Jul 2026 01:10:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991420; cv=none; b=aa0EIdeKhXotVzEp5nJQqdXVOCWkVdkiXqmXWOvEEnjUg7QaGEJoi98Dwk5Q1ym06IBbM4igNfHxcgmG7mrfIh7MukbFJdPF5kFzGmqrGgRezE35WjeoxI2wCNqa/B2PywOU4H2M/5wn5ex1gzdbPbxH03niCn4bib0GIdYjJO4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783991420; c=relaxed/simple; bh=wNTvoZPoUdeBjlctW2RTUpGTBoi43EhWg0rcMQLHAEs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QwH/zmcSJJdRO5DzEXKgEYlpxhkUJkMimTJiie47InH0FHCUIutVf4m2r1q/msB6kurrwcI6/Tu0Vo62cyXZre8KxKSTNY5gK215X8X0zY0JYGGG62e1m14nuIF19aNpWzJyVCeJ/7cH1CHt/BSfH5VvMza+AmeOgFUaRP7g10w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QRiASUa1; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QRiASUa1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4543E1F000E9; Tue, 14 Jul 2026 01:10:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783991418; bh=CH3ukZ3w4BfiYtFaN3CWSY6yKJ+CGwf9AtYqT/D1o6U=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=QRiASUa1chUBUHsVyuJe1VH6rrFE4pDZbTez2M7BLHKsFKY3EcouRbyJ/MVHd2Rlj 2hAlm0CuzAlJQZvlWfvwEXLwCjOKroB+13iCweZlcl01N8DZsdLYk3pcUsCgHnuD6J HyBBXSpLQsCTJqpi4mnot+QpH0aXF1NWPGQATM6c13fBSjIBkql9YTfCaIf87idz77 nJdMoCU5RbzIa41Hgq0w1Ox/O6y8TRKa9q8rxrZwdb3SrLIEUY+DbVRzNLXmP+5T1T BAoQ92shgmh2NEFruAN+tyM2bTAbzppngkQFQ45uWHicZF+063wt+BfIPC4sE//0rs V6JaGmsAz1kXQ== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Masami Hiramatsu , Shuah Khan Cc: Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 5/5] tracing/probes: Eliminate recursion in parse_probe_arg() Date: Tue, 14 Jul 2026 10:10:14 +0900 Message-ID: <178399141396.27810.5390060618628718661.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178399136606.27810.4469135881050354189.stgit@devnote2> References: <178399136606.27810.4469135881050354189.stgit@devnote2> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu To avoid potential stack overflows on limited kernel stacks, convert parse_probe_arg() from a recursive function into a loop-based implementation with a simple local state stack. Since recursion is eliminated using a loop with a fixed-size stack in the context, this restricts the dereference nesting depth. The maximum nesting depth of dereferences is now restricted to the same limit as typecasts (TRACEPROBE_MAX_NESTED_LEVEL, which is 8) and reports the same TOO_MANY_NESTED error. Update ftrace selftests to reflect this restriction and simplify the checks. Note that this change slightly alters the behavior of nested dereferencing in fetcharg. Previously, dereferencing without BTF allowed for up to 14 levels of nesting, whereas dereferencing with BTF was limited to 3 levels. With this change, the nesting depth is now limited to 8 levels in both cases. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- Changes in v3: - Removed unused is_ptr. - Add trace_probe_log_err() to the error case in parse_this_cpu(). Changes in v2: - Clearly state that both derefernce nest and typecast nest are limited by the same TRACEPROBE_MAX_NESTED_LEVEL. - Extend TRACEPROBE_MAX_NESTED_LEVEL to 8. - Fix testcase to check TOO_MANY_NESTED instead of TOO_MANY_OPS (that should not be hit anymore) --- kernel/trace/trace_probe.c | 338 ++++++++++++----= ---- kernel/trace/trace_probe.h | 33 ++ .../ftrace/test.d/dynevent/fprobe_syntax_errors.tc | 4=20 .../ftrace/test.d/dynevent/tprobe_syntax_errors.tc | 2=20 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc | 4=20 5 files changed, 242 insertions(+), 139 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index eb9f7bd13c19..7568f5e68de7 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -356,61 +356,10 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, struct fetch_insn **pcode, struct fetch_insn *end, struct traceprobe_parse_context *ctx); =20 -/* handle dereference nested call */ -static inline int handle_dereference(char *arg, struct fetch_insn **pcode, - struct fetch_insn *end, struct traceprobe_parse_context *ctx, - int deref, long offset) +static int parse_this_cpu(char *arg, struct traceprobe_parse_context *ctx) { - const struct fetch_type *type =3D find_fetch_type(NULL, ctx->flags); - struct fetch_insn *code =3D *pcode; - int cur_offs =3D ctx->offset; + bool is_read =3D false; char *tmp; - int ret; - - tmp =3D strrchr(arg, ')'); - if (!tmp) { - trace_probe_log_err(ctx->offset + strlen(arg), - DEREF_OPEN_BRACE); - return -EINVAL; - } - - *tmp =3D '\0'; - ret =3D parse_probe_arg(arg, type, &code, end, ctx); - if (ret) - return ret; - ctx->offset =3D cur_offs; - if (code->op =3D=3D FETCH_OP_COMM || code->op =3D=3D FETCH_OP_IMMSTR) { - trace_probe_log_err(ctx->offset, COMM_CANT_DEREF); - return -EINVAL; - } - - /* - * this_cpu_ptr(@SYM) does not use SYM value, but use SYM address. - * So we overwrite the last FETCH_OP_DEREF with FETCH_OP_CPU_PTR. - */ - if (!(deref =3D=3D FETCH_OP_CPU_PTR && *arg =3D=3D '@')) { - code++; - if (code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); - return -EINVAL; - } - } - *pcode =3D code; - - code->op =3D deref; - code->offset =3D offset; - /* Reset the last type if used */ - ctx->last_type =3D NULL; - return 0; -} - -static int parse_this_cpu(char *arg, struct fetch_insn **pcode, - struct fetch_insn *end, - struct traceprobe_parse_context *ctx) -{ - struct fetch_insn *code; - bool is_ptr =3D false; - int ret; =20 /* * This is only for kernel probes, excluding eprobe, because per-cpu @@ -424,27 +373,29 @@ static int parse_this_cpu(char *arg, struct fetch_ins= n **pcode, if (str_has_prefix(arg, THIS_CPU_PTR_PREFIX)) { arg +=3D THIS_CPU_PTR_LEN; ctx->offset +=3D THIS_CPU_PTR_LEN; - is_ptr =3D true; } else if (str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { arg +=3D THIS_CPU_READ_LEN; ctx->offset +=3D THIS_CPU_READ_LEN; - } else + is_read =3D true; + } else { + trace_probe_log_err(ctx->offset, BAD_FETCH_ARG); return -EINVAL; + } =20 - ret =3D handle_dereference(arg, pcode, end, ctx, FETCH_OP_CPU_PTR, 0); - if (ret || is_ptr) - return ret; - - /* this_cpu_read(VAR) -> +0(this_cpu_ptr(VAR)) */ - code =3D *pcode; - code++; - if (code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + tmp =3D strrchr(arg, ')'); + if (!tmp) { + trace_probe_log_err(ctx->offset + strlen(arg), + DEREF_OPEN_BRACE); return -EINVAL; } - code->op =3D FETCH_OP_DEREF; - code->offset =3D 0; - *pcode =3D code; + *tmp =3D '\0'; + + ctx->stack[ctx->depth].type =3D STATE_DEREF; + ctx->stack[ctx->depth].deref.deref =3D FETCH_OP_CPU_PTR; + ctx->stack[ctx->depth].deref.offset =3D 0; + ctx->stack[ctx->depth].deref.cur_offs =3D ctx->offset; + ctx->stack[ctx->depth].deref.inner_arg =3D arg; + ctx->stack[ctx->depth].deref.is_cpu_read =3D is_read; return 0; } =20 @@ -1007,14 +958,12 @@ static char *find_matched_close_paren(char *s) return NULL; } =20 -static int handle_typecast(char *arg, struct fetch_insn **pcode, - struct fetch_insn *end, - struct traceprobe_parse_context *ctx) +static int handle_typecast(char *arg, struct traceprobe_parse_context *ctx) { int orig_offset =3D ctx->offset; char *close; char *tmp; - int ret; + char *fieldname; =20 if (!(tparg_is_event_probe(ctx->flags) || tparg_is_function_entry(ctx->flags) || @@ -1028,12 +977,6 @@ static int handle_typecast(char *arg, struct fetch_in= sn **pcode, * For example: (STRUCT)VAR->FIELD and (STRUCT)(VAR)->FIELD are same. * VAR is solved in the nested call. */ - ctx->nested_level++; - if (ctx->nested_level > TRACEPROBE_MAX_NESTED_LEVEL) { - trace_probe_log_err(ctx->offset, TOO_MANY_NESTED); - return -E2BIG; - } - tmp =3D strchr(arg, ')'); if (!tmp) { trace_probe_log_err(ctx->offset + strlen(arg), @@ -1103,30 +1046,19 @@ static int handle_typecast(char *arg, struct fetch_= insn **pcode, } *close =3D '\0'; =20 - /* We need to parse the nested one */ - ret =3D parse_probe_arg(tmp, find_fetch_type(NULL, ctx->flags), - pcode, end, ctx); - if (ret < 0) - return ret; - ctx->nested_level--; - clear_struct_btf(ctx); - - /* Let tmp point the field name. */ + /* Let fieldname point the field name. */ if (close[1] =3D=3D '-') - tmp =3D close + 3; /* Skip "->" after closing parenthesis */ + fieldname =3D close + 3; /* Skip "->" after closing parenthesis */ else - tmp =3D close + 2; /* Skip ">" after inner variable name */ - - /* resolve the typecast struct name */ - ctx->offset =3D orig_offset + 1; /* for the '(' */ - ret =3D parse_btf_casttype(arg + 1, ctx); - if (ret < 0) - return ret; - - ctx->offset =3D orig_offset + tmp - arg; - ret =3D parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx); - ctx->prefix_byteoffs =3D 0; - return ret; + fieldname =3D close + 2; /* Skip ">" after inner variable name */ + + ctx->stack[ctx->depth].type =3D STATE_TYPECAST; + ctx->stack[ctx->depth].typecast.casttype =3D arg + 1; + ctx->stack[ctx->depth].typecast.fieldname =3D fieldname; + ctx->stack[ctx->depth].typecast.orig_offset =3D orig_offset; + ctx->stack[ctx->depth].typecast.field_offset_diff =3D fieldname - arg; + ctx->stack[ctx->depth].typecast.inner_arg =3D tmp; + return 0; } =20 #else /* !CONFIG_PROBE_EVENTS_BTF_ARGS */ @@ -1171,9 +1103,20 @@ static int check_prepare_btf_string_fetch(char *type= name, return 0; } =20 -static int handle_typecast(char *arg, struct fetch_insn **pcode, - struct fetch_insn *end, +static int parse_btf_casttype(char *casttype, + struct traceprobe_parse_context *ctx) +{ + return -EOPNOTSUPP; +} + +static int parse_btf_field(char *fieldname, const struct btf_type *type, + struct fetch_insn **pcode, struct fetch_insn *end, struct traceprobe_parse_context *ctx) +{ + return -EOPNOTSUPP; +} + +static int handle_typecast(char *arg, struct traceprobe_parse_context *ctx) { trace_probe_log_err(ctx->offset, NOSUP_BTFARG); return -EOPNOTSUPP; @@ -1598,9 +1541,7 @@ static int parse_probe_arg_mem_symbol(char *arg, stru= ct fetch_insn **pcode, return 0; } =20 -static int parse_probe_arg_deref(char *arg, struct fetch_insn **pcode, - struct fetch_insn *end, - struct traceprobe_parse_context *ctx) +static int parse_probe_arg_deref(char *arg, struct traceprobe_parse_contex= t *ctx) { int deref =3D FETCH_OP_DEREF; long offset =3D 0; @@ -1627,7 +1568,22 @@ static int parse_probe_arg_deref(char *arg, struct f= etch_insn **pcode, } ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); arg =3D tmp + 1; - return handle_dereference(arg, pcode, end, ctx, deref, offset); + + tmp =3D strrchr(arg, ')'); + if (!tmp) { + trace_probe_log_err(ctx->offset + strlen(arg), + DEREF_OPEN_BRACE); + return -EINVAL; + } + *tmp =3D '\0'; + + ctx->stack[ctx->depth].type =3D STATE_DEREF; + ctx->stack[ctx->depth].deref.deref =3D deref; + ctx->stack[ctx->depth].deref.offset =3D offset; + ctx->stack[ctx->depth].deref.cur_offs =3D ctx->offset; + ctx->stack[ctx->depth].deref.inner_arg =3D arg; + ctx->stack[ctx->depth].deref.is_cpu_read =3D false; + return 0; } =20 static int parse_probe_arg_imm(char *arg, struct fetch_insn *code, @@ -1659,11 +1615,6 @@ static int parse_probe_arg_default(char *arg, struct= fetch_insn **pcode, { int ret; =20 - if (str_has_prefix(arg, THIS_CPU_PTR_PREFIX) || - str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { - return parse_this_cpu(arg, pcode, end, ctx); - } - if (isalpha(arg[0]) || arg[0] =3D=3D '_') { /* BTF variable or event field */ if (ctx->flags & TPARG_FL_TEVENT) { @@ -1685,11 +1636,56 @@ static int parse_probe_arg_default(char *arg, struc= t fetch_insn **pcode, return 0; } =20 -/* Recursive argument parser */ -static int -parse_probe_arg(char *arg, const struct fetch_type *type, - struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) +static int parse_probe_arg_nested(char **parg, struct traceprobe_parse_con= text *ctx) +{ + char *arg =3D *parg; + int ret; + + while (true) { + /* Determine if this is a nested argument */ + if (arg[0] !=3D '+' && arg[0] !=3D '-' && arg[0] !=3D '(' && + !str_has_prefix(arg, THIS_CPU_PTR_PREFIX) && + !str_has_prefix(arg, THIS_CPU_READ_PREFIX)) + break; + + /* If nested, check the maximum depth limit */ + if (ctx->depth >=3D TRACEPROBE_MAX_NESTED_LEVEL) { + trace_probe_log_err(ctx->offset, TOO_MANY_NESTED); + return -E2BIG; + } + + /* Perform the actual parsing subroutine calls */ + switch (arg[0]) { + case '+': + case '-': + ret =3D parse_probe_arg_deref(arg, ctx); + if (ret) + return ret; + arg =3D ctx->stack[ctx->depth].deref.inner_arg; + break; + case '(': + ret =3D handle_typecast(arg, ctx); + if (ret) + return ret; + arg =3D ctx->stack[ctx->depth].typecast.inner_arg; + break; + default: + ret =3D parse_this_cpu(arg, ctx); + if (ret) + return ret; + arg =3D ctx->stack[ctx->depth].deref.inner_arg; + break; + } + ctx->depth++; + } + + *parg =3D arg; + return 0; +} + +static int parse_probe_arg_leaf(char *arg, const struct fetch_type *type, + struct fetch_insn **pcode, struct fetch_insn *end, + struct traceprobe_parse_context *ctx) { struct fetch_insn *code =3D *pcode; int ret; @@ -1704,26 +1700,112 @@ parse_probe_arg(char *arg, const struct fetch_type= *type, case '@': /* memory, file-offset or symbol */ ret =3D parse_probe_arg_mem_symbol(arg, pcode, end, ctx); break; - case '+': /* deref memory */ - case '-': - ret =3D parse_probe_arg_deref(arg, pcode, end, ctx); - break; case '\\': /* Immediate value */ ret =3D parse_probe_arg_imm(arg, code, ctx); break; - case '(': - ret =3D handle_typecast(arg, pcode, end, ctx); - break; default: ret =3D parse_probe_arg_default(arg, pcode, end, ctx); break; } - if (!ret && code->op =3D=3D FETCH_OP_NOP) { + + if (ret) + return ret; + + if (code->op =3D=3D FETCH_OP_NOP) { /* Parsed, but do not find fetch method */ trace_probe_log_err(ctx->offset, BAD_FETCH_ARG); - ret =3D -EINVAL; + return -EINVAL; } - return ret; + + return 0; +} + +static int unwind_parse_states(struct fetch_insn **pcode, struct fetch_ins= n *end, + struct traceprobe_parse_context *ctx) +{ + struct parse_state *state; + struct fetch_insn *code; + int ret; + + while (ctx->depth > 0) { + ctx->depth--; + state =3D &ctx->stack[ctx->depth]; + + if (state->type =3D=3D STATE_DEREF) { + code =3D *pcode; + ctx->offset =3D state->deref.cur_offs; + if (code->op =3D=3D FETCH_OP_COMM || code->op =3D=3D FETCH_OP_IMMSTR) { + trace_probe_log_err(ctx->offset, COMM_CANT_DEREF); + return -EINVAL; + } + + if (!(state->deref.deref =3D=3D FETCH_OP_CPU_PTR && + *state->deref.inner_arg =3D=3D '@')) { + code++; + if (code =3D=3D end) { + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + return -EINVAL; + } + } + *pcode =3D code; + + code->op =3D state->deref.deref; + code->offset =3D state->deref.offset; + ctx->last_type =3D NULL; + + if (state->deref.is_cpu_read) { + code =3D *pcode; + code++; + if (code =3D=3D end) { + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + return -EINVAL; + } + code->op =3D FETCH_OP_DEREF; + code->offset =3D 0; + *pcode =3D code; + } + } else if (state->type =3D=3D STATE_TYPECAST) { + clear_struct_btf(ctx); + + /* resolve the typecast struct name */ + ctx->offset =3D state->typecast.orig_offset + 1; /* for the '(' */ + ret =3D parse_btf_casttype(state->typecast.casttype, ctx); + if (ret < 0) + return ret; + + ctx->offset =3D state->typecast.orig_offset + + state->typecast.field_offset_diff; + ret =3D parse_btf_field(state->typecast.fieldname, + ctx->last_struct, pcode, + end, ctx); + ctx->prefix_byteoffs =3D 0; + if (ret < 0) + return ret; + } + } + + return 0; +} + +/* Loop-based (non-recursive) argument parser */ +static int +parse_probe_arg(char *arg, const struct fetch_type *type, + struct fetch_insn **pcode, struct fetch_insn *end, + struct traceprobe_parse_context *ctx) +{ + int ret; + + ctx->depth =3D 0; + + ret =3D parse_probe_arg_nested(&arg, ctx); + if (ret) + return ret; + + ret =3D parse_probe_arg_leaf(arg, type, pcode, end, ctx); + if (ret) + return ret; + + return unwind_parse_states(pcode, end, ctx); } =20 /* Bitfield type needs to be parsed into a fetch function */ @@ -1984,12 +2066,6 @@ static int traceprobe_parse_probe_arg_body(const cha= r *argv, ssize_t *size, ctx); if (ret < 0) goto fail; - /* nested_level must be 0 here, otherwise there is a bug. */ - if (WARN_ON_ONCE(ctx->nested_level)) { - ret =3D -EINVAL; - goto fail; - } - /* Update storing type if BTF is available */ if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && ctx->last_type) { diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index e6d427910c4f..ebdc706e7cb6 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -437,6 +437,34 @@ static inline bool tparg_is_event_probe(unsigned int f= lags) return !!(flags & TPARG_FL_TEVENT); } =20 +/* Each typecast consumes nested level. So the max number of typecast is 8= . */ +#define TRACEPROBE_MAX_NESTED_LEVEL 8 + +enum parse_state_type { + STATE_DEREF, + STATE_TYPECAST, +}; + +struct parse_state { + int type; + union { + struct { + int deref; + long offset; + int cur_offs; + char *inner_arg; + bool is_cpu_read; + } deref; + struct { + char *casttype; + char *fieldname; + int orig_offset; + int field_offset_diff; + char *inner_arg; + } typecast; + }; +}; + struct traceprobe_parse_context { struct trace_event_call *event; /* BTF related parameters */ @@ -453,12 +481,11 @@ struct traceprobe_parse_context { struct trace_probe *tp; unsigned int flags; int offset; - int nested_level; int prefix_byteoffs; /* The byte offset of the prefix field of typecast */ + struct parse_state stack[TRACEPROBE_MAX_NESTED_LEVEL + 1]; + int depth; }; =20 -/* Each typecast consumes nested level. So the max number of typecast is 3= . */ -#define TRACEPROBE_MAX_NESTED_LEVEL 3 =20 extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *argv, diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_e= rrors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_err= ors.tc index 984ab94df213..384209968325 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc @@ -60,7 +60,7 @@ check_error 'f vfs_read ^&1' # BAD_FETCH_ARG =20 # We've introduced this limitation with array support if grep -q ' \\\[\\\]' README; then -check_error 'f vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0)))))= )))))))))' # TOO_MANY_OPS? +check_error 'f vfs_read +0(+0(+0(+0(+0(+0(+0(+0(^+0(@0)))))))))' # TOO_MAN= Y_NESTED check_error 'f vfs_read +0(@11):u8[10^' # ARRAY_NO_CLOSE check_error 'f vfs_read +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX check_error 'f vfs_read +0(@11):u8[^10a]' # BAD_ARRAY_NUM @@ -114,7 +114,7 @@ check_error 'f vfs_read file^-.foo' # BAD_HYPHEN check_error 'f vfs_read ^file:string' # BAD_TYPE4STR if grep -qF "[(structname" README ; then check_error 'f vfs_read arg1=3D(task_struct)file^' # TYPECAST_REQ_FIELD -check_error 'f vfs_read arg1=3D(a)((b)((c)(^(d)file->d)->c)->b)->a' # TOO_= MANY_NESTED +check_error 'f vfs_read arg1=3D(a)((b)((c)((d)((e)((f)((g)((h)(^(i)file->i= )->h)->g)->f)->e)->d)->c)->b)->a' # TOO_MANY_NESTED check_error 'f vfs_read arg1=3D(task_struct,^in_execve)file->comm' # TYPEC= AST_NOT_ALIGNED check_error 'f vfs_read arg1=3D(task_struct,^foo_bar)file->pid' # NO_BTF_F= IELD check_error 'f vfs_read arg1=3D(^task_struct1234)file->pid' # NO_PTR_STRCT diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_e= rrors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_err= ors.tc index 2d0905b2c8b7..72b8652df9ba 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc @@ -46,7 +46,7 @@ check_error 't kfree ^&1' # BAD_FETCH_ARG =20 # We've introduced this limitation with array support if grep -q ' \\\[\\\]' README; then -check_error 't kfree +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))= ))))))' # TOO_MANY_OPS? +check_error 't kfree +0(+0(+0(+0(+0(+0(+0(+0(^+0(@0)))))))))' # TOO_MANY_N= ESTED check_error 't kfree +0(@11):u8[10^' # ARRAY_NO_CLOSE check_error 't kfree +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX check_error 't kfree +0(@11):u8[^10a]' # BAD_ARRAY_NUM diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_err= ors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.= tc index d28f63b7e8a9..b0e6b80ccb01 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc @@ -56,7 +56,7 @@ check_error 'p vfs_read ^&1' # BAD_FETCH_ARG =20 # We've introduced this limitation with array support if grep -q ' \\\[\\\]' README; then -check_error 'p vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0)))))= )))))))))' # TOO_MANY_OPS? +check_error 'p vfs_read +0(+0(+0(+0(+0(+0(+0(+0(^+0(@0)))))))))' # TOO_MAN= Y_NESTED check_error 'p vfs_read +0(@11):u8[10^' # ARRAY_NO_CLOSE check_error 'p vfs_read +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX check_error 'p vfs_read +0(@11):u8[^10a]' # BAD_ARRAY_NUM @@ -117,7 +117,7 @@ check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the= number of parameters) check_error 'r kfree ^$retval' # NO_RETVAL if grep -qF "[(structname" README ; then check_error 'p vfs_read arg1=3D(task_struct)file^' # TYPECAST_REQ_FIELD -check_error 'p vfs_read arg1=3D(a)((b)((c)(^(d)file->d)->c)->b)->a' # TOO_= MANY_NESTED +check_error 'p vfs_read arg1=3D(a)((b)((c)((d)((e)((f)((g)((h)(^(i)file->i= )->h)->g)->f)->e)->d)->c)->b)->a' # TOO_MANY_NESTED check_error 'p vfs_read arg1=3D(task_struct,^in_execve)file->comm' # TYPEC= AST_NOT_ALIGNED check_error 'p vfs_read arg1=3D(task_struct,^foo_bar)file->pid' # NO_BTF_F= IELD check_error 'p vfs_read arg1=3D(^task_struct1234)file->pid' # NO_PTR_STRCT