aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c275
1 files changed, 1 insertions, 274 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index fca0233f1d73..90ce0c1d437b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -38,6 +38,7 @@
38#include <linux/irqflags.h> 38#include <linux/irqflags.h>
39 39
40#include "trace.h" 40#include "trace.h"
41#include "trace_output.h"
41 42
42#define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE) 43#define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE)
43 44
@@ -330,132 +331,6 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
330 tracing_record_cmdline(current); 331 tracing_record_cmdline(current);
331} 332}
332 333
333/**
334 * trace_seq_printf - sequence printing of trace information
335 * @s: trace sequence descriptor
336 * @fmt: printf format string
337 *
338 * The tracer may use either sequence operations or its own
339 * copy to user routines. To simplify formating of a trace
340 * trace_seq_printf is used to store strings into a special
341 * buffer (@s). Then the output may be either used by
342 * the sequencer or pulled into another buffer.
343 */
344int
345trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
346{
347 int len = (PAGE_SIZE - 1) - s->len;
348 va_list ap;
349 int ret;
350
351 if (!len)
352 return 0;
353
354 va_start(ap, fmt);
355 ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
356 va_end(ap);
357
358 /* If we can't write it all, don't bother writing anything */
359 if (ret >= len)
360 return 0;
361
362 s->len += ret;
363
364 return len;
365}
366
367/**
368 * trace_seq_puts - trace sequence printing of simple string
369 * @s: trace sequence descriptor
370 * @str: simple string to record
371 *
372 * The tracer may use either the sequence operations or its own
373 * copy to user routines. This function records a simple string
374 * into a special buffer (@s) for later retrieval by a sequencer
375 * or other mechanism.
376 */
377static int
378trace_seq_puts(struct trace_seq *s, const char *str)
379{
380 int len = strlen(str);
381
382 if (len > ((PAGE_SIZE - 1) - s->len))
383 return 0;
384
385 memcpy(s->buffer + s->len, str, len);
386 s->len += len;
387
388 return len;
389}
390
391static int
392trace_seq_putc(struct trace_seq *s, unsigned char c)
393{
394 if (s->len >= (PAGE_SIZE - 1))
395 return 0;
396
397 s->buffer[s->len++] = c;
398
399 return 1;
400}
401
402static int
403trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
404{
405 if (len > ((PAGE_SIZE - 1) - s->len))
406 return 0;
407
408 memcpy(s->buffer + s->len, mem, len);
409 s->len += len;
410
411 return len;
412}
413
414#define MAX_MEMHEX_BYTES 8
415#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
416
417static int
418trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
419{
420 unsigned char hex[HEX_CHARS];
421 unsigned char *data = mem;
422 int i, j;
423
424#ifdef __BIG_ENDIAN
425 for (i = 0, j = 0; i < len; i++) {
426#else
427 for (i = len-1, j = 0; i >= 0; i--) {
428#endif
429 hex[j++] = hex_asc_hi(data[i]);
430 hex[j++] = hex_asc_lo(data[i]);
431 }
432 hex[j++] = ' ';
433
434 return trace_seq_putmem(s, hex, j);
435}
436
437static int
438trace_seq_path(struct trace_seq *s, struct path *path)
439{
440 unsigned char *p;
441
442 if (s->len >= (PAGE_SIZE - 1))
443 return 0;
444 p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
445 if (!IS_ERR(p)) {
446 p = mangle_path(s->buffer + s->len, p, "\n");
447 if (p) {
448 s->len = p - s->buffer;
449 return 1;
450 }
451 } else {
452 s->buffer[s->len++] = '?';
453 return 1;
454 }
455
456 return 0;
457}
458
459static void 334static void
460trace_seq_reset(struct trace_seq *s) 335trace_seq_reset(struct trace_seq *s)
461{ 336{
@@ -1473,154 +1348,6 @@ static void s_stop(struct seq_file *m, void *p)
1473 mutex_unlock(&trace_types_lock); 1348 mutex_unlock(&trace_types_lock);
1474} 1349}
1475 1350
1476#ifdef CONFIG_KRETPROBES
1477static inline const char *kretprobed(const char *name)
1478{
1479 static const char tramp_name[] = "kretprobe_trampoline";
1480 int size = sizeof(tramp_name);
1481
1482 if (strncmp(tramp_name, name, size) == 0)
1483 return "[unknown/kretprobe'd]";
1484 return name;
1485}
1486#else
1487static inline const char *kretprobed(const char *name)
1488{
1489 return name;
1490}
1491#endif /* CONFIG_KRETPROBES */
1492
1493static int
1494seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
1495{
1496#ifdef CONFIG_KALLSYMS
1497 char str[KSYM_SYMBOL_LEN];
1498 const char *name;
1499
1500 kallsyms_lookup(address, NULL, NULL, NULL, str);
1501
1502 name = kretprobed(str);
1503
1504 return trace_seq_printf(s, fmt, name);
1505#endif
1506 return 1;
1507}
1508
1509static int
1510seq_print_sym_offset(struct trace_seq *s, const char *fmt,
1511 unsigned long address)
1512{
1513#ifdef CONFIG_KALLSYMS
1514 char str[KSYM_SYMBOL_LEN];
1515 const char *name;
1516
1517 sprint_symbol(str, address);
1518 name = kretprobed(str);
1519
1520 return trace_seq_printf(s, fmt, name);
1521#endif
1522 return 1;
1523}
1524
1525#ifndef CONFIG_64BIT
1526# define IP_FMT "%08lx"
1527#else
1528# define IP_FMT "%016lx"
1529#endif
1530
1531int
1532seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
1533{
1534 int ret;
1535
1536 if (!ip)
1537 return trace_seq_printf(s, "0");
1538
1539 if (sym_flags & TRACE_ITER_SYM_OFFSET)
1540 ret = seq_print_sym_offset(s, "%s", ip);
1541 else
1542 ret = seq_print_sym_short(s, "%s", ip);
1543
1544 if (!ret)
1545 return 0;
1546
1547 if (sym_flags & TRACE_ITER_SYM_ADDR)
1548 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
1549 return ret;
1550}
1551
1552static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
1553 unsigned long ip, unsigned long sym_flags)
1554{
1555 struct file *file = NULL;
1556 unsigned long vmstart = 0;
1557 int ret = 1;
1558
1559 if (mm) {
1560 const struct vm_area_struct *vma;
1561
1562 down_read(&mm->mmap_sem);
1563 vma = find_vma(mm, ip);
1564 if (vma) {
1565 file = vma->vm_file;
1566 vmstart = vma->vm_start;
1567 }
1568 if (file) {
1569 ret = trace_seq_path(s, &file->f_path);
1570 if (ret)
1571 ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart);
1572 }
1573 up_read(&mm->mmap_sem);
1574 }
1575 if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
1576 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
1577 return ret;
1578}
1579
1580static int
1581seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
1582 unsigned long sym_flags)
1583{
1584 struct mm_struct *mm = NULL;
1585 int ret = 1;
1586 unsigned int i;
1587
1588 if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
1589 struct task_struct *task;
1590 /*
1591 * we do the lookup on the thread group leader,
1592 * since individual threads might have already quit!
1593 */
1594 rcu_read_lock();
1595 task = find_task_by_vpid(entry->ent.tgid);
1596 if (task)
1597 mm = get_task_mm(task);
1598 rcu_read_unlock();
1599 }
1600
1601 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
1602 unsigned long ip = entry->caller[i];
1603
1604 if (ip == ULONG_MAX || !ret)
1605 break;
1606 if (i && ret)
1607 ret = trace_seq_puts(s, " <- ");
1608 if (!ip) {
1609 if (ret)
1610 ret = trace_seq_puts(s, "??");
1611 continue;
1612 }
1613 if (!ret)
1614 break;
1615 if (ret)
1616 ret = seq_print_user_ip(s, mm, ip, sym_flags);
1617 }
1618
1619 if (mm)
1620 mmput(mm);
1621 return ret;
1622}
1623
1624static void print_lat_help_header(struct seq_file *m) 1351static void print_lat_help_header(struct seq_file *m)
1625{ 1352{
1626 seq_puts(m, "# _------=> CPU# \n"); 1353 seq_puts(m, "# _------=> CPU# \n");