From nobody Sat Jun 27 16:01:21 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 669693D16E2; Mon, 8 Jun 2026 14:24:31 +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=1780928672; cv=none; b=iRW5OznlThQJFX3JdxLLkT6ysKgUWWhF15hEtw/PWTGBMkoK6T+eSd57bRJrUzOz1yBLdPD1KcenDQe33TxUKu8yWm1RkpqRhxgul04xENHmjspIBv8XatDBII+Jy9qxhpnwcvmpsopJyH/eOcfXdM/rvCNtQ5Mx7mqOsKJDifU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928672; c=relaxed/simple; bh=V0c+IyF3SscrcA6Rf9PobeT44GuZn6nth30MNP0OUkw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gZ52ggVUCIBuLanPf2mgd9L9js4yNORWy2SkaVwPgAkdHIohKY9FybPgfKu7YaoDzYrNOtPI18b6m2/L2et8aD4lxJFP8MwUr0wS4vPRyhJPZ8B+FSPzRKw8C28VD8pewFKLi1odGeUe1OezhUbyllZBJwgXS99Syl0xRN5dvtk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MAVuL7iG; 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="MAVuL7iG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A8BE1F00893; Mon, 8 Jun 2026 14:24:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928671; bh=y2S0cH7Hc5ycetv8oxZAkbKoW30tIBWPCidb4Za0kqg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MAVuL7iGEFS8S4rELvRF9IWcrU7Ph/6KLLbfrhc0gz8G9tkXLEb5s6zScLEZOX/Of KW1NhEzlgD6JvQGDQEm+zNjhm6yicJcI7eGZrH2ocnz9+ePyTKlqMglWWRqeZbWLE6 /qct2oSBnRvLIkBBsT18EQfpBlG9hvHekwe/Mbzfu4hMrTu+w8Po0ch9+Z+nIJ8+dP TA3lNqHU+Vz4rzhdrjLyocG4dGlLDs9scZ6f3vZvJ65uVcGiI3cZNOdj5QEyTFpi+w RqinfXMsVOfVsiZ678ZJpAzYSkOBNvfBVzoLD+gTlM7tSFY1zxNsZ9MUtKZLDXI2Kh WNnOi+K2setnA== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 1/7] tracing/probes: Support typecast for various probe events Date: Mon, 8 Jun 2026 23:24:26 +0900 Message-ID: <178092866688.163648.6670468618889245533.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) Support BTF typecast feature on other probe events (but only if it is kernel function entry or return.) To support other probe events, we just need to use last_struct type when we find a function parameter in parse_btf_arg(). This also update /README file to show struct typecast. Signed-off-by: Masami Hiramatsu (Google) --- Documentation/trace/fprobetrace.rst | 3 +++ Documentation/trace/kprobetrace.rst | 4 ++++ kernel/trace/trace.c | 2 +- kernel/trace/trace_probe.c | 12 +++++++----- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index b4c2ca3d02c1..7435ded2d66d 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -57,6 +57,9 @@ Synopsis of fprobe-events (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types (x8/x16/x32/x64), "char", "string", "ustring", "symbol",= "symstr" and bitfield are supported. + (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to + a pointer to STRUCT and then derference the pointer defi= ned by + ->MEMBER. =20 (\*1) This is available only when BTF is enabled. (\*2) only for the probe on function entry (offs =3D=3D 0). Note, this a= rgument access diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kpro= betrace.rst index 3b6791c17e9b..f73614997d52 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -61,6 +61,10 @@ Synopsis of kprobe_events (x8/x16/x32/x64), VFS layer common type(%pd/%pD), "char", "string", "ustring", "symbol", "symstr" and bitfield are supported. + (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to + a pointer to STRUCT and then derference the pointer defi= ned by + ->MEMBER. Note that this is available only when the prob= e is + on function entry. =20 (\*1) only for the probe on function entry (offs =3D=3D 0). Note, this a= rgument access is best effort, because depending on the argument type, it may be = passed on diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 6eb4d3097a4d..aa93e7b01146 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4325,7 +4325,7 @@ static const char readme_msg[] =3D #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API "\t $stack, $stack, $retval, $comm, $arg,\n" #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS - "\t [->field[->field|.field...]],\n" + "\t [(structname)][->field[->field|.field...]],\n" #endif #else "\t $stack, $stack, $retval, $comm,\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index fd1caa1f9723..609b156986c5 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -759,7 +759,10 @@ static int parse_btf_arg(char *varname, return -ENOENT; =20 found: - type =3D btf_type_skip_modifiers(ctx->btf, tid, &tid); + if (ctx->struct_btf) + type =3D ctx->last_struct; + else + type =3D btf_type_skip_modifiers(ctx->btf, tid, &tid); found_type: if (!type) { trace_probe_log_err(ctx->offset, BAD_BTF_TID); @@ -836,10 +839,9 @@ static int handle_typecast(char *arg, struct fetch_ins= n **pcode, char *tmp; int ret; =20 - /* Currently this only works for eprobes */ - if (!(ctx->flags & TPARG_FL_TEVENT)) { - trace_probe_log_err(ctx->offset, TYPECAST_NOT_EVENT); - return -EINVAL; + if (!(tparg_is_function_entry(ctx->flags) || tparg_is_function_return(ctx= ->flags))) { + trace_probe_log_err(ctx->offset, NOSUP_BTFARG); + return -EOPNOTSUPP; } =20 tmp =3D strchr(arg, ')'); From nobody Sat Jun 27 16:01:21 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 910F81F2B8D; Mon, 8 Jun 2026 14:24:41 +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=1780928682; cv=none; b=kku/+MhpLTH4yvfPTOQZ4LsRbjUYq7MpIDd9ufzALlPii3lxDDj6KJwcB7Xk0xjixjxWUw+ZtRVjZxXV1hL9plyu7K6BHKZdDYXEoyvtdBw+HL005ccyK99kKQ1a2cXKm/wP34yxJbDvZLxddhyAhq4clguKam7i83tt+09QOt8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928682; c=relaxed/simple; bh=uDa54GWYMrkBxHaq5K9lowraTi4tuG5uV8fAXG8gle8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iDFX90AFgSuQqa45IIPYbjVtXTPFw0PoxVqhVAo1gWLZFjA1l20+IfcbIuPgNUEWIL7ad0UIAu9LQu+p7RYt5EoKyApfssvVB9Xgwj+sX3W+G/5YNridcQfNNSVGMl62+o4rjWSs0c3MAzaPOoI78BGn1ZAiVUXT5TkEhcQyDU8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R/3T+Dm1; 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="R/3T+Dm1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E58E41F00893; Mon, 8 Jun 2026 14:24:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928681; bh=K04Y1frCYdc/og8m1FwqqV5Jgd0jJFUJxq4j5GJ5Zaw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=R/3T+Dm1mBNK17pHZZQ7n/m8xt0h6N44zDNrCPEgOtRzfyF4QG/HOUEgXu1YwNtDV HF/zrkNBkNUptyzZy6RCFyx6HPvOiWukY2+CsTsBVhm3U5j4cdLERU2wsqrG8vEL1R HZSJwLgSRC23OgEfjBwLsX1MVz0py8mXAolVKxFSeEqsoTveBBx5THYmLSIl6biF9Q Fc5GlgkkQv498xNUA0Z0NknytZdQBxu/aQolz7/ADFxDV4vPRNb5TLArRIV9fJf3TG T1SoJ1XbJdbEivcIKJfnh/IW7l+BwwPSWZUQmNxAnmNLqO1Wx/hHk1fDpZZ8sewjC3 T5jhm9dCLVgpg== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 2/7] tracing/probes: Support nested typecast Date: Mon, 8 Jun 2026 23:24:36 +0900 Message-ID: <178092867670.163648.6658248217596569592.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) When we hit an open parenthesis right after typecast closing parenthesis, it means we have nested typecast. This allows us to typecast a generic data member in a structure to a pointer to another structure. For example, to cast a DATA_MEMBER of VAR structure to STRUCT pointer and get MEMBER value. (STRUCT)(VAR->DATA_MEMBER)->MEMBER Also, we can nest typecast. (STRUCT1)((STRUCT2)$ARG->FIELD2)->FIELD1 Currently the max nest level is limited to 3. Signed-off-by: Masami Hiramatsu (Google) --- Documentation/trace/eprobetrace.rst | 2 + Documentation/trace/fprobetrace.rst | 2 + Documentation/trace/kprobetrace.rst | 2 + kernel/trace/trace.c | 1=20 kernel/trace/trace_probe.c | 76 +++++++++++++++++++++++++++++++= +--- kernel/trace/trace_probe.h | 7 +++ 6 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Documentation/trace/eprobetrace.rst b/Documentation/trace/epro= betrace.rst index fe3602540569..cd0b4aa7f896 100644 --- a/Documentation/trace/eprobetrace.rst +++ b/Documentation/trace/eprobetrace.rst @@ -50,6 +50,8 @@ Synopsis of eprobe_events a pointer to STRUCT and then derference the pointer defi= ned by ->MEMBER. Note that when this is used, the FIELD name do= es not need to be prefixed with a '$'. + (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an + also be used with another FETCHARG instead of FIELD. =20 Types ----- diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index 7435ded2d66d..6b8bb27bb62d 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -60,6 +60,8 @@ Synopsis of fprobe-events (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to a pointer to STRUCT and then derference the pointer defi= ned by ->MEMBER. + (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an + also be used with another FETCHARG instead of FIELD. =20 (\*1) This is available only when BTF is enabled. (\*2) only for the probe on function entry (offs =3D=3D 0). Note, this a= rgument access diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kpro= betrace.rst index f73614997d52..c4382765d5b2 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -65,6 +65,8 @@ Synopsis of kprobe_events a pointer to STRUCT and then derference the pointer defi= ned by ->MEMBER. Note that this is available only when the prob= e is on function entry. + (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an + also be used with another FETCHARG instead of FIELD. =20 (\*1) only for the probe on function entry (offs =3D=3D 0). Note, this a= rgument access is best effort, because depending on the argument type, it may be = passed on diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index aa93e7b01146..4f70318918c2 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4326,6 +4326,7 @@ static const char readme_msg[] =3D "\t $stack, $stack, $retval, $comm, $arg,\n" #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS "\t [(structname)][->field[->field|.field...]],\n" + "\t [(structname)](fetcharg)->field[->field|.field...],\n" #endif #else "\t $stack, $stack, $retval, $comm,\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 609b156986c5..ddd9b1b63a17 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -832,10 +832,35 @@ static int query_btf_struct(const char *sname, struct= traceprobe_parse_context * return 0; } =20 +/* Find the matching closing parenthesis for a given opening parenthesis. = */ +static char *find_matched_close_paren(char *s) +{ + char *p =3D s; + int count =3D 0; + + while (*p) { + if (*p =3D=3D '(') + count++; + else if (*p =3D=3D ')') { + if (--count =3D=3D 0) + return p; + } + p++; + } + return NULL; +} + +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 handle_typecast(char *arg, struct fetch_insn **pcode, struct fetch_insn *end, struct traceprobe_parse_context *ctx) { + int orig_offset =3D ctx->offset; + bool nested =3D false; char *tmp; int ret; =20 @@ -850,19 +875,56 @@ static int handle_typecast(char *arg, struct fetch_in= sn **pcode, DEREF_OPEN_BRACE); return -EINVAL; } - *tmp =3D '\0'; - ret =3D query_btf_struct(arg + 1, ctx); - *tmp =3D ')'; + *tmp++ =3D '\0'; + + /* Handle the nested structure like (STRUCT)(VAR->FIELD)->... */ + if (*tmp =3D=3D '(') { + char *close =3D find_matched_close_paren(tmp); + + ctx->offset +=3D tmp - arg; + if (!close) { + trace_probe_log_err(ctx->offset, DEREF_OPEN_BRACE); + return -EINVAL; + } + /* We expect a field access for typecast */ + if (close[1] !=3D '-' || close[2] !=3D '>') { + trace_probe_log_err(ctx->offset + close - tmp + 1, + TYPECAST_REQ_FIELD); + return -EINVAL; + } =20 + ctx->nested_level++; + if (ctx->nested_level > TRACEPROBE_MAX_NESTED_LEVEL) { + trace_probe_log_err(ctx->offset, TOO_MANY_NESTED); + return -E2BIG; + } + *close =3D '\0'; + + ctx->offset +=3D 1; /* for the '(' */ + /* We need to parse the nested one */ + ret =3D parse_probe_arg(tmp + 1, find_fetch_type(NULL, ctx->flags), + pcode, end, ctx); + if (ret < 0) + return ret; + ctx->nested_level--; + clear_struct_btf(ctx); + + tmp =3D close + 1; + nested =3D true; + } + + ret =3D query_btf_struct(arg + 1, ctx); if (ret < 0) { trace_probe_log_err(ctx->offset + 1, NO_PTR_STRCT); return -EINVAL; } =20 - tmp++; - - ctx->offset +=3D tmp - arg; - ret =3D parse_btf_arg(tmp, pcode, end, ctx); + ctx->offset =3D orig_offset + tmp - arg; + /* If it is nested, tmp points to the field name. */ + if (nested) + ret =3D parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx); + else + ret =3D parse_btf_arg(tmp, pcode, end, ctx); return ret; } =20 diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 15758cc11fc6..8dcc65e4e1db 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -430,8 +430,11 @@ struct traceprobe_parse_context { struct trace_probe *tp; unsigned int flags; int offset; + int nested_level; }; =20 +#define TRACEPROBE_MAX_NESTED_LEVEL 3 + extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *argv, struct traceprobe_parse_context *ctx); @@ -566,7 +569,9 @@ extern int traceprobe_define_arg_fields(struct trace_ev= ent_call *event_call, 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(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"), =20 #undef C #define C(a, b) TP_ERR_##a From nobody Sat Jun 27 16:01:21 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 DFDCF3D34A4; Mon, 8 Jun 2026 14:24:50 +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=1780928692; cv=none; b=hEAeOgImDtNd+zya1rkfXAmUz5/uXZFm19KZAAZFDahDGeHzdf6s4xdm7GSMWlcB6zkxymBjYH9uJ5rbxyxSOGTIBsxZUKL3Fi9YxosEcg/bw/lMv5S/8uJ0uPL5RNlrBfuocYZxJ+28S31ZX3HeSnJoS7k18ajtyjm/4kn0B1g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928692; c=relaxed/simple; bh=EFimOQdJA9cXFHekDnMJHoF8R6IirVT6k+ThEpOV0D8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=d60l66pV5yxUOvmna1LPqlpTsfDgNu56wG7GFYlYe7fzevRsQ3/Az3SNVoegpp1Hk5Q5EJ7FlMerrdWZ1AZeere6J/H57GdOiiEEbaGofjL/venw7EhuM5GLt85cSpyGEUlPqvhluN3fRKlAsBQ/Q1KXb40yJmVlzExFlFlU778= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OwASHI6i; 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="OwASHI6i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BC5051F00893; Mon, 8 Jun 2026 14:24:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928690; bh=fwiXlThn0od5ilLjGbcur1/XCtdOPyk7xKrb5RYE+bw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=OwASHI6iQaXHSRFBEFFWM07kiOxtVklAtzfaGh3FCN4ijNG+GyJ8lbvPEOvLJs/pu bjEk5YePgwwxb3cI8g0WAjvvryIu2Qm+yBhOKAwjJkO+aeub7RAldA3UT7P54hRrbn Q6CA7hulJ4BKov9FOw51HZi0lj/PnjbwR4FRBMpr40q5+SIabL1lq5xlr2+cni6WAs /qGinBknNVDwyMrCMwsIWF805Tt7CWKEC71a9zVrqMoPRQmK7SKImW7d3RhCJBuv6A D7MRD4hlvtVa4Y4b32xum+TQEZpwZ5qRU215Lxm1bxIG3pGtq3OgVAOZZDCWTymMHG Xr4AVO26v9kuQ== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 3/7] tracing/probes: Support field specifier option for typecast Date: Mon, 8 Jun 2026 23:24:46 +0900 Message-ID: <178092868655.163648.6822850065797972881.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) Add a field specifier option for the typecast. This works like container_of() macro. (STRUCT[,FIELD[.FIELD2...]])VAR This is equivalent to : container_of(VAR, struct STRUCT, FIELD[.FIELD2...]) For example: echo "f tick_nohz_handler next_tick=3D(tick_sched,sched_timer)timer->next_= tick" >> dynamic_events This will trace tick_nohz_handler() with its tick_sched::next_tick which is converted from @timer by contianer_of(tick, struct tick_sched, sched_tim= er). So, if you enabkle both fprobes:tick_nohz_handler__entry and timer:hrtimer_expire_entry events, we will see something like: -0 [002] d.h1. 3778.087272: hrtimer_expire_entry: hr= timer=3D00000000d63db328 f unction=3Dtick_nohz_handler now=3D3777450051040 -0 [002] d.h1. 3778.087281: tick_nohz_handler__entry= : (tick_nohz_handler+0x4 /0x140) next_tick=3D3777450000000 Signed-off-by: Masami Hiramatsu (Google) --- Documentation/trace/eprobetrace.rst | 5 + Documentation/trace/fprobetrace.rst | 8 +- Documentation/trace/kprobetrace.rst | 8 +- kernel/trace/trace.c | 4 - kernel/trace/trace_probe.c | 169 +++++++++++++++++++++++--------= ---- kernel/trace/trace_probe.h | 4 + 6 files changed, 131 insertions(+), 67 deletions(-) diff --git a/Documentation/trace/eprobetrace.rst b/Documentation/trace/epro= betrace.rst index cd0b4aa7f896..680e0af43d5d 100644 --- a/Documentation/trace/eprobetrace.rst +++ b/Documentation/trace/eprobetrace.rst @@ -49,7 +49,10 @@ Synopsis of eprobe_events (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to a pointer to STRUCT and then derference the pointer defi= ned by ->MEMBER. Note that when this is used, the FIELD name do= es not - need to be prefixed with a '$'. + need to be prefixed with a '$'. ASGN can be specified op= tionally. + If ASGN is specified, FIELD will be cast to the same offset + position as the ASGN member, rather than to the beginning of + the STRUCT. (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an also be used with another FETCHARG instead of FIELD. =20 diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index 6b8bb27bb62d..290a9e6f7491 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -57,10 +57,12 @@ Synopsis of fprobe-events (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types (x8/x16/x32/x64), "char", "string", "ustring", "symbol",= "symstr" and bitfield are supported. - (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to + (STRUCT[,ASGN])FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast F= IELD to a pointer to STRUCT and then derference the pointer defi= ned by - ->MEMBER. - (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an + ->MEMBER. ASGN can be specified optionally. If ASGN is s= pecified, + FIELD will be cast to the same offset position as the ASGN member, + rather than to the beginning of the STRUCT. + (STRUCT[,ASGN])(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the = above can also be used with another FETCHARG instead of FIELD. =20 (\*1) This is available only when BTF is enabled. diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kpro= betrace.rst index c4382765d5b2..a62707e6a9f2 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -61,11 +61,13 @@ Synopsis of kprobe_events (x8/x16/x32/x64), VFS layer common type(%pd/%pD), "char", "string", "ustring", "symbol", "symstr" and bitfield are supported. - (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to + (STRUCT[,ASGN])FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast F= IELD to a pointer to STRUCT and then derference the pointer defi= ned by ->MEMBER. Note that this is available only when the prob= e is - on function entry. - (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above c= an + on function entry. ASGN can be specified optionally. If ASGN + is specified, FIELD will be cast to the same offset position + as the ASGN member, rather than to the beginning of the STRUCT. + (STRUCT[,ASGN])(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the = above can also be used with another FETCHARG instead of FIELD. =20 (\*1) only for the probe on function entry (offs =3D=3D 0). Note, this a= rgument access diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4f70318918c2..0e36af853199 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4325,8 +4325,8 @@ static const char readme_msg[] =3D #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API "\t $stack, $stack, $retval, $comm, $arg,\n" #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS - "\t [(structname)][->field[->field|.field...]],\n" - "\t [(structname)](fetcharg)->field[->field|.field...],\n" + "\t [(structname[,field])][->field[->field|.field...]]= ,\n" + "\t [(structname[,field])](fetcharg)->field[->field|.field...],= \n" #endif #else "\t $stack, $stack, $retval, $comm,\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index ddd9b1b63a17..ff0b619e9a90 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -574,6 +574,65 @@ static int split_next_field(char *varname, char **next= _field, return ret; } =20 +/* Inner loop for solving dot operator ('.'). Return bit-offset of the giv= en field */ +static int get_bitoffset_of_field(char **pfieldname, const struct btf_type= **ptype, + struct traceprobe_parse_context *ctx) +{ + const struct btf_type *type =3D *ptype; + const struct btf_member *field; + struct btf *btf =3D ctx_btf(ctx); + char *fieldname =3D *pfieldname; + int bitoffs =3D 0; + u32 anon_offs; + char *next; + int is_ptr; + s32 tid; + + do { + next =3D NULL; + is_ptr =3D split_next_field(fieldname, &next, ctx); + if (is_ptr < 0) + return is_ptr; + + anon_offs =3D 0; + field =3D btf_find_struct_member(btf, type, fieldname, + &anon_offs); + if (IS_ERR(field)) { + trace_probe_log_err(ctx->offset, BAD_BTF_TID); + return PTR_ERR(field); + } + if (!field) { + trace_probe_log_err(ctx->offset, NO_BTF_FIELD); + return -ENOENT; + } + /* Add anonymous structure/union offset */ + bitoffs +=3D anon_offs; + + /* Accumulate the bit-offsets of the dot-connected fields */ + if (btf_type_kflag(type)) { + bitoffs +=3D BTF_MEMBER_BIT_OFFSET(field->offset); + ctx->last_bitsize =3D BTF_MEMBER_BITFIELD_SIZE(field->offset); + } else { + bitoffs +=3D field->offset; + ctx->last_bitsize =3D 0; + } + + type =3D btf_type_skip_modifiers(btf, field->type, &tid); + if (!type) { + trace_probe_log_err(ctx->offset, BAD_BTF_TID); + return -EINVAL; + } + + if (next) + ctx->offset +=3D next - fieldname; + fieldname =3D next; + } while (!is_ptr && fieldname); + + *pfieldname =3D fieldname; + *ptype =3D type; + + return bitoffs; +} /* * Parse the field of data structure. The @type must be a pointer type * pointing the target data structure type. @@ -583,16 +642,14 @@ static int parse_btf_field(char *fieldname, const str= uct btf_type *type, struct traceprobe_parse_context *ctx) { struct fetch_insn *code =3D *pcode; - const struct btf_member *field; - u32 bitoffs, anon_offs; - bool is_struct =3D ctx->struct_btf !=3D NULL; struct btf *btf =3D ctx_btf(ctx); - char *next; - int is_ptr; + bool is_first_field =3D true; + int bitoffs; s32 tid; =20 do { - if (!is_struct) { + /* For the first field of typecast, @type will be the target structure t= ype. */ + if (!(is_first_field && ctx->struct_btf)) { /* Outer loop for solving arrow operator ('->') */ if (BTF_INFO_KIND(type->info) !=3D BTF_KIND_PTR) { trace_probe_log_err(ctx->offset, NO_PTR_STRCT); @@ -606,60 +663,25 @@ static int parse_btf_field(char *fieldname, const str= uct btf_type *type, return -EINVAL; } } - /* Only the first type can skip being a pointer */ - is_struct =3D false; - - bitoffs =3D 0; - do { - /* Inner loop for solving dot operator ('.') */ - next =3D NULL; - is_ptr =3D split_next_field(fieldname, &next, ctx); - if (is_ptr < 0) - return is_ptr; - - anon_offs =3D 0; - field =3D btf_find_struct_member(btf, type, fieldname, - &anon_offs); - if (IS_ERR(field)) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); - return PTR_ERR(field); - } - if (!field) { - trace_probe_log_err(ctx->offset, NO_BTF_FIELD); - return -ENOENT; - } - /* Add anonymous structure/union offset */ - bitoffs +=3D anon_offs; - - /* Accumulate the bit-offsets of the dot-connected fields */ - if (btf_type_kflag(type)) { - bitoffs +=3D BTF_MEMBER_BIT_OFFSET(field->offset); - ctx->last_bitsize =3D BTF_MEMBER_BITFIELD_SIZE(field->offset); - } else { - bitoffs +=3D field->offset; - ctx->last_bitsize =3D 0; - } - - type =3D btf_type_skip_modifiers(btf, field->type, &tid); - if (!type) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); - return -EINVAL; - } - - ctx->offset +=3D next - fieldname; - fieldname =3D next; - } while (!is_ptr && fieldname); =20 + bitoffs =3D get_bitoffset_of_field(&fieldname, &type, ctx); + if (bitoffs < 0) + return bitoffs; if (++code =3D=3D end) { trace_probe_log_err(ctx->offset, TOO_MANY_OPS); return -EINVAL; } code->op =3D FETCH_OP_DEREF; /* TODO: user deref support */ + if (is_first_field && ctx->struct_btf) { + /* The first field can be typecasted with field option. */ + bitoffs -=3D ctx->prefix_bitoffs; + } code->offset =3D bitoffs / 8; *pcode =3D code; =20 ctx->last_bitoffs =3D bitoffs % 8; ctx->last_type =3D type; + is_first_field =3D false; } while (fieldname); =20 return 0; @@ -700,8 +722,7 @@ static int parse_btf_arg(char *varname, /* TEVENT is only here via a typecast */ if (WARN_ON_ONCE(ctx->struct_btf =3D=3D NULL)) return -EINVAL; - type =3D ctx->last_struct; - goto found_type; + goto found; } =20 if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { @@ -763,7 +784,6 @@ static int parse_btf_arg(char *varname, type =3D ctx->last_struct; else type =3D btf_type_skip_modifiers(ctx->btf, tid, &tid); -found_type: if (!type) { trace_probe_log_err(ctx->offset, BAD_BTF_TID); return -EINVAL; @@ -832,6 +852,41 @@ static int query_btf_struct(const char *sname, struct = traceprobe_parse_context * return 0; } =20 +static int parse_btf_casttype(char *casttype, struct traceprobe_parse_cont= ext *ctx) +{ + char *field; + int ret; + + /* Field option - evaluated later. */ + field =3D strchr(casttype, ','); + if (field) + *field++ =3D '\0'; + + ret =3D query_btf_struct(casttype, ctx); + if (ret < 0) { + trace_probe_log_err(ctx->offset, NO_PTR_STRCT); + return -EINVAL; + } + + if (field) { + struct btf_type *type =3D (struct btf_type *)ctx->last_struct; + + ctx->offset +=3D field - casttype; + ret =3D get_bitoffset_of_field(&field, &ctx->last_struct, ctx); + if (ret < 0) + return ret; + if (ret % 8) { + trace_probe_log_err(ctx->offset, TYPECAST_NOT_ALIGNED); + return -EINVAL; + } + ctx->prefix_bitoffs =3D ret; + /* Restore the original struct type (overwritten by get_bitoffset_of_fie= ld) */ + ctx->last_struct =3D type; + } + + return ret; +} + /* Find the matching closing parenthesis for a given opening parenthesis. = */ static char *find_matched_close_paren(char *s) { @@ -913,11 +968,10 @@ static int handle_typecast(char *arg, struct fetch_in= sn **pcode, nested =3D true; } =20 - ret =3D query_btf_struct(arg + 1, ctx); - if (ret < 0) { - trace_probe_log_err(ctx->offset + 1, NO_PTR_STRCT); - return -EINVAL; - } + ctx->offset =3D orig_offset + 1; /* for the '(' */ + ret =3D parse_btf_casttype(arg + 1, ctx); + if (ret < 0) + return ret; =20 ctx->offset =3D orig_offset + tmp - arg; /* If it is nested, tmp points to the field name. */ @@ -925,6 +979,7 @@ static int handle_typecast(char *arg, struct fetch_insn= **pcode, ret =3D parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx); else ret =3D parse_btf_arg(tmp, pcode, end, ctx); + ctx->prefix_bitoffs =3D 0; return ret; } =20 diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 8dcc65e4e1db..b1a54da3c761 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -431,6 +431,7 @@ struct traceprobe_parse_context { unsigned int flags; int offset; int nested_level; + int prefix_bitoffs; /* The bit offset of the prefix field of typecast */ }; =20 #define TRACEPROBE_MAX_NESTED_LEVEL 3 @@ -571,7 +572,8 @@ extern int traceprobe_define_arg_fields(struct trace_ev= ent_call *event_call, C(EVENT_TOO_BIG, "Event too big (too many fields?)"), \ 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(TOO_MANY_NESTED, "Too many nested typecasts/dereferences"), \ + C(TYPECAST_NOT_ALIGNED, "Typecast field option is not byte-aligned"), =20 #undef C #define C(a, b) TP_ERR_##a From nobody Sat Jun 27 16:01:21 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 09E463D34A4; Mon, 8 Jun 2026 14:25:00 +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=1780928702; cv=none; b=A2yrKI8qi1XuACVuTmXQHUouyuT6xR/QQZ/gJ5ii13SzuJ3V+GpO7vcpjSRXcka2+ITNm3xncQFXeuDwCLS8RXBw/aeFobFPr7PmA7nfcJ1yxQgfzBrqdnf2M2eQUE4QqQpwV0hoCAIyihbGmVt6tEMe2Ia1FEuYY//9HrbFLOU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928702; c=relaxed/simple; bh=mZYqD+WxyQ1SlDs/mXsKtQBftb99G0BzFoyKO0yat9c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bgMbHAmWH1iL9fVftNorMiKbaG36+w5klXCmQdpltZSH/8P6nIXanOEW0c0x5FMnu8oZIEzgUNiqdJUfc9ivgS8jbphd+oUf4iuAndwpXsa4ufehPrQ/m2I8HdATe9zF3pMXMjkF9ivdKz31WWafhjpU2/34GIFrgnA/iyyj2Z0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=U+jr3feM; 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="U+jr3feM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 792901F00893; Mon, 8 Jun 2026 14:24:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928700; bh=8qTAGqtGn3AZzYpmsSksil2kynfsaWnAEpF5s06Uqnk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=U+jr3feMdP3z3SVsfKgRyywuv0kaS18QSg3xunSzLI7wdSK14lYkQXTF32jNwspsq H7hHRhjgnrSCxCSO0HPkCrrLW5LyQUEMHDnva2RhB1OmY+rPeXpfOKAcxao7p9FVXX afOeVLOkHRFH/rKK2gdR+4Uq7omoa/6FLdPhFyhZEUv6867KjWNHLtdkOhuntrnugn 5PftoG9ZQMUd1NP5KP+iqQozdhBNeCQ9tBHMpMB/Szus8asBstu4bRexRah6UiZa1b GoBZVBKAHk5yeWp2UCSe4WsAeFy+tcKXQO6glj+3A4AvmNY3S38/40v4EnArcAllJk 3YpgpTJM6+WTg== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 4/7] tracing/probes: Add $current variable support Date: Mon, 8 Jun 2026 23:24:56 +0900 Message-ID: <178092869618.163648.515347808636675462.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) Since we can use the BTF to cast value to a structure pointer type, it is useful to introduce "$current" special variable support to fetcharg. User can define a fetcharg to access current task_struct properties using BTF typecast (or dereference - but this may be complicated) e.g. (task_struct)$current->cpus_ptr Signed-off-by: Masami Hiramatsu (Google) --- Documentation/trace/eprobetrace.rst | 1 + Documentation/trace/fprobetrace.rst | 1 + Documentation/trace/kprobetrace.rst | 1 + kernel/trace/trace.c | 2 +- kernel/trace/trace_probe.c | 6 ++++++ kernel/trace/trace_probe.h | 1 + kernel/trace/trace_probe_tmpl.h | 3 +++ 7 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/trace/eprobetrace.rst b/Documentation/trace/epro= betrace.rst index 680e0af43d5d..dcf92d5b4175 100644 --- a/Documentation/trace/eprobetrace.rst +++ b/Documentation/trace/eprobetrace.rst @@ -38,6 +38,7 @@ Synopsis of eprobe_events @ADDR : Fetch memory at ADDR (ADDR should be in kernel) @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbo= l) $comm : Fetch current task comm. + $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\= *4) \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index 290a9e6f7491..3392cab016b3 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -50,6 +50,7 @@ Synopsis of fprobe-events $argN : Fetch the Nth function argument. (N >=3D 1) (\*2) $retval : Fetch return value.(\*3) $comm : Fetch current task comm. + $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*4)(\= *5) \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kpro= betrace.rst index a62707e6a9f2..81e4fe38791d 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -53,6 +53,7 @@ Synopsis of kprobe_events $argN : Fetch the Nth function argument. (N >=3D 1) (\*1) $retval : Fetch return value.(\*2) $comm : Fetch current task comm. + $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\= *4) \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0e36af853199..e185a006cb08 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4329,7 +4329,7 @@ static const char readme_msg[] =3D "\t [(structname[,field])](fetcharg)->field[->field|.field...],= \n" #endif #else - "\t $stack, $stack, $retval, $comm,\n" + "\t $stack, $stack, $retval, $comm, $current\n" #endif "\t +|-[u](), \\imm-value, \\\"imm-string\"\n" "\t kernel return probes support: $retval, $arg, $comm\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index ff0b619e9a90..2c5deb1e1463 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1235,6 +1235,12 @@ static int parse_probe_vars(char *orig_arg, const st= ruct fetch_type *t, return 0; } =20 + /* $current returns the address of the current task_struct. */ + if (strcmp(arg, "current") =3D=3D 0) { + code->op =3D FETCH_OP_CURRENT; + return 0; + } + #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API len =3D str_has_prefix(arg, "arg"); if (len) { diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index b1a54da3c761..f2b31089779c 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -96,6 +96,7 @@ enum fetch_op { FETCH_OP_FOFFS, /* File offset: .immediate */ FETCH_OP_DATA, /* Allocated data: .data */ FETCH_OP_EDATA, /* Entry data: .offset */ + FETCH_OP_CURRENT, /* Current task_struct address */ // Stage 2 (dereference) op FETCH_OP_DEREF, /* Dereference: .offset */ FETCH_OP_UDEREF, /* User-space Dereference: .offset */ diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmp= l.h index f39b37fcdb3b..f630930288d2 100644 --- a/kernel/trace/trace_probe_tmpl.h +++ b/kernel/trace/trace_probe_tmpl.h @@ -112,6 +112,9 @@ process_common_fetch_insn(struct fetch_insn *code, unsi= gned long *val) case FETCH_OP_DATA: *val =3D (unsigned long)code->data; break; + case FETCH_OP_CURRENT: + *val =3D (unsigned long)current; + break; default: return -EILSEQ; } From nobody Sat Jun 27 16:01:21 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 CA4753D6692; Mon, 8 Jun 2026 14:25:10 +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=1780928712; cv=none; b=NNcoM8qIf2AoXKN7qy1QjaIH8MFto8wXkeXEVXBP5tTzMnoNCCXAk63c1MYLpX2WyoW6cJrvCCPFtrtxcZiDWsnQBsusbQ4Re1lt7JBA1G+glhwCaML5TyawVtVWGkW5koW7ii0mhlw8o9C8tphO8D2mAwZ92LEGZ6Hk5ijwAbQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928712; c=relaxed/simple; bh=HZJtSvOJll4jTVWRRxieHiVVjPwzVlIrDAhkyhTBbaQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hb+lu7ImBkoTuGZhQeFXisSLqrzkAJM17rpqYhJIjKoNr+UitpZEmbV/TgdxApxP9BEpfV37Zia2fNwIx94IpbxBGRX2By+nmcn8l9sBf4IkDXCObon44whLJZDqqMR5WA0RqCtOP1NdRlZwSqVx4gxHoHcHw/PAg25gmsatS7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=afT52TO0; 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="afT52TO0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6953F1F00893; Mon, 8 Jun 2026 14:25:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928710; bh=wtjV5ZRRw8hPfEPfsfZ4zbPwmpEihOdeIGlBAiEVMEk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=afT52TO0XaH0Txcj98Cq0DVhh4JKKtOQQWUKpgfk4ZtCaBkTB2l2LM/CfA1Gq1M6a 2iWH5SEW+lhF247VlSzTB3t9OhoNJZHSOBQm1/p40fgsP1WevWtpWp9sgqxwUfyu8q qLUlCCHobPng70IbVdjBk9DcUh9rdJlaxqi/3uoss+uvASXxZFusWEQU6usc22lx5j ybu7KK+GR2MJuIcjhqsD5GgB/7ggFJfmpEuVmOxuZYfekHmxtXqqkeejJO+9Q85RDQ t8tWUnP++asNklqwel613qR/sLuiv//14tZNtTcCYqFBdMtA7Oy1gZz8yWkzE0Dee2 C/oRZ/hgT2JpQ== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 5/7] tracing/probes: Add +CPU() and +PCPU() dereference method to fetcharg Date: Mon, 8 Jun 2026 23:25:06 +0900 Message-ID: <178092870611.163648.7277795674989278181.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) When tracing the kernel local variables, sometimes we need to get the CPU local variables. To access it, current simple dereference is not enough. Thus, introduce a special +CPU() dereference to access per-cpu variable for the current CPU (accessing other CPU variable may race with updates on other CPUs). Also +PCPU() is for accessing per-cpu pointer. +CPU(pcp) is equal to this_cpu_read(pcp) And +PCPU(pcp) is equal to this_cpu_ptr(pcp) Signed-off-by: Masami Hiramatsu (Google) --- Documentation/trace/eprobetrace.rst | 3 ++ Documentation/trace/fprobetrace.rst | 3 ++ Documentation/trace/kprobetrace.rst | 3 ++ kernel/trace/trace.c | 1 + kernel/trace/trace_probe.c | 48 +++++++++++++++++++++----------= ---- kernel/trace/trace_probe.h | 2 + kernel/trace/trace_probe_tmpl.h | 30 ++++++++++++++++++---- 7 files changed, 65 insertions(+), 25 deletions(-) diff --git a/Documentation/trace/eprobetrace.rst b/Documentation/trace/epro= betrace.rst index dcf92d5b4175..0c7878df02f6 100644 --- a/Documentation/trace/eprobetrace.rst +++ b/Documentation/trace/eprobetrace.rst @@ -40,6 +40,9 @@ Synopsis of eprobe_events $comm : Fetch current task comm. $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\= *4) + +CPU(FETCHARG) : Fetch memory at FETCHARG address on the CPU specified b= y CPU. + This is useful for fetching per-CPU variables. + +PCPU(FETCHARG) : Fetch memory address at FETCHARG address on the per-CP= U area. \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index 3392cab016b3..c851f98bb310 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -52,6 +52,9 @@ Synopsis of fprobe-events $comm : Fetch current task comm. $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*4)(\= *5) + +CPU(FETCHARG) : Fetch memory at FETCHARG address on the CPU specified b= y CPU. + This is useful for fetching per-CPU variables. + +PCPU(FETCHARG) : Fetch memory address at FETCHARG address on the per-CP= U area. \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kpro= betrace.rst index 81e4fe38791d..bc806fd82a91 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -55,6 +55,9 @@ Synopsis of kprobe_events $comm : Fetch current task comm. $current : Fetch the address of the current task_struct. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\= *4) + +CPU(FETCHARG) : Fetch memory at FETCHARG address on the CPU specified b= y CPU. + This is useful for fetching per-CPU variables. + +PCPU(FETCHARG) : Fetch memory address at FETCHARG address on the per-CP= U area. \IMM : Store an immediate value to the argument. NAME=3DFETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e185a006cb08..2b8c8ac4036a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4332,6 +4332,7 @@ static const char readme_msg[] =3D "\t $stack, $stack, $retval, $comm, $current\n" #endif "\t +|-[u](), \\imm-value, \\\"imm-string\"\n" + "\t +CPU(), +PCPU()\n" "\t kernel return probes support: $retval, $arg, $comm\n" "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol= ,\n" "\t b@/, ustring,\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 2c5deb1e1463..fa6757222fe6 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1396,26 +1396,36 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, =20 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; + if (str_has_prefix(arg, "+CPU(")) { + deref =3D FETCH_OP_DEREF_CPU; + arg +=3D 5; + ctx->offset +=3D 5; + } else if (str_has_prefix(arg, "+PCPU(")) { + deref =3D FETCH_OP_CPU_PTR; + arg +=3D 6; + ctx->offset +=3D 6; + } else { + 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; } - ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); - arg =3D tmp + 1; tmp =3D strrchr(arg, ')'); if (!tmp) { trace_probe_log_err(ctx->offset + strlen(arg), diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index f2b31089779c..bec04bcc4226 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -100,6 +100,8 @@ enum fetch_op { // Stage 2 (dereference) op FETCH_OP_DEREF, /* Dereference: .offset */ FETCH_OP_UDEREF, /* User-space Dereference: .offset */ + FETCH_OP_DEREF_CPU, /* Per-CPU Dereference for this CPU */ + FETCH_OP_CPU_PTR, /* Per-CPU pointer for this CPU */ // Stage 3 (store) ops FETCH_OP_ST_RAW, /* Raw: .size */ FETCH_OP_ST_MEM, /* Mem: .offset, .size */ diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmp= l.h index f630930288d2..82d753decf48 100644 --- a/kernel/trace/trace_probe_tmpl.h +++ b/kernel/trace/trace_probe_tmpl.h @@ -129,25 +129,43 @@ process_fetch_insn_bottom(struct fetch_insn *code, un= signed long val, struct fetch_insn *s3 =3D NULL; int total =3D 0, ret =3D 0, i =3D 0; u32 loc =3D 0; - unsigned long lval =3D val; + unsigned long lval, llval =3D val; =20 stage2: /* 2nd stage: dereference memory if needed */ do { - if (code->op =3D=3D FETCH_OP_DEREF) { - lval =3D val; + lval =3D val; + switch (code->op) { + case FETCH_OP_DEREF: ret =3D probe_mem_read(&val, (void *)val + code->offset, sizeof(val)); - } else if (code->op =3D=3D FETCH_OP_UDEREF) { - lval =3D val; + break; + case FETCH_OP_UDEREF: ret =3D probe_mem_read_user(&val, (void *)val + code->offset, sizeof(val)); - } else break; + case FETCH_OP_DEREF_CPU: + case FETCH_OP_CPU_PTR: + if (!is_kernel_percpu_address(val)) { + ret =3D -EFAULT; + break; + } + val =3D (unsigned long)this_cpu_ptr((void __percpu *)val); + if (code->op =3D=3D FETCH_OP_DEREF_CPU) + ret =3D probe_mem_read(&val, (void *)val, sizeof(val)); + else + ret =3D 0; + break; + default: + lval =3D llval; + goto out; + } if (ret) return ret; + llval =3D lval; code++; } while (1); +out: =20 s3 =3D code; stage3: From nobody Sat Jun 27 16:01:21 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 A5CF33CB8F4; Mon, 8 Jun 2026 14:25:20 +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=1780928721; cv=none; b=fAVMvQ5ONY56ViqpW5cs9ILyBC8aYRLNX50VQwgSmPumHUZ6/yTXL45v6TNz+H2P2GM+rgTQzHKKHDsoLqhIZdfSDOx5K2QL39+jy7456NJ4pSxKDQsU3odqGi3Fw6aeks0QUT+mqSDEwDVuCwKcfBlK+zzQwH3vlbwux3IGpVM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928721; c=relaxed/simple; bh=jjC2TroFZ4GHCUKzT+lReLkVA6zya7eZH2JC/izyyPo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eViWZFZBSDbmaCaIH9K4ftXdgwuo78fy5A36fFlvkw7L81B1PAwqJsL54PBQVp3Mg4rp6LCa/YIuER7YIR3+vNPBbuCRYhV7ApnZyj351oPCgjM6mm9Z9BkXFhcIhMF/VWwzwUaAXFWmJW94npD+H/+C+9YlKtTSRsVi4dPB+yk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lg/jHuIr; 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="lg/jHuIr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 58E7F1F00893; Mon, 8 Jun 2026 14:25:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928720; bh=QaiBhxkgTSsycOO0IquMLBjmDZbI+8btldjP6ELN4Ys=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lg/jHuIr4j8JLH030+n/9wcJYAi+zCoL6XWz9P1JTnNlvFYfOuOg5Ez5PtDri0veI lwlFUU+z2iuuu0XGg4imf26Pn2mmK3wHbNbIwUU73MyywQL/auzl9lTrIRla5UN4Ql Jm5XP3weIldrJf6wsd2BoIh9Pfsi7TTk8muwb56r+e9kwkK/NaNDUEDlQKd/YSK6Jb l9m9aJmV9S67J9qD0TO4pXCct3Ewc/JwrUXldpVNQm7diYQt+TBfP5iYgloJ7ubby6 KaRafBJEdIwC61o0lJuxuEDrxgkuqwQ5kWEA05QCqukCl2fep7DqbvrKDE/g+kZUAk ip6mU6SrEZ12w== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 6/7] tracing/probes: Support reserved this_cpu_ptr() method Date: Mon, 8 Jun 2026 23:25:16 +0900 Message-ID: <178092871603.163648.8025563775854608488.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) The +PCPU() dereference operator was introduced in trace probes to access a per-CPU pointer of a CPU local variable. However, kernel developers are more familiar with the "this_cpu_ptr()" macro. To make trace probe syntax more intuitive and aligned with standard kernel macros, introduce support for "this_cpu_ptr()" as a reserved method. Signed-off-by: Masami Hiramatsu (Google) --- kernel/trace/trace.c | 2 +- kernel/trace/trace_probe.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2b8c8ac4036a..60ab839d0867 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4332,7 +4332,7 @@ static const char readme_msg[] =3D "\t $stack, $stack, $retval, $comm, $current\n" #endif "\t +|-[u](), \\imm-value, \\\"imm-string\"\n" - "\t +CPU(), +PCPU()\n" + "\t +CPU(), +PCPU(), this_cpu_ptr()\n" "\t kernel return probes support: $retval, $arg, $comm\n" "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol= ,\n" "\t b@/, ustring,\n" diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index fa6757222fe6..27be0664cdf3 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1315,6 +1315,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, struct fetch_insn **pcode, struct fetch_insn *end, struct traceprobe_parse_context *ctx) { + static const char *THIS_CPU_PTR_STR =3D "this_cpu_ptr("; struct fetch_insn *code =3D *pcode; unsigned long param; int deref =3D FETCH_OP_DEREF; @@ -1426,6 +1427,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); arg =3D tmp + 1; } +handle_deref: tmp =3D strrchr(arg, ')'); if (!tmp) { trace_probe_log_err(ctx->offset + strlen(arg), @@ -1476,6 +1478,11 @@ parse_probe_arg(char *arg, const struct fetch_type *= type, ret =3D handle_typecast(arg, pcode, end, ctx); break; default: + if (str_has_prefix(arg, THIS_CPU_PTR_STR)) { + arg +=3D strlen(THIS_CPU_PTR_STR); + deref =3D FETCH_OP_CPU_PTR; + goto handle_deref; + } if (isalpha(arg[0]) || arg[0] =3D=3D '_') { /* BTF variable */ if (!tparg_is_function_entry(ctx->flags) && !tparg_is_function_return(ctx->flags)) { From nobody Sat Jun 27 16:01:21 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 DBA493BBFBF; Mon, 8 Jun 2026 14:25:30 +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=1780928732; cv=none; b=SYe8muEDYEFDdlgteFWgDIr93uqU/4KJgd/7PXe7BagUb4zY4T5j7BJPmzLhxRfE5ISEhbssjboE0bmPfGDWqtxfDQnesnBl+Mnm1TO2tsAnHuK4saFJoxMytjwjjnFZlbfIVcUH9AIyUaTvDY46/N2LqYpZ5araKNVDR+tlPxk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780928732; c=relaxed/simple; bh=OUIfpm4yjESU1AoCPcmkXCaC7HzyHnY3p+M2tI4H2Uw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=btygi2q5l/A9YdNoFvixVAIlgGXz6vUo1JjPH799gDt+7WSHzXFA0DMfhqbaNoPuopKkoc7iOUQ2HdCCak9SR89DM1sWDlQmABqyVvTzb2PXRTfZbl4cg22tv29jOyGOLNNMmcBg0QrT8u1mzloZpRPecbo9wNipYgdadlby9kQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=POvJmeMY; 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="POvJmeMY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 484AC1F00893; Mon, 8 Jun 2026 14:25:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780928730; bh=LXebLbU2PlO++pXKjvrv4XdGUtGGv/sVqpWNGZI12mI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=POvJmeMYSx9UAj3HfJbX4UIIte/iPDJNRUJhZM9IzDYz/oDcVE6URGfU+d1nJrcKe ZXtDMBhfgr2Y7DbV1TS+NXJRMTYhXvns+p+TigtDhfuTfA6hixbsfiFqkK8xHWTN8J RrpUApPFVi+AwTTjRJBF/e8fS7NFcn7uXG8EJFaJ5Uj9S5qgznR04rqVYHTfWheqeS amuKcmhirwSZEAT6UOuy1BzoAsEKsH4ZpjBblT+SsUb8p4rEd8VS4Sqb7ay377YwyH 36J5EBi2TK0KQ6+lcNeIoLyS+UxjLpi6C+Yg42J1nFzuQfIBOf990eWgzE1C2E7LsE A7Ph4C33Sz46A== From: "Masami Hiramatsu (Google)" To: Steven Rostedt , Mathieu Desnoyers Cc: Jonathan Corbet , Shuah Khan , Masami Hiramatsu , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 7/7] tracing/probes: Add a new testcase for BTF typecasts Date: Mon, 8 Jun 2026 23:25:26 +0900 Message-ID: <178092872598.163648.6705606677777891702.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2> References: <178092865666.163648.10457567771536160909.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 (Google) With the introduction of container_of-style BTF typecasting and per-CPU variable access support in trace probes, we need a way to verify their functionality and prevent regressions. Add a new ftrace kselftest and update the trace event sample module to test and validate these features. Specifically, update the trace-events-sample module to set up a periodic timer whose callback accesses a per-CPU counter. Introduce a new sample trace event, foo_timer_fn, to trace this callback and log the current counter value. Then, add a new test case, btf_probe_event.tc, which defines a dynamic probe on the timer callback. The probe uses BTF typecasting to recover the parent structure from the timer argument and +CPU() to fetch the per-CPU counter. The test verifies the integrity of the implementation by ensuring the values recorded by the dynamic probe match those from the static tracepoint. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- samples/trace_events/trace-events-sample.c | 38 ++++++++++++++- samples/trace_events/trace-events-sample.h | 34 ++++++++++++- .../ftrace/test.d/dynevent/btf_probe_event.tc | 52 ++++++++++++++++= ++++ 3 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_prob= e_event.tc diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_eve= nts/trace-events-sample.c index ecc7db237f2e..770315812218 100644 --- a/samples/trace_events/trace-events-sample.c +++ b/samples/trace_events/trace-events-sample.c @@ -94,6 +94,20 @@ static int simple_thread_fn(void *arg) static DEFINE_MUTEX(thread_mutex); static int simple_thread_cnt; =20 +static struct foo_timer_data *foo_timer_data; + +static void sample_timer_cb(struct timer_list *t) +{ + struct foo_timer_data *data =3D container_of(t, struct foo_timer_data, ti= mer); + + get_cpu(); + trace_foo_timer_fn(data); + (*this_cpu_ptr(data->counter))++; + put_cpu(); + + mod_timer(t, jiffies + HZ); +} + int foo_bar_reg(void) { mutex_lock(&thread_mutex); @@ -128,9 +142,27 @@ void foo_bar_unreg(void) =20 static int __init trace_event_init(void) { + foo_timer_data =3D kzalloc_obj(*foo_timer_data, GFP_KERNEL); + if (!foo_timer_data) + return -ENOMEM; + + foo_timer_data->name =3D "sample_timer_counter"; + foo_timer_data->counter =3D alloc_percpu(int); + if (!foo_timer_data->counter) { + kfree(foo_timer_data); + return -ENOMEM; + } + + timer_setup(&foo_timer_data->timer, sample_timer_cb, 0); + mod_timer(&foo_timer_data->timer, jiffies + HZ); + simple_tsk =3D kthread_run(simple_thread, NULL, "event-sample"); - if (IS_ERR(simple_tsk)) + if (IS_ERR(simple_tsk)) { + timer_delete_sync(&foo_timer_data->timer); + free_percpu(foo_timer_data->counter); + kfree(foo_timer_data); return -1; + } =20 return 0; } @@ -143,6 +175,10 @@ static void __exit trace_event_exit(void) kthread_stop(simple_tsk_fn); simple_tsk_fn =3D NULL; mutex_unlock(&thread_mutex); + + timer_delete_sync(&foo_timer_data->timer); + free_percpu(foo_timer_data->counter); + kfree(foo_timer_data); } =20 module_init(trace_event_init); diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_eve= nts/trace-events-sample.h index 1a05fc153353..816848a456a2 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h @@ -247,12 +247,14 @@ */ =20 /* - * It is OK to have helper functions in the file, but they need to be prot= ected - * from being defined more than once. Remember, this file gets included mo= re - * than once. + * It is OK to have helper functions and data structures in the file, but = they + * need to be protected from being defined more than once. Remember, this = file + * gets included more than once. */ #ifndef __TRACE_EVENT_SAMPLE_HELPER_FUNCTIONS #define __TRACE_EVENT_SAMPLE_HELPER_FUNCTIONS +#include + static inline int __length_of(const int *list) { int i; @@ -270,6 +272,13 @@ enum { TRACE_SAMPLE_BAR =3D 4, TRACE_SAMPLE_ZOO =3D 8, }; + +struct foo_timer_data { + const char *name; + struct timer_list timer; + int __percpu *counter; +}; + #endif =20 /* @@ -595,6 +604,25 @@ TRACE_EVENT(foo_rel_loc, __get_rel_bitmask(bitmask), __get_rel_cpumask(cpumask)) ); + +TRACE_EVENT(foo_timer_fn, + + TP_PROTO(struct foo_timer_data *data), + + TP_ARGS(data), + + TP_STRUCT__entry( + __string( name, data->name ) + __field( int, count ) + ), + + TP_fast_assign( + __assign_str(name); + __entry->count =3D *this_cpu_ptr(data->counter); + ), + + TP_printk("name=3D%s count=3D%d", __get_str(name), __entry->count) +); #endif =20 /***** NOTICE! The #if protection ends here. *****/ diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event= .tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc new file mode 100644 index 000000000000..f1980650dbe2 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc @@ -0,0 +1,52 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: BTF event with typecast and percpu access +# requires: dynamic_events " +CPU()":README "[(structname[,field= ])][->field[->field|.field...]]":README + +# Check if the sample module is loaded +if ! lsmod | grep -q trace_events_sample; then + modprobe trace-events-sample || exit_unsupported +fi + +echo 0 > events/enable +echo > dynamic_events + +# The sample_timer_cb(struct timer_list *t) is called. +# We want to check (STRUCT,FIELD)VAR typecast and +PCPU() dereference. +# (foo_timer_data,timer)t converts t to struct foo_timer_data * using cont= ainer_of. +# data->counter is a per-cpu pointer to int. +# +PCPU(data->counter) should give the per-cpu address of the counter. +# *+PCPU(data->counter) should give the value of the counter. + +echo 'f:mysample/myevent sample_timer_cb name=3D(foo_timer_data,timer)t->n= ame:string count=3D+CPU((foo_timer_data,timer)t->counter)' >> dynamic_events + +echo 1 > events/mysample/myevent/enable +echo 1 > events/sample-trace/foo_timer_fn/enable + +sleep 2 + +echo 0 > events/mysample/myevent/enable +echo 0 > events/sample-trace/foo_timer_fn/enable + +# Compare the values. +MATCH=3D0 +while read line; do + if echo $line | grep -q "foo_timer_fn:"; then + NAME=3D`echo $line | sed 's/.*name=3D\([^ ]*\) .*/\1/'` + COUNT=3D`echo $line | sed 's/.*count=3D\([^ ]*\).*/\1/'` + if grep -q "myevent:.*name=3D\"${NAME}\" count=3D$COUNT" trace; then + MATCH=3D$((MATCH+1)) + fi + fi +done < trace + +if [ $MATCH -eq 0 ]; then + echo "No matching events found" + exit_fail +fi + +# Clean up +echo 0 > events/mysample/myevent/enable +echo 0 > events/sample-trace/foo_timer_fn/enable +echo > dynamic_events +clear_trace