Skip to contentSkip to conversation

tracing: Add 'within' filter logic

PATCH New Steven Rostedt 1 participant 3 messages Aug 21

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover tracing: Add 'within' filter logic

Add a "within" filter predicate that tests whether a given function appears in the current call stack at event time. The function name is resolved to its address range via kallsyms during filter setup; at runtime, stack_trace_save() captures the call stack and compares each return address against the stored range.

Changes since v1: https://lore.kernel.org/linux-trace-kernel/[email protected]

- Added patch to show error message

Chen Jun (1):
tracing: Add "within" filter for call-stack-based event filtering

Steven Rostedt (1):
tracnig: Add proper error message for glob use with "within" filter

----

 Documentation/trace/events.rst     | 12 +++++++++++
 include/linux/trace_events.h       |  1 +
 kernel/trace/trace.h               |  3 ++-
 kernel/trace/trace_events.c        |  3 +++
 kernel/trace/trace_events_filter.c | 44 ++++++++++++++++++++++++++++++++++++--
 5 files changed, 60 insertions(+), 3 deletions(-)
#1 lore raw

PATCH v2 1/2 tracing: Add "within" filter for call-stack-based event filtering

From: Chen Jun <[email protected]>

Low-level kernel functions are called from many different paths. When debugging, it is often useful to filter trace events to only those occurring within a specific call chain.

Add a "within" filter predicate that tests whether a given function appears in the current call stack at event time. The function name is resolved to its address range via kallsyms during filter setup; at runtime, stack_trace_save() captures the call stack and compares each return address against the stored range.

Example:
echo 'within == "vfs_read"' > events/sched/sched_switch/filter

Only "==" and "!=" operators are supported. The filter depends on CONFIG_STACKTRACE.

---
 Documentation/trace/events.rst     | 12 +++++++++
 include/linux/trace_events.h       |  1 +
 kernel/trace/trace.h               |  3 ++-
 kernel/trace/trace_events.c        |  3 +++
 kernel/trace/trace_events_filter.c | 41 ++++++++++++++++++++++++++++--
 5 files changed, 57 insertions(+), 3 deletions(-)
Documentation/trace/events.rst +12 -0
index 581f2260614b..a1a219208ecc 100644
@@ -243,6 +243,18 @@ the function "security_prepare_creds" and less than the end of that function.
 The ".function" postfix can only be attached to values of size long, and can only
 be compared with "==" or "!=".
 
+The special field "within" can be used to filter events based on whether
+a specific function appears in the current call stack::
+
+  within == "function_name"
+  within != "function_name"
+
+For example, to only trace events where "vfs_read" is in the call stack::
+
+  # echo 'within == "vfs_read"' > events/sched/sched_switch/filter
+
+The within field supports only the "==" and "!=" operators.
+
 Cpumask fields or scalar fields that encode a CPU number can be filtered using
 a user-provided cpumask in cpulist format. The format is as follows::
 
include/linux/trace_events.h +1 -0
index 5cbd09c8be8d..d0259a515a83 100644
@@ -872,6 +872,7 @@ enum {
 	FILTER_COMM,
 	FILTER_CPU,
 	FILTER_STACKTRACE,
+	FILTER_WITHIN,
 };
 
 extern int trace_event_raw_init(struct trace_event_call *call);
kernel/trace/trace.h +2 -1
index 74a7a50d1e78..92eee3eca43a 100644
@@ -1825,7 +1825,8 @@ static inline bool is_string_field(struct ftrace_event_field *field)
 	       field->filter_type == FILTER_RDYN_STRING ||
 	       field->filter_type == FILTER_STATIC_STRING ||
 	       field->filter_type == FILTER_PTR_STRING ||
-	       field->filter_type == FILTER_COMM;
+	       field->filter_type == FILTER_COMM ||
+	       field->filter_type == FILTER_WITHIN;
 }
 
 static inline bool is_function_field(struct ftrace_event_field *field)
kernel/trace/trace_events.c +3 -0
index 7313eb1361c9..874c0c023eb1 100644
@@ -201,6 +201,9 @@ static int trace_define_generic_fields(void)
 	__generic_field(char *, comm, FILTER_COMM);
 	__generic_field(char *, stacktrace, FILTER_STACKTRACE);
 	__generic_field(char *, STACKTRACE, FILTER_STACKTRACE);
+#ifdef CONFIG_STACKTRACE
+	__generic_field(char *, within, FILTER_WITHIN);
+#endif
 
 	return ret;
 }
kernel/trace/trace_events_filter.c +39 -2

67 lines not on this page · raw message

Signature · 1 line
2.53.0
#2 lore raw

PATCH v2 2/2 tracnig: Add proper error message for glob use with "within" filter

In reply to Steven Rostedt

From: Steven Rostedt <[email protected]>

If a user were to use a glob expression with the "within" filter, it currently just fails with an errno return but does not update the error_log to tell the user why it failed. Update it to use the parsing error log to tell the user why it failed.

  # echo 'within ~ "*_read"' > events/kmem/kmem_cache_alloc/filter
  -bash: echo: write error: Invalid argument
  # cat error_log
  [ 4676.606481] event filter parse error: error: 'within' filter cannot take glob expressions
    Command: within ~ "*_read"
                              ^
---
 kernel/trace/trace_events_filter.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
kernel/trace/trace_events_filter.c +4 -1
index 297bf156ea65..f811c527cce8 100644
@@ -118,6 +118,7 @@ struct filter_pred {
 	C(IP_FIELD_ONLY,	"Only 'ip' field is supported for function trace"), \
 	C(INVALID_VALUE,	"Invalid value (did you forget quotes)?"), \
 	C(NO_FUNCTION,		"Function not found"),			\
+	C(GLOB_WITHIN,		"'within' filter cannot take glob expressions"), \
 	C(ERRNO,		"Error"),				\
 	C(NO_FILTER,		"No filter found")
 
@@ -2024,8 +2025,10 @@ static int parse_pred(const char *str, void *data,
 		} else if (field->filter_type == FILTER_WITHIN) {
 			unsigned long func;
 
-			if (op == OP_GLOB)
+			if (op == OP_GLOB) {
+				parse_error(pe, FILT_ERR_GLOB_WITHIN, pos + i);
 				goto err_free;
+			}
 
 			pred->fn_num = FILTER_PRED_FN_WITHIN;
 			func = kallsyms_lookup_name(pred->regex->pattern);
Signature · 1 line
2.53.0