@@ -70,6 +70,10 @@ static struct tracer_opt trace_opts[] = {
70
70
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
71
71
/* Display function return address ? */
72
72
{ TRACER_OPT (funcgraph - retaddr , TRACE_GRAPH_PRINT_RETADDR ) },
73
+ #endif
74
+ #ifdef CONFIG_FUNCTION_TRACE_ARGS
75
+ /* Display function arguments ? */
76
+ { TRACER_OPT (funcgraph - args , TRACE_GRAPH_ARGS ) },
73
77
#endif
74
78
/* Include sleep time (scheduled out) between entry and return */
75
79
{ TRACER_OPT (sleep - time , TRACE_GRAPH_SLEEP_TIME ) },
@@ -110,25 +114,43 @@ static void
110
114
print_graph_duration (struct trace_array * tr , unsigned long long duration ,
111
115
struct trace_seq * s , u32 flags );
112
116
113
- int __trace_graph_entry (struct trace_array * tr ,
114
- struct ftrace_graph_ent * trace ,
115
- unsigned int trace_ctx )
117
+ static int __graph_entry (struct trace_array * tr , struct ftrace_graph_ent * trace ,
118
+ unsigned int trace_ctx , struct ftrace_regs * fregs )
116
119
{
117
120
struct ring_buffer_event * event ;
118
121
struct trace_buffer * buffer = tr -> array_buffer .buffer ;
119
122
struct ftrace_graph_ent_entry * entry ;
123
+ int size ;
120
124
121
- event = trace_buffer_lock_reserve (buffer , TRACE_GRAPH_ENT ,
122
- sizeof (* entry ), trace_ctx );
125
+ /* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */
126
+ size = sizeof (* entry ) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof (long ));
127
+
128
+ event = trace_buffer_lock_reserve (buffer , TRACE_GRAPH_ENT , size , trace_ctx );
123
129
if (!event )
124
130
return 0 ;
125
- entry = ring_buffer_event_data (event );
126
- entry -> graph_ent = * trace ;
131
+
132
+ entry = ring_buffer_event_data (event );
133
+ entry -> graph_ent = * trace ;
134
+
135
+ #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
136
+ if (fregs ) {
137
+ for (int i = 0 ; i < FTRACE_REGS_MAX_ARGS ; i ++ )
138
+ entry -> args [i ] = ftrace_regs_get_argument (fregs , i );
139
+ }
140
+ #endif
141
+
127
142
trace_buffer_unlock_commit_nostack (buffer , event );
128
143
129
144
return 1 ;
130
145
}
131
146
147
+ int __trace_graph_entry (struct trace_array * tr ,
148
+ struct ftrace_graph_ent * trace ,
149
+ unsigned int trace_ctx )
150
+ {
151
+ return __graph_entry (tr , trace , trace_ctx , NULL );
152
+ }
153
+
132
154
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
133
155
int __trace_graph_retaddr_entry (struct trace_array * tr ,
134
156
struct ftrace_graph_ent * trace ,
@@ -174,9 +196,9 @@ struct fgraph_times {
174
196
unsigned long long sleeptime ; /* may be optional! */
175
197
};
176
198
177
- int trace_graph_entry (struct ftrace_graph_ent * trace ,
178
- struct fgraph_ops * gops ,
179
- struct ftrace_regs * fregs )
199
+ static int graph_entry (struct ftrace_graph_ent * trace ,
200
+ struct fgraph_ops * gops ,
201
+ struct ftrace_regs * fregs )
180
202
{
181
203
unsigned long * task_var = fgraph_get_task_var (gops );
182
204
struct trace_array * tr = gops -> private ;
@@ -246,14 +268,28 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
246
268
unsigned long retaddr = ftrace_graph_top_ret_addr (current );
247
269
ret = __trace_graph_retaddr_entry (tr , trace , trace_ctx , retaddr );
248
270
} else {
249
- ret = __trace_graph_entry (tr , trace , trace_ctx );
271
+ ret = __graph_entry (tr , trace , trace_ctx , fregs );
250
272
}
251
273
}
252
274
preempt_enable_notrace ();
253
275
254
276
return ret ;
255
277
}
256
278
279
+ int trace_graph_entry (struct ftrace_graph_ent * trace ,
280
+ struct fgraph_ops * gops ,
281
+ struct ftrace_regs * fregs )
282
+ {
283
+ return graph_entry (trace , gops , NULL );
284
+ }
285
+
286
+ static int trace_graph_entry_args (struct ftrace_graph_ent * trace ,
287
+ struct fgraph_ops * gops ,
288
+ struct ftrace_regs * fregs )
289
+ {
290
+ return graph_entry (trace , gops , fregs );
291
+ }
292
+
257
293
static void
258
294
__trace_graph_function (struct trace_array * tr ,
259
295
unsigned long ip , unsigned int trace_ctx )
@@ -418,7 +454,10 @@ static int graph_trace_init(struct trace_array *tr)
418
454
{
419
455
int ret ;
420
456
421
- tr -> gops -> entryfunc = trace_graph_entry ;
457
+ if (tracer_flags_is_set (TRACE_GRAPH_ARGS ))
458
+ tr -> gops -> entryfunc = trace_graph_entry_args ;
459
+ else
460
+ tr -> gops -> entryfunc = trace_graph_entry ;
422
461
423
462
if (tracing_thresh )
424
463
tr -> gops -> retfunc = trace_graph_thresh_return ;
@@ -775,7 +814,7 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e
775
814
776
815
static void print_graph_retval (struct trace_seq * s , struct ftrace_graph_ent_entry * entry ,
777
816
struct ftrace_graph_ret * graph_ret , void * func ,
778
- u32 opt_flags , u32 trace_flags )
817
+ u32 opt_flags , u32 trace_flags , int args_size )
779
818
{
780
819
unsigned long err_code = 0 ;
781
820
unsigned long retval = 0 ;
@@ -809,7 +848,14 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
809
848
if (entry -> ent .type != TRACE_GRAPH_RETADDR_ENT )
810
849
print_retaddr = false;
811
850
812
- trace_seq_printf (s , "%ps();" , func );
851
+ trace_seq_printf (s , "%ps" , func );
852
+
853
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof (long )) {
854
+ print_function_args (s , entry -> args , (unsigned long )func );
855
+ trace_seq_putc (s , ';' );
856
+ } else
857
+ trace_seq_puts (s , "();" );
858
+
813
859
if (print_retval || print_retaddr )
814
860
trace_seq_puts (s , " /*" );
815
861
else
@@ -836,7 +882,8 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
836
882
837
883
#else
838
884
839
- #define print_graph_retval (_seq , _ent , _ret , _func , _opt_flags , _trace_flags ) do {} while (0)
885
+ #define print_graph_retval (_seq , _ent , _ret , _func , _opt_flags , _trace_flags , args_size ) \
886
+ do {} while (0)
840
887
841
888
#endif
842
889
@@ -852,10 +899,14 @@ print_graph_entry_leaf(struct trace_iterator *iter,
852
899
struct ftrace_graph_ret * graph_ret ;
853
900
struct ftrace_graph_ent * call ;
854
901
unsigned long long duration ;
902
+ unsigned long ret_func ;
855
903
unsigned long func ;
904
+ int args_size ;
856
905
int cpu = iter -> cpu ;
857
906
int i ;
858
907
908
+ args_size = iter -> ent_size - offsetof(struct ftrace_graph_ent_entry , args );
909
+
859
910
graph_ret = & ret_entry -> ret ;
860
911
call = & entry -> graph_ent ;
861
912
duration = ret_entry -> rettime - ret_entry -> calltime ;
@@ -887,16 +938,25 @@ print_graph_entry_leaf(struct trace_iterator *iter,
887
938
for (i = 0 ; i < call -> depth * TRACE_GRAPH_INDENT ; i ++ )
888
939
trace_seq_putc (s , ' ' );
889
940
941
+ ret_func = graph_ret -> func + iter -> tr -> text_delta ;
942
+
890
943
/*
891
944
* Write out the function return value or return address
892
945
*/
893
946
if (flags & (__TRACE_GRAPH_PRINT_RETVAL | __TRACE_GRAPH_PRINT_RETADDR )) {
894
947
print_graph_retval (s , entry , graph_ret ,
895
948
(void * )graph_ret -> func + iter -> tr -> text_delta ,
896
- flags , tr -> trace_flags );
949
+ flags , tr -> trace_flags , args_size );
897
950
} else {
898
- trace_seq_printf (s , "%ps();\n" , (void * )func );
951
+ trace_seq_printf (s , "%ps" , (void * )ret_func );
952
+
953
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof (long )) {
954
+ print_function_args (s , entry -> args , ret_func );
955
+ trace_seq_putc (s , ';' );
956
+ } else
957
+ trace_seq_puts (s , "();" );
899
958
}
959
+ trace_seq_printf (s , "\n" );
900
960
901
961
print_graph_irq (iter , graph_ret -> func , TRACE_GRAPH_RET ,
902
962
cpu , iter -> ent -> pid , flags );
@@ -913,6 +973,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
913
973
struct fgraph_data * data = iter -> private ;
914
974
struct trace_array * tr = iter -> tr ;
915
975
unsigned long func ;
976
+ int args_size ;
916
977
int i ;
917
978
918
979
if (data ) {
@@ -937,7 +998,17 @@ print_graph_entry_nested(struct trace_iterator *iter,
937
998
938
999
func = call -> func + iter -> tr -> text_delta ;
939
1000
940
- trace_seq_printf (s , "%ps() {" , (void * )func );
1001
+ trace_seq_printf (s , "%ps" , (void * )func );
1002
+
1003
+ args_size = iter -> ent_size - offsetof(struct ftrace_graph_ent_entry , args );
1004
+
1005
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof (long ))
1006
+ print_function_args (s , entry -> args , func );
1007
+ else
1008
+ trace_seq_puts (s , "()" );
1009
+
1010
+ trace_seq_puts (s , " {" );
1011
+
941
1012
if (flags & __TRACE_GRAPH_PRINT_RETADDR &&
942
1013
entry -> ent .type == TRACE_GRAPH_RETADDR_ENT )
943
1014
print_graph_retaddr (s , (struct fgraph_retaddr_ent_entry * )entry ,
@@ -1107,21 +1178,38 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
1107
1178
struct trace_iterator * iter , u32 flags )
1108
1179
{
1109
1180
struct fgraph_data * data = iter -> private ;
1110
- struct ftrace_graph_ent * call = & field -> graph_ent ;
1181
+ struct ftrace_graph_ent * call ;
1111
1182
struct ftrace_graph_ret_entry * leaf_ret ;
1112
1183
static enum print_line_t ret ;
1113
1184
int cpu = iter -> cpu ;
1185
+ /*
1186
+ * print_graph_entry() may consume the current event,
1187
+ * thus @field may become invalid, so we need to save it.
1188
+ * sizeof(struct ftrace_graph_ent_entry) is very small,
1189
+ * it can be safely saved at the stack.
1190
+ */
1191
+ struct ftrace_graph_ent_entry * entry ;
1192
+ u8 save_buf [sizeof (* entry ) + FTRACE_REGS_MAX_ARGS * sizeof (long )];
1193
+
1194
+ /* The ent_size is expected to be as big as the entry */
1195
+ if (iter -> ent_size > sizeof (save_buf ))
1196
+ iter -> ent_size = sizeof (save_buf );
1197
+
1198
+ entry = (void * )save_buf ;
1199
+ memcpy (entry , field , iter -> ent_size );
1200
+
1201
+ call = & entry -> graph_ent ;
1114
1202
1115
1203
if (check_irq_entry (iter , flags , call -> func , call -> depth ))
1116
1204
return TRACE_TYPE_HANDLED ;
1117
1205
1118
1206
print_graph_prologue (iter , s , TRACE_GRAPH_ENT , call -> func , flags );
1119
1207
1120
- leaf_ret = get_return_for_leaf (iter , field );
1208
+ leaf_ret = get_return_for_leaf (iter , entry );
1121
1209
if (leaf_ret )
1122
- ret = print_graph_entry_leaf (iter , field , leaf_ret , s , flags );
1210
+ ret = print_graph_entry_leaf (iter , entry , leaf_ret , s , flags );
1123
1211
else
1124
- ret = print_graph_entry_nested (iter , field , s , cpu , flags );
1212
+ ret = print_graph_entry_nested (iter , entry , s , cpu , flags );
1125
1213
1126
1214
if (data ) {
1127
1215
/*
@@ -1195,7 +1283,8 @@ print_graph_return(struct ftrace_graph_ret_entry *retentry, struct trace_seq *s,
1195
1283
* funcgraph-retval option is enabled.
1196
1284
*/
1197
1285
if (flags & __TRACE_GRAPH_PRINT_RETVAL ) {
1198
- print_graph_retval (s , NULL , trace , (void * )func , flags , tr -> trace_flags );
1286
+ print_graph_retval (s , NULL , trace , (void * )func , flags ,
1287
+ tr -> trace_flags , 0 );
1199
1288
} else {
1200
1289
/*
1201
1290
* If the return function does not have a matching entry,
@@ -1323,16 +1412,8 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
1323
1412
1324
1413
switch (entry -> type ) {
1325
1414
case TRACE_GRAPH_ENT : {
1326
- /*
1327
- * print_graph_entry() may consume the current event,
1328
- * thus @field may become invalid, so we need to save it.
1329
- * sizeof(struct ftrace_graph_ent_entry) is very small,
1330
- * it can be safely saved at the stack.
1331
- */
1332
- struct ftrace_graph_ent_entry saved ;
1333
1415
trace_assign_type (field , entry );
1334
- saved = * field ;
1335
- return print_graph_entry (& saved , s , iter , flags );
1416
+ return print_graph_entry (field , s , iter , flags );
1336
1417
}
1337
1418
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
1338
1419
case TRACE_GRAPH_RETADDR_ENT : {
0 commit comments