aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace.c86
-rw-r--r--kernel/trace/trace.h3
2 files changed, 81 insertions, 8 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index ced8b4fa9f51..62776b71b1c5 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>
@@ -276,6 +277,7 @@ static const char *trace_options[] = {
276 "branch", 277 "branch",
277 "annotate", 278 "annotate",
278 "userstacktrace", 279 "userstacktrace",
280 "sym-userobj",
279 NULL 281 NULL
280}; 282};
281 283
@@ -422,6 +424,28 @@ trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
422 return trace_seq_putmem(s, hex, j); 424 return trace_seq_putmem(s, hex, j);
423} 425}
424 426
427static int
428trace_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
425static void 449static void
426trace_seq_reset(struct trace_seq *s) 450trace_seq_reset(struct trace_seq *s)
427{ 451{
@@ -802,6 +826,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
802 826
803 entry->preempt_count = pc & 0xff; 827 entry->preempt_count = pc & 0xff;
804 entry->pid = (tsk) ? tsk->pid : 0; 828 entry->pid = (tsk) ? tsk->pid : 0;
829 entry->tgid = (tsk) ? tsk->tgid : 0;
805 entry->flags = 830 entry->flags =
806#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT 831#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
807 (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | 832 (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -1429,28 +1454,73 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
1429 return ret; 1454 return ret;
1430} 1455}
1431 1456
1457static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
1458 unsigned long ip, unsigned long sym_flags)
1459{
1460 struct file *file = NULL;
1461 unsigned long vmstart = 0;
1462 int ret = 1;
1463
1464 if (mm) {
1465 const struct vm_area_struct *vma = find_vma(mm, ip);
1466 if (vma) {
1467 file = vma->vm_file;
1468 vmstart = vma->vm_start;
1469 }
1470 }
1471 if (file) {
1472 ret = trace_seq_path(s, &file->f_path);
1473 if (ret)
1474 ret = trace_seq_printf(s, "[+0x%lx]",
1475 ip - vmstart);
1476 }
1477 if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
1478 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
1479 return ret;
1480}
1481
1432static int 1482static int
1433seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, 1483seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
1434 unsigned long sym_flags) 1484 unsigned long sym_flags)
1435{ 1485{
1486 struct mm_struct *mm = NULL;
1436 int ret = 1; 1487 int ret = 1;
1437 unsigned i; 1488 unsigned i;
1438 1489
1490 if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
1491 struct task_struct *task;
1492 /*
1493 * we do the lookup on the thread group leader,
1494 * since individual threads might have already quit!
1495 */
1496 rcu_read_lock();
1497 task = find_task_by_vpid(entry->ent.tgid);
1498 rcu_read_unlock();
1499
1500 if (task)
1501 mm = get_task_mm(task);
1502 }
1503
1439 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { 1504 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
1440 unsigned long ip = entry->caller[i]; 1505 unsigned long ip = entry->caller[i];
1441 1506
1442 if (ip == ULONG_MAX || !ret) 1507 if (ip == ULONG_MAX || !ret)
1443 break; 1508 break;
1444 if (i) 1509 if (i && ret)
1445 ret = trace_seq_puts(s, " <- "); 1510 ret = trace_seq_puts(s, " <- ");
1446 if (!ip) { 1511 if (!ip) {
1447 ret = trace_seq_puts(s, "??"); 1512 if (ret)
1513 ret = trace_seq_puts(s, "??");
1448 continue; 1514 continue;
1449 } 1515 }
1450 if (ret /*&& (sym_flags & TRACE_ITER_SYM_ADDR)*/) 1516 if (!ret)
1451 ret = trace_seq_printf(s, " <" IP_FMT ">", ip); 1517 break;
1518 if (ret)
1519 ret = seq_print_user_ip(s, mm, ip, sym_flags);
1452 } 1520 }
1453 1521
1522 if (mm)
1523 mmput(mm);
1454 return ret; 1524 return ret;
1455} 1525}
1456 1526
@@ -1775,8 +1845,7 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1775 trace_assign_type(field, entry); 1845 trace_assign_type(field, entry);
1776 1846
1777 seq_print_userip_objs(field, s, sym_flags); 1847 seq_print_userip_objs(field, s, sym_flags);
1778 if (entry->flags & TRACE_FLAG_CONT) 1848 trace_seq_putc(s, '\n');
1779 trace_seq_print_cont(s, iter);
1780 break; 1849 break;
1781 } 1850 }
1782 default: 1851 default:
@@ -3581,6 +3650,9 @@ void ftrace_dump(void)
3581 atomic_inc(&global_trace.data[cpu]->disabled); 3650 atomic_inc(&global_trace.data[cpu]->disabled);
3582 } 3651 }
3583 3652
3653 /* don't look at user memory in panic mode */
3654 trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
3655
3584 printk(KERN_TRACE "Dumping ftrace buffer:\n"); 3656 printk(KERN_TRACE "Dumping ftrace buffer:\n");
3585 3657
3586 iter.tr = &global_trace; 3658 iter.tr = &global_trace;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 17bb4c830b01..28c15c2ebc22 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -508,7 +508,8 @@ enum trace_iterator_flags {
508 TRACE_ITER_PREEMPTONLY = 0x800, 508 TRACE_ITER_PREEMPTONLY = 0x800,
509 TRACE_ITER_BRANCH = 0x1000, 509 TRACE_ITER_BRANCH = 0x1000,
510 TRACE_ITER_ANNOTATE = 0x2000, 510 TRACE_ITER_ANNOTATE = 0x2000,
511 TRACE_ITER_USERSTACKTRACE = 0x4000 511 TRACE_ITER_USERSTACKTRACE = 0x4000,
512 TRACE_ITER_SYM_USEROBJ = 0x8000
512}; 513};
513 514
514/* 515/*