Pull tracing updates from Steven Rostedt: - Add function names as a way to filter function addresses - Add sample module to test ftrace ops and dynamic trampolines - Allow stack traces to be passed from beginning event to end event for synthetic events. This will allow seeing the stack trace of when a task is scheduled out and recorded when it gets scheduled back in. - Add trace event helper __get_buf() to use as a temporary buffer when printing out trace event output. - Add kernel command line to create trace instances on boot up. - Add enabling of events to instances created at boot up. - Add trace_array_puts() to write into instances. - Allow boot instances to take a snapshot at the end of boot up. - Allow live patch modules to include trace events - Minor fixes and clean ups * tag 'trace-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (31 commits) tracing: Remove unnecessary NULL assignment tracepoint: Allow livepatch module add trace event tracing: Always use canonical ftrace path tracing/histogram: Fix stacktrace histogram Documententation tracing/histogram: Fix stacktrace key tracing/histogram: Fix a few problems with stacktrace variable printing tracing: Add BUILD_BUG() to make sure stacktrace fits in strings tracing/histogram: Don't use strlen to find length of stacktrace variables tracing: Allow boot instances to have snapshot buffers tracing: Add trace_array_puts() to write into instance tracing: Add enabling of events to boot instances tracing: Add creation of instances at boot command line tracing: Fix trace_event_raw_event_synth() if else statement samples: ftrace: Make some global variables static ftrace: sample: avoid open-coded 64-bit division samples: ftrace: Include the nospec-branch.h only for x86 tracing: Acquire buffer from temparary trace sequence tracing/histogram: Wrap remaining shell snippets in code blocks tracing/osnoise: No need for schedule_hrtimeout range bpf/tracing: Use stage6 of tracing to not duplicate macros ...
Showing the changes to kernel (14 of 42 files). Show all
Unified · Split
| @@ -242,7 +242,7 @@ config DYNAMIC_FTRACE · 241 unmodified lines | ||
| 242 | 242 | enabled, and the functions not enabled will not affect |
| 243 | 243 | performance of the system. |
| 244 | 244 | |
| 245 | − See the files in /sys/kernel/debug/tracing: | |
| 245 | + See the files in /sys/kernel/tracing: | |
| 246 | 246 | available_filter_functions |
| 247 | 247 | set_ftrace_filter |
| 248 | 248 | set_ftrace_notrace |
| @@ -306,7 +306,7 @@ config STACK_TRACER · 57 unmodified lines | ||
| 306 | 306 | select KALLSYMS |
| 307 | 307 | help |
| 308 | 308 | This special tracer records the maximum stack footprint of the |
| 309 | − kernel and displays it in /sys/kernel/debug/tracing/stack_trace. | |
| 309 | + kernel and displays it in /sys/kernel/tracing/stack_trace. | |
| 310 | 310 | |
| 311 | 311 | This tracer works by hooking into every function call that the |
| 312 | 312 | kernel executes, and keeping a maximum stack depth value and |
| @@ -346,7 +346,7 @@ config IRQSOFF_TRACER · 33 unmodified lines | ||
| 346 | 346 | disabled by default and can be runtime (re-)started |
| 347 | 347 | via: |
| 348 | 348 | |
| 349 | − echo 0 > /sys/kernel/debug/tracing/tracing_max_latency | |
| 349 | + echo 0 > /sys/kernel/tracing/tracing_max_latency | |
| 350 | 350 | |
| 351 | 351 | (Note that kernel size and overhead increase with this option |
| 352 | 352 | enabled. This option and the preempt-off timing option can be |
| @@ -370,7 +370,7 @@ config PREEMPT_TRACER · 17 unmodified lines | ||
| 370 | 370 | disabled by default and can be runtime (re-)started |
| 371 | 371 | via: |
| 372 | 372 | |
| 373 | − echo 0 > /sys/kernel/debug/tracing/tracing_max_latency | |
| 373 | + echo 0 > /sys/kernel/tracing/tracing_max_latency | |
| 374 | 374 | |
| 375 | 375 | (Note that kernel size and overhead increase with this option |
| 376 | 376 | enabled. This option and the irqs-off timing option can be |
| @@ -522,7 +522,7 @@ config TRACER_SNAPSHOT · 145 unmodified lines | ||
| 522 | 522 | Allow tracing users to take snapshot of the current buffer using the |
| 523 | 523 | ftrace interface, e.g.: |
| 524 | 524 | |
| 525 | − echo 1 > /sys/kernel/debug/tracing/snapshot | |
| 525 | + echo 1 > /sys/kernel/tracing/snapshot | |
| 526 | 526 | cat snapshot |
| 527 | 527 | |
| 528 | 528 | config TRACER_SNAPSHOT_PER_CPU_SWAP |
| @@ -534,7 +534,7 @@ config TRACER_SNAPSHOT_PER_CPU_SWAP · 5 unmodified lines | ||
| 534 | 534 | full swap (all buffers). If this is set, then the following is |
| 535 | 535 | allowed: |
| 536 | 536 | |
| 537 | − echo 1 > /sys/kernel/debug/tracing/per_cpu/cpu2/snapshot | |
| 537 | + echo 1 > /sys/kernel/tracing/per_cpu/cpu2/snapshot | |
| 538 | 538 | |
| 539 | 539 | After which, only the tracing buffer for CPU 2 was swapped with |
| 540 | 540 | the main tracing buffer, and the other CPU buffers remain the same. |
| @@ -581,7 +581,7 @@ config PROFILE_ANNOTATED_BRANCHES · 40 unmodified lines | ||
| 581 | 581 | This tracer profiles all likely and unlikely macros |
| 582 | 582 | in the kernel. It will display the results in: |
| 583 | 583 | |
| 584 | − /sys/kernel/debug/tracing/trace_stat/branch_annotated | |
| 584 | + /sys/kernel/tracing/trace_stat/branch_annotated | |
| 585 | 585 | |
| 586 | 586 | Note: this will add a significant overhead; only turn this |
| 587 | 587 | on if you need to profile the system's use of these macros. |
| @@ -594,7 +594,7 @@ config PROFILE_ALL_BRANCHES · 6 unmodified lines | ||
| 594 | 594 | taken in the kernel is recorded whether it hit or miss. |
| 595 | 595 | The results will be displayed in: |
| 596 | 596 | |
| 597 | − /sys/kernel/debug/tracing/trace_stat/branch_all | |
| 597 | + /sys/kernel/tracing/trace_stat/branch_all | |
| 598 | 598 | |
| 599 | 599 | This option also enables the likely/unlikely profiler. |
| 600 | 600 | |
| @@ -645,8 +645,8 @@ config BLK_DEV_IO_TRACE · 44 unmodified lines | ||
| 645 | 645 | Tracing also is possible using the ftrace interface, e.g.: |
| 646 | 646 | |
| 647 | 647 | echo 1 > /sys/block/sda/sda1/trace/enable |
| 648 | − echo blk > /sys/kernel/debug/tracing/current_tracer | |
| 649 | − cat /sys/kernel/debug/tracing/trace_pipe | |
| 648 | + echo blk > /sys/kernel/tracing/current_tracer | |
| 649 | + cat /sys/kernel/tracing/trace_pipe | |
| 650 | 650 | |
| 651 | 651 | If unsure, say N. |
| 652 | 652 | |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | * Then: |
| 22 | 22 | * |
| 23 | 23 | * # insmod kernel/trace/kprobe_event_gen_test.ko |
| 24 | − * # cat /sys/kernel/debug/tracing/trace | |
| 24 | + * # cat /sys/kernel/tracing/trace | |
| 25 | 25 | * |
| 26 | 26 | * You should see many instances of the "gen_kprobe_test" and |
| 27 | 27 | * "gen_kretprobe_test" events in the trace buffer. |
| @@ -2864,7 +2864,7 @@ rb_check_timestamp(struct ring_buffer_per_cpu *cpu_buffer, · 2863 unmodified lines | ||
| 2864 | 2864 | sched_clock_stable() ? "" : |
| 2865 | 2865 | "If you just came from a suspend/resume,\n" |
| 2866 | 2866 | "please switch to the trace global clock:\n" |
| 2867 | − " echo global > /sys/kernel/debug/tracing/trace_clock\n" | |
| 2867 | + " echo global > /sys/kernel/tracing/trace_clock\n" | |
| 2868 | 2868 | "or add trace_clock=global to the kernel command line\n"); |
| 2869 | 2869 | } |
| 2870 | 2870 | |
| @@ -5604,11 +5604,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); · 2733 unmodified lines | ||
| 5604 | 5604 | */ |
| 5605 | 5605 | void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data) |
| 5606 | 5606 | { |
| 5607 | − struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; | |
| 5607 | + struct ring_buffer_per_cpu *cpu_buffer; | |
| 5608 | 5608 | struct buffer_data_page *bpage = data; |
| 5609 | 5609 | struct page *page = virt_to_page(bpage); |
| 5610 | 5610 | unsigned long flags; |
| 5611 | 5611 | |
| 5612 | + if (!buffer || !buffer->buffers || !buffer->buffers[cpu]) | |
| 5613 | + return; | |
| 5614 | + | |
| 5615 | + cpu_buffer = buffer->buffers[cpu]; | |
| 5616 | + | |
| 5612 | 5617 | /* If the page is still in use someplace else, we can't reuse it */ |
| 5613 | 5618 | if (page_ref_count(page) > 1) |
| 5614 | 5619 | goto out; |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | * Then: |
| 23 | 23 | * |
| 24 | 24 | * # insmod kernel/trace/synth_event_gen_test.ko |
| 25 | − * # cat /sys/kernel/debug/tracing/trace | |
| 25 | + * # cat /sys/kernel/tracing/trace | |
| 26 | 26 | * |
| 27 | 27 | * You should see several events in the trace buffer - |
| 28 | 28 | * "create_synth_test", "empty_synth_test", and several instances of |
| @@ -49,6 +49,8 @@ · 48 unmodified lines | ||
| 49 | 49 | #include <linux/irq_work.h> |
| 50 | 50 | #include <linux/workqueue.h> |
| 51 | 51 | |
| 52 | +#include <asm/setup.h> /* COMMAND_LINE_SIZE */ | |
| 53 | + | |
| 52 | 54 | #include "trace.h" |
| 53 | 55 | #include "trace_output.h" |
| 54 | 56 | |
| @@ -186,6 +188,12 @@ static char *default_bootup_tracer; · 131 unmodified lines | ||
| 186 | 188 | static bool allocate_snapshot; |
| 187 | 189 | static bool snapshot_at_boot; |
| 188 | 190 | |
| 191 | +static char boot_instance_info[COMMAND_LINE_SIZE] __initdata; | |
| 192 | +static int boot_instance_index; | |
| 193 | + | |
| 194 | +static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; | |
| 195 | +static int boot_snapshot_index; | |
| 196 | + | |
| 189 | 197 | static int __init set_cmdline_ftrace(char *str) |
| 190 | 198 | { |
| 191 | 199 | strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); |
| @@ -222,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning); · 30 unmodified lines | ||
| 222 | 230 | |
| 223 | 231 | static int __init boot_alloc_snapshot(char *str) |
| 224 | 232 | { |
| 225 | − allocate_snapshot = true; | |
| 226 | − /* We also need the main ring buffer expanded */ | |
| 227 | − ring_buffer_expanded = true; | |
| 233 | + char *slot = boot_snapshot_info + boot_snapshot_index; | |
| 234 | + int left = sizeof(boot_snapshot_info) - boot_snapshot_index; | |
| 235 | + int ret; | |
| 236 | + | |
| 237 | + if (str[0] == '=') { | |
| 238 | + str++; | |
| 239 | + if (strlen(str) >= left) | |
| 240 | + return -1; | |
| 241 | + | |
| 242 | + ret = snprintf(slot, left, "%s\t", str); | |
| 243 | + boot_snapshot_index += ret; | |
| 244 | + } else { | |
| 245 | + allocate_snapshot = true; | |
| 246 | + /* We also need the main ring buffer expanded */ | |
| 247 | + ring_buffer_expanded = true; | |
| 248 | + } | |
| 228 | 249 | return 1; |
| 229 | 250 | } |
| 230 | 251 | __setup("alloc_snapshot", boot_alloc_snapshot); |
| @@ -239,6 +260,23 @@ static int __init boot_snapshot(char *str) · 8 unmodified lines | ||
| 239 | 260 | __setup("ftrace_boot_snapshot", boot_snapshot); |
| 240 | 261 | |
| 241 | 262 | |
| 263 | +static int __init boot_instance(char *str) | |
| 264 | +{ | |
| 265 | + char *slot = boot_instance_info + boot_instance_index; | |
| 266 | + int left = sizeof(boot_instance_info) - boot_instance_index; | |
| 267 | + int ret; | |
| 268 | + | |
| 269 | + if (strlen(str) >= left) | |
| 270 | + return -1; | |
| 271 | + | |
| 272 | + ret = snprintf(slot, left, "%s\t", str); | |
| 273 | + boot_instance_index += ret; | |
| 274 | + | |
| 275 | + return 1; | |
| 276 | +} | |
| 277 | +__setup("trace_instance=", boot_instance); | |
| 278 | + | |
| 279 | + | |
| 242 | 280 | static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; |
| 243 | 281 | |
| 244 | 282 | static int __init set_trace_boot_options(char *str) |
| @@ -1001,13 +1039,8 @@ __buffer_unlock_commit(struct trace_buffer *buffer, struct ring_buffer_event *ev · 756 unmodified lines | ||
| 1001 | 1039 | ring_buffer_unlock_commit(buffer); |
| 1002 | 1040 | } |
| 1003 | 1041 | |
| 1004 | −/** | |
| 1005 | − * __trace_puts - write a constant string into the trace buffer. | |
| 1006 | − * @ip: The address of the caller | |
| 1007 | − * @str: The constant string to write | |
| 1008 | − * @size: The size of the string. | |
| 1009 | − */ | |
| 1010 | −int __trace_puts(unsigned long ip, const char *str, int size) | |
| 1042 | +int __trace_array_puts(struct trace_array *tr, unsigned long ip, | |
| 1043 | + const char *str, int size) | |
| 1011 | 1044 | { |
| 1012 | 1045 | struct ring_buffer_event *event; |
| 1013 | 1046 | struct trace_buffer *buffer; |
| @@ -1015,7 +1048,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 1 unmodified line | ||
| 1015 | 1048 | unsigned int trace_ctx; |
| 1016 | 1049 | int alloc; |
| 1017 | 1050 | |
| 1018 | − if (!(global_trace.trace_flags & TRACE_ITER_PRINTK)) | |
| 1051 | + if (!(tr->trace_flags & TRACE_ITER_PRINTK)) | |
| 1019 | 1052 | return 0; |
| 1020 | 1053 | |
| 1021 | 1054 | if (unlikely(tracing_selftest_running || tracing_disabled)) |
| @@ -1024,7 +1057,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 2 unmodified lines | ||
| 1024 | 1057 | alloc = sizeof(*entry) + size + 2; /* possible \n added */ |
| 1025 | 1058 | |
| 1026 | 1059 | trace_ctx = tracing_gen_ctx(); |
| 1027 | − buffer = global_trace.array_buffer.buffer; | |
| 1060 | + buffer = tr->array_buffer.buffer; | |
| 1028 | 1061 | ring_buffer_nest_start(buffer); |
| 1029 | 1062 | event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, |
| 1030 | 1063 | trace_ctx); |
| @@ -1046,11 +1079,23 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 15 unmodified lines | ||
| 1046 | 1079 | entry->buf[size] = '\0'; |
| 1047 | 1080 | |
| 1048 | 1081 | __buffer_unlock_commit(buffer, event); |
| 1049 | − ftrace_trace_stack(&global_trace, buffer, trace_ctx, 4, NULL); | |
| 1082 | + ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL); | |
| 1050 | 1083 | out: |
| 1051 | 1084 | ring_buffer_nest_end(buffer); |
| 1052 | 1085 | return size; |
| 1053 | 1086 | } |
| 1087 | +EXPORT_SYMBOL_GPL(__trace_array_puts); | |
| 1088 | + | |
| 1089 | +/** | |
| 1090 | + * __trace_puts - write a constant string into the trace buffer. | |
| 1091 | + * @ip: The address of the caller | |
| 1092 | + * @str: The constant string to write | |
| 1093 | + * @size: The size of the string. | |
| 1094 | + */ | |
| 1095 | +int __trace_puts(unsigned long ip, const char *str, int size) | |
| 1096 | +{ | |
| 1097 | + return __trace_array_puts(&global_trace, ip, str, size); | |
| 1098 | +} | |
| 1054 | 1099 | EXPORT_SYMBOL_GPL(__trace_puts); |
| 1055 | 1100 | |
| 1056 | 1101 | /** |
| @@ -1142,7 +1187,7 @@ void tracing_snapshot_instance(struct trace_array *tr) · 85 unmodified lines | ||
| 1142 | 1187 | * |
| 1143 | 1188 | * Note, make sure to allocate the snapshot with either |
| 1144 | 1189 | * a tracing_snapshot_alloc(), or by doing it manually |
| 1145 | − * with: echo 1 > /sys/kernel/debug/tracing/snapshot | |
| 1190 | + * with: echo 1 > /sys/kernel/tracing/snapshot | |
| 1146 | 1191 | * |
| 1147 | 1192 | * If the snapshot buffer is not allocated, it will stop tracing. |
| 1148 | 1193 | * Basically making a permanent snapshot. |
| @@ -5760,7 +5805,7 @@ static const char readme_msg[] = · 4611 unmodified lines | ||
| 5760 | 5805 | #ifdef CONFIG_SYNTH_EVENTS |
| 5761 | 5806 | " events/synthetic_events\t- Create/append/remove/show synthetic events\n" |
| 5762 | 5807 | "\t Write into this file to define/undefine new synthetic events.\n" |
| 5763 | − "\t example: echo 'myevent u64 lat; char name[]' >> synthetic_events\n" | |
| 5808 | + "\t example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n" | |
| 5764 | 5809 | #endif |
| 5765 | 5810 | #endif |
| 5766 | 5811 | ; |
| @@ -9225,10 +9270,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) · 3458 unmodified lines | ||
| 9225 | 9270 | } |
| 9226 | 9271 | tr->allocated_snapshot = allocate_snapshot; |
| 9227 | 9272 | |
| 9228 | − /* | |
| 9229 | − * Only the top level trace array gets its snapshot allocated | |
| 9230 | − * from the kernel command line. | |
| 9231 | − */ | |
| 9232 | 9273 | allocate_snapshot = false; |
| 9233 | 9274 | #endif |
| 9234 | 9275 | |
| @@ -10144,6 +10185,79 @@ out: · 909 unmodified lines | ||
| 10144 | 10185 | return ret; |
| 10145 | 10186 | } |
| 10146 | 10187 | |
| 10188 | +#ifdef CONFIG_TRACER_MAX_TRACE | |
| 10189 | +__init static bool tr_needs_alloc_snapshot(const char *name) | |
| 10190 | +{ | |
| 10191 | + char *test; | |
| 10192 | + int len = strlen(name); | |
| 10193 | + bool ret; | |
| 10194 | + | |
| 10195 | + if (!boot_snapshot_index) | |
| 10196 | + return false; | |
| 10197 | + | |
| 10198 | + if (strncmp(name, boot_snapshot_info, len) == 0 && | |
| 10199 | + boot_snapshot_info[len] == '\t') | |
| 10200 | + return true; | |
| 10201 | + | |
| 10202 | + test = kmalloc(strlen(name) + 3, GFP_KERNEL); | |
| 10203 | + if (!test) | |
| 10204 | + return false; | |
| 10205 | + | |
| 10206 | + sprintf(test, "\t%s\t", name); | |
| 10207 | + ret = strstr(boot_snapshot_info, test) == NULL; | |
| 10208 | + kfree(test); | |
| 10209 | + return ret; | |
| 10210 | +} | |
| 10211 | + | |
| 10212 | +__init static void do_allocate_snapshot(const char *name) | |
| 10213 | +{ | |
| 10214 | + if (!tr_needs_alloc_snapshot(name)) | |
| 10215 | + return; | |
| 10216 | + | |
| 10217 | + /* | |
| 10218 | + * When allocate_snapshot is set, the next call to | |
| 10219 | + * allocate_trace_buffers() (called by trace_array_get_by_name()) | |
| 10220 | + * will allocate the snapshot buffer. That will alse clear | |
| 10221 | + * this flag. | |
| 10222 | + */ | |
| 10223 | + allocate_snapshot = true; | |
| 10224 | +} | |
| 10225 | +#else | |
| 10226 | +static inline void do_allocate_snapshot(const char *name) { } | |
| 10227 | +#endif | |
| 10228 | + | |
| 10229 | +__init static void enable_instances(void) | |
| 10230 | +{ | |
| 10231 | + struct trace_array *tr; | |
| 10232 | + char *curr_str; | |
| 10233 | + char *str; | |
| 10234 | + char *tok; | |
| 10235 | + | |
| 10236 | + /* A tab is always appended */ | |
| 10237 | + boot_instance_info[boot_instance_index - 1] = '\0'; | |
| 10238 | + str = boot_instance_info; | |
| 10239 | + | |
| 10240 | + while ((curr_str = strsep(&str, "\t"))) { | |
| 10241 | + | |
| 10242 | + tok = strsep(&curr_str, ","); | |
| 10243 | + | |
| 10244 | + if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE)) | |
| 10245 | + do_allocate_snapshot(tok); | |
| 10246 | + | |
| 10247 | + tr = trace_array_get_by_name(tok); | |
| 10248 | + if (!tr) { | |
| 10249 | + pr_warn("Failed to create instance buffer %s\n", curr_str); | |
| 10250 | + continue; | |
| 10251 | + } | |
| 10252 | + /* Allow user space to delete it */ | |
| 10253 | + trace_array_put(tr); | |
| 10254 | + | |
| 10255 | + while ((tok = strsep(&curr_str, ","))) { | |
| 10256 | + early_enable_events(tr, tok, true); | |
| 10257 | + } | |
| 10258 | + } | |
| 10259 | +} | |
| 10260 | + | |
| 10147 | 10261 | __init static int tracer_alloc_buffers(void) |
| 10148 | 10262 | { |
| 10149 | 10263 | int ring_buf_size; |
| @@ -10277,10 +10391,19 @@ out: · 127 unmodified lines | ||
| 10277 | 10391 | |
| 10278 | 10392 | void __init ftrace_boot_snapshot(void) |
| 10279 | 10393 | { |
| 10394 | + struct trace_array *tr; | |
| 10395 | + | |
| 10280 | 10396 | if (snapshot_at_boot) { |
| 10281 | 10397 | tracing_snapshot(); |
| 10282 | 10398 | internal_trace_puts("** Boot snapshot taken **\n"); |
| 10283 | 10399 | } |
| 10400 | + | |
| 10401 | + list_for_each_entry(tr, &ftrace_trace_arrays, list) { | |
| 10402 | + if (tr == &global_trace) | |
| 10403 | + continue; | |
| 10404 | + trace_array_puts(tr, "** Boot snapshot taken **\n"); | |
| 10405 | + tracing_snapshot_instance(tr); | |
| 10406 | + } | |
| 10284 | 10407 | } |
| 10285 | 10408 | |
| 10286 | 10409 | void __init early_trace_init(void) |
| @@ -10302,6 +10425,9 @@ void __init early_trace_init(void) · 15 unmodified lines | ||
| 10302 | 10425 | void __init trace_init(void) |
| 10303 | 10426 | { |
| 10304 | 10427 | trace_event_init(); |
| 10428 | + | |
| 10429 | + if (boot_instance_index) | |
| 10430 | + enable_instances(); | |
| 10305 | 10431 | } |
| 10306 | 10432 | |
| 10307 | 10433 | __init static void clear_boot_tracer(void) |
| @@ -113,6 +113,10 @@ enum trace_type { · 112 unmodified lines | ||
| 113 | 113 | #define MEM_FAIL(condition, fmt, ...) \ |
| 114 | 114 | DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__) |
| 115 | 115 | |
| 116 | +#define HIST_STACKTRACE_DEPTH 16 | |
| 117 | +#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) | |
| 118 | +#define HIST_STACKTRACE_SKIP 5 | |
| 119 | + | |
| 116 | 120 | /* |
| 117 | 121 | * syscalls are special, and need special handling, this is why |
| 118 | 122 | * they are not included in trace_entries.h |
| @@ -1331,6 +1335,8 @@ DECLARE_PER_CPU(int, trace_buffered_event_cnt); · 1212 unmodified lines | ||
| 1331 | 1335 | void trace_buffered_event_disable(void); |
| 1332 | 1336 | void trace_buffered_event_enable(void); |
| 1333 | 1337 | |
| 1338 | +void early_enable_events(struct trace_array *tr, char *buf, bool disable_first); | |
| 1339 | + | |
| 1334 | 1340 | static inline void |
| 1335 | 1341 | __trace_event_discard_commit(struct trace_buffer *buffer, |
| 1336 | 1342 | struct ring_buffer_event *event) |
| @@ -2281,8 +2281,6 @@ create_new_subsystem(const char *name) · 2280 unmodified lines | ||
| 2281 | 2281 | if (!system->name) |
| 2282 | 2282 | goto out_free; |
| 2283 | 2283 | |
| 2284 | − system->filter = NULL; | |
| 2285 | − | |
| 2286 | 2284 | system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL); |
| 2287 | 2285 | if (!system->filter) |
| 2288 | 2286 | goto out_free; |
| @@ -2843,7 +2841,7 @@ static __init int setup_trace_triggers(char *str) · 554 unmodified lines | ||
| 2843 | 2841 | if (!trigger) |
| 2844 | 2842 | break; |
| 2845 | 2843 | bootup_triggers[i].event = strsep(&trigger, "."); |
| 2846 | − bootup_triggers[i].trigger = strsep(&trigger, "."); | |
| 2844 | + bootup_triggers[i].trigger = trigger; | |
| 2847 | 2845 | if (!bootup_triggers[i].trigger) |
| 2848 | 2846 | break; |
| 2849 | 2847 | } |
| @@ -3771,10 +3769,9 @@ static __init int event_trace_memsetup(void) · 921 unmodified lines | ||
| 3771 | 3769 | return 0; |
| 3772 | 3770 | } |
| 3773 | 3771 | |
| 3774 | −static __init void | |
| 3775 | −early_enable_events(struct trace_array *tr, bool disable_first) | |
| 3772 | +__init void | |
| 3773 | +early_enable_events(struct trace_array *tr, char *buf, bool disable_first) | |
| 3776 | 3774 | { |
| 3777 | − char *buf = bootup_event_buf; | |
| 3778 | 3775 | char *token; |
| 3779 | 3776 | int ret; |
| 3780 | 3777 | |
| @@ -3827,7 +3824,7 @@ static __init int event_trace_enable(void) · 46 unmodified lines | ||
| 3827 | 3824 | */ |
| 3828 | 3825 | __trace_early_add_events(tr); |
| 3829 | 3826 | |
| 3830 | − early_enable_events(tr, false); | |
| 3827 | + early_enable_events(tr, bootup_event_buf, false); | |
| 3831 | 3828 | |
| 3832 | 3829 | trace_printk_start_comm(); |
| 3833 | 3830 | |
| @@ -3855,7 +3852,7 @@ static __init int event_trace_enable_again(void) · 21 unmodified lines | ||
| 3855 | 3852 | if (!tr) |
| 3856 | 3853 | return -ENODEV; |
| 3857 | 3854 | |
| 3858 | − early_enable_events(tr, true); | |
| 3855 | + early_enable_events(tr, bootup_event_buf, true); | |
| 3859 | 3856 | |
| 3860 | 3857 | return 0; |
| 3861 | 3858 | } |
| @@ -64,6 +64,7 @@ enum filter_pred_fn { · 63 unmodified lines | ||
| 64 | 64 | FILTER_PRED_FN_PCHAR_USER, |
| 65 | 65 | FILTER_PRED_FN_PCHAR, |
| 66 | 66 | FILTER_PRED_FN_CPU, |
| 67 | + FILTER_PRED_FN_FUNCTION, | |
| 67 | 68 | FILTER_PRED_FN_, |
| 68 | 69 | FILTER_PRED_TEST_VISITED, |
| 69 | 70 | }; |
| @@ -71,6 +72,7 @@ enum filter_pred_fn { · 1 unmodified line | ||
| 71 | 72 | struct filter_pred { |
| 72 | 73 | enum filter_pred_fn fn_num; |
| 73 | 74 | u64 val; |
| 75 | + u64 val2; | |
| 74 | 76 | struct regex regex; |
| 75 | 77 | unsigned short *ops; |
| 76 | 78 | struct ftrace_event_field *field; |
| @@ -103,6 +105,7 @@ struct filter_pred { · 26 unmodified lines | ||
| 103 | 105 | C(INVALID_FILTER, "Meaningless filter expression"), \ |
| 104 | 106 | C(IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \ |
| 105 | 107 | C(INVALID_VALUE, "Invalid value (did you forget quotes)?"), \ |
| 108 | + C(NO_FUNCTION, "Function not found"), \ | |
| 106 | 109 | C(ERRNO, "Error"), \ |
| 107 | 110 | C(NO_FILTER, "No filter found") |
| 108 | 111 | |
| @@ -876,6 +879,17 @@ static int filter_pred_comm(struct filter_pred *pred, void *event) · 767 unmodified lines | ||
| 876 | 879 | return cmp ^ pred->not; |
| 877 | 880 | } |
| 878 | 881 | |
| 882 | +/* Filter predicate for functions. */ | |
| 883 | +static int filter_pred_function(struct filter_pred *pred, void *event) | |
| 884 | +{ | |
| 885 | + unsigned long *addr = (unsigned long *)(event + pred->offset); | |
| 886 | + unsigned long start = (unsigned long)pred->val; | |
| 887 | + unsigned long end = (unsigned long)pred->val2; | |
| 888 | + int ret = *addr >= start && *addr < end; | |
| 889 | + | |
| 890 | + return pred->op == OP_EQ ? ret : !ret; | |
| 891 | +} | |
| 892 | + | |
| 879 | 893 | /* |
| 880 | 894 | * regex_match_foo - Basic regex callbacks |
| 881 | 895 | * |
| @@ -1335,6 +1349,8 @@ static int filter_pred_fn_call(struct filter_pred *pred, void *event) · 453 unmodified lines | ||
| 1335 | 1349 | return filter_pred_pchar(pred, event); |
| 1336 | 1350 | case FILTER_PRED_FN_CPU: |
| 1337 | 1351 | return filter_pred_cpu(pred, event); |
| 1352 | + case FILTER_PRED_FN_FUNCTION: | |
| 1353 | + return filter_pred_function(pred, event); | |
| 1338 | 1354 | case FILTER_PRED_TEST_VISITED: |
| 1339 | 1355 | return test_pred_visited_fn(pred, event); |
| 1340 | 1356 | default: |
| @@ -1350,8 +1366,13 @@ static int parse_pred(const char *str, void *data, · 9 unmodified lines | ||
| 1350 | 1366 | struct trace_event_call *call = data; |
| 1351 | 1367 | struct ftrace_event_field *field; |
| 1352 | 1368 | struct filter_pred *pred = NULL; |
| 1369 | + unsigned long offset; | |
| 1370 | + unsigned long size; | |
| 1371 | + unsigned long ip; | |
| 1353 | 1372 | char num_buf[24]; /* Big enough to hold an address */ |
| 1354 | 1373 | char *field_name; |
| 1374 | + char *name; | |
| 1375 | + bool function = false; | |
| 1355 | 1376 | bool ustring = false; |
| 1356 | 1377 | char q; |
| 1357 | 1378 | u64 val; |
| @@ -1393,6 +1414,12 @@ static int parse_pred(const char *str, void *data, · 35 unmodified lines | ||
| 1393 | 1414 | i += len; |
| 1394 | 1415 | } |
| 1395 | 1416 | |
| 1417 | + /* See if the field is a kernel function name */ | |
| 1418 | + if ((len = str_has_prefix(str + i, ".function"))) { | |
| 1419 | + function = true; | |
| 1420 | + i += len; | |
| 1421 | + } | |
| 1422 | + | |
| 1396 | 1423 | while (isspace(str[i])) |
| 1397 | 1424 | i++; |
| 1398 | 1425 | |
| @@ -1423,7 +1450,71 @@ static int parse_pred(const char *str, void *data, · 24 unmodified lines | ||
| 1423 | 1450 | pred->offset = field->offset; |
| 1424 | 1451 | pred->op = op; |
| 1425 | 1452 | |
| 1426 | − if (ftrace_event_is_function(call)) { | |
| 1453 | + if (function) { | |
| 1454 | + /* The field must be the same size as long */ | |
| 1455 | + if (field->size != sizeof(long)) { | |
| 1456 | + parse_error(pe, FILT_ERR_ILLEGAL_FIELD_OP, pos + i); | |
| 1457 | + goto err_free; | |
| 1458 | + } | |
| 1459 | + | |
| 1460 | + /* Function only works with '==' or '!=' and an unquoted string */ | |
| 1461 | + switch (op) { | |
| 1462 | + case OP_NE: | |
| 1463 | + case OP_EQ: | |
| 1464 | + break; | |
| 1465 | + default: | |
| 1466 | + parse_error(pe, FILT_ERR_INVALID_OP, pos + i); | |
| 1467 | + goto err_free; | |
| 1468 | + } | |
| 1469 | + | |
| 1470 | + if (isdigit(str[i])) { | |
| 1471 | + /* We allow 0xDEADBEEF */ | |
| 1472 | + while (isalnum(str[i])) | |
| 1473 | + i++; | |
| 1474 | + | |
| 1475 | + len = i - s; | |
| 1476 | + /* 0xfeedfacedeadbeef is 18 chars max */ | |
| 1477 | + if (len >= sizeof(num_buf)) { | |
| 1478 | + parse_error(pe, FILT_ERR_OPERAND_TOO_LONG, pos + i); | |
| 1479 | + goto err_free; | |
| 1480 | + } | |
| 1481 | + | |
| 1482 | + strncpy(num_buf, str + s, len); | |
| 1483 | + num_buf[len] = 0; | |
| 1484 | + | |
| 1485 | + ret = kstrtoul(num_buf, 0, &ip); | |
| 1486 | + if (ret) { | |
| 1487 | + parse_error(pe, FILT_ERR_INVALID_VALUE, pos + i); | |
| 1488 | + goto err_free; | |
| 1489 | + } | |
| 1490 | + } else { | |
| 1491 | + s = i; | |
| 1492 | + for (; str[i] && !isspace(str[i]); i++) | |
| 1493 | + ; | |
| 1494 | + | |
| 1495 | + len = i - s; | |
| 1496 | + name = kmemdup_nul(str + s, len, GFP_KERNEL); | |
| 1497 | + if (!name) | |
| 1498 | + goto err_mem; | |
| 1499 | + ip = kallsyms_lookup_name(name); | |
| 1500 | + kfree(name); | |
| 1501 | + if (!ip) { | |
| 1502 | + parse_error(pe, FILT_ERR_NO_FUNCTION, pos + i); | |
| 1503 | + goto err_free; | |
| 1504 | + } | |
| 1505 | + } | |
| 1506 | + | |
| 1507 | + /* Now find the function start and end address */ | |
| 1508 | + if (!kallsyms_lookup_size_offset(ip, &size, &offset)) { | |
| 1509 | + parse_error(pe, FILT_ERR_NO_FUNCTION, pos + i); | |
| 1510 | + goto err_free; | |
| 1511 | + } | |
| 1512 | + | |
| 1513 | + pred->fn_num = FILTER_PRED_FN_FUNCTION; | |
| 1514 | + pred->val = ip - offset; | |
| 1515 | + pred->val2 = pred->val + size; | |
| 1516 | + | |
| 1517 | + } else if (ftrace_event_is_function(call)) { | |
| 1427 | 1518 | /* |
| 1428 | 1519 | * Perf does things different with function events. |
| 1429 | 1520 | * It only allows an "ip" field, and expects a string. |
| @@ -135,6 +135,7 @@ enum hist_field_fn { · 134 unmodified lines | ||
| 135 | 135 | HIST_FIELD_FN_DIV_NOT_POWER2, |
| 136 | 136 | HIST_FIELD_FN_DIV_MULT_SHIFT, |
| 137 | 137 | HIST_FIELD_FN_EXECNAME, |
| 138 | + HIST_FIELD_FN_STACK, | |
| 138 | 139 | }; |
| 139 | 140 | |
| 140 | 141 | /* |
| @@ -480,10 +481,6 @@ DEFINE_HIST_FIELD_FN(u8); · 339 unmodified lines | ||
| 480 | 481 | #define for_each_hist_key_field(i, hist_data) \ |
| 481 | 482 | for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) |
| 482 | 483 | |
| 483 | −#define HIST_STACKTRACE_DEPTH 16 | |
| 484 | −#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) | |
| 485 | −#define HIST_STACKTRACE_SKIP 5 | |
| 486 | − | |
| 487 | 484 | #define HITCOUNT_IDX 0 |
| 488 | 485 | #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) |
| 489 | 486 | |
| @@ -1360,7 +1357,12 @@ static const char *hist_field_name(struct hist_field *field, · 870 unmodified lines | ||
| 1360 | 1357 | field_name = field->name; |
| 1361 | 1358 | } else if (field->flags & HIST_FIELD_FL_TIMESTAMP) |
| 1362 | 1359 | field_name = "common_timestamp"; |
| 1363 | − else if (field->flags & HIST_FIELD_FL_HITCOUNT) | |
| 1360 | + else if (field->flags & HIST_FIELD_FL_STACKTRACE) { | |
| 1361 | + if (field->field) | |
| 1362 | + field_name = field->field->name; | |
| 1363 | + else | |
| 1364 | + field_name = "stacktrace"; | |
| 1365 | + } else if (field->flags & HIST_FIELD_FL_HITCOUNT) | |
| 1364 | 1366 | field_name = "hitcount"; |
| 1365 | 1367 | |
| 1366 | 1368 | if (field_name == NULL) |
| @@ -1718,6 +1720,8 @@ static const char *get_hist_field_flags(struct hist_field *hist_field) · 351 unmodified lines | ||
| 1718 | 1720 | flags_str = "percent"; |
| 1719 | 1721 | else if (hist_field->flags & HIST_FIELD_FL_GRAPH) |
| 1720 | 1722 | flags_str = "graph"; |
| 1723 | + else if (hist_field->flags & HIST_FIELD_FL_STACKTRACE) | |
| 1724 | + flags_str = "stacktrace"; | |
| 1721 | 1725 | |
| 1722 | 1726 | return flags_str; |
| 1723 | 1727 | } |
| @@ -1979,7 +1983,14 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data, · 255 unmodified lines | ||
| 1979 | 1983 | } |
| 1980 | 1984 | |
| 1981 | 1985 | if (flags & HIST_FIELD_FL_STACKTRACE) { |
| 1982 | − hist_field->fn_num = HIST_FIELD_FN_NOP; | |
| 1986 | + if (field) | |
| 1987 | + hist_field->fn_num = HIST_FIELD_FN_STACK; | |
| 1988 | + else | |
| 1989 | + hist_field->fn_num = HIST_FIELD_FN_NOP; | |
| 1990 | + hist_field->size = HIST_STACKTRACE_SIZE; | |
| 1991 | + hist_field->type = kstrdup_const("unsigned long[]", GFP_KERNEL); | |
| 1992 | + if (!hist_field->type) | |
| 1993 | + goto free; | |
| 1983 | 1994 | goto out; |
| 1984 | 1995 | } |
| 1985 | 1996 | |
| @@ -2312,6 +2323,8 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file, · 326 unmodified lines | ||
| 2312 | 2323 | *flags |= HIST_FIELD_FL_EXECNAME; |
| 2313 | 2324 | else if (strcmp(modifier, "syscall") == 0) |
| 2314 | 2325 | *flags |= HIST_FIELD_FL_SYSCALL; |
| 2326 | + else if (strcmp(modifier, "stacktrace") == 0) | |
| 2327 | + *flags |= HIST_FIELD_FL_STACKTRACE; | |
| 2315 | 2328 | else if (strcmp(modifier, "log2") == 0) |
| 2316 | 2329 | *flags |= HIST_FIELD_FL_LOG2; |
| 2317 | 2330 | else if (strcmp(modifier, "usecs") == 0) |
| @@ -2351,6 +2364,8 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file, · 33 unmodified lines | ||
| 2351 | 2364 | hist_data->enable_timestamps = true; |
| 2352 | 2365 | if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS) |
| 2353 | 2366 | hist_data->attrs->ts_in_usecs = true; |
| 2367 | + } else if (strcmp(field_name, "stacktrace") == 0) { | |
| 2368 | + *flags |= HIST_FIELD_FL_STACKTRACE; | |
| 2354 | 2369 | } else if (strcmp(field_name, "common_cpu") == 0) |
| 2355 | 2370 | *flags |= HIST_FIELD_FL_CPU; |
| 2356 | 2371 | else if (strcmp(field_name, "hitcount") == 0) |
| @@ -3111,6 +3126,9 @@ static inline void __update_field_vars(struct tracing_map_elt *elt, · 754 unmodified lines | ||
| 3111 | 3126 | unsigned int i, j, var_idx; |
| 3112 | 3127 | u64 var_val; |
| 3113 | 3128 | |
| 3129 | + /* Make sure stacktrace can fit in the string variable length */ | |
| 3130 | + BUILD_BUG_ON((HIST_STACKTRACE_DEPTH + 1) * sizeof(long) >= STR_VAR_LEN_MAX); | |
| 3131 | + | |
| 3114 | 3132 | for (i = 0, j = field_var_str_start; i < n_field_vars; i++) { |
| 3115 | 3133 | struct field_var *field_var = field_vars[i]; |
| 3116 | 3134 | struct hist_field *var = field_var->var; |
| @@ -3119,13 +3137,26 @@ static inline void __update_field_vars(struct tracing_map_elt *elt, · 2 unmodified lines | ||
| 3119 | 3137 | var_val = hist_fn_call(val, elt, buffer, rbe, rec); |
| 3120 | 3138 | var_idx = var->var.idx; |
| 3121 | 3139 | |
| 3122 | − if (val->flags & HIST_FIELD_FL_STRING) { | |
| 3140 | + if (val->flags & (HIST_FIELD_FL_STRING | | |
| 3141 | + HIST_FIELD_FL_STACKTRACE)) { | |
| 3123 | 3142 | char *str = elt_data->field_var_str[j++]; |
| 3124 | 3143 | char *val_str = (char *)(uintptr_t)var_val; |
| 3125 | 3144 | unsigned int size; |
| 3126 | 3145 | |
| 3127 | − size = min(val->size, STR_VAR_LEN_MAX); | |
| 3128 | − strscpy(str, val_str, size); | |
| 3146 | + if (val->flags & HIST_FIELD_FL_STRING) { | |
| 3147 | + size = min(val->size, STR_VAR_LEN_MAX); | |
| 3148 | + strscpy(str, val_str, size); | |
| 3149 | + } else { | |
| 3150 | + char *stack_start = str + sizeof(unsigned long); | |
| 3151 | + int e; | |
| 3152 | + | |
| 3153 | + e = stack_trace_save((void *)stack_start, | |
| 3154 | + HIST_STACKTRACE_DEPTH, | |
| 3155 | + HIST_STACKTRACE_SKIP); | |
| 3156 | + if (e < HIST_STACKTRACE_DEPTH - 1) | |
| 3157 | + ((unsigned long *)stack_start)[e] = 0; | |
| 3158 | + *((unsigned long *)str) = e; | |
| 3159 | + } | |
| 3129 | 3160 | var_val = (u64)(uintptr_t)str; |
| 3130 | 3161 | } |
| 3131 | 3162 | tracing_map_set_var(elt, var_idx, var_val); |
| @@ -3824,7 +3855,8 @@ static void save_field_var(struct hist_trigger_data *hist_data, · 692 unmodified lines | ||
| 3824 | 3855 | { |
| 3825 | 3856 | hist_data->field_vars[hist_data->n_field_vars++] = field_var; |
| 3826 | 3857 | |
| 3827 | − if (field_var->val->flags & HIST_FIELD_FL_STRING) | |
| 3858 | + /* Stack traces are saved in the string storage too */ | |
| 3859 | + if (field_var->val->flags & (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | |
| 3828 | 3860 | hist_data->n_field_var_str++; |
| 3829 | 3861 | } |
| 3830 | 3862 | |
| @@ -3849,6 +3881,9 @@ static int check_synth_field(struct synth_event *event, · 18 unmodified lines | ||
| 3849 | 3881 | && field->is_dynamic) |
| 3850 | 3882 | return 0; |
| 3851 | 3883 | |
| 3884 | + if (strstr(hist_field->type, "long[") && field->is_stack) | |
| 3885 | + return 0; | |
| 3886 | + | |
| 3852 | 3887 | if (strcmp(field->type, hist_field->type) != 0) { |
| 3853 | 3888 | if (field->size != hist_field->size || |
| 3854 | 3889 | (!field->is_string && field->is_signed != hist_field->is_signed)) |
| @@ -4103,7 +4138,8 @@ static int action_create(struct hist_trigger_data *hist_data, · 248 unmodified lines | ||
| 4103 | 4138 | } |
| 4104 | 4139 | |
| 4105 | 4140 | hist_data->save_vars[hist_data->n_save_vars++] = field_var; |
| 4106 | − if (field_var->val->flags & HIST_FIELD_FL_STRING) | |
| 4141 | + if (field_var->val->flags & | |
| 4142 | + (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | |
| 4107 | 4143 | hist_data->n_save_var_str++; |
| 4108 | 4144 | kfree(param); |
| 4109 | 4145 | } |
| @@ -4242,6 +4278,19 @@ static u64 hist_field_execname(struct hist_field *hist_field, · 132 unmodified lines | ||
| 4242 | 4278 | return (u64)(unsigned long)(elt_data->comm); |
| 4243 | 4279 | } |
| 4244 | 4280 | |
| 4281 | +static u64 hist_field_stack(struct hist_field *hist_field, | |
| 4282 | + struct tracing_map_elt *elt, | |
| 4283 | + struct trace_buffer *buffer, | |
| 4284 | + struct ring_buffer_event *rbe, | |
| 4285 | + void *event) | |
| 4286 | +{ | |
| 4287 | + u32 str_item = *(u32 *)(event + hist_field->field->offset); | |
| 4288 | + int str_loc = str_item & 0xffff; | |
| 4289 | + char *addr = (char *)(event + str_loc); | |
| 4290 | + | |
| 4291 | + return (u64)(unsigned long)addr; | |
| 4292 | +} | |
| 4293 | + | |
| 4245 | 4294 | static u64 hist_fn_call(struct hist_field *hist_field, |
| 4246 | 4295 | struct tracing_map_elt *elt, |
| 4247 | 4296 | struct trace_buffer *buffer, |
| @@ -4305,6 +4354,8 @@ static u64 hist_fn_call(struct hist_field *hist_field, · 57 unmodified lines | ||
| 4305 | 4354 | return div_by_mult_and_shift(hist_field, elt, buffer, rbe, event); |
| 4306 | 4355 | case HIST_FIELD_FN_EXECNAME: |
| 4307 | 4356 | return hist_field_execname(hist_field, elt, buffer, rbe, event); |
| 4357 | + case HIST_FIELD_FN_STACK: | |
| 4358 | + return hist_field_stack(hist_field, elt, buffer, rbe, event); | |
| 4308 | 4359 | default: |
| 4309 | 4360 | return 0; |
| 4310 | 4361 | } |
| @@ -4351,7 +4402,8 @@ static int create_var_field(struct hist_trigger_data *hist_data, · 40 unmodified lines | ||
| 4351 | 4402 | if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME) |
| 4352 | 4403 | update_var_execname(hist_data->fields[val_idx]); |
| 4353 | 4404 | |
| 4354 | − if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING) | |
| 4405 | + if (!ret && hist_data->fields[val_idx]->flags & | |
| 4406 | + (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | |
| 4355 | 4407 | hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++; |
| 4356 | 4408 | |
| 4357 | 4409 | return ret; |
| @@ -5092,7 +5144,8 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data, · 734 unmodified lines | ||
| 5092 | 5144 | if (hist_field->flags & HIST_FIELD_FL_VAR) { |
| 5093 | 5145 | var_idx = hist_field->var.idx; |
| 5094 | 5146 | |
| 5095 | − if (hist_field->flags & HIST_FIELD_FL_STRING) { | |
| 5147 | + if (hist_field->flags & | |
| 5148 | + (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) { | |
| 5096 | 5149 | unsigned int str_start, var_str_idx, idx; |
| 5097 | 5150 | char *str, *val_str; |
| 5098 | 5151 | unsigned int size; |
| @@ -5105,9 +5158,20 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data, · 6 unmodified lines | ||
| 5105 | 5158 | str = elt_data->field_var_str[idx]; |
| 5106 | 5159 | val_str = (char *)(uintptr_t)hist_val; |
| 5107 | 5160 | |
| 5108 | − size = min(hist_field->size, STR_VAR_LEN_MAX); | |
| 5109 | − strscpy(str, val_str, size); | |
| 5110 | − | |
| 5161 | + if (hist_field->flags & HIST_FIELD_FL_STRING) { | |
| 5162 | + size = min(hist_field->size, STR_VAR_LEN_MAX); | |
| 5163 | + strscpy(str, val_str, size); | |
| 5164 | + } else { | |
| 5165 | + char *stack_start = str + sizeof(unsigned long); | |
| 5166 | + int e; | |
| 5167 | + | |
| 5168 | + e = stack_trace_save((void *)stack_start, | |
| 5169 | + HIST_STACKTRACE_DEPTH, | |
| 5170 | + HIST_STACKTRACE_SKIP); | |
| 5171 | + if (e < HIST_STACKTRACE_DEPTH - 1) | |
| 5172 | + ((unsigned long *)stack_start)[e] = 0; | |
| 5173 | + *((unsigned long *)str) = e; | |
| 5174 | + } | |
| 5111 | 5175 | hist_val = (u64)(uintptr_t)str; |
| 5112 | 5176 | } |
| 5113 | 5177 | tracing_map_set_var(elt, var_idx, hist_val); |
| @@ -5193,8 +5257,17 @@ static void event_hist_trigger(struct event_trigger_data *data, · 79 unmodified lines | ||
| 5193 | 5257 | |
| 5194 | 5258 | if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 5195 | 5259 | memset(entries, 0, HIST_STACKTRACE_SIZE); |
| 5196 | − stack_trace_save(entries, HIST_STACKTRACE_DEPTH, | |
| 5197 | − HIST_STACKTRACE_SKIP); | |
| 5260 | + if (key_field->field) { | |
| 5261 | + unsigned long *stack, n_entries; | |
| 5262 | + | |
| 5263 | + field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec); | |
| 5264 | + stack = (unsigned long *)(long)field_contents; | |
| 5265 | + n_entries = *stack; | |
| 5266 | + memcpy(entries, ++stack, n_entries * sizeof(unsigned long)); | |
| 5267 | + } else { | |
| 5268 | + stack_trace_save(entries, HIST_STACKTRACE_DEPTH, | |
| 5269 | + HIST_STACKTRACE_SKIP); | |
| 5270 | + } | |
| 5198 | 5271 | key = entries; |
| 5199 | 5272 | } else { |
| 5200 | 5273 | field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec); |
| @@ -5297,7 +5370,10 @@ static void hist_trigger_print_key(struct seq_file *m, · 96 unmodified lines | ||
| 5297 | 5370 | seq_printf(m, "%s: %-30s[%3llu]", field_name, |
| 5298 | 5371 | syscall_name, uval); |
| 5299 | 5372 | } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 5300 | − seq_puts(m, "stacktrace:\n"); | |
| 5373 | + if (key_field->field) | |
| 5374 | + seq_printf(m, "%s.stacktrace", key_field->field->name); | |
| 5375 | + else | |
| 5376 | + seq_puts(m, "stacktrace:\n"); | |
| 5301 | 5377 | hist_trigger_stacktrace_print(m, |
| 5302 | 5378 | key + key_field->offset, |
| 5303 | 5379 | HIST_STACKTRACE_DEPTH); |
| @@ -5842,7 +5918,8 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field) · 538 unmodified lines | ||
| 5842 | 5918 | |
| 5843 | 5919 | if (hist_field->flags) { |
| 5844 | 5920 | if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) && |
| 5845 | − !(hist_field->flags & HIST_FIELD_FL_EXPR)) { | |
| 5921 | + !(hist_field->flags & HIST_FIELD_FL_EXPR) && | |
| 5922 | + !(hist_field->flags & HIST_FIELD_FL_STACKTRACE)) { | |
| 5846 | 5923 | const char *flags = get_hist_field_flags(hist_field); |
| 5847 | 5924 | |
| 5848 | 5925 | if (flags) |
| @@ -5875,9 +5952,12 @@ static int event_hist_trigger_print(struct seq_file *m, · 26 unmodified lines | ||
| 5875 | 5952 | if (i > hist_data->n_vals) |
| 5876 | 5953 | seq_puts(m, ","); |
| 5877 | 5954 | |
| 5878 | − if (field->flags & HIST_FIELD_FL_STACKTRACE) | |
| 5879 | − seq_puts(m, "stacktrace"); | |
| 5880 | − else | |
| 5955 | + if (field->flags & HIST_FIELD_FL_STACKTRACE) { | |
| 5956 | + if (field->field) | |
| 5957 | + seq_printf(m, "%s.stacktrace", field->field->name); | |
| 5958 | + else | |
| 5959 | + seq_puts(m, "stacktrace"); | |
| 5960 | + } else | |
| 5881 | 5961 | hist_field_print(m, field); |
| 5882 | 5962 | } |
| 5883 | 5963 | |
| @@ -173,6 +173,14 @@ static int synth_field_is_string(char *type) · 172 unmodified lines | ||
| 173 | 173 | return false; |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | +static int synth_field_is_stack(char *type) | |
| 177 | +{ | |
| 178 | + if (strstr(type, "long[") != NULL) | |
| 179 | + return true; | |
| 180 | + | |
| 181 | + return false; | |
| 182 | +} | |
| 183 | + | |
| 176 | 184 | static int synth_field_string_size(char *type) |
| 177 | 185 | { |
| 178 | 186 | char buf[4], *end, *start; |
| @@ -248,6 +256,8 @@ static int synth_field_size(char *type) · 69 unmodified lines | ||
| 248 | 256 | size = sizeof(gfp_t); |
| 249 | 257 | else if (synth_field_is_string(type)) |
| 250 | 258 | size = synth_field_string_size(type); |
| 259 | + else if (synth_field_is_stack(type)) | |
| 260 | + size = 0; | |
| 251 | 261 | |
| 252 | 262 | return size; |
| 253 | 263 | } |
| @@ -292,6 +302,8 @@ static const char *synth_field_fmt(char *type) · 38 unmodified lines | ||
| 292 | 302 | fmt = "%x"; |
| 293 | 303 | else if (synth_field_is_string(type)) |
| 294 | 304 | fmt = "%.*s"; |
| 305 | + else if (synth_field_is_stack(type)) | |
| 306 | + fmt = "%s"; | |
| 295 | 307 | |
| 296 | 308 | return fmt; |
| 297 | 309 | } |
| @@ -371,6 +383,23 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, · 73 unmodified lines | ||
| 371 | 383 | i == se->n_fields - 1 ? "" : " "); |
| 372 | 384 | n_u64 += STR_VAR_LEN_MAX / sizeof(u64); |
| 373 | 385 | } |
| 386 | + } else if (se->fields[i]->is_stack) { | |
| 387 | + u32 offset, data_offset, len; | |
| 388 | + unsigned long *p, *end; | |
| 389 | + | |
| 390 | + offset = (u32)entry->fields[n_u64]; | |
| 391 | + data_offset = offset & 0xffff; | |
| 392 | + len = offset >> 16; | |
| 393 | + | |
| 394 | + p = (void *)entry + data_offset; | |
| 395 | + end = (void *)p + len - (sizeof(long) - 1); | |
| 396 | + | |
| 397 | + trace_seq_printf(s, "%s=STACK:\n", se->fields[i]->name); | |
| 398 | + | |
| 399 | + for (; *p && p < end; p++) | |
| 400 | + trace_seq_printf(s, "=> %pS\n", (void *)*p); | |
| 401 | + n_u64++; | |
| 402 | + | |
| 374 | 403 | } else { |
| 375 | 404 | struct trace_print_flags __flags[] = { |
| 376 | 405 | __def_gfpflag_names, {-1, NULL} }; |
| @@ -416,8 +445,7 @@ static unsigned int trace_string(struct synth_trace_event *entry, · 39 unmodified lines | ||
| 416 | 445 | if (is_dynamic) { |
| 417 | 446 | u32 data_offset; |
| 418 | 447 | |
| 419 | − data_offset = offsetof(typeof(*entry), fields); | |
| 420 | − data_offset += event->n_u64 * sizeof(u64); | |
| 448 | + data_offset = struct_size(entry, fields, event->n_u64); | |
| 421 | 449 | data_offset += data_size; |
| 422 | 450 | |
| 423 | 451 | len = kern_fetch_store_strlen((unsigned long)str_val); |
| @@ -447,6 +475,43 @@ static unsigned int trace_string(struct synth_trace_event *entry, · 23 unmodified lines | ||
| 447 | 475 | return len; |
| 448 | 476 | } |
| 449 | 477 | |
| 478 | +static unsigned int trace_stack(struct synth_trace_event *entry, | |
| 479 | + struct synth_event *event, | |
| 480 | + long *stack, | |
| 481 | + unsigned int data_size, | |
| 482 | + unsigned int *n_u64) | |
| 483 | +{ | |
| 484 | + unsigned int len; | |
| 485 | + u32 data_offset; | |
| 486 | + void *data_loc; | |
| 487 | + | |
| 488 | + data_offset = struct_size(entry, fields, event->n_u64); | |
| 489 | + data_offset += data_size; | |
| 490 | + | |
| 491 | + for (len = 0; len < HIST_STACKTRACE_DEPTH; len++) { | |
| 492 | + if (!stack[len]) | |
| 493 | + break; | |
| 494 | + } | |
| 495 | + | |
| 496 | + /* Include the zero'd element if it fits */ | |
| 497 | + if (len < HIST_STACKTRACE_DEPTH) | |
| 498 | + len++; | |
| 499 | + | |
| 500 | + len *= sizeof(long); | |
| 501 | + | |
| 502 | + /* Find the dynamic section to copy the stack into. */ | |
| 503 | + data_loc = (void *)entry + data_offset; | |
| 504 | + memcpy(data_loc, stack, len); | |
| 505 | + | |
| 506 | + /* Fill in the field that holds the offset/len combo */ | |
| 507 | + data_offset |= len << 16; | |
| 508 | + *(u32 *)&entry->fields[*n_u64] = data_offset; | |
| 509 | + | |
| 510 | + (*n_u64)++; | |
| 511 | + | |
| 512 | + return len; | |
| 513 | +} | |
| 514 | + | |
| 450 | 515 | static notrace void trace_event_raw_event_synth(void *__data, |
| 451 | 516 | u64 *var_ref_vals, |
| 452 | 517 | unsigned int *var_ref_idx) |
| @@ -473,7 +538,12 @@ static notrace void trace_event_raw_event_synth(void *__data, · 20 unmodified lines | ||
| 473 | 538 | val_idx = var_ref_idx[field_pos]; |
| 474 | 539 | str_val = (char *)(long)var_ref_vals[val_idx]; |
| 475 | 540 | |
| 476 | − len = kern_fetch_store_strlen((unsigned long)str_val); | |
| 541 | + if (event->dynamic_fields[i]->is_stack) { | |
| 542 | + len = *((unsigned long *)str_val); | |
| 543 | + len *= sizeof(unsigned long); | |
| 544 | + } else { | |
| 545 | + len = kern_fetch_store_strlen((unsigned long)str_val); | |
| 546 | + } | |
| 477 | 547 | |
| 478 | 548 | fields_size += len; |
| 479 | 549 | } |
| @@ -499,6 +569,12 @@ static notrace void trace_event_raw_event_synth(void *__data, · 19 unmodified lines | ||
| 499 | 569 | event->fields[i]->is_dynamic, |
| 500 | 570 | data_size, &n_u64); |
| 501 | 571 | data_size += len; /* only dynamic string increments */ |
| 572 | + } else if (event->fields[i]->is_stack) { | |
| 573 | + long *stack = (long *)(long)var_ref_vals[val_idx]; | |
| 574 | + | |
| 575 | + len = trace_stack(entry, event, stack, | |
| 576 | + data_size, &n_u64); | |
| 577 | + data_size += len; | |
| 502 | 578 | } else { |
| 503 | 579 | struct synth_field *field = event->fields[i]; |
| 504 | 580 | u64 val = var_ref_vals[val_idx]; |
| @@ -561,6 +637,9 @@ static int __set_synth_event_print_fmt(struct synth_event *event, · 56 unmodified lines | ||
| 561 | 637 | event->fields[i]->is_dynamic) |
| 562 | 638 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
| 563 | 639 | ", __get_str(%s)", event->fields[i]->name); |
| 640 | + else if (event->fields[i]->is_stack) | |
| 641 | + pos += snprintf(buf + pos, LEN_OR_ZERO, | |
| 642 | + ", __get_stacktrace(%s)", event->fields[i]->name); | |
| 564 | 643 | else |
| 565 | 644 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
| 566 | 645 | ", REC->%s", event->fields[i]->name); |
| @@ -697,7 +776,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv, · 130 unmodified lines | ||
| 697 | 776 | ret = -EINVAL; |
| 698 | 777 | goto free; |
| 699 | 778 | } else if (size == 0) { |
| 700 | − if (synth_field_is_string(field->type)) { | |
| 779 | + if (synth_field_is_string(field->type) || | |
| 780 | + synth_field_is_stack(field->type)) { | |
| 701 | 781 | char *type; |
| 702 | 782 | |
| 703 | 783 | len = sizeof("__data_loc ") + strlen(field->type) + 1; |
| @@ -728,6 +808,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv, · 24 unmodified lines | ||
| 728 | 808 | |
| 729 | 809 | if (synth_field_is_string(field->type)) |
| 730 | 810 | field->is_string = true; |
| 811 | + else if (synth_field_is_stack(field->type)) | |
| 812 | + field->is_stack = true; | |
| 731 | 813 | |
| 732 | 814 | field->is_signed = synth_field_signed(field->type); |
| 733 | 815 | out: |
| @@ -1539,7 +1539,7 @@ static void osnoise_sleep(void) · 1538 unmodified lines | ||
| 1539 | 1539 | wake_time = ktime_add_us(ktime_get(), interval); |
| 1540 | 1540 | __set_current_state(TASK_INTERRUPTIBLE); |
| 1541 | 1541 | |
| 1542 | − while (schedule_hrtimeout_range(&wake_time, 0, HRTIMER_MODE_ABS)) { | |
| 1542 | + while (schedule_hrtimeout(&wake_time, HRTIMER_MODE_ABS)) { | |
| 1543 | 1543 | if (kthread_should_stop()) |
| 1544 | 1544 | break; |
| 1545 | 1545 | } |
| @@ -403,3 +403,26 @@ int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str, · 402 unmodified lines | ||
| 403 | 403 | return 1; |
| 404 | 404 | } |
| 405 | 405 | EXPORT_SYMBOL(trace_seq_hex_dump); |
| 406 | + | |
| 407 | +/* | |
| 408 | + * trace_seq_acquire - acquire seq buffer with size len | |
| 409 | + * @s: trace sequence descriptor | |
| 410 | + * @len: size of buffer to be acquired | |
| 411 | + * | |
| 412 | + * acquire buffer with size of @len from trace_seq for output usage, | |
| 413 | + * user can fill string into that buffer. | |
| 414 | + * | |
| 415 | + * Returns start address of acquired buffer. | |
| 416 | + * | |
| 417 | + * it allow multiple usage in one trace output function call. | |
| 418 | + */ | |
| 419 | +char *trace_seq_acquire(struct trace_seq *s, unsigned int len) | |
| 420 | +{ | |
| 421 | + char *ret = trace_seq_buffer_ptr(s); | |
| 422 | + | |
| 423 | + if (!WARN_ON_ONCE(seq_buf_buffer_left(&s->seq) < len)) | |
| 424 | + seq_buf_commit(&s->seq, len); | |
| 425 | + | |
| 426 | + return ret; | |
| 427 | +} | |
| 428 | +EXPORT_SYMBOL(trace_seq_acquire); | |
| @@ -18,6 +18,7 @@ struct synth_field { · 17 unmodified lines | ||
| 18 | 18 | bool is_signed; |
| 19 | 19 | bool is_string; |
| 20 | 20 | bool is_dynamic; |
| 21 | + bool is_stack; | |
| 21 | 22 | }; |
| 22 | 23 | |
| 23 | 24 | struct synth_event { |
| @@ -571,8 +571,8 @@ static void for_each_tracepoint_range( · 570 unmodified lines | ||
| 571 | 571 | bool trace_module_has_bad_taint(struct module *mod) |
| 572 | 572 | { |
| 573 | 573 | return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | |
| 574 | − (1 << TAINT_UNSIGNED_MODULE) | | |
| 575 | − (1 << TAINT_TEST)); | |
| 574 | + (1 << TAINT_UNSIGNED_MODULE) | (1 << TAINT_TEST) | | |
| 575 | + (1 << TAINT_LIVEPATCH)); | |
| 576 | 576 | } |
| 577 | 577 | |
| 578 | 578 | static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); |