trace_output.c 23.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * trace_output.c
 *
 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
 *
 */

#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/ftrace.h>

#include "trace_output.h"

/* must be a power of 2 */
#define EVENT_HASHSIZE	128

17
static DECLARE_RWSEM(trace_event_mutex);
18
19
20

DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);

21
22
23
24
static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;

static int next_event_type = __TRACE_LAST_TYPE + 1;

25
26
27
28
29
30
31
32
33
34
void trace_print_seq(struct seq_file *m, struct trace_seq *s)
{
	int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;

	s->buffer[len] = 0;
	seq_puts(m, s->buffer);

	trace_seq_init(s);
}

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry = iter->ent;
	struct bprint_entry *field;
	int ret;

	trace_assign_type(field, entry);

	ret = trace_seq_bprintf(s, field->fmt, field->buf);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	return TRACE_TYPE_HANDLED;
}

enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry = iter->ent;
	struct print_entry *field;
	int ret;

	trace_assign_type(field, entry);

	ret = trace_seq_printf(s, "%s", field->buf);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	return TRACE_TYPE_HANDLED;
}

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * trace_seq_printf - sequence printing of trace information
 * @s: trace sequence descriptor
 * @fmt: printf format string
 *
 * The tracer may use either sequence operations or its own
 * copy to user routines. To simplify formating of a trace
 * trace_seq_printf is used to store strings into a special
 * buffer (@s). Then the output may be either used by
 * the sequencer or pulled into another buffer.
 */
int
trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
{
	int len = (PAGE_SIZE - 1) - s->len;
	va_list ap;
	int ret;

	if (!len)
		return 0;

	va_start(ap, fmt);
	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
	va_end(ap);

	/* If we can't write it all, don't bother writing anything */
	if (ret >= len)
		return 0;

	s->len += ret;

	return len;
}
100
EXPORT_SYMBOL_GPL(trace_seq_printf);
101

102
int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
{
	int len = (PAGE_SIZE - 1) - s->len;
	int ret;

	if (!len)
		return 0;

	ret = bstr_printf(s->buffer + s->len, len, fmt, binary);

	/* If we can't write it all, don't bother writing anything */
	if (ret >= len)
		return 0;

	s->len += ret;

	return len;
}

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
 * trace_seq_puts - trace sequence printing of simple string
 * @s: trace sequence descriptor
 * @str: simple string to record
 *
 * The tracer may use either the sequence operations or its own
 * copy to user routines. This function records a simple string
 * into a special buffer (@s) for later retrieval by a sequencer
 * or other mechanism.
 */
int trace_seq_puts(struct trace_seq *s, const char *str)
{
	int len = strlen(str);

	if (len > ((PAGE_SIZE - 1) - s->len))
		return 0;

	memcpy(s->buffer + s->len, str, len);
	s->len += len;

	return len;
}

int trace_seq_putc(struct trace_seq *s, unsigned char c)
{
	if (s->len >= (PAGE_SIZE - 1))
		return 0;

	s->buffer[s->len++] = c;

	return 1;
}

154
int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
155
156
157
158
159
160
161
162
163
164
{
	if (len > ((PAGE_SIZE - 1) - s->len))
		return 0;

	memcpy(s->buffer + s->len, mem, len);
	s->len += len;

	return len;
}

165
int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len)
166
167
{
	unsigned char hex[HEX_CHARS];
168
	const unsigned char *data = mem;
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
	int i, j;

#ifdef __BIG_ENDIAN
	for (i = 0, j = 0; i < len; i++) {
#else
	for (i = len-1, j = 0; i >= 0; i--) {
#endif
		hex[j++] = hex_asc_hi(data[i]);
		hex[j++] = hex_asc_lo(data[i]);
	}
	hex[j++] = ' ';

	return trace_seq_putmem(s, hex, j);
}

184
185
186
187
188
189
190
191
192
193
194
195
196
void *trace_seq_reserve(struct trace_seq *s, size_t len)
{
	void *ret;

	if (len > ((PAGE_SIZE - 1) - s->len))
		return NULL;

	ret = s->buffer + s->len;
	s->len += len;

	return ret;
}

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
int trace_seq_path(struct trace_seq *s, struct path *path)
{
	unsigned char *p;

	if (s->len >= (PAGE_SIZE - 1))
		return 0;
	p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
	if (!IS_ERR(p)) {
		p = mangle_path(s->buffer + s->len, p, "\n");
		if (p) {
			s->len = p - s->buffer;
			return 1;
		}
	} else {
		s->buffer[s->len++] = '?';
		return 1;
	}

	return 0;
}

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
const char *
ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
		       unsigned long flags,
		       const struct trace_print_flags *flag_array)
{
	unsigned long mask;
	const char *str;
	int i;

	trace_seq_init(p);

	for (i = 0;  flag_array[i].name && flags; i++) {

		mask = flag_array[i].mask;
		if ((flags & mask) != mask)
			continue;

		str = flag_array[i].name;
		flags &= ~mask;
		if (p->len && delim)
			trace_seq_puts(p, delim);
		trace_seq_puts(p, str);
	}

	/* check for left over flags */
	if (flags) {
		if (p->len && delim)
			trace_seq_puts(p, delim);
		trace_seq_printf(p, "0x%lx", flags);
	}

	trace_seq_putc(p, 0);

	return p->buffer;
}

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
#ifdef CONFIG_KRETPROBES
static inline const char *kretprobed(const char *name)
{
	static const char tramp_name[] = "kretprobe_trampoline";
	int size = sizeof(tramp_name);

	if (strncmp(tramp_name, name, size) == 0)
		return "[unknown/kretprobe'd]";
	return name;
}
#else
static inline const char *kretprobed(const char *name)
{
	return name;
}
#endif /* CONFIG_KRETPROBES */

static int
seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
	char str[KSYM_SYMBOL_LEN];
	const char *name;

	kallsyms_lookup(address, NULL, NULL, NULL, str);

	name = kretprobed(str);

	return trace_seq_printf(s, fmt, name);
#endif
	return 1;
}

static int
seq_print_sym_offset(struct trace_seq *s, const char *fmt,
		     unsigned long address)
{
#ifdef CONFIG_KALLSYMS
	char str[KSYM_SYMBOL_LEN];
	const char *name;

	sprint_symbol(str, address);
	name = kretprobed(str);

	return trace_seq_printf(s, fmt, name);
#endif
	return 1;
}

#ifndef CONFIG_64BIT
# define IP_FMT "%08lx"
#else
# define IP_FMT "%016lx"
#endif

int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
		      unsigned long ip, unsigned long sym_flags)
{
	struct file *file = NULL;
	unsigned long vmstart = 0;
	int ret = 1;

	if (mm) {
		const struct vm_area_struct *vma;

		down_read(&mm->mmap_sem);
		vma = find_vma(mm, ip);
		if (vma) {
			file = vma->vm_file;
			vmstart = vma->vm_start;
		}
		if (file) {
			ret = trace_seq_path(s, &file->f_path);
			if (ret)
				ret = trace_seq_printf(s, "[+0x%lx]",
						       ip - vmstart);
		}
		up_read(&mm->mmap_sem);
	}
	if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
		ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
	return ret;
}

int
seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
		      unsigned long sym_flags)
{
	struct mm_struct *mm = NULL;
	int ret = 1;
	unsigned int i;

	if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
		struct task_struct *task;
		/*
		 * we do the lookup on the thread group leader,
		 * since individual threads might have already quit!
		 */
		rcu_read_lock();
		task = find_task_by_vpid(entry->ent.tgid);
		if (task)
			mm = get_task_mm(task);
		rcu_read_unlock();
	}

	for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
		unsigned long ip = entry->caller[i];

		if (ip == ULONG_MAX || !ret)
			break;
		if (i && ret)
			ret = trace_seq_puts(s, " <- ");
		if (!ip) {
			if (ret)
				ret = trace_seq_puts(s, "??");
			continue;
		}
		if (!ret)
			break;
		if (ret)
			ret = seq_print_user_ip(s, mm, ip, sym_flags);
	}

	if (mm)
		mmput(mm);
	return ret;
}

int
seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
{
	int ret;

	if (!ip)
		return trace_seq_printf(s, "0");

	if (sym_flags & TRACE_ITER_SYM_OFFSET)
		ret = seq_print_sym_offset(s, "%s", ip);
	else
		ret = seq_print_sym_short(s, "%s", ip);

	if (!ret)
		return 0;

	if (sym_flags & TRACE_ITER_SYM_ADDR)
		ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
	return ret;
}

403
static int
404
405
406
lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
{
	int hardirq, softirq;
407
	char comm[TASK_COMM_LEN];
408

409
	trace_find_cmdline(entry->pid, comm);
410
411
	hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
	softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
412
413
414
415
416
417
418
419
420
421
422

	if (!trace_seq_printf(s, "%8.8s-%-5d %3d%c%c%c",
			      comm, entry->pid, cpu,
			      (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
				(entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
				  'X' : '.',
			      (entry->flags & TRACE_FLAG_NEED_RESCHED) ?
				'N' : '.',
			      (hardirq && softirq) ? 'H' :
				hardirq ? 'h' : softirq ? 's' : '.'))
		return 0;
423
424

	if (entry->preempt_count)
425
426
		return trace_seq_printf(s, "%x", entry->preempt_count);
	return trace_seq_puts(s, ".");
427
428
429
430
}

static unsigned long preempt_mark_thresh = 100;

431
static int
432
433
434
lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
		    unsigned long rel_usecs)
{
435
436
437
	return trace_seq_printf(s, " %4lldus%c: ", abs_usecs,
				rel_usecs > preempt_mark_thresh ? '!' :
				  rel_usecs > 1 ? '+' : ' ');
438
439
440
441
442
443
444
445
446
}

int trace_print_context(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry = iter->ent;
	unsigned long long t = ns2usecs(iter->ts);
	unsigned long usec_rem = do_div(t, USEC_PER_SEC);
	unsigned long secs = (unsigned long)t;
447
448
449
	char comm[TASK_COMM_LEN];

	trace_find_cmdline(entry->pid, comm);
450

451
	return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ",
452
				comm, entry->pid, iter->cpu, secs, usec_rem);
453
454
455
456
457
}

int trace_print_lat_context(struct trace_iterator *iter)
{
	u64 next_ts;
458
	int ret;
459
460
461
462
463
464
465
466
467
468
469
470
471
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry = iter->ent,
			   *next_entry = trace_find_next_entry(iter, NULL,
							       &next_ts);
	unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
	unsigned long abs_usecs = ns2usecs(iter->ts - iter->tr->time_start);
	unsigned long rel_usecs;

	if (!next_entry)
		next_ts = iter->ts;
	rel_usecs = ns2usecs(next_ts - iter->ts);

	if (verbose) {
472
473
474
475
		char comm[TASK_COMM_LEN];

		trace_find_cmdline(entry->pid, comm);

476
		ret = trace_seq_printf(s, "%16s %5d %3d %d %08x %08lx [%08llx]"
477
				       " %ld.%03ldms (+%ld.%03ldms): ", comm,
478
				       entry->pid, iter->cpu, entry->flags,
479
480
481
482
483
484
				       entry->preempt_count, iter->idx,
				       ns2usecs(iter->ts),
				       abs_usecs / USEC_PER_MSEC,
				       abs_usecs % USEC_PER_MSEC,
				       rel_usecs / USEC_PER_MSEC,
				       rel_usecs % USEC_PER_MSEC);
485
	} else {
486
		ret = lat_print_generic(s, entry, iter->cpu);
487
488
		if (ret)
			ret = lat_print_timestamp(s, abs_usecs, rel_usecs);
489
490
	}

491
	return ret;
492
493
}

494
495
496
497
498
499
500
501
502
static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;

static int task_state_char(unsigned long state)
{
	int bit = state ? __ffs(state) + 1 : 0;

	return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
}

503
504
505
506
507
/**
 * ftrace_find_event - find a registered event
 * @type: the type of event to look for
 *
 * Returns an event of type @type otherwise NULL
508
 * Called with trace_event_read_lock() held.
509
510
511
512
513
514
515
516
517
 */
struct trace_event *ftrace_find_event(int type)
{
	struct trace_event *event;
	struct hlist_node *n;
	unsigned key;

	key = type & (EVENT_HASHSIZE - 1);

518
	hlist_for_each_entry(event, n, &event_hash[key], node) {
519
520
521
522
523
524
525
		if (event->type == type)
			return event;
	}

	return NULL;
}

526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
static LIST_HEAD(ftrace_event_list);

static int trace_search_list(struct list_head **list)
{
	struct trace_event *e;
	int last = __TRACE_LAST_TYPE;

	if (list_empty(&ftrace_event_list)) {
		*list = &ftrace_event_list;
		return last + 1;
	}

	/*
	 * We used up all possible max events,
	 * lets see if somebody freed one.
	 */
	list_for_each_entry(e, &ftrace_event_list, list) {
		if (e->type != last + 1)
			break;
		last++;
	}

	/* Did we used up all 65 thousand events??? */
	if ((last + 1) > FTRACE_MAX_EVENT)
		return 0;

	*list = &e->list;
	return last + 1;
}

556
557
558
559
560
561
562
563
564
565
void trace_event_read_lock(void)
{
	down_read(&trace_event_mutex);
}

void trace_event_read_unlock(void)
{
	up_read(&trace_event_mutex);
}

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
/**
 * register_ftrace_event - register output for an event type
 * @event: the event type to register
 *
 * Event types are stored in a hash and this hash is used to
 * find a way to print an event. If the @event->type is set
 * then it will use that type, otherwise it will assign a
 * type to use.
 *
 * If you assign your own type, please make sure it is added
 * to the trace_type enum in trace.h, to avoid collisions
 * with the dynamic types.
 *
 * Returns the event type number or zero on error.
 */
int register_ftrace_event(struct trace_event *event)
{
	unsigned key;
	int ret = 0;

586
	down_write(&trace_event_mutex);
587

588
	if (WARN_ON(!event))
589
590
		goto out;

591
592
593
	INIT_LIST_HEAD(&event->list);

	if (!event->type) {
594
		struct list_head *list = NULL;
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613

		if (next_event_type > FTRACE_MAX_EVENT) {

			event->type = trace_search_list(&list);
			if (!event->type)
				goto out;

		} else {
			
			event->type = next_event_type++;
			list = &ftrace_event_list;
		}

		if (WARN_ON(ftrace_find_event(event->type)))
			goto out;

		list_add_tail(&event->list, list);

	} else if (event->type > __TRACE_LAST_TYPE) {
614
615
616
		printk(KERN_WARNING "Need to add type to trace.h\n");
		WARN_ON(1);
		goto out;
617
618
619
620
621
	} else {
		/* Is this event already used */
		if (ftrace_find_event(event->type))
			goto out;
	}
622

623
624
625
626
627
628
629
630
631
	if (event->trace == NULL)
		event->trace = trace_nop_print;
	if (event->raw == NULL)
		event->raw = trace_nop_print;
	if (event->hex == NULL)
		event->hex = trace_nop_print;
	if (event->binary == NULL)
		event->binary = trace_nop_print;

632
633
	key = event->type & (EVENT_HASHSIZE - 1);

634
	hlist_add_head(&event->node, &event_hash[key]);
635
636
637

	ret = event->type;
 out:
638
	up_write(&trace_event_mutex);
639
640
641

	return ret;
}
642
EXPORT_SYMBOL_GPL(register_ftrace_event);
643
644
645
646
647
648
649

/**
 * unregister_ftrace_event - remove a no longer used event
 * @event: the event to remove
 */
int unregister_ftrace_event(struct trace_event *event)
{
650
	down_write(&trace_event_mutex);
651
	hlist_del(&event->node);
652
	list_del(&event->list);
653
	up_write(&trace_event_mutex);
654
655
656

	return 0;
}
657
EXPORT_SYMBOL_GPL(unregister_ftrace_event);
658
659
660
661
662

/*
 * Standard events
 */

663
enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
664
{
665
	return TRACE_TYPE_HANDLED;
666
667
668
}

/* TRACE_FN */
669
static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
670
671
{
	struct ftrace_entry *field;
672
	struct trace_seq *s = &iter->seq;
673

674
	trace_assign_type(field, iter->ent);
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689

	if (!seq_print_ip_sym(s, field->ip, flags))
		goto partial;

	if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
		if (!trace_seq_printf(s, " <-"))
			goto partial;
		if (!seq_print_ip_sym(s,
				      field->parent_ip,
				      flags))
			goto partial;
	}
	if (!trace_seq_printf(s, "\n"))
		goto partial;

690
	return TRACE_TYPE_HANDLED;
691
692
693
694
695

 partial:
	return TRACE_TYPE_PARTIAL_LINE;
}

696
static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
697
698
699
{
	struct ftrace_entry *field;

700
	trace_assign_type(field, iter->ent);
701

702
	if (!trace_seq_printf(&iter->seq, "%lx %lx\n",
Lai Jiangshan's avatar
Lai Jiangshan committed
703
704
			      field->ip,
			      field->parent_ip))
705
706
		return TRACE_TYPE_PARTIAL_LINE;

707
	return TRACE_TYPE_HANDLED;
708
709
}

710
static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
711
712
{
	struct ftrace_entry *field;
713
	struct trace_seq *s = &iter->seq;
714

715
	trace_assign_type(field, iter->ent);
716
717
718
719

	SEQ_PUT_HEX_FIELD_RET(s, field->ip);
	SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);

720
	return TRACE_TYPE_HANDLED;
721
722
}

723
static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
724
725
{
	struct ftrace_entry *field;
726
	struct trace_seq *s = &iter->seq;
727

728
	trace_assign_type(field, iter->ent);
729
730
731
732

	SEQ_PUT_FIELD_RET(s, field->ip);
	SEQ_PUT_FIELD_RET(s, field->parent_ip);

733
	return TRACE_TYPE_HANDLED;
734
735
736
}

static struct trace_event trace_fn_event = {
737
	.type		= TRACE_FN,
738
739
740
741
742
743
744
	.trace		= trace_fn_trace,
	.raw		= trace_fn_raw,
	.hex		= trace_fn_hex,
	.binary		= trace_fn_bin,
};

/* TRACE_CTX an TRACE_WAKE */
745
746
static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
					     char *delim)
747
748
{
	struct ctx_switch_entry *field;
749
	char comm[TASK_COMM_LEN];
750
751
	int S, T;

752

753
	trace_assign_type(field, iter->ent);
754
755
756

	T = task_state_char(field->next_state);
	S = task_state_char(field->prev_state);
757
	trace_find_cmdline(field->next_pid, comm);
758
759
	if (!trace_seq_printf(&iter->seq,
			      " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
Lai Jiangshan's avatar
Lai Jiangshan committed
760
761
762
763
764
765
766
			      field->prev_pid,
			      field->prev_prio,
			      S, delim,
			      field->next_cpu,
			      field->next_pid,
			      field->next_prio,
			      T, comm))
767
768
		return TRACE_TYPE_PARTIAL_LINE;

769
	return TRACE_TYPE_HANDLED;
770
771
}

772
static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
773
{
774
	return trace_ctxwake_print(iter, "==>");
775
776
}

777
778
static enum print_line_t trace_wake_print(struct trace_iterator *iter,
					  int flags)
779
{
780
	return trace_ctxwake_print(iter, "  +");
781
782
}

783
static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
784
785
786
787
{
	struct ctx_switch_entry *field;
	int T;

788
	trace_assign_type(field, iter->ent);
789
790
791
792

	if (!S)
		task_state_char(field->prev_state);
	T = task_state_char(field->next_state);
793
	if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
Lai Jiangshan's avatar
Lai Jiangshan committed
794
795
796
797
798
799
800
			      field->prev_pid,
			      field->prev_prio,
			      S,
			      field->next_cpu,
			      field->next_pid,
			      field->next_prio,
			      T))
801
802
		return TRACE_TYPE_PARTIAL_LINE;

803
	return TRACE_TYPE_HANDLED;
804
805
}

806
static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
807
{
808
	return trace_ctxwake_raw(iter, 0);
809
810
}

811
static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
812
{
813
	return trace_ctxwake_raw(iter, '+');
814
815
816
}


817
static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
818
819
{
	struct ctx_switch_entry *field;
820
	struct trace_seq *s = &iter->seq;
821
822
	int T;

823
	trace_assign_type(field, iter->ent);
824
825
826
827
828
829
830
831
832
833
834
835
836

	if (!S)
		task_state_char(field->prev_state);
	T = task_state_char(field->next_state);

	SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
	SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
	SEQ_PUT_HEX_FIELD_RET(s, S);
	SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
	SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
	SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
	SEQ_PUT_HEX_FIELD_RET(s, T);

837
	return TRACE_TYPE_HANDLED;
838
839
}

840
static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
841
{
842
	return trace_ctxwake_hex(iter, 0);
843
844
}

845
static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
846
{
847
	return trace_ctxwake_hex(iter, '+');
848
849
}

850
851
static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
					   int flags)
852
853
{
	struct ctx_switch_entry *field;
854
	struct trace_seq *s = &iter->seq;
855

856
	trace_assign_type(field, iter->ent);
857
858
859
860
861
862
863
864

	SEQ_PUT_FIELD_RET(s, field->prev_pid);
	SEQ_PUT_FIELD_RET(s, field->prev_prio);
	SEQ_PUT_FIELD_RET(s, field->prev_state);
	SEQ_PUT_FIELD_RET(s, field->next_pid);
	SEQ_PUT_FIELD_RET(s, field->next_prio);
	SEQ_PUT_FIELD_RET(s, field->next_state);

865
	return TRACE_TYPE_HANDLED;
866
867
868
}

static struct trace_event trace_ctx_event = {
869
	.type		= TRACE_CTX,
870
871
872
873
874
875
876
	.trace		= trace_ctx_print,
	.raw		= trace_ctx_raw,
	.hex		= trace_ctx_hex,
	.binary		= trace_ctxwake_bin,
};

static struct trace_event trace_wake_event = {
877
	.type		= TRACE_WAKE,
878
879
880
881
882
883
884
	.trace		= trace_wake_print,
	.raw		= trace_wake_raw,
	.hex		= trace_wake_hex,
	.binary		= trace_ctxwake_bin,
};

/* TRACE_SPECIAL */
885
886
static enum print_line_t trace_special_print(struct trace_iterator *iter,
					     int flags)
887
888
889
{
	struct special_entry *field;

890
	trace_assign_type(field, iter->ent);
891

892
	if (!trace_seq_printf(&iter->seq, "# %ld %ld %ld\n",
Lai Jiangshan's avatar
Lai Jiangshan committed
893
894
895
			      field->arg1,
			      field->arg2,
			      field->arg3))
896
897
		return TRACE_TYPE_PARTIAL_LINE;

898
	return TRACE_TYPE_HANDLED;
899
900
}

901
902
static enum print_line_t trace_special_hex(struct trace_iterator *iter,
					   int flags)
903
904
{
	struct special_entry *field;
905
	struct trace_seq *s = &iter->seq;
906

907
	trace_assign_type(field, iter->ent);
908
909
910
911
912

	SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
	SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
	SEQ_PUT_HEX_FIELD_RET(s, field->arg3);

913
	return TRACE_TYPE_HANDLED;
914
915
}

916
917
static enum print_line_t trace_special_bin(struct trace_iterator *iter,
					   int flags)
918
919
{
	struct special_entry *field;
920
	struct trace_seq *s = &iter->seq;
921

922
	trace_assign_type(field, iter->ent);
923
924
925
926
927

	SEQ_PUT_FIELD_RET(s, field->arg1);
	SEQ_PUT_FIELD_RET(s, field->arg2);
	SEQ_PUT_FIELD_RET(s, field->arg3);

928
	return TRACE_TYPE_HANDLED;
929
930
931
}

static struct trace_event trace_special_event = {
932
	.type		= TRACE_SPECIAL,
933
934
935
936
937
938
939
940
	.trace		= trace_special_print,
	.raw		= trace_special_print,
	.hex		= trace_special_hex,
	.binary		= trace_special_bin,
};

/* TRACE_STACK */

941
942
static enum print_line_t trace_stack_print(struct trace_iterator *iter,
					   int flags)
943
944
{
	struct stack_entry *field;
945
	struct trace_seq *s = &iter->seq;
946
947
	int i;

948
	trace_assign_type(field, iter->ent);
949
950

	for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
951
952
		if (!field->caller[i])
			break;
953
		if (i) {
Lai Jiangshan's avatar
Lai Jiangshan committed
954
			if (!trace_seq_puts(s, " <= "))
955
956
				goto partial;

Lai Jiangshan's avatar
Lai Jiangshan committed
957
			if (!seq_print_ip_sym(s, field->caller[i], flags))
958
959
				goto partial;
		}
Lai Jiangshan's avatar
Lai Jiangshan committed
960
		if (!trace_seq_puts(s, "\n"))
961
962
963
			goto partial;
	}

964
	return TRACE_TYPE_HANDLED;
965
966
967
968
969
970

 partial:
	return TRACE_TYPE_PARTIAL_LINE;
}

static struct trace_event trace_stack_event = {
971
	.type		= TRACE_STACK,
972
973
974
975
976
977
978
	.trace		= trace_stack_print,
	.raw		= trace_special_print,
	.hex		= trace_special_hex,
	.binary		= trace_special_bin,
};

/* TRACE_USER_STACK */
979
980
static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
						int flags)
981
982
{
	struct userstack_entry *field;
983
	struct trace_seq *s = &iter->seq;
984

985
	trace_assign_type(field, iter->ent);
986

Lai Jiangshan's avatar
Lai Jiangshan committed
987
	if (!seq_print_userip_objs(field, s, flags))
988
989
		goto partial;

Lai Jiangshan's avatar
Lai Jiangshan committed
990
	if (!trace_seq_putc(s, '\n'))
991
992
		goto partial;

993
	return TRACE_TYPE_HANDLED;
994
995
996
997
998
999

 partial:
	return TRACE_TYPE_PARTIAL_LINE;
}

static struct trace_event trace_user_stack_event = {
1000
	.type		= TRACE_USER_STACK,