Merge branch 'linux-linaro-lsk-v4.4' into linux-linaro-lsk-v4.4-android
[firefly-linux-kernel-4.4.55.git] / kernel / trace / trace_output.c
index 8e481a84aeea79b8b008900f3b6f5dbf3044ba7c..3bc4b6de0f4d1f46983f460756b1b4b4972636a9 100644 (file)
@@ -322,8 +322,8 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt,
 # define IP_FMT "%016lx"
 #endif
 
-int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
-                     unsigned long ip, unsigned long sym_flags)
+static 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;
@@ -354,50 +354,6 @@ int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
        return !trace_seq_has_overflowed(s);
 }
 
-int
-seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
-                     unsigned long sym_flags)
-{
-       struct mm_struct *mm = NULL;
-       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->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 || trace_seq_has_overflowed(s))
-                       break;
-
-               trace_seq_puts(s, " => ");
-
-               if (!ip) {
-                       trace_seq_puts(s, "??");
-                       trace_seq_putc(s, '\n');
-                       continue;
-               }
-
-               seq_print_user_ip(s, mm, ip, sym_flags);
-               trace_seq_putc(s, '\n');
-       }
-
-       if (mm)
-               mmput(mm);
-
-       return !trace_seq_has_overflowed(s);
-}
-
 int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
 {
@@ -520,7 +476,8 @@ char trace_find_mark(unsigned long long d)
 static int
 lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
 {
-       unsigned long verbose = trace_flags & TRACE_ITER_VERBOSE;
+       struct trace_array *tr = iter->tr;
+       unsigned long verbose = tr->trace_flags & TRACE_ITER_VERBOSE;
        unsigned long in_ns = iter->iter_flags & TRACE_FILE_TIME_IN_NS;
        unsigned long long abs_ts = iter->ts - iter->trace_buffer->time_start;
        unsigned long long rel_ts = next_ts - iter->ts;
@@ -563,18 +520,29 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
 
 int trace_print_context(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry = iter->ent;
        unsigned long long t;
        unsigned long secs, usec_rem;
        char comm[TASK_COMM_LEN];
+       int tgid;
 
        trace_find_cmdline(entry->pid, comm);
 
-       trace_seq_printf(s, "%16s-%-5d [%03d] ",
-                              comm, entry->pid, iter->cpu);
+       trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid);
+
+       if (tr->trace_flags & TRACE_ITER_TGID) {
+               tgid = trace_find_tgid(entry->pid);
+               if (tgid < 0)
+                       trace_seq_puts(s, "(-----) ");
+               else
+                       trace_seq_printf(s, "(%5d) ", tgid);
+       }
+
+       trace_seq_printf(s, "[%03d] ", iter->cpu);
 
-       if (trace_flags & TRACE_ITER_IRQ_INFO)
+       if (tr->trace_flags & TRACE_ITER_IRQ_INFO)
                trace_print_lat_fmt(s, entry);
 
        if (iter->iter_flags & TRACE_FILE_TIME_IN_NS) {
@@ -590,14 +558,15 @@ int trace_print_context(struct trace_iterator *iter)
 
 int trace_print_lat_context(struct trace_iterator *iter)
 {
-       u64 next_ts;
+       struct trace_array *tr = iter->tr;
        /* trace_find_next_entry will reset ent_size */
        int ent_size = iter->ent_size;
        struct trace_seq *s = &iter->seq;
+       u64 next_ts;
        struct trace_entry *entry = iter->ent,
                           *next_entry = trace_find_next_entry(iter, NULL,
                                                               &next_ts);
-       unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
+       unsigned long verbose = (tr->trace_flags & TRACE_ITER_VERBOSE);
 
        /* Restore the original ent_size */
        iter->ent_size = ent_size;
@@ -886,6 +855,174 @@ static struct trace_event trace_fn_event = {
        .funcs          = &trace_fn_funcs,
 };
 
+/* TRACE_GRAPH_ENT */
+static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
+{
+       struct trace_seq *s = &iter->seq;
+       struct ftrace_graph_ent_entry *field;
+
+       trace_assign_type(field, iter->ent);
+
+       trace_seq_puts(s, "graph_ent: func=");
+       if (trace_seq_has_overflowed(s))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       if (!seq_print_ip_sym(s, field->graph_ent.func, flags))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       trace_seq_puts(s, "\n");
+       if (trace_seq_has_overflowed(s))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ent_entry *field;
+
+       trace_assign_type(field, iter->ent);
+
+       trace_seq_printf(&iter->seq, "%lx %d\n",
+                             field->graph_ent.func,
+                             field->graph_ent.depth);
+       if (trace_seq_has_overflowed(&iter->seq))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ent_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       SEQ_PUT_HEX_FIELD(s, field->graph_ent.func);
+       SEQ_PUT_HEX_FIELD(s, field->graph_ent.depth);
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ent_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       SEQ_PUT_FIELD(s, field->graph_ent.func);
+       SEQ_PUT_FIELD(s, field->graph_ent.depth);
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static struct trace_event_functions trace_graph_ent_funcs = {
+       .trace          = trace_graph_ent_trace,
+       .raw            = trace_graph_ent_raw,
+       .hex            = trace_graph_ent_hex,
+       .binary         = trace_graph_ent_bin,
+};
+
+static struct trace_event trace_graph_ent_event = {
+       .type           = TRACE_GRAPH_ENT,
+       .funcs          = &trace_graph_ent_funcs,
+};
+
+/* TRACE_GRAPH_RET */
+static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
+{
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent;
+       struct ftrace_graph_ret_entry *field;
+
+       trace_assign_type(field, entry);
+
+       trace_seq_puts(s, "graph_ret: func=");
+       if (trace_seq_has_overflowed(s))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       if (!seq_print_ip_sym(s, field->ret.func, flags))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       trace_seq_puts(s, "\n");
+       if (trace_seq_has_overflowed(s))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ret_entry *field;
+
+       trace_assign_type(field, iter->ent);
+
+       trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n",
+                             field->ret.func,
+                             field->ret.calltime,
+                             field->ret.rettime,
+                             field->ret.overrun,
+                             field->ret.depth);
+       if (trace_seq_has_overflowed(&iter->seq))
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ret_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       SEQ_PUT_HEX_FIELD(s, field->ret.func);
+       SEQ_PUT_HEX_FIELD(s, field->ret.calltime);
+       SEQ_PUT_HEX_FIELD(s, field->ret.rettime);
+       SEQ_PUT_HEX_FIELD(s, field->ret.overrun);
+       SEQ_PUT_HEX_FIELD(s, field->ret.depth);
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
+{
+       struct ftrace_graph_ret_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       SEQ_PUT_FIELD(s, field->ret.func);
+       SEQ_PUT_FIELD(s, field->ret.calltime);
+       SEQ_PUT_FIELD(s, field->ret.rettime);
+       SEQ_PUT_FIELD(s, field->ret.overrun);
+       SEQ_PUT_FIELD(s, field->ret.depth);
+
+       return TRACE_TYPE_HANDLED;
+}
+
+static struct trace_event_functions trace_graph_ret_funcs = {
+       .trace          = trace_graph_ret_trace,
+       .raw            = trace_graph_ret_raw,
+       .hex            = trace_graph_ret_hex,
+       .binary         = trace_graph_ret_bin,
+};
+
+static struct trace_event trace_graph_ret_event = {
+       .type           = TRACE_GRAPH_RET,
+       .funcs          = &trace_graph_ret_funcs,
+};
+
 /* TRACE_CTX an TRACE_WAKE */
 static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
                                             char *delim)
@@ -1079,13 +1216,49 @@ static struct trace_event trace_stack_event = {
 static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
                                                int flags, struct trace_event *event)
 {
+       struct trace_array *tr = iter->tr;
        struct userstack_entry *field;
        struct trace_seq *s = &iter->seq;
+       struct mm_struct *mm = NULL;
+       unsigned int i;
 
        trace_assign_type(field, iter->ent);
 
        trace_seq_puts(s, "<user stack trace>\n");
-       seq_print_userip_objs(field, s, flags);
+
+       if (tr->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(field->tgid);
+               if (task)
+                       mm = get_task_mm(task);
+               rcu_read_unlock();
+       }
+
+       for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
+               unsigned long ip = field->caller[i];
+
+               if (ip == ULONG_MAX || trace_seq_has_overflowed(s))
+                       break;
+
+               trace_seq_puts(s, " => ");
+
+               if (!ip) {
+                       trace_seq_puts(s, "??");
+                       trace_seq_putc(s, '\n');
+                       continue;
+               }
+
+               seq_print_user_ip(s, mm, ip, flags);
+               trace_seq_putc(s, '\n');
+       }
+
+       if (mm)
+               mmput(mm);
 
        return trace_handle_return(s);
 }
@@ -1227,6 +1400,8 @@ static struct trace_event trace_print_event = {
 
 static struct trace_event *events[] __initdata = {
        &trace_fn_event,
+       &trace_graph_ent_event,
+       &trace_graph_ret_event,
        &trace_ctx_event,
        &trace_wake_event,
        &trace_stack_event,