|
@@ -37,6 +37,7 @@
|
|
|
#include <linux/irqflags.h>
|
|
|
|
|
|
#include "trace.h"
|
|
|
+#include "trace_output.h"
|
|
|
|
|
|
#define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE)
|
|
|
|
|
@@ -329,132 +330,6 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
|
|
|
tracing_record_cmdline(current);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * trace_seq_printf - sequence printing of trace information
|
|
|
- * @s: trace sequence descriptor
|
|
|
- * @fmt: printf format string
|
|
|
- *
|
|
|
- * The tracer may use either sequence operations or its own
|
|
|
- * copy to user routines. To simplify formating of a trace
|
|
|
- * trace_seq_printf is used to store strings into a special
|
|
|
- * buffer (@s). Then the output may be either used by
|
|
|
- * the sequencer or pulled into another buffer.
|
|
|
- */
|
|
|
-int
|
|
|
-trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
|
|
|
-{
|
|
|
- int len = (PAGE_SIZE - 1) - s->len;
|
|
|
- va_list ap;
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (!len)
|
|
|
- return 0;
|
|
|
-
|
|
|
- va_start(ap, fmt);
|
|
|
- ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
|
|
|
- va_end(ap);
|
|
|
-
|
|
|
- /* If we can't write it all, don't bother writing anything */
|
|
|
- if (ret >= len)
|
|
|
- return 0;
|
|
|
-
|
|
|
- s->len += ret;
|
|
|
-
|
|
|
- return len;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * trace_seq_puts - trace sequence printing of simple string
|
|
|
- * @s: trace sequence descriptor
|
|
|
- * @str: simple string to record
|
|
|
- *
|
|
|
- * The tracer may use either the sequence operations or its own
|
|
|
- * copy to user routines. This function records a simple string
|
|
|
- * into a special buffer (@s) for later retrieval by a sequencer
|
|
|
- * or other mechanism.
|
|
|
- */
|
|
|
-static int
|
|
|
-trace_seq_puts(struct trace_seq *s, const char *str)
|
|
|
-{
|
|
|
- int len = strlen(str);
|
|
|
-
|
|
|
- if (len > ((PAGE_SIZE - 1) - s->len))
|
|
|
- return 0;
|
|
|
-
|
|
|
- memcpy(s->buffer + s->len, str, len);
|
|
|
- s->len += len;
|
|
|
-
|
|
|
- return len;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-trace_seq_putc(struct trace_seq *s, unsigned char c)
|
|
|
-{
|
|
|
- if (s->len >= (PAGE_SIZE - 1))
|
|
|
- return 0;
|
|
|
-
|
|
|
- s->buffer[s->len++] = c;
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
|
|
|
-{
|
|
|
- if (len > ((PAGE_SIZE - 1) - s->len))
|
|
|
- return 0;
|
|
|
-
|
|
|
- memcpy(s->buffer + s->len, mem, len);
|
|
|
- s->len += len;
|
|
|
-
|
|
|
- return len;
|
|
|
-}
|
|
|
-
|
|
|
-#define MAX_MEMHEX_BYTES 8
|
|
|
-#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
|
|
|
-
|
|
|
-static int
|
|
|
-trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
|
|
|
-{
|
|
|
- unsigned char hex[HEX_CHARS];
|
|
|
- unsigned char *data = mem;
|
|
|
- int i, j;
|
|
|
-
|
|
|
-#ifdef __BIG_ENDIAN
|
|
|
- for (i = 0, j = 0; i < len; i++) {
|
|
|
-#else
|
|
|
- for (i = len-1, j = 0; i >= 0; i--) {
|
|
|
-#endif
|
|
|
- hex[j++] = hex_asc_hi(data[i]);
|
|
|
- hex[j++] = hex_asc_lo(data[i]);
|
|
|
- }
|
|
|
- hex[j++] = ' ';
|
|
|
-
|
|
|
- return trace_seq_putmem(s, hex, j);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-trace_seq_path(struct trace_seq *s, struct path *path)
|
|
|
-{
|
|
|
- unsigned char *p;
|
|
|
-
|
|
|
- if (s->len >= (PAGE_SIZE - 1))
|
|
|
- return 0;
|
|
|
- p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
|
|
|
- if (!IS_ERR(p)) {
|
|
|
- p = mangle_path(s->buffer + s->len, p, "\n");
|
|
|
- if (p) {
|
|
|
- s->len = p - s->buffer;
|
|
|
- return 1;
|
|
|
- }
|
|
|
- } else {
|
|
|
- s->buffer[s->len++] = '?';
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static void
|
|
|
trace_seq_reset(struct trace_seq *s)
|
|
|
{
|
|
@@ -1472,154 +1347,6 @@ static void s_stop(struct seq_file *m, void *p)
|
|
|
mutex_unlock(&trace_types_lock);
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_KRETPROBES
|
|
|
-static inline const char *kretprobed(const char *name)
|
|
|
-{
|
|
|
- static const char tramp_name[] = "kretprobe_trampoline";
|
|
|
- int size = sizeof(tramp_name);
|
|
|
-
|
|
|
- if (strncmp(tramp_name, name, size) == 0)
|
|
|
- return "[unknown/kretprobe'd]";
|
|
|
- return name;
|
|
|
-}
|
|
|
-#else
|
|
|
-static inline const char *kretprobed(const char *name)
|
|
|
-{
|
|
|
- return name;
|
|
|
-}
|
|
|
-#endif /* CONFIG_KRETPROBES */
|
|
|
-
|
|
|
-static int
|
|
|
-seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
|
|
|
-{
|
|
|
-#ifdef CONFIG_KALLSYMS
|
|
|
- char str[KSYM_SYMBOL_LEN];
|
|
|
- const char *name;
|
|
|
-
|
|
|
- kallsyms_lookup(address, NULL, NULL, NULL, str);
|
|
|
-
|
|
|
- name = kretprobed(str);
|
|
|
-
|
|
|
- return trace_seq_printf(s, fmt, name);
|
|
|
-#endif
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-seq_print_sym_offset(struct trace_seq *s, const char *fmt,
|
|
|
- unsigned long address)
|
|
|
-{
|
|
|
-#ifdef CONFIG_KALLSYMS
|
|
|
- char str[KSYM_SYMBOL_LEN];
|
|
|
- const char *name;
|
|
|
-
|
|
|
- sprint_symbol(str, address);
|
|
|
- name = kretprobed(str);
|
|
|
-
|
|
|
- return trace_seq_printf(s, fmt, name);
|
|
|
-#endif
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-#ifndef CONFIG_64BIT
|
|
|
-# define IP_FMT "%08lx"
|
|
|
-#else
|
|
|
-# define IP_FMT "%016lx"
|
|
|
-#endif
|
|
|
-
|
|
|
-int
|
|
|
-seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
|
|
|
-{
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (!ip)
|
|
|
- return trace_seq_printf(s, "0");
|
|
|
-
|
|
|
- if (sym_flags & TRACE_ITER_SYM_OFFSET)
|
|
|
- ret = seq_print_sym_offset(s, "%s", ip);
|
|
|
- else
|
|
|
- ret = seq_print_sym_short(s, "%s", ip);
|
|
|
-
|
|
|
- if (!ret)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (sym_flags & TRACE_ITER_SYM_ADDR)
|
|
|
- ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
|
|
|
- unsigned long ip, unsigned long sym_flags)
|
|
|
-{
|
|
|
- struct file *file = NULL;
|
|
|
- unsigned long vmstart = 0;
|
|
|
- int ret = 1;
|
|
|
-
|
|
|
- if (mm) {
|
|
|
- const struct vm_area_struct *vma;
|
|
|
-
|
|
|
- down_read(&mm->mmap_sem);
|
|
|
- vma = find_vma(mm, ip);
|
|
|
- if (vma) {
|
|
|
- file = vma->vm_file;
|
|
|
- vmstart = vma->vm_start;
|
|
|
- }
|
|
|
- if (file) {
|
|
|
- ret = trace_seq_path(s, &file->f_path);
|
|
|
- if (ret)
|
|
|
- ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart);
|
|
|
- }
|
|
|
- up_read(&mm->mmap_sem);
|
|
|
- }
|
|
|
- if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
|
|
|
- ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
|
|
|
- unsigned long sym_flags)
|
|
|
-{
|
|
|
- struct mm_struct *mm = NULL;
|
|
|
- int ret = 1;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
|
|
|
- struct task_struct *task;
|
|
|
- /*
|
|
|
- * we do the lookup on the thread group leader,
|
|
|
- * since individual threads might have already quit!
|
|
|
- */
|
|
|
- rcu_read_lock();
|
|
|
- task = find_task_by_vpid(entry->ent.tgid);
|
|
|
- if (task)
|
|
|
- mm = get_task_mm(task);
|
|
|
- rcu_read_unlock();
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
|
|
|
- unsigned long ip = entry->caller[i];
|
|
|
-
|
|
|
- if (ip == ULONG_MAX || !ret)
|
|
|
- break;
|
|
|
- if (i && ret)
|
|
|
- ret = trace_seq_puts(s, " <- ");
|
|
|
- if (!ip) {
|
|
|
- if (ret)
|
|
|
- ret = trace_seq_puts(s, "??");
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!ret)
|
|
|
- break;
|
|
|
- if (ret)
|
|
|
- ret = seq_print_user_ip(s, mm, ip, sym_flags);
|
|
|
- }
|
|
|
-
|
|
|
- if (mm)
|
|
|
- mmput(mm);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
static void print_lat_help_header(struct seq_file *m)
|
|
|
{
|
|
|
seq_puts(m, "# _------=> CPU# \n");
|
|
@@ -1755,52 +1482,6 @@ lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
|
|
|
trace_seq_puts(s, " : ");
|
|
|
}
|
|
|
|
|
|
-static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
|
|
|
-
|
|
|
-static int task_state_char(unsigned long state)
|
|
|
-{
|
|
|
- int bit = state ? __ffs(state) + 1 : 0;
|
|
|
-
|
|
|
- return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * The message is supposed to contain an ending newline.
|
|
|
- * If the printing stops prematurely, try to add a newline of our own.
|
|
|
- */
|
|
|
-void trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
|
|
|
-{
|
|
|
- struct trace_entry *ent;
|
|
|
- struct trace_field_cont *cont;
|
|
|
- bool ok = true;
|
|
|
-
|
|
|
- ent = peek_next_entry(iter, iter->cpu, NULL);
|
|
|
- if (!ent || ent->type != TRACE_CONT) {
|
|
|
- trace_seq_putc(s, '\n');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- do {
|
|
|
- cont = (struct trace_field_cont *)ent;
|
|
|
- if (ok)
|
|
|
- ok = (trace_seq_printf(s, "%s", cont->buf) > 0);
|
|
|
-
|
|
|
- ftrace_disable_cpu();
|
|
|
-
|
|
|
- if (iter->buffer_iter[iter->cpu])
|
|
|
- ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
|
|
|
- else
|
|
|
- ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL);
|
|
|
-
|
|
|
- ftrace_enable_cpu();
|
|
|
-
|
|
|
- ent = peek_next_entry(iter, iter->cpu, NULL);
|
|
|
- } while (ent && ent->type == TRACE_CONT);
|
|
|
-
|
|
|
- if (!ok)
|
|
|
- trace_seq_putc(s, '\n');
|
|
|
-}
|
|
|
-
|
|
|
static void test_cpu_buff_start(struct trace_iterator *iter)
|
|
|
{
|
|
|
struct trace_seq *s = &iter->seq;
|
|
@@ -1824,17 +1505,14 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
|
|
|
struct trace_seq *s = &iter->seq;
|
|
|
unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
|
|
|
struct trace_entry *next_entry;
|
|
|
+ struct trace_event *event;
|
|
|
unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
|
|
|
struct trace_entry *entry = iter->ent;
|
|
|
unsigned long abs_usecs;
|
|
|
unsigned long rel_usecs;
|
|
|
u64 next_ts;
|
|
|
char *comm;
|
|
|
- int S, T;
|
|
|
- int i;
|
|
|
-
|
|
|
- if (entry->type == TRACE_CONT)
|
|
|
- return TRACE_TYPE_HANDLED;
|
|
|
+ int ret;
|
|
|
|
|
|
test_cpu_buff_start(iter);
|
|
|
|
|
@@ -1859,96 +1537,16 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
|
|
|
lat_print_generic(s, entry, cpu);
|
|
|
lat_print_timestamp(s, abs_usecs, rel_usecs);
|
|
|
}
|
|
|
- switch (entry->type) {
|
|
|
- case TRACE_FN: {
|
|
|
- struct ftrace_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- seq_print_ip_sym(s, field->ip, sym_flags);
|
|
|
- trace_seq_puts(s, " (");
|
|
|
- seq_print_ip_sym(s, field->parent_ip, sym_flags);
|
|
|
- trace_seq_puts(s, ")\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_CTX:
|
|
|
- case TRACE_WAKE: {
|
|
|
- struct ctx_switch_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- T = task_state_char(field->next_state);
|
|
|
- S = task_state_char(field->prev_state);
|
|
|
- comm = trace_find_cmdline(field->next_pid);
|
|
|
- trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
|
|
|
- field->prev_pid,
|
|
|
- field->prev_prio,
|
|
|
- S, entry->type == TRACE_CTX ? "==>" : " +",
|
|
|
- field->next_cpu,
|
|
|
- field->next_pid,
|
|
|
- field->next_prio,
|
|
|
- T, comm);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_SPECIAL: {
|
|
|
- struct special_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- trace_seq_printf(s, "# %ld %ld %ld\n",
|
|
|
- field->arg1,
|
|
|
- field->arg2,
|
|
|
- field->arg3);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_STACK: {
|
|
|
- struct stack_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
|
|
|
- if (i)
|
|
|
- trace_seq_puts(s, " <= ");
|
|
|
- seq_print_ip_sym(s, field->caller[i], sym_flags);
|
|
|
- }
|
|
|
- trace_seq_puts(s, "\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_PRINT: {
|
|
|
- struct print_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
|
|
|
- seq_print_ip_sym(s, field->ip, sym_flags);
|
|
|
- trace_seq_printf(s, ": %s", field->buf);
|
|
|
- if (entry->flags & TRACE_FLAG_CONT)
|
|
|
- trace_seq_print_cont(s, iter);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_BRANCH: {
|
|
|
- struct trace_branch *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- trace_seq_printf(s, "[%s] %s:%s:%d\n",
|
|
|
- field->correct ? " ok " : " MISS ",
|
|
|
- field->func,
|
|
|
- field->file,
|
|
|
- field->line);
|
|
|
- break;
|
|
|
+ event = ftrace_find_event(entry->type);
|
|
|
+ if (event && event->latency_trace) {
|
|
|
+ ret = event->latency_trace(s, entry, sym_flags);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
- case TRACE_USER_STACK: {
|
|
|
- struct userstack_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
|
|
|
- seq_print_userip_objs(field, s, sym_flags);
|
|
|
- trace_seq_putc(s, '\n');
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- trace_seq_printf(s, "Unknown type %d\n", entry->type);
|
|
|
- }
|
|
|
+ trace_seq_printf(s, "Unknown type %d\n", entry->type);
|
|
|
return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -1957,19 +1555,15 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
|
|
|
struct trace_seq *s = &iter->seq;
|
|
|
unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
|
|
|
struct trace_entry *entry;
|
|
|
+ struct trace_event *event;
|
|
|
unsigned long usec_rem;
|
|
|
unsigned long long t;
|
|
|
unsigned long secs;
|
|
|
char *comm;
|
|
|
int ret;
|
|
|
- int S, T;
|
|
|
- int i;
|
|
|
|
|
|
entry = iter->ent;
|
|
|
|
|
|
- if (entry->type == TRACE_CONT)
|
|
|
- return TRACE_TYPE_HANDLED;
|
|
|
-
|
|
|
test_cpu_buff_start(iter);
|
|
|
|
|
|
comm = trace_find_cmdline(iter->ent->pid);
|
|
@@ -1988,129 +1582,17 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
|
|
|
if (!ret)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- switch (entry->type) {
|
|
|
- case TRACE_FN: {
|
|
|
- struct ftrace_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- ret = seq_print_ip_sym(s, field->ip, sym_flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- if ((sym_flags & TRACE_ITER_PRINT_PARENT) &&
|
|
|
- field->parent_ip) {
|
|
|
- ret = trace_seq_printf(s, " <-");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- ret = seq_print_ip_sym(s,
|
|
|
- field->parent_ip,
|
|
|
- sym_flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
- ret = trace_seq_printf(s, "\n");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_CTX:
|
|
|
- case TRACE_WAKE: {
|
|
|
- struct ctx_switch_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- T = task_state_char(field->next_state);
|
|
|
- S = task_state_char(field->prev_state);
|
|
|
- ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n",
|
|
|
- field->prev_pid,
|
|
|
- field->prev_prio,
|
|
|
- S,
|
|
|
- entry->type == TRACE_CTX ? "==>" : " +",
|
|
|
- field->next_cpu,
|
|
|
- field->next_pid,
|
|
|
- field->next_prio,
|
|
|
- T);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_SPECIAL: {
|
|
|
- struct special_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- ret = trace_seq_printf(s, "# %ld %ld %ld\n",
|
|
|
- field->arg1,
|
|
|
- field->arg2,
|
|
|
- field->arg3);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_STACK: {
|
|
|
- struct stack_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
|
|
|
- if (i) {
|
|
|
- ret = trace_seq_puts(s, " <= ");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
- ret = seq_print_ip_sym(s, field->caller[i],
|
|
|
- sym_flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
- ret = trace_seq_puts(s, "\n");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_PRINT: {
|
|
|
- struct print_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- seq_print_ip_sym(s, field->ip, sym_flags);
|
|
|
- trace_seq_printf(s, ": %s", field->buf);
|
|
|
- if (entry->flags & TRACE_FLAG_CONT)
|
|
|
- trace_seq_print_cont(s, iter);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_GRAPH_RET: {
|
|
|
- return print_graph_function(iter);
|
|
|
- }
|
|
|
- case TRACE_GRAPH_ENT: {
|
|
|
- return print_graph_function(iter);
|
|
|
- }
|
|
|
- case TRACE_BRANCH: {
|
|
|
- struct trace_branch *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- trace_seq_printf(s, "[%s] %s:%s:%d\n",
|
|
|
- field->correct ? " ok " : " MISS ",
|
|
|
- field->func,
|
|
|
- field->file,
|
|
|
- field->line);
|
|
|
- break;
|
|
|
+ event = ftrace_find_event(entry->type);
|
|
|
+ if (event && event->trace) {
|
|
|
+ ret = event->trace(s, entry, sym_flags);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
- case TRACE_USER_STACK: {
|
|
|
- struct userstack_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
+ ret = trace_seq_printf(s, "Unknown type %d\n", entry->type);
|
|
|
+ if (!ret)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- ret = seq_print_userip_objs(field, s, sym_flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- ret = trace_seq_putc(s, '\n');
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -2118,152 +1600,47 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
|
|
|
{
|
|
|
struct trace_seq *s = &iter->seq;
|
|
|
struct trace_entry *entry;
|
|
|
+ struct trace_event *event;
|
|
|
int ret;
|
|
|
- int S, T;
|
|
|
|
|
|
entry = iter->ent;
|
|
|
|
|
|
- if (entry->type == TRACE_CONT)
|
|
|
- return TRACE_TYPE_HANDLED;
|
|
|
-
|
|
|
ret = trace_seq_printf(s, "%d %d %llu ",
|
|
|
entry->pid, iter->cpu, iter->ts);
|
|
|
if (!ret)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- switch (entry->type) {
|
|
|
- case TRACE_FN: {
|
|
|
- struct ftrace_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- ret = trace_seq_printf(s, "%x %x\n",
|
|
|
- field->ip,
|
|
|
- field->parent_ip);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_CTX:
|
|
|
- case TRACE_WAKE: {
|
|
|
- struct ctx_switch_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- T = task_state_char(field->next_state);
|
|
|
- S = entry->type == TRACE_WAKE ? '+' :
|
|
|
- task_state_char(field->prev_state);
|
|
|
- ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
|
|
|
- field->prev_pid,
|
|
|
- field->prev_prio,
|
|
|
- S,
|
|
|
- field->next_cpu,
|
|
|
- field->next_pid,
|
|
|
- field->next_prio,
|
|
|
- T);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_SPECIAL:
|
|
|
- case TRACE_USER_STACK:
|
|
|
- case TRACE_STACK: {
|
|
|
- struct special_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- ret = trace_seq_printf(s, "# %ld %ld %ld\n",
|
|
|
- field->arg1,
|
|
|
- field->arg2,
|
|
|
- field->arg3);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- break;
|
|
|
+ event = ftrace_find_event(entry->type);
|
|
|
+ if (event && event->raw) {
|
|
|
+ ret = event->raw(s, entry, 0);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
- case TRACE_PRINT: {
|
|
|
- struct print_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
+ ret = trace_seq_printf(s, "%d ?\n", entry->type);
|
|
|
+ if (!ret)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- trace_seq_printf(s, "# %lx %s", field->ip, field->buf);
|
|
|
- if (entry->flags & TRACE_FLAG_CONT)
|
|
|
- trace_seq_print_cont(s, iter);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
|
|
|
-#define SEQ_PUT_FIELD_RET(s, x) \
|
|
|
-do { \
|
|
|
- if (!trace_seq_putmem(s, &(x), sizeof(x))) \
|
|
|
- return 0; \
|
|
|
-} while (0)
|
|
|
-
|
|
|
-#define SEQ_PUT_HEX_FIELD_RET(s, x) \
|
|
|
-do { \
|
|
|
- BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES); \
|
|
|
- if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \
|
|
|
- return 0; \
|
|
|
-} while (0)
|
|
|
-
|
|
|
static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
|
|
|
{
|
|
|
struct trace_seq *s = &iter->seq;
|
|
|
unsigned char newline = '\n';
|
|
|
struct trace_entry *entry;
|
|
|
- int S, T;
|
|
|
+ struct trace_event *event;
|
|
|
|
|
|
entry = iter->ent;
|
|
|
|
|
|
- if (entry->type == TRACE_CONT)
|
|
|
- return TRACE_TYPE_HANDLED;
|
|
|
-
|
|
|
SEQ_PUT_HEX_FIELD_RET(s, entry->pid);
|
|
|
SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);
|
|
|
SEQ_PUT_HEX_FIELD_RET(s, iter->ts);
|
|
|
|
|
|
- switch (entry->type) {
|
|
|
- case TRACE_FN: {
|
|
|
- struct ftrace_entry *field;
|
|
|
+ event = ftrace_find_event(entry->type);
|
|
|
+ if (event && event->hex)
|
|
|
+ event->hex(s, entry, 0);
|
|
|
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->ip);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_CTX:
|
|
|
- case TRACE_WAKE: {
|
|
|
- struct ctx_switch_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- T = task_state_char(field->next_state);
|
|
|
- S = entry->type == TRACE_WAKE ? '+' :
|
|
|
- task_state_char(field->prev_state);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, S);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, T);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_SPECIAL:
|
|
|
- case TRACE_USER_STACK:
|
|
|
- case TRACE_STACK: {
|
|
|
- struct special_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
|
|
|
- SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
SEQ_PUT_FIELD_RET(s, newline);
|
|
|
|
|
|
return TRACE_TYPE_HANDLED;
|
|
@@ -2282,9 +1659,6 @@ static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
|
|
|
if (!ret)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- if (entry->flags & TRACE_FLAG_CONT)
|
|
|
- trace_seq_print_cont(s, iter);
|
|
|
-
|
|
|
return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -2292,53 +1666,19 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
|
|
|
{
|
|
|
struct trace_seq *s = &iter->seq;
|
|
|
struct trace_entry *entry;
|
|
|
+ struct trace_event *event;
|
|
|
|
|
|
entry = iter->ent;
|
|
|
|
|
|
- if (entry->type == TRACE_CONT)
|
|
|
- return TRACE_TYPE_HANDLED;
|
|
|
-
|
|
|
SEQ_PUT_FIELD_RET(s, entry->pid);
|
|
|
SEQ_PUT_FIELD_RET(s, entry->cpu);
|
|
|
SEQ_PUT_FIELD_RET(s, iter->ts);
|
|
|
|
|
|
- switch (entry->type) {
|
|
|
- case TRACE_FN: {
|
|
|
- struct ftrace_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- SEQ_PUT_FIELD_RET(s, field->ip);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->parent_ip);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_CTX: {
|
|
|
- struct ctx_switch_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
-
|
|
|
- SEQ_PUT_FIELD_RET(s, field->prev_pid);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->prev_prio);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->prev_state);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->next_pid);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->next_prio);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->next_state);
|
|
|
- break;
|
|
|
- }
|
|
|
- case TRACE_SPECIAL:
|
|
|
- case TRACE_USER_STACK:
|
|
|
- case TRACE_STACK: {
|
|
|
- struct special_entry *field;
|
|
|
-
|
|
|
- trace_assign_type(field, entry);
|
|
|
+ event = ftrace_find_event(entry->type);
|
|
|
+ if (event && event->binary)
|
|
|
+ event->binary(s, entry, 0);
|
|
|
|
|
|
- SEQ_PUT_FIELD_RET(s, field->arg1);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->arg2);
|
|
|
- SEQ_PUT_FIELD_RET(s, field->arg3);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return 1;
|
|
|
+ return TRACE_TYPE_HANDLED;
|
|
|
}
|
|
|
|
|
|
static int trace_empty(struct trace_iterator *iter)
|
|
@@ -3013,6 +2353,7 @@ static int tracing_set_tracer(char *buf)
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
}
|
|
|
+ init_tracer_stat(t);
|
|
|
|
|
|
trace_branch_enable(tr);
|
|
|
out:
|
|
@@ -3877,7 +3218,7 @@ __init static int tracer_alloc_buffers(void)
|
|
|
#else
|
|
|
current_trace = &nop_trace;
|
|
|
#endif
|
|
|
-
|
|
|
+ init_tracer_stat(current_trace);
|
|
|
/* All seems OK, enable tracing */
|
|
|
tracing_disabled = 0;
|
|
|
|