Commit | Line | Data |
---|---|---|
bcea3f96 | 1 | // SPDX-License-Identifier: GPL-2.0 |
f0868d1e SR |
2 | /* |
3 | * trace_output.c | |
4 | * | |
5 | * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | |
6 | * | |
7 | */ | |
35a380dd | 8 | #include "trace.h" |
f0868d1e SR |
9 | #include <linux/module.h> |
10 | #include <linux/mutex.h> | |
11 | #include <linux/ftrace.h> | |
7da89495 | 12 | #include <linux/kprobes.h> |
e6017571 | 13 | #include <linux/sched/clock.h> |
6e84f315 | 14 | #include <linux/sched/mm.h> |
96e6122c | 15 | #include <linux/idr.h> |
533c20b0 SS |
16 | #include <linux/btf.h> |
17 | #include <linux/bpf.h> | |
391dda1b | 18 | #include <linux/hashtable.h> |
f0868d1e SR |
19 | |
20 | #include "trace_output.h" | |
533c20b0 | 21 | #include "trace_btf.h" |
f0868d1e | 22 | |
391dda1b SL |
23 | /* 2^7 = 128 */ |
24 | #define EVENT_HASH_BITS 7 | |
f0868d1e | 25 | |
52f6ad6d | 26 | DECLARE_RWSEM(trace_event_sem); |
be74b73a | 27 | |
391dda1b | 28 | static DEFINE_HASHTABLE(event_hash, EVENT_HASH_BITS); |
f0868d1e | 29 | |
09ae7234 SRRH |
30 | enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter) |
31 | { | |
32 | struct trace_seq *s = &iter->seq; | |
33 | struct trace_entry *entry = iter->ent; | |
34 | struct bputs_entry *field; | |
09ae7234 SRRH |
35 | |
36 | trace_assign_type(field, entry); | |
37 | ||
19a7fe20 | 38 | trace_seq_puts(s, field->str); |
09ae7234 | 39 | |
19a7fe20 | 40 | return trace_handle_return(s); |
09ae7234 SRRH |
41 | } |
42 | ||
5ef841f6 SR |
43 | enum 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; | |
5ef841f6 SR |
48 | |
49 | trace_assign_type(field, entry); | |
50 | ||
19a7fe20 | 51 | trace_seq_bprintf(s, field->fmt, field->buf); |
5ef841f6 | 52 | |
19a7fe20 | 53 | return trace_handle_return(s); |
5ef841f6 SR |
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; | |
5ef841f6 SR |
61 | |
62 | trace_assign_type(field, entry); | |
63 | ||
19a7fe20 | 64 | trace_seq_puts(s, field->buf); |
5ef841f6 | 65 | |
19a7fe20 | 66 | return trace_handle_return(s); |
5ef841f6 SR |
67 | } |
68 | ||
be74b73a | 69 | const char * |
645df987 SRRH |
70 | trace_print_flags_seq(struct trace_seq *p, const char *delim, |
71 | unsigned long flags, | |
72 | const struct trace_print_flags *flag_array) | |
be74b73a SR |
73 | { |
74 | unsigned long mask; | |
75 | const char *str; | |
7b039cb4 | 76 | const char *ret = trace_seq_buffer_ptr(p); |
e404b321 | 77 | int i, first = 1; |
be74b73a | 78 | |
be74b73a SR |
79 | for (i = 0; flag_array[i].name && flags; i++) { |
80 | ||
81 | mask = flag_array[i].mask; | |
82 | if ((flags & mask) != mask) | |
83 | continue; | |
84 | ||
85 | str = flag_array[i].name; | |
86 | flags &= ~mask; | |
e404b321 | 87 | if (!first && delim) |
be74b73a | 88 | trace_seq_puts(p, delim); |
e404b321 AV |
89 | else |
90 | first = 0; | |
be74b73a SR |
91 | trace_seq_puts(p, str); |
92 | } | |
93 | ||
94 | /* check for left over flags */ | |
95 | if (flags) { | |
5b349261 | 96 | if (!first && delim) |
be74b73a SR |
97 | trace_seq_puts(p, delim); |
98 | trace_seq_printf(p, "0x%lx", flags); | |
99 | } | |
100 | ||
101 | trace_seq_putc(p, 0); | |
102 | ||
56d8bd3f | 103 | return ret; |
be74b73a | 104 | } |
645df987 | 105 | EXPORT_SYMBOL(trace_print_flags_seq); |
be74b73a | 106 | |
0f4fc29d | 107 | const char * |
645df987 SRRH |
108 | trace_print_symbols_seq(struct trace_seq *p, unsigned long val, |
109 | const struct trace_print_flags *symbol_array) | |
0f4fc29d SR |
110 | { |
111 | int i; | |
7b039cb4 | 112 | const char *ret = trace_seq_buffer_ptr(p); |
0f4fc29d SR |
113 | |
114 | for (i = 0; symbol_array[i].name; i++) { | |
115 | ||
116 | if (val != symbol_array[i].mask) | |
117 | continue; | |
118 | ||
119 | trace_seq_puts(p, symbol_array[i].name); | |
120 | break; | |
121 | } | |
122 | ||
7b039cb4 | 123 | if (ret == (const char *)(trace_seq_buffer_ptr(p))) |
0f4fc29d | 124 | trace_seq_printf(p, "0x%lx", val); |
8e1e1df2 | 125 | |
0f4fc29d SR |
126 | trace_seq_putc(p, 0); |
127 | ||
56d8bd3f | 128 | return ret; |
0f4fc29d | 129 | } |
645df987 | 130 | EXPORT_SYMBOL(trace_print_symbols_seq); |
0f4fc29d | 131 | |
2fc1b6f0 | 132 | #if BITS_PER_LONG == 32 |
d3213e8f RZ |
133 | const char * |
134 | trace_print_flags_seq_u64(struct trace_seq *p, const char *delim, | |
135 | unsigned long long flags, | |
136 | const struct trace_print_flags_u64 *flag_array) | |
137 | { | |
138 | unsigned long long mask; | |
139 | const char *str; | |
140 | const char *ret = trace_seq_buffer_ptr(p); | |
141 | int i, first = 1; | |
142 | ||
143 | for (i = 0; flag_array[i].name && flags; i++) { | |
144 | ||
145 | mask = flag_array[i].mask; | |
146 | if ((flags & mask) != mask) | |
147 | continue; | |
148 | ||
149 | str = flag_array[i].name; | |
150 | flags &= ~mask; | |
151 | if (!first && delim) | |
152 | trace_seq_puts(p, delim); | |
153 | else | |
154 | first = 0; | |
155 | trace_seq_puts(p, str); | |
156 | } | |
157 | ||
158 | /* check for left over flags */ | |
159 | if (flags) { | |
160 | if (!first && delim) | |
161 | trace_seq_puts(p, delim); | |
162 | trace_seq_printf(p, "0x%llx", flags); | |
163 | } | |
164 | ||
165 | trace_seq_putc(p, 0); | |
166 | ||
167 | return ret; | |
168 | } | |
169 | EXPORT_SYMBOL(trace_print_flags_seq_u64); | |
170 | ||
2fc1b6f0 | 171 | const char * |
645df987 | 172 | trace_print_symbols_seq_u64(struct trace_seq *p, unsigned long long val, |
2fc1b6f0 | 173 | const struct trace_print_flags_u64 *symbol_array) |
174 | { | |
175 | int i; | |
7b039cb4 | 176 | const char *ret = trace_seq_buffer_ptr(p); |
2fc1b6f0 | 177 | |
178 | for (i = 0; symbol_array[i].name; i++) { | |
179 | ||
180 | if (val != symbol_array[i].mask) | |
181 | continue; | |
182 | ||
183 | trace_seq_puts(p, symbol_array[i].name); | |
184 | break; | |
185 | } | |
186 | ||
7b039cb4 | 187 | if (ret == (const char *)(trace_seq_buffer_ptr(p))) |
2fc1b6f0 | 188 | trace_seq_printf(p, "0x%llx", val); |
189 | ||
190 | trace_seq_putc(p, 0); | |
191 | ||
192 | return ret; | |
193 | } | |
645df987 | 194 | EXPORT_SYMBOL(trace_print_symbols_seq_u64); |
2fc1b6f0 | 195 | #endif |
196 | ||
4449bf92 | 197 | const char * |
645df987 SRRH |
198 | trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr, |
199 | unsigned int bitmask_size) | |
4449bf92 | 200 | { |
7b039cb4 | 201 | const char *ret = trace_seq_buffer_ptr(p); |
4449bf92 SRRH |
202 | |
203 | trace_seq_bitmask(p, bitmask_ptr, bitmask_size * 8); | |
204 | trace_seq_putc(p, 0); | |
205 | ||
206 | return ret; | |
207 | } | |
645df987 | 208 | EXPORT_SYMBOL_GPL(trace_print_bitmask_seq); |
4449bf92 | 209 | |
3898fac1 DB |
210 | /** |
211 | * trace_print_hex_seq - print buffer as hex sequence | |
212 | * @p: trace seq struct to write to | |
213 | * @buf: The buffer to print | |
214 | * @buf_len: Length of @buf in bytes | |
215 | * @concatenate: Print @buf as single hex string or with spacing | |
216 | * | |
217 | * Prints the passed buffer as a hex sequence either as a whole, | |
218 | * single hex string if @concatenate is true or with spacing after | |
219 | * each byte in case @concatenate is false. | |
220 | */ | |
5a2e3995 | 221 | const char * |
2acae0d5 | 222 | trace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len, |
3898fac1 | 223 | bool concatenate) |
5a2e3995 KT |
224 | { |
225 | int i; | |
7b039cb4 | 226 | const char *ret = trace_seq_buffer_ptr(p); |
119cdbdb | 227 | const char *fmt = concatenate ? "%*phN" : "%*ph"; |
5a2e3995 | 228 | |
adace440 KL |
229 | for (i = 0; i < buf_len; i += 16) { |
230 | if (!concatenate && i != 0) | |
231 | trace_seq_putc(p, ' '); | |
119cdbdb | 232 | trace_seq_printf(p, fmt, min(buf_len - i, 16), &buf[i]); |
adace440 | 233 | } |
5a2e3995 KT |
234 | trace_seq_putc(p, 0); |
235 | ||
236 | return ret; | |
237 | } | |
645df987 | 238 | EXPORT_SYMBOL(trace_print_hex_seq); |
5a2e3995 | 239 | |
6ea22486 | 240 | const char * |
645df987 SRRH |
241 | trace_print_array_seq(struct trace_seq *p, const void *buf, int count, |
242 | size_t el_size) | |
6ea22486 DM |
243 | { |
244 | const char *ret = trace_seq_buffer_ptr(p); | |
245 | const char *prefix = ""; | |
246 | void *ptr = (void *)buf; | |
ac01ce14 | 247 | size_t buf_len = count * el_size; |
6ea22486 DM |
248 | |
249 | trace_seq_putc(p, '{'); | |
250 | ||
251 | while (ptr < buf + buf_len) { | |
252 | switch (el_size) { | |
253 | case 1: | |
254 | trace_seq_printf(p, "%s0x%x", prefix, | |
255 | *(u8 *)ptr); | |
256 | break; | |
257 | case 2: | |
258 | trace_seq_printf(p, "%s0x%x", prefix, | |
259 | *(u16 *)ptr); | |
260 | break; | |
261 | case 4: | |
262 | trace_seq_printf(p, "%s0x%x", prefix, | |
263 | *(u32 *)ptr); | |
264 | break; | |
265 | case 8: | |
266 | trace_seq_printf(p, "%s0x%llx", prefix, | |
267 | *(u64 *)ptr); | |
268 | break; | |
269 | default: | |
270 | trace_seq_printf(p, "BAD SIZE:%zu 0x%x", el_size, | |
271 | *(u8 *)ptr); | |
272 | el_size = 1; | |
273 | } | |
274 | prefix = ","; | |
275 | ptr += el_size; | |
276 | } | |
277 | ||
278 | trace_seq_putc(p, '}'); | |
279 | trace_seq_putc(p, 0); | |
280 | ||
281 | return ret; | |
282 | } | |
645df987 | 283 | EXPORT_SYMBOL(trace_print_array_seq); |
6ea22486 | 284 | |
ef56e047 PM |
285 | const char * |
286 | trace_print_hex_dump_seq(struct trace_seq *p, const char *prefix_str, | |
287 | int prefix_type, int rowsize, int groupsize, | |
288 | const void *buf, size_t len, bool ascii) | |
289 | { | |
290 | const char *ret = trace_seq_buffer_ptr(p); | |
291 | ||
292 | trace_seq_putc(p, '\n'); | |
293 | trace_seq_hex_dump(p, prefix_str, prefix_type, | |
294 | rowsize, groupsize, buf, len, ascii); | |
295 | trace_seq_putc(p, 0); | |
296 | return ret; | |
297 | } | |
298 | EXPORT_SYMBOL(trace_print_hex_dump_seq); | |
299 | ||
892c505a SRRH |
300 | int trace_raw_output_prep(struct trace_iterator *iter, |
301 | struct trace_event *trace_event) | |
f71130de | 302 | { |
2425bcb9 | 303 | struct trace_event_call *event; |
f71130de LZ |
304 | struct trace_seq *s = &iter->seq; |
305 | struct trace_seq *p = &iter->tmp_seq; | |
306 | struct trace_entry *entry; | |
f71130de | 307 | |
2425bcb9 | 308 | event = container_of(trace_event, struct trace_event_call, event); |
f71130de LZ |
309 | entry = iter->ent; |
310 | ||
311 | if (entry->type != event->event.type) { | |
312 | WARN_ON_ONCE(1); | |
313 | return TRACE_TYPE_UNHANDLED; | |
314 | } | |
315 | ||
316 | trace_seq_init(p); | |
687fcc4a | 317 | trace_seq_printf(s, "%s: ", trace_event_name(event)); |
19a7fe20 | 318 | |
8e2e095c | 319 | return trace_handle_return(s); |
f71130de | 320 | } |
892c505a | 321 | EXPORT_SYMBOL(trace_raw_output_prep); |
f71130de | 322 | |
efbbdaa2 MH |
323 | void trace_event_printf(struct trace_iterator *iter, const char *fmt, ...) |
324 | { | |
afd2627f | 325 | struct trace_seq *s = &iter->seq; |
efbbdaa2 MH |
326 | va_list ap; |
327 | ||
afd2627f SR |
328 | if (ignore_event(iter)) |
329 | return; | |
330 | ||
efbbdaa2 | 331 | va_start(ap, fmt); |
afd2627f | 332 | trace_seq_vprintf(s, trace_event_format(iter, fmt), ap); |
efbbdaa2 MH |
333 | va_end(ap); |
334 | } | |
335 | EXPORT_SYMBOL(trace_event_printf); | |
336 | ||
bfd5a5e8 DH |
337 | static __printf(3, 0) |
338 | int trace_output_raw(struct trace_iterator *iter, char *name, | |
339 | char *fmt, va_list ap) | |
1d6bae96 SR |
340 | { |
341 | struct trace_seq *s = &iter->seq; | |
1d6bae96 | 342 | |
19a7fe20 | 343 | trace_seq_printf(s, "%s: ", name); |
efbbdaa2 | 344 | trace_seq_vprintf(s, trace_event_format(iter, fmt), ap); |
1d6bae96 | 345 | |
19a7fe20 | 346 | return trace_handle_return(s); |
1d6bae96 SR |
347 | } |
348 | ||
892c505a | 349 | int trace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...) |
1d6bae96 SR |
350 | { |
351 | va_list ap; | |
352 | int ret; | |
353 | ||
354 | va_start(ap, fmt); | |
892c505a | 355 | ret = trace_output_raw(iter, name, fmt, ap); |
1d6bae96 SR |
356 | va_end(ap); |
357 | ||
358 | return ret; | |
359 | } | |
892c505a | 360 | EXPORT_SYMBOL_GPL(trace_output_call); |
1d6bae96 | 361 | |
7da89495 | 362 | static inline const char *kretprobed(const char *name, unsigned long addr) |
f0868d1e | 363 | { |
7da89495 | 364 | if (is_kretprobe_trampoline(addr)) |
f0868d1e SR |
365 | return "[unknown/kretprobe'd]"; |
366 | return name; | |
367 | } | |
f0868d1e | 368 | |
773c1670 SRV |
369 | void |
370 | trace_seq_print_sym(struct trace_seq *s, unsigned long address, bool offset) | |
f0868d1e | 371 | { |
feaf1283 | 372 | #ifdef CONFIG_KALLSYMS |
bea6957d | 373 | char str[KSYM_SYMBOL_LEN]; |
f0868d1e SR |
374 | const char *name; |
375 | ||
59dd974b RV |
376 | if (offset) |
377 | sprint_symbol(str, address); | |
378 | else | |
379 | kallsyms_lookup(address, NULL, NULL, NULL, str); | |
7da89495 | 380 | name = kretprobed(str, address); |
f0868d1e | 381 | |
feaf1283 | 382 | if (name && strlen(name)) { |
bea6957d | 383 | trace_seq_puts(s, name); |
feaf1283 SRV |
384 | return; |
385 | } | |
f0868d1e | 386 | #endif |
bea6957d | 387 | trace_seq_printf(s, "0x%08lx", address); |
f0868d1e SR |
388 | } |
389 | ||
390 | #ifndef CONFIG_64BIT | |
391 | # define IP_FMT "%08lx" | |
392 | #else | |
393 | # define IP_FMT "%016lx" | |
394 | #endif | |
395 | ||
ef92480a SRRH |
396 | static int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, |
397 | unsigned long ip, unsigned long sym_flags) | |
f0868d1e SR |
398 | { |
399 | struct file *file = NULL; | |
400 | unsigned long vmstart = 0; | |
401 | int ret = 1; | |
402 | ||
d184b31c JB |
403 | if (s->full) |
404 | return 0; | |
405 | ||
f0868d1e SR |
406 | if (mm) { |
407 | const struct vm_area_struct *vma; | |
408 | ||
d8ed45c5 | 409 | mmap_read_lock(mm); |
f0868d1e SR |
410 | vma = find_vma(mm, ip); |
411 | if (vma) { | |
412 | file = vma->vm_file; | |
413 | vmstart = vma->vm_start; | |
414 | } | |
415 | if (file) { | |
08582d67 | 416 | ret = trace_seq_path(s, file_user_path(file)); |
f0868d1e | 417 | if (ret) |
19a7fe20 SRRH |
418 | trace_seq_printf(s, "[+0x%lx]", |
419 | ip - vmstart); | |
f0868d1e | 420 | } |
d8ed45c5 | 421 | mmap_read_unlock(mm); |
f0868d1e SR |
422 | } |
423 | if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file)) | |
19a7fe20 SRRH |
424 | trace_seq_printf(s, " <" IP_FMT ">", ip); |
425 | return !trace_seq_has_overflowed(s); | |
f0868d1e SR |
426 | } |
427 | ||
f0868d1e SR |
428 | int |
429 | seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags) | |
430 | { | |
19a7fe20 SRRH |
431 | if (!ip) { |
432 | trace_seq_putc(s, '0'); | |
433 | goto out; | |
434 | } | |
f0868d1e | 435 | |
773c1670 | 436 | trace_seq_print_sym(s, ip, sym_flags & TRACE_ITER_SYM_OFFSET); |
f0868d1e SR |
437 | |
438 | if (sym_flags & TRACE_ITER_SYM_ADDR) | |
19a7fe20 SRRH |
439 | trace_seq_printf(s, " <" IP_FMT ">", ip); |
440 | ||
441 | out: | |
442 | return !trace_seq_has_overflowed(s); | |
f0868d1e SR |
443 | } |
444 | ||
f81c972d SR |
445 | /** |
446 | * trace_print_lat_fmt - print the irq, preempt and lockdep fields | |
447 | * @s: trace seq struct to write to | |
448 | * @entry: The trace entry field from the ring buffer | |
449 | * | |
450 | * Prints the generic fields of irqs off, in hard or softirq, preempt | |
e6e1e259 | 451 | * count. |
f81c972d SR |
452 | */ |
453 | int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) | |
c4a8e8be | 454 | { |
10da37a6 DS |
455 | char hardsoft_irq; |
456 | char need_resched; | |
457 | char irqs_off; | |
458 | int hardirq; | |
459 | int softirq; | |
289e7b0f | 460 | int bh_off; |
7e6867bf | 461 | int nmi; |
c4a8e8be | 462 | |
7e6867bf | 463 | nmi = entry->flags & TRACE_FLAG_NMI; |
c4a8e8be FW |
464 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; |
465 | softirq = entry->flags & TRACE_FLAG_SOFTIRQ; | |
289e7b0f | 466 | bh_off = entry->flags & TRACE_FLAG_BH_OFF; |
d9793bd8 | 467 | |
10da37a6 | 468 | irqs_off = |
289e7b0f | 469 | (entry->flags & TRACE_FLAG_IRQS_OFF && bh_off) ? 'D' : |
10da37a6 | 470 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : |
289e7b0f | 471 | bh_off ? 'b' : |
10da37a6 | 472 | '.'; |
e5137b50 | 473 | |
0172afef | 474 | switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY | |
e5137b50 | 475 | TRACE_FLAG_PREEMPT_RESCHED)) { |
0172afef TG |
476 | case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED: |
477 | need_resched = 'B'; | |
478 | break; | |
e5137b50 PZ |
479 | case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_PREEMPT_RESCHED: |
480 | need_resched = 'N'; | |
481 | break; | |
0172afef TG |
482 | case TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED: |
483 | need_resched = 'L'; | |
484 | break; | |
485 | case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY: | |
486 | need_resched = 'b'; | |
487 | break; | |
e5137b50 PZ |
488 | case TRACE_FLAG_NEED_RESCHED: |
489 | need_resched = 'n'; | |
490 | break; | |
491 | case TRACE_FLAG_PREEMPT_RESCHED: | |
492 | need_resched = 'p'; | |
493 | break; | |
0172afef TG |
494 | case TRACE_FLAG_NEED_RESCHED_LAZY: |
495 | need_resched = 'l'; | |
496 | break; | |
e5137b50 PZ |
497 | default: |
498 | need_resched = '.'; | |
499 | break; | |
500 | } | |
501 | ||
10da37a6 | 502 | hardsoft_irq = |
7e6867bf PZ |
503 | (nmi && hardirq) ? 'Z' : |
504 | nmi ? 'z' : | |
10da37a6 | 505 | (hardirq && softirq) ? 'H' : |
7e6867bf PZ |
506 | hardirq ? 'h' : |
507 | softirq ? 's' : | |
508 | '.' ; | |
10da37a6 | 509 | |
19a7fe20 SRRH |
510 | trace_seq_printf(s, "%c%c%c", |
511 | irqs_off, need_resched, hardsoft_irq); | |
c4a8e8be | 512 | |
54357f0c TG |
513 | if (entry->preempt_count & 0xf) |
514 | trace_seq_printf(s, "%x", entry->preempt_count & 0xf); | |
515 | else | |
516 | trace_seq_putc(s, '.'); | |
517 | ||
518 | if (entry->preempt_count & 0xf0) | |
519 | trace_seq_printf(s, "%x", entry->preempt_count >> 4); | |
637e7e86 | 520 | else |
19a7fe20 | 521 | trace_seq_putc(s, '.'); |
829b876d | 522 | |
19a7fe20 | 523 | return !trace_seq_has_overflowed(s); |
c4a8e8be FW |
524 | } |
525 | ||
f81c972d SR |
526 | static int |
527 | lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu) | |
528 | { | |
529 | char comm[TASK_COMM_LEN]; | |
530 | ||
531 | trace_find_cmdline(entry->pid, comm); | |
532 | ||
795d6379 | 533 | trace_seq_printf(s, "%8.8s-%-7d %3d", |
19a7fe20 | 534 | comm, entry->pid, cpu); |
f81c972d SR |
535 | |
536 | return trace_print_lat_fmt(s, entry); | |
537 | } | |
538 | ||
8e1e1df2 BP |
539 | #undef MARK |
540 | #define MARK(v, s) {.val = v, .sym = s} | |
541 | /* trace overhead mark */ | |
542 | static const struct trace_mark { | |
543 | unsigned long long val; /* unit: nsec */ | |
544 | char sym; | |
545 | } mark[] = { | |
546 | MARK(1000000000ULL , '$'), /* 1 sec */ | |
b838e1d9 JL |
547 | MARK(100000000ULL , '@'), /* 100 msec */ |
548 | MARK(10000000ULL , '*'), /* 10 msec */ | |
8e1e1df2 BP |
549 | MARK(1000000ULL , '#'), /* 1000 usecs */ |
550 | MARK(100000ULL , '!'), /* 100 usecs */ | |
551 | MARK(10000ULL , '+'), /* 10 usecs */ | |
552 | }; | |
553 | #undef MARK | |
554 | ||
555 | char trace_find_mark(unsigned long long d) | |
556 | { | |
557 | int i; | |
558 | int size = ARRAY_SIZE(mark); | |
559 | ||
560 | for (i = 0; i < size; i++) { | |
b838e1d9 | 561 | if (d > mark[i].val) |
8e1e1df2 BP |
562 | break; |
563 | } | |
564 | ||
565 | return (i == size) ? ' ' : mark[i].sym; | |
566 | } | |
c4a8e8be | 567 | |
d9793bd8 | 568 | static int |
8be0709f | 569 | lat_print_timestamp(struct trace_iterator *iter, u64 next_ts) |
c4a8e8be | 570 | { |
983f938a SRRH |
571 | struct trace_array *tr = iter->tr; |
572 | unsigned long verbose = tr->trace_flags & TRACE_ITER_VERBOSE; | |
8be0709f | 573 | unsigned long in_ns = iter->iter_flags & TRACE_FILE_TIME_IN_NS; |
1c5eb448 | 574 | unsigned long long abs_ts = iter->ts - iter->array_buffer->time_start; |
8be0709f DS |
575 | unsigned long long rel_ts = next_ts - iter->ts; |
576 | struct trace_seq *s = &iter->seq; | |
577 | ||
578 | if (in_ns) { | |
579 | abs_ts = ns2usecs(abs_ts); | |
580 | rel_ts = ns2usecs(rel_ts); | |
581 | } | |
582 | ||
583 | if (verbose && in_ns) { | |
584 | unsigned long abs_usec = do_div(abs_ts, USEC_PER_MSEC); | |
585 | unsigned long abs_msec = (unsigned long)abs_ts; | |
586 | unsigned long rel_usec = do_div(rel_ts, USEC_PER_MSEC); | |
587 | unsigned long rel_msec = (unsigned long)rel_ts; | |
588 | ||
19a7fe20 SRRH |
589 | trace_seq_printf( |
590 | s, "[%08llx] %ld.%03ldms (+%ld.%03ldms): ", | |
591 | ns2usecs(iter->ts), | |
592 | abs_msec, abs_usec, | |
593 | rel_msec, rel_usec); | |
594 | ||
8be0709f | 595 | } else if (verbose && !in_ns) { |
19a7fe20 SRRH |
596 | trace_seq_printf( |
597 | s, "[%016llx] %lld (+%lld): ", | |
598 | iter->ts, abs_ts, rel_ts); | |
599 | ||
8be0709f | 600 | } else if (!verbose && in_ns) { |
19a7fe20 SRRH |
601 | trace_seq_printf( |
602 | s, " %4lldus%c: ", | |
603 | abs_ts, | |
8e1e1df2 | 604 | trace_find_mark(rel_ts * NSEC_PER_USEC)); |
19a7fe20 | 605 | |
8be0709f | 606 | } else { /* !verbose && !in_ns */ |
19a7fe20 | 607 | trace_seq_printf(s, " %4lld: ", abs_ts); |
8be0709f | 608 | } |
19a7fe20 SRRH |
609 | |
610 | return !trace_seq_has_overflowed(s); | |
c4a8e8be FW |
611 | } |
612 | ||
eaa7a897 YKV |
613 | static void trace_print_time(struct trace_seq *s, struct trace_iterator *iter, |
614 | unsigned long long ts) | |
615 | { | |
616 | unsigned long secs, usec_rem; | |
617 | unsigned long long t; | |
618 | ||
619 | if (iter->iter_flags & TRACE_FILE_TIME_IN_NS) { | |
620 | t = ns2usecs(ts); | |
621 | usec_rem = do_div(t, USEC_PER_SEC); | |
622 | secs = (unsigned long)t; | |
623 | trace_seq_printf(s, " %5lu.%06lu", secs, usec_rem); | |
624 | } else | |
625 | trace_seq_printf(s, " %12llu", ts); | |
626 | } | |
627 | ||
c4a8e8be FW |
628 | int trace_print_context(struct trace_iterator *iter) |
629 | { | |
983f938a | 630 | struct trace_array *tr = iter->tr; |
c4a8e8be FW |
631 | struct trace_seq *s = &iter->seq; |
632 | struct trace_entry *entry = iter->ent; | |
4ca53085 SR |
633 | char comm[TASK_COMM_LEN]; |
634 | ||
635 | trace_find_cmdline(entry->pid, comm); | |
c4a8e8be | 636 | |
795d6379 | 637 | trace_seq_printf(s, "%16s-%-7d ", comm, entry->pid); |
77271ce4 | 638 | |
441dae8f JF |
639 | if (tr->trace_flags & TRACE_ITER_RECORD_TGID) { |
640 | unsigned int tgid = trace_find_tgid(entry->pid); | |
641 | ||
642 | if (!tgid) | |
795d6379 | 643 | trace_seq_printf(s, "(-------) "); |
441dae8f | 644 | else |
795d6379 | 645 | trace_seq_printf(s, "(%7d) ", tgid); |
441dae8f JF |
646 | } |
647 | ||
f8494fa3 JFG |
648 | trace_seq_printf(s, "[%03d] ", iter->cpu); |
649 | ||
983f938a | 650 | if (tr->trace_flags & TRACE_ITER_IRQ_INFO) |
19a7fe20 | 651 | trace_print_lat_fmt(s, entry); |
77271ce4 | 652 | |
eaa7a897 YKV |
653 | trace_print_time(s, iter, iter->ts); |
654 | trace_seq_puts(s, ": "); | |
19a7fe20 SRRH |
655 | |
656 | return !trace_seq_has_overflowed(s); | |
c4a8e8be FW |
657 | } |
658 | ||
659 | int trace_print_lat_context(struct trace_iterator *iter) | |
660 | { | |
ff895103 | 661 | struct trace_entry *entry, *next_entry; |
983f938a | 662 | struct trace_array *tr = iter->tr; |
c4a8e8be | 663 | struct trace_seq *s = &iter->seq; |
983f938a | 664 | unsigned long verbose = (tr->trace_flags & TRACE_ITER_VERBOSE); |
ff895103 | 665 | u64 next_ts; |
c4a8e8be | 666 | |
ff895103 | 667 | next_entry = trace_find_next_entry(iter, NULL, &next_ts); |
c4a8e8be FW |
668 | if (!next_entry) |
669 | next_ts = iter->ts; | |
c4a8e8be | 670 | |
ff895103 SRV |
671 | /* trace_find_next_entry() may change iter->ent */ |
672 | entry = iter->ent; | |
673 | ||
c4a8e8be | 674 | if (verbose) { |
4ca53085 SR |
675 | char comm[TASK_COMM_LEN]; |
676 | ||
677 | trace_find_cmdline(entry->pid, comm); | |
678 | ||
19a7fe20 | 679 | trace_seq_printf( |
795d6379 | 680 | s, "%16s %7d %3d %d %08x %08lx ", |
19a7fe20 | 681 | comm, entry->pid, iter->cpu, entry->flags, |
54357f0c | 682 | entry->preempt_count & 0xf, iter->idx); |
c4a8e8be | 683 | } else { |
19a7fe20 | 684 | lat_print_generic(s, entry, iter->cpu); |
c4a8e8be FW |
685 | } |
686 | ||
19a7fe20 | 687 | lat_print_timestamp(iter, next_ts); |
8be0709f | 688 | |
19a7fe20 | 689 | return !trace_seq_has_overflowed(s); |
c4a8e8be FW |
690 | } |
691 | ||
533c20b0 SS |
692 | #ifdef CONFIG_FUNCTION_TRACE_ARGS |
693 | void print_function_args(struct trace_seq *s, unsigned long *args, | |
694 | unsigned long func) | |
695 | { | |
696 | const struct btf_param *param; | |
697 | const struct btf_type *t; | |
698 | const char *param_name; | |
699 | char name[KSYM_NAME_LEN]; | |
700 | unsigned long arg; | |
701 | struct btf *btf; | |
702 | s32 tid, nr = 0; | |
703 | int a, p, x; | |
704 | ||
705 | trace_seq_printf(s, "("); | |
706 | ||
707 | if (!args) | |
708 | goto out; | |
709 | if (lookup_symbol_name(func, name)) | |
710 | goto out; | |
711 | ||
712 | /* TODO: Pass module name here too */ | |
713 | t = btf_find_func_proto(name, &btf); | |
714 | if (IS_ERR_OR_NULL(t)) | |
715 | goto out; | |
716 | ||
717 | param = btf_get_func_param(t, &nr); | |
718 | if (!param) | |
719 | goto out_put; | |
720 | ||
721 | for (a = 0, p = 0; p < nr; a++, p++) { | |
722 | if (p) | |
723 | trace_seq_puts(s, ", "); | |
724 | ||
725 | /* This only prints what the arch allows (6 args by default) */ | |
726 | if (a == FTRACE_REGS_MAX_ARGS) { | |
727 | trace_seq_puts(s, "..."); | |
728 | break; | |
729 | } | |
730 | ||
731 | arg = args[a]; | |
732 | ||
733 | param_name = btf_name_by_offset(btf, param[p].name_off); | |
734 | if (param_name) | |
735 | trace_seq_printf(s, "%s=", param_name); | |
736 | t = btf_type_skip_modifiers(btf, param[p].type, &tid); | |
737 | ||
738 | switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { | |
739 | case BTF_KIND_UNKN: | |
740 | trace_seq_putc(s, '?'); | |
741 | /* Still print unknown type values */ | |
742 | fallthrough; | |
743 | case BTF_KIND_PTR: | |
744 | trace_seq_printf(s, "0x%lx", arg); | |
745 | break; | |
746 | case BTF_KIND_INT: | |
747 | trace_seq_printf(s, "%ld", arg); | |
748 | break; | |
749 | case BTF_KIND_ENUM: | |
750 | trace_seq_printf(s, "%ld", arg); | |
751 | break; | |
752 | default: | |
753 | /* This does not handle complex arguments */ | |
754 | trace_seq_printf(s, "(%s)[0x%lx", btf_type_str(t), arg); | |
755 | for (x = sizeof(long); x < t->size; x += sizeof(long)) { | |
756 | trace_seq_putc(s, ':'); | |
757 | if (++a == FTRACE_REGS_MAX_ARGS) { | |
758 | trace_seq_puts(s, "...]"); | |
759 | goto out_put; | |
760 | } | |
761 | trace_seq_printf(s, "0x%lx", args[a]); | |
762 | } | |
763 | trace_seq_putc(s, ']'); | |
764 | break; | |
765 | } | |
766 | } | |
767 | out_put: | |
768 | btf_put(btf); | |
769 | out: | |
770 | trace_seq_printf(s, ")"); | |
771 | } | |
772 | #endif | |
773 | ||
f0868d1e SR |
774 | /** |
775 | * ftrace_find_event - find a registered event | |
776 | * @type: the type of event to look for | |
777 | * | |
778 | * Returns an event of type @type otherwise NULL | |
4f535968 | 779 | * Called with trace_event_read_lock() held. |
f0868d1e SR |
780 | */ |
781 | struct trace_event *ftrace_find_event(int type) | |
782 | { | |
783 | struct trace_event *event; | |
f0868d1e | 784 | |
391dda1b | 785 | hash_for_each_possible(event_hash, event, node, type) { |
f0868d1e SR |
786 | if (event->type == type) |
787 | return event; | |
788 | } | |
789 | ||
790 | return NULL; | |
791 | } | |
792 | ||
96e6122c | 793 | static DEFINE_IDA(trace_event_ida); |
060fa5c8 | 794 | |
96e6122c | 795 | static void free_trace_event_type(int type) |
060fa5c8 | 796 | { |
96e6122c ZY |
797 | if (type >= __TRACE_LAST_TYPE) |
798 | ida_free(&trace_event_ida, type); | |
799 | } | |
060fa5c8 | 800 | |
96e6122c ZY |
801 | static int alloc_trace_event_type(void) |
802 | { | |
803 | int next; | |
060fa5c8 | 804 | |
96e6122c ZY |
805 | /* Skip static defined type numbers */ |
806 | next = ida_alloc_range(&trace_event_ida, __TRACE_LAST_TYPE, | |
807 | TRACE_EVENT_TYPE_MAX, GFP_KERNEL); | |
808 | if (next < 0) | |
060fa5c8 | 809 | return 0; |
746cf345 | 810 | return next; |
060fa5c8 SR |
811 | } |
812 | ||
4f535968 LJ |
813 | void trace_event_read_lock(void) |
814 | { | |
52f6ad6d | 815 | down_read(&trace_event_sem); |
4f535968 LJ |
816 | } |
817 | ||
818 | void trace_event_read_unlock(void) | |
819 | { | |
52f6ad6d | 820 | up_read(&trace_event_sem); |
4f535968 LJ |
821 | } |
822 | ||
f0868d1e | 823 | /** |
9023c930 | 824 | * register_trace_event - register output for an event type |
f0868d1e SR |
825 | * @event: the event type to register |
826 | * | |
827 | * Event types are stored in a hash and this hash is used to | |
828 | * find a way to print an event. If the @event->type is set | |
829 | * then it will use that type, otherwise it will assign a | |
830 | * type to use. | |
831 | * | |
832 | * If you assign your own type, please make sure it is added | |
833 | * to the trace_type enum in trace.h, to avoid collisions | |
834 | * with the dynamic types. | |
835 | * | |
836 | * Returns the event type number or zero on error. | |
837 | */ | |
9023c930 | 838 | int register_trace_event(struct trace_event *event) |
f0868d1e | 839 | { |
f0868d1e SR |
840 | int ret = 0; |
841 | ||
52f6ad6d | 842 | down_write(&trace_event_sem); |
f0868d1e | 843 | |
060fa5c8 | 844 | if (WARN_ON(!event)) |
28bea271 | 845 | goto out; |
28bea271 | 846 | |
a9a57763 SR |
847 | if (WARN_ON(!event->funcs)) |
848 | goto out; | |
849 | ||
060fa5c8 | 850 | if (!event->type) { |
96e6122c ZY |
851 | event->type = alloc_trace_event_type(); |
852 | if (!event->type) | |
060fa5c8 | 853 | goto out; |
4ee51101 GZ |
854 | } else if (WARN(event->type > __TRACE_LAST_TYPE, |
855 | "Need to add type to trace.h")) { | |
f0868d1e | 856 | goto out; |
060fa5c8 SR |
857 | } else { |
858 | /* Is this event already used */ | |
859 | if (ftrace_find_event(event->type)) | |
860 | goto out; | |
861 | } | |
f0868d1e | 862 | |
a9a57763 SR |
863 | if (event->funcs->trace == NULL) |
864 | event->funcs->trace = trace_nop_print; | |
865 | if (event->funcs->raw == NULL) | |
866 | event->funcs->raw = trace_nop_print; | |
867 | if (event->funcs->hex == NULL) | |
868 | event->funcs->hex = trace_nop_print; | |
869 | if (event->funcs->binary == NULL) | |
870 | event->funcs->binary = trace_nop_print; | |
268ccda0 | 871 | |
391dda1b | 872 | hash_add(event_hash, &event->node, event->type); |
f0868d1e SR |
873 | |
874 | ret = event->type; | |
875 | out: | |
52f6ad6d | 876 | up_write(&trace_event_sem); |
f0868d1e SR |
877 | |
878 | return ret; | |
879 | } | |
9023c930 | 880 | EXPORT_SYMBOL_GPL(register_trace_event); |
f0868d1e | 881 | |
110bf2b7 | 882 | /* |
52f6ad6d | 883 | * Used by module code with the trace_event_sem held for write. |
110bf2b7 | 884 | */ |
9023c930 | 885 | int __unregister_trace_event(struct trace_event *event) |
110bf2b7 | 886 | { |
391dda1b | 887 | hash_del(&event->node); |
96e6122c | 888 | free_trace_event_type(event->type); |
110bf2b7 SR |
889 | return 0; |
890 | } | |
891 | ||
f0868d1e | 892 | /** |
9023c930 | 893 | * unregister_trace_event - remove a no longer used event |
f0868d1e SR |
894 | * @event: the event to remove |
895 | */ | |
9023c930 | 896 | int unregister_trace_event(struct trace_event *event) |
f0868d1e | 897 | { |
52f6ad6d | 898 | down_write(&trace_event_sem); |
9023c930 | 899 | __unregister_trace_event(event); |
52f6ad6d | 900 | up_write(&trace_event_sem); |
f0868d1e SR |
901 | |
902 | return 0; | |
903 | } | |
9023c930 | 904 | EXPORT_SYMBOL_GPL(unregister_trace_event); |
f633cef0 SR |
905 | |
906 | /* | |
907 | * Standard events | |
908 | */ | |
909 | ||
80a76994 SRG |
910 | static void print_array(struct trace_iterator *iter, void *pos, |
911 | struct ftrace_event_field *field) | |
912 | { | |
913 | int offset; | |
914 | int len; | |
915 | int i; | |
916 | ||
917 | offset = *(int *)pos & 0xffff; | |
918 | len = *(int *)pos >> 16; | |
919 | ||
920 | if (field) | |
c7bdb079 | 921 | offset += field->offset + sizeof(int); |
80a76994 | 922 | |
c7bdb079 | 923 | if (offset + len > iter->ent_size) { |
80a76994 SRG |
924 | trace_seq_puts(&iter->seq, "<OVERFLOW>"); |
925 | return; | |
926 | } | |
927 | ||
c7bdb079 BB |
928 | pos = (void *)iter->ent + offset; |
929 | ||
80a76994 SRG |
930 | for (i = 0; i < len; i++, pos++) { |
931 | if (i) | |
932 | trace_seq_putc(&iter->seq, ','); | |
933 | trace_seq_printf(&iter->seq, "%02x", *(unsigned char *)pos); | |
934 | } | |
935 | } | |
936 | ||
937 | static void print_fields(struct trace_iterator *iter, struct trace_event_call *call, | |
938 | struct list_head *head) | |
939 | { | |
940 | struct ftrace_event_field *field; | |
dc6a49d4 SR |
941 | struct trace_array *tr = iter->tr; |
942 | unsigned long long laddr; | |
943 | unsigned long addr; | |
80a76994 SRG |
944 | int offset; |
945 | int len; | |
946 | int ret; | |
947 | void *pos; | |
948 | ||
e70bb54d | 949 | list_for_each_entry_reverse(field, head, link) { |
80a76994 SRG |
950 | trace_seq_printf(&iter->seq, " %s=", field->name); |
951 | if (field->offset + field->size > iter->ent_size) { | |
952 | trace_seq_puts(&iter->seq, "<OVERFLOW>"); | |
953 | continue; | |
954 | } | |
955 | pos = (void *)iter->ent + field->offset; | |
956 | ||
957 | switch (field->filter_type) { | |
958 | case FILTER_COMM: | |
959 | case FILTER_STATIC_STRING: | |
960 | trace_seq_printf(&iter->seq, "%.*s", field->size, (char *)pos); | |
961 | break; | |
962 | case FILTER_RDYN_STRING: | |
963 | case FILTER_DYN_STRING: | |
964 | offset = *(int *)pos & 0xffff; | |
965 | len = *(int *)pos >> 16; | |
966 | ||
967 | if (field->filter_type == FILTER_RDYN_STRING) | |
c7bdb079 | 968 | offset += field->offset + sizeof(int); |
80a76994 | 969 | |
c7bdb079 | 970 | if (offset + len > iter->ent_size) { |
80a76994 SRG |
971 | trace_seq_puts(&iter->seq, "<OVERFLOW>"); |
972 | break; | |
973 | } | |
974 | pos = (void *)iter->ent + offset; | |
975 | trace_seq_printf(&iter->seq, "%.*s", len, (char *)pos); | |
976 | break; | |
977 | case FILTER_PTR_STRING: | |
978 | if (!iter->fmt_size) | |
979 | trace_iter_expand_format(iter); | |
dc6a49d4 SR |
980 | addr = trace_adjust_address(tr, *(unsigned long *)pos); |
981 | ret = strncpy_from_kernel_nofault(iter->fmt, (void *)addr, | |
80a76994 SRG |
982 | iter->fmt_size); |
983 | if (ret < 0) | |
984 | trace_seq_printf(&iter->seq, "(0x%px)", pos); | |
985 | else | |
986 | trace_seq_printf(&iter->seq, "(0x%px:%s)", | |
987 | pos, iter->fmt); | |
988 | break; | |
989 | case FILTER_TRACE_FN: | |
dc6a49d4 SR |
990 | addr = trace_adjust_address(tr, *(unsigned long *)pos); |
991 | trace_seq_printf(&iter->seq, "%pS", (void *)addr); | |
80a76994 SRG |
992 | break; |
993 | case FILTER_CPU: | |
994 | case FILTER_OTHER: | |
995 | switch (field->size) { | |
996 | case 1: | |
997 | if (isprint(*(char *)pos)) { | |
998 | trace_seq_printf(&iter->seq, "'%c'", | |
999 | *(unsigned char *)pos); | |
1000 | } | |
1001 | trace_seq_printf(&iter->seq, "(%d)", | |
1002 | *(unsigned char *)pos); | |
1003 | break; | |
1004 | case 2: | |
1005 | trace_seq_printf(&iter->seq, "0x%x (%d)", | |
1006 | *(unsigned short *)pos, | |
1007 | *(unsigned short *)pos); | |
1008 | break; | |
1009 | case 4: | |
1010 | /* dynamic array info is 4 bytes */ | |
1011 | if (strstr(field->type, "__data_loc")) { | |
1012 | print_array(iter, pos, NULL); | |
1013 | break; | |
1014 | } | |
1015 | ||
1016 | if (strstr(field->type, "__rel_loc")) { | |
1017 | print_array(iter, pos, field); | |
1018 | break; | |
1019 | } | |
1020 | ||
dc6a49d4 | 1021 | addr = *(unsigned int *)pos; |
3e4b3716 SR |
1022 | |
1023 | /* Some fields reference offset from _stext. */ | |
1024 | if (!strcmp(field->name, "caller_offs") || | |
1025 | !strcmp(field->name, "parent_offs")) { | |
1026 | unsigned long ip; | |
1027 | ||
1028 | ip = addr + (unsigned long)_stext; | |
1029 | ip = trace_adjust_address(tr, ip); | |
1030 | trace_seq_printf(&iter->seq, "%pS ", (void *)ip); | |
1031 | } | |
1032 | ||
dc6a49d4 SR |
1033 | if (sizeof(long) == 4) { |
1034 | addr = trace_adjust_address(tr, addr); | |
531ee10b | 1035 | trace_seq_printf(&iter->seq, "%pS (%d)", |
dc6a49d4 SR |
1036 | (void *)addr, (int)addr); |
1037 | } else { | |
531ee10b | 1038 | trace_seq_printf(&iter->seq, "0x%x (%d)", |
dc6a49d4 SR |
1039 | (unsigned int)addr, (int)addr); |
1040 | } | |
80a76994 SRG |
1041 | break; |
1042 | case 8: | |
dc6a49d4 SR |
1043 | laddr = *(unsigned long long *)pos; |
1044 | if (sizeof(long) == 8) { | |
1045 | laddr = trace_adjust_address(tr, (unsigned long)laddr); | |
531ee10b | 1046 | trace_seq_printf(&iter->seq, "%pS (%lld)", |
dc6a49d4 SR |
1047 | (void *)(long)laddr, laddr); |
1048 | } else { | |
1049 | trace_seq_printf(&iter->seq, "0x%llx (%lld)", laddr, laddr); | |
1050 | } | |
80a76994 SRG |
1051 | break; |
1052 | default: | |
1053 | trace_seq_puts(&iter->seq, "<INVALID-SIZE>"); | |
1054 | break; | |
1055 | } | |
1056 | break; | |
1057 | default: | |
1058 | trace_seq_puts(&iter->seq, "<INVALID-TYPE>"); | |
1059 | } | |
1060 | } | |
1061 | trace_seq_putc(&iter->seq, '\n'); | |
1062 | } | |
1063 | ||
1064 | enum print_line_t print_event_fields(struct trace_iterator *iter, | |
1065 | struct trace_event *event) | |
1066 | { | |
1067 | struct trace_event_call *call; | |
1068 | struct list_head *head; | |
1069 | ||
0a8f11f8 SR |
1070 | lockdep_assert_held_read(&trace_event_sem); |
1071 | ||
80a76994 SRG |
1072 | /* ftrace defined events have separate call structures */ |
1073 | if (event->type <= __TRACE_LAST_TYPE) { | |
1074 | bool found = false; | |
1075 | ||
80a76994 SRG |
1076 | list_for_each_entry(call, &ftrace_events, list) { |
1077 | if (call->event.type == event->type) { | |
1078 | found = true; | |
1079 | break; | |
1080 | } | |
1081 | /* No need to search all events */ | |
1082 | if (call->event.type > __TRACE_LAST_TYPE) | |
1083 | break; | |
1084 | } | |
80a76994 SRG |
1085 | if (!found) { |
1086 | trace_seq_printf(&iter->seq, "UNKNOWN TYPE %d\n", event->type); | |
1087 | goto out; | |
1088 | } | |
1089 | } else { | |
1090 | call = container_of(event, struct trace_event_call, event); | |
1091 | } | |
1092 | head = trace_get_fields(call); | |
1093 | ||
1094 | trace_seq_printf(&iter->seq, "%s:", trace_event_name(call)); | |
1095 | ||
1096 | if (head && !list_empty(head)) | |
1097 | print_fields(iter, call, head); | |
1098 | else | |
1099 | trace_seq_puts(&iter->seq, "No fields found\n"); | |
1100 | ||
1101 | out: | |
1102 | return trace_handle_return(&iter->seq); | |
1103 | } | |
1104 | ||
a9a57763 SR |
1105 | enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags, |
1106 | struct trace_event *event) | |
f633cef0 | 1107 | { |
19a7fe20 | 1108 | trace_seq_printf(&iter->seq, "type: %d\n", iter->ent->type); |
ee5e51f5 | 1109 | |
19a7fe20 | 1110 | return trace_handle_return(&iter->seq); |
f633cef0 SR |
1111 | } |
1112 | ||
e1db6338 | 1113 | static void print_fn_trace(struct trace_seq *s, unsigned long ip, |
e3223e1e SR |
1114 | unsigned long parent_ip, unsigned long *args, |
1115 | struct trace_array *tr, int flags) | |
e1db6338 | 1116 | { |
e3223e1e SR |
1117 | ip = trace_adjust_address(tr, ip); |
1118 | parent_ip = trace_adjust_address(tr, parent_ip); | |
7cfeb903 | 1119 | |
e1db6338 | 1120 | seq_print_ip_sym(s, ip, flags); |
76fe0337 SS |
1121 | if (args) |
1122 | print_function_args(s, args, ip); | |
e1db6338 SRV |
1123 | |
1124 | if ((flags & TRACE_ITER_PRINT_PARENT) && parent_ip) { | |
1125 | trace_seq_puts(s, " <-"); | |
1126 | seq_print_ip_sym(s, parent_ip, flags); | |
1127 | } | |
1128 | } | |
1129 | ||
f633cef0 | 1130 | /* TRACE_FN */ |
a9a57763 SR |
1131 | static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags, |
1132 | struct trace_event *event) | |
f633cef0 SR |
1133 | { |
1134 | struct ftrace_entry *field; | |
2c9b238e | 1135 | struct trace_seq *s = &iter->seq; |
76fe0337 SS |
1136 | unsigned long *args; |
1137 | int args_size; | |
f633cef0 | 1138 | |
2c9b238e | 1139 | trace_assign_type(field, iter->ent); |
f633cef0 | 1140 | |
76fe0337 SS |
1141 | args_size = iter->ent_size - offsetof(struct ftrace_entry, args); |
1142 | if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) | |
1143 | args = field->args; | |
1144 | else | |
1145 | args = NULL; | |
1146 | ||
e3223e1e | 1147 | print_fn_trace(s, field->ip, field->parent_ip, args, iter->tr, flags); |
19a7fe20 | 1148 | trace_seq_putc(s, '\n'); |
f633cef0 | 1149 | |
19a7fe20 | 1150 | return trace_handle_return(s); |
f633cef0 SR |
1151 | } |
1152 | ||
a9a57763 SR |
1153 | static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags, |
1154 | struct trace_event *event) | |
f633cef0 SR |
1155 | { |
1156 | struct ftrace_entry *field; | |
1157 | ||
2c9b238e | 1158 | trace_assign_type(field, iter->ent); |
f633cef0 | 1159 | |
19a7fe20 SRRH |
1160 | trace_seq_printf(&iter->seq, "%lx %lx\n", |
1161 | field->ip, | |
1162 | field->parent_ip); | |
f633cef0 | 1163 | |
19a7fe20 | 1164 | return trace_handle_return(&iter->seq); |
f633cef0 SR |
1165 | } |
1166 | ||
a9a57763 SR |
1167 | static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags, |
1168 | struct trace_event *event) | |
f633cef0 SR |
1169 | { |
1170 | struct ftrace_entry *field; | |
2c9b238e | 1171 | struct trace_seq *s = &iter->seq; |
f633cef0 | 1172 | |
2c9b238e | 1173 | trace_assign_type(field, iter->ent); |
f633cef0 | 1174 | |
19a7fe20 SRRH |
1175 | SEQ_PUT_HEX_FIELD(s, field->ip); |
1176 | SEQ_PUT_HEX_FIELD(s, field->parent_ip); | |
f633cef0 | 1177 | |
19a7fe20 | 1178 | return trace_handle_return(s); |
f633cef0 SR |
1179 | } |
1180 | ||
a9a57763 SR |
1181 | static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags, |
1182 | struct trace_event *event) | |
f633cef0 SR |
1183 | { |
1184 | struct ftrace_entry *field; | |
2c9b238e | 1185 | struct trace_seq *s = &iter->seq; |
f633cef0 | 1186 | |
2c9b238e | 1187 | trace_assign_type(field, iter->ent); |
f633cef0 | 1188 | |
19a7fe20 SRRH |
1189 | SEQ_PUT_FIELD(s, field->ip); |
1190 | SEQ_PUT_FIELD(s, field->parent_ip); | |
f633cef0 | 1191 | |
19a7fe20 | 1192 | return trace_handle_return(s); |
f633cef0 SR |
1193 | } |
1194 | ||
a9a57763 | 1195 | static struct trace_event_functions trace_fn_funcs = { |
f633cef0 | 1196 | .trace = trace_fn_trace, |
f633cef0 SR |
1197 | .raw = trace_fn_raw, |
1198 | .hex = trace_fn_hex, | |
1199 | .binary = trace_fn_bin, | |
1200 | }; | |
1201 | ||
a9a57763 SR |
1202 | static struct trace_event trace_fn_event = { |
1203 | .type = TRACE_FN, | |
1204 | .funcs = &trace_fn_funcs, | |
1205 | }; | |
1206 | ||
f633cef0 | 1207 | /* TRACE_CTX an TRACE_WAKE */ |
ae7462b4 ACM |
1208 | static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, |
1209 | char *delim) | |
f633cef0 SR |
1210 | { |
1211 | struct ctx_switch_entry *field; | |
4ca53085 | 1212 | char comm[TASK_COMM_LEN]; |
f633cef0 SR |
1213 | int S, T; |
1214 | ||
4ca53085 | 1215 | |
2c9b238e | 1216 | trace_assign_type(field, iter->ent); |
f633cef0 | 1217 | |
1d48b080 PZ |
1218 | T = task_index_to_char(field->next_state); |
1219 | S = task_index_to_char(field->prev_state); | |
4ca53085 | 1220 | trace_find_cmdline(field->next_pid, comm); |
19a7fe20 | 1221 | trace_seq_printf(&iter->seq, |
795d6379 | 1222 | " %7d:%3d:%c %s [%03d] %7d:%3d:%c %s\n", |
19a7fe20 SRRH |
1223 | field->prev_pid, |
1224 | field->prev_prio, | |
1225 | S, delim, | |
1226 | field->next_cpu, | |
1227 | field->next_pid, | |
1228 | field->next_prio, | |
1229 | T, comm); | |
1230 | ||
1231 | return trace_handle_return(&iter->seq); | |
f633cef0 SR |
1232 | } |
1233 | ||
a9a57763 SR |
1234 | static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags, |
1235 | struct trace_event *event) | |
f633cef0 | 1236 | { |
2c9b238e | 1237 | return trace_ctxwake_print(iter, "==>"); |
f633cef0 SR |
1238 | } |
1239 | ||
ae7462b4 | 1240 | static enum print_line_t trace_wake_print(struct trace_iterator *iter, |
a9a57763 | 1241 | int flags, struct trace_event *event) |
f633cef0 | 1242 | { |
2c9b238e | 1243 | return trace_ctxwake_print(iter, " +"); |
f633cef0 SR |
1244 | } |
1245 | ||
2c9b238e | 1246 | static int trace_ctxwake_raw(struct trace_iterator *iter, char S) |
f633cef0 SR |
1247 | { |
1248 | struct ctx_switch_entry *field; | |
1249 | int T; | |
1250 | ||
2c9b238e | 1251 | trace_assign_type(field, iter->ent); |
f633cef0 SR |
1252 | |
1253 | if (!S) | |
1d48b080 PZ |
1254 | S = task_index_to_char(field->prev_state); |
1255 | T = task_index_to_char(field->next_state); | |
19a7fe20 SRRH |
1256 | trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n", |
1257 | field->prev_pid, | |
1258 | field->prev_prio, | |
1259 | S, | |
1260 | field->next_cpu, | |
1261 | field->next_pid, | |
1262 | field->next_prio, | |
1263 | T); | |
1264 | ||
1265 | return trace_handle_return(&iter->seq); | |
f633cef0 SR |
1266 | } |
1267 | ||
a9a57763 SR |
1268 | static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags, |
1269 | struct trace_event *event) | |
f633cef0 | 1270 | { |
2c9b238e | 1271 | return trace_ctxwake_raw(iter, 0); |
f633cef0 SR |
1272 | } |
1273 | ||
a9a57763 SR |
1274 | static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags, |
1275 | struct trace_event *event) | |
f633cef0 | 1276 | { |
2c9b238e | 1277 | return trace_ctxwake_raw(iter, '+'); |
f633cef0 SR |
1278 | } |
1279 | ||
1280 | ||
2c9b238e | 1281 | static int trace_ctxwake_hex(struct trace_iterator *iter, char S) |
f633cef0 SR |
1282 | { |
1283 | struct ctx_switch_entry *field; | |
2c9b238e | 1284 | struct trace_seq *s = &iter->seq; |
f633cef0 SR |
1285 | int T; |
1286 | ||
2c9b238e | 1287 | trace_assign_type(field, iter->ent); |
f633cef0 SR |
1288 | |
1289 | if (!S) | |
1d48b080 PZ |
1290 | S = task_index_to_char(field->prev_state); |
1291 | T = task_index_to_char(field->next_state); | |
f633cef0 | 1292 | |
19a7fe20 SRRH |
1293 | SEQ_PUT_HEX_FIELD(s, field->prev_pid); |
1294 | SEQ_PUT_HEX_FIELD(s, field->prev_prio); | |
1295 | SEQ_PUT_HEX_FIELD(s, S); | |
1296 | SEQ_PUT_HEX_FIELD(s, field->next_cpu); | |
1297 | SEQ_PUT_HEX_FIELD(s, field->next_pid); | |
1298 | SEQ_PUT_HEX_FIELD(s, field->next_prio); | |
1299 | SEQ_PUT_HEX_FIELD(s, T); | |
f633cef0 | 1300 | |
19a7fe20 | 1301 | return trace_handle_return(s); |
f633cef0 SR |
1302 | } |
1303 | ||
a9a57763 SR |
1304 | static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags, |
1305 | struct trace_event *event) | |
f633cef0 | 1306 | { |
2c9b238e | 1307 | return trace_ctxwake_hex(iter, 0); |
f633cef0 SR |
1308 | } |
1309 | ||
a9a57763 SR |
1310 | static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags, |
1311 | struct trace_event *event) | |
f633cef0 | 1312 | { |
2c9b238e | 1313 | return trace_ctxwake_hex(iter, '+'); |
f633cef0 SR |
1314 | } |
1315 | ||
ae7462b4 | 1316 | static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter, |
a9a57763 | 1317 | int flags, struct trace_event *event) |
f633cef0 SR |
1318 | { |
1319 | struct ctx_switch_entry *field; | |
2c9b238e | 1320 | struct trace_seq *s = &iter->seq; |
f633cef0 | 1321 | |
2c9b238e | 1322 | trace_assign_type(field, iter->ent); |
f633cef0 | 1323 | |
19a7fe20 SRRH |
1324 | SEQ_PUT_FIELD(s, field->prev_pid); |
1325 | SEQ_PUT_FIELD(s, field->prev_prio); | |
1326 | SEQ_PUT_FIELD(s, field->prev_state); | |
1327 | SEQ_PUT_FIELD(s, field->next_cpu); | |
1328 | SEQ_PUT_FIELD(s, field->next_pid); | |
1329 | SEQ_PUT_FIELD(s, field->next_prio); | |
1330 | SEQ_PUT_FIELD(s, field->next_state); | |
f633cef0 | 1331 | |
19a7fe20 | 1332 | return trace_handle_return(s); |
f633cef0 SR |
1333 | } |
1334 | ||
a9a57763 | 1335 | static struct trace_event_functions trace_ctx_funcs = { |
f633cef0 | 1336 | .trace = trace_ctx_print, |
f633cef0 SR |
1337 | .raw = trace_ctx_raw, |
1338 | .hex = trace_ctx_hex, | |
1339 | .binary = trace_ctxwake_bin, | |
1340 | }; | |
1341 | ||
a9a57763 SR |
1342 | static struct trace_event trace_ctx_event = { |
1343 | .type = TRACE_CTX, | |
1344 | .funcs = &trace_ctx_funcs, | |
1345 | }; | |
1346 | ||
1347 | static struct trace_event_functions trace_wake_funcs = { | |
f633cef0 | 1348 | .trace = trace_wake_print, |
f633cef0 SR |
1349 | .raw = trace_wake_raw, |
1350 | .hex = trace_wake_hex, | |
1351 | .binary = trace_ctxwake_bin, | |
1352 | }; | |
1353 | ||
a9a57763 SR |
1354 | static struct trace_event trace_wake_event = { |
1355 | .type = TRACE_WAKE, | |
1356 | .funcs = &trace_wake_funcs, | |
1357 | }; | |
1358 | ||
f633cef0 SR |
1359 | /* TRACE_STACK */ |
1360 | ||
ae7462b4 | 1361 | static enum print_line_t trace_stack_print(struct trace_iterator *iter, |
a9a57763 | 1362 | int flags, struct trace_event *event) |
f633cef0 SR |
1363 | { |
1364 | struct stack_entry *field; | |
2c9b238e | 1365 | struct trace_seq *s = &iter->seq; |
4a9bd3f1 SR |
1366 | unsigned long *p; |
1367 | unsigned long *end; | |
f633cef0 | 1368 | |
2c9b238e | 1369 | trace_assign_type(field, iter->ent); |
4a9bd3f1 | 1370 | end = (unsigned long *)((long)iter->ent + iter->ent_size); |
f633cef0 | 1371 | |
19a7fe20 | 1372 | trace_seq_puts(s, "<stack trace>\n"); |
4a9bd3f1 | 1373 | |
becf33f6 | 1374 | for (p = field->caller; p && p < end && *p != ULONG_MAX; p++) { |
f633cef0 | 1375 | |
19a7fe20 SRRH |
1376 | if (trace_seq_has_overflowed(s)) |
1377 | break; | |
f633cef0 | 1378 | |
19a7fe20 | 1379 | trace_seq_puts(s, " => "); |
6ce5a6f0 T |
1380 | if ((*p) == FTRACE_TRAMPOLINE_MARKER) { |
1381 | trace_seq_puts(s, "[FTRACE TRAMPOLINE]\n"); | |
1382 | continue; | |
1383 | } | |
35a380dd | 1384 | seq_print_ip_sym(s, trace_adjust_address(iter->tr, *p), flags); |
19a7fe20 SRRH |
1385 | trace_seq_putc(s, '\n'); |
1386 | } | |
f633cef0 | 1387 | |
19a7fe20 | 1388 | return trace_handle_return(s); |
f633cef0 SR |
1389 | } |
1390 | ||
a9a57763 | 1391 | static struct trace_event_functions trace_stack_funcs = { |
f633cef0 | 1392 | .trace = trace_stack_print, |
f633cef0 SR |
1393 | }; |
1394 | ||
a9a57763 SR |
1395 | static struct trace_event trace_stack_event = { |
1396 | .type = TRACE_STACK, | |
1397 | .funcs = &trace_stack_funcs, | |
1398 | }; | |
1399 | ||
f633cef0 | 1400 | /* TRACE_USER_STACK */ |
ae7462b4 | 1401 | static enum print_line_t trace_user_stack_print(struct trace_iterator *iter, |
a9a57763 | 1402 | int flags, struct trace_event *event) |
f633cef0 | 1403 | { |
983f938a | 1404 | struct trace_array *tr = iter->tr; |
f633cef0 | 1405 | struct userstack_entry *field; |
2c9b238e | 1406 | struct trace_seq *s = &iter->seq; |
6b1032d5 SRRH |
1407 | struct mm_struct *mm = NULL; |
1408 | unsigned int i; | |
f633cef0 | 1409 | |
2c9b238e | 1410 | trace_assign_type(field, iter->ent); |
f633cef0 | 1411 | |
19a7fe20 | 1412 | trace_seq_puts(s, "<user stack trace>\n"); |
6b1032d5 | 1413 | |
983f938a | 1414 | if (tr->trace_flags & TRACE_ITER_SYM_USEROBJ) { |
6b1032d5 SRRH |
1415 | struct task_struct *task; |
1416 | /* | |
1417 | * we do the lookup on the thread group leader, | |
1418 | * since individual threads might have already quit! | |
1419 | */ | |
1420 | rcu_read_lock(); | |
1421 | task = find_task_by_vpid(field->tgid); | |
1422 | if (task) | |
1423 | mm = get_task_mm(task); | |
1424 | rcu_read_unlock(); | |
1425 | } | |
1426 | ||
1427 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { | |
1428 | unsigned long ip = field->caller[i]; | |
1429 | ||
6d54ceb5 | 1430 | if (!ip || trace_seq_has_overflowed(s)) |
6b1032d5 SRRH |
1431 | break; |
1432 | ||
1433 | trace_seq_puts(s, " => "); | |
6b1032d5 SRRH |
1434 | seq_print_user_ip(s, mm, ip, flags); |
1435 | trace_seq_putc(s, '\n'); | |
1436 | } | |
1437 | ||
1438 | if (mm) | |
1439 | mmput(mm); | |
f633cef0 | 1440 | |
19a7fe20 | 1441 | return trace_handle_return(s); |
f633cef0 SR |
1442 | } |
1443 | ||
a9a57763 | 1444 | static struct trace_event_functions trace_user_stack_funcs = { |
f633cef0 | 1445 | .trace = trace_user_stack_print, |
f633cef0 SR |
1446 | }; |
1447 | ||
a9a57763 SR |
1448 | static struct trace_event trace_user_stack_event = { |
1449 | .type = TRACE_USER_STACK, | |
1450 | .funcs = &trace_user_stack_funcs, | |
1451 | }; | |
1452 | ||
e7c15cd8 SRRH |
1453 | /* TRACE_HWLAT */ |
1454 | static enum print_line_t | |
1455 | trace_hwlat_print(struct trace_iterator *iter, int flags, | |
1456 | struct trace_event *event) | |
1457 | { | |
1458 | struct trace_entry *entry = iter->ent; | |
1459 | struct trace_seq *s = &iter->seq; | |
1460 | struct hwlat_entry *field; | |
1461 | ||
1462 | trace_assign_type(field, entry); | |
1463 | ||
b396bfde | 1464 | trace_seq_printf(s, "#%-5u inner/outer(us): %4llu/%-5llu ts:%lld.%09ld count:%d", |
e7c15cd8 SRRH |
1465 | field->seqnum, |
1466 | field->duration, | |
1467 | field->outer_duration, | |
51aad0ae | 1468 | (long long)field->timestamp.tv_sec, |
b396bfde | 1469 | field->timestamp.tv_nsec, field->count); |
e7c15cd8 | 1470 | |
7b2c8625 SRRH |
1471 | if (field->nmi_count) { |
1472 | /* | |
1473 | * The generic sched_clock() is not NMI safe, thus | |
1474 | * we only record the count and not the time. | |
1475 | */ | |
1476 | if (!IS_ENABLED(CONFIG_GENERIC_SCHED_CLOCK)) | |
1477 | trace_seq_printf(s, " nmi-total:%llu", | |
1478 | field->nmi_total_ts); | |
1479 | trace_seq_printf(s, " nmi-count:%u", | |
1480 | field->nmi_count); | |
1481 | } | |
1482 | ||
1483 | trace_seq_putc(s, '\n'); | |
1484 | ||
e7c15cd8 SRRH |
1485 | return trace_handle_return(s); |
1486 | } | |
1487 | ||
e7c15cd8 SRRH |
1488 | static enum print_line_t |
1489 | trace_hwlat_raw(struct trace_iterator *iter, int flags, | |
1490 | struct trace_event *event) | |
1491 | { | |
1492 | struct hwlat_entry *field; | |
1493 | struct trace_seq *s = &iter->seq; | |
1494 | ||
1495 | trace_assign_type(field, iter->ent); | |
1496 | ||
51aad0ae | 1497 | trace_seq_printf(s, "%llu %lld %lld %09ld %u\n", |
e7c15cd8 SRRH |
1498 | field->duration, |
1499 | field->outer_duration, | |
51aad0ae | 1500 | (long long)field->timestamp.tv_sec, |
e7c15cd8 SRRH |
1501 | field->timestamp.tv_nsec, |
1502 | field->seqnum); | |
1503 | ||
1504 | return trace_handle_return(s); | |
1505 | } | |
1506 | ||
1507 | static struct trace_event_functions trace_hwlat_funcs = { | |
1508 | .trace = trace_hwlat_print, | |
1509 | .raw = trace_hwlat_raw, | |
1510 | }; | |
1511 | ||
1512 | static struct trace_event trace_hwlat_event = { | |
1513 | .type = TRACE_HWLAT, | |
1514 | .funcs = &trace_hwlat_funcs, | |
1515 | }; | |
1516 | ||
bce29ac9 DBO |
1517 | /* TRACE_OSNOISE */ |
1518 | static enum print_line_t | |
1519 | trace_osnoise_print(struct trace_iterator *iter, int flags, | |
1520 | struct trace_event *event) | |
1521 | { | |
1522 | struct trace_entry *entry = iter->ent; | |
1523 | struct trace_seq *s = &iter->seq; | |
1524 | struct osnoise_entry *field; | |
1525 | u64 ratio, ratio_dec; | |
1526 | u64 net_runtime; | |
1527 | ||
1528 | trace_assign_type(field, entry); | |
1529 | ||
1530 | /* | |
1531 | * compute the available % of cpu time. | |
1532 | */ | |
1533 | net_runtime = field->runtime - field->noise; | |
1534 | ratio = net_runtime * 10000000; | |
1535 | do_div(ratio, field->runtime); | |
1536 | ratio_dec = do_div(ratio, 100000); | |
1537 | ||
1538 | trace_seq_printf(s, "%llu %10llu %3llu.%05llu %7llu", | |
1539 | field->runtime, | |
1540 | field->noise, | |
1541 | ratio, ratio_dec, | |
1542 | field->max_sample); | |
1543 | ||
1544 | trace_seq_printf(s, " %6u", field->hw_count); | |
1545 | trace_seq_printf(s, " %6u", field->nmi_count); | |
1546 | trace_seq_printf(s, " %6u", field->irq_count); | |
1547 | trace_seq_printf(s, " %6u", field->softirq_count); | |
1548 | trace_seq_printf(s, " %6u", field->thread_count); | |
1549 | ||
1550 | trace_seq_putc(s, '\n'); | |
1551 | ||
1552 | return trace_handle_return(s); | |
1553 | } | |
1554 | ||
1555 | static enum print_line_t | |
1556 | trace_osnoise_raw(struct trace_iterator *iter, int flags, | |
1557 | struct trace_event *event) | |
1558 | { | |
1559 | struct osnoise_entry *field; | |
1560 | struct trace_seq *s = &iter->seq; | |
1561 | ||
1562 | trace_assign_type(field, iter->ent); | |
1563 | ||
1564 | trace_seq_printf(s, "%lld %llu %llu %u %u %u %u %u\n", | |
1565 | field->runtime, | |
1566 | field->noise, | |
1567 | field->max_sample, | |
1568 | field->hw_count, | |
1569 | field->nmi_count, | |
1570 | field->irq_count, | |
1571 | field->softirq_count, | |
1572 | field->thread_count); | |
1573 | ||
1574 | return trace_handle_return(s); | |
1575 | } | |
1576 | ||
1577 | static struct trace_event_functions trace_osnoise_funcs = { | |
1578 | .trace = trace_osnoise_print, | |
1579 | .raw = trace_osnoise_raw, | |
1580 | }; | |
1581 | ||
1582 | static struct trace_event trace_osnoise_event = { | |
1583 | .type = TRACE_OSNOISE, | |
1584 | .funcs = &trace_osnoise_funcs, | |
1585 | }; | |
1586 | ||
a955d7ea | 1587 | /* TRACE_TIMERLAT */ |
e88ed227 DBO |
1588 | |
1589 | static char *timerlat_lat_context[] = {"irq", "thread", "user-ret"}; | |
a955d7ea DBO |
1590 | static enum print_line_t |
1591 | trace_timerlat_print(struct trace_iterator *iter, int flags, | |
1592 | struct trace_event *event) | |
1593 | { | |
1594 | struct trace_entry *entry = iter->ent; | |
1595 | struct trace_seq *s = &iter->seq; | |
1596 | struct timerlat_entry *field; | |
1597 | ||
1598 | trace_assign_type(field, entry); | |
1599 | ||
1600 | trace_seq_printf(s, "#%-5u context %6s timer_latency %9llu ns\n", | |
1601 | field->seqnum, | |
e88ed227 | 1602 | timerlat_lat_context[field->context], |
a955d7ea DBO |
1603 | field->timer_latency); |
1604 | ||
1605 | return trace_handle_return(s); | |
1606 | } | |
1607 | ||
1608 | static enum print_line_t | |
1609 | trace_timerlat_raw(struct trace_iterator *iter, int flags, | |
1610 | struct trace_event *event) | |
1611 | { | |
1612 | struct timerlat_entry *field; | |
1613 | struct trace_seq *s = &iter->seq; | |
1614 | ||
1615 | trace_assign_type(field, iter->ent); | |
1616 | ||
1617 | trace_seq_printf(s, "%u %d %llu\n", | |
1618 | field->seqnum, | |
1619 | field->context, | |
1620 | field->timer_latency); | |
1621 | ||
1622 | return trace_handle_return(s); | |
1623 | } | |
1624 | ||
1625 | static struct trace_event_functions trace_timerlat_funcs = { | |
1626 | .trace = trace_timerlat_print, | |
1627 | .raw = trace_timerlat_raw, | |
1628 | }; | |
1629 | ||
1630 | static struct trace_event trace_timerlat_event = { | |
1631 | .type = TRACE_TIMERLAT, | |
1632 | .funcs = &trace_timerlat_funcs, | |
1633 | }; | |
1634 | ||
09ae7234 SRRH |
1635 | /* TRACE_BPUTS */ |
1636 | static enum print_line_t | |
1637 | trace_bputs_print(struct trace_iterator *iter, int flags, | |
1638 | struct trace_event *event) | |
1639 | { | |
1640 | struct trace_entry *entry = iter->ent; | |
1641 | struct trace_seq *s = &iter->seq; | |
1642 | struct bputs_entry *field; | |
1643 | ||
1644 | trace_assign_type(field, entry); | |
1645 | ||
19a7fe20 SRRH |
1646 | seq_print_ip_sym(s, field->ip, flags); |
1647 | trace_seq_puts(s, ": "); | |
1648 | trace_seq_puts(s, field->str); | |
09ae7234 | 1649 | |
19a7fe20 | 1650 | return trace_handle_return(s); |
09ae7234 SRRH |
1651 | } |
1652 | ||
1653 | ||
1654 | static enum print_line_t | |
1655 | trace_bputs_raw(struct trace_iterator *iter, int flags, | |
1656 | struct trace_event *event) | |
1657 | { | |
1658 | struct bputs_entry *field; | |
1659 | struct trace_seq *s = &iter->seq; | |
1660 | ||
1661 | trace_assign_type(field, iter->ent); | |
1662 | ||
19a7fe20 SRRH |
1663 | trace_seq_printf(s, ": %lx : ", field->ip); |
1664 | trace_seq_puts(s, field->str); | |
09ae7234 | 1665 | |
19a7fe20 | 1666 | return trace_handle_return(s); |
09ae7234 SRRH |
1667 | } |
1668 | ||
1669 | static struct trace_event_functions trace_bputs_funcs = { | |
1670 | .trace = trace_bputs_print, | |
1671 | .raw = trace_bputs_raw, | |
1672 | }; | |
1673 | ||
1674 | static struct trace_event trace_bputs_event = { | |
1675 | .type = TRACE_BPUTS, | |
1676 | .funcs = &trace_bputs_funcs, | |
1677 | }; | |
1678 | ||
48ead020 | 1679 | /* TRACE_BPRINT */ |
1427cdf0 | 1680 | static enum print_line_t |
a9a57763 SR |
1681 | trace_bprint_print(struct trace_iterator *iter, int flags, |
1682 | struct trace_event *event) | |
1427cdf0 LJ |
1683 | { |
1684 | struct trace_entry *entry = iter->ent; | |
1685 | struct trace_seq *s = &iter->seq; | |
48ead020 | 1686 | struct bprint_entry *field; |
1427cdf0 LJ |
1687 | |
1688 | trace_assign_type(field, entry); | |
1689 | ||
19a7fe20 SRRH |
1690 | seq_print_ip_sym(s, field->ip, flags); |
1691 | trace_seq_puts(s, ": "); | |
1692 | trace_seq_bprintf(s, field->fmt, field->buf); | |
1427cdf0 | 1693 | |
19a7fe20 | 1694 | return trace_handle_return(s); |
1427cdf0 LJ |
1695 | } |
1696 | ||
769b0441 | 1697 | |
48ead020 | 1698 | static enum print_line_t |
a9a57763 SR |
1699 | trace_bprint_raw(struct trace_iterator *iter, int flags, |
1700 | struct trace_event *event) | |
1427cdf0 | 1701 | { |
48ead020 | 1702 | struct bprint_entry *field; |
1427cdf0 | 1703 | struct trace_seq *s = &iter->seq; |
1427cdf0 | 1704 | |
769b0441 | 1705 | trace_assign_type(field, iter->ent); |
1427cdf0 | 1706 | |
19a7fe20 SRRH |
1707 | trace_seq_printf(s, ": %lx : ", field->ip); |
1708 | trace_seq_bprintf(s, field->fmt, field->buf); | |
1427cdf0 | 1709 | |
19a7fe20 | 1710 | return trace_handle_return(s); |
1427cdf0 LJ |
1711 | } |
1712 | ||
a9a57763 SR |
1713 | static struct trace_event_functions trace_bprint_funcs = { |
1714 | .trace = trace_bprint_print, | |
1715 | .raw = trace_bprint_raw, | |
1716 | }; | |
769b0441 | 1717 | |
48ead020 FW |
1718 | static struct trace_event trace_bprint_event = { |
1719 | .type = TRACE_BPRINT, | |
a9a57763 | 1720 | .funcs = &trace_bprint_funcs, |
48ead020 FW |
1721 | }; |
1722 | ||
1723 | /* TRACE_PRINT */ | |
1724 | static enum print_line_t trace_print_print(struct trace_iterator *iter, | |
a9a57763 | 1725 | int flags, struct trace_event *event) |
48ead020 FW |
1726 | { |
1727 | struct print_entry *field; | |
1728 | struct trace_seq *s = &iter->seq; | |
9b7bdf6f | 1729 | unsigned long ip; |
48ead020 FW |
1730 | |
1731 | trace_assign_type(field, iter->ent); | |
1732 | ||
e3223e1e | 1733 | ip = trace_adjust_address(iter->tr, field->ip); |
9b7bdf6f SR |
1734 | |
1735 | seq_print_ip_sym(s, ip, flags); | |
5efd3e2a | 1736 | trace_seq_printf(s, ": %s", field->buf); |
48ead020 | 1737 | |
19a7fe20 | 1738 | return trace_handle_return(s); |
48ead020 FW |
1739 | } |
1740 | ||
a9a57763 SR |
1741 | static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags, |
1742 | struct trace_event *event) | |
48ead020 FW |
1743 | { |
1744 | struct print_entry *field; | |
1745 | ||
1746 | trace_assign_type(field, iter->ent); | |
1747 | ||
5efd3e2a | 1748 | trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf); |
48ead020 | 1749 | |
19a7fe20 | 1750 | return trace_handle_return(&iter->seq); |
48ead020 FW |
1751 | } |
1752 | ||
a9a57763 | 1753 | static struct trace_event_functions trace_print_funcs = { |
769b0441 FW |
1754 | .trace = trace_print_print, |
1755 | .raw = trace_print_raw, | |
1427cdf0 LJ |
1756 | }; |
1757 | ||
a9a57763 SR |
1758 | static struct trace_event trace_print_event = { |
1759 | .type = TRACE_PRINT, | |
1760 | .funcs = &trace_print_funcs, | |
1761 | }; | |
1762 | ||
fa32e855 SR |
1763 | static enum print_line_t trace_raw_data(struct trace_iterator *iter, int flags, |
1764 | struct trace_event *event) | |
1765 | { | |
1766 | struct raw_data_entry *field; | |
1767 | int i; | |
1768 | ||
1769 | trace_assign_type(field, iter->ent); | |
1770 | ||
1771 | trace_seq_printf(&iter->seq, "# %x buf:", field->id); | |
1772 | ||
1773 | for (i = 0; i < iter->ent_size - offsetof(struct raw_data_entry, buf); i++) | |
1774 | trace_seq_printf(&iter->seq, " %02x", | |
1775 | (unsigned char)field->buf[i]); | |
1776 | ||
1777 | trace_seq_putc(&iter->seq, '\n'); | |
1778 | ||
1779 | return trace_handle_return(&iter->seq); | |
1780 | } | |
1781 | ||
1782 | static struct trace_event_functions trace_raw_data_funcs = { | |
1783 | .trace = trace_raw_data, | |
1784 | .raw = trace_raw_data, | |
1785 | }; | |
1786 | ||
1787 | static struct trace_event trace_raw_data_event = { | |
1788 | .type = TRACE_RAW_DATA, | |
1789 | .funcs = &trace_raw_data_funcs, | |
1790 | }; | |
1791 | ||
f689e4f2 YKV |
1792 | static enum print_line_t |
1793 | trace_func_repeats_raw(struct trace_iterator *iter, int flags, | |
1794 | struct trace_event *event) | |
1795 | { | |
1796 | struct func_repeats_entry *field; | |
1797 | struct trace_seq *s = &iter->seq; | |
1798 | ||
1799 | trace_assign_type(field, iter->ent); | |
1800 | ||
1801 | trace_seq_printf(s, "%lu %lu %u %llu\n", | |
1802 | field->ip, | |
1803 | field->parent_ip, | |
1804 | field->count, | |
1805 | FUNC_REPEATS_GET_DELTA_TS(field)); | |
1806 | ||
1807 | return trace_handle_return(s); | |
1808 | } | |
1809 | ||
1810 | static enum print_line_t | |
1811 | trace_func_repeats_print(struct trace_iterator *iter, int flags, | |
1812 | struct trace_event *event) | |
1813 | { | |
1814 | struct func_repeats_entry *field; | |
1815 | struct trace_seq *s = &iter->seq; | |
1816 | ||
1817 | trace_assign_type(field, iter->ent); | |
1818 | ||
e3223e1e | 1819 | print_fn_trace(s, field->ip, field->parent_ip, NULL, iter->tr, flags); |
f689e4f2 YKV |
1820 | trace_seq_printf(s, " (repeats: %u, last_ts:", field->count); |
1821 | trace_print_time(s, iter, | |
1822 | iter->ts - FUNC_REPEATS_GET_DELTA_TS(field)); | |
1823 | trace_seq_puts(s, ")\n"); | |
1824 | ||
1825 | return trace_handle_return(s); | |
1826 | } | |
1827 | ||
1828 | static struct trace_event_functions trace_func_repeats_funcs = { | |
1829 | .trace = trace_func_repeats_print, | |
1830 | .raw = trace_func_repeats_raw, | |
1831 | }; | |
1832 | ||
1833 | static struct trace_event trace_func_repeats_event = { | |
1834 | .type = TRACE_FUNC_REPEATS, | |
1835 | .funcs = &trace_func_repeats_funcs, | |
1836 | }; | |
48ead020 | 1837 | |
f633cef0 SR |
1838 | static struct trace_event *events[] __initdata = { |
1839 | &trace_fn_event, | |
1840 | &trace_ctx_event, | |
1841 | &trace_wake_event, | |
f633cef0 SR |
1842 | &trace_stack_event, |
1843 | &trace_user_stack_event, | |
09ae7234 | 1844 | &trace_bputs_event, |
48ead020 | 1845 | &trace_bprint_event, |
f633cef0 | 1846 | &trace_print_event, |
e7c15cd8 | 1847 | &trace_hwlat_event, |
bce29ac9 | 1848 | &trace_osnoise_event, |
a955d7ea | 1849 | &trace_timerlat_event, |
fa32e855 | 1850 | &trace_raw_data_event, |
f689e4f2 | 1851 | &trace_func_repeats_event, |
f633cef0 SR |
1852 | NULL |
1853 | }; | |
1854 | ||
3bb06eb6 | 1855 | __init int init_events(void) |
f633cef0 SR |
1856 | { |
1857 | struct trace_event *event; | |
1858 | int i, ret; | |
1859 | ||
1860 | for (i = 0; events[i]; i++) { | |
1861 | event = events[i]; | |
9023c930 | 1862 | ret = register_trace_event(event); |
4ee51101 | 1863 | WARN_ONCE(!ret, "event %d failed to register", event->type); |
f633cef0 SR |
1864 | } |
1865 | ||
1866 | return 0; | |
1867 | } |