From nobody Sat Jun 27 16:57:49 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 7464F3EFFAE; Fri, 26 Jun 2026 14:14: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=1782483272; cv=none; b=FGknDZsX1I6b2CmCYso5dg+VZUZEfQglLjXdCeiepl0jLmO00s4BfcGgKnHZlQHPgXfkyzRwGQrZLBqLxVHS+18jO3z+Cfv6Vlwr5vJpJDRz7hzjuskFce4AtXFYVtFzk5DdVTUeaC4J156gmX/WU22hS/4HjlxdRmIy3sxn6pg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483272; c=relaxed/simple; bh=ILB/ElfIWa9u0xQ12aAYqyj8anSCHxMnZsNP9BRN1oE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TaC/9gFMsCIOqU895+rT/xdardSC3kekKLjP9PNfbR6ApoVT96hhSIrRDjk6DP7UaNscv3BHGk2FfUJk+pwBNW0n3zomnODpg8C7rtpHZtAATU/IAk2VnAqHXCM0jgP0GdF/zx8v7wxUK/pkitbhyhCjqubjyOxTpFRnXI9HEjk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WHSkm1Pq; 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="WHSkm1Pq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B425B1F00A3D; Fri, 26 Jun 2026 14:14:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483271; bh=zA1ny7mz86qD9VEgfTKY9l9S9cY7unn92daWUtN0ORY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=WHSkm1Pqp32TDMD98U2dsB0jvyLGZNUrC7D3K4aI5nkKxlo38YZzX6FZJ7Q0U1Xx/ s9cOooDptDT0zdbJluyJEQm+m7vKqSwRWfLNOYPfAyM0nVVay+QR0+XBPjlw2SXiY1 4R65lKzqQL5ryNU1upjrFIRMl8dpaF9HHhU7wqeMABmMQptW47E0H+0Oqdfmtk6t21 RJB86rL5AaIZI4naMlCNCfI++iyLXf6L3R8F7Lux/WZNFSR2W4hrHVh3h8YE4BpZR5 GZ5YSDSXQu9RsC/a634SXNWU8DzpjLp4lt4Q/C5xC15LHHcWucYuVxB+F/At2PG1Xf BXePjSd7di7gw== 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: [PATCH v11 01/11] tracing/probes: Allow eprobe to use variable without $ prefix Date: Fri, 26 Jun 2026 23:14:26 +0900 Message-ID: <178248326672.841606.5469594713059767810.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 commit 69efd863a785 ("tracing/eprobes: Allow use of BTF names to dereference pointers") allows eprobe to use event field without "$" prefix when it is used with typecast, it is natual to allow it without typecast. Signed-off-by: Masami Hiramatsu (Google) --- Changes in v8: - Newly added. --- kernel/trace/trace_probe.c | 12 +++++++++++- kernel/trace/trace_probe.h | 1 + .../test.d/dynevent/eprobes_syntax_errors.tc | 3 +-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 0da7c0b53ba7..2ce7d62471cb 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -1341,7 +1341,17 @@ parse_probe_arg(char *arg, const struct fetch_type *= type, ret =3D handle_typecast(arg, pcode, end, ctx); break; default: - if (isalpha(arg[0]) || arg[0] =3D=3D '_') { /* BTF variable */ + 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); diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 40b53b5b58a9..2e0d8384ee5c 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -559,6 +559,7 @@ extern int traceprobe_define_arg_fields(struct trace_ev= ent_call *event_call, 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."),\ diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_= errors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_e= rrors.tc index 2a680c086047..0e65e787e426 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.= tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.= tc @@ -10,7 +10,7 @@ check_error() { # command-with-error-pos-by-^ check_error 'e ^a.' # NO_EVENT_INFO check_error 'e ^.b' # NO_EVENT_INFO check_error 'e ^a.b' # BAD_ATTACH_EVENT -check_error 'e syscalls/sys_enter_openat ^foo' # BAD_ATTACH_ARG +check_error 'e syscalls/sys_enter_openat ^foo' # NO_EVENT_FIELD check_error 'e:^/bar syscalls/sys_enter_openat' # NO_GROUP_NAME check_error 'e:^1234567890123456789012345678901234567890123456789012345678= 9012345/bar syscalls/sys_enter_openat' # GROUP_TOO_LONG =20 @@ -19,7 +19,6 @@ check_error 'e:^ syscalls/sys_enter_openat' # NO_EVENT_N= AME check_error 'e:foo/^123456789012345678901234567890123456789012345678901234= 56789012345 syscalls/sys_enter_openat' # EVENT_TOO_LONG check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME =20 -check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^dfd' # BAD_FETCH_A= RG check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^$foo' # BAD_ATTACH= _ARG =20 if grep -q '\..*\[if \]' README; t= hen From nobody Sat Jun 27 16:57:49 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 3EEB43EFFAE; Fri, 26 Jun 2026 14:14:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483282; cv=none; b=R4dXqUK6djJdhPC7xap8NxJEgVLMuM2DlQYtIW2kXaoROgh40jsy9Y4QYCeBrbmzFegpz3hw3aIELrSpd0fhLXSnOPVEYmnG2vQhTlasYEe5EThIpmP7q515vNcH57tj2xk5ESlCOPyv0zBuiN95xw5uxVSLehukASioWUgklxM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483282; c=relaxed/simple; bh=brzCWiuuGFqINoBFZGv95K4h/rljuY6RV+d+NGVogyw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=L5w8o4j3wic2GiDSMMqdQV17KpBghTLgAfUK4ZtULFsF3qrYNr1mRlZ6LOWKTvVvRSR7uQjV8tPHcIxIqqrF+13bWoaakajUIZ4wmShtFiTMS/aCIQ4xyxTuoCIdyGlYWoA7/UamdZPQe/+Z3N8FHdU/5Lss0YtTUTtN0+dnUbo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=X7nMsFc4; 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="X7nMsFc4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E5C6D1F00A3A; Fri, 26 Jun 2026 14:14:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483280; bh=BPLbjH4kxpoEtI36kcllxUoKMnXhc8+/tSHnVGlA93w=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=X7nMsFc4gprt52Dg0SCtZWfRirlAGhhlK/L+kNipvOh3doLiUbCTUnDSInWmVV6yY p/U1DBRtKrWp/1IRf3MiWBJrzSxpLs+IceR1K7wrSZFf010Evkm22Y9ImRxUHYMa9q zBqOsnhjRO2FkntPvpzGttvrCAY8UOMYxsKhw/JvjmJ7jlO6tI7dWEDlk4N2rEpy0Q iWuAmNyfrrClvZ0gcA03zgS6oho2dvHzG5jgrjM3oef4RKp4CvCXwek8+kQ/iLPONX 5JQb5Y3K7M9hospUDrhecx+zXFHlcZM9My3YTf2dzwKkhsAWdOzAjAWmGdG/mSDc1x 9ogka8FVL6mkA== 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: [PATCH v11 02/11] tracing/probes: Support dumping fetcharg program for debugging dynamic events Date: Fri, 26 Jun 2026 23:14:36 +0900 Message-ID: <178248327666.841606.10742303555302930401.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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) For debugging probe events, it is helpful to verify the compiled fetch instructions for each probe argument. This introduces a new kernel config CONFIG_PROBE_EVENTS_DUMP_FETCHARG to decode the instruction sequence of each argument and display it under a commented line starting with '#' immediately following the dynamic event definition (such as in dynamic_events, kprobe_events, uprobe_events, etc.). For example: /sys/kernel/tracing # cat dynamic_events p:kprobes/p_vfs_read_0 vfs_read arg1=3D+0(file):ustring arg2=3D%ax:x16 # arg1: ARG(0) -> ST_USTRING(offset=3D0,size=3D4) -> END # arg2: REG(80) -> ST_RAW(size=3D2) -> END Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Masami Hiramatsu (Google) --- Changes in v8: - State this feature is only for debugging probe events. - Fix dependency list after description in Kconfig. Changes in v7: - Show trace event field name for FETCH_OP_TP_ARG. - Show immediate string value for FETCH_OP_IMMSTR. - Fix style issues warned by checkpatch.pl. Changes in v6: - Newly added. --- kernel/trace/Kconfig | 12 +++++ kernel/trace/trace_eprobe.c | 2 + kernel/trace/trace_fprobe.c | 2 + kernel/trace/trace_kprobe.c | 2 + kernel/trace/trace_probe.c | 96 +++++++++++++++++++++++++++++++++++++++= ++++ kernel/trace/trace_probe.h | 79 +++++++++++++++++++++-------------- kernel/trace/trace_uprobe.c | 3 + 7 files changed, 164 insertions(+), 32 deletions(-) diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 084f34dc6c9f..0ab5916575a9 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -779,6 +779,18 @@ config PROBE_EVENTS_BTF_ARGS kernel function entry or a tracepoint. This is available only if BTF (BPF Type Format) support is enabled. =20 +config PROBE_EVENTS_DUMP_FETCHARG + bool "Dump of dynamic probe event fetch-arguments" + depends on PROBE_EVENTS + default n + help + This shows the dump of fetch-arguments of dynamic probe events + alongside their event definitions in the dynamic_events file + as comment lines. This is useful to debug the probe events. + Since this exposes the raw values in the dynamic_events file, + it might be a security risk. Only enable it if you need to debug + probe events themselves. + config KPROBE_EVENTS depends on KPROBES depends on HAVE_REGS_AND_STACK_ACCESS_API diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c index 50518b071414..462c31145733 100644 --- a/kernel/trace/trace_eprobe.c +++ b/kernel/trace/trace_eprobe.c @@ -87,6 +87,8 @@ static int eprobe_dyn_event_show(struct seq_file *m, stru= ct dyn_event *ev) seq_printf(m, " %s=3D%s", ep->tp.args[i].name, ep->tp.args[i].comm); seq_putc(m, '\n'); =20 + trace_probe_dump_args(m, &ep->tp); + return 0; } =20 diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c index 4d1abbf66229..536781cd4c47 100644 --- a/kernel/trace/trace_fprobe.c +++ b/kernel/trace/trace_fprobe.c @@ -1449,6 +1449,8 @@ static int trace_fprobe_show(struct seq_file *m, stru= ct dyn_event *ev) seq_printf(m, " %s=3D%s", tf->tp.args[i].name, tf->tp.args[i].comm); seq_putc(m, '\n'); =20 + trace_probe_dump_args(m, &tf->tp); + return 0; } =20 diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a8420e6abb56..cfa807d8e760 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1320,6 +1320,8 @@ static int trace_kprobe_show(struct seq_file *m, stru= ct dyn_event *ev) seq_printf(m, " %s=3D%s", tk->tp.args[i].name, tk->tp.args[i].comm); seq_putc(m, '\n'); =20 + trace_probe_dump_args(m, &tk->tp); + return 0; } =20 diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 2ce7d62471cb..0908019aea12 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -2403,3 +2403,99 @@ int trace_probe_print_args(struct trace_seq *s, stru= ct probe_arg *args, int nr_a } return 0; } + +#ifdef CONFIG_PROBE_EVENTS_DUMP_FETCHARG + +struct fetch_op_decode { + const char *name; + void (*decode)(struct seq_file *m, struct fetch_insn *insn); +}; + +static const struct fetch_op_decode fetch_op_decode[]; + +static void fetcharg_decode_none(struct seq_file *m, struct fetch_insn *in= sn) +{ + seq_puts(m, fetch_op_decode[insn->op].name); +} + +static void fetcharg_decode_param(struct seq_file *m, struct fetch_insn *i= nsn) +{ + seq_printf(m, "%s(%u)", fetch_op_decode[insn->op].name, insn->param); +} + +static void fetcharg_decode_imm(struct seq_file *m, struct fetch_insn *ins= n) +{ + seq_printf(m, "%s(0x%lx)", fetch_op_decode[insn->op].name, insn->immediat= e); +} + +static void fetcharg_decode_string(struct seq_file *m, struct fetch_insn *= insn) +{ + seq_printf(m, "%s(%s)", fetch_op_decode[insn->op].name, (char *)insn->dat= a); +} + +static void fetcharg_decode_symbol(struct seq_file *m, struct fetch_insn *= insn) +{ + seq_printf(m, "%s(%s)", fetch_op_decode[insn->op].name, (char *)insn->dat= a); +} + +static void fetcharg_decode_offset(struct seq_file *m, struct fetch_insn *= insn) +{ + seq_printf(m, "%s(offset=3D%d)", fetch_op_decode[insn->op].name, insn->of= fset); +} + +static void fetcharg_decode_store(struct seq_file *m, struct fetch_insn *i= nsn) +{ + if (insn->op =3D=3D FETCH_OP_ST_RAW) + seq_printf(m, "%s(size=3D%u)", fetch_op_decode[insn->op].name, insn->siz= e); + else + seq_printf(m, "%s(offset=3D%d,size=3D%u)", fetch_op_decode[insn->op].nam= e, + insn->offset, insn->size); +} + +static void fetcharg_decode_bf(struct seq_file *m, struct fetch_insn *insn) +{ + seq_printf(m, "%s(basesize=3D%u,lshift=3D%u,rshift=3D%u)", + fetch_op_decode[insn->op].name, insn->basesize, insn->lshift, insn->r= shift); +} + +static void fetcharg_decode_tp_arg(struct seq_file *m, struct fetch_insn *= insn) +{ + struct ftrace_event_field *field =3D insn->data; + + seq_printf(m, "%s(%s)", fetch_op_decode[insn->op].name, field->name); +} + +#define FETCH_OP(opname, decode_fn) \ + [FETCH_OP_##opname] =3D { .name =3D #opname, .decode =3D fetcharg_decode_= ##decode_fn } + +static const struct fetch_op_decode fetch_op_decode[] =3D FETCH_OP_LIST; +#undef FETCH_OP + +static void trace_probe_dump_arg(struct seq_file *m, struct probe_arg *par= g) +{ + int i; + + seq_printf(m, "# %s: ", parg->name); + for (i =3D 0; i < FETCH_INSN_MAX; i++) { + struct fetch_insn *insn =3D parg->code + i; + + if (insn->op >=3D ARRAY_SIZE(fetch_op_decode) || !fetch_op_decode[insn->= op].decode) + seq_printf(m, "unknown(%d)", insn->op); + else + fetch_op_decode[insn->op].decode(m, insn); + + if (insn->op =3D=3D FETCH_OP_END) + break; + seq_puts(m, " -> "); + } + seq_putc(m, '\n'); +} + +void trace_probe_dump_args(struct seq_file *m, struct trace_probe *tp) +{ + int i; + + for (i =3D 0; i < tp->nr_args; i++) + trace_probe_dump_arg(m, &tp->args[i]); +} +#endif /* CONFIG_PROBE_EVENTS_DUMP_FETCHARG */ diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 2e0d8384ee5c..e36cfe39e9a8 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -83,38 +83,46 @@ static nokprobe_inline u32 update_data_loc(u32 loc, int= consumed) /* Printing function type */ typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); =20 -enum fetch_op { - FETCH_OP_NOP =3D 0, - // Stage 1 (load) ops - FETCH_OP_REG, /* Register : .param =3D offset */ - FETCH_OP_STACK, /* Stack : .param =3D index */ - FETCH_OP_STACKP, /* Stack pointer */ - FETCH_OP_RETVAL, /* Return value */ - FETCH_OP_IMM, /* Immediate : .immediate */ - FETCH_OP_COMM, /* Current comm */ - FETCH_OP_ARG, /* Function argument : .param */ - FETCH_OP_FOFFS, /* File offset: .immediate */ - FETCH_OP_IMMSTR, /* Allocated string: .data */ - FETCH_OP_EDATA, /* Entry data: .offset */ - // Stage 2 (dereference) op - FETCH_OP_DEREF, /* Dereference: .offset */ - FETCH_OP_UDEREF, /* User-space Dereference: .offset */ - // Stage 3 (store) ops - FETCH_OP_ST_RAW, /* Raw: .size */ - FETCH_OP_ST_MEM, /* Mem: .offset, .size */ - FETCH_OP_ST_UMEM, /* Mem: .offset, .size */ - FETCH_OP_ST_STRING, /* String: .offset, .size */ - FETCH_OP_ST_USTRING, /* User String: .offset, .size */ - FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */ - FETCH_OP_ST_EDATA, /* Store Entry Data: .offset */ - // Stage 4 (modify) op - FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */ - // Stage 5 (loop) op - FETCH_OP_LP_ARRAY, /* Array: .param =3D loop count */ - FETCH_OP_TP_ARG, /* Trace Point argument */ - FETCH_OP_END, - FETCH_NOP_SYMBOL, /* Unresolved Symbol holder */ -}; +#define FETCH_OP_LIST { \ + /* Stage 1 (load) ops */ \ + FETCH_OP(NOP, none), /* NOP */ \ + FETCH_OP(REG, param), /* Register: .param =3D offset */ \ + FETCH_OP(STACK, param), /* Stack: .param =3D index */ \ + FETCH_OP(STACKP, none), /* Stack pointer */ \ + FETCH_OP(RETVAL, none), /* Return value */ \ + FETCH_OP(IMM, imm), /* Immediate: .immediate */ \ + FETCH_OP(COMM, none), /* Current comm */ \ + FETCH_OP(ARG, param), /* Argument: .param =3D index */ \ + FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \ + FETCH_OP(IMMSTR, string), /* Allocated string: .data */ \ + FETCH_OP(EDATA, offset), /* Entry data: .offset */ \ + FETCH_OP(TP_ARG, tp_arg), /* Tracepoint argument: .data */\ + /* Stage 2 (dereference) ops */ \ + FETCH_OP(DEREF, offset), /* Dereference: .offset */ \ + FETCH_OP(UDEREF, offset), /* User-space dereference: .offset */\ + /* Stage 3 (store) ops */ \ + FETCH_OP(ST_RAW, store), /* Raw value: .size */ \ + FETCH_OP(ST_MEM, store), /* Memory: .offset, .size */ \ + FETCH_OP(ST_UMEM, store), /* User memory: .offset, .size */\ + FETCH_OP(ST_STRING, store), /* String: .offset, .size */ \ + FETCH_OP(ST_USTRING, store), /* User string: .offset, .size */\ + FETCH_OP(ST_SYMSTR, store), /* Symbol name: .offset, .size */\ + FETCH_OP(ST_EDATA, offset), /* Entry data: .offset */ \ + /* Stage 4 (modify) op */ \ + FETCH_OP(MOD_BF, bf), /* Bitfield: .basesize, .lshift, .rshift*/\ + /* Stage 5 (loop) op */ \ + FETCH_OP(LP_ARRAY, param), /* Loop array: .param =3D count */\ + /* End */ \ + FETCH_OP(END, none), \ + /* Unresolved Symbol holder */ \ + FETCH_OP(NOP_SYMBOL, symbol), /* Non loaded symbol: .data =3D symbol name= */\ +} + +#define FETCH_OP(opname, decode_fn) FETCH_OP_##opname +enum fetch_op FETCH_OP_LIST; +#undef FETCH_OP + +#define FETCH_NOP_SYMBOL FETCH_OP_NOP_SYMBOL =20 struct fetch_insn { enum fetch_op op; @@ -370,6 +378,13 @@ bool trace_probe_match_command_args(struct trace_probe= *tp, int trace_probe_create(const char *raw_command, int (*createfn)(int, const= char **)); int trace_probe_print_args(struct trace_seq *s, struct probe_arg *args, in= t nr_args, u8 *data, void *field); +#ifdef CONFIG_PROBE_EVENTS_DUMP_FETCHARG +void trace_probe_dump_args(struct seq_file *m, struct trace_probe *tp); +#else +static inline void trace_probe_dump_args(struct seq_file *m, struct trace_= probe *tp) +{ +} +#endif =20 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API int traceprobe_get_entry_data_size(struct trace_probe *tp); diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index c274346853d1..b2e264a4b96c 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -765,6 +765,9 @@ static int trace_uprobe_show(struct seq_file *m, struct= dyn_event *ev) seq_printf(m, " %s=3D%s", tu->tp.args[i].name, tu->tp.args[i].comm); =20 seq_putc(m, '\n'); + + trace_probe_dump_args(m, &tu->tp); + return 0; } From nobody Sat Jun 27 16:57:49 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 DBF7E3EFFAE; Fri, 26 Jun 2026 14:14: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=1782483291; cv=none; b=JR1KOUe7m6zn7VDARKKkepXJaPc1F4/KCyte+qFEe9kUCnCTy4IcJ/MDLSBPprt1xUN3OdQC6Io6/fUYwnB8R5QhO4rdzL+AwLb9DkT+ax85dfpAyXs3u/2F1qOkjLenJ2MBnDT++tMUt9OhklKIrmNZqn1xFKSQlUCX4/8hljw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483291; c=relaxed/simple; bh=iwvJEEmSo6kakYtR3FrwdqO9JhTL7AXMa5BsjUanyOU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=F4cz0M9tYYaF32Y69USXSDj6YKkM/r/D+MmUPZor13nkfl6MqzGzBoC049y4K7RABf5LDNJjKDHs6mIl4KpqBbeKbVas72zr3cqR02uHF/F8WKvgjMeFQDxeuDa8nE6hoK+ndz/EtVv9Mvd3h+K9H1xErHgTwnkHZsTG2G04+9k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hJS3pV1Z; 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="hJS3pV1Z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D14D1F000E9; Fri, 26 Jun 2026 14:14:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483290; bh=DRQQpc50/HOc5q+xOiqMoSHrmuL8PZ/YatZQSWy4Uu4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=hJS3pV1Zexa+WcZsLne1IHF/E+pVDkx8yNsPhfMHYalHzy++BcXRhsACExWufF0O/ QB17u9KhqjnGMFmGIPuXmptaSsCvX9M+LKsiHj6cUlweeU/Y/AVJT4fD4hdIwSEo1m N8ps5W6aMkGl7xzh1638Y1SIWF2cI6PLDikLYlmMkrktwMtGxs4BSPZIpra2k+B+3f RktnAgUwg+yc+/+I0irODp8E3mhb3UqYHMQyVMUtX2gJOGW9b3G9a+BtihNv8R3ttt gRcZNzbSFcfKXDwh0ZJjlVbCpcVW//Fx12/dBuEG6vHR7fnBctsTOHpP7Mtzd3XV5I mT8QTg3jrmySQ== 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: [PATCH v11 03/11] tools/bootconfig: Ignore comment lines in dynamic_events/kprobe_events file Date: Fri, 26 Jun 2026 23:14:46 +0900 Message-ID: <178248328618.841606.12096364096224070176.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 dynamic_events/kprobe_events files show the fetcharg debug information as comment lines, its reader needs to ignore it. Signed-off-by: Masami Hiramatsu (Google) --- tools/bootconfig/scripts/ftrace2bconf.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/bootconfig/scripts/ftrace2bconf.sh b/tools/bootconfig/sc= ripts/ftrace2bconf.sh index 1603801cf126..8eed445c295e 100755 --- a/tools/bootconfig/scripts/ftrace2bconf.sh +++ b/tools/bootconfig/scripts/ftrace2bconf.sh @@ -57,6 +57,8 @@ EOF kprobe_event_options() { cat $TRACEFS/kprobe_events | while read p args; do case $p in + \#*) + continue;; r*) cat 1>&2 << EOF # WARN: A return probe found but it is not supported by bootconfig. Skip i= t. From nobody Sat Jun 27 16:57:49 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 9901A3E559A; Fri, 26 Jun 2026 14:15: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=1782483301; cv=none; b=uWvUX1TO+EjzhARSSAW/dmvJ7Hh0pX/NAbzv0s8lQKfUUoaqmuyMHz4PYtUNfaQBvFYpnl3/tnDzQGsXlFmojvh95vV8y6BJG/uCjX5hHfD1SumaCw6QbGwixYKPaxzFxuRd8YK/pLPdWqXjO1fA+ntecuN4ZKXAGFIFP84Ubvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483301; c=relaxed/simple; bh=o3fcbFp0pBvZ6VeygN5BLrM057jFH+3OjGKMeTl88Ko=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ISDxKjGwyZzujLmLdE2UYJWLZSzbF5heGfEW1gElXnZtcyV9fsoVO+Y/MYBPB3/BDCTx5BtqXjJxbJqYEjPfJ8LBpUbGmjYL3BE5jeuMlolmmt8Eml7Y2B6occu3d2yGzmiF0t+TObI3aURoenp2PIZtF5RBgzTsC80WuO7O8ug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=M38BsJyf; 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="M38BsJyf" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 391FD1F000E9; Fri, 26 Jun 2026 14:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483300; bh=IwXYV//eN/UulKrBQVQ9tKlK1h/PJvqTlVUST+nm2pU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=M38BsJyfn6v6rkkQmXzdPQTsybILwhZRcOS5EBtXBah2DvRRbBrLcOmI+jm7QZDlR b2qZokvKVqKrH6RV+ljOp8BJC74hu/QxwMoKGsfs781PjJAE7hDfvy0fMw2f+3nhCy zUOA8TtPkFQoCMuLFRcnMKIkOnyhYKnZ1NbftqT2yHx0Eb6gnRJ4CZ30D4H/LQDUGk a8CIvyQI+mhKdXGSVb95DMVoUEAfxE/e5T8SiZxnjDQ/+qC1aPiAFb3Ea6qsxb5Few Z2J1jTCpbuv7e6Lu6MMT0gtAmeVwz9KhI6tHjwXqZc/NsejcWYqrcmN9I/8ZoM75mo 8A4lHtMeVafiw== 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: [PATCH v11 04/11] perf/probe: Ignore comment lines in dynamic_events/kprobe_events file Date: Fri, 26 Jun 2026 23:14:56 +0900 Message-ID: <178248329591.841606.4795357924636831995.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 dynamic_events/kprobe_events files show the fetcharg debug information as comment lines, its reader needs to ignore it. Signed-off-by: Masami Hiramatsu (Google) --- tools/perf/util/probe-file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 4032572cbf55..4d12693a83b3 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -197,6 +197,8 @@ struct strlist *probe_file__get_rawlist(int fd) idx =3D strlen(p) - 1; if (p[idx] =3D=3D '\n') p[idx] =3D '\0'; + if (buf[0] =3D=3D '#') + continue; ret =3D strlist__add(sl, buf); if (ret < 0) { pr_debug("strlist__add failed (%d)\n", ret); From nobody Sat Jun 27 16:57:49 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 4E85F37C10C; Fri, 26 Jun 2026 14:15: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=1782483311; cv=none; b=lHOifKuqzD1y0L4p+NpZUqsw4A1Ebf8GaOi2OXqBnm/iGz0/iQ9W/J+m/wNaLFYP8nc082T9vYQbdNx7q7a2TmQlVB6BjdBhz+ZASZE+T1o61Fc/CR/LJHDUhsuxNxACc5JoICamMhNPOj9Dc+hUr7pI8MlrplsQlwQFVm/f/2k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483311; c=relaxed/simple; bh=O9xG2z+EFR+eRHAxrXpB7iM2ieNX3YhCuZhXD79qljQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WMu0zHmsCg0TvAx50CtSq4898+p61Ldc5LdE7BGLBEwMbyHkdA8U7nNvE6PhWVphBN0tX4iUuSGbCPODIgcOgpJWpX7jZXZsbHUrMSleYngLr63Xy0qzEFTQweEiTccmJNxKf2Hn68WbKAcNbb8HMzxYEA78LyYZR4tTn3o72uE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CELlmzP9; 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="CELlmzP9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5C201F000E9; Fri, 26 Jun 2026 14:15:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483309; bh=5bW0GTnmvIpAldxgyCiZYrRAz0izEcnXpJfTh/lMxjE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=CELlmzP9rjupzZldRsaR8iaAXDNs4cKSX1Q7v9kAFD7KprG+ewgUhWHzonne83xDS LiP+BSaHSkFmCb3UWvnDY2lrTz1AbujTat3nAE1YZUKUijiMjswnXBxcs24C0yaEf3 h1GbnU91HYe8LVQHeWYCk0w3A9/dEp7yZ4Ai5mTwJ0+AldZhCHleJW4NRpr6v21KRh dvmL3DczQCYthZlpzBaaAyl65eHkuzM7UoM097NfZRJwBEVKLi8WhhplWVzSRAcnTy 11co2TeuTz5JeoewQyLQLFiehN6te24gVUSgkHNAsMk0o8nSImsJyqpin8sKpdGaPK aSc8uc5uhpwZw== 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: [PATCH v11 05/11] tracing/probes: Support typecast for various probe events Date: Fri, 26 Jun 2026 23:15:05 +0900 Message-ID: <178248330564.841606.15954758183438726969.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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, and must use function parameter name or $retval. This means you can do: (STRUCT)PARAM->MEMBER Note: you can not use other variables like $stackN, %reg etc. That needs nesting support. 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 updates /README file to show struct typecast. Signed-off-by: Masami Hiramatsu (Google) --- Changes in v5: - Add comments about $retval with typecast. - Even if the type of retvalue is not known, if user specifies typecast, use it for its type. Changes in v3: - Clarify the limitation. Changes in v2: - Fix to re-enable typecast on eprobe. --- Documentation/trace/fprobetrace.rst | 3 +++ Documentation/trace/kprobetrace.rst | 4 ++++ kernel/trace/trace.c | 2 +- kernel/trace/trace_probe.c | 23 +++++++++++++++++------ kernel/trace/trace_probe.h | 5 +++++ 5 files changed, 30 insertions(+), 7 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 1146b83b711a..280a3dccd13f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4322,7 +4322,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 0908019aea12..e6cc9f3d6c8b 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -699,7 +699,7 @@ static int parse_btf_arg(char *varname, =20 if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { code->op =3D FETCH_OP_RETVAL; - /* Check whether the function return type is not void */ + /* Check whether the function return type is not void, even with typecas= t. */ if (query_btf_context(ctx) =3D=3D 0) { if (ctx->proto->type =3D=3D 0) { trace_probe_log_err(ctx->offset, NO_RETVAL); @@ -708,6 +708,13 @@ static int parse_btf_arg(char *varname, tid =3D ctx->proto->type; goto found; } + /* + * Even if we can not find appropriate BTF info, we can still access + * the field via typecast. + */ + if (ctx->struct_btf) + goto found; + if (field) { trace_probe_log_err(ctx->offset + field - varname, NO_BTF_ENTRY); @@ -752,7 +759,10 @@ static int parse_btf_arg(char *varname, return -ENOENT; =20 found: - type =3D btf_type_skip_modifiers(ctx->btf, tid, NULL); + if (ctx->struct_btf) + type =3D ctx->last_struct; + else + type =3D btf_type_skip_modifiers(ctx->btf, tid, NULL); found_type: if (!type) { trace_probe_log_err(ctx->offset, BAD_BTF_TID); @@ -829,10 +839,11 @@ static int handle_typecast(char *arg, struct fetch_in= sn **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_event_probe(ctx->flags) || + 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, ')'); diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index e36cfe39e9a8..aa72e2ffdd93 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -429,6 +429,11 @@ static inline bool tparg_is_function_return(unsigned i= nt flags) return (flags & TPARG_FL_LOC_MASK) =3D=3D (TPARG_FL_KERNEL | TPARG_FL_RET= URN); } =20 +static inline bool tparg_is_event_probe(unsigned int flags) +{ + return !!(flags & TPARG_FL_TEVENT); +} + struct traceprobe_parse_context { struct trace_event_call *event; /* BTF related parameters */ From nobody Sat Jun 27 16:57:49 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 D764437C910; Fri, 26 Jun 2026 14:15: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=1782483321; cv=none; b=rstTAnNAxZPlvnRzHxdcZYBlDCE5F3ZY3EWUPuPE8DSSlmHjcp+lI7BiC5+tzorY/uTzsVAfn3wPdrJyq3liP+cZTlpRPqPSlWK5rDUEa5sQ4cXvFQHKAyl6vVu3T2sT5DtGOPJKH2HpxQPPC+6RK+kS2F09wwbcwJDSPAjXCD4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483321; c=relaxed/simple; bh=uj+y5em99PMn2z8GbyB9qYfg2vDZ31tYblrwj0IGfPE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Sap/c2LQnfeNdPsCAgrkg9j8IXkoFZYorAtgItne0ntIT1QDP7bcFUABy5dlB0ZMbih0VCKpDkP4ZhwL1gtxpaWH5rqB8g+AcOFtQ72WY00sDWNsm2J5eTkiSP0L0ojKByLlTyDColw4r7s7P1kRyD+jPHMQjb9iaGrUM89uETg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D6koYmQ2; 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="D6koYmQ2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 736261F000E9; Fri, 26 Jun 2026 14:15:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483319; bh=P8+4xCBUtTfmePbva0AYMM+62LAp93QK5Yx3yCDBnI4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=D6koYmQ2e+CvEalBAnlAGJszPdAtlDuKZBdNOWy0s7ItWNMjxIy69rl1kk/ZMT0U3 xJkJk2Iy2id9bf/9FafeGj5fk4eAK5BgCGTdWmz5el2/zcNSXBgAJCy8n+At6+XgIg WQZD5Jn5DpekU91fZ4lK5yeWC2x6fJuMP6hfOC8IbzfbxEL8YIs9bnw9fkYve1PSm+ Iv/25LO18qjb/YV+5op6Zr68BA/J3uROZorYmWuKO9NMgBqSR4ls6Bo5UClIVhMjtO 5IPFNc5W0Ajhy+g+GnxTJaCMJAr2I4LusrIbQTzJqg3RanzSknRHOkrrYg9PBTu6cx alqQkqTOuxDSg== 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: [PATCH v11 06/11] tracing/probes: Support nested typecast Date: Fri, 26 Jun 2026 23:15:15 +0900 Message-ID: <178248331526.841606.16127421411735993426.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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. This also allows user to use typecasting for registers or stacks on kprobe events. e.g. (STRUCT)(%ax)->MEMBER (STRUCT)($stack0)->MEMBER Signed-off-by: Masami Hiramatsu (Google) --- Changes in v11: - Fix to return -EINVAL if WARN_ON_ONCE() is hit. Changes in v6: - Add a WARN_ON_ONCE check for leaking nested_level (it must not happen.) Changes in v4: - Use orig_offset for reporting NO_PTR_STRCT error. Changes in v2: - Fix to skip "->" after closing parenthetsis. --- 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 | 83 +++++++++++++++++++++++++++++++= +--- kernel/trace/trace_probe.h | 7 +++ 6 files changed, 88 insertions(+), 9 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 280a3dccd13f..e56ee034c486 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4323,6 +4323,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 e6cc9f3d6c8b..827ae04f6351 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 @@ -852,19 +877,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'; =20 + /* 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; + } + + 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 + 3;/* Skip "->" after closing parenthesis */ + nested =3D true; + } + + ret =3D query_btf_struct(arg + 1, ctx); if (ret < 0) { - trace_probe_log_err(ctx->offset + 1, NO_PTR_STRCT); + trace_probe_log_err(orig_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 @@ -1638,6 +1700,11 @@ 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; + } =20 /* Update storing type if BTF is available */ if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index aa72e2ffdd93..7d71925244e8 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -450,8 +450,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); @@ -587,7 +590,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:57:49 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 3B06A37C10C; Fri, 26 Jun 2026 14:15: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=1782483330; cv=none; b=TbzWzgrE5I3yyYNLJZDan1ozYg3dncAF3wIQEca1RRGnJ/4nHRfCL59FOBivLYyYoEGGyWWjYjBUTXoFz+TzUEi1NV0IR3Ip8Qjurzsg8+nZLLllIFHs0q8XytVHDYUPt2jOsjwFoZavT6xG0Da1h/GvZtTzKdyiswdO0CbdK2A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483330; c=relaxed/simple; bh=s7iK5Vnr1A+nfXCc0dUg10Fz3VBELf3c74bst5xJV+U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bmn8ZK+yupnNeOQa5XkoNJQ0lH0L3HQoCXvrt+FSzFIi0odcaK+PhvdpUcCS8R0pv/ijtSZxpaiMDf62Dzy4AY1MjU5z/JEgEKzmH/hY7JAktDpTISi7rN0HcafOewwZ8+0XejrFl5t7duOX7cIeo1OLX5dc3Z0HRSTk0X2jBjM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h1iAjrid; 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="h1iAjrid" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAEE31F000E9; Fri, 26 Jun 2026 14:15:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483328; bh=G0F3WkDnxAsnJ+ic2fWZoMY8z1J+qJbFouRtZeR2slM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=h1iAjrid0uxsWoCc04VjP+9qsdNtKbuyz399oZftF9ES8VjPdVM09weNfp2MAjt/F zsX3pgR7LCfyd6lu81/7g4y8D6TaanBpyn82wXIrGVs0V/j8kGmQbXV6EYFO9A/zu+ K8sFiMMCiannEJ2aSmLK59VeGnbFIGCkD2oLvSLiEfYGrKB5msCe3vfPakh7FcLGjH rBIv5oNCVl+O585eHijiFwRL/w7FsBe/epP/42E47UpoPr+Z1UcDhp8LXqq7ZHSHxj SIMoWIZMc+QlBlvrfhTi9BHeAF6pUABuTQzV54LCYbaXs4YKYbOU+LuyANLIdFO2AF HRQMx7l767Heg== 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: [PATCH v11 07/11] tracing/probes: Type casting always involves nested calls Date: Fri, 26 Jun 2026 23:15:24 +0900 Message-ID: <178248332489.841606.6395733419195710457.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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) This allows type casting to various fetchargs without parentheses by recursively calling parse_probe_arg on the target when type casting is used. For example, this allows the following expressions: - (STRUCT)%REG->FIELD - (STRUCT)$stackN->FIELD - (STRUCT)@SYM->FIELD Note that @SYM+/-OFFSET with typecast needs parentheses like: - (STRUCT)(@SYM-8)->FIELD Signed-off-by: Masami Hiramatsu (Google) --- Changes in v8: - Fix caret position in error case. - Add a comment about @SYM+/-OFFSET without parentheses. Changes in v7: - Prohibit using @SYM+/-OFFSET without parentheses. - Cleanup parse_btf_arg() since ctx->struct_btf is always NULL now. Changes in v6: - Newly added. --- kernel/trace/trace_probe.c | 123 ++++++++++++++++++++++++++--------------= ---- kernel/trace/trace_probe.h | 4 + 2 files changed, 75 insertions(+), 52 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 827ae04f6351..1b97b125e9cb 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -684,19 +684,6 @@ static int parse_btf_arg(char *varname, return -EOPNOTSUPP; } =20 - if (ctx->flags & TPARG_FL_TEVENT) { - ret =3D parse_trace_event(varname, code, ctx); - if (ret < 0) { - trace_probe_log_err(ctx->offset, BAD_ATTACH_ARG); - return ret; - } - /* 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; - } - if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { code->op =3D FETCH_OP_RETVAL; /* Check whether the function return type is not void, even with typecas= t. */ @@ -708,13 +695,6 @@ static int parse_btf_arg(char *varname, tid =3D ctx->proto->type; goto found; } - /* - * Even if we can not find appropriate BTF info, we can still access - * the field via typecast. - */ - if (ctx->struct_btf) - goto found; - if (field) { trace_probe_log_err(ctx->offset + field - varname, NO_BTF_ENTRY); @@ -759,11 +739,7 @@ static int parse_btf_arg(char *varname, return -ENOENT; =20 found: - if (ctx->struct_btf) - type =3D ctx->last_struct; - else - type =3D btf_type_skip_modifiers(ctx->btf, tid, NULL); -found_type: + type =3D btf_type_skip_modifiers(ctx->btf, tid, NULL); if (!type) { trace_probe_log_err(ctx->offset, BAD_BTF_TID); return -EINVAL; @@ -860,7 +836,7 @@ static int handle_typecast(char *arg, struct fetch_insn= **pcode, struct traceprobe_parse_context *ctx) { int orig_offset =3D ctx->offset; - bool nested =3D false; + char *close; char *tmp; int ret; =20 @@ -871,6 +847,17 @@ static int handle_typecast(char *arg, struct fetch_ins= n **pcode, return -EOPNOTSUPP; } =20 + /* + * Always consider the token after typecast as a nested call + * 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), @@ -879,11 +866,10 @@ static int handle_typecast(char *arg, struct fetch_in= sn **pcode, } *tmp++ =3D '\0'; =20 - /* Handle the nested structure like (STRUCT)(VAR->FIELD)->... */ + ctx->offset +=3D tmp - arg; if (*tmp =3D=3D '(') { - char *close =3D find_matched_close_paren(tmp); + close =3D find_matched_close_paren(tmp); =20 - ctx->offset +=3D tmp - arg; if (!close) { trace_probe_log_err(ctx->offset, DEREF_OPEN_BRACE); return -EINVAL; @@ -894,27 +880,66 @@ static int handle_typecast(char *arg, struct fetch_in= sn **pcode, TYPECAST_REQ_FIELD); return -EINVAL; } - - ctx->nested_level++; - if (ctx->nested_level > TRACEPROBE_MAX_NESTED_LEVEL) { - trace_probe_log_err(ctx->offset, TOO_MANY_NESTED); - return -E2BIG; + /* Skip '(' */ + ctx->offset +=3D 1; + tmp++; + } else if (*tmp =3D=3D '+' || *tmp =3D=3D '-') { + /* Dereference can have another field access inside it. */ + char *open =3D strchr(tmp + 1, '('); + + if (!open) { + trace_probe_log_err(ctx->offset, + DEREF_NEED_BRACE); + return -EINVAL; + } + close =3D find_matched_close_paren(open); + if (!close) { + trace_probe_log_err(ctx->offset + strlen(tmp), + DEREF_OPEN_BRACE); + return -EINVAL; + } + close++; + /* We expect a field access for typecast */ + if (close[0] !=3D '-' || close[1] !=3D '>') { + trace_probe_log_err(ctx->offset + close - tmp, + TYPECAST_REQ_FIELD); + return -EINVAL; + } + } else { + if (tmp[0] =3D=3D '@') { + /* @sym+offset is not allowed without parenthesized */ + close =3D strpbrk(tmp, "+-"); + if (close && isdigit(close[1])) { + trace_probe_log_err(ctx->offset, + TYPECAST_SYM_OFFSET); + return -EINVAL; + } } - *close =3D '\0'; + /* Inner variable name */ + close =3D strchr(tmp, '-'); + if (!close || close[1] !=3D '>') { + trace_probe_log_err(ctx->offset + strlen(tmp), + TYPECAST_REQ_FIELD); + return -EINVAL; + } + } + *close =3D '\0'; =20 - 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); + /* 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); =20 - tmp =3D close + 3;/* Skip "->" after closing parenthesis */ - nested =3D true; - } + /* Let tmp point the field name. */ + if (close[1] =3D=3D '-') + tmp =3D close + 3; /* Skip "->" after closing parenthesis */ + else + tmp =3D close + 2; /* Skip ">" after inner variable name */ =20 + /* resolve the typecast struct name */ ret =3D query_btf_struct(arg + 1, ctx); if (ret < 0) { trace_probe_log_err(orig_offset + 1, NO_PTR_STRCT); @@ -922,11 +947,7 @@ static int handle_typecast(char *arg, struct fetch_ins= n **pcode, } =20 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); + ret =3D parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx); return ret; } =20 diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 7d71925244e8..f4fbe3010978 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -453,6 +453,7 @@ struct traceprobe_parse_context { int nested_level; }; =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, @@ -592,7 +593,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_SYM_OFFSET, "@SYM+/-OFFSET with typecast needs parentheses") =20 #undef C #define C(a, b) TP_ERR_##a From nobody Sat Jun 27 16:57:49 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 466AC37C10C; Fri, 26 Jun 2026 14:15:39 +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=1782483340; cv=none; b=KOR+Z3fsleXJAzKdkeNEU1riv0qNx/tmdMYeQN/djSa8GelDdFBaf/Z99PJza9ehod901Ximp2OuKoaledbuHeUJmsfybyEoKJoNA+z/B0iZF/4NhqkYmXSLlB3fPBQ7t2/zGvcREn2d5KCOWQPGZFEW62/DPSz0D3SxyNe+7fQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483340; c=relaxed/simple; bh=eCMo9aVONaip3q5b5DtUrfcWhARWP+kFqF52DM9Q3zA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=OXugsFFAPC3BPDKTxWAAsWxhC8wkO7dpKTgwnS6HErWXpgpZ9IGKyNgfA9t6ogaWwH80bR6Z9gkmC8acsMcOyf55jn84iQ+6JxUJxwhoE9pPti++KO2/m0bkeFroDE2KZfbl9ZwE8tXiqLyYK0zYrpKBtSusX7w6Mm1bdBHOOas= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fkkNxFA3; 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="fkkNxFA3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D1B61F000E9; Fri, 26 Jun 2026 14:15:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483338; bh=revRSyWlFX1VZbewes3wJERg51uPaOy5r+JreHzpj+M=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fkkNxFA39sCKtJIB/5+Z5GuJKC6bPKrhHI/Q+PNvqRjIDlQ+BX95rrn4Dypv+MLhY aJaX8dAd2a4z0IP/akYrSUbaXsJvUsvezbZ+xl+AnXewQF7BF6y0SCMBSbOMedZco+ pi5bAZ++pDnknz3jIhr1onIjLXrJRhEQoQ0HklKfF79H77GyiJB3hZwNQETGEsJSkR 2vO880ycDcfSJzzp+gDeZBEtzJl/suVhtyvVVy+QMNbMdfWAcusozqyNRuLFmGUAtv 2SKWQX0XDgSkf5p2gr3B/biTW2FB5GDNwlkp0RxL7TLN9j7Er/io2Ke8ylIw7YxEtM Q77v/5gcAjp2w== 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: [PATCH v11 08/11] tracing/probes: Support field specifier option for typecast Date: Fri, 26 Jun 2026 23:15:34 +0900 Message-ID: <178248333421.841606.13236575618384239705.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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) --- Changes in v6: - Update according to the allways nested patch. Changes in v3: - Fix error caret position. Changes in v2: - Use byteoffset for typecast field offset instead of bitoffset. This fix= es negative modulo calculation. - Check whether a field is specified after typecast. - Reject if typecast field option has arrow operator. --- 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 | 5 + 6 files changed, 135 insertions(+), 64 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 e56ee034c486..5670c4b91dc0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4322,8 +4322,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 1b97b125e9cb..fd006b415c68 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -568,6 +568,64 @@ 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; + + 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, NULL); + 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. @@ -577,15 +635,13 @@ 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; =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); @@ -599,60 +655,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, NULL); - 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 */ code->offset =3D bitoffs / 8; + if (is_first_field && ctx->struct_btf) { + /* The first field can be typecasted with field option. */ + code->offset -=3D ctx->prefix_byteoffs; + } *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; @@ -808,6 +829,46 @@ 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; + } + if (field !=3D NULL) { + /* this means @field skips an arrow operator ("->"). */ + trace_probe_log_err(ctx->offset - 2, TYPECAST_BAD_ARROW); + return -EINVAL; + } + ctx->prefix_byteoffs =3D ret / 8; + /* 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) { @@ -940,14 +1001,14 @@ static int handle_typecast(char *arg, struct fetch_i= nsn **pcode, tmp =3D close + 2; /* Skip ">" after inner variable name */ =20 /* resolve the typecast struct name */ - ret =3D query_btf_struct(arg + 1, ctx); - if (ret < 0) { - trace_probe_log_err(orig_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; ret =3D parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx); + ctx->prefix_byteoffs =3D 0; return ret; } =20 diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index f4fbe3010978..e7fcc77f51fc 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -451,6 +451,7 @@ struct traceprobe_parse_context { unsigned int flags; int offset; int nested_level; + int prefix_byteoffs; /* The byte offset of the prefix field of typecast */ }; =20 /* Each typecast consumes nested level. So the max number of typecast is 3= . */ @@ -594,7 +595,9 @@ extern int traceprobe_define_arg_fields(struct trace_ev= ent_call *event_call, 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_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= "), =20 #undef C #define C(a, b) TP_ERR_##a From nobody Sat Jun 27 16:57:49 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 6C20B3F4DCC; Fri, 26 Jun 2026 14:15:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483350; cv=none; b=FSTcDeHsyJNtka0Sfx1gaiMfGXCOeA1aM7lueJFpNegl9zMytQ8sAGv+orPiK4GWq5j7iLTxMDlJ27IWE6DlHw9xC2Ot/TiI8eaNcfTQ22mYEExWV0DKtj9OTGrwB9m9Pot304VOEUanFHMNb7EsvZNB86Yl5A+RTqWkwGx2mRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483350; c=relaxed/simple; bh=drig70x3LDKb/KcxWYdMP7ptK8YdfuYh0CI1kyqzTUs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SAFzJx7Z17fvKGkyQy//zwCI1PDOsul8BQzag8SmsHoV/wqjwEwEMWCa2LFRkCywf6KD+IRYRvQXc3A0/K6qH6nleUDi9vCgHjqBSTL1If0WrGTcuEmYvNksWTJMkW+G7R3g+3ReAId/m0hrEu5iBv7+AO5HTJ0ox+QXtaXTrDg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K1X/XjHn; 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="K1X/XjHn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 542C11F000E9; Fri, 26 Jun 2026 14:15:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483349; bh=vuFV0DbmAe1vqGCg0Y3CpSUt5AojPHDM3aed7bIGyuc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=K1X/XjHnkdoYiMI4csGw0R6A26ts0jc9AwHVLfQ1/mb36NUA7Zcv7tqbSOHTF6WXp zmcoWOfC2qKbKcOW0qY+hzJCe06PZJcg36HHC0EhPKyw/kYeP+Jl79ulyWAbjm3NPE Dpd+tqTlG8Pk6E6cbaeM/3cKNrDeL7p8OxLThvvBnlI9Uvk1CFYLg/AGYgKep5tAvX Prb2BA9TzZw7GN7wnF90VWvcGrSzvo3H3hlAuMGmsnJsa9Xq/g6isq0JtHBYeVWCvf IMsv/a0jY1odp2nkNF/C63GdPWnajVumfHs+nLrlFs6jIlus9nx0wU35JnVsNFZQTv W0WNquS2nMubw== 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: [PATCH v11 09/11] tracing/probes: Add $current variable support Date: Fri, 26 Jun 2026 23:15:44 +0900 Message-ID: <178248334465.841606.6894609121925726269.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 info. e.g. $current->cpus_ptr Signed-off-by: Masami Hiramatsu (Google) --- Changes in v8: - Avoid uninitialized ctx->btf issue on $current without typecast. Changes in v7: - Fix to use force-typecast for task_struct implicitly. Changes in v6: - Rebased on dump fetcharg patch. - Remove function name/eprobe requirement for $current. Changes in v5: - Use s32 for bof_find_btf_id(). Changes in v4: - Add $current in README when CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=3Dy cas= e. - Fix to prohibit using $current in eprobes and address based kprobes. Changes in v3: - Remove $current support from eprobes (because eprobes is only for event) - Prohibit uprobes to use $current. Changes in v2: - Support to parse $current in parse_btf_arg(). - If no typecast on $current, it automatically casted to task_struct. - Check error case if $current follows something except for "-". --- Documentation/trace/fprobetrace.rst | 1 + Documentation/trace/kprobetrace.rst | 1 + kernel/trace/trace.c | 4 ++-- kernel/trace/trace_probe.c | 37 +++++++++++++++++++++++++++++++= +++- kernel/trace/trace_probe.h | 1 + kernel/trace/trace_probe_tmpl.h | 3 +++ 6 files changed, 44 insertions(+), 3 deletions(-) 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 5670c4b91dc0..2b0b4f9acb2e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4320,13 +4320,13 @@ static const char readme_msg[] =3D "\t args: =3Dfetcharg[:type]\n" "\t fetcharg: (%|$), @
, @[+|-]= ,\n" #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API - "\t $stack, $stack, $retval, $comm, $arg,\n" + "\t $stack, $stack, $retval, $comm, $arg, $current\n" #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS "\t [(structname[,field])][->field[->field|.field...]]= ,\n" "\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 fd006b415c68..999dec84275d 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -692,7 +692,9 @@ static int parse_btf_arg(char *varname, int i, is_ptr, ret; u32 tid; =20 - if (!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)) + /* Note: field is not separated at this point, so check prefix. */ + if (!str_has_prefix(varname, "$current") && + !ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)) return -EINVAL; =20 is_ptr =3D split_next_field(varname, &field, ctx); @@ -705,6 +707,20 @@ static int parse_btf_arg(char *varname, return -EOPNOTSUPP; } =20 + if (!strcmp(varname, "$current")) { + code->op =3D FETCH_OP_CURRENT; + /* If no typecast is specified for $current, use task_struct by default = */ + ret =3D bpf_find_btf_id("task_struct", BTF_KIND_STRUCT, &ctx->struct_btf= ); + if (ret < 0) { + trace_probe_log_err(ctx->offset, NO_BTF_ENTRY); + return -ENOENT; + } + tid =3D (u32)ret; + type =3D ctx->last_struct =3D + btf_type_skip_modifiers(ctx->struct_btf, tid, NULL); + goto found_type; + } + if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { code->op =3D FETCH_OP_RETVAL; /* Check whether the function return type is not void, even with typecas= t. */ @@ -761,6 +777,7 @@ static int parse_btf_arg(char *varname, =20 found: type =3D btf_type_skip_modifiers(ctx->btf, tid, NULL); +found_type: if (!type) { trace_probe_log_err(ctx->offset, BAD_BTF_TID); return -EINVAL; @@ -1270,6 +1287,24 @@ 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 (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; + + 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 e7fcc77f51fc..053f72fdaece 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -92,6 +92,7 @@ typedef int (*print_type_func_t)(struct trace_seq *, void= *, void *); FETCH_OP(RETVAL, none), /* Return value */ \ FETCH_OP(IMM, imm), /* Immediate: .immediate */ \ FETCH_OP(COMM, none), /* Current comm */ \ + FETCH_OP(CURRENT, none), /* Current task_struct address */\ FETCH_OP(ARG, param), /* Argument: .param =3D index */ \ FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \ FETCH_OP(IMMSTR, string), /* Allocated string: .data */ \ diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmp= l.h index 51436f19083b..d0e9662cde00 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_IMMSTR: *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:57:49 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 CF8C337C10C; Fri, 26 Jun 2026 14:15:58 +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=1782483360; cv=none; b=tEijkAyVJFKpiBEimY6hNCzZsplFiNTO0b3n+ExTAXLV3W4MYrwSKUdOUmZhMFng/1/LzNM6CEDyhNKmA684bYdf8OjUWZvqCONKwL737jUr41xa1wZxXA1nKiPPpw25EcLdlcg7pBoByR5n7L3j04CzD8gSrq6szbFxdGUWlMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483360; c=relaxed/simple; bh=JkKOXiqRWzoUFEyhz3V444ZCN63ERh8lu+J5zHQPIFA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HLv4jZTz/v82VQjN8g1YXRQeo8BSge46nK6rXvp5Fw5RhS6LVi670Pr+OaYUQ9UwwxUWeuRopYmEZko/kfViFVf7Z8J74WWhKsmMnOVEHw1vJ8zgibVxcN26U7kEDRbd28etDaiAXmNo2tCpYilaH7f2l9Y6Umc/7AbxdMLrEOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GFC5BWm4; 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="GFC5BWm4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D3BAC1F000E9; Fri, 26 Jun 2026 14:15:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483358; bh=jAz9eYFW/TGstkikzKlABHcINoyFGfVMQTkcWDY17SM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=GFC5BWm4JxDBTuz4VeaxQgdTZ+9QQeaN9ykADV656+LyphQChMYVsCMwhSrZTd28A WRHUF9Sup64oewk+vNEmh8hkfkb0KEWD9ATDrYJMFR3I433TxQBrYpfjoa7AW82b22 8i/4NvqzSPRdOxCotwBPg1g/0D5vcMzB87wI6Skk/h0S+Fck32zvwelMu7TjUFhoa2 qFVPPfVnwxK5Cb0X571lkJZgLC68yiAdyDqAgy0IqG+EoTkeMDtfNbk/RXyoYcgXem TigUbQhk1s0aTFjO4xr+mQKRJ4CrqbrEZ+EDFeTAoqcH3A/5OErOHov9H8S+E84Y/Y U6i+Zm1uUmyGQ== 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: [PATCH v11 10/11] tracing/probes: Add this_cpu_read() and this_cpu_ptr() dereference method to fetcharg Date: Fri, 26 Jun 2026 23:15:54 +0900 Message-ID: <178248335469.841606.15408438910653929255.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 this_cpu_read() dereference to access per-cpu variable for the current CPU (accessing other CPU variable may race with updates on other CPUs). Also this_cpu_ptr() is for accessing per-cpu pointer. Those are working as same as the kernel percpu macro. Signed-off-by: Masami Hiramatsu (Google) --- Changes in v11: - Remove this_cpu_*() from eprobetrace.rst. Changes in v10: - Prohibit this_cpu_*() for eprobe events. Changes in v9: - Prohibit this_cpu_*() for non kernel probes. Changes in v6: - Rebased on dump fetcharg patch. - Fix to fetch static percpu variable with @SYM correctly. Changes in v5: - Simplify this_cpu_read() into +0(this_cpu_ptr()). Changes in v3: - Remove NULL check for percpu var because it is just an offset, could be= 0. - Simplify process_fetch_insn_bottom() code. - If the last operation is this_cpu_read(), read only memory of the speci= fic size (of type). Changes in v2: - Drop +CPU/+PCPU and introduce this_cpu_read() and this_cpu_ptr(). - Support these method with BTF typecast. - Just check the base address is NOT NULL instead of is_kernel_percpu_add= ress(). --- Documentation/trace/fprobetrace.rst | 2=20 Documentation/trace/kprobetrace.rst | 2=20 kernel/trace/trace.c | 1=20 kernel/trace/trace_probe.c | 152 ++++++++++++++++++++++++++-----= ---- kernel/trace/trace_probe.h | 6 + kernel/trace/trace_probe_tmpl.h | 22 ++++- 6 files changed, 139 insertions(+), 46 deletions(-) diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fpro= betrace.rst index 3392cab016b3..3439bc9bd351 100644 --- a/Documentation/trace/fprobetrace.rst +++ b/Documentation/trace/fprobetrace.rst @@ -52,6 +52,8 @@ 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) + this_cpu_read(FETCHARG) : Read the value of the per-CPU variable FETCHAR= G on the current CPU. + this_cpu_ptr(FETCHARG) : Get the address of the per-CPU variable FETCHAR= G on the current CPU. \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..9ae330eb0a52 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -55,6 +55,8 @@ 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) + this_cpu_read(FETCHARG) : Read the value of the per-CPU variable FETCHAR= G on the current CPU. + this_cpu_ptr(FETCHARG) : Get the address of the per-CPU variable FETCHAR= G on the current CPU. \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 2b0b4f9acb2e..c9e182d40059 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4329,6 +4329,7 @@ static const char readme_msg[] =3D "\t $stack, $stack, $retval, $comm, $current\n" #endif "\t +|-[u](), \\imm-value, \\\"imm-string\"\n" + "\t this_cpu_read(), 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 999dec84275d..18c212122344 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -345,6 +345,109 @@ static int parse_trace_event(char *arg, struct fetch_= insn *code, return -EINVAL; } =20 +/* this_cpu_* parser */ +#define THIS_CPU_PTR_PREFIX "this_cpu_ptr(" +#define THIS_CPU_READ_PREFIX "this_cpu_read(" +#define THIS_CPU_PTR_LEN (sizeof(THIS_CPU_PTR_PREFIX) - 1) +#define THIS_CPU_READ_LEN (sizeof(THIS_CPU_READ_PREFIX) - 1) + +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); + +/* 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) +{ + 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; + + /* + * This is only for kernel probes, excluding eprobe, because per-cpu + * pointer should not be recorded by events. + */ + if (!(ctx->flags & TPARG_FL_KERNEL) || + (ctx->flags & TPARG_FL_TEVENT)) { + trace_probe_log_err(ctx->offset, NOSUP_PERCPU); + return -EINVAL; + } + if (str_has_prefix(arg, THIS_CPU_PTR_PREFIX)) { + arg +=3D THIS_CPU_PTR_LEN; + ctx->offset +=3D THIS_CPU_PTR_LEN; + is_ptr =3D true; + } else if (str_has_prefix(arg, THIS_CPU_READ_PREFIX)) { + arg +=3D THIS_CPU_READ_LEN; + ctx->offset +=3D THIS_CPU_READ_LEN; + } else + return -EINVAL; + + 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); + return -EINVAL; + } + code->op =3D FETCH_OP_DEREF; + code->offset =3D 0; + *pcode =3D code; + return 0; +} + #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS =20 static u32 btf_type_int(const struct btf_type *t) @@ -904,11 +1007,6 @@ static char *find_matched_close_paren(char *s) return NULL; } =20 -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) @@ -961,7 +1059,9 @@ static int handle_typecast(char *arg, struct fetch_ins= n **pcode, /* Skip '(' */ ctx->offset +=3D 1; tmp++; - } else if (*tmp =3D=3D '+' || *tmp =3D=3D '-') { + } else if (*tmp =3D=3D '+' || *tmp =3D=3D '-' || + str_has_prefix(tmp, THIS_CPU_PTR_PREFIX) || + str_has_prefix(tmp, THIS_CPU_READ_PREFIX)) { /* Dereference can have another field access inside it. */ char *open =3D strchr(tmp + 1, '('); =20 @@ -1481,36 +1581,9 @@ parse_probe_arg(char *arg, const struct fetch_type *= type, } 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), - DEREF_OPEN_BRACE); - return -EINVAL; - } else { - const struct fetch_type *t2 =3D find_fetch_type(NULL, ctx->flags); - int cur_offs =3D ctx->offset; - - *tmp =3D '\0'; - ret =3D parse_probe_arg(arg, t2, &code, end, ctx); - if (ret) - break; - 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; - } - 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; - } + ret =3D handle_dereference(arg, pcode, end, ctx, deref, offset); + if (ret < 0) + return ret; break; case '\\': /* Immediate value */ if (arg[1] =3D=3D '"') { /* Immediate string */ @@ -1531,7 +1604,10 @@ parse_probe_arg(char *arg, const struct fetch_type *= type, ret =3D handle_typecast(arg, pcode, end, ctx); break; default: - if (isalpha(arg[0]) || arg[0] =3D=3D '_') { + 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); @@ -1548,8 +1624,8 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, return -EINVAL; } ret =3D parse_btf_arg(arg, pcode, end, ctx); - break; } + break; } if (!ret && code->op =3D=3D FETCH_OP_NOP) { /* Parsed, but do not find fetch method */ diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 053f72fdaece..e6268a8dc378 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -101,6 +101,7 @@ typedef int (*print_type_func_t)(struct trace_seq *, vo= id *, void *); /* Stage 2 (dereference) ops */ \ FETCH_OP(DEREF, offset), /* Dereference: .offset */ \ FETCH_OP(UDEREF, offset), /* User-space dereference: .offset */\ + FETCH_OP(CPU_PTR, none), /* Per-CPU pointer: .offset */ \ /* Stage 3 (store) ops */ \ FETCH_OP(ST_RAW, store), /* Raw value: .size */ \ FETCH_OP(ST_MEM, store), /* Memory: .offset, .size */ \ @@ -596,9 +597,10 @@ extern int traceprobe_define_arg_fields(struct trace_e= vent_call *event_call, 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_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(TYPECAST_BAD_ARROW, "Typecast field option does not support -> operator= "), \ + C(NOSUP_PERCPU, "Per-cpu variable access is only for kernel probes"), =20 #undef C #define C(a, b) TP_ERR_##a diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmp= l.h index d0e9662cde00..8db12f758fda 100644 --- a/kernel/trace/trace_probe_tmpl.h +++ b/kernel/trace/trace_probe_tmpl.h @@ -129,25 +129,35 @@ 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_CPU_PTR: + val =3D (unsigned long)this_cpu_ptr((void __percpu *)val); + 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:57:49 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 837263F6C2C; Fri, 26 Jun 2026 14:16:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483370; cv=none; b=ae1/nKjdghHojDK+eMKt5MWT4+FWfwYorkVUir+BrIlaNxl+/rUaQOCAIhz3XJEQZHBvhs9TiqrjHjlksKHw9HDA9jU9U9HDWDiHBkm0UCbayhzp9kcrW6OkFFazu3Ccxc1Zft7ag9CehXtfslLuvlpmY+Pqlzq4o8MAqE+RY9M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782483370; c=relaxed/simple; bh=v38HuRAPB1YghbZm/zrLEtyLcRRjS/lfbOA4KknZHBg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=neR5dIt73s/Dji6BfJwkDo5CzdbtDL9qTgNUb4dYC8y6lx9gZMZ+kc8tHoWILbbuNu5YqbOi1FJ8XHPzQx6Xr5l9SZErE2JmRmu7BNCAw5w3GnFpW+iH0V5SDoSkedK96NU9c1Xn37bnV2ZBKg0TfbvK47wd/a/9Syr6VIOW58M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mAznQvzb; 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="mAznQvzb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 12CA21F000E9; Fri, 26 Jun 2026 14:16:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782483368; bh=RIgEUpim9TavyCOWPX7oI/d1ffPlhM2XO/uhjaJYBAg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mAznQvzbUcKJyo7qDj0docebWug36gzChNe6eJOIVUWSFdVw4V0S1esJ6VkxvnQXf jyP6Ut/2jufZY+ozudWtKqr4d648LA+fbevIV989pJaZLyNmg86WQylF5sFKm1uhLB JUQOWKlxnjN24zfJ9zX0IgK/M6Bt2gZmxE09SymYK/dAmVOJ24PPjV91ZC7Tk+DHhn Hy3d2cURlgGBC7PCezArucmIdSlgUvTETeqxdRvgbpRzGkQmXywB4Srjfjrh0E1Zys awkUp/6HV+s8qVR+WWhJPlW7vHB32MeeTgvbGYyi/w+CWx7gjSgE48Qz0LHngGfeMQ EtUzmgst/G7Hw== 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: [PATCH v11 11/11] tracing/probes: Add a new testcase for BTF typecasts Date: Fri, 26 Jun 2026 23:16:04 +0900 Message-ID: <178248336390.841606.1695444929833877704.stgit@devnote2> X-Mailer: git-send-email 2.43.0 In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2> References: <178248325671.841606.17344906774310339507.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 this_cpu_read() 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) --- Changes in v11: - nit: fix the error code in comment. Changes in v10: - Add a check for $current and this_cpu_* for eprobe Changes in v9: - Add a testcase for checking new syntax. Changes in v8: - Add more test cases. Changes in v6: - Update testcase according to changes. Changes in v5: - Add more syntax test cases. Changes in v4: - Fix uprobe $current test. Changes in v3: - Add syntax test case. - Update testcase to use this_cpu_read() Changes in v2: - Use timer_shutdown_sync() instead of timer_delete_sync() for teardown. --- samples/trace_events/trace-events-sample.c | 40 +++++++ samples/trace_events/trace-events-sample.h | 34 ++++++ .../ftrace/test.d/dynevent/btf_probe_event.tc | 51 ++++++++++ .../test.d/dynevent/btf_typecast_accepted.tc | 107 ++++++++++++++++= ++++ .../test.d/dynevent/eprobes_syntax_errors.tc | 9 ++ .../ftrace/test.d/dynevent/fprobe_syntax_errors.tc | 12 ++ .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc | 12 ++ .../ftrace/test.d/kprobe/uprobe_syntax_errors.tc | 5 + 8 files changed, 265 insertions(+), 5 deletions(-) create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_prob= e_event.tc create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_type= cast_accepted.tc diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_eve= nts/trace-events-sample.c index 0b7a6efdb247..ca5d98c360cb 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); @@ -132,9 +146,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)) - return -1; + if (IS_ERR(simple_tsk)) { + timer_shutdown_sync(&foo_timer_data->timer); + free_percpu(foo_timer_data->counter); + kfree(foo_timer_data); + return PTR_ERR(simple_tsk); + } =20 return 0; } @@ -147,6 +179,10 @@ static void __exit trace_event_exit(void) kthread_stop(simple_tsk_fn); simple_tsk_fn =3D NULL; mutex_unlock(&thread_mutex); + + timer_shutdown_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..96791e120b7d --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc @@ -0,0 +1,51 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: BTF event with typecast and percpu access +# requires: dynamic_events "this_cpu_read()":README "[(structnam= e[,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 this_cpu_read() access. +# (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. +# this_cpu_read(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=3Dthis_cpu_read((foo_timer_data,timer)t->counter)' >> dyna= mic_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 diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_ac= cepted.tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_acc= epted.tc new file mode 100644 index 000000000000..acf0b5a917d3 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.= tc @@ -0,0 +1,107 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: BTF typecast and percpu access syntax validation +# requires: dynamic_events "this_cpu_read()":README "[(structnam= e[,field])][->field[->field|.field...]]":README + +KPROBES=3D +FPROBES=3D + +if grep -qF "p[:[/][]] []" README ; then + KPROBES=3Dyes +fi +if grep -qF "f[:[/][]] [%return] []" README= ; then + FPROBES=3Dyes +fi + +if [ -z "$KPROBES" -a -z "$FPROBES" ] ; then + exit_unsupported +fi + +echo 0 > events/enable +echo > dynamic_events + +# Load trace-events-sample module if available to have per-CPU counter str= ucture defined +if ! lsmod | grep -q trace_events_sample; then + modprobe trace-events-sample || true +fi + +if [ "$FPROBES" ] ; then + # 1. Test basic typecast on fprobe + echo 'f:fpevent1 vfs_read name=3D(file)file->f_path.dentry->d_name.name:= string' >> dynamic_events + # 2. Test parenthesized typecast target on fprobe + echo 'f:fpevent2 vfs_read name=3D(file)(file)->f_path.dentry->d_name.nam= e:string' >> dynamic_events + # 3. Test nested typecasts on fprobe + echo 'f:fpevent3 vfs_read name=3D(dentry)((file)file->f_path.dentry)->d_= name.name:string' >> dynamic_events + # 4. Test container_of-style typecast with field option on fprobe + echo 'f:fpevent4 vfs_read name=3D(file,f_path)file->f_mode' >> dynamic_e= vents + # 5. Test typecast on return value on fprobe + echo 'f:fpevent5 vfs_read%return name=3D(file)$retval->f_path.dentry->d_= name.name:string' >> dynamic_events + # 6. Test $current variable support on fprobe + echo 'f:fpevent6 vfs_read pid=3D$current->pid' >> dynamic_events + echo 'f:fpevent7 vfs_read pid=3D(task_struct)$current->pid' >> dynamic_e= vents + echo 'f:fpevent8 vfs_read pid=3D(task_struct,group_leader)$current->pid'= >> dynamic_events + + # Test this_cpu_read and this_cpu_ptr on fprobe + if lsmod | grep -q trace_events_sample; then + echo 'f:fpevent9 sample_timer_cb name=3D(foo_timer_data,timer)t->name:= string count=3Dthis_cpu_read((foo_timer_data,timer)t->counter)' >> dynamic_= events + echo 'f:fpevent10 sample_timer_cb ptr=3Dthis_cpu_ptr((foo_timer_data,t= imer)t->counter)' >> dynamic_events + fi +fi + +if [ "$KPROBES" ] ; then + # 7. Test basic typecast on kprobe + echo 'p:kpevent1 vfs_read name=3D(file)file->f_path.dentry->d_name.name:= string' >> dynamic_events + # 8. Test parenthesized typecast target on kprobe + echo 'p:kpevent2 vfs_read name=3D(file)(file)->f_path.dentry->d_name.nam= e:string' >> dynamic_events + # 9. Test nested typecasts on kprobe + echo 'p:kpevent3 vfs_read name=3D(dentry)((file)file->f_path.dentry)->d_= name.name:string' >> dynamic_events + # 10. Test container_of-style typecast with field option on kprobe + echo 'p:kpevent4 vfs_read name=3D(file,f_path)file->f_mode' >> dynamic_e= vents + # 11. Test typecast on return value on kretprobe + echo 'r:kpevent5 vfs_read name=3D(file)$retval->f_path.dentry->d_name.na= me:string' >> dynamic_events + # 12. Test $current variable support on kprobe + echo 'p:kpevent6 vfs_read pid=3D$current->pid' >> dynamic_events + echo 'p:kpevent7 vfs_read pid=3D(task_struct)$current->pid' >> dynamic_e= vents + echo 'p:kpevent8 vfs_read pid=3D(task_struct,group_leader)$current->pid'= >> dynamic_events + + # Test this_cpu_read and this_cpu_ptr on kprobe + if lsmod | grep -q trace_events_sample; then + echo 'p:kpevent9 sample_timer_cb name=3D(foo_timer_data,timer)t->name:= string count=3Dthis_cpu_read((foo_timer_data,timer)t->counter)' >> dynamic_= events + echo 'p:kpevent10 sample_timer_cb ptr=3Dthis_cpu_ptr((foo_timer_data,t= imer)t->counter)' >> dynamic_events + fi +fi + +# Verify the events exist in dynamic_events +if [ "$FPROBES" ] ; then + grep -q "fpevent1 " dynamic_events + grep -q "fpevent2 " dynamic_events + grep -q "fpevent3 " dynamic_events + grep -q "fpevent4 " dynamic_events + grep -q "fpevent5 " dynamic_events + grep -q "fpevent6 " dynamic_events + grep -q "fpevent7 " dynamic_events + grep -q "fpevent8 " dynamic_events + if lsmod | grep -q trace_events_sample; then + grep -q "fpevent9 " dynamic_events + grep -q "fpevent10 " dynamic_events + fi +fi + +if [ "$KPROBES" ] ; then + grep -q "kpevent1 " dynamic_events + grep -q "kpevent2 " dynamic_events + grep -q "kpevent3 " dynamic_events + grep -q "kpevent4 " dynamic_events + grep -q "kpevent5 " dynamic_events + grep -q "kpevent6 " dynamic_events + grep -q "kpevent7 " dynamic_events + grep -q "kpevent8 " dynamic_events + if lsmod | grep -q trace_events_sample; then + grep -q "kpevent9 " dynamic_events + grep -q "kpevent10 " dynamic_events + fi +fi + +# Clean up +echo > dynamic_events +clear_trace diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_= errors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_e= rrors.tc index 0e65e787e426..1d6d1cf94f16 100644 --- a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.= tc +++ b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.= tc @@ -21,8 +21,17 @@ check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # B= AD_EVENT_NAME =20 check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^$foo' # BAD_ATTACH= _ARG =20 +check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^COMM' # NO_EVENT_F= IELD +if grep -q '\\$current' README; then + check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^current' # NO_EV= ENT_FIELD +fi + if grep -q '\..*\[if \]' README; t= hen check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER fi =20 +if grep -q 'this_cpu_read()' README; then + check_error 'e:foo/bar syscalls/sys_enter_openat arg=3D^this_cpu_read(fi= le)' # NOSUP_PERCPU +fi + exit 0 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 fee479295e2f..e9d7e6919c7f 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 @@ -112,6 +112,18 @@ check_error 'f vfs_read%return $retval->^foo' # NO_PTR= _STRCT check_error 'f vfs_read file->^foo' # NO_BTF_FIELD 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(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 +check_error 'f vfs_read arg1=3D(task_struct,se^->group_node)file->comm' # = TYPECAST_BAD_ARROW +check_error 'f vfs_read arg1=3D(task_struct,^->pid)file->comm' # NO_BTF_FI= ELD +check_error 'f vfs_read arg1=3D(task_struct,^.pid)file->comm' # NO_BTF_FIE= LD +check_error 'f vfs_read arg1=3D(task_struct,^.)file->comm' # NO_BTF_FIELD +check_error 'f vfs_read arg1=3D(task_struct)^@symbol+10->comm' # TYPECAST_= SYM_OFFSET +fi fi =20 else 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 8f1c58f0c239..21ce8414459f 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 @@ -115,6 +115,18 @@ check_error 'p vfs_read+20 ^$arg*' # NOFENTRY_ARGS check_error 'p vfs_read ^hoge' # NO_BTFARG check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of paramete= rs) 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(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 +check_error 'p vfs_read arg1=3D(task_struct,se^->group_node)file->comm' # = TYPECAST_BAD_ARROW +check_error 'p vfs_read arg1=3D(task_struct,^->pid)file->comm' # NO_BTF_FI= ELD +check_error 'p vfs_read arg1=3D(task_struct,^.pid)file->comm' # NO_BTF_FIE= LD +check_error 'p vfs_read arg1=3D(task_struct,^.)file->comm' # NO_BTF_FIELD +check_error 'p vfs_read arg1=3D(task_struct)^@symbol+10->comm' # TYPECAST_= SYM_OFFSET +fi else check_error 'p vfs_read ^$arg*' # NOSUP_BTFARG fi diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_err= ors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.= tc index c817158b99db..e12dc967ec76 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc @@ -28,4 +28,9 @@ if grep -q ".*symstr.*" README; then check_error 'p /bin/sh:10 $stack0:^symstr' # BAD_TYPE fi =20 +# $current is not supported by uprobe +if grep -q "\$current.*" README; then +check_error 'p /bin/sh:10 ^$current:u8' # BAD_VAR +fi + exit 0