diff options
author | Steven Rostedt <srostedt@redhat.com> | 2008-12-23 23:24:12 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-29 06:46:11 -0500 |
commit | f0868d1e23a8efec33beb3aa688aab7fdb1ae093 (patch) | |
tree | 73593e14d0d127fe3fe055a85b6e16b50a43578a /kernel/trace/trace.c | |
parent | c47956d9ae3341d2d1998bff26620fa3338c01e4 (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.c | 275 |
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 | */ | ||
344 | int | ||
345 | trace_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 | */ | ||
377 | static int | ||
378 | trace_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 | |||
391 | static int | ||
392 | trace_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 | |||
402 | static int | ||
403 | trace_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 | |||
417 | static int | ||
418 | trace_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 | |||
437 | static int | ||
438 | trace_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 | |||
459 | static void | 334 | static void |
460 | trace_seq_reset(struct trace_seq *s) | 335 | trace_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 | ||
1477 | static 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 | ||
1487 | static inline const char *kretprobed(const char *name) | ||
1488 | { | ||
1489 | return name; | ||
1490 | } | ||
1491 | #endif /* CONFIG_KRETPROBES */ | ||
1492 | |||
1493 | static int | ||
1494 | seq_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 | |||
1509 | static int | ||
1510 | seq_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 | |||
1531 | int | ||
1532 | seq_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 | |||
1552 | static 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 | |||
1580 | static int | ||
1581 | seq_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 | |||
1624 | static void print_lat_help_header(struct seq_file *m) | 1351 | static void print_lat_help_header(struct seq_file *m) |
1625 | { | 1352 | { |
1626 | seq_puts(m, "# _------=> CPU# \n"); | 1353 | seq_puts(m, "# _------=> CPU# \n"); |