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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ftrace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull ftrace updates from Steven Rostedt:

- Record function parameters for function and function graph tracers

An option has been added to function tracer (func-args) and the
function graph tracer (funcgraph-args) that when set, the tracers
will record the registers that hold the arguments into each function
event. On reading of the trace, it will use BTF to print those
arguments. Most archs support up to 6 arguments (depending on the
complexity of the arguments) and those are printed.

If a function has more arguments then what was recorded, the output
will end with " ... )".

Example of function graph tracer:

6) | dummy_xmit [dummy](skb = 0x8887c100, dev = 0x872ca000) {
6) | consume_skb(skb = 0x8887c100) {
6) | skb_release_head_state(skb = 0x8887c100) {
6) 0.178 us | sock_wfree(skb = 0x8887c100)
6) 0.627 us | }

- The rest of the changes are minor clean ups and fixes

* tag 'ftrace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tracing: Use hashtable.h for event_hash
tracing: Fix use-after-free in print_graph_function_flags during tracer switching
function_graph: Remove the unused variable func
ftrace: Add arguments to function tracer
ftrace: Have funcgraph-args take affect during tracing
ftrace: Add support for function argument to graph tracer
ftrace: Add print_function_args()
ftrace: Have ftrace_free_filter() WARN and exit if ops is active
fgraph: Correct typo in ftrace_return_to_handler comment

+351 -74
+5
include/linux/ftrace_regs.h
··· 35 35 36 36 #endif /* HAVE_ARCH_FTRACE_REGS */ 37 37 38 + /* This can be overridden by the architectures */ 39 + #ifndef FTRACE_REGS_MAX_ARGS 40 + # define FTRACE_REGS_MAX_ARGS 6 41 + #endif 42 + 38 43 #endif /* _LINUX_FTRACE_REGS_H */
+12
kernel/trace/Kconfig
··· 263 263 the function is called. This feature is off by default, and you can 264 264 enable it via the trace option funcgraph-retaddr. 265 265 266 + config FUNCTION_TRACE_ARGS 267 + bool 268 + depends on HAVE_FUNCTION_ARG_ACCESS_API 269 + depends on DEBUG_INFO_BTF 270 + default y 271 + help 272 + If supported with function argument access API and BTF, then 273 + the function tracer and function graph tracer will support printing 274 + of function arguments. This feature is off by default, and can be 275 + enabled via the trace option func-args (for the function tracer) and 276 + funcgraph-args (for the function graph tracer) 277 + 266 278 config DYNAMIC_FTRACE 267 279 bool "enable/disable function tracing dynamically" 268 280 depends on FUNCTION_TRACER
+1 -1
kernel/trace/fgraph.c
··· 865 865 } 866 866 867 867 /* 868 - * After all architecures have selected HAVE_FUNCTION_GRAPH_FREGS, we can 868 + * After all architectures have selected HAVE_FUNCTION_GRAPH_FREGS, we can 869 869 * leave only ftrace_return_to_handler(fregs). 870 870 */ 871 871 #ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS
+2
kernel/trace/ftrace.c
··· 1293 1293 void ftrace_free_filter(struct ftrace_ops *ops) 1294 1294 { 1295 1295 ftrace_ops_init(ops); 1296 + if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) 1297 + return; 1296 1298 free_ftrace_hash(ops->func_hash->filter_hash); 1297 1299 free_ftrace_hash(ops->func_hash->notrace_hash); 1298 1300 }
+12 -2
kernel/trace/trace.c
··· 2878 2878 2879 2879 void 2880 2880 trace_function(struct trace_array *tr, unsigned long ip, unsigned long 2881 - parent_ip, unsigned int trace_ctx) 2881 + parent_ip, unsigned int trace_ctx, struct ftrace_regs *fregs) 2882 2882 { 2883 2883 struct trace_buffer *buffer = tr->array_buffer.buffer; 2884 2884 struct ring_buffer_event *event; 2885 2885 struct ftrace_entry *entry; 2886 + int size = sizeof(*entry); 2886 2887 2887 - event = __trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry), 2888 + size += FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long); 2889 + 2890 + event = __trace_buffer_lock_reserve(buffer, TRACE_FN, size, 2888 2891 trace_ctx); 2889 2892 if (!event) 2890 2893 return; 2891 2894 entry = ring_buffer_event_data(event); 2892 2895 entry->ip = ip; 2893 2896 entry->parent_ip = parent_ip; 2897 + 2898 + #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API 2899 + if (fregs) { 2900 + for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++) 2901 + entry->args[i] = ftrace_regs_get_argument(fregs, i); 2902 + } 2903 + #endif 2894 2904 2895 2905 if (static_branch_unlikely(&trace_function_exports_enabled)) 2896 2906 ftrace_exports(event, TRACE_EXPORT_FUNCTION);
+4 -1
kernel/trace/trace.h
··· 21 21 #include <linux/workqueue.h> 22 22 #include <linux/ctype.h> 23 23 #include <linux/once_lite.h> 24 + #include <linux/ftrace_regs.h> 24 25 25 26 #include "pid_list.h" 26 27 ··· 698 697 void trace_function(struct trace_array *tr, 699 698 unsigned long ip, 700 699 unsigned long parent_ip, 701 - unsigned int trace_ctx); 700 + unsigned int trace_ctx, 701 + struct ftrace_regs *regs); 702 702 void trace_graph_function(struct trace_array *tr, 703 703 unsigned long ip, 704 704 unsigned long parent_ip, ··· 899 897 #define TRACE_GRAPH_PRINT_RETVAL 0x800 900 898 #define TRACE_GRAPH_PRINT_RETVAL_HEX 0x1000 901 899 #define TRACE_GRAPH_PRINT_RETADDR 0x2000 900 + #define TRACE_GRAPH_ARGS 0x4000 902 901 #define TRACE_GRAPH_PRINT_FILL_SHIFT 28 903 902 #define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT) 904 903
+7 -5
kernel/trace/trace_entries.h
··· 61 61 TRACE_FN, 62 62 63 63 F_STRUCT( 64 - __field_fn( unsigned long, ip ) 65 - __field_fn( unsigned long, parent_ip ) 64 + __field_fn( unsigned long, ip ) 65 + __field_fn( unsigned long, parent_ip ) 66 + __dynamic_array( unsigned long, args ) 66 67 ), 67 68 68 69 F_printk(" %ps <-- %ps", ··· 73 72 ); 74 73 75 74 /* Function call entry */ 76 - FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry, 75 + FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry, 77 76 78 77 TRACE_GRAPH_ENT, 79 78 80 79 F_STRUCT( 81 80 __field_struct( struct ftrace_graph_ent, graph_ent ) 82 81 __field_packed( unsigned long, graph_ent, func ) 83 - __field_packed( int, graph_ent, depth ) 82 + __field_packed( unsigned long, graph_ent, depth ) 83 + __dynamic_array(unsigned long, args ) 84 84 ), 85 85 86 - F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth) 86 + F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth) 87 87 ); 88 88 89 89 #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
+41 -5
kernel/trace/trace_functions.c
··· 25 25 function_trace_call(unsigned long ip, unsigned long parent_ip, 26 26 struct ftrace_ops *op, struct ftrace_regs *fregs); 27 27 static void 28 + function_args_trace_call(unsigned long ip, unsigned long parent_ip, 29 + struct ftrace_ops *op, struct ftrace_regs *fregs); 30 + static void 28 31 function_stack_trace_call(unsigned long ip, unsigned long parent_ip, 29 32 struct ftrace_ops *op, struct ftrace_regs *fregs); 30 33 static void ··· 45 42 TRACE_FUNC_NO_OPTS = 0x0, /* No flags set. */ 46 43 TRACE_FUNC_OPT_STACK = 0x1, 47 44 TRACE_FUNC_OPT_NO_REPEATS = 0x2, 45 + TRACE_FUNC_OPT_ARGS = 0x4, 48 46 49 47 /* Update this to next highest bit. */ 50 - TRACE_FUNC_OPT_HIGHEST_BIT = 0x4 48 + TRACE_FUNC_OPT_HIGHEST_BIT = 0x8 51 49 }; 52 50 53 51 #define TRACE_FUNC_OPT_MASK (TRACE_FUNC_OPT_HIGHEST_BIT - 1) ··· 118 114 switch (flags_val & TRACE_FUNC_OPT_MASK) { 119 115 case TRACE_FUNC_NO_OPTS: 120 116 return function_trace_call; 117 + case TRACE_FUNC_OPT_ARGS: 118 + return function_args_trace_call; 121 119 case TRACE_FUNC_OPT_STACK: 122 120 return function_stack_trace_call; 123 121 case TRACE_FUNC_OPT_NO_REPEATS: ··· 226 220 227 221 data = this_cpu_ptr(tr->array_buffer.data); 228 222 if (!atomic_read(&data->disabled)) 229 - trace_function(tr, ip, parent_ip, trace_ctx); 223 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 224 + 225 + ftrace_test_recursion_unlock(bit); 226 + } 227 + 228 + static void 229 + function_args_trace_call(unsigned long ip, unsigned long parent_ip, 230 + struct ftrace_ops *op, struct ftrace_regs *fregs) 231 + { 232 + struct trace_array *tr = op->private; 233 + struct trace_array_cpu *data; 234 + unsigned int trace_ctx; 235 + int bit; 236 + int cpu; 237 + 238 + if (unlikely(!tr->function_enabled)) 239 + return; 240 + 241 + bit = ftrace_test_recursion_trylock(ip, parent_ip); 242 + if (bit < 0) 243 + return; 244 + 245 + trace_ctx = tracing_gen_ctx(); 246 + 247 + cpu = smp_processor_id(); 248 + data = per_cpu_ptr(tr->array_buffer.data, cpu); 249 + if (!atomic_read(&data->disabled)) 250 + trace_function(tr, ip, parent_ip, trace_ctx, fregs); 230 251 231 252 ftrace_test_recursion_unlock(bit); 232 253 } ··· 303 270 304 271 if (likely(disabled == 1)) { 305 272 trace_ctx = tracing_gen_ctx_flags(flags); 306 - trace_function(tr, ip, parent_ip, trace_ctx); 273 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 307 274 #ifdef CONFIG_UNWINDER_FRAME_POINTER 308 275 if (ftrace_pids_enabled(op)) 309 276 skip++; ··· 382 349 trace_ctx = tracing_gen_ctx_dec(); 383 350 process_repeats(tr, ip, parent_ip, last_info, trace_ctx); 384 351 385 - trace_function(tr, ip, parent_ip, trace_ctx); 352 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 386 353 387 354 out: 388 355 ftrace_test_recursion_unlock(bit); ··· 422 389 trace_ctx = tracing_gen_ctx_flags(flags); 423 390 process_repeats(tr, ip, parent_ip, last_info, trace_ctx); 424 391 425 - trace_function(tr, ip, parent_ip, trace_ctx); 392 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 426 393 __trace_stack(tr, trace_ctx, STACK_SKIP); 427 394 } 428 395 ··· 436 403 { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) }, 437 404 #endif 438 405 { TRACER_OPT(func-no-repeats, TRACE_FUNC_OPT_NO_REPEATS) }, 406 + #ifdef CONFIG_FUNCTION_TRACE_ARGS 407 + { TRACER_OPT(func-args, TRACE_FUNC_OPT_ARGS) }, 408 + #endif 439 409 { } /* Always set a last empty entry */ 440 410 }; 441 411
+140 -36
kernel/trace/trace_functions_graph.c
··· 71 71 /* Display function return address ? */ 72 72 { TRACER_OPT(funcgraph-retaddr, TRACE_GRAPH_PRINT_RETADDR) }, 73 73 #endif 74 + #ifdef CONFIG_FUNCTION_TRACE_ARGS 75 + /* Display function arguments ? */ 76 + { TRACER_OPT(funcgraph-args, TRACE_GRAPH_ARGS) }, 77 + #endif 74 78 /* Include sleep time (scheduled out) between entry and return */ 75 79 { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, 76 80 ··· 114 110 print_graph_duration(struct trace_array *tr, unsigned long long duration, 115 111 struct trace_seq *s, u32 flags); 116 112 117 - int __trace_graph_entry(struct trace_array *tr, 118 - struct ftrace_graph_ent *trace, 119 - unsigned int trace_ctx) 113 + static int __graph_entry(struct trace_array *tr, struct ftrace_graph_ent *trace, 114 + unsigned int trace_ctx, struct ftrace_regs *fregs) 120 115 { 121 116 struct ring_buffer_event *event; 122 117 struct trace_buffer *buffer = tr->array_buffer.buffer; 123 118 struct ftrace_graph_ent_entry *entry; 119 + int size; 124 120 125 - event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, 126 - sizeof(*entry), trace_ctx); 121 + /* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */ 122 + size = sizeof(*entry) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long)); 123 + 124 + event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, size, trace_ctx); 127 125 if (!event) 128 126 return 0; 129 - entry = ring_buffer_event_data(event); 130 - entry->graph_ent = *trace; 127 + 128 + entry = ring_buffer_event_data(event); 129 + entry->graph_ent = *trace; 130 + 131 + #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API 132 + if (fregs) { 133 + for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++) 134 + entry->args[i] = ftrace_regs_get_argument(fregs, i); 135 + } 136 + #endif 137 + 131 138 trace_buffer_unlock_commit_nostack(buffer, event); 132 139 133 140 return 1; 141 + } 142 + 143 + int __trace_graph_entry(struct trace_array *tr, 144 + struct ftrace_graph_ent *trace, 145 + unsigned int trace_ctx) 146 + { 147 + return __graph_entry(tr, trace, trace_ctx, NULL); 134 148 } 135 149 136 150 #ifdef CONFIG_FUNCTION_GRAPH_RETADDR ··· 196 174 unsigned long long sleeptime; /* may be optional! */ 197 175 }; 198 176 199 - int trace_graph_entry(struct ftrace_graph_ent *trace, 200 - struct fgraph_ops *gops, 201 - struct ftrace_regs *fregs) 177 + static int graph_entry(struct ftrace_graph_ent *trace, 178 + struct fgraph_ops *gops, 179 + struct ftrace_regs *fregs) 202 180 { 203 181 unsigned long *task_var = fgraph_get_task_var(gops); 204 182 struct trace_array *tr = gops->private; ··· 268 246 unsigned long retaddr = ftrace_graph_top_ret_addr(current); 269 247 ret = __trace_graph_retaddr_entry(tr, trace, trace_ctx, retaddr); 270 248 } else { 271 - ret = __trace_graph_entry(tr, trace, trace_ctx); 249 + ret = __graph_entry(tr, trace, trace_ctx, fregs); 272 250 } 273 251 } 274 252 preempt_enable_notrace(); 275 253 276 254 return ret; 255 + } 256 + 257 + int trace_graph_entry(struct ftrace_graph_ent *trace, 258 + struct fgraph_ops *gops, 259 + struct ftrace_regs *fregs) 260 + { 261 + return graph_entry(trace, gops, NULL); 262 + } 263 + 264 + static int trace_graph_entry_args(struct ftrace_graph_ent *trace, 265 + struct fgraph_ops *gops, 266 + struct ftrace_regs *fregs) 267 + { 268 + return graph_entry(trace, gops, fregs); 277 269 } 278 270 279 271 static void ··· 454 418 { 455 419 int ret; 456 420 457 - tr->gops->entryfunc = trace_graph_entry; 421 + if (tracer_flags_is_set(TRACE_GRAPH_ARGS)) 422 + tr->gops->entryfunc = trace_graph_entry_args; 423 + else 424 + tr->gops->entryfunc = trace_graph_entry; 458 425 459 426 if (tracing_thresh) 460 427 tr->gops->retfunc = trace_graph_thresh_return; 461 428 else 462 429 tr->gops->retfunc = trace_graph_return; 463 430 464 - /* Make gops functions are visible before we start tracing */ 431 + /* Make gops functions visible before we start tracing */ 465 432 smp_mb(); 466 433 467 434 ret = register_ftrace_graph(tr->gops); ··· 473 434 tracing_start_cmdline_record(); 474 435 475 436 return 0; 437 + } 438 + 439 + static int ftrace_graph_trace_args(struct trace_array *tr, int set) 440 + { 441 + trace_func_graph_ent_t entry; 442 + 443 + if (set) 444 + entry = trace_graph_entry_args; 445 + else 446 + entry = trace_graph_entry; 447 + 448 + /* See if there's any changes */ 449 + if (tr->gops->entryfunc == entry) 450 + return 0; 451 + 452 + unregister_ftrace_graph(tr->gops); 453 + 454 + tr->gops->entryfunc = entry; 455 + 456 + /* Make gops functions visible before we start tracing */ 457 + smp_mb(); 458 + return register_ftrace_graph(tr->gops); 476 459 } 477 460 478 461 static void graph_trace_reset(struct trace_array *tr) ··· 836 775 837 776 static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry, 838 777 struct ftrace_graph_ret *graph_ret, void *func, 839 - u32 opt_flags, u32 trace_flags) 778 + u32 opt_flags, u32 trace_flags, int args_size) 840 779 { 841 780 unsigned long err_code = 0; 842 781 unsigned long retval = 0; ··· 870 809 if (entry->ent.type != TRACE_GRAPH_RETADDR_ENT) 871 810 print_retaddr = false; 872 811 873 - trace_seq_printf(s, "%ps();", func); 812 + trace_seq_printf(s, "%ps", func); 813 + 814 + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) { 815 + print_function_args(s, entry->args, (unsigned long)func); 816 + trace_seq_putc(s, ';'); 817 + } else 818 + trace_seq_puts(s, "();"); 819 + 874 820 if (print_retval || print_retaddr) 875 821 trace_seq_puts(s, " /*"); 876 822 else ··· 904 836 905 837 #else 906 838 907 - #define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags) do {} while (0) 839 + #define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags, args_size) \ 840 + do {} while (0) 908 841 909 842 #endif 910 843 ··· 921 852 struct ftrace_graph_ret *graph_ret; 922 853 struct ftrace_graph_ent *call; 923 854 unsigned long long duration; 924 - unsigned long func; 855 + unsigned long ret_func; 856 + int args_size; 925 857 int cpu = iter->cpu; 926 858 int i; 859 + 860 + args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args); 927 861 928 862 graph_ret = &ret_entry->ret; 929 863 call = &entry->graph_ent; 930 864 duration = ret_entry->rettime - ret_entry->calltime; 931 - 932 - func = call->func + iter->tr->text_delta; 933 865 934 866 if (data) { 935 867 struct fgraph_cpu_data *cpu_data; ··· 957 887 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) 958 888 trace_seq_putc(s, ' '); 959 889 890 + ret_func = graph_ret->func + iter->tr->text_delta; 891 + 960 892 /* 961 893 * Write out the function return value or return address 962 894 */ 963 895 if (flags & (__TRACE_GRAPH_PRINT_RETVAL | __TRACE_GRAPH_PRINT_RETADDR)) { 964 896 print_graph_retval(s, entry, graph_ret, 965 897 (void *)graph_ret->func + iter->tr->text_delta, 966 - flags, tr->trace_flags); 898 + flags, tr->trace_flags, args_size); 967 899 } else { 968 - trace_seq_printf(s, "%ps();\n", (void *)func); 900 + trace_seq_printf(s, "%ps", (void *)ret_func); 901 + 902 + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) { 903 + print_function_args(s, entry->args, ret_func); 904 + trace_seq_putc(s, ';'); 905 + } else 906 + trace_seq_puts(s, "();"); 969 907 } 908 + trace_seq_printf(s, "\n"); 970 909 971 910 print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET, 972 911 cpu, iter->ent->pid, flags); ··· 992 913 struct fgraph_data *data = iter->private; 993 914 struct trace_array *tr = iter->tr; 994 915 unsigned long func; 916 + int args_size; 995 917 int i; 996 918 997 919 if (data) { ··· 1017 937 1018 938 func = call->func + iter->tr->text_delta; 1019 939 1020 - trace_seq_printf(s, "%ps() {", (void *)func); 940 + trace_seq_printf(s, "%ps", (void *)func); 941 + 942 + args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args); 943 + 944 + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) 945 + print_function_args(s, entry->args, func); 946 + else 947 + trace_seq_puts(s, "()"); 948 + 949 + trace_seq_puts(s, " {"); 950 + 1021 951 if (flags & __TRACE_GRAPH_PRINT_RETADDR && 1022 952 entry->ent.type == TRACE_GRAPH_RETADDR_ENT) 1023 953 print_graph_retaddr(s, (struct fgraph_retaddr_ent_entry *)entry, ··· 1197 1107 struct trace_iterator *iter, u32 flags) 1198 1108 { 1199 1109 struct fgraph_data *data = iter->private; 1200 - struct ftrace_graph_ent *call = &field->graph_ent; 1110 + struct ftrace_graph_ent *call; 1201 1111 struct ftrace_graph_ret_entry *leaf_ret; 1202 1112 static enum print_line_t ret; 1203 1113 int cpu = iter->cpu; 1114 + /* 1115 + * print_graph_entry() may consume the current event, 1116 + * thus @field may become invalid, so we need to save it. 1117 + * sizeof(struct ftrace_graph_ent_entry) is very small, 1118 + * it can be safely saved at the stack. 1119 + */ 1120 + struct ftrace_graph_ent_entry *entry; 1121 + u8 save_buf[sizeof(*entry) + FTRACE_REGS_MAX_ARGS * sizeof(long)]; 1122 + 1123 + /* The ent_size is expected to be as big as the entry */ 1124 + if (iter->ent_size > sizeof(save_buf)) 1125 + iter->ent_size = sizeof(save_buf); 1126 + 1127 + entry = (void *)save_buf; 1128 + memcpy(entry, field, iter->ent_size); 1129 + 1130 + call = &entry->graph_ent; 1204 1131 1205 1132 if (check_irq_entry(iter, flags, call->func, call->depth)) 1206 1133 return TRACE_TYPE_HANDLED; 1207 1134 1208 1135 print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags); 1209 1136 1210 - leaf_ret = get_return_for_leaf(iter, field); 1137 + leaf_ret = get_return_for_leaf(iter, entry); 1211 1138 if (leaf_ret) 1212 - ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags); 1139 + ret = print_graph_entry_leaf(iter, entry, leaf_ret, s, flags); 1213 1140 else 1214 - ret = print_graph_entry_nested(iter, field, s, cpu, flags); 1141 + ret = print_graph_entry_nested(iter, entry, s, cpu, flags); 1215 1142 1216 1143 if (data) { 1217 1144 /* ··· 1302 1195 * funcgraph-retval option is enabled. 1303 1196 */ 1304 1197 if (flags & __TRACE_GRAPH_PRINT_RETVAL) { 1305 - print_graph_retval(s, NULL, trace, (void *)func, flags, tr->trace_flags); 1198 + print_graph_retval(s, NULL, trace, (void *)func, flags, 1199 + tr->trace_flags, 0); 1306 1200 } else { 1307 1201 /* 1308 1202 * If the return function does not have a matching entry, ··· 1431 1323 1432 1324 switch (entry->type) { 1433 1325 case TRACE_GRAPH_ENT: { 1434 - /* 1435 - * print_graph_entry() may consume the current event, 1436 - * thus @field may become invalid, so we need to save it. 1437 - * sizeof(struct ftrace_graph_ent_entry) is very small, 1438 - * it can be safely saved at the stack. 1439 - */ 1440 - struct ftrace_graph_ent_entry saved; 1441 1326 trace_assign_type(field, entry); 1442 - saved = *field; 1443 - return print_graph_entry(&saved, s, iter, flags); 1327 + return print_graph_entry(field, s, iter, flags); 1444 1328 } 1445 1329 #ifdef CONFIG_FUNCTION_GRAPH_RETADDR 1446 1330 case TRACE_GRAPH_RETADDR_ENT: { ··· 1611 1511 if (data) { 1612 1512 free_percpu(data->cpu_data); 1613 1513 kfree(data); 1514 + iter->private = NULL; 1614 1515 } 1615 1516 } 1616 1517 ··· 1626 1525 1627 1526 if (bit == TRACE_GRAPH_GRAPH_TIME) 1628 1527 ftrace_graph_graph_time_control(set); 1528 + 1529 + if (bit == TRACE_GRAPH_ARGS) 1530 + return ftrace_graph_trace_args(tr, set); 1629 1531 1630 1532 return 0; 1631 1533 }
+9 -5
kernel/trace/trace_irqsoff.c
··· 150 150 151 151 trace_ctx = tracing_gen_ctx_flags(flags); 152 152 153 - trace_function(tr, ip, parent_ip, trace_ctx); 153 + trace_function(tr, ip, parent_ip, trace_ctx, fregs); 154 154 155 155 atomic_dec(&data->disabled); 156 156 } ··· 250 250 { 251 251 if (is_graph(iter->tr)) 252 252 graph_trace_open(iter); 253 - else 254 - iter->private = NULL; 255 253 } 256 254 257 255 static void irqsoff_trace_close(struct trace_iterator *iter) ··· 293 295 if (is_graph(tr)) 294 296 trace_graph_function(tr, ip, parent_ip, trace_ctx); 295 297 else 296 - trace_function(tr, ip, parent_ip, trace_ctx); 298 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 297 299 } 298 300 299 301 #else 300 - #define __trace_function trace_function 302 + static inline void 303 + __trace_function(struct trace_array *tr, 304 + unsigned long ip, unsigned long parent_ip, 305 + unsigned int trace_ctx) 306 + { 307 + return trace_function(tr, ip, parent_ip, trace_ctx, NULL); 308 + } 301 309 302 310 static enum print_line_t irqsoff_print_line(struct trace_iterator *iter) 303 311 {
+107 -15
kernel/trace/trace_output.c
··· 12 12 #include <linux/sched/clock.h> 13 13 #include <linux/sched/mm.h> 14 14 #include <linux/idr.h> 15 + #include <linux/btf.h> 16 + #include <linux/bpf.h> 17 + #include <linux/hashtable.h> 15 18 16 19 #include "trace_output.h" 20 + #include "trace_btf.h" 17 21 18 - /* must be a power of 2 */ 19 - #define EVENT_HASHSIZE 128 22 + /* 2^7 = 128 */ 23 + #define EVENT_HASH_BITS 7 20 24 21 25 DECLARE_RWSEM(trace_event_sem); 22 26 23 - static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; 27 + static DEFINE_HASHTABLE(event_hash, EVENT_HASH_BITS); 24 28 25 29 enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter) 26 30 { ··· 688 684 return !trace_seq_has_overflowed(s); 689 685 } 690 686 687 + #ifdef CONFIG_FUNCTION_TRACE_ARGS 688 + void print_function_args(struct trace_seq *s, unsigned long *args, 689 + unsigned long func) 690 + { 691 + const struct btf_param *param; 692 + const struct btf_type *t; 693 + const char *param_name; 694 + char name[KSYM_NAME_LEN]; 695 + unsigned long arg; 696 + struct btf *btf; 697 + s32 tid, nr = 0; 698 + int a, p, x; 699 + 700 + trace_seq_printf(s, "("); 701 + 702 + if (!args) 703 + goto out; 704 + if (lookup_symbol_name(func, name)) 705 + goto out; 706 + 707 + /* TODO: Pass module name here too */ 708 + t = btf_find_func_proto(name, &btf); 709 + if (IS_ERR_OR_NULL(t)) 710 + goto out; 711 + 712 + param = btf_get_func_param(t, &nr); 713 + if (!param) 714 + goto out_put; 715 + 716 + for (a = 0, p = 0; p < nr; a++, p++) { 717 + if (p) 718 + trace_seq_puts(s, ", "); 719 + 720 + /* This only prints what the arch allows (6 args by default) */ 721 + if (a == FTRACE_REGS_MAX_ARGS) { 722 + trace_seq_puts(s, "..."); 723 + break; 724 + } 725 + 726 + arg = args[a]; 727 + 728 + param_name = btf_name_by_offset(btf, param[p].name_off); 729 + if (param_name) 730 + trace_seq_printf(s, "%s=", param_name); 731 + t = btf_type_skip_modifiers(btf, param[p].type, &tid); 732 + 733 + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { 734 + case BTF_KIND_UNKN: 735 + trace_seq_putc(s, '?'); 736 + /* Still print unknown type values */ 737 + fallthrough; 738 + case BTF_KIND_PTR: 739 + trace_seq_printf(s, "0x%lx", arg); 740 + break; 741 + case BTF_KIND_INT: 742 + trace_seq_printf(s, "%ld", arg); 743 + break; 744 + case BTF_KIND_ENUM: 745 + trace_seq_printf(s, "%ld", arg); 746 + break; 747 + default: 748 + /* This does not handle complex arguments */ 749 + trace_seq_printf(s, "(%s)[0x%lx", btf_type_str(t), arg); 750 + for (x = sizeof(long); x < t->size; x += sizeof(long)) { 751 + trace_seq_putc(s, ':'); 752 + if (++a == FTRACE_REGS_MAX_ARGS) { 753 + trace_seq_puts(s, "...]"); 754 + goto out_put; 755 + } 756 + trace_seq_printf(s, "0x%lx", args[a]); 757 + } 758 + trace_seq_putc(s, ']'); 759 + break; 760 + } 761 + } 762 + out_put: 763 + btf_put(btf); 764 + out: 765 + trace_seq_printf(s, ")"); 766 + } 767 + #endif 768 + 691 769 /** 692 770 * ftrace_find_event - find a registered event 693 771 * @type: the type of event to look for ··· 780 694 struct trace_event *ftrace_find_event(int type) 781 695 { 782 696 struct trace_event *event; 783 - unsigned key; 784 697 785 - key = type & (EVENT_HASHSIZE - 1); 786 - 787 - hlist_for_each_entry(event, &event_hash[key], node) { 698 + hash_for_each_possible(event_hash, event, node, type) { 788 699 if (event->type == type) 789 700 return event; 790 701 } ··· 836 753 */ 837 754 int register_trace_event(struct trace_event *event) 838 755 { 839 - unsigned key; 840 756 int ret = 0; 841 757 842 758 down_write(&trace_event_sem); ··· 868 786 if (event->funcs->binary == NULL) 869 787 event->funcs->binary = trace_nop_print; 870 788 871 - key = event->type & (EVENT_HASHSIZE - 1); 872 - 873 - hlist_add_head(&event->node, &event_hash[key]); 789 + hash_add(event_hash, &event->node, event->type); 874 790 875 791 ret = event->type; 876 792 out: ··· 883 803 */ 884 804 int __unregister_trace_event(struct trace_event *event) 885 805 { 886 - hlist_del(&event->node); 806 + hash_del(&event->node); 887 807 free_trace_event_type(event->type); 888 808 return 0; 889 809 } ··· 1085 1005 } 1086 1006 1087 1007 static void print_fn_trace(struct trace_seq *s, unsigned long ip, 1088 - unsigned long parent_ip, long delta, int flags) 1008 + unsigned long parent_ip, long delta, 1009 + unsigned long *args, int flags) 1089 1010 { 1090 1011 ip += delta; 1091 1012 parent_ip += delta; 1092 1013 1093 1014 seq_print_ip_sym(s, ip, flags); 1015 + if (args) 1016 + print_function_args(s, args, ip); 1094 1017 1095 1018 if ((flags & TRACE_ITER_PRINT_PARENT) && parent_ip) { 1096 1019 trace_seq_puts(s, " <-"); ··· 1107 1024 { 1108 1025 struct ftrace_entry *field; 1109 1026 struct trace_seq *s = &iter->seq; 1027 + unsigned long *args; 1028 + int args_size; 1110 1029 1111 1030 trace_assign_type(field, iter->ent); 1112 1031 1113 - print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, flags); 1032 + args_size = iter->ent_size - offsetof(struct ftrace_entry, args); 1033 + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) 1034 + args = field->args; 1035 + else 1036 + args = NULL; 1037 + 1038 + print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, 1039 + args, flags); 1114 1040 trace_seq_putc(s, '\n'); 1115 1041 1116 1042 return trace_handle_return(s); ··· 1792 1700 1793 1701 trace_assign_type(field, iter->ent); 1794 1702 1795 - print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, flags); 1703 + print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, NULL, flags); 1796 1704 trace_seq_printf(s, " (repeats: %u, last_ts:", field->count); 1797 1705 trace_print_time(s, iter, 1798 1706 iter->ts - FUNC_REPEATS_GET_DELTA_TS(field));
+9
kernel/trace/trace_output.h
··· 41 41 #define SEQ_PUT_HEX_FIELD(s, x) \ 42 42 trace_seq_putmem_hex(s, &(x), sizeof(x)) 43 43 44 + #ifdef CONFIG_FUNCTION_TRACE_ARGS 45 + void print_function_args(struct trace_seq *s, unsigned long *args, 46 + unsigned long func); 47 + #else 48 + static inline void print_function_args(struct trace_seq *s, unsigned long *args, 49 + unsigned long func) { 50 + trace_seq_puts(s, "()"); 51 + } 52 + #endif 44 53 #endif 45 54
+2 -4
kernel/trace/trace_sched_wakeup.c
··· 188 188 { 189 189 if (is_graph(iter->tr)) 190 190 graph_trace_open(iter); 191 - else 192 - iter->private = NULL; 193 191 } 194 192 195 193 static void wakeup_trace_close(struct trace_iterator *iter) ··· 240 242 return; 241 243 242 244 local_irq_save(flags); 243 - trace_function(tr, ip, parent_ip, trace_ctx); 245 + trace_function(tr, ip, parent_ip, trace_ctx, fregs); 244 246 local_irq_restore(flags); 245 247 246 248 atomic_dec(&data->disabled); ··· 325 327 if (is_graph(tr)) 326 328 trace_graph_function(tr, ip, parent_ip, trace_ctx); 327 329 else 328 - trace_function(tr, ip, parent_ip, trace_ctx); 330 + trace_function(tr, ip, parent_ip, trace_ctx, NULL); 329 331 } 330 332 331 333 static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set)