Root/
1 | /* |
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 | |
17 | DECLARE_RWSEM(trace_event_mutex); |
18 | |
19 | static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; |
20 | |
21 | static int next_event_type = __TRACE_LAST_TYPE + 1; |
22 | |
23 | int trace_print_seq(struct seq_file *m, struct trace_seq *s) |
24 | { |
25 | int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; |
26 | int ret; |
27 | |
28 | ret = seq_write(m, s->buffer, len); |
29 | |
30 | /* |
31 | * Only reset this buffer if we successfully wrote to the |
32 | * seq_file buffer. |
33 | */ |
34 | if (!ret) |
35 | trace_seq_init(s); |
36 | |
37 | return ret; |
38 | } |
39 | |
40 | enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) |
41 | { |
42 | struct trace_seq *s = &iter->seq; |
43 | struct trace_entry *entry = iter->ent; |
44 | struct bprint_entry *field; |
45 | int ret; |
46 | |
47 | trace_assign_type(field, entry); |
48 | |
49 | ret = trace_seq_bprintf(s, field->fmt, field->buf); |
50 | if (!ret) |
51 | return TRACE_TYPE_PARTIAL_LINE; |
52 | |
53 | return TRACE_TYPE_HANDLED; |
54 | } |
55 | |
56 | enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter) |
57 | { |
58 | struct trace_seq *s = &iter->seq; |
59 | struct trace_entry *entry = iter->ent; |
60 | struct print_entry *field; |
61 | int ret; |
62 | |
63 | trace_assign_type(field, entry); |
64 | |
65 | ret = trace_seq_printf(s, "%s", field->buf); |
66 | if (!ret) |
67 | return TRACE_TYPE_PARTIAL_LINE; |
68 | |
69 | return TRACE_TYPE_HANDLED; |
70 | } |
71 | |
72 | /** |
73 | * trace_seq_printf - sequence printing of trace information |
74 | * @s: trace sequence descriptor |
75 | * @fmt: printf format string |
76 | * |
77 | * It returns 0 if the trace oversizes the buffer's free |
78 | * space, 1 otherwise. |
79 | * |
80 | * The tracer may use either sequence operations or its own |
81 | * copy to user routines. To simplify formating of a trace |
82 | * trace_seq_printf is used to store strings into a special |
83 | * buffer (@s). Then the output may be either used by |
84 | * the sequencer or pulled into another buffer. |
85 | */ |
86 | int |
87 | trace_seq_printf(struct trace_seq *s, const char *fmt, ...) |
88 | { |
89 | int len = (PAGE_SIZE - 1) - s->len; |
90 | va_list ap; |
91 | int ret; |
92 | |
93 | if (s->full || !len) |
94 | return 0; |
95 | |
96 | va_start(ap, fmt); |
97 | ret = vsnprintf(s->buffer + s->len, len, fmt, ap); |
98 | va_end(ap); |
99 | |
100 | /* If we can't write it all, don't bother writing anything */ |
101 | if (ret >= len) { |
102 | s->full = 1; |
103 | return 0; |
104 | } |
105 | |
106 | s->len += ret; |
107 | |
108 | return 1; |
109 | } |
110 | EXPORT_SYMBOL_GPL(trace_seq_printf); |
111 | |
112 | /** |
113 | * trace_seq_vprintf - sequence printing of trace information |
114 | * @s: trace sequence descriptor |
115 | * @fmt: printf format string |
116 | * |
117 | * The tracer may use either sequence operations or its own |
118 | * copy to user routines. To simplify formating of a trace |
119 | * trace_seq_printf is used to store strings into a special |
120 | * buffer (@s). Then the output may be either used by |
121 | * the sequencer or pulled into another buffer. |
122 | */ |
123 | int |
124 | trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) |
125 | { |
126 | int len = (PAGE_SIZE - 1) - s->len; |
127 | int ret; |
128 | |
129 | if (s->full || !len) |
130 | return 0; |
131 | |
132 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); |
133 | |
134 | /* If we can't write it all, don't bother writing anything */ |
135 | if (ret >= len) { |
136 | s->full = 1; |
137 | return 0; |
138 | } |
139 | |
140 | s->len += ret; |
141 | |
142 | return len; |
143 | } |
144 | EXPORT_SYMBOL_GPL(trace_seq_vprintf); |
145 | |
146 | int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) |
147 | { |
148 | int len = (PAGE_SIZE - 1) - s->len; |
149 | int ret; |
150 | |
151 | if (s->full || !len) |
152 | return 0; |
153 | |
154 | ret = bstr_printf(s->buffer + s->len, len, fmt, binary); |
155 | |
156 | /* If we can't write it all, don't bother writing anything */ |
157 | if (ret >= len) { |
158 | s->full = 1; |
159 | return 0; |
160 | } |
161 | |
162 | s->len += ret; |
163 | |
164 | return len; |
165 | } |
166 | |
167 | /** |
168 | * trace_seq_puts - trace sequence printing of simple string |
169 | * @s: trace sequence descriptor |
170 | * @str: simple string to record |
171 | * |
172 | * The tracer may use either the sequence operations or its own |
173 | * copy to user routines. This function records a simple string |
174 | * into a special buffer (@s) for later retrieval by a sequencer |
175 | * or other mechanism. |
176 | */ |
177 | int trace_seq_puts(struct trace_seq *s, const char *str) |
178 | { |
179 | int len = strlen(str); |
180 | |
181 | if (s->full) |
182 | return 0; |
183 | |
184 | if (len > ((PAGE_SIZE - 1) - s->len)) { |
185 | s->full = 1; |
186 | return 0; |
187 | } |
188 | |
189 | memcpy(s->buffer + s->len, str, len); |
190 | s->len += len; |
191 | |
192 | return len; |
193 | } |
194 | |
195 | int trace_seq_putc(struct trace_seq *s, unsigned char c) |
196 | { |
197 | if (s->full) |
198 | return 0; |
199 | |
200 | if (s->len >= (PAGE_SIZE - 1)) { |
201 | s->full = 1; |
202 | return 0; |
203 | } |
204 | |
205 | s->buffer[s->len++] = c; |
206 | |
207 | return 1; |
208 | } |
209 | EXPORT_SYMBOL(trace_seq_putc); |
210 | |
211 | int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len) |
212 | { |
213 | if (s->full) |
214 | return 0; |
215 | |
216 | if (len > ((PAGE_SIZE - 1) - s->len)) { |
217 | s->full = 1; |
218 | return 0; |
219 | } |
220 | |
221 | memcpy(s->buffer + s->len, mem, len); |
222 | s->len += len; |
223 | |
224 | return len; |
225 | } |
226 | |
227 | int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len) |
228 | { |
229 | unsigned char hex[HEX_CHARS]; |
230 | const unsigned char *data = mem; |
231 | int i, j; |
232 | |
233 | if (s->full) |
234 | return 0; |
235 | |
236 | #ifdef __BIG_ENDIAN |
237 | for (i = 0, j = 0; i < len; i++) { |
238 | #else |
239 | for (i = len-1, j = 0; i >= 0; i--) { |
240 | #endif |
241 | hex[j++] = hex_asc_hi(data[i]); |
242 | hex[j++] = hex_asc_lo(data[i]); |
243 | } |
244 | hex[j++] = ' '; |
245 | |
246 | return trace_seq_putmem(s, hex, j); |
247 | } |
248 | |
249 | void *trace_seq_reserve(struct trace_seq *s, size_t len) |
250 | { |
251 | void *ret; |
252 | |
253 | if (s->full) |
254 | return NULL; |
255 | |
256 | if (len > ((PAGE_SIZE - 1) - s->len)) { |
257 | s->full = 1; |
258 | return NULL; |
259 | } |
260 | |
261 | ret = s->buffer + s->len; |
262 | s->len += len; |
263 | |
264 | return ret; |
265 | } |
266 | |
267 | int trace_seq_path(struct trace_seq *s, struct path *path) |
268 | { |
269 | unsigned char *p; |
270 | |
271 | if (s->full) |
272 | return 0; |
273 | |
274 | if (s->len >= (PAGE_SIZE - 1)) { |
275 | s->full = 1; |
276 | return 0; |
277 | } |
278 | |
279 | p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len); |
280 | if (!IS_ERR(p)) { |
281 | p = mangle_path(s->buffer + s->len, p, "\n"); |
282 | if (p) { |
283 | s->len = p - s->buffer; |
284 | return 1; |
285 | } |
286 | } else { |
287 | s->buffer[s->len++] = '?'; |
288 | return 1; |
289 | } |
290 | |
291 | s->full = 1; |
292 | return 0; |
293 | } |
294 | |
295 | const char * |
296 | ftrace_print_flags_seq(struct trace_seq *p, const char *delim, |
297 | unsigned long flags, |
298 | const struct trace_print_flags *flag_array) |
299 | { |
300 | unsigned long mask; |
301 | const char *str; |
302 | const char *ret = p->buffer + p->len; |
303 | int i; |
304 | |
305 | for (i = 0; flag_array[i].name && flags; i++) { |
306 | |
307 | mask = flag_array[i].mask; |
308 | if ((flags & mask) != mask) |
309 | continue; |
310 | |
311 | str = flag_array[i].name; |
312 | flags &= ~mask; |
313 | if (p->len && delim) |
314 | trace_seq_puts(p, delim); |
315 | trace_seq_puts(p, str); |
316 | } |
317 | |
318 | /* check for left over flags */ |
319 | if (flags) { |
320 | if (p->len && delim) |
321 | trace_seq_puts(p, delim); |
322 | trace_seq_printf(p, "0x%lx", flags); |
323 | } |
324 | |
325 | trace_seq_putc(p, 0); |
326 | |
327 | return ret; |
328 | } |
329 | EXPORT_SYMBOL(ftrace_print_flags_seq); |
330 | |
331 | const char * |
332 | ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, |
333 | const struct trace_print_flags *symbol_array) |
334 | { |
335 | int i; |
336 | const char *ret = p->buffer + p->len; |
337 | |
338 | for (i = 0; symbol_array[i].name; i++) { |
339 | |
340 | if (val != symbol_array[i].mask) |
341 | continue; |
342 | |
343 | trace_seq_puts(p, symbol_array[i].name); |
344 | break; |
345 | } |
346 | |
347 | if (!p->len) |
348 | trace_seq_printf(p, "0x%lx", val); |
349 | |
350 | trace_seq_putc(p, 0); |
351 | |
352 | return ret; |
353 | } |
354 | EXPORT_SYMBOL(ftrace_print_symbols_seq); |
355 | |
356 | const char * |
357 | ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) |
358 | { |
359 | int i; |
360 | const char *ret = p->buffer + p->len; |
361 | |
362 | for (i = 0; i < buf_len; i++) |
363 | trace_seq_printf(p, "%s%2.2x", i == 0 ? "" : " ", buf[i]); |
364 | |
365 | trace_seq_putc(p, 0); |
366 | |
367 | return ret; |
368 | } |
369 | EXPORT_SYMBOL(ftrace_print_hex_seq); |
370 | |
371 | #ifdef CONFIG_KRETPROBES |
372 | static inline const char *kretprobed(const char *name) |
373 | { |
374 | static const char tramp_name[] = "kretprobe_trampoline"; |
375 | int size = sizeof(tramp_name); |
376 | |
377 | if (strncmp(tramp_name, name, size) == 0) |
378 | return "[unknown/kretprobe'd]"; |
379 | return name; |
380 | } |
381 | #else |
382 | static inline const char *kretprobed(const char *name) |
383 | { |
384 | return name; |
385 | } |
386 | #endif /* CONFIG_KRETPROBES */ |
387 | |
388 | static int |
389 | seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address) |
390 | { |
391 | #ifdef CONFIG_KALLSYMS |
392 | char str[KSYM_SYMBOL_LEN]; |
393 | const char *name; |
394 | |
395 | kallsyms_lookup(address, NULL, NULL, NULL, str); |
396 | |
397 | name = kretprobed(str); |
398 | |
399 | return trace_seq_printf(s, fmt, name); |
400 | #endif |
401 | return 1; |
402 | } |
403 | |
404 | static int |
405 | seq_print_sym_offset(struct trace_seq *s, const char *fmt, |
406 | unsigned long address) |
407 | { |
408 | #ifdef CONFIG_KALLSYMS |
409 | char str[KSYM_SYMBOL_LEN]; |
410 | const char *name; |
411 | |
412 | sprint_symbol(str, address); |
413 | name = kretprobed(str); |
414 | |
415 | return trace_seq_printf(s, fmt, name); |
416 | #endif |
417 | return 1; |
418 | } |
419 | |
420 | #ifndef CONFIG_64BIT |
421 | # define IP_FMT "%08lx" |
422 | #else |
423 | # define IP_FMT "%016lx" |
424 | #endif |
425 | |
426 | int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, |
427 | unsigned long ip, unsigned long sym_flags) |
428 | { |
429 | struct file *file = NULL; |
430 | unsigned long vmstart = 0; |
431 | int ret = 1; |
432 | |
433 | if (s->full) |
434 | return 0; |
435 | |
436 | if (mm) { |
437 | const struct vm_area_struct *vma; |
438 | |
439 | down_read(&mm->mmap_sem); |
440 | vma = find_vma(mm, ip); |
441 | if (vma) { |
442 | file = vma->vm_file; |
443 | vmstart = vma->vm_start; |
444 | } |
445 | if (file) { |
446 | ret = trace_seq_path(s, &file->f_path); |
447 | if (ret) |
448 | ret = trace_seq_printf(s, "[+0x%lx]", |
449 | ip - vmstart); |
450 | } |
451 | up_read(&mm->mmap_sem); |
452 | } |
453 | if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file)) |
454 | ret = trace_seq_printf(s, " <" IP_FMT ">", ip); |
455 | return ret; |
456 | } |
457 | |
458 | int |
459 | seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, |
460 | unsigned long sym_flags) |
461 | { |
462 | struct mm_struct *mm = NULL; |
463 | int ret = 1; |
464 | unsigned int i; |
465 | |
466 | if (trace_flags & TRACE_ITER_SYM_USEROBJ) { |
467 | struct task_struct *task; |
468 | /* |
469 | * we do the lookup on the thread group leader, |
470 | * since individual threads might have already quit! |
471 | */ |
472 | rcu_read_lock(); |
473 | task = find_task_by_vpid(entry->tgid); |
474 | if (task) |
475 | mm = get_task_mm(task); |
476 | rcu_read_unlock(); |
477 | } |
478 | |
479 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { |
480 | unsigned long ip = entry->caller[i]; |
481 | |
482 | if (ip == ULONG_MAX || !ret) |
483 | break; |
484 | if (ret) |
485 | ret = trace_seq_puts(s, " => "); |
486 | if (!ip) { |
487 | if (ret) |
488 | ret = trace_seq_puts(s, "??"); |
489 | if (ret) |
490 | ret = trace_seq_puts(s, "\n"); |
491 | continue; |
492 | } |
493 | if (!ret) |
494 | break; |
495 | if (ret) |
496 | ret = seq_print_user_ip(s, mm, ip, sym_flags); |
497 | ret = trace_seq_puts(s, "\n"); |
498 | } |
499 | |
500 | if (mm) |
501 | mmput(mm); |
502 | return ret; |
503 | } |
504 | |
505 | int |
506 | seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags) |
507 | { |
508 | int ret; |
509 | |
510 | if (!ip) |
511 | return trace_seq_printf(s, "0"); |
512 | |
513 | if (sym_flags & TRACE_ITER_SYM_OFFSET) |
514 | ret = seq_print_sym_offset(s, "%s", ip); |
515 | else |
516 | ret = seq_print_sym_short(s, "%s", ip); |
517 | |
518 | if (!ret) |
519 | return 0; |
520 | |
521 | if (sym_flags & TRACE_ITER_SYM_ADDR) |
522 | ret = trace_seq_printf(s, " <" IP_FMT ">", ip); |
523 | return ret; |
524 | } |
525 | |
526 | /** |
527 | * trace_print_lat_fmt - print the irq, preempt and lockdep fields |
528 | * @s: trace seq struct to write to |
529 | * @entry: The trace entry field from the ring buffer |
530 | * |
531 | * Prints the generic fields of irqs off, in hard or softirq, preempt |
532 | * count and lock depth. |
533 | */ |
534 | int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) |
535 | { |
536 | int hardirq, softirq; |
537 | int ret; |
538 | |
539 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; |
540 | softirq = entry->flags & TRACE_FLAG_SOFTIRQ; |
541 | |
542 | if (!trace_seq_printf(s, "%c%c%c", |
543 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : |
544 | (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? |
545 | 'X' : '.', |
546 | (entry->flags & TRACE_FLAG_NEED_RESCHED) ? |
547 | 'N' : '.', |
548 | (hardirq && softirq) ? 'H' : |
549 | hardirq ? 'h' : softirq ? 's' : '.')) |
550 | return 0; |
551 | |
552 | if (entry->preempt_count) |
553 | ret = trace_seq_printf(s, "%x", entry->preempt_count); |
554 | else |
555 | ret = trace_seq_putc(s, '.'); |
556 | |
557 | if (!ret) |
558 | return 0; |
559 | |
560 | if (entry->lock_depth < 0) |
561 | return trace_seq_putc(s, '.'); |
562 | |
563 | return trace_seq_printf(s, "%d", entry->lock_depth); |
564 | } |
565 | |
566 | static int |
567 | lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu) |
568 | { |
569 | char comm[TASK_COMM_LEN]; |
570 | |
571 | trace_find_cmdline(entry->pid, comm); |
572 | |
573 | if (!trace_seq_printf(s, "%8.8s-%-5d %3d", |
574 | comm, entry->pid, cpu)) |
575 | return 0; |
576 | |
577 | return trace_print_lat_fmt(s, entry); |
578 | } |
579 | |
580 | static unsigned long preempt_mark_thresh = 100; |
581 | |
582 | static int |
583 | lat_print_timestamp(struct trace_seq *s, u64 abs_usecs, |
584 | unsigned long rel_usecs) |
585 | { |
586 | return trace_seq_printf(s, " %4lldus%c: ", abs_usecs, |
587 | rel_usecs > preempt_mark_thresh ? '!' : |
588 | rel_usecs > 1 ? '+' : ' '); |
589 | } |
590 | |
591 | int trace_print_context(struct trace_iterator *iter) |
592 | { |
593 | struct trace_seq *s = &iter->seq; |
594 | struct trace_entry *entry = iter->ent; |
595 | unsigned long long t = ns2usecs(iter->ts); |
596 | unsigned long usec_rem = do_div(t, USEC_PER_SEC); |
597 | unsigned long secs = (unsigned long)t; |
598 | char comm[TASK_COMM_LEN]; |
599 | |
600 | trace_find_cmdline(entry->pid, comm); |
601 | |
602 | return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ", |
603 | comm, entry->pid, iter->cpu, secs, usec_rem); |
604 | } |
605 | |
606 | int trace_print_lat_context(struct trace_iterator *iter) |
607 | { |
608 | u64 next_ts; |
609 | int ret; |
610 | struct trace_seq *s = &iter->seq; |
611 | struct trace_entry *entry = iter->ent, |
612 | *next_entry = trace_find_next_entry(iter, NULL, |
613 | &next_ts); |
614 | unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE); |
615 | unsigned long abs_usecs = ns2usecs(iter->ts - iter->tr->time_start); |
616 | unsigned long rel_usecs; |
617 | |
618 | if (!next_entry) |
619 | next_ts = iter->ts; |
620 | rel_usecs = ns2usecs(next_ts - iter->ts); |
621 | |
622 | if (verbose) { |
623 | char comm[TASK_COMM_LEN]; |
624 | |
625 | trace_find_cmdline(entry->pid, comm); |
626 | |
627 | ret = trace_seq_printf(s, "%16s %5d %3d %d %08x %08lx [%08llx]" |
628 | " %ld.%03ldms (+%ld.%03ldms): ", comm, |
629 | entry->pid, iter->cpu, entry->flags, |
630 | entry->preempt_count, iter->idx, |
631 | ns2usecs(iter->ts), |
632 | abs_usecs / USEC_PER_MSEC, |
633 | abs_usecs % USEC_PER_MSEC, |
634 | rel_usecs / USEC_PER_MSEC, |
635 | rel_usecs % USEC_PER_MSEC); |
636 | } else { |
637 | ret = lat_print_generic(s, entry, iter->cpu); |
638 | if (ret) |
639 | ret = lat_print_timestamp(s, abs_usecs, rel_usecs); |
640 | } |
641 | |
642 | return ret; |
643 | } |
644 | |
645 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; |
646 | |
647 | static int task_state_char(unsigned long state) |
648 | { |
649 | int bit = state ? __ffs(state) + 1 : 0; |
650 | |
651 | return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?'; |
652 | } |
653 | |
654 | /** |
655 | * ftrace_find_event - find a registered event |
656 | * @type: the type of event to look for |
657 | * |
658 | * Returns an event of type @type otherwise NULL |
659 | * Called with trace_event_read_lock() held. |
660 | */ |
661 | struct trace_event *ftrace_find_event(int type) |
662 | { |
663 | struct trace_event *event; |
664 | struct hlist_node *n; |
665 | unsigned key; |
666 | |
667 | key = type & (EVENT_HASHSIZE - 1); |
668 | |
669 | hlist_for_each_entry(event, n, &event_hash[key], node) { |
670 | if (event->type == type) |
671 | return event; |
672 | } |
673 | |
674 | return NULL; |
675 | } |
676 | |
677 | static LIST_HEAD(ftrace_event_list); |
678 | |
679 | static int trace_search_list(struct list_head **list) |
680 | { |
681 | struct trace_event *e; |
682 | int last = __TRACE_LAST_TYPE; |
683 | |
684 | if (list_empty(&ftrace_event_list)) { |
685 | *list = &ftrace_event_list; |
686 | return last + 1; |
687 | } |
688 | |
689 | /* |
690 | * We used up all possible max events, |
691 | * lets see if somebody freed one. |
692 | */ |
693 | list_for_each_entry(e, &ftrace_event_list, list) { |
694 | if (e->type != last + 1) |
695 | break; |
696 | last++; |
697 | } |
698 | |
699 | /* Did we used up all 65 thousand events??? */ |
700 | if ((last + 1) > FTRACE_MAX_EVENT) |
701 | return 0; |
702 | |
703 | *list = &e->list; |
704 | return last + 1; |
705 | } |
706 | |
707 | void trace_event_read_lock(void) |
708 | { |
709 | down_read(&trace_event_mutex); |
710 | } |
711 | |
712 | void trace_event_read_unlock(void) |
713 | { |
714 | up_read(&trace_event_mutex); |
715 | } |
716 | |
717 | /** |
718 | * register_ftrace_event - register output for an event type |
719 | * @event: the event type to register |
720 | * |
721 | * Event types are stored in a hash and this hash is used to |
722 | * find a way to print an event. If the @event->type is set |
723 | * then it will use that type, otherwise it will assign a |
724 | * type to use. |
725 | * |
726 | * If you assign your own type, please make sure it is added |
727 | * to the trace_type enum in trace.h, to avoid collisions |
728 | * with the dynamic types. |
729 | * |
730 | * Returns the event type number or zero on error. |
731 | */ |
732 | int register_ftrace_event(struct trace_event *event) |
733 | { |
734 | unsigned key; |
735 | int ret = 0; |
736 | |
737 | down_write(&trace_event_mutex); |
738 | |
739 | if (WARN_ON(!event)) |
740 | goto out; |
741 | |
742 | if (WARN_ON(!event->funcs)) |
743 | goto out; |
744 | |
745 | INIT_LIST_HEAD(&event->list); |
746 | |
747 | if (!event->type) { |
748 | struct list_head *list = NULL; |
749 | |
750 | if (next_event_type > FTRACE_MAX_EVENT) { |
751 | |
752 | event->type = trace_search_list(&list); |
753 | if (!event->type) |
754 | goto out; |
755 | |
756 | } else { |
757 | |
758 | event->type = next_event_type++; |
759 | list = &ftrace_event_list; |
760 | } |
761 | |
762 | if (WARN_ON(ftrace_find_event(event->type))) |
763 | goto out; |
764 | |
765 | list_add_tail(&event->list, list); |
766 | |
767 | } else if (event->type > __TRACE_LAST_TYPE) { |
768 | printk(KERN_WARNING "Need to add type to trace.h\n"); |
769 | WARN_ON(1); |
770 | goto out; |
771 | } else { |
772 | /* Is this event already used */ |
773 | if (ftrace_find_event(event->type)) |
774 | goto out; |
775 | } |
776 | |
777 | if (event->funcs->trace == NULL) |
778 | event->funcs->trace = trace_nop_print; |
779 | if (event->funcs->raw == NULL) |
780 | event->funcs->raw = trace_nop_print; |
781 | if (event->funcs->hex == NULL) |
782 | event->funcs->hex = trace_nop_print; |
783 | if (event->funcs->binary == NULL) |
784 | event->funcs->binary = trace_nop_print; |
785 | |
786 | key = event->type & (EVENT_HASHSIZE - 1); |
787 | |
788 | hlist_add_head(&event->node, &event_hash[key]); |
789 | |
790 | ret = event->type; |
791 | out: |
792 | up_write(&trace_event_mutex); |
793 | |
794 | return ret; |
795 | } |
796 | EXPORT_SYMBOL_GPL(register_ftrace_event); |
797 | |
798 | /* |
799 | * Used by module code with the trace_event_mutex held for write. |
800 | */ |
801 | int __unregister_ftrace_event(struct trace_event *event) |
802 | { |
803 | hlist_del(&event->node); |
804 | list_del(&event->list); |
805 | return 0; |
806 | } |
807 | |
808 | /** |
809 | * unregister_ftrace_event - remove a no longer used event |
810 | * @event: the event to remove |
811 | */ |
812 | int unregister_ftrace_event(struct trace_event *event) |
813 | { |
814 | down_write(&trace_event_mutex); |
815 | __unregister_ftrace_event(event); |
816 | up_write(&trace_event_mutex); |
817 | |
818 | return 0; |
819 | } |
820 | EXPORT_SYMBOL_GPL(unregister_ftrace_event); |
821 | |
822 | /* |
823 | * Standard events |
824 | */ |
825 | |
826 | enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags, |
827 | struct trace_event *event) |
828 | { |
829 | return TRACE_TYPE_HANDLED; |
830 | } |
831 | |
832 | /* TRACE_FN */ |
833 | static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags, |
834 | struct trace_event *event) |
835 | { |
836 | struct ftrace_entry *field; |
837 | struct trace_seq *s = &iter->seq; |
838 | |
839 | trace_assign_type(field, iter->ent); |
840 | |
841 | if (!seq_print_ip_sym(s, field->ip, flags)) |
842 | goto partial; |
843 | |
844 | if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) { |
845 | if (!trace_seq_printf(s, " <-")) |
846 | goto partial; |
847 | if (!seq_print_ip_sym(s, |
848 | field->parent_ip, |
849 | flags)) |
850 | goto partial; |
851 | } |
852 | if (!trace_seq_printf(s, "\n")) |
853 | goto partial; |
854 | |
855 | return TRACE_TYPE_HANDLED; |
856 | |
857 | partial: |
858 | return TRACE_TYPE_PARTIAL_LINE; |
859 | } |
860 | |
861 | static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags, |
862 | struct trace_event *event) |
863 | { |
864 | struct ftrace_entry *field; |
865 | |
866 | trace_assign_type(field, iter->ent); |
867 | |
868 | if (!trace_seq_printf(&iter->seq, "%lx %lx\n", |
869 | field->ip, |
870 | field->parent_ip)) |
871 | return TRACE_TYPE_PARTIAL_LINE; |
872 | |
873 | return TRACE_TYPE_HANDLED; |
874 | } |
875 | |
876 | static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags, |
877 | struct trace_event *event) |
878 | { |
879 | struct ftrace_entry *field; |
880 | struct trace_seq *s = &iter->seq; |
881 | |
882 | trace_assign_type(field, iter->ent); |
883 | |
884 | SEQ_PUT_HEX_FIELD_RET(s, field->ip); |
885 | SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip); |
886 | |
887 | return TRACE_TYPE_HANDLED; |
888 | } |
889 | |
890 | static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags, |
891 | struct trace_event *event) |
892 | { |
893 | struct ftrace_entry *field; |
894 | struct trace_seq *s = &iter->seq; |
895 | |
896 | trace_assign_type(field, iter->ent); |
897 | |
898 | SEQ_PUT_FIELD_RET(s, field->ip); |
899 | SEQ_PUT_FIELD_RET(s, field->parent_ip); |
900 | |
901 | return TRACE_TYPE_HANDLED; |
902 | } |
903 | |
904 | static struct trace_event_functions trace_fn_funcs = { |
905 | .trace = trace_fn_trace, |
906 | .raw = trace_fn_raw, |
907 | .hex = trace_fn_hex, |
908 | .binary = trace_fn_bin, |
909 | }; |
910 | |
911 | static struct trace_event trace_fn_event = { |
912 | .type = TRACE_FN, |
913 | .funcs = &trace_fn_funcs, |
914 | }; |
915 | |
916 | /* TRACE_CTX an TRACE_WAKE */ |
917 | static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, |
918 | char *delim) |
919 | { |
920 | struct ctx_switch_entry *field; |
921 | char comm[TASK_COMM_LEN]; |
922 | int S, T; |
923 | |
924 | |
925 | trace_assign_type(field, iter->ent); |
926 | |
927 | T = task_state_char(field->next_state); |
928 | S = task_state_char(field->prev_state); |
929 | trace_find_cmdline(field->next_pid, comm); |
930 | if (!trace_seq_printf(&iter->seq, |
931 | " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n", |
932 | field->prev_pid, |
933 | field->prev_prio, |
934 | S, delim, |
935 | field->next_cpu, |
936 | field->next_pid, |
937 | field->next_prio, |
938 | T, comm)) |
939 | return TRACE_TYPE_PARTIAL_LINE; |
940 | |
941 | return TRACE_TYPE_HANDLED; |
942 | } |
943 | |
944 | static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags, |
945 | struct trace_event *event) |
946 | { |
947 | return trace_ctxwake_print(iter, "==>"); |
948 | } |
949 | |
950 | static enum print_line_t trace_wake_print(struct trace_iterator *iter, |
951 | int flags, struct trace_event *event) |
952 | { |
953 | return trace_ctxwake_print(iter, " +"); |
954 | } |
955 | |
956 | static int trace_ctxwake_raw(struct trace_iterator *iter, char S) |
957 | { |
958 | struct ctx_switch_entry *field; |
959 | int T; |
960 | |
961 | trace_assign_type(field, iter->ent); |
962 | |
963 | if (!S) |
964 | S = task_state_char(field->prev_state); |
965 | T = task_state_char(field->next_state); |
966 | if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n", |
967 | field->prev_pid, |
968 | field->prev_prio, |
969 | S, |
970 | field->next_cpu, |
971 | field->next_pid, |
972 | field->next_prio, |
973 | T)) |
974 | return TRACE_TYPE_PARTIAL_LINE; |
975 | |
976 | return TRACE_TYPE_HANDLED; |
977 | } |
978 | |
979 | static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags, |
980 | struct trace_event *event) |
981 | { |
982 | return trace_ctxwake_raw(iter, 0); |
983 | } |
984 | |
985 | static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags, |
986 | struct trace_event *event) |
987 | { |
988 | return trace_ctxwake_raw(iter, '+'); |
989 | } |
990 | |
991 | |
992 | static int trace_ctxwake_hex(struct trace_iterator *iter, char S) |
993 | { |
994 | struct ctx_switch_entry *field; |
995 | struct trace_seq *s = &iter->seq; |
996 | int T; |
997 | |
998 | trace_assign_type(field, iter->ent); |
999 | |
1000 | if (!S) |
1001 | S = task_state_char(field->prev_state); |
1002 | T = task_state_char(field->next_state); |
1003 | |
1004 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid); |
1005 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio); |
1006 | SEQ_PUT_HEX_FIELD_RET(s, S); |
1007 | SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu); |
1008 | SEQ_PUT_HEX_FIELD_RET(s, field->next_pid); |
1009 | SEQ_PUT_HEX_FIELD_RET(s, field->next_prio); |
1010 | SEQ_PUT_HEX_FIELD_RET(s, T); |
1011 | |
1012 | return TRACE_TYPE_HANDLED; |
1013 | } |
1014 | |
1015 | static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags, |
1016 | struct trace_event *event) |
1017 | { |
1018 | return trace_ctxwake_hex(iter, 0); |
1019 | } |
1020 | |
1021 | static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags, |
1022 | struct trace_event *event) |
1023 | { |
1024 | return trace_ctxwake_hex(iter, '+'); |
1025 | } |
1026 | |
1027 | static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter, |
1028 | int flags, struct trace_event *event) |
1029 | { |
1030 | struct ctx_switch_entry *field; |
1031 | struct trace_seq *s = &iter->seq; |
1032 | |
1033 | trace_assign_type(field, iter->ent); |
1034 | |
1035 | SEQ_PUT_FIELD_RET(s, field->prev_pid); |
1036 | SEQ_PUT_FIELD_RET(s, field->prev_prio); |
1037 | SEQ_PUT_FIELD_RET(s, field->prev_state); |
1038 | SEQ_PUT_FIELD_RET(s, field->next_pid); |
1039 | SEQ_PUT_FIELD_RET(s, field->next_prio); |
1040 | SEQ_PUT_FIELD_RET(s, field->next_state); |
1041 | |
1042 | return TRACE_TYPE_HANDLED; |
1043 | } |
1044 | |
1045 | static struct trace_event_functions trace_ctx_funcs = { |
1046 | .trace = trace_ctx_print, |
1047 | .raw = trace_ctx_raw, |
1048 | .hex = trace_ctx_hex, |
1049 | .binary = trace_ctxwake_bin, |
1050 | }; |
1051 | |
1052 | static struct trace_event trace_ctx_event = { |
1053 | .type = TRACE_CTX, |
1054 | .funcs = &trace_ctx_funcs, |
1055 | }; |
1056 | |
1057 | static struct trace_event_functions trace_wake_funcs = { |
1058 | .trace = trace_wake_print, |
1059 | .raw = trace_wake_raw, |
1060 | .hex = trace_wake_hex, |
1061 | .binary = trace_ctxwake_bin, |
1062 | }; |
1063 | |
1064 | static struct trace_event trace_wake_event = { |
1065 | .type = TRACE_WAKE, |
1066 | .funcs = &trace_wake_funcs, |
1067 | }; |
1068 | |
1069 | /* TRACE_STACK */ |
1070 | |
1071 | static enum print_line_t trace_stack_print(struct trace_iterator *iter, |
1072 | int flags, struct trace_event *event) |
1073 | { |
1074 | struct stack_entry *field; |
1075 | struct trace_seq *s = &iter->seq; |
1076 | int i; |
1077 | |
1078 | trace_assign_type(field, iter->ent); |
1079 | |
1080 | if (!trace_seq_puts(s, "<stack trace>\n")) |
1081 | goto partial; |
1082 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { |
1083 | if (!field->caller[i] || (field->caller[i] == ULONG_MAX)) |
1084 | break; |
1085 | if (!trace_seq_puts(s, " => ")) |
1086 | goto partial; |
1087 | |
1088 | if (!seq_print_ip_sym(s, field->caller[i], flags)) |
1089 | goto partial; |
1090 | if (!trace_seq_puts(s, "\n")) |
1091 | goto partial; |
1092 | } |
1093 | |
1094 | return TRACE_TYPE_HANDLED; |
1095 | |
1096 | partial: |
1097 | return TRACE_TYPE_PARTIAL_LINE; |
1098 | } |
1099 | |
1100 | static struct trace_event_functions trace_stack_funcs = { |
1101 | .trace = trace_stack_print, |
1102 | }; |
1103 | |
1104 | static struct trace_event trace_stack_event = { |
1105 | .type = TRACE_STACK, |
1106 | .funcs = &trace_stack_funcs, |
1107 | }; |
1108 | |
1109 | /* TRACE_USER_STACK */ |
1110 | static enum print_line_t trace_user_stack_print(struct trace_iterator *iter, |
1111 | int flags, struct trace_event *event) |
1112 | { |
1113 | struct userstack_entry *field; |
1114 | struct trace_seq *s = &iter->seq; |
1115 | |
1116 | trace_assign_type(field, iter->ent); |
1117 | |
1118 | if (!trace_seq_puts(s, "<user stack trace>\n")) |
1119 | goto partial; |
1120 | |
1121 | if (!seq_print_userip_objs(field, s, flags)) |
1122 | goto partial; |
1123 | |
1124 | return TRACE_TYPE_HANDLED; |
1125 | |
1126 | partial: |
1127 | return TRACE_TYPE_PARTIAL_LINE; |
1128 | } |
1129 | |
1130 | static struct trace_event_functions trace_user_stack_funcs = { |
1131 | .trace = trace_user_stack_print, |
1132 | }; |
1133 | |
1134 | static struct trace_event trace_user_stack_event = { |
1135 | .type = TRACE_USER_STACK, |
1136 | .funcs = &trace_user_stack_funcs, |
1137 | }; |
1138 | |
1139 | /* TRACE_BPRINT */ |
1140 | static enum print_line_t |
1141 | trace_bprint_print(struct trace_iterator *iter, int flags, |
1142 | struct trace_event *event) |
1143 | { |
1144 | struct trace_entry *entry = iter->ent; |
1145 | struct trace_seq *s = &iter->seq; |
1146 | struct bprint_entry *field; |
1147 | |
1148 | trace_assign_type(field, entry); |
1149 | |
1150 | if (!seq_print_ip_sym(s, field->ip, flags)) |
1151 | goto partial; |
1152 | |
1153 | if (!trace_seq_puts(s, ": ")) |
1154 | goto partial; |
1155 | |
1156 | if (!trace_seq_bprintf(s, field->fmt, field->buf)) |
1157 | goto partial; |
1158 | |
1159 | return TRACE_TYPE_HANDLED; |
1160 | |
1161 | partial: |
1162 | return TRACE_TYPE_PARTIAL_LINE; |
1163 | } |
1164 | |
1165 | |
1166 | static enum print_line_t |
1167 | trace_bprint_raw(struct trace_iterator *iter, int flags, |
1168 | struct trace_event *event) |
1169 | { |
1170 | struct bprint_entry *field; |
1171 | struct trace_seq *s = &iter->seq; |
1172 | |
1173 | trace_assign_type(field, iter->ent); |
1174 | |
1175 | if (!trace_seq_printf(s, ": %lx : ", field->ip)) |
1176 | goto partial; |
1177 | |
1178 | if (!trace_seq_bprintf(s, field->fmt, field->buf)) |
1179 | goto partial; |
1180 | |
1181 | return TRACE_TYPE_HANDLED; |
1182 | |
1183 | partial: |
1184 | return TRACE_TYPE_PARTIAL_LINE; |
1185 | } |
1186 | |
1187 | static struct trace_event_functions trace_bprint_funcs = { |
1188 | .trace = trace_bprint_print, |
1189 | .raw = trace_bprint_raw, |
1190 | }; |
1191 | |
1192 | static struct trace_event trace_bprint_event = { |
1193 | .type = TRACE_BPRINT, |
1194 | .funcs = &trace_bprint_funcs, |
1195 | }; |
1196 | |
1197 | /* TRACE_PRINT */ |
1198 | static enum print_line_t trace_print_print(struct trace_iterator *iter, |
1199 | int flags, struct trace_event *event) |
1200 | { |
1201 | struct print_entry *field; |
1202 | struct trace_seq *s = &iter->seq; |
1203 | |
1204 | trace_assign_type(field, iter->ent); |
1205 | |
1206 | if (!seq_print_ip_sym(s, field->ip, flags)) |
1207 | goto partial; |
1208 | |
1209 | if (!trace_seq_printf(s, ": %s", field->buf)) |
1210 | goto partial; |
1211 | |
1212 | return TRACE_TYPE_HANDLED; |
1213 | |
1214 | partial: |
1215 | return TRACE_TYPE_PARTIAL_LINE; |
1216 | } |
1217 | |
1218 | static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags, |
1219 | struct trace_event *event) |
1220 | { |
1221 | struct print_entry *field; |
1222 | |
1223 | trace_assign_type(field, iter->ent); |
1224 | |
1225 | if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf)) |
1226 | goto partial; |
1227 | |
1228 | return TRACE_TYPE_HANDLED; |
1229 | |
1230 | partial: |
1231 | return TRACE_TYPE_PARTIAL_LINE; |
1232 | } |
1233 | |
1234 | static struct trace_event_functions trace_print_funcs = { |
1235 | .trace = trace_print_print, |
1236 | .raw = trace_print_raw, |
1237 | }; |
1238 | |
1239 | static struct trace_event trace_print_event = { |
1240 | .type = TRACE_PRINT, |
1241 | .funcs = &trace_print_funcs, |
1242 | }; |
1243 | |
1244 | |
1245 | static struct trace_event *events[] __initdata = { |
1246 | &trace_fn_event, |
1247 | &trace_ctx_event, |
1248 | &trace_wake_event, |
1249 | &trace_stack_event, |
1250 | &trace_user_stack_event, |
1251 | &trace_bprint_event, |
1252 | &trace_print_event, |
1253 | NULL |
1254 | }; |
1255 | |
1256 | __init static int init_events(void) |
1257 | { |
1258 | struct trace_event *event; |
1259 | int i, ret; |
1260 | |
1261 | for (i = 0; events[i]; i++) { |
1262 | event = events[i]; |
1263 | |
1264 | ret = register_ftrace_event(event); |
1265 | if (!ret) { |
1266 | printk(KERN_WARNING "event %d failed to register\n", |
1267 | event->type); |
1268 | WARN_ON_ONCE(1); |
1269 | } |
1270 | } |
1271 | |
1272 | return 0; |
1273 | } |
1274 | device_initcall(init_events); |
1275 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9