From nobody Sat Jul 25 22:31:35 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 444C41FC101; Sun, 12 Jul 2026 15:06:19 +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=1783868780; cv=none; b=UFnhHSm2pR+rqvoF6Z5NRwIMoXCPBX1Nlk68GvzO6AlaA8IYJEa505Zv12dZgDwYZwWd8q4y+HQKFp9pDqNdqcpMuKtDlKx54+mGxWrG0wKxenxBjereiYtSQNTJ0RHux+nk6NxpyGMeQeHf1EJwMjVIDobJSE/4+MoDX92VCgs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783868780; c=relaxed/simple; bh=sbUj+3v53dPLU66tan8aCdsvJuBn6HapejRXnHkwQxQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ihX1nyIBAojPF7VCT78gMeqZAoQcuQMXtX9A/I3n7qMufu+VbVZXTkc4L9t1Q/sdoCJypUL796dzXf+rZL5cDvVrm20odJ9epSJ4Xt7kii9jaPj+fSw90cZOg30M6QeTW7rtO8wUmy5qqC9SGRgaAbFa7ngY87Mumh0ETw/7/tI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WT6u/YI3; 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="WT6u/YI3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5C7361F000E9; Sun, 12 Jul 2026 15:06:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783868779; bh=Lp2LKTwGDvoSloSg7EhLWRTt1pdS3kMEMSXspT6hlaw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=WT6u/YI30ko6ZSQQhf6nshtuP57JwxPgx9TAGi9DralRrp2MveLfAdSXZJiMdI/IM kDx8bxq2HYPm0+8G4676VXw2enNyeu9wjgOviubbT869UsGHC3NMMzoq2iz01J+XyL lICwIiFMTdbslo78uLHPmYN7PiS+NoP0g8d157X7rVy1cmq0Nz1D64v4Ue8WPQN9vk GtR5DnaKFPW4BurhEC4okJNOKMgC2Icgb1P+aorGKhiVrf+D/OHCAQbNltbopQseep 7v1u5ZMbww3sYnRffC5XUdG77E+A3Szuh8Ur7zlE+ztc7NAMyzULsOT1HG7mcowjk/ m0YtSEJodrpLw== 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 1/5] tracing/probes: Refactor parse_probe_vars() Date: Mon, 13 Jul 2026 00:06:15 +0900 Message-ID: <178386877517.3174487.13406442794979828170.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178386876526.3174487.5142283230157728964.stgit@devnote2> References: <178386876526.3174487.5142283230157728964.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) --- kernel/trace/trace_probe.c | 248 +++++++++++++++++++++++++++-------------= ---- 1 file changed, 151 insertions(+), 97 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 18c212122344..b762336ebf03 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1319,67 +1319,147 @@ 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, + int *err) { 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)) { + *err =3D TP_ERR_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, + int *err) +{ 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 (!(ctx->flags & TPARG_FL_KERNEL) || - !IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) { - code->op =3D FETCH_OP_RETVAL; - return 0; + if (isdigit(arg[len])) { + ret =3D kstrtoul(arg + len, 10, ¶m); + if (ret) + return ret; + + if ((ctx->flags & TPARG_FL_KERNEL) && + param > PARAM_MAX_STACK) { + *err =3D TP_ERR_BAD_STACK_NUM; + return -EINVAL; } + code->op =3D FETCH_OP_STACK; + code->param =3D (unsigned int)param; + return 0; + } + + 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, + int *err) +{ + struct fetch_insn *code =3D *pcode; + + /* $current is only supported by kernel probe. */ + if (!(ctx->flags & TPARG_FL_KERNEL)) { + *err =3D TP_ERR_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') + return -EINVAL; + + code->op =3D FETCH_OP_CURRENT; + 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, + int *err) +{ + unsigned long param; + int ret; + + ret =3D kstrtoul(arg + len, 10, ¶m); + if (ret) + return ret; + + if (!param || param > PARAM_MAX_STACK) { + *err =3D TP_ERR_BAD_ARG_NUM; + return -EINVAL; } + param--; /* argN starts from 1, but internal arg[N] starts from 0 */ =20 - len =3D str_has_prefix(arg, "stack"); - if (len) { + 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; =20 - if (arg[len] =3D=3D '\0') { - code->op =3D FETCH_OP_STACKP; - return 0; - } + code->op =3D FETCH_OP_EDATA; + code->offset =3D ret; + } else { + *err =3D TP_ERR_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, + int *err) +{ + *err =3D TP_ERR_BAD_VAR; + return -EINVAL; +} +#endif =20 - if (isdigit(arg[len])) { - ret =3D kstrtoul(arg + len, 10, ¶m); - if (ret) - goto inval; +/* 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 err =3D TP_ERR_BAD_VAR; + int ret =3D -EINVAL; + int len; =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; + if (ctx->flags & TPARG_FL_TEVENT) { + ret =3D parse_trace_event(arg, code, ctx); + if (!ret) return 0; - } - goto inval; } =20 if (strcmp(arg, "comm") =3D=3D 0 || strcmp(arg, "COMM") =3D=3D 0) { @@ -1387,65 +1467,39 @@ static int parse_probe_vars(char *orig_arg, const s= truct fetch_type *t, return 0; } =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); - - if (*arg !=3D '\0') - goto inval; + /* eprobe only support event fields or '$comm'. */ + if (ctx->flags & TPARG_FL_TEVENT) + goto end; =20 - code->op =3D FETCH_OP_CURRENT; - return 0; + if (str_has_prefix(arg, "retval")) { + ret =3D parse_probe_var_retval(orig_arg, arg, pcode, end, ctx, &err); + goto end; } =20 -#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API - len =3D str_has_prefix(arg, "arg"); + len =3D str_has_prefix(arg, "stack"); if (len) { - ret =3D kstrtoul(arg + len, 10, ¶m); - if (ret) - goto inval; - - 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 */ + ret =3D parse_probe_var_stack(arg, len, code, ctx, &err); + goto end; + } =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; + /* $current returns the address of the current task_struct. */ + if (str_has_prefix(arg, "current")) { + ret =3D parse_probe_var_current(orig_arg, arg, pcode, end, ctx, &err); + goto end; + } =20 - code->op =3D FETCH_OP_EDATA; - code->offset =3D ret; - } else { - err =3D TP_ERR_NOFENTRY_ARGS; - goto inval; - } - return 0; + len =3D str_has_prefix(arg, "arg"); + if (len) { + ret =3D parse_probe_var_arg(arg, len, code, ctx, &err); + goto end; } -#endif =20 -inval: - __trace_probe_log_err(ctx->offset, err); - return -EINVAL; +end: + if (ret < 0) { + __trace_probe_log_err(ctx->offset, err); + return ret; + } + return 0; } =20 static int str_to_immediate(char *str, unsigned long *imm) From nobody Sat Jul 25 22:31:35 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 617DE33F58E; Sun, 12 Jul 2026 15:06:28 +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=1783868789; cv=none; b=jYBFY/QjCPsaDYr633W+xg7cbeM+FDyeMQCzT8pZr91lVBNy90vOwJEsgC8kzNzqiIhqKGWIpMY01BhHU7Woz/ilSPc+oodEnd18keG7KBqe33DVMJ/AAzqCTr4aIE+8I9h4AeZ5aaHnCuBeo2RhyT16EmxxG/lwtw5GIInxd0Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783868789; c=relaxed/simple; bh=Yvs6+cRZKZgZh+ZvaQLgQmHwVrhHHvOorcdbaBiI73s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VUq5g7YiNElXvNFgNqXq1mWhd1DAlB/oktYjjFq39rEGeCHzgTOCkT8JoWzL3JLf+04vxyKe9x/pseZf/6WWd4lqfYvfGT9wKMA6bVV1WHnTCyR88VDMf3uR4iuzKpYVAu+BfjF3yfIw/KTU3jvzfaxFo7i5ng+mJW2/fSEHa5A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DzGWzwZt; 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="DzGWzwZt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 910171F000E9; Sun, 12 Jul 2026 15:06:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783868788; bh=h6ESoGLCkOqGsVYJx3C54LUbDsC9lxEg7Havt6NwIPU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=DzGWzwZtQkFRN233Aavc4QtHlzxMDAhdOKlXv+jTj9CZKzvcFPgrbD6olPhJHN0Ri XDdVTVrkedMKK29oS2aSY/FvdQBG8hk076AVcc1yxvN2w7vz8pX0980Tljp1VLQO+r ySF5UverR4G/+MRaKBSH+asq1XGZpHESq2Xg367iv/XkeMC98k2eAHOgxuiRQIqbRy UDZpbHJ6Hsc51RUzzsklFpeV068VwgOFohRfVZh50jbwDm8DihN0diWc07+DBrDzNu Gls+zagEB/BSQAlOLPHEeJNI4CTMHgRE7XlS+kKHSRgm1i9M2SNvtYqykb76XSTcZx /zayxeBeBRpEw== 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 2/5] tracing/probes: Refactor parse_probe_arg() Date: Mon, 13 Jul 2026 00:06:24 +0900 Message-ID: <178386878453.3174487.11053162981481666910.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178386876526.3174487.5142283230157728964.stgit@devnote2> References: <178386876526.3174487.5142283230157728964.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 b762336ebf03..2b8cc4cf5109 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1527,158 +1527,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); + } + + 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) +{ + 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 22:31:35 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 F059F33F369; Sun, 12 Jul 2026 15:06:36 +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=1783868798; cv=none; b=Sk0Z4ik4lpl4U5RhEAfo0+JWHiMQWU72ocvucN9HaeEVNu6dtyGl3+ylmNoFh9lIJqyHr5CttoG7F0cs3bESfgShyHCVBYjurf1kK2UEKUfbTeoyHHfS1gBD2fszvnPDKkGuvkPvvYzb9ASLR5Dg6h7QHV0wxn2gv3jtQY7sUIE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783868798; 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=B2scbOJTEkxdp/7bRal2lntj8lW3xFv/89joZ9BjZ2/V54cp78QWdTVtpAQ91gDHQ6vKUp91F1HJLIovzEHXfcCkPg87X+QWxDcLwD17/bWgqDnl8JFiTgNmI5s6odaj9X7EeBvy1DLZ7gqFbinIppW4ygtrMxLyZhGHVYRDWCY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RevIMKt3; 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="RevIMKt3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7AD401F000E9; Sun, 12 Jul 2026 15:06:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783868796; bh=ykkygFjoUseT4cJdY6LDUUSLsLeCSFMWe0Bi0JBfXDY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=RevIMKt3SKDqOS5z1M9t85ahWgs9iAH/uks/6RhXMure/3igi6mAkyG+aQ50qVPyQ 9ViiQMFhsjvhCKYhRnupg5RV8F8qV5QP4dIPKCQp+f7VViNPKf4x4kn8lfuSqzy3bC CxBsUkNHLoEAy9D3a9hBORf9NT558UJQ/eW+WvcLpIxv1w/vZhMIrWd943qI/netJk gda/9i+RYmFMxewkFmyJIStwVv0s0pAlE6IQDkaYEyya6ziYjUGI1Rqn47uGYjNg1o P0Qm8zV8643CtS+G9RwPKTFPouwpGgtbII7+xLqcfqTbeofohrqf57rp3J0hsdTg04 FLW+O9FWTvhrg== 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 3/5] tracing/probes: Sort ERRORS list in trace_probe.h alphabetically Date: Mon, 13 Jul 2026 00:06:33 +0900 Message-ID: <178386879350.3174487.6908641358093671296.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178386876526.3174487.5142283230157728964.stgit@devnote2> References: <178386876526.3174487.5142283230157728964.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 22:31:35 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 EF1D01FC101; Sun, 12 Jul 2026 15:06:45 +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=1783868807; cv=none; b=nvno3n8VUcr7AZ854e/8P5B4owVd3Wr2qT6iyNUTvWIBLsqGSf0uwgqMnKH3cc6RkAIidSRFu+o59jPEUcpdYQHUm5EGnNzCUOsYhh21w306lnu2TjIzNMuNYhJcqbms1fpjZA/E5nof2QJs0xrVe2DQa7txKfSsRi8op0Zd/wY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783868807; c=relaxed/simple; bh=SspKmTVqDykIsyYfDevWXlwNnCi4xsMnGE47RHqCvzo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QpF84X+4LPp6vlG/cdBg1EJwb5IuZNE1IT+9zTrBiyLZ1Wq5O6J2qkgeukAk1KA7IdTcuF99QrG0RHhtTy2JAWoylvERQTfEUiubklzXaWYv0ZIRrtACaBQX+aEx+1BlLueckWrlm0WJn8L47TEHGCMWRTLcVrsVcZ9oIclD9cM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D4vdAukk; 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="D4vdAukk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0D29C1F000E9; Sun, 12 Jul 2026 15:06:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783868805; bh=5qdaZDdFG7Iggglcfn9bMxDum+ivTyVX00VB1yXRkJE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=D4vdAukkgoWksHI9Vnevd8+9UnEqSOlILcz7rTyzM1cla/4xeTPicIlIHZcKOntcL y0Ukae5Jmt/VBz5rHIriRs6cYf22E9XQTfk+NOd4/zV2oAP3Qfp22mCeRx7oDbKMFT JLOkbuhh4yzRB9xy761RJL6OBtlk/a2oxTE7nLASQ7t7a1CA4rZgheoEfzZqh9FXC4 I6jg6IOn7X61JOiIAKhsT2ROYmMI+3Byvl4o5HbVUAGE8DkePg+UGOvWg8NlHLUrhG kMOLP/XB9vqSu49CWA0UjTVscxlFapkqDrNLVHIZt5/FCPM+QBOGqLqNoFZIoroblv eLdSlGLnQ4b3g== 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 4/5] tracing/probes: Extend max length of argument string Date: Mon, 13 Jul 2026 00:06:42 +0900 Message-ID: <178386880215.3174487.982264935084717241.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178386876526.3174487.5142283230157728964.stgit@devnote2> References: <178386876526.3174487.5142283230157728964.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 256. 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) --- 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..e6aee800a7d9 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 256 +#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 22:31:35 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 3F9931FC101; Sun, 12 Jul 2026 15:06:55 +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=1783868816; cv=none; b=Mpjd2ZwbsmB7HXeSu34jxUSw2TtHpyw90A+OxZhjZrctBtYSngRprXhEIWSrU+526uOtLfjYPGxYNf5zH3rBIqVcFpokpRxxhRxQ+xgDNiZoGxSbK9H8wVRK+4ji5SF98j/8WDJpljDCOSNKYCUst+Er1rVdiTAHUe44MeTWNp8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783868816; c=relaxed/simple; bh=Je/KH3ai9xXsgloFt0LVPFbzAgc6Uwe1M1+FyRC5b5Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Y5EK6VRKdxdf6bntFnqFrGR8x+V5ASMZ6PVOzRZSkbFyHoX5A+YVoGyOsRXYzssqM6pV4kfjzbaU3zdR7EJZgjTCgUr4b+ECO7zXAEa2F1PNxwkTEszRYlfuqsUm4b8l8o4y3PtPXRu3hR1CYnQG3g6Z9CZZOyGTGD7PRnvGNkI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=osngyvHM; 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="osngyvHM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4EB9C1F000E9; Sun, 12 Jul 2026 15:06:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783868814; bh=RltBTbj3781JqaBaSrdKJpcYWo+bhrdgC24nlsWOY94=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=osngyvHMYzxr7CWKOUmxRTWOlfqVDbWPYMy2s5F41rl79VBg02TZr07NmtERu4a+o pC1PIMN6gkXZw2pNzWyiq+JTFQZYIOZ6nIrLl4JLVXn4hu6WL3jg0i5lWkvpuJn4XA soxv7OCeIMHOt+17FZSYPBQEkY8oBEO3p1Z9XEOjwlHoVc+lVjKMWvtnH2Q1h8/Ooy nbCqwYmjCmMmutRhG1vxWogWNhy4teKe0CnAGMWu4zjQeT75mBvlhwJQMjY2GIVU2A Spn42kGkx+YlGFVEoWrhckAzcrfhRb4/vnngjQ+YTmrUCurIr0VyW+Ez3aBxkCeH3f VWUb6Tikr5bcg== 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 5/5] tracing/probes: Eliminate recursion in parse_probe_arg() Date: Mon, 13 Jul 2026 00:06:51 +0900 Message-ID: <178386881106.3174487.4517613868901251001.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178386876526.3174487.5142283230157728964.stgit@devnote2> References: <178386876526.3174487.5142283230157728964.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 tiny local state stack. Define struct parse_state to hold the parsing contexts for nested dereference and typecast operations. Modify parse_probe_arg_deref(), parse_this_cpu(), and handle_typecast() to return parsing state details rather than calling parse_probe_arg() recursively. parse_probe_arg() then processes nested nodes by pushing onto the parse_state array, parsing the leaf node, and unwinding/evaluating the array entries in LIFO order. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- kernel/trace/trace_probe.c | 337 ++++++++++++----= ---- 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, 243 insertions(+), 137 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 2b8cc4cf5109..345fa06f6980 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -356,61 +356,11 @@ 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; - 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; + bool is_read =3D false; + char *tmp; =20 /* * This is only for kernel probes, excluding eprobe, because per-cpu @@ -428,23 +378,24 @@ static int parse_this_cpu(char *arg, struct fetch_ins= n **pcode, } else if (str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { arg +=3D THIS_CPU_READ_LEN; ctx->offset +=3D THIS_CPU_READ_LEN; + is_read =3D true; } else 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; @@ -1609,9 +1552,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; @@ -1638,7 +1579,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, @@ -1670,11 +1626,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) { @@ -1696,11 +1647,59 @@ 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) { + if (arg[0] =3D=3D '(') + trace_probe_log_err(ctx->offset, TOO_MANY_NESTED); + else + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + 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; @@ -1715,26 +1714,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 */ @@ -1995,12 +2080,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 e6aee800a7d9..f0958707db8e 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 4= . */ +#define TRACEPROBE_MAX_NESTED_LEVEL 4 + +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..a48ad751b615 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(+0(+0(+0(@0))))))))= ))))))' # TOO_MANY_OPS? 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)file->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..d871ba0b7110 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(+0(+0(+0(@0)))))))))))= )))' # TOO_MANY_OPS? 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..c93d5f2612fd 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(+0(+0(+0(@0))))))))= ))))))' # TOO_MANY_OPS? 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)file->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