Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing: Fix ftrace event field alignments

The fields of ftrace specific events (events used to save ftrace internal
events like function traces and trace_printk) are generated similarly to
how normal trace event fields are generated. That is, the fields are added
to a trace_events_fields array that saves the name, offset, size,
alignment and signness of the field. It is used to produce the output in
the format file in tracefs so that tooling knows how to parse the binary
data of the trace events.

The issue is that some of the ftrace event structures are packed. The
function graph exit event structures are one of them. The 64 bit calltime
and rettime fields end up 4 byte aligned, but the algorithm to show to
userspace shows them as 8 byte aligned.

The macros that create the ftrace events has one for embedded structure
fields. There's two macros for theses fields:

__field_desc() and __field_packed()

The difference of the latter macro is that it treats the field as packed.

Rename that field to __field_desc_packed() and create replace the
__field_packed() to be a normal field that is packed and have the calltime
and rettime use those.

This showed up on 32bit architectures for function graph time fields. It
had:

~# cat /sys/kernel/tracing/events/ftrace/funcgraph_exit/format
[..]
field:unsigned long func; offset:8; size:4; signed:0;
field:unsigned int depth; offset:12; size:4; signed:0;
field:unsigned int overrun; offset:16; size:4; signed:0;
field:unsigned long long calltime; offset:24; size:8; signed:0;
field:unsigned long long rettime; offset:32; size:8; signed:0;

Notice that overrun is at offset 16 with size 4, where in the structure
calltime is at offset 20 (16 + 4), but it shows the offset at 24. That's
because it used the alignment of unsigned long long when used as a
declaration and not as a member of a structure where it would be aligned
by word size (in this case 4).

By using the proper structure alignment, the format has it at the correct
offset:

~# cat /sys/kernel/tracing/events/ftrace/funcgraph_exit/format
[..]
field:unsigned long func; offset:8; size:4; signed:0;
field:unsigned int depth; offset:12; size:4; signed:0;
field:unsigned int overrun; offset:16; size:4; signed:0;
field:unsigned long long calltime; offset:20; size:8; signed:0;
field:unsigned long long rettime; offset:28; size:8; signed:0;

Cc: stable@vger.kernel.org
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reported-by: "jempty.liang" <imntjempty@163.com>
Link: https://patch.msgid.link/20260204113628.53faec78@gandalf.local.home
Fixes: 04ae87a52074e ("ftrace: Rework event_create_dir()")
Closes: https://lore.kernel.org/all/20260130015740.212343-1-imntjempty@163.com/
Closes: https://lore.kernel.org/all/20260202123342.2544795-1-imntjempty@163.com/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

+36 -24
+5 -2
kernel/trace/trace.h
··· 68 68 #undef __field_fn 69 69 #define __field_fn(type, item) type item; 70 70 71 + #undef __field_packed 72 + #define __field_packed(type, item) type item; 73 + 71 74 #undef __field_struct 72 75 #define __field_struct(type, item) __field(type, item) 73 76 74 77 #undef __field_desc 75 78 #define __field_desc(type, container, item) 76 79 77 - #undef __field_packed 78 - #define __field_packed(type, container, item) 80 + #undef __field_desc_packed 81 + #define __field_desc_packed(type, container, item) 79 82 80 83 #undef __array 81 84 #define __array(type, item, size) type item[size];
+16 -16
kernel/trace/trace_entries.h
··· 79 79 80 80 F_STRUCT( 81 81 __field_struct( struct ftrace_graph_ent, graph_ent ) 82 - __field_packed( unsigned long, graph_ent, func ) 83 - __field_packed( unsigned long, graph_ent, depth ) 82 + __field_desc_packed(unsigned long, graph_ent, func ) 83 + __field_desc_packed(unsigned long, graph_ent, depth ) 84 84 __dynamic_array(unsigned long, args ) 85 85 ), 86 86 ··· 96 96 97 97 F_STRUCT( 98 98 __field_struct( struct fgraph_retaddr_ent, graph_rent ) 99 - __field_packed( unsigned long, graph_rent.ent, func ) 100 - __field_packed( unsigned long, graph_rent.ent, depth ) 101 - __field_packed( unsigned long, graph_rent, retaddr ) 99 + __field_desc_packed( unsigned long, graph_rent.ent, func ) 100 + __field_desc_packed( unsigned long, graph_rent.ent, depth ) 101 + __field_desc_packed( unsigned long, graph_rent, retaddr ) 102 102 __dynamic_array(unsigned long, args ) 103 103 ), 104 104 ··· 123 123 124 124 F_STRUCT( 125 125 __field_struct( struct ftrace_graph_ret, ret ) 126 - __field_packed( unsigned long, ret, func ) 127 - __field_packed( unsigned long, ret, retval ) 128 - __field_packed( unsigned int, ret, depth ) 129 - __field_packed( unsigned int, ret, overrun ) 130 - __field(unsigned long long, calltime ) 131 - __field(unsigned long long, rettime ) 126 + __field_desc_packed( unsigned long, ret, func ) 127 + __field_desc_packed( unsigned long, ret, retval ) 128 + __field_desc_packed( unsigned int, ret, depth ) 129 + __field_desc_packed( unsigned int, ret, overrun ) 130 + __field_packed(unsigned long long, calltime) 131 + __field_packed(unsigned long long, rettime ) 132 132 ), 133 133 134 134 F_printk("<-- %ps (%u) (start: %llx end: %llx) over: %u retval: %lx", ··· 146 146 147 147 F_STRUCT( 148 148 __field_struct( struct ftrace_graph_ret, ret ) 149 - __field_packed( unsigned long, ret, func ) 150 - __field_packed( unsigned int, ret, depth ) 151 - __field_packed( unsigned int, ret, overrun ) 152 - __field(unsigned long long, calltime ) 153 - __field(unsigned long long, rettime ) 149 + __field_desc_packed( unsigned long, ret, func ) 150 + __field_desc_packed( unsigned int, ret, depth ) 151 + __field_desc_packed( unsigned int, ret, overrun ) 152 + __field_packed(unsigned long long, calltime ) 153 + __field_packed(unsigned long long, rettime ) 154 154 ), 155 155 156 156 F_printk("<-- %ps (%u) (start: %llx end: %llx) over: %u",
+15 -6
kernel/trace/trace_export.c
··· 42 42 #undef __field_fn 43 43 #define __field_fn(type, item) type item; 44 44 45 + #undef __field_packed 46 + #define __field_packed(type, item) type item; 47 + 45 48 #undef __field_desc 46 49 #define __field_desc(type, container, item) type item; 47 50 48 - #undef __field_packed 49 - #define __field_packed(type, container, item) type item; 51 + #undef __field_desc_packed 52 + #define __field_desc_packed(type, container, item) type item; 50 53 51 54 #undef __array 52 55 #define __array(type, item, size) type item[size]; ··· 107 104 #undef __field_fn 108 105 #define __field_fn(_type, _item) __field_ext(_type, _item, FILTER_TRACE_FN) 109 106 107 + #undef __field_packed 108 + #define __field_packed(_type, _item) __field_ext_packed(_type, _item, FILTER_OTHER) 109 + 110 110 #undef __field_desc 111 111 #define __field_desc(_type, _container, _item) __field_ext(_type, _item, FILTER_OTHER) 112 112 113 - #undef __field_packed 114 - #define __field_packed(_type, _container, _item) __field_ext_packed(_type, _item, FILTER_OTHER) 113 + #undef __field_desc_packed 114 + #define __field_desc_packed(_type, _container, _item) __field_ext_packed(_type, _item, FILTER_OTHER) 115 115 116 116 #undef __array 117 117 #define __array(_type, _item, _len) { \ ··· 152 146 #undef __field_fn 153 147 #define __field_fn(type, item) 154 148 149 + #undef __field_packed 150 + #define __field_packed(type, item) 151 + 155 152 #undef __field_desc 156 153 #define __field_desc(type, container, item) 157 154 158 - #undef __field_packed 159 - #define __field_packed(type, container, item) 155 + #undef __field_desc_packed 156 + #define __field_desc_packed(type, container, item) 160 157 161 158 #undef __array 162 159 #define __array(type, item, len)