aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-12-23 23:24:12 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-29 06:46:11 -0500
commitf0868d1e23a8efec33beb3aa688aab7fdb1ae093 (patch)
tree73593e14d0d127fe3fe055a85b6e16b50a43578a /kernel/trace/trace.c
parentc47956d9ae3341d2d1998bff26620fa3338c01e4 (diff)
ftrace: set up trace event hash infrastructure
Impact: simplify/generalize/refactor trace.c The trace.c file is becoming more difficult to maintain due to the growing number of events. There is several formats that an event may be printed. This patch sets up the infrastructure of an event hash to allow for events to register how they should be printed. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
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");