blob: 491832af9ba15c8b24b29ff80a00acc122b51caa [file] [log] [blame]
Steven Rostedtf0868d12008-12-23 23:24:12 -05001/*
2 * trace_output.c
3 *
4 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
5 *
6 */
7
8#include <linux/module.h>
9#include <linux/mutex.h>
10#include <linux/ftrace.h>
11
12#include "trace_output.h"
13
14/* must be a power of 2 */
15#define EVENT_HASHSIZE 128
16
17static DEFINE_MUTEX(trace_event_mutex);
18static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
19
20static int next_event_type = __TRACE_LAST_TYPE + 1;
21
22/**
23 * trace_seq_printf - sequence printing of trace information
24 * @s: trace sequence descriptor
25 * @fmt: printf format string
26 *
27 * The tracer may use either sequence operations or its own
28 * copy to user routines. To simplify formating of a trace
29 * trace_seq_printf is used to store strings into a special
30 * buffer (@s). Then the output may be either used by
31 * the sequencer or pulled into another buffer.
32 */
33int
34trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
35{
36 int len = (PAGE_SIZE - 1) - s->len;
37 va_list ap;
38 int ret;
39
40 if (!len)
41 return 0;
42
43 va_start(ap, fmt);
44 ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
45 va_end(ap);
46
47 /* If we can't write it all, don't bother writing anything */
48 if (ret >= len)
49 return 0;
50
51 s->len += ret;
52
53 return len;
54}
55
Frederic Weisbecker769b0442009-03-06 17:21:49 +010056int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010057{
58 int len = (PAGE_SIZE - 1) - s->len;
59 int ret;
60
61 if (!len)
62 return 0;
63
64 ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
65
66 /* If we can't write it all, don't bother writing anything */
67 if (ret >= len)
68 return 0;
69
70 s->len += ret;
71
72 return len;
73}
74
Steven Rostedtf0868d12008-12-23 23:24:12 -050075/**
76 * trace_seq_puts - trace sequence printing of simple string
77 * @s: trace sequence descriptor
78 * @str: simple string to record
79 *
80 * The tracer may use either the sequence operations or its own
81 * copy to user routines. This function records a simple string
82 * into a special buffer (@s) for later retrieval by a sequencer
83 * or other mechanism.
84 */
85int trace_seq_puts(struct trace_seq *s, const char *str)
86{
87 int len = strlen(str);
88
89 if (len > ((PAGE_SIZE - 1) - s->len))
90 return 0;
91
92 memcpy(s->buffer + s->len, str, len);
93 s->len += len;
94
95 return len;
96}
97
98int trace_seq_putc(struct trace_seq *s, unsigned char c)
99{
100 if (s->len >= (PAGE_SIZE - 1))
101 return 0;
102
103 s->buffer[s->len++] = c;
104
105 return 1;
106}
107
108int trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
109{
110 if (len > ((PAGE_SIZE - 1) - s->len))
111 return 0;
112
113 memcpy(s->buffer + s->len, mem, len);
114 s->len += len;
115
116 return len;
117}
118
119int trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
120{
121 unsigned char hex[HEX_CHARS];
122 unsigned char *data = mem;
123 int i, j;
124
125#ifdef __BIG_ENDIAN
126 for (i = 0, j = 0; i < len; i++) {
127#else
128 for (i = len-1, j = 0; i >= 0; i--) {
129#endif
130 hex[j++] = hex_asc_hi(data[i]);
131 hex[j++] = hex_asc_lo(data[i]);
132 }
133 hex[j++] = ' ';
134
135 return trace_seq_putmem(s, hex, j);
136}
137
138int trace_seq_path(struct trace_seq *s, struct path *path)
139{
140 unsigned char *p;
141
142 if (s->len >= (PAGE_SIZE - 1))
143 return 0;
144 p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
145 if (!IS_ERR(p)) {
146 p = mangle_path(s->buffer + s->len, p, "\n");
147 if (p) {
148 s->len = p - s->buffer;
149 return 1;
150 }
151 } else {
152 s->buffer[s->len++] = '?';
153 return 1;
154 }
155
156 return 0;
157}
158
159#ifdef CONFIG_KRETPROBES
160static inline const char *kretprobed(const char *name)
161{
162 static const char tramp_name[] = "kretprobe_trampoline";
163 int size = sizeof(tramp_name);
164
165 if (strncmp(tramp_name, name, size) == 0)
166 return "[unknown/kretprobe'd]";
167 return name;
168}
169#else
170static inline const char *kretprobed(const char *name)
171{
172 return name;
173}
174#endif /* CONFIG_KRETPROBES */
175
176static int
177seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
178{
179#ifdef CONFIG_KALLSYMS
180 char str[KSYM_SYMBOL_LEN];
181 const char *name;
182
183 kallsyms_lookup(address, NULL, NULL, NULL, str);
184
185 name = kretprobed(str);
186
187 return trace_seq_printf(s, fmt, name);
188#endif
189 return 1;
190}
191
192static int
193seq_print_sym_offset(struct trace_seq *s, const char *fmt,
194 unsigned long address)
195{
196#ifdef CONFIG_KALLSYMS
197 char str[KSYM_SYMBOL_LEN];
198 const char *name;
199
200 sprint_symbol(str, address);
201 name = kretprobed(str);
202
203 return trace_seq_printf(s, fmt, name);
204#endif
205 return 1;
206}
207
208#ifndef CONFIG_64BIT
209# define IP_FMT "%08lx"
210#else
211# define IP_FMT "%016lx"
212#endif
213
214int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
215 unsigned long ip, unsigned long sym_flags)
216{
217 struct file *file = NULL;
218 unsigned long vmstart = 0;
219 int ret = 1;
220
221 if (mm) {
222 const struct vm_area_struct *vma;
223
224 down_read(&mm->mmap_sem);
225 vma = find_vma(mm, ip);
226 if (vma) {
227 file = vma->vm_file;
228 vmstart = vma->vm_start;
229 }
230 if (file) {
231 ret = trace_seq_path(s, &file->f_path);
232 if (ret)
233 ret = trace_seq_printf(s, "[+0x%lx]",
234 ip - vmstart);
235 }
236 up_read(&mm->mmap_sem);
237 }
238 if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
239 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
240 return ret;
241}
242
243int
244seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
245 unsigned long sym_flags)
246{
247 struct mm_struct *mm = NULL;
248 int ret = 1;
249 unsigned int i;
250
251 if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
252 struct task_struct *task;
253 /*
254 * we do the lookup on the thread group leader,
255 * since individual threads might have already quit!
256 */
257 rcu_read_lock();
258 task = find_task_by_vpid(entry->ent.tgid);
259 if (task)
260 mm = get_task_mm(task);
261 rcu_read_unlock();
262 }
263
264 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
265 unsigned long ip = entry->caller[i];
266
267 if (ip == ULONG_MAX || !ret)
268 break;
269 if (i && ret)
270 ret = trace_seq_puts(s, " <- ");
271 if (!ip) {
272 if (ret)
273 ret = trace_seq_puts(s, "??");
274 continue;
275 }
276 if (!ret)
277 break;
278 if (ret)
279 ret = seq_print_user_ip(s, mm, ip, sym_flags);
280 }
281
282 if (mm)
283 mmput(mm);
284 return ret;
285}
286
287int
288seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
289{
290 int ret;
291
292 if (!ip)
293 return trace_seq_printf(s, "0");
294
295 if (sym_flags & TRACE_ITER_SYM_OFFSET)
296 ret = seq_print_sym_offset(s, "%s", ip);
297 else
298 ret = seq_print_sym_short(s, "%s", ip);
299
300 if (!ret)
301 return 0;
302
303 if (sym_flags & TRACE_ITER_SYM_ADDR)
304 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
305 return ret;
306}
307
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200308static int
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200309lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
310{
311 int hardirq, softirq;
312 char *comm;
313
314 comm = trace_find_cmdline(entry->pid);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200315 hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
316 softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200317
318 if (!trace_seq_printf(s, "%8.8s-%-5d %3d%c%c%c",
319 comm, entry->pid, cpu,
320 (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
321 (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
322 'X' : '.',
323 (entry->flags & TRACE_FLAG_NEED_RESCHED) ?
324 'N' : '.',
325 (hardirq && softirq) ? 'H' :
326 hardirq ? 'h' : softirq ? 's' : '.'))
327 return 0;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200328
329 if (entry->preempt_count)
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200330 return trace_seq_printf(s, "%x", entry->preempt_count);
331 return trace_seq_puts(s, ".");
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200332}
333
334static unsigned long preempt_mark_thresh = 100;
335
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200336static int
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200337lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
338 unsigned long rel_usecs)
339{
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200340 return trace_seq_printf(s, " %4lldus%c: ", abs_usecs,
341 rel_usecs > preempt_mark_thresh ? '!' :
342 rel_usecs > 1 ? '+' : ' ');
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200343}
344
345int trace_print_context(struct trace_iterator *iter)
346{
347 struct trace_seq *s = &iter->seq;
348 struct trace_entry *entry = iter->ent;
349 char *comm = trace_find_cmdline(entry->pid);
350 unsigned long long t = ns2usecs(iter->ts);
351 unsigned long usec_rem = do_div(t, USEC_PER_SEC);
352 unsigned long secs = (unsigned long)t;
353
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200354 return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ",
Steven Rostedt1830b522009-02-07 19:38:43 -0500355 comm, entry->pid, iter->cpu, secs, usec_rem);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200356}
357
358int trace_print_lat_context(struct trace_iterator *iter)
359{
360 u64 next_ts;
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200361 int ret;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200362 struct trace_seq *s = &iter->seq;
363 struct trace_entry *entry = iter->ent,
364 *next_entry = trace_find_next_entry(iter, NULL,
365 &next_ts);
366 unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
367 unsigned long abs_usecs = ns2usecs(iter->ts - iter->tr->time_start);
368 unsigned long rel_usecs;
369
370 if (!next_entry)
371 next_ts = iter->ts;
372 rel_usecs = ns2usecs(next_ts - iter->ts);
373
374 if (verbose) {
375 char *comm = trace_find_cmdline(entry->pid);
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200376 ret = trace_seq_printf(s, "%16s %5d %3d %d %08x %08lx [%08lx]"
377 " %ld.%03ldms (+%ld.%03ldms): ", comm,
Steven Rostedt1830b522009-02-07 19:38:43 -0500378 entry->pid, iter->cpu, entry->flags,
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200379 entry->preempt_count, iter->idx,
380 ns2usecs(iter->ts),
381 abs_usecs / USEC_PER_MSEC,
382 abs_usecs % USEC_PER_MSEC,
383 rel_usecs / USEC_PER_MSEC,
384 rel_usecs % USEC_PER_MSEC);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200385 } else {
Steven Rostedt1830b522009-02-07 19:38:43 -0500386 ret = lat_print_generic(s, entry, iter->cpu);
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200387 if (ret)
388 ret = lat_print_timestamp(s, abs_usecs, rel_usecs);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200389 }
390
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200391 return ret;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200392}
393
Steven Rostedtf633cef2008-12-23 23:24:13 -0500394static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
395
396static int task_state_char(unsigned long state)
397{
398 int bit = state ? __ffs(state) + 1 : 0;
399
400 return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
401}
402
Steven Rostedtf0868d12008-12-23 23:24:12 -0500403/**
404 * ftrace_find_event - find a registered event
405 * @type: the type of event to look for
406 *
407 * Returns an event of type @type otherwise NULL
408 */
409struct trace_event *ftrace_find_event(int type)
410{
411 struct trace_event *event;
412 struct hlist_node *n;
413 unsigned key;
414
415 key = type & (EVENT_HASHSIZE - 1);
416
417 hlist_for_each_entry_rcu(event, n, &event_hash[key], node) {
418 if (event->type == type)
419 return event;
420 }
421
422 return NULL;
423}
424
425/**
426 * register_ftrace_event - register output for an event type
427 * @event: the event type to register
428 *
429 * Event types are stored in a hash and this hash is used to
430 * find a way to print an event. If the @event->type is set
431 * then it will use that type, otherwise it will assign a
432 * type to use.
433 *
434 * If you assign your own type, please make sure it is added
435 * to the trace_type enum in trace.h, to avoid collisions
436 * with the dynamic types.
437 *
438 * Returns the event type number or zero on error.
439 */
440int register_ftrace_event(struct trace_event *event)
441{
442 unsigned key;
443 int ret = 0;
444
445 mutex_lock(&trace_event_mutex);
446
447 if (!event->type)
448 event->type = next_event_type++;
449 else if (event->type > __TRACE_LAST_TYPE) {
450 printk(KERN_WARNING "Need to add type to trace.h\n");
451 WARN_ON(1);
452 }
453
454 if (ftrace_find_event(event->type))
455 goto out;
456
Arnaldo Carvalho de Melo268ccda2009-02-04 20:16:39 -0200457 if (event->trace == NULL)
458 event->trace = trace_nop_print;
Arnaldo Carvalho de Melo268ccda2009-02-04 20:16:39 -0200459 if (event->raw == NULL)
460 event->raw = trace_nop_print;
461 if (event->hex == NULL)
462 event->hex = trace_nop_print;
463 if (event->binary == NULL)
464 event->binary = trace_nop_print;
465
Steven Rostedtf0868d12008-12-23 23:24:12 -0500466 key = event->type & (EVENT_HASHSIZE - 1);
467
468 hlist_add_head_rcu(&event->node, &event_hash[key]);
469
470 ret = event->type;
471 out:
472 mutex_unlock(&trace_event_mutex);
473
474 return ret;
475}
476
477/**
478 * unregister_ftrace_event - remove a no longer used event
479 * @event: the event to remove
480 */
481int unregister_ftrace_event(struct trace_event *event)
482{
483 mutex_lock(&trace_event_mutex);
484 hlist_del(&event->node);
485 mutex_unlock(&trace_event_mutex);
486
487 return 0;
488}
Steven Rostedtf633cef2008-12-23 23:24:13 -0500489
490/*
491 * Standard events
492 */
493
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200494enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500495{
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200496 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500497}
498
499/* TRACE_FN */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200500static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500501{
502 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200503 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500504
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200505 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500506
507 if (!seq_print_ip_sym(s, field->ip, flags))
508 goto partial;
509
510 if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
511 if (!trace_seq_printf(s, " <-"))
512 goto partial;
513 if (!seq_print_ip_sym(s,
514 field->parent_ip,
515 flags))
516 goto partial;
517 }
518 if (!trace_seq_printf(s, "\n"))
519 goto partial;
520
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200521 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500522
523 partial:
524 return TRACE_TYPE_PARTIAL_LINE;
525}
526
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200527static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500528{
529 struct ftrace_entry *field;
530
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200531 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500532
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200533 if (!trace_seq_printf(&iter->seq, "%lx %lx\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800534 field->ip,
535 field->parent_ip))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500536 return TRACE_TYPE_PARTIAL_LINE;
537
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200538 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500539}
540
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200541static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500542{
543 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200544 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500545
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200546 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500547
548 SEQ_PUT_HEX_FIELD_RET(s, field->ip);
549 SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
550
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200551 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500552}
553
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200554static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500555{
556 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200557 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500558
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200559 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500560
561 SEQ_PUT_FIELD_RET(s, field->ip);
562 SEQ_PUT_FIELD_RET(s, field->parent_ip);
563
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200564 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500565}
566
567static struct trace_event trace_fn_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400568 .type = TRACE_FN,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500569 .trace = trace_fn_trace,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500570 .raw = trace_fn_raw,
571 .hex = trace_fn_hex,
572 .binary = trace_fn_bin,
573};
574
575/* TRACE_CTX an TRACE_WAKE */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200576static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
577 char *delim)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500578{
579 struct ctx_switch_entry *field;
580 char *comm;
581 int S, T;
582
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200583 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500584
585 T = task_state_char(field->next_state);
586 S = task_state_char(field->prev_state);
587 comm = trace_find_cmdline(field->next_pid);
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200588 if (!trace_seq_printf(&iter->seq,
589 " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800590 field->prev_pid,
591 field->prev_prio,
592 S, delim,
593 field->next_cpu,
594 field->next_pid,
595 field->next_prio,
596 T, comm))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500597 return TRACE_TYPE_PARTIAL_LINE;
598
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200599 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500600}
601
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200602static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500603{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200604 return trace_ctxwake_print(iter, "==>");
Steven Rostedtf633cef2008-12-23 23:24:13 -0500605}
606
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200607static enum print_line_t trace_wake_print(struct trace_iterator *iter,
608 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500609{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200610 return trace_ctxwake_print(iter, " +");
Steven Rostedtf633cef2008-12-23 23:24:13 -0500611}
612
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200613static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500614{
615 struct ctx_switch_entry *field;
616 int T;
617
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200618 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500619
620 if (!S)
621 task_state_char(field->prev_state);
622 T = task_state_char(field->next_state);
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200623 if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800624 field->prev_pid,
625 field->prev_prio,
626 S,
627 field->next_cpu,
628 field->next_pid,
629 field->next_prio,
630 T))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500631 return TRACE_TYPE_PARTIAL_LINE;
632
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200633 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500634}
635
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200636static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500637{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200638 return trace_ctxwake_raw(iter, 0);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500639}
640
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200641static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500642{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200643 return trace_ctxwake_raw(iter, '+');
Steven Rostedtf633cef2008-12-23 23:24:13 -0500644}
645
646
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200647static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500648{
649 struct ctx_switch_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200650 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500651 int T;
652
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200653 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500654
655 if (!S)
656 task_state_char(field->prev_state);
657 T = task_state_char(field->next_state);
658
659 SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
660 SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
661 SEQ_PUT_HEX_FIELD_RET(s, S);
662 SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
663 SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
664 SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
665 SEQ_PUT_HEX_FIELD_RET(s, T);
666
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200667 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500668}
669
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200670static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500671{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200672 return trace_ctxwake_hex(iter, 0);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500673}
674
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200675static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500676{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200677 return trace_ctxwake_hex(iter, '+');
Steven Rostedtf633cef2008-12-23 23:24:13 -0500678}
679
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200680static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
681 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500682{
683 struct ctx_switch_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200684 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500685
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200686 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500687
688 SEQ_PUT_FIELD_RET(s, field->prev_pid);
689 SEQ_PUT_FIELD_RET(s, field->prev_prio);
690 SEQ_PUT_FIELD_RET(s, field->prev_state);
691 SEQ_PUT_FIELD_RET(s, field->next_pid);
692 SEQ_PUT_FIELD_RET(s, field->next_prio);
693 SEQ_PUT_FIELD_RET(s, field->next_state);
694
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200695 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500696}
697
698static struct trace_event trace_ctx_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400699 .type = TRACE_CTX,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500700 .trace = trace_ctx_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500701 .raw = trace_ctx_raw,
702 .hex = trace_ctx_hex,
703 .binary = trace_ctxwake_bin,
704};
705
706static struct trace_event trace_wake_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400707 .type = TRACE_WAKE,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500708 .trace = trace_wake_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500709 .raw = trace_wake_raw,
710 .hex = trace_wake_hex,
711 .binary = trace_ctxwake_bin,
712};
713
714/* TRACE_SPECIAL */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200715static enum print_line_t trace_special_print(struct trace_iterator *iter,
716 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500717{
718 struct special_entry *field;
719
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200720 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500721
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200722 if (!trace_seq_printf(&iter->seq, "# %ld %ld %ld\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800723 field->arg1,
724 field->arg2,
725 field->arg3))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500726 return TRACE_TYPE_PARTIAL_LINE;
727
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200728 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500729}
730
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200731static enum print_line_t trace_special_hex(struct trace_iterator *iter,
732 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500733{
734 struct special_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200735 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500736
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200737 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500738
739 SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
740 SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
741 SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
742
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200743 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500744}
745
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200746static enum print_line_t trace_special_bin(struct trace_iterator *iter,
747 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500748{
749 struct special_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200750 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500751
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200752 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500753
754 SEQ_PUT_FIELD_RET(s, field->arg1);
755 SEQ_PUT_FIELD_RET(s, field->arg2);
756 SEQ_PUT_FIELD_RET(s, field->arg3);
757
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200758 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500759}
760
761static struct trace_event trace_special_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400762 .type = TRACE_SPECIAL,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500763 .trace = trace_special_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500764 .raw = trace_special_print,
765 .hex = trace_special_hex,
766 .binary = trace_special_bin,
767};
768
769/* TRACE_STACK */
770
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200771static enum print_line_t trace_stack_print(struct trace_iterator *iter,
772 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500773{
774 struct stack_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200775 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500776 int i;
777
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200778 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500779
780 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
781 if (i) {
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800782 if (!trace_seq_puts(s, " <= "))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500783 goto partial;
784
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800785 if (!seq_print_ip_sym(s, field->caller[i], flags))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500786 goto partial;
787 }
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800788 if (!trace_seq_puts(s, "\n"))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500789 goto partial;
790 }
791
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200792 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500793
794 partial:
795 return TRACE_TYPE_PARTIAL_LINE;
796}
797
798static struct trace_event trace_stack_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400799 .type = TRACE_STACK,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500800 .trace = trace_stack_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500801 .raw = trace_special_print,
802 .hex = trace_special_hex,
803 .binary = trace_special_bin,
804};
805
806/* TRACE_USER_STACK */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200807static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
808 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500809{
810 struct userstack_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200811 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500812
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200813 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500814
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800815 if (!seq_print_userip_objs(field, s, flags))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500816 goto partial;
817
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800818 if (!trace_seq_putc(s, '\n'))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500819 goto partial;
820
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200821 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500822
823 partial:
824 return TRACE_TYPE_PARTIAL_LINE;
825}
826
827static struct trace_event trace_user_stack_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400828 .type = TRACE_USER_STACK,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500829 .trace = trace_user_stack_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500830 .raw = trace_special_print,
831 .hex = trace_special_hex,
832 .binary = trace_special_bin,
833};
834
835/* TRACE_PRINT */
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100836static enum print_line_t
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100837trace_print_print(struct trace_iterator *iter, int flags)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100838{
839 struct trace_entry *entry = iter->ent;
840 struct trace_seq *s = &iter->seq;
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100841 struct print_entry *field;
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100842
843 trace_assign_type(field, entry);
844
845 if (!seq_print_ip_sym(s, field->ip, flags))
846 goto partial;
847
848 if (!trace_seq_puts(s, ": "))
849 goto partial;
850
851 if (!trace_seq_bprintf(s, field->fmt, field->buf))
852 goto partial;
853
854 return TRACE_TYPE_HANDLED;
855
856 partial:
857 return TRACE_TYPE_PARTIAL_LINE;
858}
859
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100860
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100861static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
862{
863 struct print_entry *field;
864 struct trace_seq *s = &iter->seq;
865
866 trace_assign_type(field, iter->ent);
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100867
868 if (!trace_seq_printf(s, ": %lx : ", field->ip))
869 goto partial;
870
871 if (!trace_seq_bprintf(s, field->fmt, field->buf))
872 goto partial;
873
874 return TRACE_TYPE_HANDLED;
875
876 partial:
877 return TRACE_TYPE_PARTIAL_LINE;
878}
879
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100880
881static struct trace_event trace_print_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400882 .type = TRACE_PRINT,
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100883 .trace = trace_print_print,
884 .raw = trace_print_raw,
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100885};
886
Steven Rostedtf633cef2008-12-23 23:24:13 -0500887static struct trace_event *events[] __initdata = {
888 &trace_fn_event,
889 &trace_ctx_event,
890 &trace_wake_event,
891 &trace_special_event,
892 &trace_stack_event,
893 &trace_user_stack_event,
894 &trace_print_event,
895 NULL
896};
897
898__init static int init_events(void)
899{
900 struct trace_event *event;
901 int i, ret;
902
903 for (i = 0; events[i]; i++) {
904 event = events[i];
905
906 ret = register_ftrace_event(event);
907 if (!ret) {
908 printk(KERN_WARNING "event %d failed to register\n",
909 event->type);
910 WARN_ON_ONCE(1);
911 }
912 }
913
914 return 0;
915}
916device_initcall(init_events);