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
350 an 'I' will be displayed on the same line as the function that350 an 'I' will be displayed on the same line as the function that
351 can be overridden.351 can be overridden.
352 352
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
353 If the architecture supports it, it will also show what callback366 If the architecture supports it, it will also show what callback
354 is being directly called by the function. If the count is greater367 is being directly called by the function. If the count is greater
355 than 1 it most likely will be ftrace_ops_list_func().368 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
359 its address will be printed as well as the function that the372 its address will be printed as well as the function that the
360 trampoline calls.373 trampoline calls.
361 374
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
362 function_profile_enabled:387 function_profile_enabled:
363 388
364 When set it will enable all functions with either the function389 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
549 * CALL_OPS - the record can use callsite-specific ops549 * CALL_OPS - the record can use callsite-specific ops
550 * CALL_OPS_EN - the function is set up to use callsite-specific ops550 * CALL_OPS_EN - the function is set up to use callsite-specific ops
551 * TOUCHED - A callback was added since boot up551 * TOUCHED - A callback was added since boot up
552 * MODIFIED - The function had IPMODIFY or DIRECT attached to it
552 *553 *
553 * When a new ftrace_ops is registered and wants a function to save554 * When a new ftrace_ops is registered and wants a function to save
554 * pt_regs, the rec->flags REGS is set. When the function has been555 * pt_regs, the rec->flags REGS is set. When the function has been
@@ -569,9 +570,10 @@ enum { · 14 unmodified lines
569 FTRACE_FL_CALL_OPS = (1UL << 22),570 FTRACE_FL_CALL_OPS = (1UL << 22),
570 FTRACE_FL_CALL_OPS_EN = (1UL << 21),571 FTRACE_FL_CALL_OPS_EN = (1UL << 21),
571 FTRACE_FL_TOUCHED = (1UL << 20),572 FTRACE_FL_TOUCHED = (1UL << 20),
573 FTRACE_FL_MODIFIED = (1UL << 19),
572};574};
573 575
574#define FTRACE_REF_MAX_SHIFT 20576#define FTRACE_REF_MAX_SHIFT 19
575#define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1)577#define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1)
576 578
577#define ftrace_rec_count(rec) ((rec)->flags & FTRACE_REF_MAX)579#define ftrace_rec_count(rec) ((rec)->flags & FTRACE_REF_MAX)
kernel/trace/ftrace.c+9−3
@@ -46,7 +46,8 @@ · 45 unmodified lines
46#include "trace_stat.h"46#include "trace_stat.h"
47 47
48/* Flags that do not get reset */48/* 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)
50 51
51#define FTRACE_INVALID_FUNCTION "__ftrace_invalid_address__"52#define FTRACE_INVALID_FUNCTION "__ftrace_invalid_address__"
52 53
@@ -2273,6 +2274,10 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update) · 2220 unmodified lines
2273 rec->flags &= ~FTRACE_FL_TRAMP_EN;2274 rec->flags &= ~FTRACE_FL_TRAMP_EN;
2274 }2275 }
2275 2276
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
2276 if (flag & FTRACE_FL_DIRECT) {2281 if (flag & FTRACE_FL_DIRECT) {
2277 /*2282 /*
2278 * If there's only one user (direct_ops helper)2283 * 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
3866 if (iter->flags & (FTRACE_ITER_ENABLED | FTRACE_ITER_TOUCHED)) {3871 if (iter->flags & (FTRACE_ITER_ENABLED | FTRACE_ITER_TOUCHED)) {
3867 struct ftrace_ops *ops;3872 struct ftrace_ops *ops;
3868 3873
3869 seq_printf(m, " (%ld)%s%s%s%s",3874 seq_printf(m, " (%ld)%s%s%s%s%s",
3870 ftrace_rec_count(rec),3875 ftrace_rec_count(rec),
3871 rec->flags & FTRACE_FL_REGS ? " R" : " ",3876 rec->flags & FTRACE_FL_REGS ? " R" : " ",
3872 rec->flags & FTRACE_FL_IPMODIFY ? " I" : " ",3877 rec->flags & FTRACE_FL_IPMODIFY ? " I" : " ",
3873 rec->flags & FTRACE_FL_DIRECT ? " D" : " ",3878 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 " : " ");
3875 if (rec->flags & FTRACE_FL_TRAMP_EN) {3881 if (rec->flags & FTRACE_FL_TRAMP_EN) {
3876 ops = ftrace_find_tramp_ops_any(rec);3882 ops = ftrace_find_tramp_ops_any(rec);
3877 if (ops) {3883 if (ops) {