blob: e5cf90fef34e928546b962a2afa5927e0f5964d4 [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
Steven Rostedt110bf2b2009-06-09 17:29:07 -040017DECLARE_RWSEM(trace_event_mutex);
Steven Rostedtbe74b732009-05-26 20:25:22 +020018
19DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
Steven Whitehouseec081dd2009-06-01 15:53:35 +010020EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
Steven Rostedtbe74b732009-05-26 20:25:22 +020021
Steven Rostedtf0868d12008-12-23 23:24:12 -050022static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
23
24static int next_event_type = __TRACE_LAST_TYPE + 1;
25
Steven Rostedta63ce5b2009-12-07 09:11:39 -050026int trace_print_seq(struct seq_file *m, struct trace_seq *s)
Steven Rostedt0706f1c2009-03-23 23:12:58 -040027{
28 int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
Steven Rostedta63ce5b2009-12-07 09:11:39 -050029 int ret;
Steven Rostedt0706f1c2009-03-23 23:12:58 -040030
Steven Rostedta63ce5b2009-12-07 09:11:39 -050031 ret = seq_write(m, s->buffer, len);
Steven Rostedt0706f1c2009-03-23 23:12:58 -040032
Steven Rostedta63ce5b2009-12-07 09:11:39 -050033 /*
34 * Only reset this buffer if we successfully wrote to the
35 * seq_file buffer.
36 */
37 if (!ret)
38 trace_seq_init(s);
39
40 return ret;
Steven Rostedt0706f1c2009-03-23 23:12:58 -040041}
42
Steven Rostedt5ef841f2009-03-19 12:20:38 -040043enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
44{
45 struct trace_seq *s = &iter->seq;
46 struct trace_entry *entry = iter->ent;
47 struct bprint_entry *field;
48 int ret;
49
50 trace_assign_type(field, entry);
51
52 ret = trace_seq_bprintf(s, field->fmt, field->buf);
53 if (!ret)
54 return TRACE_TYPE_PARTIAL_LINE;
55
56 return TRACE_TYPE_HANDLED;
57}
58
59enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
60{
61 struct trace_seq *s = &iter->seq;
62 struct trace_entry *entry = iter->ent;
63 struct print_entry *field;
64 int ret;
65
66 trace_assign_type(field, entry);
67
68 ret = trace_seq_printf(s, "%s", field->buf);
69 if (!ret)
70 return TRACE_TYPE_PARTIAL_LINE;
71
72 return TRACE_TYPE_HANDLED;
73}
74
Steven Rostedtf0868d12008-12-23 23:24:12 -050075/**
76 * trace_seq_printf - sequence printing of trace information
77 * @s: trace sequence descriptor
78 * @fmt: printf format string
79 *
Jiri Olsa3e695332009-10-23 19:36:17 -040080 * It returns 0 if the trace oversizes the buffer's free
81 * space, 1 otherwise.
82 *
Steven Rostedtf0868d12008-12-23 23:24:12 -050083 * The tracer may use either sequence operations or its own
84 * copy to user routines. To simplify formating of a trace
85 * trace_seq_printf is used to store strings into a special
86 * buffer (@s). Then the output may be either used by
87 * the sequencer or pulled into another buffer.
88 */
89int
90trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
91{
92 int len = (PAGE_SIZE - 1) - s->len;
93 va_list ap;
94 int ret;
95
96 if (!len)
97 return 0;
98
99 va_start(ap, fmt);
100 ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
101 va_end(ap);
102
103 /* If we can't write it all, don't bother writing anything */
104 if (ret >= len)
105 return 0;
106
107 s->len += ret;
108
Jiri Olsa3e695332009-10-23 19:36:17 -0400109 return 1;
Steven Rostedtf0868d12008-12-23 23:24:12 -0500110}
Steven Rostedt17c873e2009-04-10 18:12:50 -0400111EXPORT_SYMBOL_GPL(trace_seq_printf);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500112
Steven Rostedt725c6242009-06-08 19:09:45 -0400113/**
114 * trace_seq_vprintf - sequence printing of trace information
115 * @s: trace sequence descriptor
116 * @fmt: printf format string
117 *
118 * The tracer may use either sequence operations or its own
119 * copy to user routines. To simplify formating of a trace
120 * trace_seq_printf is used to store strings into a special
121 * buffer (@s). Then the output may be either used by
122 * the sequencer or pulled into another buffer.
123 */
124int
125trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
126{
127 int len = (PAGE_SIZE - 1) - s->len;
128 int ret;
129
130 if (!len)
131 return 0;
132
133 ret = vsnprintf(s->buffer + s->len, len, fmt, args);
134
135 /* If we can't write it all, don't bother writing anything */
136 if (ret >= len)
137 return 0;
138
139 s->len += ret;
140
141 return len;
142}
143EXPORT_SYMBOL_GPL(trace_seq_vprintf);
144
Frederic Weisbecker769b0442009-03-06 17:21:49 +0100145int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100146{
147 int len = (PAGE_SIZE - 1) - s->len;
148 int ret;
149
150 if (!len)
151 return 0;
152
153 ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
154
155 /* If we can't write it all, don't bother writing anything */
156 if (ret >= len)
157 return 0;
158
159 s->len += ret;
160
161 return len;
162}
163
Steven Rostedtf0868d12008-12-23 23:24:12 -0500164/**
165 * trace_seq_puts - trace sequence printing of simple string
166 * @s: trace sequence descriptor
167 * @str: simple string to record
168 *
169 * The tracer may use either the sequence operations or its own
170 * copy to user routines. This function records a simple string
171 * into a special buffer (@s) for later retrieval by a sequencer
172 * or other mechanism.
173 */
174int trace_seq_puts(struct trace_seq *s, const char *str)
175{
176 int len = strlen(str);
177
178 if (len > ((PAGE_SIZE - 1) - s->len))
179 return 0;
180
181 memcpy(s->buffer + s->len, str, len);
182 s->len += len;
183
184 return len;
185}
186
187int trace_seq_putc(struct trace_seq *s, unsigned char c)
188{
189 if (s->len >= (PAGE_SIZE - 1))
190 return 0;
191
192 s->buffer[s->len++] = c;
193
194 return 1;
195}
196
Li Zefanb14b70a2009-03-27 10:21:00 +0800197int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
Steven Rostedtf0868d12008-12-23 23:24:12 -0500198{
199 if (len > ((PAGE_SIZE - 1) - s->len))
200 return 0;
201
202 memcpy(s->buffer + s->len, mem, len);
203 s->len += len;
204
205 return len;
206}
207
Li Zefanb14b70a2009-03-27 10:21:00 +0800208int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len)
Steven Rostedtf0868d12008-12-23 23:24:12 -0500209{
210 unsigned char hex[HEX_CHARS];
Li Zefanb14b70a2009-03-27 10:21:00 +0800211 const unsigned char *data = mem;
Steven Rostedtf0868d12008-12-23 23:24:12 -0500212 int i, j;
213
214#ifdef __BIG_ENDIAN
215 for (i = 0, j = 0; i < len; i++) {
216#else
217 for (i = len-1, j = 0; i >= 0; i--) {
218#endif
219 hex[j++] = hex_asc_hi(data[i]);
220 hex[j++] = hex_asc_lo(data[i]);
221 }
222 hex[j++] = ' ';
223
224 return trace_seq_putmem(s, hex, j);
225}
226
Eduard - Gabriel Munteanubdd6df62009-03-23 15:12:22 +0200227void *trace_seq_reserve(struct trace_seq *s, size_t len)
228{
229 void *ret;
230
231 if (len > ((PAGE_SIZE - 1) - s->len))
232 return NULL;
233
234 ret = s->buffer + s->len;
235 s->len += len;
236
237 return ret;
238}
239
Steven Rostedtf0868d12008-12-23 23:24:12 -0500240int trace_seq_path(struct trace_seq *s, struct path *path)
241{
242 unsigned char *p;
243
244 if (s->len >= (PAGE_SIZE - 1))
245 return 0;
246 p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
247 if (!IS_ERR(p)) {
248 p = mangle_path(s->buffer + s->len, p, "\n");
249 if (p) {
250 s->len = p - s->buffer;
251 return 1;
252 }
253 } else {
254 s->buffer[s->len++] = '?';
255 return 1;
256 }
257
258 return 0;
259}
260
Steven Rostedtbe74b732009-05-26 20:25:22 +0200261const char *
262ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
263 unsigned long flags,
264 const struct trace_print_flags *flag_array)
265{
266 unsigned long mask;
267 const char *str;
Steven Whitehouse56d8bd32009-06-03 14:52:03 +0100268 const char *ret = p->buffer + p->len;
Steven Rostedtbe74b732009-05-26 20:25:22 +0200269 int i;
270
Steven Rostedtbe74b732009-05-26 20:25:22 +0200271 for (i = 0; flag_array[i].name && flags; i++) {
272
273 mask = flag_array[i].mask;
274 if ((flags & mask) != mask)
275 continue;
276
277 str = flag_array[i].name;
278 flags &= ~mask;
279 if (p->len && delim)
280 trace_seq_puts(p, delim);
281 trace_seq_puts(p, str);
282 }
283
284 /* check for left over flags */
285 if (flags) {
286 if (p->len && delim)
287 trace_seq_puts(p, delim);
288 trace_seq_printf(p, "0x%lx", flags);
289 }
290
291 trace_seq_putc(p, 0);
292
Steven Whitehouse56d8bd32009-06-03 14:52:03 +0100293 return ret;
Steven Rostedtbe74b732009-05-26 20:25:22 +0200294}
Steven Whitehouseec081dd2009-06-01 15:53:35 +0100295EXPORT_SYMBOL(ftrace_print_flags_seq);
Steven Rostedtbe74b732009-05-26 20:25:22 +0200296
Steven Rostedt0f4fc292009-05-20 19:21:47 -0400297const char *
298ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
299 const struct trace_print_flags *symbol_array)
300{
301 int i;
Steven Whitehouse56d8bd32009-06-03 14:52:03 +0100302 const char *ret = p->buffer + p->len;
Steven Rostedt0f4fc292009-05-20 19:21:47 -0400303
304 for (i = 0; symbol_array[i].name; i++) {
305
306 if (val != symbol_array[i].mask)
307 continue;
308
309 trace_seq_puts(p, symbol_array[i].name);
310 break;
311 }
312
313 if (!p->len)
314 trace_seq_printf(p, "0x%lx", val);
315
316 trace_seq_putc(p, 0);
317
Steven Whitehouse56d8bd32009-06-03 14:52:03 +0100318 return ret;
Steven Rostedt0f4fc292009-05-20 19:21:47 -0400319}
Steven Whitehouseec081dd2009-06-01 15:53:35 +0100320EXPORT_SYMBOL(ftrace_print_symbols_seq);
Steven Rostedt0f4fc292009-05-20 19:21:47 -0400321
Steven Rostedtf0868d12008-12-23 23:24:12 -0500322#ifdef CONFIG_KRETPROBES
323static inline const char *kretprobed(const char *name)
324{
325 static const char tramp_name[] = "kretprobe_trampoline";
326 int size = sizeof(tramp_name);
327
328 if (strncmp(tramp_name, name, size) == 0)
329 return "[unknown/kretprobe'd]";
330 return name;
331}
332#else
333static inline const char *kretprobed(const char *name)
334{
335 return name;
336}
337#endif /* CONFIG_KRETPROBES */
338
339static int
340seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
341{
342#ifdef CONFIG_KALLSYMS
343 char str[KSYM_SYMBOL_LEN];
344 const char *name;
345
346 kallsyms_lookup(address, NULL, NULL, NULL, str);
347
348 name = kretprobed(str);
349
350 return trace_seq_printf(s, fmt, name);
351#endif
352 return 1;
353}
354
355static int
356seq_print_sym_offset(struct trace_seq *s, const char *fmt,
357 unsigned long address)
358{
359#ifdef CONFIG_KALLSYMS
360 char str[KSYM_SYMBOL_LEN];
361 const char *name;
362
363 sprint_symbol(str, address);
364 name = kretprobed(str);
365
366 return trace_seq_printf(s, fmt, name);
367#endif
368 return 1;
369}
370
371#ifndef CONFIG_64BIT
372# define IP_FMT "%08lx"
373#else
374# define IP_FMT "%016lx"
375#endif
376
377int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
378 unsigned long ip, unsigned long sym_flags)
379{
380 struct file *file = NULL;
381 unsigned long vmstart = 0;
382 int ret = 1;
383
384 if (mm) {
385 const struct vm_area_struct *vma;
386
387 down_read(&mm->mmap_sem);
388 vma = find_vma(mm, ip);
389 if (vma) {
390 file = vma->vm_file;
391 vmstart = vma->vm_start;
392 }
393 if (file) {
394 ret = trace_seq_path(s, &file->f_path);
395 if (ret)
396 ret = trace_seq_printf(s, "[+0x%lx]",
397 ip - vmstart);
398 }
399 up_read(&mm->mmap_sem);
400 }
401 if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
402 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
403 return ret;
404}
405
406int
407seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
408 unsigned long sym_flags)
409{
410 struct mm_struct *mm = NULL;
411 int ret = 1;
412 unsigned int i;
413
414 if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
415 struct task_struct *task;
416 /*
417 * we do the lookup on the thread group leader,
418 * since individual threads might have already quit!
419 */
420 rcu_read_lock();
Steven Rostedt48659d32009-09-11 11:36:23 -0400421 task = find_task_by_vpid(entry->tgid);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500422 if (task)
423 mm = get_task_mm(task);
424 rcu_read_unlock();
425 }
426
427 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
428 unsigned long ip = entry->caller[i];
429
430 if (ip == ULONG_MAX || !ret)
431 break;
walimis048dc502009-06-03 16:01:30 +0800432 if (ret)
433 ret = trace_seq_puts(s, " => ");
Steven Rostedtf0868d12008-12-23 23:24:12 -0500434 if (!ip) {
435 if (ret)
436 ret = trace_seq_puts(s, "??");
walimis048dc502009-06-03 16:01:30 +0800437 if (ret)
438 ret = trace_seq_puts(s, "\n");
Steven Rostedtf0868d12008-12-23 23:24:12 -0500439 continue;
440 }
441 if (!ret)
442 break;
443 if (ret)
444 ret = seq_print_user_ip(s, mm, ip, sym_flags);
walimis048dc502009-06-03 16:01:30 +0800445 ret = trace_seq_puts(s, "\n");
Steven Rostedtf0868d12008-12-23 23:24:12 -0500446 }
447
448 if (mm)
449 mmput(mm);
450 return ret;
451}
452
453int
454seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
455{
456 int ret;
457
458 if (!ip)
459 return trace_seq_printf(s, "0");
460
461 if (sym_flags & TRACE_ITER_SYM_OFFSET)
462 ret = seq_print_sym_offset(s, "%s", ip);
463 else
464 ret = seq_print_sym_short(s, "%s", ip);
465
466 if (!ret)
467 return 0;
468
469 if (sym_flags & TRACE_ITER_SYM_ADDR)
470 ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
471 return ret;
472}
473
Steven Rostedtf81c9722009-09-11 14:24:13 -0400474/**
475 * trace_print_lat_fmt - print the irq, preempt and lockdep fields
476 * @s: trace seq struct to write to
477 * @entry: The trace entry field from the ring buffer
478 *
479 * Prints the generic fields of irqs off, in hard or softirq, preempt
480 * count and lock depth.
481 */
482int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200483{
484 int hardirq, softirq;
Steven Rostedt637e7e82009-09-11 13:55:35 -0400485 int ret;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200486
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200487 hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
488 softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200489
Steven Rostedtf81c9722009-09-11 14:24:13 -0400490 if (!trace_seq_printf(s, "%c%c%c",
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200491 (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
492 (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
493 'X' : '.',
494 (entry->flags & TRACE_FLAG_NEED_RESCHED) ?
495 'N' : '.',
496 (hardirq && softirq) ? 'H' :
497 hardirq ? 'h' : softirq ? 's' : '.'))
498 return 0;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200499
Steven Rostedt829b8762009-09-27 07:02:07 -0400500 if (entry->preempt_count)
501 ret = trace_seq_printf(s, "%x", entry->preempt_count);
Steven Rostedt637e7e82009-09-11 13:55:35 -0400502 else
Steven Rostedt829b8762009-09-27 07:02:07 -0400503 ret = trace_seq_putc(s, '.');
504
Steven Rostedt637e7e82009-09-11 13:55:35 -0400505 if (!ret)
506 return 0;
507
Steven Rostedt829b8762009-09-27 07:02:07 -0400508 if (entry->lock_depth < 0)
509 return trace_seq_putc(s, '.');
510
511 return trace_seq_printf(s, "%d", entry->lock_depth);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200512}
513
Steven Rostedtf81c9722009-09-11 14:24:13 -0400514static int
515lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
516{
517 char comm[TASK_COMM_LEN];
518
519 trace_find_cmdline(entry->pid, comm);
520
521 if (!trace_seq_printf(s, "%8.8s-%-5d %3d",
522 comm, entry->pid, cpu))
523 return 0;
524
525 return trace_print_lat_fmt(s, entry);
526}
527
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200528static unsigned long preempt_mark_thresh = 100;
529
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200530static int
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200531lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
532 unsigned long rel_usecs)
533{
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200534 return trace_seq_printf(s, " %4lldus%c: ", abs_usecs,
535 rel_usecs > preempt_mark_thresh ? '!' :
536 rel_usecs > 1 ? '+' : ' ');
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200537}
538
539int trace_print_context(struct trace_iterator *iter)
540{
541 struct trace_seq *s = &iter->seq;
542 struct trace_entry *entry = iter->ent;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200543 unsigned long long t = ns2usecs(iter->ts);
544 unsigned long usec_rem = do_div(t, USEC_PER_SEC);
545 unsigned long secs = (unsigned long)t;
Steven Rostedt4ca53082009-03-16 19:20:15 -0400546 char comm[TASK_COMM_LEN];
547
548 trace_find_cmdline(entry->pid, comm);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200549
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200550 return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ",
Steven Rostedt1830b52d2009-02-07 19:38:43 -0500551 comm, entry->pid, iter->cpu, secs, usec_rem);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200552}
553
554int trace_print_lat_context(struct trace_iterator *iter)
555{
556 u64 next_ts;
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200557 int ret;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200558 struct trace_seq *s = &iter->seq;
559 struct trace_entry *entry = iter->ent,
560 *next_entry = trace_find_next_entry(iter, NULL,
561 &next_ts);
562 unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
563 unsigned long abs_usecs = ns2usecs(iter->ts - iter->tr->time_start);
564 unsigned long rel_usecs;
565
566 if (!next_entry)
567 next_ts = iter->ts;
568 rel_usecs = ns2usecs(next_ts - iter->ts);
569
570 if (verbose) {
Steven Rostedt4ca53082009-03-16 19:20:15 -0400571 char comm[TASK_COMM_LEN];
572
573 trace_find_cmdline(entry->pid, comm);
574
Lai Jiangshancf8e3472009-03-30 13:48:00 +0800575 ret = trace_seq_printf(s, "%16s %5d %3d %d %08x %08lx [%08llx]"
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200576 " %ld.%03ldms (+%ld.%03ldms): ", comm,
Steven Rostedt1830b52d2009-02-07 19:38:43 -0500577 entry->pid, iter->cpu, entry->flags,
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200578 entry->preempt_count, iter->idx,
579 ns2usecs(iter->ts),
580 abs_usecs / USEC_PER_MSEC,
581 abs_usecs % USEC_PER_MSEC,
582 rel_usecs / USEC_PER_MSEC,
583 rel_usecs % USEC_PER_MSEC);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200584 } else {
Steven Rostedt1830b52d2009-02-07 19:38:43 -0500585 ret = lat_print_generic(s, entry, iter->cpu);
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200586 if (ret)
587 ret = lat_print_timestamp(s, abs_usecs, rel_usecs);
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200588 }
589
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200590 return ret;
Frederic Weisbeckerc4a8e8b2009-02-02 20:29:21 -0200591}
592
Steven Rostedtf633cef2008-12-23 23:24:13 -0500593static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
594
595static int task_state_char(unsigned long state)
596{
597 int bit = state ? __ffs(state) + 1 : 0;
598
599 return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
600}
601
Steven Rostedtf0868d12008-12-23 23:24:12 -0500602/**
603 * ftrace_find_event - find a registered event
604 * @type: the type of event to look for
605 *
606 * Returns an event of type @type otherwise NULL
Lai Jiangshan4f535962009-05-18 19:35:34 +0800607 * Called with trace_event_read_lock() held.
Steven Rostedtf0868d12008-12-23 23:24:12 -0500608 */
609struct trace_event *ftrace_find_event(int type)
610{
611 struct trace_event *event;
612 struct hlist_node *n;
613 unsigned key;
614
615 key = type & (EVENT_HASHSIZE - 1);
616
Lai Jiangshan4f535962009-05-18 19:35:34 +0800617 hlist_for_each_entry(event, n, &event_hash[key], node) {
Steven Rostedtf0868d12008-12-23 23:24:12 -0500618 if (event->type == type)
619 return event;
620 }
621
622 return NULL;
623}
624
Steven Rostedt060fa5c82009-04-24 12:20:52 -0400625static LIST_HEAD(ftrace_event_list);
626
627static int trace_search_list(struct list_head **list)
628{
629 struct trace_event *e;
630 int last = __TRACE_LAST_TYPE;
631
632 if (list_empty(&ftrace_event_list)) {
633 *list = &ftrace_event_list;
634 return last + 1;
635 }
636
637 /*
638 * We used up all possible max events,
639 * lets see if somebody freed one.
640 */
641 list_for_each_entry(e, &ftrace_event_list, list) {
642 if (e->type != last + 1)
643 break;
644 last++;
645 }
646
647 /* Did we used up all 65 thousand events??? */
648 if ((last + 1) > FTRACE_MAX_EVENT)
649 return 0;
650
651 *list = &e->list;
652 return last + 1;
653}
654
Lai Jiangshan4f535962009-05-18 19:35:34 +0800655void trace_event_read_lock(void)
656{
657 down_read(&trace_event_mutex);
658}
659
660void trace_event_read_unlock(void)
661{
662 up_read(&trace_event_mutex);
663}
664
Steven Rostedtf0868d12008-12-23 23:24:12 -0500665/**
666 * register_ftrace_event - register output for an event type
667 * @event: the event type to register
668 *
669 * Event types are stored in a hash and this hash is used to
670 * find a way to print an event. If the @event->type is set
671 * then it will use that type, otherwise it will assign a
672 * type to use.
673 *
674 * If you assign your own type, please make sure it is added
675 * to the trace_type enum in trace.h, to avoid collisions
676 * with the dynamic types.
677 *
678 * Returns the event type number or zero on error.
679 */
680int register_ftrace_event(struct trace_event *event)
681{
682 unsigned key;
683 int ret = 0;
684
Lai Jiangshan4f535962009-05-18 19:35:34 +0800685 down_write(&trace_event_mutex);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500686
Steven Rostedt060fa5c82009-04-24 12:20:52 -0400687 if (WARN_ON(!event))
Peter Zijlstra28bea272009-03-19 20:26:14 +0100688 goto out;
Peter Zijlstra28bea272009-03-19 20:26:14 +0100689
Steven Rostedt060fa5c82009-04-24 12:20:52 -0400690 INIT_LIST_HEAD(&event->list);
691
692 if (!event->type) {
Jaswinder Singh Rajput48dd0fe2009-05-06 15:45:45 +0530693 struct list_head *list = NULL;
Steven Rostedt060fa5c82009-04-24 12:20:52 -0400694
695 if (next_event_type > FTRACE_MAX_EVENT) {
696
697 event->type = trace_search_list(&list);
698 if (!event->type)
699 goto out;
700
701 } else {
702
703 event->type = next_event_type++;
704 list = &ftrace_event_list;
705 }
706
707 if (WARN_ON(ftrace_find_event(event->type)))
708 goto out;
709
710 list_add_tail(&event->list, list);
711
712 } else if (event->type > __TRACE_LAST_TYPE) {
Steven Rostedtf0868d12008-12-23 23:24:12 -0500713 printk(KERN_WARNING "Need to add type to trace.h\n");
714 WARN_ON(1);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500715 goto out;
Steven Rostedt060fa5c82009-04-24 12:20:52 -0400716 } else {
717 /* Is this event already used */
718 if (ftrace_find_event(event->type))
719 goto out;
720 }
Steven Rostedtf0868d12008-12-23 23:24:12 -0500721
Arnaldo Carvalho de Melo268ccda2009-02-04 20:16:39 -0200722 if (event->trace == NULL)
723 event->trace = trace_nop_print;
Arnaldo Carvalho de Melo268ccda2009-02-04 20:16:39 -0200724 if (event->raw == NULL)
725 event->raw = trace_nop_print;
726 if (event->hex == NULL)
727 event->hex = trace_nop_print;
728 if (event->binary == NULL)
729 event->binary = trace_nop_print;
730
Steven Rostedtf0868d12008-12-23 23:24:12 -0500731 key = event->type & (EVENT_HASHSIZE - 1);
732
Lai Jiangshan4f535962009-05-18 19:35:34 +0800733 hlist_add_head(&event->node, &event_hash[key]);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500734
735 ret = event->type;
736 out:
Lai Jiangshan4f535962009-05-18 19:35:34 +0800737 up_write(&trace_event_mutex);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500738
739 return ret;
740}
Steven Rostedt17c873e2009-04-10 18:12:50 -0400741EXPORT_SYMBOL_GPL(register_ftrace_event);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500742
Steven Rostedt110bf2b2009-06-09 17:29:07 -0400743/*
744 * Used by module code with the trace_event_mutex held for write.
745 */
746int __unregister_ftrace_event(struct trace_event *event)
747{
748 hlist_del(&event->node);
749 list_del(&event->list);
750 return 0;
751}
752
Steven Rostedtf0868d12008-12-23 23:24:12 -0500753/**
754 * unregister_ftrace_event - remove a no longer used event
755 * @event: the event to remove
756 */
757int unregister_ftrace_event(struct trace_event *event)
758{
Lai Jiangshan4f535962009-05-18 19:35:34 +0800759 down_write(&trace_event_mutex);
Steven Rostedt110bf2b2009-06-09 17:29:07 -0400760 __unregister_ftrace_event(event);
Lai Jiangshan4f535962009-05-18 19:35:34 +0800761 up_write(&trace_event_mutex);
Steven Rostedtf0868d12008-12-23 23:24:12 -0500762
763 return 0;
764}
Steven Rostedt17c873e2009-04-10 18:12:50 -0400765EXPORT_SYMBOL_GPL(unregister_ftrace_event);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500766
767/*
768 * Standard events
769 */
770
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200771enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500772{
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200773 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500774}
775
776/* TRACE_FN */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200777static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500778{
779 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200780 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500781
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200782 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500783
784 if (!seq_print_ip_sym(s, field->ip, flags))
785 goto partial;
786
787 if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
788 if (!trace_seq_printf(s, " <-"))
789 goto partial;
790 if (!seq_print_ip_sym(s,
791 field->parent_ip,
792 flags))
793 goto partial;
794 }
795 if (!trace_seq_printf(s, "\n"))
796 goto partial;
797
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200798 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500799
800 partial:
801 return TRACE_TYPE_PARTIAL_LINE;
802}
803
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200804static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500805{
806 struct ftrace_entry *field;
807
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200808 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500809
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200810 if (!trace_seq_printf(&iter->seq, "%lx %lx\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800811 field->ip,
812 field->parent_ip))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500813 return TRACE_TYPE_PARTIAL_LINE;
814
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200815 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500816}
817
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200818static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500819{
820 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200821 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500822
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200823 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500824
825 SEQ_PUT_HEX_FIELD_RET(s, field->ip);
826 SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
827
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200828 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500829}
830
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200831static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500832{
833 struct ftrace_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200834 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500835
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200836 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500837
838 SEQ_PUT_FIELD_RET(s, field->ip);
839 SEQ_PUT_FIELD_RET(s, field->parent_ip);
840
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200841 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500842}
843
844static struct trace_event trace_fn_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400845 .type = TRACE_FN,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500846 .trace = trace_fn_trace,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500847 .raw = trace_fn_raw,
848 .hex = trace_fn_hex,
849 .binary = trace_fn_bin,
850};
851
852/* TRACE_CTX an TRACE_WAKE */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200853static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
854 char *delim)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500855{
856 struct ctx_switch_entry *field;
Steven Rostedt4ca53082009-03-16 19:20:15 -0400857 char comm[TASK_COMM_LEN];
Steven Rostedtf633cef2008-12-23 23:24:13 -0500858 int S, T;
859
Steven Rostedt4ca53082009-03-16 19:20:15 -0400860
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200861 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500862
863 T = task_state_char(field->next_state);
864 S = task_state_char(field->prev_state);
Steven Rostedt4ca53082009-03-16 19:20:15 -0400865 trace_find_cmdline(field->next_pid, comm);
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200866 if (!trace_seq_printf(&iter->seq,
867 " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800868 field->prev_pid,
869 field->prev_prio,
870 S, delim,
871 field->next_cpu,
872 field->next_pid,
873 field->next_prio,
874 T, comm))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500875 return TRACE_TYPE_PARTIAL_LINE;
876
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200877 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500878}
879
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200880static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500881{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200882 return trace_ctxwake_print(iter, "==>");
Steven Rostedtf633cef2008-12-23 23:24:13 -0500883}
884
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200885static enum print_line_t trace_wake_print(struct trace_iterator *iter,
886 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500887{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200888 return trace_ctxwake_print(iter, " +");
Steven Rostedtf633cef2008-12-23 23:24:13 -0500889}
890
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200891static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500892{
893 struct ctx_switch_entry *field;
894 int T;
895
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200896 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500897
898 if (!S)
Hiroshi Shimamotob0f56f12009-10-01 13:33:28 +0900899 S = task_state_char(field->prev_state);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500900 T = task_state_char(field->next_state);
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200901 if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +0800902 field->prev_pid,
903 field->prev_prio,
904 S,
905 field->next_cpu,
906 field->next_pid,
907 field->next_prio,
908 T))
Steven Rostedtf633cef2008-12-23 23:24:13 -0500909 return TRACE_TYPE_PARTIAL_LINE;
910
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200911 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500912}
913
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200914static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500915{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200916 return trace_ctxwake_raw(iter, 0);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500917}
918
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200919static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500920{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200921 return trace_ctxwake_raw(iter, '+');
Steven Rostedtf633cef2008-12-23 23:24:13 -0500922}
923
924
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200925static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500926{
927 struct ctx_switch_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200928 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500929 int T;
930
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200931 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500932
933 if (!S)
Hiroshi Shimamotob0f56f12009-10-01 13:33:28 +0900934 S = task_state_char(field->prev_state);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500935 T = task_state_char(field->next_state);
936
937 SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
938 SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
939 SEQ_PUT_HEX_FIELD_RET(s, S);
940 SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
941 SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
942 SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
943 SEQ_PUT_HEX_FIELD_RET(s, T);
944
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200945 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500946}
947
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200948static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500949{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200950 return trace_ctxwake_hex(iter, 0);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500951}
952
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200953static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500954{
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200955 return trace_ctxwake_hex(iter, '+');
Steven Rostedtf633cef2008-12-23 23:24:13 -0500956}
957
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200958static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
959 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500960{
961 struct ctx_switch_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200962 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500963
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200964 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500965
966 SEQ_PUT_FIELD_RET(s, field->prev_pid);
967 SEQ_PUT_FIELD_RET(s, field->prev_prio);
968 SEQ_PUT_FIELD_RET(s, field->prev_state);
969 SEQ_PUT_FIELD_RET(s, field->next_pid);
970 SEQ_PUT_FIELD_RET(s, field->next_prio);
971 SEQ_PUT_FIELD_RET(s, field->next_state);
972
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -0200973 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -0500974}
975
976static struct trace_event trace_ctx_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400977 .type = TRACE_CTX,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500978 .trace = trace_ctx_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500979 .raw = trace_ctx_raw,
980 .hex = trace_ctx_hex,
981 .binary = trace_ctxwake_bin,
982};
983
984static struct trace_event trace_wake_event = {
Steven Rostedtef180122009-03-10 14:10:56 -0400985 .type = TRACE_WAKE,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500986 .trace = trace_wake_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -0500987 .raw = trace_wake_raw,
988 .hex = trace_wake_hex,
989 .binary = trace_ctxwake_bin,
990};
991
992/* TRACE_SPECIAL */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -0200993static enum print_line_t trace_special_print(struct trace_iterator *iter,
994 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -0500995{
996 struct special_entry *field;
997
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -0200998 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -0500999
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001000 if (!trace_seq_printf(&iter->seq, "# %ld %ld %ld\n",
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +08001001 field->arg1,
1002 field->arg2,
1003 field->arg3))
Steven Rostedtf633cef2008-12-23 23:24:13 -05001004 return TRACE_TYPE_PARTIAL_LINE;
1005
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -02001006 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001007}
1008
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -02001009static enum print_line_t trace_special_hex(struct trace_iterator *iter,
1010 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -05001011{
1012 struct special_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001013 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001014
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001015 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -05001016
1017 SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
1018 SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
1019 SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
1020
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -02001021 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001022}
1023
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -02001024static enum print_line_t trace_special_bin(struct trace_iterator *iter,
1025 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -05001026{
1027 struct special_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001028 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001029
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001030 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -05001031
1032 SEQ_PUT_FIELD_RET(s, field->arg1);
1033 SEQ_PUT_FIELD_RET(s, field->arg2);
1034 SEQ_PUT_FIELD_RET(s, field->arg3);
1035
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -02001036 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001037}
1038
1039static struct trace_event trace_special_event = {
Steven Rostedtef180122009-03-10 14:10:56 -04001040 .type = TRACE_SPECIAL,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001041 .trace = trace_special_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001042 .raw = trace_special_print,
1043 .hex = trace_special_hex,
1044 .binary = trace_special_bin,
1045};
1046
1047/* TRACE_STACK */
1048
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -02001049static enum print_line_t trace_stack_print(struct trace_iterator *iter,
1050 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -05001051{
1052 struct stack_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001053 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001054 int i;
1055
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001056 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -05001057
Steven Rostedt563af162009-06-03 11:10:44 -04001058 if (!trace_seq_puts(s, "<stack trace>\n"))
walimisf11b3f42009-06-03 16:01:29 +08001059 goto partial;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001060 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
walimisf11b3f42009-06-03 16:01:29 +08001061 if (!field->caller[i] || (field->caller[i] == ULONG_MAX))
Steven Rostedt1ec7c482009-05-14 23:40:06 -04001062 break;
walimisf11b3f42009-06-03 16:01:29 +08001063 if (!trace_seq_puts(s, " => "))
1064 goto partial;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001065
walimisf11b3f42009-06-03 16:01:29 +08001066 if (!seq_print_ip_sym(s, field->caller[i], flags))
1067 goto partial;
Lai Jiangshan6c1a99a2009-01-15 18:05:40 +08001068 if (!trace_seq_puts(s, "\n"))
Steven Rostedtf633cef2008-12-23 23:24:13 -05001069 goto partial;
1070 }
1071
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -02001072 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001073
1074 partial:
1075 return TRACE_TYPE_PARTIAL_LINE;
1076}
1077
1078static struct trace_event trace_stack_event = {
Steven Rostedtef180122009-03-10 14:10:56 -04001079 .type = TRACE_STACK,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001080 .trace = trace_stack_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001081 .raw = trace_special_print,
1082 .hex = trace_special_hex,
1083 .binary = trace_special_bin,
1084};
1085
1086/* TRACE_USER_STACK */
Arnaldo Carvalho de Meloae7462b2009-02-03 22:05:50 -02001087static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
1088 int flags)
Steven Rostedtf633cef2008-12-23 23:24:13 -05001089{
1090 struct userstack_entry *field;
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001091 struct trace_seq *s = &iter->seq;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001092
Arnaldo Carvalho de Melo2c9b2382009-02-02 20:30:12 -02001093 trace_assign_type(field, iter->ent);
Steven Rostedtf633cef2008-12-23 23:24:13 -05001094
Steven Rostedt563af162009-06-03 11:10:44 -04001095 if (!trace_seq_puts(s, "<user stack trace>\n"))
Steven Rostedtf633cef2008-12-23 23:24:13 -05001096 goto partial;
1097
walimis048dc502009-06-03 16:01:30 +08001098 if (!seq_print_userip_objs(field, s, flags))
Steven Rostedtf633cef2008-12-23 23:24:13 -05001099 goto partial;
1100
Arnaldo Carvalho de Melod9793bd2009-02-03 20:20:41 -02001101 return TRACE_TYPE_HANDLED;
Steven Rostedtf633cef2008-12-23 23:24:13 -05001102
1103 partial:
1104 return TRACE_TYPE_PARTIAL_LINE;
1105}
1106
1107static struct trace_event trace_user_stack_event = {
Steven Rostedtef180122009-03-10 14:10:56 -04001108 .type = TRACE_USER_STACK,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001109 .trace = trace_user_stack_print,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001110 .raw = trace_special_print,
1111 .hex = trace_special_hex,
1112 .binary = trace_special_bin,
1113};
1114
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001115/* TRACE_BPRINT */
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001116static enum print_line_t
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001117trace_bprint_print(struct trace_iterator *iter, int flags)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001118{
1119 struct trace_entry *entry = iter->ent;
1120 struct trace_seq *s = &iter->seq;
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001121 struct bprint_entry *field;
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001122
1123 trace_assign_type(field, entry);
1124
1125 if (!seq_print_ip_sym(s, field->ip, flags))
1126 goto partial;
1127
1128 if (!trace_seq_puts(s, ": "))
1129 goto partial;
1130
1131 if (!trace_seq_bprintf(s, field->fmt, field->buf))
1132 goto partial;
1133
1134 return TRACE_TYPE_HANDLED;
1135
1136 partial:
1137 return TRACE_TYPE_PARTIAL_LINE;
1138}
1139
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001140
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001141static enum print_line_t
1142trace_bprint_raw(struct trace_iterator *iter, int flags)
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001143{
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001144 struct bprint_entry *field;
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001145 struct trace_seq *s = &iter->seq;
1146
1147 trace_assign_type(field, iter->ent);
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001148
1149 if (!trace_seq_printf(s, ": %lx : ", field->ip))
1150 goto partial;
1151
1152 if (!trace_seq_bprintf(s, field->fmt, field->buf))
1153 goto partial;
1154
1155 return TRACE_TYPE_HANDLED;
1156
1157 partial:
1158 return TRACE_TYPE_PARTIAL_LINE;
1159}
1160
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001161
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001162static struct trace_event trace_bprint_event = {
1163 .type = TRACE_BPRINT,
1164 .trace = trace_bprint_print,
1165 .raw = trace_bprint_raw,
1166};
1167
1168/* TRACE_PRINT */
1169static enum print_line_t trace_print_print(struct trace_iterator *iter,
1170 int flags)
1171{
1172 struct print_entry *field;
1173 struct trace_seq *s = &iter->seq;
1174
1175 trace_assign_type(field, iter->ent);
1176
1177 if (!seq_print_ip_sym(s, field->ip, flags))
1178 goto partial;
1179
1180 if (!trace_seq_printf(s, ": %s", field->buf))
1181 goto partial;
1182
1183 return TRACE_TYPE_HANDLED;
1184
1185 partial:
1186 return TRACE_TYPE_PARTIAL_LINE;
1187}
1188
1189static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
1190{
1191 struct print_entry *field;
1192
1193 trace_assign_type(field, iter->ent);
1194
1195 if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf))
1196 goto partial;
1197
1198 return TRACE_TYPE_HANDLED;
1199
1200 partial:
1201 return TRACE_TYPE_PARTIAL_LINE;
1202}
1203
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001204static struct trace_event trace_print_event = {
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001205 .type = TRACE_PRINT,
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001206 .trace = trace_print_print,
1207 .raw = trace_print_raw,
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001208};
1209
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001210
Steven Rostedtf633cef2008-12-23 23:24:13 -05001211static struct trace_event *events[] __initdata = {
1212 &trace_fn_event,
1213 &trace_ctx_event,
1214 &trace_wake_event,
1215 &trace_special_event,
1216 &trace_stack_event,
1217 &trace_user_stack_event,
Frederic Weisbecker48ead022009-03-12 18:24:49 +01001218 &trace_bprint_event,
Steven Rostedtf633cef2008-12-23 23:24:13 -05001219 &trace_print_event,
1220 NULL
1221};
1222
1223__init static int init_events(void)
1224{
1225 struct trace_event *event;
1226 int i, ret;
1227
1228 for (i = 0; events[i]; i++) {
1229 event = events[i];
1230
1231 ret = register_ftrace_event(event);
1232 if (!ret) {
1233 printk(KERN_WARNING "event %d failed to register\n",
1234 event->type);
1235 WARN_ON_ONCE(1);
1236 }
1237 }
1238
1239 return 0;
1240}
1241device_initcall(init_events);