History

ftrace: Add MODIFIED flag to show if IPMODIFY or direct was attached

If a function had ever had IPMODIFY or DIRECT attached to it, where this is how live kernel patching and BPF overrides work, mark them and display an "M" in the enabled_functions and touched_functions files. This can be used for debugging. If a function had been modified and later there's a bug in the code related to that function, this can be used to know if the cause is possibly from a live kernel patch or a BPF program that changed the behavior of the code. Also update the documentation on the enabled_functions and touched_functions output, as it was missing direct callers and CALL_OPS. And include this new modify attribute. Link: https://lore.kernel.org/linux-trace-kernel/20230502213233.004e3ae4@gandalf.local.home

Steven Rostedt (Google) committed 3 years ago

Commit 6ce2c041 parent 4f945593 files · +37 −4Browse files

Unified · Split

3 files
  1. Documentation/trace/ftrace.rst +25 −0
  2. include/linux/ftrace.h +3 −1
  3. kernel/trace/ftrace.c +9 −3
Documentation/trace/ftrace.rst+25−0
@@ -350,6 +350,19 @@ of ftrace. Here is a list of some of the key files: · 349 unmodified lines
350350 an 'I' will be displayed on the same line as the function that
351351 can be overridden.
352352
353+ If a non ftrace trampoline is attached (BPF) a 'D' will be displayed.
354+ Note, normal ftrace trampolines can also be attached, but only one
355+ "direct" trampoline can be attached to a given function at a time.
356+
357+ Some architectures can not call direct trampolines, but instead have
358+ the ftrace ops function located above the function entry point. In
359+ such cases an 'O' will be displayed.
360+
361+ If a function had either the "ip modify" or a "direct" call attached to
362+ it in the past, a 'M' will be shown. This flag is never cleared. It is
363+ used to know if a function was every modified by the ftrace infrastructure,
364+ and can be used for debugging.
365+
353366 If the architecture supports it, it will also show what callback
354367 is being directly called by the function. If the count is greater
355368 than 1 it most likely will be ftrace_ops_list_func().
@@ -359,6 +372,18 @@ of ftrace. Here is a list of some of the key files: · 3 unmodified lines
359372 its address will be printed as well as the function that the
360373 trampoline calls.
361374
375+ touched_functions:
376+
377+ This file contains all the functions that ever had a function callback
378+ to it via the ftrace infrastructure. It has the same format as
379+ enabled_functions but shows all functions that have every been
380+ traced.
381+
382+ To see any function that has every been modified by "ip modify" or a
383+ direct trampoline, one can perform the following command:
384+
385+ grep ' M ' /sys/kernel/tracing/touched_functions
386+
362387 function_profile_enabled:
363388
364389 When set it will enable all functions with either the function
include/linux/ftrace.h+3−1
@@ -549,6 +549,7 @@ bool is_ftrace_trampoline(unsigned long addr); · 548 unmodified lines
549549 * CALL_OPS - the record can use callsite-specific ops
550550 * CALL_OPS_EN - the function is set up to use callsite-specific ops
551551 * TOUCHED - A callback was added since boot up
552+ * MODIFIED - The function had IPMODIFY or DIRECT attached to it
552553 *
553554 * When a new ftrace_ops is registered and wants a function to save
554555 * pt_regs, the rec->flags REGS is set. When the function has been
@@ -569,9 +570,10 @@ enum { · 14 unmodified lines
569570 FTRACE_FL_CALL_OPS = (1UL << 22),
570571 FTRACE_FL_CALL_OPS_EN = (1UL << 21),
571572 FTRACE_FL_TOUCHED = (1UL << 20),
573+ FTRACE_FL_MODIFIED = (1UL << 19),
572574 };
573575
574−#define FTRACE_REF_MAX_SHIFT 20
576+#define FTRACE_REF_MAX_SHIFT 19
575577 #define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1)
576578
577579 #define ftrace_rec_count(rec) ((rec)->flags & FTRACE_REF_MAX)
kernel/trace/ftrace.c+9−3
@@ -46,7 +46,8 @@ · 45 unmodified lines
4646 #include "trace_stat.h"
4747
4848 /* Flags that do not get reset */
49−#define FTRACE_NOCLEAR_FLAGS (FTRACE_FL_DISABLED | FTRACE_FL_TOUCHED)
49+#define FTRACE_NOCLEAR_FLAGS (FTRACE_FL_DISABLED | FTRACE_FL_TOUCHED | \
50+ FTRACE_FL_MODIFIED)
5051
5152 #define FTRACE_INVALID_FUNCTION "__ftrace_invalid_address__"
5253
@@ -2273,6 +2274,10 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update) · 2220 unmodified lines
22732274 rec->flags &= ~FTRACE_FL_TRAMP_EN;
22742275 }
22752276
2277+ /* Keep track of anything that modifies the function */
2278+ if (rec->flags & (FTRACE_FL_DIRECT | FTRACE_FL_IPMODIFY))
2279+ rec->flags |= FTRACE_FL_MODIFIED;
2280+
22762281 if (flag & FTRACE_FL_DIRECT) {
22772282 /*
22782283 * If there's only one user (direct_ops helper)
@@ -3866,12 +3871,13 @@ static int t_show(struct seq_file *m, void *v) · 1587 unmodified lines
38663871 if (iter->flags & (FTRACE_ITER_ENABLED | FTRACE_ITER_TOUCHED)) {
38673872 struct ftrace_ops *ops;
38683873
3869− seq_printf(m, " (%ld)%s%s%s%s",
3874+ seq_printf(m, " (%ld)%s%s%s%s%s",
38703875 ftrace_rec_count(rec),
38713876 rec->flags & FTRACE_FL_REGS ? " R" : " ",
38723877 rec->flags & FTRACE_FL_IPMODIFY ? " I" : " ",
38733878 rec->flags & FTRACE_FL_DIRECT ? " D" : " ",
3874− rec->flags & FTRACE_FL_CALL_OPS ? " O" : " ");
3879+ rec->flags & FTRACE_FL_CALL_OPS ? " O" : " ",
3880+ rec->flags & FTRACE_FL_MODIFIED ? " M " : " ");
38753881 if (rec->flags & FTRACE_FL_TRAMP_EN) {
38763882 ops = ftrace_find_tramp_ops_any(rec);
38773883 if (ops) {