aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTörök Edwin <edwintorok@gmail.com>2008-11-22 06:28:48 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-23 03:45:42 -0500
commitb54d3de9f3b8956653b06f1a32e9f9321c6d9027 (patch)
treefef98e07a9327371304811191cafebdd65311502
parent74e2f334f4440cbcb63e9ebbcdcea430d41bdfa3 (diff)
tracing: identify which executable object the userspace address belongs to
Impact: modify+improve the userstacktrace tracing visualization feature Store thread group leader id, and use it to lookup the address in the process's map. We could have looked up the address on thread's map, but the thread might not exist by the time we are called. The process might not exist either, but if you are reading trace_pipe, that is unlikely. Example usage: mount -t debugfs nodev /sys/kernel/debug cd /sys/kernel/debug/tracing echo userstacktrace >iter_ctrl echo sym-userobj >iter_ctrl echo sched_switch >current_tracer echo 1 >tracing_enabled cat trace_pipe >/tmp/trace& .... run application ... echo 0 >tracing_enabled cat /tmp/trace You'll see stack entries like: /lib/libpthread-2.7.so[+0xd370] You can convert them to function/line using: addr2line -fie /lib/libpthread-2.7.so 0xd370 Or: addr2line -fie /usr/lib/debug/libpthread-2.7.so 0xd370 For non-PIC/PIE executables this won't work: a.out[+0x73b] You need to run the following: addr2line -fie a.out 0x40073b (where 0x400000 is the default load address of a.out) Signed-off-by: Török Edwin <edwintorok@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--Documentation/ftrace.txt13
-rw-r--r--kernel/trace/trace.c86
-rw-r--r--kernel/trace/trace.h3
3 files changed, 93 insertions, 9 deletions
diff --git a/Documentation/ftrace.txt b/Documentation/ftrace.txt
index 79a80f79c062..35a78bc6651d 100644
--- a/Documentation/ftrace.txt
+++ b/Documentation/ftrace.txt
@@ -324,7 +324,7 @@ output. To see what is available, simply cat the file:
324 324
325 cat /debug/tracing/trace_options 325 cat /debug/tracing/trace_options
326 print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ 326 print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
327 noblock nostacktrace nosched-tree nouserstacktrace 327 noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
328 328
329To disable one of the options, echo in the option prepended with "no". 329To disable one of the options, echo in the option prepended with "no".
330 330
@@ -381,6 +381,17 @@ Here are the available options:
381 userstacktrace - This option changes the trace. 381 userstacktrace - This option changes the trace.
382 It records a stacktrace of the current userspace thread. 382 It records a stacktrace of the current userspace thread.
383 383
384 sym-userobj - when user stacktrace are enabled, look up which object the
385 address belongs to, and print a relative address
386 This is especially useful when ASLR is on, otherwise you don't
387 get a chance to resolve the address to object/file/line after the app is no
388 longer running
389
390 The lookup is performed when you read trace,trace_pipe,latency_trace. Example:
391
392 a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
393x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
394
384 sched-tree - TBD (any users??) 395 sched-tree - TBD (any users??)
385 396
386 397
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/*