diff options
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4ee6f0375222..a45b59e53fbc 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/gfp.h> | 30 | #include <linux/gfp.h> |
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/kprobes.h> | 32 | #include <linux/kprobes.h> |
33 | #include <linux/seq_file.h> | ||
33 | #include <linux/writeback.h> | 34 | #include <linux/writeback.h> |
34 | 35 | ||
35 | #include <linux/stacktrace.h> | 36 | #include <linux/stacktrace.h> |
@@ -275,6 +276,8 @@ static const char *trace_options[] = { | |||
275 | "ftrace_preempt", | 276 | "ftrace_preempt", |
276 | "branch", | 277 | "branch", |
277 | "annotate", | 278 | "annotate", |
279 | "userstacktrace", | ||
280 | "sym-userobj", | ||
278 | NULL | 281 | NULL |
279 | }; | 282 | }; |
280 | 283 | ||
@@ -421,6 +424,28 @@ trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len) | |||
421 | return trace_seq_putmem(s, hex, j); | 424 | return trace_seq_putmem(s, hex, j); |
422 | } | 425 | } |
423 | 426 | ||
427 | static int | ||
428 | trace_seq_path(struct trace_seq *s, struct path *path) | ||
429 | { | ||
430 | unsigned char *p; | ||
431 | |||
432 | if (s->len >= (PAGE_SIZE - 1)) | ||
433 | return 0; | ||
434 | p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len); | ||
435 | if (!IS_ERR(p)) { | ||
436 | p = mangle_path(s->buffer + s->len, p, "\n"); | ||
437 | if (p) { | ||
438 | s->len = p - s->buffer; | ||
439 | return 1; | ||
440 | } | ||
441 | } else { | ||
442 | s->buffer[s->len++] = '?'; | ||
443 | return 1; | ||
444 | } | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
424 | static void | 449 | static void |
425 | trace_seq_reset(struct trace_seq *s) | 450 | trace_seq_reset(struct trace_seq *s) |
426 | { | 451 | { |
@@ -661,6 +686,21 @@ static int trace_stop_count; | |||
661 | static DEFINE_SPINLOCK(tracing_start_lock); | 686 | static DEFINE_SPINLOCK(tracing_start_lock); |
662 | 687 | ||
663 | /** | 688 | /** |
689 | * ftrace_off_permanent - disable all ftrace code permanently | ||
690 | * | ||
691 | * This should only be called when a serious anomally has | ||
692 | * been detected. This will turn off the function tracing, | ||
693 | * ring buffers, and other tracing utilites. It takes no | ||
694 | * locks and can be called from any context. | ||
695 | */ | ||
696 | void ftrace_off_permanent(void) | ||
697 | { | ||
698 | tracing_disabled = 1; | ||
699 | ftrace_stop(); | ||
700 | tracing_off_permanent(); | ||
701 | } | ||
702 | |||
703 | /** | ||
664 | * tracing_start - quick start of the tracer | 704 | * tracing_start - quick start of the tracer |
665 | * | 705 | * |
666 | * If tracing is enabled but was stopped by tracing_stop, | 706 | * If tracing is enabled but was stopped by tracing_stop, |
@@ -801,6 +841,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, | |||
801 | 841 | ||
802 | entry->preempt_count = pc & 0xff; | 842 | entry->preempt_count = pc & 0xff; |
803 | entry->pid = (tsk) ? tsk->pid : 0; | 843 | entry->pid = (tsk) ? tsk->pid : 0; |
844 | entry->tgid = (tsk) ? tsk->tgid : 0; | ||
804 | entry->flags = | 845 | entry->flags = |
805 | #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT | 846 | #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT |
806 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | | 847 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | |
@@ -918,6 +959,44 @@ void __trace_stack(struct trace_array *tr, | |||
918 | ftrace_trace_stack(tr, data, flags, skip, preempt_count()); | 959 | ftrace_trace_stack(tr, data, flags, skip, preempt_count()); |
919 | } | 960 | } |
920 | 961 | ||
962 | static void ftrace_trace_userstack(struct trace_array *tr, | ||
963 | struct trace_array_cpu *data, | ||
964 | unsigned long flags, int pc) | ||
965 | { | ||
966 | struct ring_buffer_event *event; | ||
967 | struct userstack_entry *entry; | ||
968 | struct stack_trace trace; | ||
969 | unsigned long irq_flags; | ||
970 | |||
971 | if (!(trace_flags & TRACE_ITER_USERSTACKTRACE)) | ||
972 | return; | ||
973 | |||
974 | event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), | ||
975 | &irq_flags); | ||
976 | if (!event) | ||
977 | return; | ||
978 | entry = ring_buffer_event_data(event); | ||
979 | tracing_generic_entry_update(&entry->ent, flags, pc); | ||
980 | entry->ent.type = TRACE_USER_STACK; | ||
981 | |||
982 | memset(&entry->caller, 0, sizeof(entry->caller)); | ||
983 | |||
984 | trace.nr_entries = 0; | ||
985 | trace.max_entries = FTRACE_STACK_ENTRIES; | ||
986 | trace.skip = 0; | ||
987 | trace.entries = entry->caller; | ||
988 | |||
989 | save_stack_trace_user(&trace); | ||
990 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | ||
991 | } | ||
992 | |||
993 | void __trace_userstack(struct trace_array *tr, | ||
994 | struct trace_array_cpu *data, | ||
995 | unsigned long flags) | ||
996 | { | ||
997 | ftrace_trace_userstack(tr, data, flags, preempt_count()); | ||
998 | } | ||
999 | |||
921 | static void | 1000 | static void |
922 | ftrace_trace_special(void *__tr, void *__data, | 1001 | ftrace_trace_special(void *__tr, void *__data, |
923 | unsigned long arg1, unsigned long arg2, unsigned long arg3, | 1002 | unsigned long arg1, unsigned long arg2, unsigned long arg3, |
@@ -941,6 +1020,7 @@ ftrace_trace_special(void *__tr, void *__data, | |||
941 | entry->arg3 = arg3; | 1020 | entry->arg3 = arg3; |
942 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | 1021 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); |
943 | ftrace_trace_stack(tr, data, irq_flags, 4, pc); | 1022 | ftrace_trace_stack(tr, data, irq_flags, 4, pc); |
1023 | ftrace_trace_userstack(tr, data, irq_flags, pc); | ||
944 | 1024 | ||
945 | trace_wake_up(); | 1025 | trace_wake_up(); |
946 | } | 1026 | } |
@@ -979,6 +1059,7 @@ tracing_sched_switch_trace(struct trace_array *tr, | |||
979 | entry->next_cpu = task_cpu(next); | 1059 | entry->next_cpu = task_cpu(next); |
980 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | 1060 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); |
981 | ftrace_trace_stack(tr, data, flags, 5, pc); | 1061 | ftrace_trace_stack(tr, data, flags, 5, pc); |
1062 | ftrace_trace_userstack(tr, data, flags, pc); | ||
982 | } | 1063 | } |
983 | 1064 | ||
984 | void | 1065 | void |
@@ -1008,6 +1089,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr, | |||
1008 | entry->next_cpu = task_cpu(wakee); | 1089 | entry->next_cpu = task_cpu(wakee); |
1009 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | 1090 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); |
1010 | ftrace_trace_stack(tr, data, flags, 6, pc); | 1091 | ftrace_trace_stack(tr, data, flags, 6, pc); |
1092 | ftrace_trace_userstack(tr, data, flags, pc); | ||
1011 | 1093 | ||
1012 | trace_wake_up(); | 1094 | trace_wake_up(); |
1013 | } | 1095 | } |
@@ -1387,6 +1469,78 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags) | |||
1387 | return ret; | 1469 | return ret; |
1388 | } | 1470 | } |
1389 | 1471 | ||
1472 | static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, | ||
1473 | unsigned long ip, unsigned long sym_flags) | ||
1474 | { | ||
1475 | struct file *file = NULL; | ||
1476 | unsigned long vmstart = 0; | ||
1477 | int ret = 1; | ||
1478 | |||
1479 | if (mm) { | ||
1480 | const struct vm_area_struct *vma; | ||
1481 | |||
1482 | down_read(&mm->mmap_sem); | ||
1483 | vma = find_vma(mm, ip); | ||
1484 | if (vma) { | ||
1485 | file = vma->vm_file; | ||
1486 | vmstart = vma->vm_start; | ||
1487 | } | ||
1488 | if (file) { | ||
1489 | ret = trace_seq_path(s, &file->f_path); | ||
1490 | if (ret) | ||
1491 | ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart); | ||
1492 | } | ||
1493 | up_read(&mm->mmap_sem); | ||
1494 | } | ||
1495 | if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file)) | ||
1496 | ret = trace_seq_printf(s, " <" IP_FMT ">", ip); | ||
1497 | return ret; | ||
1498 | } | ||
1499 | |||
1500 | static int | ||
1501 | seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, | ||
1502 | unsigned long sym_flags) | ||
1503 | { | ||
1504 | struct mm_struct *mm = NULL; | ||
1505 | int ret = 1; | ||
1506 | unsigned int i; | ||
1507 | |||
1508 | if (trace_flags & TRACE_ITER_SYM_USEROBJ) { | ||
1509 | struct task_struct *task; | ||
1510 | /* | ||
1511 | * we do the lookup on the thread group leader, | ||
1512 | * since individual threads might have already quit! | ||
1513 | */ | ||
1514 | rcu_read_lock(); | ||
1515 | task = find_task_by_vpid(entry->ent.tgid); | ||
1516 | if (task) | ||
1517 | mm = get_task_mm(task); | ||
1518 | rcu_read_unlock(); | ||
1519 | } | ||
1520 | |||
1521 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { | ||
1522 | unsigned long ip = entry->caller[i]; | ||
1523 | |||
1524 | if (ip == ULONG_MAX || !ret) | ||
1525 | break; | ||
1526 | if (i && ret) | ||
1527 | ret = trace_seq_puts(s, " <- "); | ||
1528 | if (!ip) { | ||
1529 | if (ret) | ||
1530 | ret = trace_seq_puts(s, "??"); | ||
1531 | continue; | ||
1532 | } | ||
1533 | if (!ret) | ||
1534 | break; | ||
1535 | if (ret) | ||
1536 | ret = seq_print_user_ip(s, mm, ip, sym_flags); | ||
1537 | } | ||
1538 | |||
1539 | if (mm) | ||
1540 | mmput(mm); | ||
1541 | return ret; | ||
1542 | } | ||
1543 | |||
1390 | static void print_lat_help_header(struct seq_file *m) | 1544 | static void print_lat_help_header(struct seq_file *m) |
1391 | { | 1545 | { |
1392 | seq_puts(m, "# _------=> CPU# \n"); | 1546 | seq_puts(m, "# _------=> CPU# \n"); |
@@ -1702,6 +1856,15 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
1702 | field->line); | 1856 | field->line); |
1703 | break; | 1857 | break; |
1704 | } | 1858 | } |
1859 | case TRACE_USER_STACK: { | ||
1860 | struct userstack_entry *field; | ||
1861 | |||
1862 | trace_assign_type(field, entry); | ||
1863 | |||
1864 | seq_print_userip_objs(field, s, sym_flags); | ||
1865 | trace_seq_putc(s, '\n'); | ||
1866 | break; | ||
1867 | } | ||
1705 | default: | 1868 | default: |
1706 | trace_seq_printf(s, "Unknown type %d\n", entry->type); | 1869 | trace_seq_printf(s, "Unknown type %d\n", entry->type); |
1707 | } | 1870 | } |
@@ -1853,6 +2016,19 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter) | |||
1853 | field->line); | 2016 | field->line); |
1854 | break; | 2017 | break; |
1855 | } | 2018 | } |
2019 | case TRACE_USER_STACK: { | ||
2020 | struct userstack_entry *field; | ||
2021 | |||
2022 | trace_assign_type(field, entry); | ||
2023 | |||
2024 | ret = seq_print_userip_objs(field, s, sym_flags); | ||
2025 | if (!ret) | ||
2026 | return TRACE_TYPE_PARTIAL_LINE; | ||
2027 | ret = trace_seq_putc(s, '\n'); | ||
2028 | if (!ret) | ||
2029 | return TRACE_TYPE_PARTIAL_LINE; | ||
2030 | break; | ||
2031 | } | ||
1856 | } | 2032 | } |
1857 | return TRACE_TYPE_HANDLED; | 2033 | return TRACE_TYPE_HANDLED; |
1858 | } | 2034 | } |
@@ -1912,6 +2088,7 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter) | |||
1912 | break; | 2088 | break; |
1913 | } | 2089 | } |
1914 | case TRACE_SPECIAL: | 2090 | case TRACE_SPECIAL: |
2091 | case TRACE_USER_STACK: | ||
1915 | case TRACE_STACK: { | 2092 | case TRACE_STACK: { |
1916 | struct special_entry *field; | 2093 | struct special_entry *field; |
1917 | 2094 | ||
@@ -2000,6 +2177,7 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter) | |||
2000 | break; | 2177 | break; |
2001 | } | 2178 | } |
2002 | case TRACE_SPECIAL: | 2179 | case TRACE_SPECIAL: |
2180 | case TRACE_USER_STACK: | ||
2003 | case TRACE_STACK: { | 2181 | case TRACE_STACK: { |
2004 | struct special_entry *field; | 2182 | struct special_entry *field; |
2005 | 2183 | ||
@@ -2054,6 +2232,7 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | |||
2054 | break; | 2232 | break; |
2055 | } | 2233 | } |
2056 | case TRACE_SPECIAL: | 2234 | case TRACE_SPECIAL: |
2235 | case TRACE_USER_STACK: | ||
2057 | case TRACE_STACK: { | 2236 | case TRACE_STACK: { |
2058 | struct special_entry *field; | 2237 | struct special_entry *field; |
2059 | 2238 | ||
@@ -3488,6 +3667,9 @@ void ftrace_dump(void) | |||
3488 | atomic_inc(&global_trace.data[cpu]->disabled); | 3667 | atomic_inc(&global_trace.data[cpu]->disabled); |
3489 | } | 3668 | } |
3490 | 3669 | ||
3670 | /* don't look at user memory in panic mode */ | ||
3671 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; | ||
3672 | |||
3491 | printk(KERN_TRACE "Dumping ftrace buffer:\n"); | 3673 | printk(KERN_TRACE "Dumping ftrace buffer:\n"); |
3492 | 3674 | ||
3493 | iter.tr = &global_trace; | 3675 | iter.tr = &global_trace; |