Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Thomas Gleixner:
"Kernel:
- Improve kallsyms coverage
- Add x86 entry trampolines to kcore
- Fix ARM SPE handling
- Correct PPC event post processing

Tools:
- Make the build system more robust
- Small fixes and enhancements all over the place
- Update kernel ABI header copies
- Preparatory work for converting libtraceevnt to a shared library
- License cleanups"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (100 commits)
tools arch: Update arch/x86/lib/memcpy_64.S copy used in 'perf bench mem memcpy'
tools arch x86: Update tools's copy of cpufeatures.h
perf python: Fix pyrf_evlist__read_on_cpu() interface
perf mmap: Store real cpu number in 'struct perf_mmap'
perf tools: Remove ext from struct kmod_path
perf tools: Add gzip_is_compressed function
perf tools: Add lzma_is_compressed function
perf tools: Add is_compressed callback to compressions array
perf tools: Move the temp file processing into decompress_kmodule
perf tools: Use compression id in decompress_kmodule()
perf tools: Store compression id into struct dso
perf tools: Add compression id into 'struct kmod_path'
perf tools: Make is_supported_compression() static
perf tools: Make decompress_to_file() function static
perf tools: Get rid of dso__needs_decompress() call in __open_dso()
perf tools: Get rid of dso__needs_decompress() call in symbol__disassemble()
perf tools: Get rid of dso__needs_decompress() call in read_object_code()
tools lib traceevent: Change to SPDX License format
perf llvm: Allow passing options to llc in addition to clang
perf parser: Improve error message for PMU address filters
...

+33
arch/x86/mm/cpu_entry_area.c
··· 2 3 #include <linux/spinlock.h> 4 #include <linux/percpu.h> 5 6 #include <asm/cpu_entry_area.h> 7 #include <asm/pgtable.h> ··· 15 #ifdef CONFIG_X86_64 16 static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks 17 [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); 18 #endif 19 20 struct cpu_entry_area *get_cpu_entry_area(int cpu) ··· 149 150 cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline, 151 __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); 152 #endif 153 percpu_setup_debug_store(cpu); 154 } 155 156 static __init void setup_cpu_entry_area_ptes(void) 157 {
··· 2 3 #include <linux/spinlock.h> 4 #include <linux/percpu.h> 5 + #include <linux/kallsyms.h> 6 + #include <linux/kcore.h> 7 8 #include <asm/cpu_entry_area.h> 9 #include <asm/pgtable.h> ··· 13 #ifdef CONFIG_X86_64 14 static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks 15 [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); 16 + static DEFINE_PER_CPU(struct kcore_list, kcore_entry_trampoline); 17 #endif 18 19 struct cpu_entry_area *get_cpu_entry_area(int cpu) ··· 146 147 cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline, 148 __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); 149 + /* 150 + * The cpu_entry_area alias addresses are not in the kernel binary 151 + * so they do not show up in /proc/kcore normally. This adds entries 152 + * for them manually. 153 + */ 154 + kclist_add_remap(&per_cpu(kcore_entry_trampoline, cpu), 155 + _entry_trampoline, 156 + &get_cpu_entry_area(cpu)->entry_trampoline, PAGE_SIZE); 157 #endif 158 percpu_setup_debug_store(cpu); 159 } 160 + 161 + #ifdef CONFIG_X86_64 162 + int arch_get_kallsym(unsigned int symnum, unsigned long *value, char *type, 163 + char *name) 164 + { 165 + unsigned int cpu, ncpu = 0; 166 + 167 + if (symnum >= num_possible_cpus()) 168 + return -EINVAL; 169 + 170 + for_each_possible_cpu(cpu) { 171 + if (ncpu++ >= symnum) 172 + break; 173 + } 174 + 175 + *value = (unsigned long)&get_cpu_entry_area(cpu)->entry_trampoline; 176 + *type = 't'; 177 + strlcpy(name, "__entry_SYSCALL_64_trampoline", KSYM_NAME_LEN); 178 + 179 + return 0; 180 + } 181 + #endif 182 183 static __init void setup_cpu_entry_area_ptes(void) 184 {
+5 -2
fs/proc/kcore.c
··· 359 phdr->p_type = PT_LOAD; 360 phdr->p_flags = PF_R | PF_W | PF_X; 361 phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset; 362 - phdr->p_vaddr = (size_t)m->addr; 363 - if (m->type == KCORE_RAM) 364 phdr->p_paddr = __pa(m->addr); 365 else if (m->type == KCORE_TEXT) 366 phdr->p_paddr = __pa_symbol(m->addr);
··· 359 phdr->p_type = PT_LOAD; 360 phdr->p_flags = PF_R | PF_W | PF_X; 361 phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset; 362 + if (m->type == KCORE_REMAP) 363 + phdr->p_vaddr = (size_t)m->vaddr; 364 + else 365 + phdr->p_vaddr = (size_t)m->addr; 366 + if (m->type == KCORE_RAM || m->type == KCORE_REMAP) 367 phdr->p_paddr = __pa(m->addr); 368 else if (m->type == KCORE_TEXT) 369 phdr->p_paddr = __pa_symbol(m->addr);
+13
include/linux/kcore.h
··· 12 KCORE_VMEMMAP, 13 KCORE_USER, 14 KCORE_OTHER, 15 }; 16 17 struct kcore_list { 18 struct list_head list; 19 unsigned long addr; 20 size_t size; 21 int type; 22 }; ··· 38 39 #ifdef CONFIG_PROC_KCORE 40 void __init kclist_add(struct kcore_list *, void *, size_t, int type); 41 #else 42 static inline 43 void kclist_add(struct kcore_list *new, void *addr, size_t size, int type) 44 { 45 } 46 #endif
··· 12 KCORE_VMEMMAP, 13 KCORE_USER, 14 KCORE_OTHER, 15 + KCORE_REMAP, 16 }; 17 18 struct kcore_list { 19 struct list_head list; 20 unsigned long addr; 21 + unsigned long vaddr; 22 size_t size; 23 int type; 24 }; ··· 36 37 #ifdef CONFIG_PROC_KCORE 38 void __init kclist_add(struct kcore_list *, void *, size_t, int type); 39 + static inline 40 + void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz) 41 + { 42 + m->vaddr = (unsigned long)vaddr; 43 + kclist_add(m, addr, sz, KCORE_REMAP); 44 + } 45 #else 46 static inline 47 void kclist_add(struct kcore_list *new, void *addr, size_t size, int type) 48 + { 49 + } 50 + 51 + static inline 52 + void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz) 53 { 54 } 55 #endif
+38 -15
kernel/kallsyms.c
··· 432 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ 433 struct kallsym_iter { 434 loff_t pos; 435 loff_t pos_mod_end; 436 loff_t pos_ftrace_mod_end; 437 unsigned long value; ··· 444 int show_value; 445 }; 446 447 static int get_ksymbol_mod(struct kallsym_iter *iter) 448 { 449 - int ret = module_get_kallsym(iter->pos - kallsyms_num_syms, 450 &iter->value, &iter->type, 451 iter->name, iter->module_name, 452 &iter->exported); ··· 522 iter->nameoff = get_symbol_offset(new_pos); 523 iter->pos = new_pos; 524 if (new_pos == 0) { 525 iter->pos_mod_end = 0; 526 iter->pos_ftrace_mod_end = 0; 527 } 528 } 529 530 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) 531 { 532 iter->pos = pos; 533 534 - if (iter->pos_ftrace_mod_end > 0 && 535 - iter->pos_ftrace_mod_end < iter->pos) 536 - return get_ksymbol_bpf(iter); 537 - 538 - if (iter->pos_mod_end > 0 && 539 - iter->pos_mod_end < iter->pos) { 540 - if (!get_ksymbol_ftrace_mod(iter)) 541 - return get_ksymbol_bpf(iter); 542 return 1; 543 - } 544 545 - if (!get_ksymbol_mod(iter)) { 546 - if (!get_ksymbol_ftrace_mod(iter)) 547 - return get_ksymbol_bpf(iter); 548 - } 549 550 - return 1; 551 } 552 553 /* Returns false if pos at or past end of file. */
··· 432 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ 433 struct kallsym_iter { 434 loff_t pos; 435 + loff_t pos_arch_end; 436 loff_t pos_mod_end; 437 loff_t pos_ftrace_mod_end; 438 unsigned long value; ··· 443 int show_value; 444 }; 445 446 + int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, 447 + char *type, char *name) 448 + { 449 + return -EINVAL; 450 + } 451 + 452 + static int get_ksymbol_arch(struct kallsym_iter *iter) 453 + { 454 + int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms, 455 + &iter->value, &iter->type, 456 + iter->name); 457 + 458 + if (ret < 0) { 459 + iter->pos_arch_end = iter->pos; 460 + return 0; 461 + } 462 + 463 + return 1; 464 + } 465 + 466 static int get_ksymbol_mod(struct kallsym_iter *iter) 467 { 468 + int ret = module_get_kallsym(iter->pos - iter->pos_arch_end, 469 &iter->value, &iter->type, 470 iter->name, iter->module_name, 471 &iter->exported); ··· 501 iter->nameoff = get_symbol_offset(new_pos); 502 iter->pos = new_pos; 503 if (new_pos == 0) { 504 + iter->pos_arch_end = 0; 505 iter->pos_mod_end = 0; 506 iter->pos_ftrace_mod_end = 0; 507 } 508 } 509 510 + /* 511 + * The end position (last + 1) of each additional kallsyms section is recorded 512 + * in iter->pos_..._end as each section is added, and so can be used to 513 + * determine which get_ksymbol_...() function to call next. 514 + */ 515 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) 516 { 517 iter->pos = pos; 518 519 + if ((!iter->pos_arch_end || iter->pos_arch_end > pos) && 520 + get_ksymbol_arch(iter)) 521 return 1; 522 523 + if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && 524 + get_ksymbol_mod(iter)) 525 + return 1; 526 527 + if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) && 528 + get_ksymbol_ftrace_mod(iter)) 529 + return 1; 530 + 531 + return get_ksymbol_bpf(iter); 532 } 533 534 /* Returns false if pos at or past end of file. */
+2 -1
tools/arch/x86/include/asm/cpufeatures.h
··· 220 #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ 221 #define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ 222 #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ 223 224 /* Virtualization flags: Linux defined, word 8 */ 225 #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ ··· 231 232 #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ 233 #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ 234 - 235 236 /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ 237 #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
··· 220 #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ 221 #define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ 222 #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ 223 + #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ 224 225 /* Virtualization flags: Linux defined, word 8 */ 226 #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ ··· 230 231 #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ 232 #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ 233 + #define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */ 234 235 /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ 236 #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
+1 -1
tools/arch/x86/lib/memcpy_64.S
··· 256 257 /* Copy successful. Return zero */ 258 .L_done_memcpy_trap: 259 - xorq %rax, %rax 260 ret 261 ENDPROC(__memcpy_mcsafe) 262 EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
··· 256 257 /* Copy successful. Return zero */ 258 .L_done_memcpy_trap: 259 + xorl %eax, %eax 260 ret 261 ENDPROC(__memcpy_mcsafe) 262 EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
+2 -2
tools/lib/lockdep/Makefile
··· 129 tags: force 130 $(RM) tags 131 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ 132 - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' 133 134 TAGS: force 135 $(RM) TAGS 136 find . -name '*.[ch]' | xargs etags \ 137 - --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' 138 139 define do_install 140 $(print_install) \
··· 129 tags: force 130 $(RM) tags 131 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ 132 + --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' 133 134 TAGS: force 135 $(RM) TAGS 136 find . -name '*.[ch]' | xargs etags \ 137 + --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' 138 139 define do_install 140 $(print_install) \
+2 -2
tools/lib/traceevent/Makefile
··· 233 tags: force 234 $(RM) tags 235 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ 236 - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' 237 238 TAGS: force 239 $(RM) TAGS 240 find . -name '*.[ch]' | xargs etags \ 241 - --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' 242 243 define do_install_mkdir 244 if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
··· 233 tags: force 234 $(RM) tags 235 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ 236 + --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' 237 238 TAGS: force 239 $(RM) TAGS 240 find . -name '*.[ch]' | xargs etags \ 241 + --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' 242 243 define do_install_mkdir 244 if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
+367 -381
tools/lib/traceevent/event-parse.c
··· 1 /* 2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * 20 * The parts for function graph printing was taken and modified from the 21 * Linux Kernel that were written by ··· 59 input_buf_ptr = 0; 60 } 61 62 - const char *pevent_get_input_buf(void) 63 { 64 return input_buf; 65 } 66 67 - unsigned long long pevent_get_input_buf_ptr(void) 68 { 69 return input_buf_ptr; 70 } ··· 74 int id; 75 const char *sys_name; 76 const char *event_name; 77 - pevent_event_handler_func func; 78 void *context; 79 }; 80 81 - struct pevent_func_params { 82 - struct pevent_func_params *next; 83 - enum pevent_func_arg_type type; 84 }; 85 86 - struct pevent_function_handler { 87 - struct pevent_function_handler *next; 88 - enum pevent_func_arg_type ret_type; 89 char *name; 90 - pevent_func_handler func; 91 - struct pevent_func_params *params; 92 int nr_args; 93 }; 94 ··· 96 process_defined_func(struct trace_seq *s, void *data, int size, 97 struct event_format *event, struct print_arg *arg); 98 99 - static void free_func_handle(struct pevent_function_handler *func); 100 101 /** 102 - * pevent_buffer_init - init buffer for parsing 103 * @buf: buffer to parse 104 * @size: the size of the buffer 105 * 106 - * For use with pevent_read_token(), this initializes the internal 107 - * buffer that pevent_read_token() will parse. 108 */ 109 - void pevent_buffer_init(const char *buf, unsigned long long size) 110 { 111 init_input_buf(buf, size); 112 } ··· 146 int pid; 147 }; 148 149 - static int cmdline_init(struct pevent *pevent) 150 { 151 struct cmdline_list *cmdlist = pevent->cmdlist; 152 struct cmdline_list *item; ··· 175 return 0; 176 } 177 178 - static const char *find_cmdline(struct pevent *pevent, int pid) 179 { 180 const struct cmdline *comm; 181 struct cmdline key; ··· 197 } 198 199 /** 200 - * pevent_pid_is_registered - return if a pid has a cmdline registered 201 * @pevent: handle for the pevent 202 * @pid: The pid to check if it has a cmdline registered with. 203 * 204 * Returns 1 if the pid has a cmdline mapped to it 205 * 0 otherwise. 206 */ 207 - int pevent_pid_is_registered(struct pevent *pevent, int pid) 208 { 209 const struct cmdline *comm; 210 struct cmdline key; ··· 230 * we must add this pid. This is much slower than when cmdlines 231 * are added before the array is initialized. 232 */ 233 - static int add_new_comm(struct pevent *pevent, const char *comm, int pid) 234 { 235 struct cmdline *cmdlines = pevent->cmdlines; 236 const struct cmdline *cmdline; ··· 274 } 275 276 /** 277 - * pevent_register_comm - register a pid / comm mapping 278 * @pevent: handle for the pevent 279 * @comm: the command line to register 280 * @pid: the pid to map the command line to ··· 282 * This adds a mapping to search for command line names with 283 * a given pid. The comm is duplicated. 284 */ 285 - int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) 286 { 287 struct cmdline_list *item; 288 ··· 310 return 0; 311 } 312 313 - int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock) 314 { 315 pevent->trace_clock = strdup(trace_clock); 316 if (!pevent->trace_clock) { ··· 367 return 1; 368 } 369 370 - static int func_map_init(struct pevent *pevent) 371 { 372 struct func_list *funclist; 373 struct func_list *item; ··· 407 } 408 409 static struct func_map * 410 - __find_func(struct pevent *pevent, unsigned long long addr) 411 { 412 struct func_map *func; 413 struct func_map key; ··· 424 } 425 426 struct func_resolver { 427 - pevent_func_resolver_t *func; 428 - void *priv; 429 - struct func_map map; 430 }; 431 432 /** 433 - * pevent_set_function_resolver - set an alternative function resolver 434 * @pevent: handle for the pevent 435 * @resolver: function to be used 436 * @priv: resolver function private state. ··· 439 * keep using it instead of duplicating all the entries inside 440 * pevent->funclist. 441 */ 442 - int pevent_set_function_resolver(struct pevent *pevent, 443 - pevent_func_resolver_t *func, void *priv) 444 { 445 struct func_resolver *resolver = malloc(sizeof(*resolver)); 446 ··· 457 } 458 459 /** 460 - * pevent_reset_function_resolver - reset alternative function resolver 461 * @pevent: handle for the pevent 462 * 463 * Stop using whatever alternative resolver was set, use the default 464 * one instead. 465 */ 466 - void pevent_reset_function_resolver(struct pevent *pevent) 467 { 468 free(pevent->func_resolver); 469 pevent->func_resolver = NULL; 470 } 471 472 static struct func_map * 473 - find_func(struct pevent *pevent, unsigned long long addr) 474 { 475 struct func_map *map; 476 ··· 489 } 490 491 /** 492 - * pevent_find_function - find a function by a given address 493 * @pevent: handle for the pevent 494 * @addr: the address to find the function with 495 * ··· 497 * address. Note, the address does not have to be exact, it 498 * will select the function that would contain the address. 499 */ 500 - const char *pevent_find_function(struct pevent *pevent, unsigned long long addr) 501 { 502 struct func_map *map; 503 ··· 509 } 510 511 /** 512 - * pevent_find_function_address - find a function address by a given address 513 * @pevent: handle for the pevent 514 * @addr: the address to find the function with 515 * 516 * Returns the address the function starts at. This can be used in 517 - * conjunction with pevent_find_function to print both the function 518 * name and the function offset. 519 */ 520 unsigned long long 521 - pevent_find_function_address(struct pevent *pevent, unsigned long long addr) 522 { 523 struct func_map *map; 524 ··· 530 } 531 532 /** 533 - * pevent_register_function - register a function with a given address 534 * @pevent: handle for the pevent 535 * @function: the function name to register 536 * @addr: the address the function starts at ··· 539 * This registers a function name with an address and module. 540 * The @func passed in is duplicated. 541 */ 542 - int pevent_register_function(struct pevent *pevent, char *func, 543 - unsigned long long addr, char *mod) 544 { 545 struct func_list *item = malloc(sizeof(*item)); 546 ··· 575 } 576 577 /** 578 - * pevent_print_funcs - print out the stored functions 579 * @pevent: handle for the pevent 580 * 581 * This prints out the stored functions. 582 */ 583 - void pevent_print_funcs(struct pevent *pevent) 584 { 585 int i; 586 ··· 622 return 0; 623 } 624 625 - static int printk_map_init(struct pevent *pevent) 626 { 627 struct printk_list *printklist; 628 struct printk_list *item; ··· 654 } 655 656 static struct printk_map * 657 - find_printk(struct pevent *pevent, unsigned long long addr) 658 { 659 struct printk_map *printk; 660 struct printk_map key; ··· 671 } 672 673 /** 674 - * pevent_register_print_string - register a string by its address 675 * @pevent: handle for the pevent 676 * @fmt: the string format to register 677 * @addr: the address the string was located at ··· 679 * This registers a string by the address it was stored in the kernel. 680 * The @fmt passed in is duplicated. 681 */ 682 - int pevent_register_print_string(struct pevent *pevent, const char *fmt, 683 - unsigned long long addr) 684 { 685 struct printk_list *item = malloc(sizeof(*item)); 686 char *p; ··· 718 } 719 720 /** 721 - * pevent_print_printk - print out the stored strings 722 * @pevent: handle for the pevent 723 * 724 * This prints the string formats that were stored. 725 */ 726 - void pevent_print_printk(struct pevent *pevent) 727 { 728 int i; 729 ··· 742 return calloc(1, sizeof(struct event_format)); 743 } 744 745 - static int add_event(struct pevent *pevent, struct event_format *event) 746 { 747 int i; 748 struct event_format **events = realloc(pevent->events, sizeof(event) * ··· 899 } 900 901 /** 902 - * pevent_peek_char - peek at the next character that will be read 903 * 904 * Returns the next character read, or -1 if end of buffer. 905 */ 906 - int pevent_peek_char(void) 907 { 908 return __peek_char(); 909 } ··· 1143 } 1144 1145 /** 1146 - * pevent_read_token - access to utilites to use the pevent parser 1147 * @tok: The token to return 1148 * 1149 * This will parse tokens from the string given by 1150 - * pevent_init_data(). 1151 * 1152 * Returns the token type. 1153 */ 1154 - enum event_type pevent_read_token(char **tok) 1155 { 1156 return read_token(tok); 1157 } 1158 1159 /** 1160 - * pevent_free_token - free a token returned by pevent_read_token 1161 * @token: the token to free 1162 */ 1163 - void pevent_free_token(char *token) 1164 { 1165 free_token(token); 1166 } ··· 2087 arg->field.name = field; 2088 2089 if (is_flag_field) { 2090 - arg->field.field = pevent_find_any_field(event, arg->field.name); 2091 arg->field.field->flags |= FIELD_IS_FLAG; 2092 is_flag_field = 0; 2093 } else if (is_symbolic_field) { 2094 - arg->field.field = pevent_find_any_field(event, arg->field.name); 2095 arg->field.field->flags |= FIELD_IS_SYMBOLIC; 2096 is_symbolic_field = 0; 2097 } ··· 2700 2701 /* Find the field */ 2702 2703 - field = pevent_find_field(event, token); 2704 if (!field) 2705 goto out_free; 2706 ··· 2757 arg->type = PRINT_DYNAMIC_ARRAY_LEN; 2758 2759 /* Find the field */ 2760 - field = pevent_find_field(event, token); 2761 if (!field) 2762 goto out_free; 2763 ··· 2900 return EVENT_ERROR; 2901 } 2902 2903 - static struct pevent_function_handler * 2904 - find_func_handler(struct pevent *pevent, char *func_name) 2905 { 2906 - struct pevent_function_handler *func; 2907 2908 if (!pevent) 2909 return NULL; ··· 2916 return func; 2917 } 2918 2919 - static void remove_func_handler(struct pevent *pevent, char *func_name) 2920 { 2921 - struct pevent_function_handler *func; 2922 - struct pevent_function_handler **next; 2923 2924 next = &pevent->func_handlers; 2925 while ((func = *next)) { ··· 2933 } 2934 2935 static enum event_type 2936 - process_func_handler(struct event_format *event, struct pevent_function_handler *func, 2937 struct print_arg *arg, char **tok) 2938 { 2939 struct print_arg **next_arg; ··· 2994 process_function(struct event_format *event, struct print_arg *arg, 2995 char *token, char **tok) 2996 { 2997 - struct pevent_function_handler *func; 2998 2999 if (strcmp(token, "__print_flags") == 0) { 3000 free_token(token); ··· 3251 } 3252 3253 /** 3254 - * pevent_find_common_field - return a common field by event 3255 * @event: handle for the event 3256 * @name: the name of the common field to return 3257 * ··· 3259 * This only searchs the common fields and not all field. 3260 */ 3261 struct format_field * 3262 - pevent_find_common_field(struct event_format *event, const char *name) 3263 { 3264 struct format_field *format; 3265 ··· 3273 } 3274 3275 /** 3276 - * pevent_find_field - find a non-common field 3277 * @event: handle for the event 3278 * @name: the name of the non-common field 3279 * ··· 3281 * This does not search common fields. 3282 */ 3283 struct format_field * 3284 - pevent_find_field(struct event_format *event, const char *name) 3285 { 3286 struct format_field *format; 3287 ··· 3295 } 3296 3297 /** 3298 - * pevent_find_any_field - find any field by name 3299 * @event: handle for the event 3300 * @name: the name of the field 3301 * ··· 3304 * the non-common ones if a common one was not found. 3305 */ 3306 struct format_field * 3307 - pevent_find_any_field(struct event_format *event, const char *name) 3308 { 3309 struct format_field *format; 3310 3311 - format = pevent_find_common_field(event, name); 3312 if (format) 3313 return format; 3314 - return pevent_find_field(event, name); 3315 } 3316 3317 /** 3318 - * pevent_read_number - read a number from data 3319 * @pevent: handle for the pevent 3320 * @ptr: the raw data 3321 * @size: the size of the data that holds the number ··· 3323 * Returns the number (converted to host) from the 3324 * raw data. 3325 */ 3326 - unsigned long long pevent_read_number(struct pevent *pevent, 3327 - const void *ptr, int size) 3328 { 3329 switch (size) { 3330 case 1: ··· 3342 } 3343 3344 /** 3345 - * pevent_read_number_field - read a number from data 3346 * @field: a handle to the field 3347 * @data: the raw data to read 3348 * @value: the value to place the number in ··· 3352 * 3353 * Returns 0 on success, -1 otherwise. 3354 */ 3355 - int pevent_read_number_field(struct format_field *field, const void *data, 3356 - unsigned long long *value) 3357 { 3358 if (!field) 3359 return -1; ··· 3362 case 2: 3363 case 4: 3364 case 8: 3365 - *value = pevent_read_number(field->event->pevent, 3366 - data + field->offset, field->size); 3367 return 0; 3368 default: 3369 return -1; 3370 } 3371 } 3372 3373 - static int get_common_info(struct pevent *pevent, 3374 const char *type, int *offset, int *size) 3375 { 3376 struct event_format *event; ··· 3386 } 3387 3388 event = pevent->events[0]; 3389 - field = pevent_find_common_field(event, type); 3390 if (!field) 3391 return -1; 3392 ··· 3396 return 0; 3397 } 3398 3399 - static int __parse_common(struct pevent *pevent, void *data, 3400 int *size, int *offset, const char *name) 3401 { 3402 int ret; ··· 3406 if (ret < 0) 3407 return ret; 3408 } 3409 - return pevent_read_number(pevent, data + *offset, *size); 3410 } 3411 3412 - static int trace_parse_common_type(struct pevent *pevent, void *data) 3413 { 3414 return __parse_common(pevent, data, 3415 &pevent->type_size, &pevent->type_offset, 3416 "common_type"); 3417 } 3418 3419 - static int parse_common_pid(struct pevent *pevent, void *data) 3420 { 3421 return __parse_common(pevent, data, 3422 &pevent->pid_size, &pevent->pid_offset, 3423 "common_pid"); 3424 } 3425 3426 - static int parse_common_pc(struct pevent *pevent, void *data) 3427 { 3428 return __parse_common(pevent, data, 3429 &pevent->pc_size, &pevent->pc_offset, 3430 "common_preempt_count"); 3431 } 3432 3433 - static int parse_common_flags(struct pevent *pevent, void *data) 3434 { 3435 return __parse_common(pevent, data, 3436 &pevent->flags_size, &pevent->flags_offset, 3437 "common_flags"); 3438 } 3439 3440 - static int parse_common_lock_depth(struct pevent *pevent, void *data) 3441 { 3442 return __parse_common(pevent, data, 3443 &pevent->ld_size, &pevent->ld_offset, 3444 "common_lock_depth"); 3445 } 3446 3447 - static int parse_common_migrate_disable(struct pevent *pevent, void *data) 3448 { 3449 return __parse_common(pevent, data, 3450 &pevent->ld_size, &pevent->ld_offset, ··· 3454 static int events_id_cmp(const void *a, const void *b); 3455 3456 /** 3457 - * pevent_find_event - find an event by given id 3458 * @pevent: a handle to the pevent 3459 * @id: the id of the event 3460 * 3461 * Returns an event that has a given @id. 3462 */ 3463 - struct event_format *pevent_find_event(struct pevent *pevent, int id) 3464 { 3465 struct event_format **eventptr; 3466 struct event_format key; ··· 3484 } 3485 3486 /** 3487 - * pevent_find_event_by_name - find an event by given name 3488 * @pevent: a handle to the pevent 3489 * @sys: the system name to search for 3490 * @name: the name of the event to search for ··· 3493 * @sys. If @sys is NULL the first event with @name is returned. 3494 */ 3495 struct event_format * 3496 - pevent_find_event_by_name(struct pevent *pevent, 3497 - const char *sys, const char *name) 3498 { 3499 struct event_format *event; 3500 int i; ··· 3523 static unsigned long long 3524 eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg) 3525 { 3526 - struct pevent *pevent = event->pevent; 3527 unsigned long long val = 0; 3528 unsigned long long left, right; 3529 struct print_arg *typearg = NULL; ··· 3539 return strtoull(arg->atom.atom, NULL, 0); 3540 case PRINT_FIELD: 3541 if (!arg->field.field) { 3542 - arg->field.field = pevent_find_any_field(event, arg->field.name); 3543 if (!arg->field.field) 3544 goto out_warning_field; 3545 3546 } 3547 /* must be a number */ 3548 - val = pevent_read_number(pevent, data + arg->field.field->offset, 3549 - arg->field.field->size); 3550 break; 3551 case PRINT_FLAGS: 3552 case PRINT_SYMBOL: ··· 3589 3590 switch (larg->type) { 3591 case PRINT_DYNAMIC_ARRAY: 3592 - offset = pevent_read_number(pevent, 3593 data + larg->dynarray.field->offset, 3594 larg->dynarray.field->size); 3595 if (larg->dynarray.field->elementsize) ··· 3605 case PRINT_FIELD: 3606 if (!larg->field.field) { 3607 larg->field.field = 3608 - pevent_find_any_field(event, larg->field.name); 3609 if (!larg->field.field) { 3610 arg = larg; 3611 goto out_warning_field; ··· 3618 default: 3619 goto default_op; /* oops, all bets off */ 3620 } 3621 - val = pevent_read_number(pevent, 3622 - data + offset, field_size); 3623 if (typearg) 3624 val = eval_type(val, typearg, 1); 3625 break; ··· 3719 } 3720 break; 3721 case PRINT_DYNAMIC_ARRAY_LEN: 3722 - offset = pevent_read_number(pevent, 3723 - data + arg->dynarray.field->offset, 3724 - arg->dynarray.field->size); 3725 /* 3726 * The total allocated length of the dynamic array is 3727 * stored in the top half of the field, and the offset ··· 3731 break; 3732 case PRINT_DYNAMIC_ARRAY: 3733 /* Without [], we pass the address to the dynamic data */ 3734 - offset = pevent_read_number(pevent, 3735 - data + arg->dynarray.field->offset, 3736 - arg->dynarray.field->size); 3737 /* 3738 * The total allocated length of the dynamic array is 3739 * stored in the top half of the field, and the offset ··· 3806 trace_seq_printf(s, format, str); 3807 } 3808 3809 - static void print_bitmask_to_seq(struct pevent *pevent, 3810 struct trace_seq *s, const char *format, 3811 int len_arg, const void *data, int size) 3812 { ··· 3864 struct event_format *event, const char *format, 3865 int len_arg, struct print_arg *arg) 3866 { 3867 - struct pevent *pevent = event->pevent; 3868 struct print_flag_sym *flag; 3869 struct format_field *field; 3870 struct printk_map *printk; ··· 3885 case PRINT_FIELD: 3886 field = arg->field.field; 3887 if (!field) { 3888 - field = pevent_find_any_field(event, arg->field.name); 3889 if (!field) { 3890 str = arg->field.name; 3891 goto out_warning_field; ··· 3978 case PRINT_HEX_STR: 3979 if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) { 3980 unsigned long offset; 3981 - offset = pevent_read_number(pevent, 3982 data + arg->hex.field->dynarray.field->offset, 3983 arg->hex.field->dynarray.field->size); 3984 hex = data + (offset & 0xffff); ··· 3986 field = arg->hex.field->field.field; 3987 if (!field) { 3988 str = arg->hex.field->field.name; 3989 - field = pevent_find_any_field(event, str); 3990 if (!field) 3991 goto out_warning_field; 3992 arg->hex.field->field.field = field; ··· 4009 unsigned long offset; 4010 struct format_field *field = 4011 arg->int_array.field->dynarray.field; 4012 - offset = pevent_read_number(pevent, 4013 - data + field->offset, 4014 - field->size); 4015 num = data + (offset & 0xffff); 4016 } else { 4017 field = arg->int_array.field->field.field; 4018 if (!field) { 4019 str = arg->int_array.field->field.name; 4020 - field = pevent_find_any_field(event, str); 4021 if (!field) 4022 goto out_warning_field; 4023 arg->int_array.field->field.field = field; ··· 4057 if (arg->string.offset == -1) { 4058 struct format_field *f; 4059 4060 - f = pevent_find_any_field(event, arg->string.string); 4061 arg->string.offset = f->offset; 4062 } 4063 str_offset = data2host4(pevent, data + arg->string.offset); ··· 4075 if (arg->bitmask.offset == -1) { 4076 struct format_field *f; 4077 4078 - f = pevent_find_any_field(event, arg->bitmask.bitmask); 4079 arg->bitmask.offset = f->offset; 4080 } 4081 bitmask_offset = data2host4(pevent, data + arg->bitmask.offset); ··· 4118 process_defined_func(struct trace_seq *s, void *data, int size, 4119 struct event_format *event, struct print_arg *arg) 4120 { 4121 - struct pevent_function_handler *func_handle = arg->func.func; 4122 - struct pevent_func_params *param; 4123 unsigned long long *args; 4124 unsigned long long ret; 4125 struct print_arg *farg; ··· 4145 4146 for (i = 0; i < func_handle->nr_args; i++) { 4147 switch (param->type) { 4148 - case PEVENT_FUNC_ARG_INT: 4149 - case PEVENT_FUNC_ARG_LONG: 4150 - case PEVENT_FUNC_ARG_PTR: 4151 args[i] = eval_num_arg(data, size, event, farg); 4152 break; 4153 - case PEVENT_FUNC_ARG_STRING: 4154 trace_seq_init(&str); 4155 print_str_arg(&str, data, size, event, "%s", -1, farg); 4156 trace_seq_terminate(&str); ··· 4213 4214 static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event) 4215 { 4216 - struct pevent *pevent = event->pevent; 4217 struct format_field *field, *ip_field; 4218 struct print_arg *args, *arg, **next; 4219 unsigned long long ip, val; ··· 4225 ip_field = pevent->bprint_ip_field; 4226 4227 if (!field) { 4228 - field = pevent_find_field(event, "buf"); 4229 if (!field) { 4230 do_warning_event(event, "can't find buffer field for binary printk"); 4231 return NULL; 4232 } 4233 - ip_field = pevent_find_field(event, "ip"); 4234 if (!ip_field) { 4235 do_warning_event(event, "can't find ip field for binary printk"); 4236 return NULL; ··· 4239 pevent->bprint_ip_field = ip_field; 4240 } 4241 4242 - ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size); 4243 4244 /* 4245 * The first arg is the IP pointer. ··· 4333 /* the pointers are always 4 bytes aligned */ 4334 bptr = (void *)(((unsigned long)bptr + 3) & 4335 ~3); 4336 - val = pevent_read_number(pevent, bptr, vsize); 4337 bptr += vsize; 4338 arg = alloc_arg(); 4339 if (!arg) { ··· 4390 get_bprint_format(void *data, int size __maybe_unused, 4391 struct event_format *event) 4392 { 4393 - struct pevent *pevent = event->pevent; 4394 unsigned long long addr; 4395 struct format_field *field; 4396 struct printk_map *printk; ··· 4399 field = pevent->bprint_fmt_field; 4400 4401 if (!field) { 4402 - field = pevent_find_field(event, "fmt"); 4403 if (!field) { 4404 do_warning_event(event, "can't find format field for binary printk"); 4405 return NULL; ··· 4407 pevent->bprint_fmt_field = field; 4408 } 4409 4410 - addr = pevent_read_number(pevent, data + field->offset, field->size); 4411 4412 printk = find_printk(pevent, addr); 4413 if (!printk) { ··· 4443 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; 4444 if (!arg->field.field) { 4445 arg->field.field = 4446 - pevent_find_any_field(event, arg->field.name); 4447 if (!arg->field.field) { 4448 do_warning_event(event, "%s: field %s not found", 4449 __func__, arg->field.name); ··· 4593 4594 if (!arg->field.field) { 4595 arg->field.field = 4596 - pevent_find_any_field(event, arg->field.name); 4597 if (!arg->field.field) { 4598 do_warning("%s: field %s not found", 4599 __func__, arg->field.name); ··· 4639 4640 if (!arg->field.field) { 4641 arg->field.field = 4642 - pevent_find_any_field(event, arg->field.name); 4643 if (!arg->field.field) { 4644 do_warning("%s: field %s not found", 4645 __func__, arg->field.name); ··· 4697 4698 if (!arg->field.field) { 4699 arg->field.field = 4700 - pevent_find_any_field(event, arg->field.name); 4701 if (!arg->field.field) { 4702 do_warning("%s: field %s not found", 4703 __func__, arg->field.name); ··· 4786 return 1; 4787 } 4788 4789 - void pevent_print_field(struct trace_seq *s, void *data, 4790 - struct format_field *field) 4791 { 4792 unsigned long long val; 4793 unsigned int offset, len, i; 4794 - struct pevent *pevent = field->event->pevent; 4795 4796 if (field->flags & FIELD_IS_ARRAY) { 4797 offset = field->offset; 4798 len = field->size; 4799 if (field->flags & FIELD_IS_DYNAMIC) { 4800 - val = pevent_read_number(pevent, data + offset, len); 4801 offset = val; 4802 len = offset >> 16; 4803 offset &= 0xffff; ··· 4817 field->flags &= ~FIELD_IS_STRING; 4818 } 4819 } else { 4820 - val = pevent_read_number(pevent, data + field->offset, 4821 - field->size); 4822 if (field->flags & FIELD_IS_POINTER) { 4823 trace_seq_printf(s, "0x%llx", val); 4824 } else if (field->flags & FIELD_IS_SIGNED) { ··· 4851 } 4852 } 4853 4854 - void pevent_print_fields(struct trace_seq *s, void *data, 4855 - int size __maybe_unused, struct event_format *event) 4856 { 4857 struct format_field *field; 4858 4859 field = event->format.fields; 4860 while (field) { 4861 trace_seq_printf(s, " %s=", field->name); 4862 - pevent_print_field(s, data, field); 4863 field = field->next; 4864 } 4865 } 4866 4867 static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event) 4868 { 4869 - struct pevent *pevent = event->pevent; 4870 struct print_fmt *print_fmt = &event->print_fmt; 4871 struct print_arg *arg = print_fmt->args; 4872 struct print_arg *args = NULL; ··· 4885 4886 if (event->flags & EVENT_FL_FAILED) { 4887 trace_seq_printf(s, "[FAILED TO PARSE]"); 4888 - pevent_print_fields(s, data, size, event); 4889 return; 4890 } 4891 ··· 5126 } 5127 5128 /** 5129 - * pevent_data_lat_fmt - parse the data for the latency format 5130 * @pevent: a handle to the pevent 5131 * @s: the trace_seq to write to 5132 * @record: the record to read from ··· 5135 * need rescheduling, in hard/soft interrupt, preempt count 5136 * and lock depth) and places it into the trace_seq. 5137 */ 5138 - void pevent_data_lat_fmt(struct pevent *pevent, 5139 - struct trace_seq *s, struct pevent_record *record) 5140 { 5141 static int check_lock_depth = 1; 5142 static int check_migrate_disable = 1; ··· 5209 } 5210 5211 /** 5212 - * pevent_data_type - parse out the given event type 5213 * @pevent: a handle to the pevent 5214 * @rec: the record to read from 5215 * 5216 * This returns the event id from the @rec. 5217 */ 5218 - int pevent_data_type(struct pevent *pevent, struct pevent_record *rec) 5219 { 5220 return trace_parse_common_type(pevent, rec->data); 5221 } 5222 5223 /** 5224 - * pevent_data_event_from_type - find the event by a given type 5225 * @pevent: a handle to the pevent 5226 * @type: the type of the event. 5227 * 5228 * This returns the event form a given @type; 5229 */ 5230 - struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type) 5231 { 5232 - return pevent_find_event(pevent, type); 5233 } 5234 5235 /** 5236 - * pevent_data_pid - parse the PID from record 5237 * @pevent: a handle to the pevent 5238 * @rec: the record to parse 5239 * 5240 * This returns the PID from a record. 5241 */ 5242 - int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec) 5243 { 5244 return parse_common_pid(pevent, rec->data); 5245 } 5246 5247 /** 5248 - * pevent_data_preempt_count - parse the preempt count from the record 5249 * @pevent: a handle to the pevent 5250 * @rec: the record to parse 5251 * 5252 * This returns the preempt count from a record. 5253 */ 5254 - int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec) 5255 { 5256 return parse_common_pc(pevent, rec->data); 5257 } 5258 5259 /** 5260 - * pevent_data_flags - parse the latency flags from the record 5261 * @pevent: a handle to the pevent 5262 * @rec: the record to parse 5263 * ··· 5265 * 5266 * Use trace_flag_type enum for the flags (see event-parse.h). 5267 */ 5268 - int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec) 5269 { 5270 return parse_common_flags(pevent, rec->data); 5271 } 5272 5273 /** 5274 - * pevent_data_comm_from_pid - return the command line from PID 5275 * @pevent: a handle to the pevent 5276 * @pid: the PID of the task to search for 5277 * 5278 * This returns a pointer to the command line that has the given 5279 * @pid. 5280 */ 5281 - const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid) 5282 { 5283 const char *comm; 5284 ··· 5287 } 5288 5289 static struct cmdline * 5290 - pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next) 5291 { 5292 struct cmdline_list *cmdlist = (struct cmdline_list *)next; 5293 ··· 5303 } 5304 5305 /** 5306 - * pevent_data_pid_from_comm - return the pid from a given comm 5307 * @pevent: a handle to the pevent 5308 * @comm: the cmdline to find the pid from 5309 * @next: the cmdline structure to find the next comm ··· 5315 * next pid. 5316 * Also, it does a linear seach, so it may be slow. 5317 */ 5318 - struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm, 5319 - struct cmdline *next) 5320 { 5321 struct cmdline *cmdline; 5322 ··· 5351 } 5352 5353 /** 5354 - * pevent_cmdline_pid - return the pid associated to a given cmdline 5355 * @cmdline: The cmdline structure to get the pid from 5356 * 5357 * Returns the pid for a give cmdline. If @cmdline is NULL, then 5358 * -1 is returned. 5359 */ 5360 - int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline) 5361 { 5362 struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; 5363 ··· 5377 } 5378 5379 /** 5380 - * pevent_data_comm_from_pid - parse the data into the print format 5381 * @s: the trace_seq to write to 5382 * @event: the handle to the event 5383 * @record: the record to read from ··· 5385 * This parses the raw @data using the given @event information and 5386 * writes the print format into the trace_seq. 5387 */ 5388 - void pevent_event_info(struct trace_seq *s, struct event_format *event, 5389 - struct pevent_record *record) 5390 { 5391 int print_pretty = 1; 5392 5393 if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) 5394 - pevent_print_fields(s, record->data, record->size, event); 5395 else { 5396 5397 if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) ··· 5419 } 5420 5421 /** 5422 - * pevent_find_event_by_record - return the event from a given record 5423 * @pevent: a handle to the pevent 5424 * @record: The record to get the event from 5425 * ··· 5427 * is found. 5428 */ 5429 struct event_format * 5430 - pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record) 5431 { 5432 int type; 5433 ··· 5438 5439 type = trace_parse_common_type(pevent, record->data); 5440 5441 - return pevent_find_event(pevent, type); 5442 } 5443 5444 /** 5445 - * pevent_print_event_task - Write the event task comm, pid and CPU 5446 * @pevent: a handle to the pevent 5447 * @s: the trace_seq to write to 5448 * @event: the handle to the record's event ··· 5450 * 5451 * Writes the tasks comm, pid and CPU to @s. 5452 */ 5453 - void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, 5454 - struct event_format *event, 5455 - struct pevent_record *record) 5456 { 5457 void *data = record->data; 5458 const char *comm; ··· 5469 } 5470 5471 /** 5472 - * pevent_print_event_time - Write the event timestamp 5473 * @pevent: a handle to the pevent 5474 * @s: the trace_seq to write to 5475 * @event: the handle to the record's event ··· 5478 * 5479 * Writes the timestamp of the record into @s. 5480 */ 5481 - void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, 5482 - struct event_format *event, 5483 - struct pevent_record *record, 5484 - bool use_trace_clock) 5485 { 5486 unsigned long secs; 5487 unsigned long usecs; ··· 5497 } 5498 5499 if (pevent->latency_format) { 5500 - pevent_data_lat_fmt(pevent, s, record); 5501 } 5502 5503 if (use_usec_format) { 5504 - if (pevent->flags & PEVENT_NSEC_OUTPUT) { 5505 usecs = nsecs; 5506 p = 9; 5507 } else { ··· 5520 } 5521 5522 /** 5523 - * pevent_print_event_data - Write the event data section 5524 * @pevent: a handle to the pevent 5525 * @s: the trace_seq to write to 5526 * @event: the handle to the record's event ··· 5528 * 5529 * Writes the parsing of the record's data to @s. 5530 */ 5531 - void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s, 5532 - struct event_format *event, 5533 - struct pevent_record *record) 5534 { 5535 static const char *spaces = " "; /* 20 spaces */ 5536 int len; ··· 5542 if (len < 20) 5543 trace_seq_printf(s, "%.*s", 20 - len, spaces); 5544 5545 - pevent_event_info(s, event, record); 5546 } 5547 5548 - void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 5549 - struct pevent_record *record, bool use_trace_clock) 5550 { 5551 struct event_format *event; 5552 5553 - event = pevent_find_event_by_record(pevent, record); 5554 if (!event) { 5555 int i; 5556 int type = trace_parse_common_type(pevent, record->data); ··· 5563 return; 5564 } 5565 5566 - pevent_print_event_task(pevent, s, event, record); 5567 - pevent_print_event_time(pevent, s, event, record, use_trace_clock); 5568 - pevent_print_event_data(pevent, s, event, record); 5569 } 5570 5571 static int events_id_cmp(const void *a, const void *b) ··· 5616 return events_id_cmp(a, b); 5617 } 5618 5619 - struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type) 5620 { 5621 struct event_format **events; 5622 int (*sort)(const void *a, const void *b); ··· 5695 } 5696 5697 /** 5698 - * pevent_event_common_fields - return a list of common fields for an event 5699 * @event: the event to return the common fields of. 5700 * 5701 * Returns an allocated array of fields. The last item in the array is NULL. 5702 * The array must be freed with free(). 5703 */ 5704 - struct format_field **pevent_event_common_fields(struct event_format *event) 5705 { 5706 return get_event_fields("common", event->name, 5707 event->format.nr_common, ··· 5709 } 5710 5711 /** 5712 - * pevent_event_fields - return a list of event specific fields for an event 5713 * @event: the event to return the fields of. 5714 * 5715 * Returns an allocated array of fields. The last item in the array is NULL. 5716 * The array must be freed with free(). 5717 */ 5718 - struct format_field **pevent_event_fields(struct event_format *event) 5719 { 5720 return get_event_fields("event", event->name, 5721 event->format.nr_fields, ··· 5916 } 5917 5918 /** 5919 - * pevent_parse_header_page - parse the data stored in the header page 5920 * @pevent: the handle to the pevent 5921 * @buf: the buffer storing the header page format string 5922 * @size: the size of @buf ··· 5927 * 5928 * /sys/kernel/debug/tracing/events/header_page 5929 */ 5930 - int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, 5931 - int long_size) 5932 { 5933 int ignore; 5934 ··· 5980 free(handle); 5981 } 5982 5983 - static int find_event_handle(struct pevent *pevent, struct event_format *event) 5984 { 5985 struct event_handler *handle, **next; 5986 ··· 6009 } 6010 6011 /** 6012 - * __pevent_parse_format - parse the event format 6013 * @buf: the buffer storing the event format string 6014 * @size: the size of @buf 6015 * @sys: the system the event belongs to ··· 6021 * 6022 * /sys/kernel/debug/tracing/events/.../.../format 6023 */ 6024 - enum pevent_errno __pevent_parse_format(struct event_format **eventp, 6025 - struct pevent *pevent, const char *buf, 6026 - unsigned long size, const char *sys) 6027 { 6028 struct event_format *event; 6029 int ret; ··· 6032 6033 *eventp = event = alloc_event(); 6034 if (!event) 6035 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 6036 6037 event->name = event_read_name(); 6038 if (!event->name) { 6039 /* Bad event? */ 6040 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 6041 goto event_alloc_failed; 6042 } 6043 ··· 6050 6051 event->id = event_read_id(); 6052 if (event->id < 0) { 6053 - ret = PEVENT_ERRNO__READ_ID_FAILED; 6054 /* 6055 * This isn't an allocation error actually. 6056 * But as the ID is critical, just bail out. ··· 6060 6061 event->system = strdup(sys); 6062 if (!event->system) { 6063 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 6064 goto event_alloc_failed; 6065 } 6066 ··· 6069 6070 ret = event_read_format(event); 6071 if (ret < 0) { 6072 - ret = PEVENT_ERRNO__READ_FORMAT_FAILED; 6073 goto event_parse_failed; 6074 } 6075 ··· 6084 show_warning = 1; 6085 6086 if (ret < 0) { 6087 - ret = PEVENT_ERRNO__READ_PRINT_FAILED; 6088 goto event_parse_failed; 6089 } 6090 ··· 6098 arg = alloc_arg(); 6099 if (!arg) { 6100 event->flags |= EVENT_FL_FAILED; 6101 - return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED; 6102 } 6103 arg->type = PRINT_FIELD; 6104 arg->field.name = strdup(field->name); 6105 if (!arg->field.name) { 6106 event->flags |= EVENT_FL_FAILED; 6107 free_arg(arg); 6108 - return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED; 6109 } 6110 arg->field.field = field; 6111 *list = arg; ··· 6128 return ret; 6129 } 6130 6131 - static enum pevent_errno 6132 - __pevent_parse_event(struct pevent *pevent, 6133 - struct event_format **eventp, 6134 - const char *buf, unsigned long size, 6135 - const char *sys) 6136 { 6137 - int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); 6138 struct event_format *event = *eventp; 6139 6140 if (event == NULL) 6141 return ret; 6142 6143 if (pevent && add_event(pevent, event)) { 6144 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 6145 goto event_add_failed; 6146 } 6147 ··· 6152 return 0; 6153 6154 event_add_failed: 6155 - pevent_free_format(event); 6156 return ret; 6157 } 6158 6159 /** 6160 - * pevent_parse_format - parse the event format 6161 * @pevent: the handle to the pevent 6162 * @eventp: returned format 6163 * @buf: the buffer storing the event format string ··· 6171 * 6172 * /sys/kernel/debug/tracing/events/.../.../format 6173 */ 6174 - enum pevent_errno pevent_parse_format(struct pevent *pevent, 6175 - struct event_format **eventp, 6176 - const char *buf, 6177 - unsigned long size, const char *sys) 6178 { 6179 - return __pevent_parse_event(pevent, eventp, buf, size, sys); 6180 } 6181 6182 /** 6183 - * pevent_parse_event - parse the event format 6184 * @pevent: the handle to the pevent 6185 * @buf: the buffer storing the event format string 6186 * @size: the size of @buf ··· 6193 * 6194 * /sys/kernel/debug/tracing/events/.../.../format 6195 */ 6196 - enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, 6197 - unsigned long size, const char *sys) 6198 { 6199 struct event_format *event = NULL; 6200 - return __pevent_parse_event(pevent, &event, buf, size, sys); 6201 } 6202 6203 #undef _PE 6204 #define _PE(code, str) str 6205 - static const char * const pevent_error_str[] = { 6206 - PEVENT_ERRORS 6207 }; 6208 #undef _PE 6209 6210 - int pevent_strerror(struct pevent *pevent __maybe_unused, 6211 - enum pevent_errno errnum, char *buf, size_t buflen) 6212 { 6213 int idx; 6214 const char *msg; ··· 6218 return 0; 6219 } 6220 6221 - if (errnum <= __PEVENT_ERRNO__START || 6222 - errnum >= __PEVENT_ERRNO__END) 6223 return -1; 6224 6225 - idx = errnum - __PEVENT_ERRNO__START - 1; 6226 - msg = pevent_error_str[idx]; 6227 snprintf(buf, buflen, "%s", msg); 6228 6229 return 0; 6230 } 6231 6232 int get_field_val(struct trace_seq *s, struct format_field *field, 6233 - const char *name, struct pevent_record *record, 6234 unsigned long long *val, int err) 6235 { 6236 if (!field) { ··· 6239 return -1; 6240 } 6241 6242 - if (pevent_read_number_field(field, record->data, val)) { 6243 if (err) 6244 trace_seq_printf(s, " %s=INVALID", name); 6245 return -1; ··· 6249 } 6250 6251 /** 6252 - * pevent_get_field_raw - return the raw pointer into the data field 6253 * @s: The seq to print to on error 6254 * @event: the event that the field is for 6255 * @name: The name of the field ··· 6262 * 6263 * On failure, it returns NULL. 6264 */ 6265 - void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, 6266 - const char *name, struct pevent_record *record, 6267 - int *len, int err) 6268 { 6269 struct format_field *field; 6270 void *data = record->data; ··· 6274 if (!event) 6275 return NULL; 6276 6277 - field = pevent_find_field(event, name); 6278 6279 if (!field) { 6280 if (err) ··· 6288 6289 offset = field->offset; 6290 if (field->flags & FIELD_IS_DYNAMIC) { 6291 - offset = pevent_read_number(event->pevent, 6292 data + offset, field->size); 6293 *len = offset >> 16; 6294 offset &= 0xffff; ··· 6299 } 6300 6301 /** 6302 - * pevent_get_field_val - find a field and return its value 6303 * @s: The seq to print to on error 6304 * @event: the event that the field is for 6305 * @name: The name of the field ··· 6309 * 6310 * Returns 0 on success -1 on field not found. 6311 */ 6312 - int pevent_get_field_val(struct trace_seq *s, struct event_format *event, 6313 - const char *name, struct pevent_record *record, 6314 - unsigned long long *val, int err) 6315 { 6316 struct format_field *field; 6317 6318 if (!event) 6319 return -1; 6320 6321 - field = pevent_find_field(event, name); 6322 6323 return get_field_val(s, field, name, record, val, err); 6324 } 6325 6326 /** 6327 - * pevent_get_common_field_val - find a common field and return its value 6328 * @s: The seq to print to on error 6329 * @event: the event that the field is for 6330 * @name: The name of the field ··· 6334 * 6335 * Returns 0 on success -1 on field not found. 6336 */ 6337 - int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event, 6338 - const char *name, struct pevent_record *record, 6339 - unsigned long long *val, int err) 6340 - { 6341 - struct format_field *field; 6342 - 6343 - if (!event) 6344 - return -1; 6345 - 6346 - field = pevent_find_common_field(event, name); 6347 - 6348 - return get_field_val(s, field, name, record, val, err); 6349 - } 6350 - 6351 - /** 6352 - * pevent_get_any_field_val - find a any field and return its value 6353 - * @s: The seq to print to on error 6354 - * @event: the event that the field is for 6355 - * @name: The name of the field 6356 - * @record: The record with the field name. 6357 - * @val: place to store the value of the field. 6358 - * @err: print default error if failed. 6359 - * 6360 - * Returns 0 on success -1 on field not found. 6361 - */ 6362 - int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, 6363 - const char *name, struct pevent_record *record, 6364 unsigned long long *val, int err) 6365 { 6366 struct format_field *field; ··· 6343 if (!event) 6344 return -1; 6345 6346 - field = pevent_find_any_field(event, name); 6347 6348 return get_field_val(s, field, name, record, val, err); 6349 } 6350 6351 /** 6352 - * pevent_print_num_field - print a field and a format 6353 * @s: The seq to print to 6354 * @fmt: The printf format to print the field with. 6355 * @event: the event that the field is for ··· 6384 * 6385 * Returns: 0 on success, -1 field not found, or 1 if buffer is full. 6386 */ 6387 - int pevent_print_num_field(struct trace_seq *s, const char *fmt, 6388 - struct event_format *event, const char *name, 6389 - struct pevent_record *record, int err) 6390 { 6391 - struct format_field *field = pevent_find_field(event, name); 6392 unsigned long long val; 6393 6394 if (!field) 6395 goto failed; 6396 6397 - if (pevent_read_number_field(field, record->data, &val)) 6398 goto failed; 6399 6400 return trace_seq_printf(s, fmt, val); ··· 6406 } 6407 6408 /** 6409 - * pevent_print_func_field - print a field and a format for function pointers 6410 * @s: The seq to print to 6411 * @fmt: The printf format to print the field with. 6412 * @event: the event that the field is for ··· 6416 * 6417 * Returns: 0 on success, -1 field not found, or 1 if buffer is full. 6418 */ 6419 - int pevent_print_func_field(struct trace_seq *s, const char *fmt, 6420 - struct event_format *event, const char *name, 6421 - struct pevent_record *record, int err) 6422 { 6423 - struct format_field *field = pevent_find_field(event, name); 6424 - struct pevent *pevent = event->pevent; 6425 unsigned long long val; 6426 struct func_map *func; 6427 char tmp[128]; ··· 6429 if (!field) 6430 goto failed; 6431 6432 - if (pevent_read_number_field(field, record->data, &val)) 6433 goto failed; 6434 6435 func = find_func(pevent, val); ··· 6447 return -1; 6448 } 6449 6450 - static void free_func_handle(struct pevent_function_handler *func) 6451 { 6452 - struct pevent_func_params *params; 6453 6454 free(func->name); 6455 ··· 6463 } 6464 6465 /** 6466 - * pevent_register_print_function - register a helper function 6467 * @pevent: the handle to the pevent 6468 * @func: the function to process the helper function 6469 * @ret_type: the return type of the helper function 6470 * @name: the name of the helper function 6471 - * @parameters: A list of enum pevent_func_arg_type 6472 * 6473 * Some events may have helper functions in the print format arguments. 6474 * This allows a plugin to dynamically create a way to process one 6475 * of these functions. 6476 * 6477 - * The @parameters is a variable list of pevent_func_arg_type enums that 6478 - * must end with PEVENT_FUNC_ARG_VOID. 6479 */ 6480 - int pevent_register_print_function(struct pevent *pevent, 6481 - pevent_func_handler func, 6482 - enum pevent_func_arg_type ret_type, 6483 - char *name, ...) 6484 { 6485 - struct pevent_function_handler *func_handle; 6486 - struct pevent_func_params **next_param; 6487 - struct pevent_func_params *param; 6488 - enum pevent_func_arg_type type; 6489 va_list ap; 6490 int ret; 6491 ··· 6503 func_handle = calloc(1, sizeof(*func_handle)); 6504 if (!func_handle) { 6505 do_warning("Failed to allocate function handler"); 6506 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 6507 } 6508 6509 func_handle->ret_type = ret_type; ··· 6512 if (!func_handle->name) { 6513 do_warning("Failed to allocate function name"); 6514 free(func_handle); 6515 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 6516 } 6517 6518 next_param = &(func_handle->params); 6519 va_start(ap, name); 6520 for (;;) { 6521 - type = va_arg(ap, enum pevent_func_arg_type); 6522 - if (type == PEVENT_FUNC_ARG_VOID) 6523 break; 6524 6525 - if (type >= PEVENT_FUNC_ARG_MAX_TYPES) { 6526 do_warning("Invalid argument type %d", type); 6527 - ret = PEVENT_ERRNO__INVALID_ARG_TYPE; 6528 goto out_free; 6529 } 6530 6531 param = malloc(sizeof(*param)); 6532 if (!param) { 6533 do_warning("Failed to allocate function param"); 6534 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 6535 goto out_free; 6536 } 6537 param->type = type; ··· 6555 } 6556 6557 /** 6558 - * pevent_unregister_print_function - unregister a helper function 6559 * @pevent: the handle to the pevent 6560 * @func: the function to process the helper function 6561 * @name: the name of the helper function ··· 6564 * 6565 * Returns 0 if the handler was removed successully, -1 otherwise. 6566 */ 6567 - int pevent_unregister_print_function(struct pevent *pevent, 6568 - pevent_func_handler func, char *name) 6569 { 6570 - struct pevent_function_handler *func_handle; 6571 6572 func_handle = find_func_handler(pevent, name); 6573 if (func_handle && func_handle->func == func) { ··· 6577 return -1; 6578 } 6579 6580 - static struct event_format *pevent_search_event(struct pevent *pevent, int id, 6581 - const char *sys_name, 6582 - const char *event_name) 6583 { 6584 struct event_format *event; 6585 6586 if (id >= 0) { 6587 /* search by id */ 6588 - event = pevent_find_event(pevent, id); 6589 if (!event) 6590 return NULL; 6591 if (event_name && (strcmp(event_name, event->name) != 0)) ··· 6593 if (sys_name && (strcmp(sys_name, event->system) != 0)) 6594 return NULL; 6595 } else { 6596 - event = pevent_find_event_by_name(pevent, sys_name, event_name); 6597 if (!event) 6598 return NULL; 6599 } ··· 6601 } 6602 6603 /** 6604 - * pevent_register_event_handler - register a way to parse an event 6605 * @pevent: the handle to the pevent 6606 * @id: the id of the event to register 6607 * @sys_name: the system name the event belongs to ··· 6617 * If @id is >= 0, then it is used to find the event. 6618 * else @sys_name and @event_name are used. 6619 */ 6620 - int pevent_register_event_handler(struct pevent *pevent, int id, 6621 - const char *sys_name, const char *event_name, 6622 - pevent_event_handler_func func, void *context) 6623 { 6624 struct event_format *event; 6625 struct event_handler *handle; 6626 6627 - event = pevent_search_event(pevent, id, sys_name, event_name); 6628 if (event == NULL) 6629 goto not_found; 6630 ··· 6640 handle = calloc(1, sizeof(*handle)); 6641 if (!handle) { 6642 do_warning("Failed to allocate event handler"); 6643 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 6644 } 6645 6646 handle->id = id; ··· 6655 free((void *)handle->event_name); 6656 free((void *)handle->sys_name); 6657 free(handle); 6658 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 6659 } 6660 6661 handle->func = func; ··· 6668 6669 static int handle_matches(struct event_handler *handler, int id, 6670 const char *sys_name, const char *event_name, 6671 - pevent_event_handler_func func, void *context) 6672 { 6673 if (id >= 0 && id != handler->id) 6674 return 0; ··· 6686 } 6687 6688 /** 6689 - * pevent_unregister_event_handler - unregister an existing event handler 6690 * @pevent: the handle to the pevent 6691 * @id: the id of the event to unregister 6692 * @sys_name: the system name the handler belongs to ··· 6701 * 6702 * Returns 0 if handler was removed successfully, -1 if event was not found. 6703 */ 6704 - int pevent_unregister_event_handler(struct pevent *pevent, int id, 6705 - const char *sys_name, const char *event_name, 6706 - pevent_event_handler_func func, void *context) 6707 { 6708 struct event_format *event; 6709 struct event_handler *handle; 6710 struct event_handler **next; 6711 6712 - event = pevent_search_event(pevent, id, sys_name, event_name); 6713 if (event == NULL) 6714 goto not_found; 6715 ··· 6740 } 6741 6742 /** 6743 - * pevent_alloc - create a pevent handle 6744 */ 6745 - struct pevent *pevent_alloc(void) 6746 { 6747 - struct pevent *pevent = calloc(1, sizeof(*pevent)); 6748 6749 if (pevent) 6750 pevent->ref_count = 1; ··· 6752 return pevent; 6753 } 6754 6755 - void pevent_ref(struct pevent *pevent) 6756 { 6757 pevent->ref_count++; 6758 } 6759 6760 - void pevent_free_format_field(struct format_field *field) 6761 { 6762 free(field->type); 6763 if (field->alias != field->name) ··· 6772 6773 while (field) { 6774 next = field->next; 6775 - pevent_free_format_field(field); 6776 field = next; 6777 } 6778 } ··· 6783 free_format_fields(format->fields); 6784 } 6785 6786 - void pevent_free_format(struct event_format *event) 6787 { 6788 free(event->name); 6789 free(event->system); ··· 6797 } 6798 6799 /** 6800 - * pevent_free - free a pevent handle 6801 * @pevent: the pevent handle to free 6802 */ 6803 - void pevent_free(struct pevent *pevent) 6804 { 6805 struct cmdline_list *cmdlist, *cmdnext; 6806 struct func_list *funclist, *funcnext; 6807 struct printk_list *printklist, *printknext; 6808 - struct pevent_function_handler *func_handler; 6809 struct event_handler *handle; 6810 int i; 6811 ··· 6869 } 6870 6871 for (i = 0; i < pevent->nr_events; i++) 6872 - pevent_free_format(pevent->events[i]); 6873 6874 while (pevent->handlers) { 6875 handle = pevent->handlers; ··· 6885 free(pevent); 6886 } 6887 6888 - void pevent_unref(struct pevent *pevent) 6889 { 6890 - pevent_free(pevent); 6891 }
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 * 6 * The parts for function graph printing was taken and modified from the 7 * Linux Kernel that were written by ··· 73 input_buf_ptr = 0; 74 } 75 76 + const char *tep_get_input_buf(void) 77 { 78 return input_buf; 79 } 80 81 + unsigned long long tep_get_input_buf_ptr(void) 82 { 83 return input_buf_ptr; 84 } ··· 88 int id; 89 const char *sys_name; 90 const char *event_name; 91 + tep_event_handler_func func; 92 void *context; 93 }; 94 95 + struct func_params { 96 + struct func_params *next; 97 + enum tep_func_arg_type type; 98 }; 99 100 + struct tep_function_handler { 101 + struct tep_function_handler *next; 102 + enum tep_func_arg_type ret_type; 103 char *name; 104 + tep_func_handler func; 105 + struct func_params *params; 106 int nr_args; 107 }; 108 ··· 110 process_defined_func(struct trace_seq *s, void *data, int size, 111 struct event_format *event, struct print_arg *arg); 112 113 + static void free_func_handle(struct tep_function_handler *func); 114 115 /** 116 + * tep_buffer_init - init buffer for parsing 117 * @buf: buffer to parse 118 * @size: the size of the buffer 119 * 120 + * For use with tep_read_token(), this initializes the internal 121 + * buffer that tep_read_token() will parse. 122 */ 123 + void tep_buffer_init(const char *buf, unsigned long long size) 124 { 125 init_input_buf(buf, size); 126 } ··· 160 int pid; 161 }; 162 163 + static int cmdline_init(struct tep_handle *pevent) 164 { 165 struct cmdline_list *cmdlist = pevent->cmdlist; 166 struct cmdline_list *item; ··· 189 return 0; 190 } 191 192 + static const char *find_cmdline(struct tep_handle *pevent, int pid) 193 { 194 const struct cmdline *comm; 195 struct cmdline key; ··· 211 } 212 213 /** 214 + * tep_pid_is_registered - return if a pid has a cmdline registered 215 * @pevent: handle for the pevent 216 * @pid: The pid to check if it has a cmdline registered with. 217 * 218 * Returns 1 if the pid has a cmdline mapped to it 219 * 0 otherwise. 220 */ 221 + int tep_pid_is_registered(struct tep_handle *pevent, int pid) 222 { 223 const struct cmdline *comm; 224 struct cmdline key; ··· 244 * we must add this pid. This is much slower than when cmdlines 245 * are added before the array is initialized. 246 */ 247 + static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid) 248 { 249 struct cmdline *cmdlines = pevent->cmdlines; 250 const struct cmdline *cmdline; ··· 288 } 289 290 /** 291 + * tep_register_comm - register a pid / comm mapping 292 * @pevent: handle for the pevent 293 * @comm: the command line to register 294 * @pid: the pid to map the command line to ··· 296 * This adds a mapping to search for command line names with 297 * a given pid. The comm is duplicated. 298 */ 299 + int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) 300 { 301 struct cmdline_list *item; 302 ··· 324 return 0; 325 } 326 327 + int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock) 328 { 329 pevent->trace_clock = strdup(trace_clock); 330 if (!pevent->trace_clock) { ··· 381 return 1; 382 } 383 384 + static int func_map_init(struct tep_handle *pevent) 385 { 386 struct func_list *funclist; 387 struct func_list *item; ··· 421 } 422 423 static struct func_map * 424 + __find_func(struct tep_handle *pevent, unsigned long long addr) 425 { 426 struct func_map *func; 427 struct func_map key; ··· 438 } 439 440 struct func_resolver { 441 + tep_func_resolver_t *func; 442 + void *priv; 443 + struct func_map map; 444 }; 445 446 /** 447 + * tep_set_function_resolver - set an alternative function resolver 448 * @pevent: handle for the pevent 449 * @resolver: function to be used 450 * @priv: resolver function private state. ··· 453 * keep using it instead of duplicating all the entries inside 454 * pevent->funclist. 455 */ 456 + int tep_set_function_resolver(struct tep_handle *pevent, 457 + tep_func_resolver_t *func, void *priv) 458 { 459 struct func_resolver *resolver = malloc(sizeof(*resolver)); 460 ··· 471 } 472 473 /** 474 + * tep_reset_function_resolver - reset alternative function resolver 475 * @pevent: handle for the pevent 476 * 477 * Stop using whatever alternative resolver was set, use the default 478 * one instead. 479 */ 480 + void tep_reset_function_resolver(struct tep_handle *pevent) 481 { 482 free(pevent->func_resolver); 483 pevent->func_resolver = NULL; 484 } 485 486 static struct func_map * 487 + find_func(struct tep_handle *pevent, unsigned long long addr) 488 { 489 struct func_map *map; 490 ··· 503 } 504 505 /** 506 + * tep_find_function - find a function by a given address 507 * @pevent: handle for the pevent 508 * @addr: the address to find the function with 509 * ··· 511 * address. Note, the address does not have to be exact, it 512 * will select the function that would contain the address. 513 */ 514 + const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr) 515 { 516 struct func_map *map; 517 ··· 523 } 524 525 /** 526 + * tep_find_function_address - find a function address by a given address 527 * @pevent: handle for the pevent 528 * @addr: the address to find the function with 529 * 530 * Returns the address the function starts at. This can be used in 531 + * conjunction with tep_find_function to print both the function 532 * name and the function offset. 533 */ 534 unsigned long long 535 + tep_find_function_address(struct tep_handle *pevent, unsigned long long addr) 536 { 537 struct func_map *map; 538 ··· 544 } 545 546 /** 547 + * tep_register_function - register a function with a given address 548 * @pevent: handle for the pevent 549 * @function: the function name to register 550 * @addr: the address the function starts at ··· 553 * This registers a function name with an address and module. 554 * The @func passed in is duplicated. 555 */ 556 + int tep_register_function(struct tep_handle *pevent, char *func, 557 + unsigned long long addr, char *mod) 558 { 559 struct func_list *item = malloc(sizeof(*item)); 560 ··· 589 } 590 591 /** 592 + * tep_print_funcs - print out the stored functions 593 * @pevent: handle for the pevent 594 * 595 * This prints out the stored functions. 596 */ 597 + void tep_print_funcs(struct tep_handle *pevent) 598 { 599 int i; 600 ··· 636 return 0; 637 } 638 639 + static int printk_map_init(struct tep_handle *pevent) 640 { 641 struct printk_list *printklist; 642 struct printk_list *item; ··· 668 } 669 670 static struct printk_map * 671 + find_printk(struct tep_handle *pevent, unsigned long long addr) 672 { 673 struct printk_map *printk; 674 struct printk_map key; ··· 685 } 686 687 /** 688 + * tep_register_print_string - register a string by its address 689 * @pevent: handle for the pevent 690 * @fmt: the string format to register 691 * @addr: the address the string was located at ··· 693 * This registers a string by the address it was stored in the kernel. 694 * The @fmt passed in is duplicated. 695 */ 696 + int tep_register_print_string(struct tep_handle *pevent, const char *fmt, 697 + unsigned long long addr) 698 { 699 struct printk_list *item = malloc(sizeof(*item)); 700 char *p; ··· 732 } 733 734 /** 735 + * tep_print_printk - print out the stored strings 736 * @pevent: handle for the pevent 737 * 738 * This prints the string formats that were stored. 739 */ 740 + void tep_print_printk(struct tep_handle *pevent) 741 { 742 int i; 743 ··· 756 return calloc(1, sizeof(struct event_format)); 757 } 758 759 + static int add_event(struct tep_handle *pevent, struct event_format *event) 760 { 761 int i; 762 struct event_format **events = realloc(pevent->events, sizeof(event) * ··· 913 } 914 915 /** 916 + * tep_peek_char - peek at the next character that will be read 917 * 918 * Returns the next character read, or -1 if end of buffer. 919 */ 920 + int tep_peek_char(void) 921 { 922 return __peek_char(); 923 } ··· 1157 } 1158 1159 /** 1160 + * tep_read_token - access to utilites to use the pevent parser 1161 * @tok: The token to return 1162 * 1163 * This will parse tokens from the string given by 1164 + * tep_init_data(). 1165 * 1166 * Returns the token type. 1167 */ 1168 + enum event_type tep_read_token(char **tok) 1169 { 1170 return read_token(tok); 1171 } 1172 1173 /** 1174 + * tep_free_token - free a token returned by tep_read_token 1175 * @token: the token to free 1176 */ 1177 + void tep_free_token(char *token) 1178 { 1179 free_token(token); 1180 } ··· 2101 arg->field.name = field; 2102 2103 if (is_flag_field) { 2104 + arg->field.field = tep_find_any_field(event, arg->field.name); 2105 arg->field.field->flags |= FIELD_IS_FLAG; 2106 is_flag_field = 0; 2107 } else if (is_symbolic_field) { 2108 + arg->field.field = tep_find_any_field(event, arg->field.name); 2109 arg->field.field->flags |= FIELD_IS_SYMBOLIC; 2110 is_symbolic_field = 0; 2111 } ··· 2714 2715 /* Find the field */ 2716 2717 + field = tep_find_field(event, token); 2718 if (!field) 2719 goto out_free; 2720 ··· 2771 arg->type = PRINT_DYNAMIC_ARRAY_LEN; 2772 2773 /* Find the field */ 2774 + field = tep_find_field(event, token); 2775 if (!field) 2776 goto out_free; 2777 ··· 2914 return EVENT_ERROR; 2915 } 2916 2917 + static struct tep_function_handler * 2918 + find_func_handler(struct tep_handle *pevent, char *func_name) 2919 { 2920 + struct tep_function_handler *func; 2921 2922 if (!pevent) 2923 return NULL; ··· 2930 return func; 2931 } 2932 2933 + static void remove_func_handler(struct tep_handle *pevent, char *func_name) 2934 { 2935 + struct tep_function_handler *func; 2936 + struct tep_function_handler **next; 2937 2938 next = &pevent->func_handlers; 2939 while ((func = *next)) { ··· 2947 } 2948 2949 static enum event_type 2950 + process_func_handler(struct event_format *event, struct tep_function_handler *func, 2951 struct print_arg *arg, char **tok) 2952 { 2953 struct print_arg **next_arg; ··· 3008 process_function(struct event_format *event, struct print_arg *arg, 3009 char *token, char **tok) 3010 { 3011 + struct tep_function_handler *func; 3012 3013 if (strcmp(token, "__print_flags") == 0) { 3014 free_token(token); ··· 3265 } 3266 3267 /** 3268 + * tep_find_common_field - return a common field by event 3269 * @event: handle for the event 3270 * @name: the name of the common field to return 3271 * ··· 3273 * This only searchs the common fields and not all field. 3274 */ 3275 struct format_field * 3276 + tep_find_common_field(struct event_format *event, const char *name) 3277 { 3278 struct format_field *format; 3279 ··· 3287 } 3288 3289 /** 3290 + * tep_find_field - find a non-common field 3291 * @event: handle for the event 3292 * @name: the name of the non-common field 3293 * ··· 3295 * This does not search common fields. 3296 */ 3297 struct format_field * 3298 + tep_find_field(struct event_format *event, const char *name) 3299 { 3300 struct format_field *format; 3301 ··· 3309 } 3310 3311 /** 3312 + * tep_find_any_field - find any field by name 3313 * @event: handle for the event 3314 * @name: the name of the field 3315 * ··· 3318 * the non-common ones if a common one was not found. 3319 */ 3320 struct format_field * 3321 + tep_find_any_field(struct event_format *event, const char *name) 3322 { 3323 struct format_field *format; 3324 3325 + format = tep_find_common_field(event, name); 3326 if (format) 3327 return format; 3328 + return tep_find_field(event, name); 3329 } 3330 3331 /** 3332 + * tep_read_number - read a number from data 3333 * @pevent: handle for the pevent 3334 * @ptr: the raw data 3335 * @size: the size of the data that holds the number ··· 3337 * Returns the number (converted to host) from the 3338 * raw data. 3339 */ 3340 + unsigned long long tep_read_number(struct tep_handle *pevent, 3341 + const void *ptr, int size) 3342 { 3343 switch (size) { 3344 case 1: ··· 3356 } 3357 3358 /** 3359 + * tep_read_number_field - read a number from data 3360 * @field: a handle to the field 3361 * @data: the raw data to read 3362 * @value: the value to place the number in ··· 3366 * 3367 * Returns 0 on success, -1 otherwise. 3368 */ 3369 + int tep_read_number_field(struct format_field *field, const void *data, 3370 + unsigned long long *value) 3371 { 3372 if (!field) 3373 return -1; ··· 3376 case 2: 3377 case 4: 3378 case 8: 3379 + *value = tep_read_number(field->event->pevent, 3380 + data + field->offset, field->size); 3381 return 0; 3382 default: 3383 return -1; 3384 } 3385 } 3386 3387 + static int get_common_info(struct tep_handle *pevent, 3388 const char *type, int *offset, int *size) 3389 { 3390 struct event_format *event; ··· 3400 } 3401 3402 event = pevent->events[0]; 3403 + field = tep_find_common_field(event, type); 3404 if (!field) 3405 return -1; 3406 ··· 3410 return 0; 3411 } 3412 3413 + static int __parse_common(struct tep_handle *pevent, void *data, 3414 int *size, int *offset, const char *name) 3415 { 3416 int ret; ··· 3420 if (ret < 0) 3421 return ret; 3422 } 3423 + return tep_read_number(pevent, data + *offset, *size); 3424 } 3425 3426 + static int trace_parse_common_type(struct tep_handle *pevent, void *data) 3427 { 3428 return __parse_common(pevent, data, 3429 &pevent->type_size, &pevent->type_offset, 3430 "common_type"); 3431 } 3432 3433 + static int parse_common_pid(struct tep_handle *pevent, void *data) 3434 { 3435 return __parse_common(pevent, data, 3436 &pevent->pid_size, &pevent->pid_offset, 3437 "common_pid"); 3438 } 3439 3440 + static int parse_common_pc(struct tep_handle *pevent, void *data) 3441 { 3442 return __parse_common(pevent, data, 3443 &pevent->pc_size, &pevent->pc_offset, 3444 "common_preempt_count"); 3445 } 3446 3447 + static int parse_common_flags(struct tep_handle *pevent, void *data) 3448 { 3449 return __parse_common(pevent, data, 3450 &pevent->flags_size, &pevent->flags_offset, 3451 "common_flags"); 3452 } 3453 3454 + static int parse_common_lock_depth(struct tep_handle *pevent, void *data) 3455 { 3456 return __parse_common(pevent, data, 3457 &pevent->ld_size, &pevent->ld_offset, 3458 "common_lock_depth"); 3459 } 3460 3461 + static int parse_common_migrate_disable(struct tep_handle *pevent, void *data) 3462 { 3463 return __parse_common(pevent, data, 3464 &pevent->ld_size, &pevent->ld_offset, ··· 3468 static int events_id_cmp(const void *a, const void *b); 3469 3470 /** 3471 + * tep_find_event - find an event by given id 3472 * @pevent: a handle to the pevent 3473 * @id: the id of the event 3474 * 3475 * Returns an event that has a given @id. 3476 */ 3477 + struct event_format *tep_find_event(struct tep_handle *pevent, int id) 3478 { 3479 struct event_format **eventptr; 3480 struct event_format key; ··· 3498 } 3499 3500 /** 3501 + * tep_find_event_by_name - find an event by given name 3502 * @pevent: a handle to the pevent 3503 * @sys: the system name to search for 3504 * @name: the name of the event to search for ··· 3507 * @sys. If @sys is NULL the first event with @name is returned. 3508 */ 3509 struct event_format * 3510 + tep_find_event_by_name(struct tep_handle *pevent, 3511 + const char *sys, const char *name) 3512 { 3513 struct event_format *event; 3514 int i; ··· 3537 static unsigned long long 3538 eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg) 3539 { 3540 + struct tep_handle *pevent = event->pevent; 3541 unsigned long long val = 0; 3542 unsigned long long left, right; 3543 struct print_arg *typearg = NULL; ··· 3553 return strtoull(arg->atom.atom, NULL, 0); 3554 case PRINT_FIELD: 3555 if (!arg->field.field) { 3556 + arg->field.field = tep_find_any_field(event, arg->field.name); 3557 if (!arg->field.field) 3558 goto out_warning_field; 3559 3560 } 3561 /* must be a number */ 3562 + val = tep_read_number(pevent, data + arg->field.field->offset, 3563 + arg->field.field->size); 3564 break; 3565 case PRINT_FLAGS: 3566 case PRINT_SYMBOL: ··· 3603 3604 switch (larg->type) { 3605 case PRINT_DYNAMIC_ARRAY: 3606 + offset = tep_read_number(pevent, 3607 data + larg->dynarray.field->offset, 3608 larg->dynarray.field->size); 3609 if (larg->dynarray.field->elementsize) ··· 3619 case PRINT_FIELD: 3620 if (!larg->field.field) { 3621 larg->field.field = 3622 + tep_find_any_field(event, larg->field.name); 3623 if (!larg->field.field) { 3624 arg = larg; 3625 goto out_warning_field; ··· 3632 default: 3633 goto default_op; /* oops, all bets off */ 3634 } 3635 + val = tep_read_number(pevent, 3636 + data + offset, field_size); 3637 if (typearg) 3638 val = eval_type(val, typearg, 1); 3639 break; ··· 3733 } 3734 break; 3735 case PRINT_DYNAMIC_ARRAY_LEN: 3736 + offset = tep_read_number(pevent, 3737 + data + arg->dynarray.field->offset, 3738 + arg->dynarray.field->size); 3739 /* 3740 * The total allocated length of the dynamic array is 3741 * stored in the top half of the field, and the offset ··· 3745 break; 3746 case PRINT_DYNAMIC_ARRAY: 3747 /* Without [], we pass the address to the dynamic data */ 3748 + offset = tep_read_number(pevent, 3749 + data + arg->dynarray.field->offset, 3750 + arg->dynarray.field->size); 3751 /* 3752 * The total allocated length of the dynamic array is 3753 * stored in the top half of the field, and the offset ··· 3820 trace_seq_printf(s, format, str); 3821 } 3822 3823 + static void print_bitmask_to_seq(struct tep_handle *pevent, 3824 struct trace_seq *s, const char *format, 3825 int len_arg, const void *data, int size) 3826 { ··· 3878 struct event_format *event, const char *format, 3879 int len_arg, struct print_arg *arg) 3880 { 3881 + struct tep_handle *pevent = event->pevent; 3882 struct print_flag_sym *flag; 3883 struct format_field *field; 3884 struct printk_map *printk; ··· 3899 case PRINT_FIELD: 3900 field = arg->field.field; 3901 if (!field) { 3902 + field = tep_find_any_field(event, arg->field.name); 3903 if (!field) { 3904 str = arg->field.name; 3905 goto out_warning_field; ··· 3992 case PRINT_HEX_STR: 3993 if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) { 3994 unsigned long offset; 3995 + offset = tep_read_number(pevent, 3996 data + arg->hex.field->dynarray.field->offset, 3997 arg->hex.field->dynarray.field->size); 3998 hex = data + (offset & 0xffff); ··· 4000 field = arg->hex.field->field.field; 4001 if (!field) { 4002 str = arg->hex.field->field.name; 4003 + field = tep_find_any_field(event, str); 4004 if (!field) 4005 goto out_warning_field; 4006 arg->hex.field->field.field = field; ··· 4023 unsigned long offset; 4024 struct format_field *field = 4025 arg->int_array.field->dynarray.field; 4026 + offset = tep_read_number(pevent, 4027 + data + field->offset, 4028 + field->size); 4029 num = data + (offset & 0xffff); 4030 } else { 4031 field = arg->int_array.field->field.field; 4032 if (!field) { 4033 str = arg->int_array.field->field.name; 4034 + field = tep_find_any_field(event, str); 4035 if (!field) 4036 goto out_warning_field; 4037 arg->int_array.field->field.field = field; ··· 4071 if (arg->string.offset == -1) { 4072 struct format_field *f; 4073 4074 + f = tep_find_any_field(event, arg->string.string); 4075 arg->string.offset = f->offset; 4076 } 4077 str_offset = data2host4(pevent, data + arg->string.offset); ··· 4089 if (arg->bitmask.offset == -1) { 4090 struct format_field *f; 4091 4092 + f = tep_find_any_field(event, arg->bitmask.bitmask); 4093 arg->bitmask.offset = f->offset; 4094 } 4095 bitmask_offset = data2host4(pevent, data + arg->bitmask.offset); ··· 4132 process_defined_func(struct trace_seq *s, void *data, int size, 4133 struct event_format *event, struct print_arg *arg) 4134 { 4135 + struct tep_function_handler *func_handle = arg->func.func; 4136 + struct func_params *param; 4137 unsigned long long *args; 4138 unsigned long long ret; 4139 struct print_arg *farg; ··· 4159 4160 for (i = 0; i < func_handle->nr_args; i++) { 4161 switch (param->type) { 4162 + case TEP_FUNC_ARG_INT: 4163 + case TEP_FUNC_ARG_LONG: 4164 + case TEP_FUNC_ARG_PTR: 4165 args[i] = eval_num_arg(data, size, event, farg); 4166 break; 4167 + case TEP_FUNC_ARG_STRING: 4168 trace_seq_init(&str); 4169 print_str_arg(&str, data, size, event, "%s", -1, farg); 4170 trace_seq_terminate(&str); ··· 4227 4228 static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event) 4229 { 4230 + struct tep_handle *pevent = event->pevent; 4231 struct format_field *field, *ip_field; 4232 struct print_arg *args, *arg, **next; 4233 unsigned long long ip, val; ··· 4239 ip_field = pevent->bprint_ip_field; 4240 4241 if (!field) { 4242 + field = tep_find_field(event, "buf"); 4243 if (!field) { 4244 do_warning_event(event, "can't find buffer field for binary printk"); 4245 return NULL; 4246 } 4247 + ip_field = tep_find_field(event, "ip"); 4248 if (!ip_field) { 4249 do_warning_event(event, "can't find ip field for binary printk"); 4250 return NULL; ··· 4253 pevent->bprint_ip_field = ip_field; 4254 } 4255 4256 + ip = tep_read_number(pevent, data + ip_field->offset, ip_field->size); 4257 4258 /* 4259 * The first arg is the IP pointer. ··· 4347 /* the pointers are always 4 bytes aligned */ 4348 bptr = (void *)(((unsigned long)bptr + 3) & 4349 ~3); 4350 + val = tep_read_number(pevent, bptr, vsize); 4351 bptr += vsize; 4352 arg = alloc_arg(); 4353 if (!arg) { ··· 4404 get_bprint_format(void *data, int size __maybe_unused, 4405 struct event_format *event) 4406 { 4407 + struct tep_handle *pevent = event->pevent; 4408 unsigned long long addr; 4409 struct format_field *field; 4410 struct printk_map *printk; ··· 4413 field = pevent->bprint_fmt_field; 4414 4415 if (!field) { 4416 + field = tep_find_field(event, "fmt"); 4417 if (!field) { 4418 do_warning_event(event, "can't find format field for binary printk"); 4419 return NULL; ··· 4421 pevent->bprint_fmt_field = field; 4422 } 4423 4424 + addr = tep_read_number(pevent, data + field->offset, field->size); 4425 4426 printk = find_printk(pevent, addr); 4427 if (!printk) { ··· 4457 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; 4458 if (!arg->field.field) { 4459 arg->field.field = 4460 + tep_find_any_field(event, arg->field.name); 4461 if (!arg->field.field) { 4462 do_warning_event(event, "%s: field %s not found", 4463 __func__, arg->field.name); ··· 4607 4608 if (!arg->field.field) { 4609 arg->field.field = 4610 + tep_find_any_field(event, arg->field.name); 4611 if (!arg->field.field) { 4612 do_warning("%s: field %s not found", 4613 __func__, arg->field.name); ··· 4653 4654 if (!arg->field.field) { 4655 arg->field.field = 4656 + tep_find_any_field(event, arg->field.name); 4657 if (!arg->field.field) { 4658 do_warning("%s: field %s not found", 4659 __func__, arg->field.name); ··· 4711 4712 if (!arg->field.field) { 4713 arg->field.field = 4714 + tep_find_any_field(event, arg->field.name); 4715 if (!arg->field.field) { 4716 do_warning("%s: field %s not found", 4717 __func__, arg->field.name); ··· 4800 return 1; 4801 } 4802 4803 + void tep_print_field(struct trace_seq *s, void *data, 4804 + struct format_field *field) 4805 { 4806 unsigned long long val; 4807 unsigned int offset, len, i; 4808 + struct tep_handle *pevent = field->event->pevent; 4809 4810 if (field->flags & FIELD_IS_ARRAY) { 4811 offset = field->offset; 4812 len = field->size; 4813 if (field->flags & FIELD_IS_DYNAMIC) { 4814 + val = tep_read_number(pevent, data + offset, len); 4815 offset = val; 4816 len = offset >> 16; 4817 offset &= 0xffff; ··· 4831 field->flags &= ~FIELD_IS_STRING; 4832 } 4833 } else { 4834 + val = tep_read_number(pevent, data + field->offset, 4835 + field->size); 4836 if (field->flags & FIELD_IS_POINTER) { 4837 trace_seq_printf(s, "0x%llx", val); 4838 } else if (field->flags & FIELD_IS_SIGNED) { ··· 4865 } 4866 } 4867 4868 + void tep_print_fields(struct trace_seq *s, void *data, 4869 + int size __maybe_unused, struct event_format *event) 4870 { 4871 struct format_field *field; 4872 4873 field = event->format.fields; 4874 while (field) { 4875 trace_seq_printf(s, " %s=", field->name); 4876 + tep_print_field(s, data, field); 4877 field = field->next; 4878 } 4879 } 4880 4881 static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event) 4882 { 4883 + struct tep_handle *pevent = event->pevent; 4884 struct print_fmt *print_fmt = &event->print_fmt; 4885 struct print_arg *arg = print_fmt->args; 4886 struct print_arg *args = NULL; ··· 4899 4900 if (event->flags & EVENT_FL_FAILED) { 4901 trace_seq_printf(s, "[FAILED TO PARSE]"); 4902 + tep_print_fields(s, data, size, event); 4903 return; 4904 } 4905 ··· 5140 } 5141 5142 /** 5143 + * tep_data_lat_fmt - parse the data for the latency format 5144 * @pevent: a handle to the pevent 5145 * @s: the trace_seq to write to 5146 * @record: the record to read from ··· 5149 * need rescheduling, in hard/soft interrupt, preempt count 5150 * and lock depth) and places it into the trace_seq. 5151 */ 5152 + void tep_data_lat_fmt(struct tep_handle *pevent, 5153 + struct trace_seq *s, struct tep_record *record) 5154 { 5155 static int check_lock_depth = 1; 5156 static int check_migrate_disable = 1; ··· 5223 } 5224 5225 /** 5226 + * tep_data_type - parse out the given event type 5227 * @pevent: a handle to the pevent 5228 * @rec: the record to read from 5229 * 5230 * This returns the event id from the @rec. 5231 */ 5232 + int tep_data_type(struct tep_handle *pevent, struct tep_record *rec) 5233 { 5234 return trace_parse_common_type(pevent, rec->data); 5235 } 5236 5237 /** 5238 + * tep_data_event_from_type - find the event by a given type 5239 * @pevent: a handle to the pevent 5240 * @type: the type of the event. 5241 * 5242 * This returns the event form a given @type; 5243 */ 5244 + struct event_format *tep_data_event_from_type(struct tep_handle *pevent, int type) 5245 { 5246 + return tep_find_event(pevent, type); 5247 } 5248 5249 /** 5250 + * tep_data_pid - parse the PID from record 5251 * @pevent: a handle to the pevent 5252 * @rec: the record to parse 5253 * 5254 * This returns the PID from a record. 5255 */ 5256 + int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec) 5257 { 5258 return parse_common_pid(pevent, rec->data); 5259 } 5260 5261 /** 5262 + * tep_data_preempt_count - parse the preempt count from the record 5263 * @pevent: a handle to the pevent 5264 * @rec: the record to parse 5265 * 5266 * This returns the preempt count from a record. 5267 */ 5268 + int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec) 5269 { 5270 return parse_common_pc(pevent, rec->data); 5271 } 5272 5273 /** 5274 + * tep_data_flags - parse the latency flags from the record 5275 * @pevent: a handle to the pevent 5276 * @rec: the record to parse 5277 * ··· 5279 * 5280 * Use trace_flag_type enum for the flags (see event-parse.h). 5281 */ 5282 + int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec) 5283 { 5284 return parse_common_flags(pevent, rec->data); 5285 } 5286 5287 /** 5288 + * tep_data_comm_from_pid - return the command line from PID 5289 * @pevent: a handle to the pevent 5290 * @pid: the PID of the task to search for 5291 * 5292 * This returns a pointer to the command line that has the given 5293 * @pid. 5294 */ 5295 + const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid) 5296 { 5297 const char *comm; 5298 ··· 5301 } 5302 5303 static struct cmdline * 5304 + pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct cmdline *next) 5305 { 5306 struct cmdline_list *cmdlist = (struct cmdline_list *)next; 5307 ··· 5317 } 5318 5319 /** 5320 + * tep_data_pid_from_comm - return the pid from a given comm 5321 * @pevent: a handle to the pevent 5322 * @comm: the cmdline to find the pid from 5323 * @next: the cmdline structure to find the next comm ··· 5329 * next pid. 5330 * Also, it does a linear seach, so it may be slow. 5331 */ 5332 + struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, 5333 + struct cmdline *next) 5334 { 5335 struct cmdline *cmdline; 5336 ··· 5365 } 5366 5367 /** 5368 + * tep_cmdline_pid - return the pid associated to a given cmdline 5369 * @cmdline: The cmdline structure to get the pid from 5370 * 5371 * Returns the pid for a give cmdline. If @cmdline is NULL, then 5372 * -1 is returned. 5373 */ 5374 + int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline) 5375 { 5376 struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; 5377 ··· 5391 } 5392 5393 /** 5394 + * tep_event_info - parse the data into the print format 5395 * @s: the trace_seq to write to 5396 * @event: the handle to the event 5397 * @record: the record to read from ··· 5399 * This parses the raw @data using the given @event information and 5400 * writes the print format into the trace_seq. 5401 */ 5402 + void tep_event_info(struct trace_seq *s, struct event_format *event, 5403 + struct tep_record *record) 5404 { 5405 int print_pretty = 1; 5406 5407 if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) 5408 + tep_print_fields(s, record->data, record->size, event); 5409 else { 5410 5411 if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) ··· 5433 } 5434 5435 /** 5436 + * tep_find_event_by_record - return the event from a given record 5437 * @pevent: a handle to the pevent 5438 * @record: The record to get the event from 5439 * ··· 5441 * is found. 5442 */ 5443 struct event_format * 5444 + tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record) 5445 { 5446 int type; 5447 ··· 5452 5453 type = trace_parse_common_type(pevent, record->data); 5454 5455 + return tep_find_event(pevent, type); 5456 } 5457 5458 /** 5459 + * tep_print_event_task - Write the event task comm, pid and CPU 5460 * @pevent: a handle to the pevent 5461 * @s: the trace_seq to write to 5462 * @event: the handle to the record's event ··· 5464 * 5465 * Writes the tasks comm, pid and CPU to @s. 5466 */ 5467 + void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, 5468 + struct event_format *event, 5469 + struct tep_record *record) 5470 { 5471 void *data = record->data; 5472 const char *comm; ··· 5483 } 5484 5485 /** 5486 + * tep_print_event_time - Write the event timestamp 5487 * @pevent: a handle to the pevent 5488 * @s: the trace_seq to write to 5489 * @event: the handle to the record's event ··· 5492 * 5493 * Writes the timestamp of the record into @s. 5494 */ 5495 + void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, 5496 + struct event_format *event, 5497 + struct tep_record *record, 5498 + bool use_trace_clock) 5499 { 5500 unsigned long secs; 5501 unsigned long usecs; ··· 5511 } 5512 5513 if (pevent->latency_format) { 5514 + tep_data_lat_fmt(pevent, s, record); 5515 } 5516 5517 if (use_usec_format) { 5518 + if (pevent->flags & TEP_NSEC_OUTPUT) { 5519 usecs = nsecs; 5520 p = 9; 5521 } else { ··· 5534 } 5535 5536 /** 5537 + * tep_print_event_data - Write the event data section 5538 * @pevent: a handle to the pevent 5539 * @s: the trace_seq to write to 5540 * @event: the handle to the record's event ··· 5542 * 5543 * Writes the parsing of the record's data to @s. 5544 */ 5545 + void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, 5546 + struct event_format *event, 5547 + struct tep_record *record) 5548 { 5549 static const char *spaces = " "; /* 20 spaces */ 5550 int len; ··· 5556 if (len < 20) 5557 trace_seq_printf(s, "%.*s", 20 - len, spaces); 5558 5559 + tep_event_info(s, event, record); 5560 } 5561 5562 + void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, 5563 + struct tep_record *record, bool use_trace_clock) 5564 { 5565 struct event_format *event; 5566 5567 + event = tep_find_event_by_record(pevent, record); 5568 if (!event) { 5569 int i; 5570 int type = trace_parse_common_type(pevent, record->data); ··· 5577 return; 5578 } 5579 5580 + tep_print_event_task(pevent, s, event, record); 5581 + tep_print_event_time(pevent, s, event, record, use_trace_clock); 5582 + tep_print_event_data(pevent, s, event, record); 5583 } 5584 5585 static int events_id_cmp(const void *a, const void *b) ··· 5630 return events_id_cmp(a, b); 5631 } 5632 5633 + struct event_format **tep_list_events(struct tep_handle *pevent, enum event_sort_type sort_type) 5634 { 5635 struct event_format **events; 5636 int (*sort)(const void *a, const void *b); ··· 5709 } 5710 5711 /** 5712 + * tep_event_common_fields - return a list of common fields for an event 5713 * @event: the event to return the common fields of. 5714 * 5715 * Returns an allocated array of fields. The last item in the array is NULL. 5716 * The array must be freed with free(). 5717 */ 5718 + struct format_field **tep_event_common_fields(struct event_format *event) 5719 { 5720 return get_event_fields("common", event->name, 5721 event->format.nr_common, ··· 5723 } 5724 5725 /** 5726 + * tep_event_fields - return a list of event specific fields for an event 5727 * @event: the event to return the fields of. 5728 * 5729 * Returns an allocated array of fields. The last item in the array is NULL. 5730 * The array must be freed with free(). 5731 */ 5732 + struct format_field **tep_event_fields(struct event_format *event) 5733 { 5734 return get_event_fields("event", event->name, 5735 event->format.nr_fields, ··· 5930 } 5931 5932 /** 5933 + * tep_parse_header_page - parse the data stored in the header page 5934 * @pevent: the handle to the pevent 5935 * @buf: the buffer storing the header page format string 5936 * @size: the size of @buf ··· 5941 * 5942 * /sys/kernel/debug/tracing/events/header_page 5943 */ 5944 + int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, 5945 + int long_size) 5946 { 5947 int ignore; 5948 ··· 5994 free(handle); 5995 } 5996 5997 + static int find_event_handle(struct tep_handle *pevent, struct event_format *event) 5998 { 5999 struct event_handler *handle, **next; 6000 ··· 6023 } 6024 6025 /** 6026 + * __tep_parse_format - parse the event format 6027 * @buf: the buffer storing the event format string 6028 * @size: the size of @buf 6029 * @sys: the system the event belongs to ··· 6035 * 6036 * /sys/kernel/debug/tracing/events/.../.../format 6037 */ 6038 + enum tep_errno __tep_parse_format(struct event_format **eventp, 6039 + struct tep_handle *pevent, const char *buf, 6040 + unsigned long size, const char *sys) 6041 { 6042 struct event_format *event; 6043 int ret; ··· 6046 6047 *eventp = event = alloc_event(); 6048 if (!event) 6049 + return TEP_ERRNO__MEM_ALLOC_FAILED; 6050 6051 event->name = event_read_name(); 6052 if (!event->name) { 6053 /* Bad event? */ 6054 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 6055 goto event_alloc_failed; 6056 } 6057 ··· 6064 6065 event->id = event_read_id(); 6066 if (event->id < 0) { 6067 + ret = TEP_ERRNO__READ_ID_FAILED; 6068 /* 6069 * This isn't an allocation error actually. 6070 * But as the ID is critical, just bail out. ··· 6074 6075 event->system = strdup(sys); 6076 if (!event->system) { 6077 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 6078 goto event_alloc_failed; 6079 } 6080 ··· 6083 6084 ret = event_read_format(event); 6085 if (ret < 0) { 6086 + ret = TEP_ERRNO__READ_FORMAT_FAILED; 6087 goto event_parse_failed; 6088 } 6089 ··· 6098 show_warning = 1; 6099 6100 if (ret < 0) { 6101 + ret = TEP_ERRNO__READ_PRINT_FAILED; 6102 goto event_parse_failed; 6103 } 6104 ··· 6112 arg = alloc_arg(); 6113 if (!arg) { 6114 event->flags |= EVENT_FL_FAILED; 6115 + return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; 6116 } 6117 arg->type = PRINT_FIELD; 6118 arg->field.name = strdup(field->name); 6119 if (!arg->field.name) { 6120 event->flags |= EVENT_FL_FAILED; 6121 free_arg(arg); 6122 + return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; 6123 } 6124 arg->field.field = field; 6125 *list = arg; ··· 6142 return ret; 6143 } 6144 6145 + static enum tep_errno 6146 + __parse_event(struct tep_handle *pevent, 6147 + struct event_format **eventp, 6148 + const char *buf, unsigned long size, 6149 + const char *sys) 6150 { 6151 + int ret = __tep_parse_format(eventp, pevent, buf, size, sys); 6152 struct event_format *event = *eventp; 6153 6154 if (event == NULL) 6155 return ret; 6156 6157 if (pevent && add_event(pevent, event)) { 6158 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 6159 goto event_add_failed; 6160 } 6161 ··· 6166 return 0; 6167 6168 event_add_failed: 6169 + tep_free_format(event); 6170 return ret; 6171 } 6172 6173 /** 6174 + * tep_parse_format - parse the event format 6175 * @pevent: the handle to the pevent 6176 * @eventp: returned format 6177 * @buf: the buffer storing the event format string ··· 6185 * 6186 * /sys/kernel/debug/tracing/events/.../.../format 6187 */ 6188 + enum tep_errno tep_parse_format(struct tep_handle *pevent, 6189 + struct event_format **eventp, 6190 + const char *buf, 6191 + unsigned long size, const char *sys) 6192 { 6193 + return __parse_event(pevent, eventp, buf, size, sys); 6194 } 6195 6196 /** 6197 + * tep_parse_event - parse the event format 6198 * @pevent: the handle to the pevent 6199 * @buf: the buffer storing the event format string 6200 * @size: the size of @buf ··· 6207 * 6208 * /sys/kernel/debug/tracing/events/.../.../format 6209 */ 6210 + enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf, 6211 + unsigned long size, const char *sys) 6212 { 6213 struct event_format *event = NULL; 6214 + return __parse_event(pevent, &event, buf, size, sys); 6215 } 6216 6217 #undef _PE 6218 #define _PE(code, str) str 6219 + static const char * const tep_error_str[] = { 6220 + TEP_ERRORS 6221 }; 6222 #undef _PE 6223 6224 + int tep_strerror(struct tep_handle *pevent __maybe_unused, 6225 + enum tep_errno errnum, char *buf, size_t buflen) 6226 { 6227 int idx; 6228 const char *msg; ··· 6232 return 0; 6233 } 6234 6235 + if (errnum <= __TEP_ERRNO__START || 6236 + errnum >= __TEP_ERRNO__END) 6237 return -1; 6238 6239 + idx = errnum - __TEP_ERRNO__START - 1; 6240 + msg = tep_error_str[idx]; 6241 snprintf(buf, buflen, "%s", msg); 6242 6243 return 0; 6244 } 6245 6246 int get_field_val(struct trace_seq *s, struct format_field *field, 6247 + const char *name, struct tep_record *record, 6248 unsigned long long *val, int err) 6249 { 6250 if (!field) { ··· 6253 return -1; 6254 } 6255 6256 + if (tep_read_number_field(field, record->data, val)) { 6257 if (err) 6258 trace_seq_printf(s, " %s=INVALID", name); 6259 return -1; ··· 6263 } 6264 6265 /** 6266 + * tep_get_field_raw - return the raw pointer into the data field 6267 * @s: The seq to print to on error 6268 * @event: the event that the field is for 6269 * @name: The name of the field ··· 6276 * 6277 * On failure, it returns NULL. 6278 */ 6279 + void *tep_get_field_raw(struct trace_seq *s, struct event_format *event, 6280 + const char *name, struct tep_record *record, 6281 + int *len, int err) 6282 { 6283 struct format_field *field; 6284 void *data = record->data; ··· 6288 if (!event) 6289 return NULL; 6290 6291 + field = tep_find_field(event, name); 6292 6293 if (!field) { 6294 if (err) ··· 6302 6303 offset = field->offset; 6304 if (field->flags & FIELD_IS_DYNAMIC) { 6305 + offset = tep_read_number(event->pevent, 6306 data + offset, field->size); 6307 *len = offset >> 16; 6308 offset &= 0xffff; ··· 6313 } 6314 6315 /** 6316 + * tep_get_field_val - find a field and return its value 6317 * @s: The seq to print to on error 6318 * @event: the event that the field is for 6319 * @name: The name of the field ··· 6323 * 6324 * Returns 0 on success -1 on field not found. 6325 */ 6326 + int tep_get_field_val(struct trace_seq *s, struct event_format *event, 6327 + const char *name, struct tep_record *record, 6328 + unsigned long long *val, int err) 6329 { 6330 struct format_field *field; 6331 6332 if (!event) 6333 return -1; 6334 6335 + field = tep_find_field(event, name); 6336 6337 return get_field_val(s, field, name, record, val, err); 6338 } 6339 6340 /** 6341 + * tep_get_common_field_val - find a common field and return its value 6342 * @s: The seq to print to on error 6343 * @event: the event that the field is for 6344 * @name: The name of the field ··· 6348 * 6349 * Returns 0 on success -1 on field not found. 6350 */ 6351 + int tep_get_common_field_val(struct trace_seq *s, struct event_format *event, 6352 + const char *name, struct tep_record *record, 6353 unsigned long long *val, int err) 6354 { 6355 struct format_field *field; ··· 6382 if (!event) 6383 return -1; 6384 6385 + field = tep_find_common_field(event, name); 6386 6387 return get_field_val(s, field, name, record, val, err); 6388 } 6389 6390 /** 6391 + * tep_get_any_field_val - find a any field and return its value 6392 + * @s: The seq to print to on error 6393 + * @event: the event that the field is for 6394 + * @name: The name of the field 6395 + * @record: The record with the field name. 6396 + * @val: place to store the value of the field. 6397 + * @err: print default error if failed. 6398 + * 6399 + * Returns 0 on success -1 on field not found. 6400 + */ 6401 + int tep_get_any_field_val(struct trace_seq *s, struct event_format *event, 6402 + const char *name, struct tep_record *record, 6403 + unsigned long long *val, int err) 6404 + { 6405 + struct format_field *field; 6406 + 6407 + if (!event) 6408 + return -1; 6409 + 6410 + field = tep_find_any_field(event, name); 6411 + 6412 + return get_field_val(s, field, name, record, val, err); 6413 + } 6414 + 6415 + /** 6416 + * tep_print_num_field - print a field and a format 6417 * @s: The seq to print to 6418 * @fmt: The printf format to print the field with. 6419 * @event: the event that the field is for ··· 6398 * 6399 * Returns: 0 on success, -1 field not found, or 1 if buffer is full. 6400 */ 6401 + int tep_print_num_field(struct trace_seq *s, const char *fmt, 6402 + struct event_format *event, const char *name, 6403 + struct tep_record *record, int err) 6404 { 6405 + struct format_field *field = tep_find_field(event, name); 6406 unsigned long long val; 6407 6408 if (!field) 6409 goto failed; 6410 6411 + if (tep_read_number_field(field, record->data, &val)) 6412 goto failed; 6413 6414 return trace_seq_printf(s, fmt, val); ··· 6420 } 6421 6422 /** 6423 + * tep_print_func_field - print a field and a format for function pointers 6424 * @s: The seq to print to 6425 * @fmt: The printf format to print the field with. 6426 * @event: the event that the field is for ··· 6430 * 6431 * Returns: 0 on success, -1 field not found, or 1 if buffer is full. 6432 */ 6433 + int tep_print_func_field(struct trace_seq *s, const char *fmt, 6434 + struct event_format *event, const char *name, 6435 + struct tep_record *record, int err) 6436 { 6437 + struct format_field *field = tep_find_field(event, name); 6438 + struct tep_handle *pevent = event->pevent; 6439 unsigned long long val; 6440 struct func_map *func; 6441 char tmp[128]; ··· 6443 if (!field) 6444 goto failed; 6445 6446 + if (tep_read_number_field(field, record->data, &val)) 6447 goto failed; 6448 6449 func = find_func(pevent, val); ··· 6461 return -1; 6462 } 6463 6464 + static void free_func_handle(struct tep_function_handler *func) 6465 { 6466 + struct func_params *params; 6467 6468 free(func->name); 6469 ··· 6477 } 6478 6479 /** 6480 + * tep_register_print_function - register a helper function 6481 * @pevent: the handle to the pevent 6482 * @func: the function to process the helper function 6483 * @ret_type: the return type of the helper function 6484 * @name: the name of the helper function 6485 + * @parameters: A list of enum tep_func_arg_type 6486 * 6487 * Some events may have helper functions in the print format arguments. 6488 * This allows a plugin to dynamically create a way to process one 6489 * of these functions. 6490 * 6491 + * The @parameters is a variable list of tep_func_arg_type enums that 6492 + * must end with TEP_FUNC_ARG_VOID. 6493 */ 6494 + int tep_register_print_function(struct tep_handle *pevent, 6495 + tep_func_handler func, 6496 + enum tep_func_arg_type ret_type, 6497 + char *name, ...) 6498 { 6499 + struct tep_function_handler *func_handle; 6500 + struct func_params **next_param; 6501 + struct func_params *param; 6502 + enum tep_func_arg_type type; 6503 va_list ap; 6504 int ret; 6505 ··· 6517 func_handle = calloc(1, sizeof(*func_handle)); 6518 if (!func_handle) { 6519 do_warning("Failed to allocate function handler"); 6520 + return TEP_ERRNO__MEM_ALLOC_FAILED; 6521 } 6522 6523 func_handle->ret_type = ret_type; ··· 6526 if (!func_handle->name) { 6527 do_warning("Failed to allocate function name"); 6528 free(func_handle); 6529 + return TEP_ERRNO__MEM_ALLOC_FAILED; 6530 } 6531 6532 next_param = &(func_handle->params); 6533 va_start(ap, name); 6534 for (;;) { 6535 + type = va_arg(ap, enum tep_func_arg_type); 6536 + if (type == TEP_FUNC_ARG_VOID) 6537 break; 6538 6539 + if (type >= TEP_FUNC_ARG_MAX_TYPES) { 6540 do_warning("Invalid argument type %d", type); 6541 + ret = TEP_ERRNO__INVALID_ARG_TYPE; 6542 goto out_free; 6543 } 6544 6545 param = malloc(sizeof(*param)); 6546 if (!param) { 6547 do_warning("Failed to allocate function param"); 6548 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 6549 goto out_free; 6550 } 6551 param->type = type; ··· 6569 } 6570 6571 /** 6572 + * tep_unregister_print_function - unregister a helper function 6573 * @pevent: the handle to the pevent 6574 * @func: the function to process the helper function 6575 * @name: the name of the helper function ··· 6578 * 6579 * Returns 0 if the handler was removed successully, -1 otherwise. 6580 */ 6581 + int tep_unregister_print_function(struct tep_handle *pevent, 6582 + tep_func_handler func, char *name) 6583 { 6584 + struct tep_function_handler *func_handle; 6585 6586 func_handle = find_func_handler(pevent, name); 6587 if (func_handle && func_handle->func == func) { ··· 6591 return -1; 6592 } 6593 6594 + static struct event_format *search_event(struct tep_handle *pevent, int id, 6595 + const char *sys_name, 6596 + const char *event_name) 6597 { 6598 struct event_format *event; 6599 6600 if (id >= 0) { 6601 /* search by id */ 6602 + event = tep_find_event(pevent, id); 6603 if (!event) 6604 return NULL; 6605 if (event_name && (strcmp(event_name, event->name) != 0)) ··· 6607 if (sys_name && (strcmp(sys_name, event->system) != 0)) 6608 return NULL; 6609 } else { 6610 + event = tep_find_event_by_name(pevent, sys_name, event_name); 6611 if (!event) 6612 return NULL; 6613 } ··· 6615 } 6616 6617 /** 6618 + * tep_register_event_handler - register a way to parse an event 6619 * @pevent: the handle to the pevent 6620 * @id: the id of the event to register 6621 * @sys_name: the system name the event belongs to ··· 6631 * If @id is >= 0, then it is used to find the event. 6632 * else @sys_name and @event_name are used. 6633 */ 6634 + int tep_register_event_handler(struct tep_handle *pevent, int id, 6635 + const char *sys_name, const char *event_name, 6636 + tep_event_handler_func func, void *context) 6637 { 6638 struct event_format *event; 6639 struct event_handler *handle; 6640 6641 + event = search_event(pevent, id, sys_name, event_name); 6642 if (event == NULL) 6643 goto not_found; 6644 ··· 6654 handle = calloc(1, sizeof(*handle)); 6655 if (!handle) { 6656 do_warning("Failed to allocate event handler"); 6657 + return TEP_ERRNO__MEM_ALLOC_FAILED; 6658 } 6659 6660 handle->id = id; ··· 6669 free((void *)handle->event_name); 6670 free((void *)handle->sys_name); 6671 free(handle); 6672 + return TEP_ERRNO__MEM_ALLOC_FAILED; 6673 } 6674 6675 handle->func = func; ··· 6682 6683 static int handle_matches(struct event_handler *handler, int id, 6684 const char *sys_name, const char *event_name, 6685 + tep_event_handler_func func, void *context) 6686 { 6687 if (id >= 0 && id != handler->id) 6688 return 0; ··· 6700 } 6701 6702 /** 6703 + * tep_unregister_event_handler - unregister an existing event handler 6704 * @pevent: the handle to the pevent 6705 * @id: the id of the event to unregister 6706 * @sys_name: the system name the handler belongs to ··· 6715 * 6716 * Returns 0 if handler was removed successfully, -1 if event was not found. 6717 */ 6718 + int tep_unregister_event_handler(struct tep_handle *pevent, int id, 6719 + const char *sys_name, const char *event_name, 6720 + tep_event_handler_func func, void *context) 6721 { 6722 struct event_format *event; 6723 struct event_handler *handle; 6724 struct event_handler **next; 6725 6726 + event = search_event(pevent, id, sys_name, event_name); 6727 if (event == NULL) 6728 goto not_found; 6729 ··· 6754 } 6755 6756 /** 6757 + * tep_alloc - create a pevent handle 6758 */ 6759 + struct tep_handle *tep_alloc(void) 6760 { 6761 + struct tep_handle *pevent = calloc(1, sizeof(*pevent)); 6762 6763 if (pevent) 6764 pevent->ref_count = 1; ··· 6766 return pevent; 6767 } 6768 6769 + void tep_ref(struct tep_handle *pevent) 6770 { 6771 pevent->ref_count++; 6772 } 6773 6774 + void tep_free_format_field(struct format_field *field) 6775 { 6776 free(field->type); 6777 if (field->alias != field->name) ··· 6786 6787 while (field) { 6788 next = field->next; 6789 + tep_free_format_field(field); 6790 field = next; 6791 } 6792 } ··· 6797 free_format_fields(format->fields); 6798 } 6799 6800 + void tep_free_format(struct event_format *event) 6801 { 6802 free(event->name); 6803 free(event->system); ··· 6811 } 6812 6813 /** 6814 + * tep_free - free a pevent handle 6815 * @pevent: the pevent handle to free 6816 */ 6817 + void tep_free(struct tep_handle *pevent) 6818 { 6819 struct cmdline_list *cmdlist, *cmdnext; 6820 struct func_list *funclist, *funcnext; 6821 struct printk_list *printklist, *printknext; 6822 + struct tep_function_handler *func_handler; 6823 struct event_handler *handle; 6824 int i; 6825 ··· 6883 } 6884 6885 for (i = 0; i < pevent->nr_events; i++) 6886 + tep_free_format(pevent->events[i]); 6887 6888 while (pevent->handlers) { 6889 handle = pevent->handlers; ··· 6899 free(pevent); 6900 } 6901 6902 + void tep_unref(struct tep_handle *pevent) 6903 { 6904 + tep_free(pevent); 6905 }
+223 -223
tools/lib/traceevent/event-parse.h
··· 41 #define DEBUG_RECORD 0 42 #endif 43 44 - struct pevent_record { 45 unsigned long long ts; 46 unsigned long long offset; 47 long long missed_events; /* buffer dropped events before */ ··· 53 int locked; /* Do not free, even if ref_count is zero */ 54 void *priv; 55 #if DEBUG_RECORD 56 - struct pevent_record *prev; 57 - struct pevent_record *next; 58 long alloc_addr; 59 #endif 60 }; ··· 98 99 /* ----------------------- pevent ----------------------- */ 100 101 - struct pevent; 102 struct event_format; 103 104 - typedef int (*pevent_event_handler_func)(struct trace_seq *s, 105 - struct pevent_record *record, 106 - struct event_format *event, 107 - void *context); 108 109 - typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 110 - typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); 111 112 - struct pevent_plugin_option { 113 - struct pevent_plugin_option *next; 114 void *handle; 115 char *file; 116 char *name; ··· 124 /* 125 * Plugin hooks that can be called: 126 * 127 - * PEVENT_PLUGIN_LOADER: (required) 128 * The function name to initialized the plugin. 129 * 130 - * int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 131 * 132 - * PEVENT_PLUGIN_UNLOADER: (optional) 133 * The function called just before unloading 134 * 135 - * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 136 * 137 - * PEVENT_PLUGIN_OPTIONS: (optional) 138 * Plugin options that can be set before loading 139 * 140 - * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = { 141 * { 142 * .name = "option-name", 143 * .plugin_alias = "override-file-name", (optional) ··· 158 * .set will be processed. If .value is defined, then it is considered 159 * a string option and .set will be ignored. 160 * 161 - * PEVENT_PLUGIN_ALIAS: (optional) 162 * The name to use for finding options (uses filename if not defined) 163 */ 164 - #define PEVENT_PLUGIN_LOADER pevent_plugin_loader 165 - #define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader 166 - #define PEVENT_PLUGIN_OPTIONS pevent_plugin_options 167 - #define PEVENT_PLUGIN_ALIAS pevent_plugin_alias 168 #define _MAKE_STR(x) #x 169 #define MAKE_STR(x) _MAKE_STR(x) 170 - #define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER) 171 - #define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER) 172 - #define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS) 173 - #define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS) 174 175 enum format_flags { 176 FIELD_IS_ARRAY = 1, ··· 269 struct print_arg *right; 270 }; 271 272 - struct pevent_function_handler; 273 274 struct print_arg_func { 275 - struct pevent_function_handler *func; 276 struct print_arg *args; 277 }; 278 ··· 320 }; 321 322 struct event_format { 323 - struct pevent *pevent; 324 char *name; 325 int id; 326 int flags; 327 struct format format; 328 struct print_fmt print_fmt; 329 char *system; 330 - pevent_event_handler_func handler; 331 void *context; 332 }; 333 ··· 361 EVENT_SQUOTE, 362 }; 363 364 - typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s, 365 - unsigned long long *args); 366 367 - enum pevent_func_arg_type { 368 - PEVENT_FUNC_ARG_VOID, 369 - PEVENT_FUNC_ARG_INT, 370 - PEVENT_FUNC_ARG_LONG, 371 - PEVENT_FUNC_ARG_STRING, 372 - PEVENT_FUNC_ARG_PTR, 373 - PEVENT_FUNC_ARG_MAX_TYPES 374 }; 375 376 - enum pevent_flag { 377 - PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ 378 - PEVENT_DISABLE_SYS_PLUGINS = 1 << 1, 379 - PEVENT_DISABLE_PLUGINS = 1 << 2, 380 }; 381 382 - #define PEVENT_ERRORS \ 383 _PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \ 384 _PE(PARSE_EVENT_FAILED, "failed to parse event"), \ 385 _PE(READ_ID_FAILED, "failed to read event id"), \ ··· 411 _PE(FILTER_MISS, "record does not match to filter") 412 413 #undef _PE 414 - #define _PE(__code, __str) PEVENT_ERRNO__ ## __code 415 - enum pevent_errno { 416 - PEVENT_ERRNO__SUCCESS = 0, 417 - PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, 418 419 /* 420 * Choose an arbitrary negative big number not to clash with standard ··· 423 * 424 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html 425 */ 426 - __PEVENT_ERRNO__START = -100000, 427 428 - PEVENT_ERRORS, 429 430 - __PEVENT_ERRNO__END, 431 }; 432 #undef _PE 433 ··· 435 436 #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) 437 438 - struct plugin_list *traceevent_load_plugins(struct pevent *pevent); 439 - void traceevent_unload_plugins(struct plugin_list *plugin_list, 440 - struct pevent *pevent); 441 - char **traceevent_plugin_list_options(void); 442 - void traceevent_plugin_free_options_list(char **list); 443 - int traceevent_plugin_add_options(const char *name, 444 - struct pevent_plugin_option *options); 445 - void traceevent_plugin_remove_options(struct pevent_plugin_option *options); 446 - void traceevent_print_plugins(struct trace_seq *s, 447 - const char *prefix, const char *suffix, 448 - const struct plugin_list *list); 449 450 struct cmdline; 451 struct cmdline_list; ··· 454 struct event_handler; 455 struct func_resolver; 456 457 - typedef char *(pevent_func_resolver_t)(void *priv, 458 - unsigned long long *addrp, char **modp); 459 460 - struct pevent { 461 int ref_count; 462 463 int header_page_ts_offset; ··· 524 struct format_field *bprint_buf_field; 525 526 struct event_handler *handlers; 527 - struct pevent_function_handler *func_handlers; 528 529 /* cache */ 530 struct event_format *last_event; ··· 532 char *trace_clock; 533 }; 534 535 - static inline void pevent_set_flag(struct pevent *pevent, int flag) 536 { 537 pevent->flags |= flag; 538 } 539 540 static inline unsigned short 541 - __data2host2(struct pevent *pevent, unsigned short data) 542 { 543 unsigned short swap; 544 ··· 552 } 553 554 static inline unsigned int 555 - __data2host4(struct pevent *pevent, unsigned int data) 556 { 557 unsigned int swap; 558 ··· 568 } 569 570 static inline unsigned long long 571 - __data2host8(struct pevent *pevent, unsigned long long data) 572 { 573 unsigned long long swap; 574 ··· 597 __data2host8(pevent, __val); \ 598 }) 599 600 - static inline int traceevent_host_bigendian(void) 601 { 602 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; 603 unsigned int val; ··· 615 TRACE_FLAG_SOFTIRQ = 0x10, 616 }; 617 618 - int pevent_set_function_resolver(struct pevent *pevent, 619 - pevent_func_resolver_t *func, void *priv); 620 - void pevent_reset_function_resolver(struct pevent *pevent); 621 - int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); 622 - int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock); 623 - int pevent_register_function(struct pevent *pevent, char *name, 624 - unsigned long long addr, char *mod); 625 - int pevent_register_print_string(struct pevent *pevent, const char *fmt, 626 - unsigned long long addr); 627 - int pevent_pid_is_registered(struct pevent *pevent, int pid); 628 629 - void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, 630 - struct event_format *event, 631 - struct pevent_record *record); 632 - void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, 633 - struct event_format *event, 634 - struct pevent_record *record, 635 - bool use_trace_clock); 636 - void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s, 637 - struct event_format *event, 638 - struct pevent_record *record); 639 - void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 640 - struct pevent_record *record, bool use_trace_clock); 641 642 - int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, 643 - int long_size); 644 645 - enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, 646 - unsigned long size, const char *sys); 647 - enum pevent_errno pevent_parse_format(struct pevent *pevent, 648 - struct event_format **eventp, 649 - const char *buf, 650 - unsigned long size, const char *sys); 651 - void pevent_free_format(struct event_format *event); 652 - void pevent_free_format_field(struct format_field *field); 653 654 - void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, 655 - const char *name, struct pevent_record *record, 656 - int *len, int err); 657 658 - int pevent_get_field_val(struct trace_seq *s, struct event_format *event, 659 - const char *name, struct pevent_record *record, 660 - unsigned long long *val, int err); 661 - int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event, 662 - const char *name, struct pevent_record *record, 663 - unsigned long long *val, int err); 664 - int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, 665 - const char *name, struct pevent_record *record, 666 unsigned long long *val, int err); 667 668 - int pevent_print_num_field(struct trace_seq *s, const char *fmt, 669 struct event_format *event, const char *name, 670 - struct pevent_record *record, int err); 671 672 - int pevent_print_func_field(struct trace_seq *s, const char *fmt, 673 - struct event_format *event, const char *name, 674 - struct pevent_record *record, int err); 675 676 - int pevent_register_event_handler(struct pevent *pevent, int id, 677 - const char *sys_name, const char *event_name, 678 - pevent_event_handler_func func, void *context); 679 - int pevent_unregister_event_handler(struct pevent *pevent, int id, 680 - const char *sys_name, const char *event_name, 681 - pevent_event_handler_func func, void *context); 682 - int pevent_register_print_function(struct pevent *pevent, 683 - pevent_func_handler func, 684 - enum pevent_func_arg_type ret_type, 685 - char *name, ...); 686 - int pevent_unregister_print_function(struct pevent *pevent, 687 - pevent_func_handler func, char *name); 688 689 - struct format_field *pevent_find_common_field(struct event_format *event, const char *name); 690 - struct format_field *pevent_find_field(struct event_format *event, const char *name); 691 - struct format_field *pevent_find_any_field(struct event_format *event, const char *name); 692 693 - const char *pevent_find_function(struct pevent *pevent, unsigned long long addr); 694 unsigned long long 695 - pevent_find_function_address(struct pevent *pevent, unsigned long long addr); 696 - unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size); 697 - int pevent_read_number_field(struct format_field *field, const void *data, 698 - unsigned long long *value); 699 700 - struct event_format *pevent_find_event(struct pevent *pevent, int id); 701 - 702 - struct event_format * 703 - pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); 704 705 struct event_format * 706 - pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record); 707 708 - void pevent_data_lat_fmt(struct pevent *pevent, 709 - struct trace_seq *s, struct pevent_record *record); 710 - int pevent_data_type(struct pevent *pevent, struct pevent_record *rec); 711 - struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); 712 - int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec); 713 - int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec); 714 - int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec); 715 - const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); 716 struct cmdline; 717 - struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm, 718 - struct cmdline *next); 719 - int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); 720 721 - void pevent_print_field(struct trace_seq *s, void *data, 722 - struct format_field *field); 723 - void pevent_print_fields(struct trace_seq *s, void *data, 724 - int size __maybe_unused, struct event_format *event); 725 - void pevent_event_info(struct trace_seq *s, struct event_format *event, 726 - struct pevent_record *record); 727 - int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, 728 char *buf, size_t buflen); 729 730 - struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type); 731 - struct format_field **pevent_event_common_fields(struct event_format *event); 732 - struct format_field **pevent_event_fields(struct event_format *event); 733 734 - static inline int pevent_get_cpus(struct pevent *pevent) 735 { 736 return pevent->cpus; 737 } 738 739 - static inline void pevent_set_cpus(struct pevent *pevent, int cpus) 740 { 741 pevent->cpus = cpus; 742 } 743 744 - static inline int pevent_get_long_size(struct pevent *pevent) 745 { 746 return pevent->long_size; 747 } 748 749 - static inline void pevent_set_long_size(struct pevent *pevent, int long_size) 750 { 751 pevent->long_size = long_size; 752 } 753 754 - static inline int pevent_get_page_size(struct pevent *pevent) 755 { 756 return pevent->page_size; 757 } 758 759 - static inline void pevent_set_page_size(struct pevent *pevent, int _page_size) 760 { 761 pevent->page_size = _page_size; 762 } 763 764 - static inline int pevent_is_file_bigendian(struct pevent *pevent) 765 { 766 return pevent->file_bigendian; 767 } 768 769 - static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian) 770 { 771 pevent->file_bigendian = endian; 772 } 773 774 - static inline int pevent_is_host_bigendian(struct pevent *pevent) 775 { 776 return pevent->host_bigendian; 777 } 778 779 - static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian) 780 { 781 pevent->host_bigendian = endian; 782 } 783 784 - static inline int pevent_is_latency_format(struct pevent *pevent) 785 { 786 return pevent->latency_format; 787 } 788 789 - static inline void pevent_set_latency_format(struct pevent *pevent, int lat) 790 { 791 pevent->latency_format = lat; 792 } 793 794 - struct pevent *pevent_alloc(void); 795 - void pevent_free(struct pevent *pevent); 796 - void pevent_ref(struct pevent *pevent); 797 - void pevent_unref(struct pevent *pevent); 798 799 /* access to the internal parser */ 800 - void pevent_buffer_init(const char *buf, unsigned long long size); 801 - enum event_type pevent_read_token(char **tok); 802 - void pevent_free_token(char *token); 803 - int pevent_peek_char(void); 804 - const char *pevent_get_input_buf(void); 805 - unsigned long long pevent_get_input_buf_ptr(void); 806 807 /* for debugging */ 808 - void pevent_print_funcs(struct pevent *pevent); 809 - void pevent_print_printk(struct pevent *pevent); 810 811 /* ----------------------- filtering ----------------------- */ 812 ··· 930 struct filter_arg *filter; 931 }; 932 933 - #define PEVENT_FILTER_ERROR_BUFSZ 1024 934 935 struct event_filter { 936 - struct pevent *pevent; 937 int filters; 938 struct filter_type *event_filters; 939 - char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; 940 }; 941 942 - struct event_filter *pevent_filter_alloc(struct pevent *pevent); 943 944 /* for backward compatibility */ 945 - #define FILTER_NONE PEVENT_ERRNO__NO_FILTER 946 - #define FILTER_NOEXIST PEVENT_ERRNO__FILTER_NOT_FOUND 947 - #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS 948 - #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH 949 950 enum filter_trivial_type { 951 FILTER_TRIVIAL_FALSE, ··· 953 FILTER_TRIVIAL_BOTH, 954 }; 955 956 - enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, 957 - const char *filter_str); 958 959 - enum pevent_errno pevent_filter_match(struct event_filter *filter, 960 - struct pevent_record *record); 961 962 - int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, 963 - char *buf, size_t buflen); 964 965 - int pevent_event_filtered(struct event_filter *filter, 966 - int event_id); 967 968 - void pevent_filter_reset(struct event_filter *filter); 969 970 - int pevent_filter_clear_trivial(struct event_filter *filter, 971 enum filter_trivial_type type); 972 973 - void pevent_filter_free(struct event_filter *filter); 974 975 - char *pevent_filter_make_string(struct event_filter *filter, int event_id); 976 977 - int pevent_filter_remove_event(struct event_filter *filter, 978 - int event_id); 979 - 980 - int pevent_filter_event_has_trivial(struct event_filter *filter, 981 - int event_id, 982 - enum filter_trivial_type type); 983 - 984 - int pevent_filter_copy(struct event_filter *dest, struct event_filter *source); 985 - 986 - int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, 987 - enum filter_trivial_type type); 988 - 989 - int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2); 990 991 #endif /* _PARSE_EVENTS_H */
··· 41 #define DEBUG_RECORD 0 42 #endif 43 44 + struct tep_record { 45 unsigned long long ts; 46 unsigned long long offset; 47 long long missed_events; /* buffer dropped events before */ ··· 53 int locked; /* Do not free, even if ref_count is zero */ 54 void *priv; 55 #if DEBUG_RECORD 56 + struct tep_record *prev; 57 + struct tep_record *next; 58 long alloc_addr; 59 #endif 60 }; ··· 98 99 /* ----------------------- pevent ----------------------- */ 100 101 + struct tep_handle; 102 struct event_format; 103 104 + typedef int (*tep_event_handler_func)(struct trace_seq *s, 105 + struct tep_record *record, 106 + struct event_format *event, 107 + void *context); 108 109 + typedef int (*tep_plugin_load_func)(struct tep_handle *pevent); 110 + typedef int (*tep_plugin_unload_func)(struct tep_handle *pevent); 111 112 + struct tep_plugin_option { 113 + struct tep_plugin_option *next; 114 void *handle; 115 char *file; 116 char *name; ··· 124 /* 125 * Plugin hooks that can be called: 126 * 127 + * TEP_PLUGIN_LOADER: (required) 128 * The function name to initialized the plugin. 129 * 130 + * int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 131 * 132 + * TEP_PLUGIN_UNLOADER: (optional) 133 * The function called just before unloading 134 * 135 + * int TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 136 * 137 + * TEP_PLUGIN_OPTIONS: (optional) 138 * Plugin options that can be set before loading 139 * 140 + * struct tep_plugin_option TEP_PLUGIN_OPTIONS[] = { 141 * { 142 * .name = "option-name", 143 * .plugin_alias = "override-file-name", (optional) ··· 158 * .set will be processed. If .value is defined, then it is considered 159 * a string option and .set will be ignored. 160 * 161 + * TEP_PLUGIN_ALIAS: (optional) 162 * The name to use for finding options (uses filename if not defined) 163 */ 164 + #define TEP_PLUGIN_LOADER tep_plugin_loader 165 + #define TEP_PLUGIN_UNLOADER tep_plugin_unloader 166 + #define TEP_PLUGIN_OPTIONS tep_plugin_options 167 + #define TEP_PLUGIN_ALIAS tep_plugin_alias 168 #define _MAKE_STR(x) #x 169 #define MAKE_STR(x) _MAKE_STR(x) 170 + #define TEP_PLUGIN_LOADER_NAME MAKE_STR(TEP_PLUGIN_LOADER) 171 + #define TEP_PLUGIN_UNLOADER_NAME MAKE_STR(TEP_PLUGIN_UNLOADER) 172 + #define TEP_PLUGIN_OPTIONS_NAME MAKE_STR(TEP_PLUGIN_OPTIONS) 173 + #define TEP_PLUGIN_ALIAS_NAME MAKE_STR(TEP_PLUGIN_ALIAS) 174 175 enum format_flags { 176 FIELD_IS_ARRAY = 1, ··· 269 struct print_arg *right; 270 }; 271 272 + struct tep_function_handler; 273 274 struct print_arg_func { 275 + struct tep_function_handler *func; 276 struct print_arg *args; 277 }; 278 ··· 320 }; 321 322 struct event_format { 323 + struct tep_handle *pevent; 324 char *name; 325 int id; 326 int flags; 327 struct format format; 328 struct print_fmt print_fmt; 329 char *system; 330 + tep_event_handler_func handler; 331 void *context; 332 }; 333 ··· 361 EVENT_SQUOTE, 362 }; 363 364 + typedef unsigned long long (*tep_func_handler)(struct trace_seq *s, 365 + unsigned long long *args); 366 367 + enum tep_func_arg_type { 368 + TEP_FUNC_ARG_VOID, 369 + TEP_FUNC_ARG_INT, 370 + TEP_FUNC_ARG_LONG, 371 + TEP_FUNC_ARG_STRING, 372 + TEP_FUNC_ARG_PTR, 373 + TEP_FUNC_ARG_MAX_TYPES 374 }; 375 376 + enum tep_flag { 377 + TEP_NSEC_OUTPUT = 1, /* output in NSECS */ 378 + TEP_DISABLE_SYS_PLUGINS = 1 << 1, 379 + TEP_DISABLE_PLUGINS = 1 << 2, 380 }; 381 382 + #define TEP_ERRORS \ 383 _PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \ 384 _PE(PARSE_EVENT_FAILED, "failed to parse event"), \ 385 _PE(READ_ID_FAILED, "failed to read event id"), \ ··· 411 _PE(FILTER_MISS, "record does not match to filter") 412 413 #undef _PE 414 + #define _PE(__code, __str) TEP_ERRNO__ ## __code 415 + enum tep_errno { 416 + TEP_ERRNO__SUCCESS = 0, 417 + TEP_ERRNO__FILTER_MATCH = TEP_ERRNO__SUCCESS, 418 419 /* 420 * Choose an arbitrary negative big number not to clash with standard ··· 423 * 424 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html 425 */ 426 + __TEP_ERRNO__START = -100000, 427 428 + TEP_ERRORS, 429 430 + __TEP_ERRNO__END, 431 }; 432 #undef _PE 433 ··· 435 436 #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) 437 438 + struct plugin_list *tep_load_plugins(struct tep_handle *pevent); 439 + void tep_unload_plugins(struct plugin_list *plugin_list, 440 + struct tep_handle *pevent); 441 + char **tep_plugin_list_options(void); 442 + void tep_plugin_free_options_list(char **list); 443 + int tep_plugin_add_options(const char *name, 444 + struct tep_plugin_option *options); 445 + void tep_plugin_remove_options(struct tep_plugin_option *options); 446 + void tep_print_plugins(struct trace_seq *s, 447 + const char *prefix, const char *suffix, 448 + const struct plugin_list *list); 449 450 struct cmdline; 451 struct cmdline_list; ··· 454 struct event_handler; 455 struct func_resolver; 456 457 + typedef char *(tep_func_resolver_t)(void *priv, 458 + unsigned long long *addrp, char **modp); 459 460 + struct tep_handle { 461 int ref_count; 462 463 int header_page_ts_offset; ··· 524 struct format_field *bprint_buf_field; 525 526 struct event_handler *handlers; 527 + struct tep_function_handler *func_handlers; 528 529 /* cache */ 530 struct event_format *last_event; ··· 532 char *trace_clock; 533 }; 534 535 + static inline void tep_set_flag(struct tep_handle *pevent, int flag) 536 { 537 pevent->flags |= flag; 538 } 539 540 static inline unsigned short 541 + __data2host2(struct tep_handle *pevent, unsigned short data) 542 { 543 unsigned short swap; 544 ··· 552 } 553 554 static inline unsigned int 555 + __data2host4(struct tep_handle *pevent, unsigned int data) 556 { 557 unsigned int swap; 558 ··· 568 } 569 570 static inline unsigned long long 571 + __data2host8(struct tep_handle *pevent, unsigned long long data) 572 { 573 unsigned long long swap; 574 ··· 597 __data2host8(pevent, __val); \ 598 }) 599 600 + static inline int tep_host_bigendian(void) 601 { 602 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; 603 unsigned int val; ··· 615 TRACE_FLAG_SOFTIRQ = 0x10, 616 }; 617 618 + int tep_set_function_resolver(struct tep_handle *pevent, 619 + tep_func_resolver_t *func, void *priv); 620 + void tep_reset_function_resolver(struct tep_handle *pevent); 621 + int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid); 622 + int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock); 623 + int tep_register_function(struct tep_handle *pevent, char *name, 624 + unsigned long long addr, char *mod); 625 + int tep_register_print_string(struct tep_handle *pevent, const char *fmt, 626 + unsigned long long addr); 627 + int tep_pid_is_registered(struct tep_handle *pevent, int pid); 628 629 + void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, 630 + struct event_format *event, 631 + struct tep_record *record); 632 + void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, 633 + struct event_format *event, 634 + struct tep_record *record, 635 + bool use_trace_clock); 636 + void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, 637 + struct event_format *event, 638 + struct tep_record *record); 639 + void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, 640 + struct tep_record *record, bool use_trace_clock); 641 642 + int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, 643 + int long_size); 644 645 + enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf, 646 + unsigned long size, const char *sys); 647 + enum tep_errno tep_parse_format(struct tep_handle *pevent, 648 + struct event_format **eventp, 649 + const char *buf, 650 + unsigned long size, const char *sys); 651 + void tep_free_format(struct event_format *event); 652 + void tep_free_format_field(struct format_field *field); 653 654 + void *tep_get_field_raw(struct trace_seq *s, struct event_format *event, 655 + const char *name, struct tep_record *record, 656 + int *len, int err); 657 658 + int tep_get_field_val(struct trace_seq *s, struct event_format *event, 659 + const char *name, struct tep_record *record, 660 + unsigned long long *val, int err); 661 + int tep_get_common_field_val(struct trace_seq *s, struct event_format *event, 662 + const char *name, struct tep_record *record, 663 unsigned long long *val, int err); 664 + int tep_get_any_field_val(struct trace_seq *s, struct event_format *event, 665 + const char *name, struct tep_record *record, 666 + unsigned long long *val, int err); 667 668 + int tep_print_num_field(struct trace_seq *s, const char *fmt, 669 struct event_format *event, const char *name, 670 + struct tep_record *record, int err); 671 672 + int tep_print_func_field(struct trace_seq *s, const char *fmt, 673 + struct event_format *event, const char *name, 674 + struct tep_record *record, int err); 675 676 + int tep_register_event_handler(struct tep_handle *pevent, int id, 677 + const char *sys_name, const char *event_name, 678 + tep_event_handler_func func, void *context); 679 + int tep_unregister_event_handler(struct tep_handle *pevent, int id, 680 + const char *sys_name, const char *event_name, 681 + tep_event_handler_func func, void *context); 682 + int tep_register_print_function(struct tep_handle *pevent, 683 + tep_func_handler func, 684 + enum tep_func_arg_type ret_type, 685 + char *name, ...); 686 + int tep_unregister_print_function(struct tep_handle *pevent, 687 + tep_func_handler func, char *name); 688 689 + struct format_field *tep_find_common_field(struct event_format *event, const char *name); 690 + struct format_field *tep_find_field(struct event_format *event, const char *name); 691 + struct format_field *tep_find_any_field(struct event_format *event, const char *name); 692 693 + const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr); 694 unsigned long long 695 + tep_find_function_address(struct tep_handle *pevent, unsigned long long addr); 696 + unsigned long long tep_read_number(struct tep_handle *pevent, const void *ptr, int size); 697 + int tep_read_number_field(struct format_field *field, const void *data, 698 + unsigned long long *value); 699 700 + struct event_format *tep_find_event(struct tep_handle *pevent, int id); 701 702 struct event_format * 703 + tep_find_event_by_name(struct tep_handle *pevent, const char *sys, const char *name); 704 705 + struct event_format * 706 + tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record); 707 + 708 + void tep_data_lat_fmt(struct tep_handle *pevent, 709 + struct trace_seq *s, struct tep_record *record); 710 + int tep_data_type(struct tep_handle *pevent, struct tep_record *rec); 711 + struct event_format *tep_data_event_from_type(struct tep_handle *pevent, int type); 712 + int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec); 713 + int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec); 714 + int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec); 715 + const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid); 716 struct cmdline; 717 + struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, 718 + struct cmdline *next); 719 + int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline); 720 721 + void tep_print_field(struct trace_seq *s, void *data, 722 + struct format_field *field); 723 + void tep_print_fields(struct trace_seq *s, void *data, 724 + int size __maybe_unused, struct event_format *event); 725 + void tep_event_info(struct trace_seq *s, struct event_format *event, 726 + struct tep_record *record); 727 + int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum, 728 char *buf, size_t buflen); 729 730 + struct event_format **tep_list_events(struct tep_handle *pevent, enum event_sort_type); 731 + struct format_field **tep_event_common_fields(struct event_format *event); 732 + struct format_field **tep_event_fields(struct event_format *event); 733 734 + static inline int tep_get_cpus(struct tep_handle *pevent) 735 { 736 return pevent->cpus; 737 } 738 739 + static inline void tep_set_cpus(struct tep_handle *pevent, int cpus) 740 { 741 pevent->cpus = cpus; 742 } 743 744 + static inline int tep_get_long_size(struct tep_handle *pevent) 745 { 746 return pevent->long_size; 747 } 748 749 + static inline void tep_set_long_size(struct tep_handle *pevent, int long_size) 750 { 751 pevent->long_size = long_size; 752 } 753 754 + static inline int tep_get_page_size(struct tep_handle *pevent) 755 { 756 return pevent->page_size; 757 } 758 759 + static inline void tep_set_page_size(struct tep_handle *pevent, int _page_size) 760 { 761 pevent->page_size = _page_size; 762 } 763 764 + static inline int tep_is_file_bigendian(struct tep_handle *pevent) 765 { 766 return pevent->file_bigendian; 767 } 768 769 + static inline void tep_set_file_bigendian(struct tep_handle *pevent, int endian) 770 { 771 pevent->file_bigendian = endian; 772 } 773 774 + static inline int tep_is_host_bigendian(struct tep_handle *pevent) 775 { 776 return pevent->host_bigendian; 777 } 778 779 + static inline void tep_set_host_bigendian(struct tep_handle *pevent, int endian) 780 { 781 pevent->host_bigendian = endian; 782 } 783 784 + static inline int tep_is_latency_format(struct tep_handle *pevent) 785 { 786 return pevent->latency_format; 787 } 788 789 + static inline void tep_set_latency_format(struct tep_handle *pevent, int lat) 790 { 791 pevent->latency_format = lat; 792 } 793 794 + struct tep_handle *tep_alloc(void); 795 + void tep_free(struct tep_handle *pevent); 796 + void tep_ref(struct tep_handle *pevent); 797 + void tep_unref(struct tep_handle *pevent); 798 799 /* access to the internal parser */ 800 + void tep_buffer_init(const char *buf, unsigned long long size); 801 + enum event_type tep_read_token(char **tok); 802 + void tep_free_token(char *token); 803 + int tep_peek_char(void); 804 + const char *tep_get_input_buf(void); 805 + unsigned long long tep_get_input_buf_ptr(void); 806 807 /* for debugging */ 808 + void tep_print_funcs(struct tep_handle *pevent); 809 + void tep_print_printk(struct tep_handle *pevent); 810 811 /* ----------------------- filtering ----------------------- */ 812 ··· 930 struct filter_arg *filter; 931 }; 932 933 + #define TEP_FILTER_ERROR_BUFSZ 1024 934 935 struct event_filter { 936 + struct tep_handle *pevent; 937 int filters; 938 struct filter_type *event_filters; 939 + char error_buffer[TEP_FILTER_ERROR_BUFSZ]; 940 }; 941 942 + struct event_filter *tep_filter_alloc(struct tep_handle *pevent); 943 944 /* for backward compatibility */ 945 + #define FILTER_NONE TEP_ERRNO__NO_FILTER 946 + #define FILTER_NOEXIST TEP_ERRNO__FILTER_NOT_FOUND 947 + #define FILTER_MISS TEP_ERRNO__FILTER_MISS 948 + #define FILTER_MATCH TEP_ERRNO__FILTER_MATCH 949 950 enum filter_trivial_type { 951 FILTER_TRIVIAL_FALSE, ··· 953 FILTER_TRIVIAL_BOTH, 954 }; 955 956 + enum tep_errno tep_filter_add_filter_str(struct event_filter *filter, 957 + const char *filter_str); 958 959 + enum tep_errno tep_filter_match(struct event_filter *filter, 960 + struct tep_record *record); 961 962 + int tep_filter_strerror(struct event_filter *filter, enum tep_errno err, 963 + char *buf, size_t buflen); 964 965 + int tep_event_filtered(struct event_filter *filter, 966 + int event_id); 967 968 + void tep_filter_reset(struct event_filter *filter); 969 970 + int tep_filter_clear_trivial(struct event_filter *filter, 971 + enum filter_trivial_type type); 972 + 973 + void tep_filter_free(struct event_filter *filter); 974 + 975 + char *tep_filter_make_string(struct event_filter *filter, int event_id); 976 + 977 + int tep_filter_remove_event(struct event_filter *filter, 978 + int event_id); 979 + 980 + int tep_filter_event_has_trivial(struct event_filter *filter, 981 + int event_id, 982 enum filter_trivial_type type); 983 984 + int tep_filter_copy(struct event_filter *dest, struct event_filter *source); 985 986 + int tep_update_trivial(struct event_filter *dest, struct event_filter *source, 987 + enum filter_trivial_type type); 988 989 + int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2); 990 991 #endif /* _PARSE_EVENTS_H */
+36 -50
tools/lib/traceevent/event-plugin.c
··· 1 /* 2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 */ 20 21 #include <ctype.h> ··· 20 21 static struct registered_plugin_options { 22 struct registered_plugin_options *next; 23 - struct pevent_plugin_option *options; 24 } *registered_options; 25 26 static struct trace_plugin_options { ··· 44 *str = tolower(*str); 45 } 46 47 - static int update_option_value(struct pevent_plugin_option *op, const char *val) 48 { 49 char *op_val; 50 ··· 83 } 84 85 /** 86 - * traceevent_plugin_list_options - get list of plugin options 87 * 88 * Returns an array of char strings that list the currently registered 89 * plugin options in the format of <plugin>:<option>. This list can be ··· 92 * Returns NULL if there's no options registered. On error it returns 93 * INVALID_PLUGIN_LIST_OPTION 94 * 95 - * Must be freed with traceevent_plugin_free_options_list(). 96 */ 97 - char **traceevent_plugin_list_options(void) 98 { 99 struct registered_plugin_options *reg; 100 - struct pevent_plugin_option *op; 101 char **list = NULL; 102 char *name; 103 int count = 0; ··· 132 return INVALID_PLUGIN_LIST_OPTION; 133 } 134 135 - void traceevent_plugin_free_options_list(char **list) 136 { 137 int i; 138 ··· 149 } 150 151 static int 152 - update_option(const char *file, struct pevent_plugin_option *option) 153 { 154 struct trace_plugin_options *op; 155 char *plugin; ··· 201 } 202 203 /** 204 - * traceevent_plugin_add_options - Add a set of options by a plugin 205 * @name: The name of the plugin adding the options 206 * @options: The set of options being loaded 207 * 208 * Sets the options with the values that have been added by user. 209 */ 210 - int traceevent_plugin_add_options(const char *name, 211 - struct pevent_plugin_option *options) 212 { 213 struct registered_plugin_options *reg; 214 ··· 227 } 228 229 /** 230 - * traceevent_plugin_remove_options - remove plugin options that were registered 231 - * @options: Options to removed that were registered with traceevent_plugin_add_options 232 */ 233 - void traceevent_plugin_remove_options(struct pevent_plugin_option *options) 234 { 235 struct registered_plugin_options **last; 236 struct registered_plugin_options *reg; ··· 246 } 247 248 /** 249 - * traceevent_print_plugins - print out the list of plugins loaded 250 * @s: the trace_seq descripter to write to 251 * @prefix: The prefix string to add before listing the option name 252 * @suffix: The suffix string ot append after the option name 253 - * @list: The list of plugins (usually returned by traceevent_load_plugins() 254 * 255 * Writes to the trace_seq @s the list of plugins (files) that is 256 - * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating: 257 * @prefix = " ", @suffix = "\n". 258 */ 259 - void traceevent_print_plugins(struct trace_seq *s, 260 - const char *prefix, const char *suffix, 261 - const struct plugin_list *list) 262 { 263 while (list) { 264 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix); ··· 267 } 268 269 static void 270 - load_plugin(struct pevent *pevent, const char *path, 271 const char *file, void *data) 272 { 273 struct plugin_list **plugin_list = data; 274 - pevent_plugin_load_func func; 275 struct plugin_list *list; 276 const char *alias; 277 char *plugin; ··· 291 goto out_free; 292 } 293 294 - alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); 295 if (!alias) 296 alias = file; 297 298 - func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); 299 if (!func) { 300 warning("could not find func '%s' in plugin '%s'\n%s\n", 301 - PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); 302 goto out_free; 303 } 304 ··· 322 } 323 324 static void 325 - load_plugins_dir(struct pevent *pevent, const char *suffix, 326 const char *path, 327 - void (*load_plugin)(struct pevent *pevent, 328 const char *path, 329 const char *name, 330 void *data), ··· 364 } 365 366 static void 367 - load_plugins(struct pevent *pevent, const char *suffix, 368 - void (*load_plugin)(struct pevent *pevent, 369 const char *path, 370 const char *name, 371 void *data), ··· 376 char *envdir; 377 int ret; 378 379 - if (pevent->flags & PEVENT_DISABLE_PLUGINS) 380 return; 381 382 /* ··· 384 * check that first. 385 */ 386 #ifdef PLUGIN_DIR 387 - if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS)) 388 load_plugins_dir(pevent, suffix, PLUGIN_DIR, 389 load_plugin, data); 390 #endif ··· 417 } 418 419 struct plugin_list* 420 - traceevent_load_plugins(struct pevent *pevent) 421 { 422 struct plugin_list *list = NULL; 423 ··· 426 } 427 428 void 429 - traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) 430 { 431 - pevent_plugin_unload_func func; 432 struct plugin_list *list; 433 434 while (plugin_list) { 435 list = plugin_list; 436 plugin_list = list->next; 437 - func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); 438 if (func) 439 func(pevent); 440 dlclose(list->handle);
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 7 #include <ctype.h> ··· 34 35 static struct registered_plugin_options { 36 struct registered_plugin_options *next; 37 + struct tep_plugin_option *options; 38 } *registered_options; 39 40 static struct trace_plugin_options { ··· 58 *str = tolower(*str); 59 } 60 61 + static int update_option_value(struct tep_plugin_option *op, const char *val) 62 { 63 char *op_val; 64 ··· 97 } 98 99 /** 100 + * tep_plugin_list_options - get list of plugin options 101 * 102 * Returns an array of char strings that list the currently registered 103 * plugin options in the format of <plugin>:<option>. This list can be ··· 106 * Returns NULL if there's no options registered. On error it returns 107 * INVALID_PLUGIN_LIST_OPTION 108 * 109 + * Must be freed with tep_plugin_free_options_list(). 110 */ 111 + char **tep_plugin_list_options(void) 112 { 113 struct registered_plugin_options *reg; 114 + struct tep_plugin_option *op; 115 char **list = NULL; 116 char *name; 117 int count = 0; ··· 146 return INVALID_PLUGIN_LIST_OPTION; 147 } 148 149 + void tep_plugin_free_options_list(char **list) 150 { 151 int i; 152 ··· 163 } 164 165 static int 166 + update_option(const char *file, struct tep_plugin_option *option) 167 { 168 struct trace_plugin_options *op; 169 char *plugin; ··· 215 } 216 217 /** 218 + * tep_plugin_add_options - Add a set of options by a plugin 219 * @name: The name of the plugin adding the options 220 * @options: The set of options being loaded 221 * 222 * Sets the options with the values that have been added by user. 223 */ 224 + int tep_plugin_add_options(const char *name, 225 + struct tep_plugin_option *options) 226 { 227 struct registered_plugin_options *reg; 228 ··· 241 } 242 243 /** 244 + * tep_plugin_remove_options - remove plugin options that were registered 245 + * @options: Options to removed that were registered with tep_plugin_add_options 246 */ 247 + void tep_plugin_remove_options(struct tep_plugin_option *options) 248 { 249 struct registered_plugin_options **last; 250 struct registered_plugin_options *reg; ··· 260 } 261 262 /** 263 + * tep_print_plugins - print out the list of plugins loaded 264 * @s: the trace_seq descripter to write to 265 * @prefix: The prefix string to add before listing the option name 266 * @suffix: The suffix string ot append after the option name 267 + * @list: The list of plugins (usually returned by tep_load_plugins() 268 * 269 * Writes to the trace_seq @s the list of plugins (files) that is 270 + * returned by tep_load_plugins(). Use @prefix and @suffix for formating: 271 * @prefix = " ", @suffix = "\n". 272 */ 273 + void tep_print_plugins(struct trace_seq *s, 274 + const char *prefix, const char *suffix, 275 + const struct plugin_list *list) 276 { 277 while (list) { 278 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix); ··· 281 } 282 283 static void 284 + load_plugin(struct tep_handle *pevent, const char *path, 285 const char *file, void *data) 286 { 287 struct plugin_list **plugin_list = data; 288 + tep_plugin_load_func func; 289 struct plugin_list *list; 290 const char *alias; 291 char *plugin; ··· 305 goto out_free; 306 } 307 308 + alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME); 309 if (!alias) 310 alias = file; 311 312 + func = dlsym(handle, TEP_PLUGIN_LOADER_NAME); 313 if (!func) { 314 warning("could not find func '%s' in plugin '%s'\n%s\n", 315 + TEP_PLUGIN_LOADER_NAME, plugin, dlerror()); 316 goto out_free; 317 } 318 ··· 336 } 337 338 static void 339 + load_plugins_dir(struct tep_handle *pevent, const char *suffix, 340 const char *path, 341 + void (*load_plugin)(struct tep_handle *pevent, 342 const char *path, 343 const char *name, 344 void *data), ··· 378 } 379 380 static void 381 + load_plugins(struct tep_handle *pevent, const char *suffix, 382 + void (*load_plugin)(struct tep_handle *pevent, 383 const char *path, 384 const char *name, 385 void *data), ··· 390 char *envdir; 391 int ret; 392 393 + if (pevent->flags & TEP_DISABLE_PLUGINS) 394 return; 395 396 /* ··· 398 * check that first. 399 */ 400 #ifdef PLUGIN_DIR 401 + if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS)) 402 load_plugins_dir(pevent, suffix, PLUGIN_DIR, 403 load_plugin, data); 404 #endif ··· 431 } 432 433 struct plugin_list* 434 + tep_load_plugins(struct tep_handle *pevent) 435 { 436 struct plugin_list *list = NULL; 437 ··· 440 } 441 442 void 443 + tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent) 444 { 445 + tep_plugin_unload_func func; 446 struct plugin_list *list; 447 448 while (plugin_list) { 449 list = plugin_list; 450 plugin_list = list->next; 451 + func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME); 452 if (func) 453 func(pevent); 454 dlclose(list->handle);
+1 -15
tools/lib/traceevent/event-utils.h
··· 1 /* 2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 */ 20 #ifndef __UTIL_H 21 #define __UTIL_H
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 */ 2 /* 3 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 #ifndef __UTIL_H 7 #define __UTIL_H
+1 -16
tools/lib/traceevent/kbuffer-parse.c
··· 1 /* 2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, write to the Free Software 17 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 - * 19 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 */ 21 #include <stdio.h> 22 #include <stdlib.h>
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 #include <stdio.h> 7 #include <stdlib.h>
+145 -159
tools/lib/traceevent/parse-filter.c
··· 1 /* 2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 */ 20 #include <stdio.h> 21 #include <stdlib.h> ··· 37 int len; 38 int i; 39 40 - input = pevent_get_input_buf(); 41 - index = pevent_get_input_buf_ptr(); 42 len = input ? strlen(input) : 0; 43 44 if (len) { ··· 52 } 53 54 va_start(ap, fmt); 55 - vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap); 56 va_end(ap); 57 } 58 59 static void free_token(char *token) 60 { 61 - pevent_free_token(token); 62 } 63 64 static enum event_type read_token(char **tok) ··· 68 69 do { 70 free_token(token); 71 - type = pevent_read_token(&token); 72 } while (type == EVENT_NEWLINE || type == EVENT_SPACE); 73 74 /* If token is = or ! check to see if the next char is ~ */ 75 if (token && 76 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && 77 - pevent_peek_char() == '~') { 78 /* append it */ 79 *tok = malloc(3); 80 if (*tok == NULL) { ··· 84 sprintf(*tok, "%c%c", *token, '~'); 85 free_token(token); 86 /* Now remove the '~' from the buffer */ 87 - pevent_read_token(&token); 88 free_token(token); 89 } else 90 *tok = token; ··· 153 154 filter_type = &filter->event_filters[i]; 155 filter_type->event_id = id; 156 - filter_type->event = pevent_find_event(filter->pevent, id); 157 filter_type->filter = NULL; 158 159 filter->filters++; ··· 162 } 163 164 /** 165 - * pevent_filter_alloc - create a new event filter 166 * @pevent: The pevent that this filter is associated with 167 */ 168 - struct event_filter *pevent_filter_alloc(struct pevent *pevent) 169 { 170 struct event_filter *filter; 171 ··· 175 176 memset(filter, 0, sizeof(*filter)); 177 filter->pevent = pevent; 178 - pevent_ref(pevent); 179 180 return filter; 181 } ··· 254 !regexec(ereg, event->name, 0, NULL, 0); 255 } 256 257 - static enum pevent_errno 258 - find_event(struct pevent *pevent, struct event_list **events, 259 char *sys_name, char *event_name) 260 { 261 struct event_format *event; ··· 275 276 ret = asprintf(&reg, "^%s$", event_name); 277 if (ret < 0) 278 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 279 280 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); 281 free(reg); 282 283 if (ret) 284 - return PEVENT_ERRNO__INVALID_EVENT_NAME; 285 286 if (sys_name) { 287 ret = asprintf(&reg, "^%s$", sys_name); 288 if (ret < 0) { 289 regfree(&ereg); 290 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 291 } 292 293 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); 294 free(reg); 295 if (ret) { 296 regfree(&ereg); 297 - return PEVENT_ERRNO__INVALID_EVENT_NAME; 298 } 299 } 300 ··· 314 regfree(&sreg); 315 316 if (!match) 317 - return PEVENT_ERRNO__EVENT_NOT_FOUND; 318 if (fail) 319 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 320 321 return 0; 322 } ··· 332 } 333 } 334 335 - static enum pevent_errno 336 create_arg_item(struct event_format *event, const char *token, 337 enum event_type type, struct filter_arg **parg, char *error_str) 338 { ··· 342 arg = allocate_arg(); 343 if (arg == NULL) { 344 show_error(error_str, "failed to allocate filter arg"); 345 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 346 } 347 348 switch (type) { ··· 356 if (!arg->value.str) { 357 free_arg(arg); 358 show_error(error_str, "failed to allocate string filter arg"); 359 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 360 } 361 break; 362 case EVENT_ITEM: ··· 368 break; 369 } 370 /* Consider this a field */ 371 - field = pevent_find_any_field(event, token); 372 if (!field) { 373 /* If token is 'COMM' or 'CPU' then it is special */ 374 if (strcmp(token, COMM) == 0) { ··· 388 default: 389 free_arg(arg); 390 show_error(error_str, "expected a value but found %s", token); 391 - return PEVENT_ERRNO__UNEXPECTED_TYPE; 392 } 393 *parg = arg; 394 return 0; ··· 440 return arg; 441 } 442 443 - static enum pevent_errno 444 add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) 445 { 446 struct filter_arg *left; ··· 473 break; 474 default: 475 show_error(error_str, "Illegal rvalue"); 476 - return PEVENT_ERRNO__ILLEGAL_RVALUE; 477 } 478 479 /* ··· 520 if (left->type != FILTER_ARG_FIELD) { 521 show_error(error_str, 522 "Illegal lvalue for string comparison"); 523 - return PEVENT_ERRNO__ILLEGAL_LVALUE; 524 } 525 526 /* Make sure this is a valid string compare */ ··· 539 show_error(error_str, 540 "RegEx '%s' did not compute", 541 str); 542 - return PEVENT_ERRNO__INVALID_REGEX; 543 } 544 break; 545 default: 546 show_error(error_str, 547 "Illegal comparison for string"); 548 - return PEVENT_ERRNO__ILLEGAL_STRING_CMP; 549 } 550 551 op->type = FILTER_ARG_STR; ··· 554 op->str.val = strdup(str); 555 if (!op->str.val) { 556 show_error(error_str, "Failed to allocate string filter"); 557 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 558 } 559 /* 560 * Need a buffer to copy data for tests ··· 562 op->str.buffer = malloc(op->str.field->size + 1); 563 if (!op->str.buffer) { 564 show_error(error_str, "Failed to allocate string filter"); 565 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 566 } 567 /* Null terminate this buffer */ 568 op->str.buffer[op->str.field->size] = 0; ··· 581 case FILTER_CMP_NOT_REGEX: 582 show_error(error_str, 583 "Op not allowed with integers"); 584 - return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; 585 586 default: 587 break; ··· 602 603 out_fail: 604 show_error(error_str, "Syntax error"); 605 - return PEVENT_ERRNO__SYNTAX_ERROR; 606 } 607 608 static struct filter_arg * ··· 615 return arg; 616 } 617 618 - static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) 619 { 620 switch (op->type) { 621 case FILTER_ARG_EXP: ··· 634 /* left arg of compares must be a field */ 635 if (arg->type != FILTER_ARG_FIELD && 636 arg->type != FILTER_ARG_BOOLEAN) 637 - return PEVENT_ERRNO__INVALID_ARG_TYPE; 638 op->num.left = arg; 639 break; 640 default: 641 - return PEVENT_ERRNO__INVALID_ARG_TYPE; 642 } 643 return 0; 644 } ··· 751 FILTER_VAL_TRUE, 752 }; 753 754 - static enum pevent_errno 755 reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, 756 struct filter_arg *arg, char *error_str) 757 { ··· 761 if (parent->type != FILTER_ARG_OP && 762 arg->type != FILTER_ARG_OP) { 763 show_error(error_str, "can not reparent other than OP"); 764 - return PEVENT_ERRNO__REPARENT_NOT_OP; 765 } 766 767 /* Get the sibling */ ··· 773 other_child = old_child->op.right; 774 } else { 775 show_error(error_str, "Error in reparent op, find other child"); 776 - return PEVENT_ERRNO__REPARENT_FAILED; 777 } 778 779 /* Detach arg from old_child */ ··· 794 ptr = &parent->op.left; 795 else { 796 show_error(error_str, "Error in reparent op"); 797 - return PEVENT_ERRNO__REPARENT_FAILED; 798 } 799 800 *ptr = arg; ··· 803 return 0; 804 } 805 806 - /* Returns either filter_vals (success) or pevent_errno (failfure) */ 807 static int test_arg(struct filter_arg *parent, struct filter_arg *arg, 808 char *error_str) 809 { ··· 898 return rval; 899 default: 900 show_error(error_str, "bad arg in filter tree"); 901 - return PEVENT_ERRNO__BAD_FILTER_ARG; 902 } 903 return FILTER_VAL_NORM; 904 } ··· 923 arg->boolean.value = ret == FILTER_VAL_TRUE; 924 } else { 925 show_error(error_str, "Failed to allocate filter arg"); 926 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 927 } 928 break; 929 ··· 938 return ret; 939 } 940 941 - static enum pevent_errno 942 process_filter(struct event_format *event, struct filter_arg **parg, 943 char *error_str, int not) 944 { ··· 952 enum filter_op_type btype; 953 enum filter_exp_type etype; 954 enum filter_cmp_type ctype; 955 - enum pevent_errno ret; 956 957 *parg = NULL; 958 ··· 990 case EVENT_DELIM: 991 if (*token == ',') { 992 show_error(error_str, "Illegal token ','"); 993 - ret = PEVENT_ERRNO__ILLEGAL_TOKEN; 994 goto fail; 995 } 996 ··· 998 if (left_item) { 999 show_error(error_str, 1000 "Open paren can not come after item"); 1001 - ret = PEVENT_ERRNO__INVALID_PAREN; 1002 goto fail; 1003 } 1004 if (current_exp) { 1005 show_error(error_str, 1006 "Open paren can not come after expression"); 1007 - ret = PEVENT_ERRNO__INVALID_PAREN; 1008 goto fail; 1009 } 1010 1011 ret = process_filter(event, &arg, error_str, 0); 1012 - if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { 1013 if (ret == 0) { 1014 show_error(error_str, 1015 "Unbalanced number of '('"); 1016 - ret = PEVENT_ERRNO__UNBALANCED_PAREN; 1017 } 1018 goto fail; 1019 } ··· 1050 else 1051 *parg = current_exp; 1052 free(token); 1053 - return PEVENT_ERRNO__UNBALANCED_PAREN; 1054 } 1055 break; 1056 ··· 1077 case OP_NONE: 1078 show_error(error_str, 1079 "Unknown op token %s", token); 1080 - ret = PEVENT_ERRNO__UNKNOWN_TOKEN; 1081 goto fail; 1082 } 1083 ··· 1165 1166 fail_alloc: 1167 show_error(error_str, "failed to allocate filter arg"); 1168 - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; 1169 goto fail; 1170 fail_syntax: 1171 show_error(error_str, "Syntax error"); 1172 - ret = PEVENT_ERRNO__SYNTAX_ERROR; 1173 fail: 1174 free_arg(current_op); 1175 free_arg(current_exp); ··· 1178 return ret; 1179 } 1180 1181 - static enum pevent_errno 1182 process_event(struct event_format *event, const char *filter_str, 1183 struct filter_arg **parg, char *error_str) 1184 { 1185 int ret; 1186 1187 - pevent_buffer_init(filter_str, strlen(filter_str)); 1188 1189 ret = process_filter(event, parg, error_str, 0); 1190 if (ret < 0) ··· 1194 if (!*parg) { 1195 *parg = allocate_arg(); 1196 if (*parg == NULL) 1197 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 1198 1199 (*parg)->type = FILTER_ARG_BOOLEAN; 1200 (*parg)->boolean.value = FILTER_FALSE; ··· 1203 return 0; 1204 } 1205 1206 - static enum pevent_errno 1207 filter_event(struct event_filter *filter, struct event_format *event, 1208 const char *filter_str, char *error_str) 1209 { 1210 struct filter_type *filter_type; 1211 struct filter_arg *arg; 1212 - enum pevent_errno ret; 1213 1214 if (filter_str) { 1215 ret = process_event(event, filter_str, &arg, error_str); ··· 1220 /* just add a TRUE arg */ 1221 arg = allocate_arg(); 1222 if (arg == NULL) 1223 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 1224 1225 arg->type = FILTER_ARG_BOOLEAN; 1226 arg->boolean.value = FILTER_TRUE; ··· 1228 1229 filter_type = add_filter_type(filter, event->id); 1230 if (filter_type == NULL) 1231 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 1232 1233 if (filter_type->filter) 1234 free_arg(filter_type->filter); ··· 1240 static void filter_init_error_buf(struct event_filter *filter) 1241 { 1242 /* clear buffer to reset show error */ 1243 - pevent_buffer_init("", 0); 1244 filter->error_buffer[0] = '\0'; 1245 } 1246 1247 /** 1248 - * pevent_filter_add_filter_str - add a new filter 1249 * @filter: the event filter to add to 1250 * @filter_str: the filter string that contains the filter 1251 * 1252 * Returns 0 if the filter was successfully added or a 1253 - * negative error code. Use pevent_filter_strerror() to see 1254 * actual error message in case of error. 1255 */ 1256 - enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, 1257 - const char *filter_str) 1258 { 1259 - struct pevent *pevent = filter->pevent; 1260 struct event_list *event; 1261 struct event_list *events = NULL; 1262 const char *filter_start; ··· 1265 char *event_name = NULL; 1266 char *sys_name = NULL; 1267 char *sp; 1268 - enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ 1269 int len; 1270 int ret; 1271 ··· 1291 if (this_event == NULL) { 1292 /* This can only happen when events is NULL, but still */ 1293 free_events(events); 1294 - return PEVENT_ERRNO__MEM_ALLOC_FAILED; 1295 } 1296 memcpy(this_event, filter_str, len); 1297 this_event[len] = 0; ··· 1308 /* This can only happen when events is NULL, but still */ 1309 free_events(events); 1310 free(this_event); 1311 - return PEVENT_ERRNO__FILTER_NOT_FOUND; 1312 } 1313 1314 /* Find this event */ ··· 1335 1336 if (ret >= 0 && pevent->test_filters) { 1337 char *test; 1338 - test = pevent_filter_make_string(filter, event->event->id); 1339 if (test) { 1340 printf(" '%s: %s'\n", event->event->name, test); 1341 free(test); ··· 1357 } 1358 1359 /** 1360 - * pevent_filter_strerror - fill error message in a buffer 1361 * @filter: the event filter contains error 1362 * @err: the error code 1363 * @buf: the buffer to be filled in ··· 1365 * 1366 * Returns 0 if message was filled successfully, -1 if error 1367 */ 1368 - int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, 1369 - char *buf, size_t buflen) 1370 { 1371 - if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END) 1372 return -1; 1373 1374 if (strlen(filter->error_buffer) > 0) { ··· 1379 return 0; 1380 } 1381 1382 - return pevent_strerror(filter->pevent, err, buf, buflen); 1383 } 1384 1385 /** 1386 - * pevent_filter_remove_event - remove a filter for an event 1387 * @filter: the event filter to remove from 1388 * @event_id: the event to remove a filter for 1389 * ··· 1393 * Returns 1: if an event was removed 1394 * 0: if the event was not found 1395 */ 1396 - int pevent_filter_remove_event(struct event_filter *filter, 1397 - int event_id) 1398 { 1399 struct filter_type *filter_type; 1400 unsigned long len; ··· 1423 } 1424 1425 /** 1426 - * pevent_filter_reset - clear all filters in a filter 1427 * @filter: the event filter to reset 1428 * 1429 * Removes all filters from a filter and resets it. 1430 */ 1431 - void pevent_filter_reset(struct event_filter *filter) 1432 { 1433 int i; 1434 ··· 1440 filter->event_filters = NULL; 1441 } 1442 1443 - void pevent_filter_free(struct event_filter *filter) 1444 { 1445 - pevent_unref(filter->pevent); 1446 1447 - pevent_filter_reset(filter); 1448 1449 free(filter); 1450 } ··· 1464 /* Can't assume that the pevent's are the same */ 1465 sys = filter_type->event->system; 1466 name = filter_type->event->name; 1467 - event = pevent_find_event_by_name(filter->pevent, sys, name); 1468 if (!event) 1469 return -1; 1470 ··· 1501 } 1502 1503 /** 1504 - * pevent_filter_copy - copy a filter using another filter 1505 * @dest - the filter to copy to 1506 * @source - the filter to copy from 1507 * 1508 * Returns 0 on success and -1 if not all filters were copied 1509 */ 1510 - int pevent_filter_copy(struct event_filter *dest, struct event_filter *source) 1511 { 1512 int ret = 0; 1513 int i; 1514 1515 - pevent_filter_reset(dest); 1516 1517 for (i = 0; i < source->filters; i++) { 1518 if (copy_filter_type(dest, source, &source->event_filters[i])) ··· 1523 1524 1525 /** 1526 - * pevent_update_trivial - update the trivial filters with the given filter 1527 * @dest - the filter to update 1528 * @source - the filter as the source of the update 1529 * @type - the type of trivial filter to update. ··· 1533 * Returns 0 on success and -1 if there was a problem updating, but 1534 * events may have still been updated on error. 1535 */ 1536 - int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, 1537 - enum filter_trivial_type type) 1538 { 1539 - struct pevent *src_pevent; 1540 - struct pevent *dest_pevent; 1541 struct event_format *event; 1542 struct filter_type *filter_type; 1543 struct filter_arg *arg; ··· 1564 1565 if (src_pevent != dest_pevent) { 1566 /* do a look up */ 1567 - event = pevent_find_event_by_name(src_pevent, 1568 - event->system, 1569 - event->name); 1570 if (!event) 1571 return -1; 1572 } 1573 1574 - str = pevent_filter_make_string(source, event->id); 1575 if (!str) 1576 continue; 1577 ··· 1584 } 1585 1586 /** 1587 - * pevent_filter_clear_trivial - clear TRUE and FALSE filters 1588 * @filter: the filter to remove trivial filters from 1589 * @type: remove only true, false, or both 1590 * ··· 1592 * 1593 * Returns 0 on success and -1 if there was a problem. 1594 */ 1595 - int pevent_filter_clear_trivial(struct event_filter *filter, 1596 - enum filter_trivial_type type) 1597 { 1598 struct filter_type *filter_type; 1599 int count = 0; ··· 1639 return 0; 1640 1641 for (i = 0; i < count; i++) 1642 - pevent_filter_remove_event(filter, ids[i]); 1643 1644 free(ids); 1645 return 0; 1646 } 1647 1648 /** 1649 - * pevent_filter_event_has_trivial - return true event contains trivial filter 1650 * @filter: the filter with the information 1651 * @event_id: the id of the event to test 1652 * @type: trivial type to test for (TRUE, FALSE, EITHER) ··· 1654 * Returns 1 if the event contains a matching trivial type 1655 * otherwise 0. 1656 */ 1657 - int pevent_filter_event_has_trivial(struct event_filter *filter, 1658 - int event_id, 1659 - enum filter_trivial_type type) 1660 { 1661 struct filter_type *filter_type; 1662 ··· 1683 } 1684 1685 static int test_filter(struct event_format *event, struct filter_arg *arg, 1686 - struct pevent_record *record, enum pevent_errno *err); 1687 1688 static const char * 1689 - get_comm(struct event_format *event, struct pevent_record *record) 1690 { 1691 const char *comm; 1692 int pid; 1693 1694 - pid = pevent_data_pid(event->pevent, record); 1695 - comm = pevent_data_comm_from_pid(event->pevent, pid); 1696 return comm; 1697 } 1698 1699 static unsigned long long 1700 get_value(struct event_format *event, 1701 - struct format_field *field, struct pevent_record *record) 1702 { 1703 unsigned long long val; 1704 ··· 1714 if (field == &cpu) 1715 return record->cpu; 1716 1717 - pevent_read_number_field(field, record->data, &val); 1718 1719 if (!(field->flags & FIELD_IS_SIGNED)) 1720 return val; ··· 1734 1735 static unsigned long long 1736 get_arg_value(struct event_format *event, struct filter_arg *arg, 1737 - struct pevent_record *record, enum pevent_errno *err); 1738 1739 static unsigned long long 1740 get_exp_value(struct event_format *event, struct filter_arg *arg, 1741 - struct pevent_record *record, enum pevent_errno *err) 1742 { 1743 unsigned long long lval, rval; 1744 ··· 1786 case FILTER_EXP_NOT: 1787 default: 1788 if (!*err) 1789 - *err = PEVENT_ERRNO__INVALID_EXP_TYPE; 1790 } 1791 return 0; 1792 } 1793 1794 static unsigned long long 1795 get_arg_value(struct event_format *event, struct filter_arg *arg, 1796 - struct pevent_record *record, enum pevent_errno *err) 1797 { 1798 switch (arg->type) { 1799 case FILTER_ARG_FIELD: ··· 1802 case FILTER_ARG_VALUE: 1803 if (arg->value.type != FILTER_NUMBER) { 1804 if (!*err) 1805 - *err = PEVENT_ERRNO__NOT_A_NUMBER; 1806 } 1807 return arg->value.val; 1808 ··· 1811 1812 default: 1813 if (!*err) 1814 - *err = PEVENT_ERRNO__INVALID_ARG_TYPE; 1815 } 1816 return 0; 1817 } 1818 1819 static int test_num(struct event_format *event, struct filter_arg *arg, 1820 - struct pevent_record *record, enum pevent_errno *err) 1821 { 1822 unsigned long long lval, rval; 1823 ··· 1852 1853 default: 1854 if (!*err) 1855 - *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; 1856 return 0; 1857 } 1858 } 1859 1860 - static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) 1861 { 1862 struct event_format *event; 1863 - struct pevent *pevent; 1864 unsigned long long addr; 1865 const char *val = NULL; 1866 unsigned int size; ··· 1895 1896 if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG)) 1897 /* convert to a kernel symbol */ 1898 - val = pevent_find_function(pevent, addr); 1899 1900 if (val == NULL) { 1901 /* just use the hex of the string name */ ··· 1908 } 1909 1910 static int test_str(struct event_format *event, struct filter_arg *arg, 1911 - struct pevent_record *record, enum pevent_errno *err) 1912 { 1913 const char *val; 1914 ··· 1933 1934 default: 1935 if (!*err) 1936 - *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; 1937 return 0; 1938 } 1939 } 1940 1941 static int test_op(struct event_format *event, struct filter_arg *arg, 1942 - struct pevent_record *record, enum pevent_errno *err) 1943 { 1944 switch (arg->op.type) { 1945 case FILTER_OP_AND: ··· 1955 1956 default: 1957 if (!*err) 1958 - *err = PEVENT_ERRNO__INVALID_OP_TYPE; 1959 return 0; 1960 } 1961 } 1962 1963 static int test_filter(struct event_format *event, struct filter_arg *arg, 1964 - struct pevent_record *record, enum pevent_errno *err) 1965 { 1966 if (*err) { 1967 /* ··· 1995 1996 default: 1997 if (!*err) 1998 - *err = PEVENT_ERRNO__INVALID_ARG_TYPE; 1999 return 0; 2000 } 2001 } 2002 2003 /** 2004 - * pevent_event_filtered - return true if event has filter 2005 * @filter: filter struct with filter information 2006 * @event_id: event id to test if filter exists 2007 * 2008 * Returns 1 if filter found for @event_id 2009 * otherwise 0; 2010 */ 2011 - int pevent_event_filtered(struct event_filter *filter, int event_id) 2012 { 2013 struct filter_type *filter_type; 2014 ··· 2021 } 2022 2023 /** 2024 - * pevent_filter_match - test if a record matches a filter 2025 * @filter: filter struct with filter information 2026 * @record: the record to test against the filter 2027 * 2028 - * Returns: match result or error code (prefixed with PEVENT_ERRNO__) 2029 * FILTER_MATCH - filter found for event and @record matches 2030 * FILTER_MISS - filter found for event and @record does not match 2031 * FILTER_NOT_FOUND - no filter found for @record's event 2032 * NO_FILTER - if no filters exist 2033 * otherwise - error occurred during test 2034 */ 2035 - enum pevent_errno pevent_filter_match(struct event_filter *filter, 2036 - struct pevent_record *record) 2037 { 2038 - struct pevent *pevent = filter->pevent; 2039 struct filter_type *filter_type; 2040 int event_id; 2041 int ret; 2042 - enum pevent_errno err = 0; 2043 2044 filter_init_error_buf(filter); 2045 2046 if (!filter->filters) 2047 - return PEVENT_ERRNO__NO_FILTER; 2048 2049 - event_id = pevent_data_type(pevent, record); 2050 2051 filter_type = find_filter_type(filter, event_id); 2052 if (!filter_type) 2053 - return PEVENT_ERRNO__FILTER_NOT_FOUND; 2054 2055 ret = test_filter(filter_type->event, filter_type->filter, record, &err); 2056 if (err) 2057 return err; 2058 2059 - return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; 2060 } 2061 2062 static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) ··· 2350 } 2351 2352 /** 2353 - * pevent_filter_make_string - return a string showing the filter 2354 * @filter: filter struct with filter information 2355 * @event_id: the event id to return the filter string with 2356 * ··· 2359 * NULL is returned if no filter is found or allocation failed. 2360 */ 2361 char * 2362 - pevent_filter_make_string(struct event_filter *filter, int event_id) 2363 { 2364 struct filter_type *filter_type; 2365 ··· 2375 } 2376 2377 /** 2378 - * pevent_filter_compare - compare two filters and return if they are the same 2379 * @filter1: Filter to compare with @filter2 2380 * @filter2: Filter to compare with @filter1 2381 * ··· 2383 * 1 if the two filters hold the same content. 2384 * 0 if they do not. 2385 */ 2386 - int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2) 2387 { 2388 struct filter_type *filter_type1; 2389 struct filter_type *filter_type2;
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 #include <stdio.h> 7 #include <stdlib.h> ··· 51 int len; 52 int i; 53 54 + input = tep_get_input_buf(); 55 + index = tep_get_input_buf_ptr(); 56 len = input ? strlen(input) : 0; 57 58 if (len) { ··· 66 } 67 68 va_start(ap, fmt); 69 + vsnprintf(error_buf + len, TEP_FILTER_ERROR_BUFSZ - len, fmt, ap); 70 va_end(ap); 71 } 72 73 static void free_token(char *token) 74 { 75 + tep_free_token(token); 76 } 77 78 static enum event_type read_token(char **tok) ··· 82 83 do { 84 free_token(token); 85 + type = tep_read_token(&token); 86 } while (type == EVENT_NEWLINE || type == EVENT_SPACE); 87 88 /* If token is = or ! check to see if the next char is ~ */ 89 if (token && 90 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && 91 + tep_peek_char() == '~') { 92 /* append it */ 93 *tok = malloc(3); 94 if (*tok == NULL) { ··· 98 sprintf(*tok, "%c%c", *token, '~'); 99 free_token(token); 100 /* Now remove the '~' from the buffer */ 101 + tep_read_token(&token); 102 free_token(token); 103 } else 104 *tok = token; ··· 167 168 filter_type = &filter->event_filters[i]; 169 filter_type->event_id = id; 170 + filter_type->event = tep_find_event(filter->pevent, id); 171 filter_type->filter = NULL; 172 173 filter->filters++; ··· 176 } 177 178 /** 179 + * tep_filter_alloc - create a new event filter 180 * @pevent: The pevent that this filter is associated with 181 */ 182 + struct event_filter *tep_filter_alloc(struct tep_handle *pevent) 183 { 184 struct event_filter *filter; 185 ··· 189 190 memset(filter, 0, sizeof(*filter)); 191 filter->pevent = pevent; 192 + tep_ref(pevent); 193 194 return filter; 195 } ··· 268 !regexec(ereg, event->name, 0, NULL, 0); 269 } 270 271 + static enum tep_errno 272 + find_event(struct tep_handle *pevent, struct event_list **events, 273 char *sys_name, char *event_name) 274 { 275 struct event_format *event; ··· 289 290 ret = asprintf(&reg, "^%s$", event_name); 291 if (ret < 0) 292 + return TEP_ERRNO__MEM_ALLOC_FAILED; 293 294 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); 295 free(reg); 296 297 if (ret) 298 + return TEP_ERRNO__INVALID_EVENT_NAME; 299 300 if (sys_name) { 301 ret = asprintf(&reg, "^%s$", sys_name); 302 if (ret < 0) { 303 regfree(&ereg); 304 + return TEP_ERRNO__MEM_ALLOC_FAILED; 305 } 306 307 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); 308 free(reg); 309 if (ret) { 310 regfree(&ereg); 311 + return TEP_ERRNO__INVALID_EVENT_NAME; 312 } 313 } 314 ··· 328 regfree(&sreg); 329 330 if (!match) 331 + return TEP_ERRNO__EVENT_NOT_FOUND; 332 if (fail) 333 + return TEP_ERRNO__MEM_ALLOC_FAILED; 334 335 return 0; 336 } ··· 346 } 347 } 348 349 + static enum tep_errno 350 create_arg_item(struct event_format *event, const char *token, 351 enum event_type type, struct filter_arg **parg, char *error_str) 352 { ··· 356 arg = allocate_arg(); 357 if (arg == NULL) { 358 show_error(error_str, "failed to allocate filter arg"); 359 + return TEP_ERRNO__MEM_ALLOC_FAILED; 360 } 361 362 switch (type) { ··· 370 if (!arg->value.str) { 371 free_arg(arg); 372 show_error(error_str, "failed to allocate string filter arg"); 373 + return TEP_ERRNO__MEM_ALLOC_FAILED; 374 } 375 break; 376 case EVENT_ITEM: ··· 382 break; 383 } 384 /* Consider this a field */ 385 + field = tep_find_any_field(event, token); 386 if (!field) { 387 /* If token is 'COMM' or 'CPU' then it is special */ 388 if (strcmp(token, COMM) == 0) { ··· 402 default: 403 free_arg(arg); 404 show_error(error_str, "expected a value but found %s", token); 405 + return TEP_ERRNO__UNEXPECTED_TYPE; 406 } 407 *parg = arg; 408 return 0; ··· 454 return arg; 455 } 456 457 + static enum tep_errno 458 add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) 459 { 460 struct filter_arg *left; ··· 487 break; 488 default: 489 show_error(error_str, "Illegal rvalue"); 490 + return TEP_ERRNO__ILLEGAL_RVALUE; 491 } 492 493 /* ··· 534 if (left->type != FILTER_ARG_FIELD) { 535 show_error(error_str, 536 "Illegal lvalue for string comparison"); 537 + return TEP_ERRNO__ILLEGAL_LVALUE; 538 } 539 540 /* Make sure this is a valid string compare */ ··· 553 show_error(error_str, 554 "RegEx '%s' did not compute", 555 str); 556 + return TEP_ERRNO__INVALID_REGEX; 557 } 558 break; 559 default: 560 show_error(error_str, 561 "Illegal comparison for string"); 562 + return TEP_ERRNO__ILLEGAL_STRING_CMP; 563 } 564 565 op->type = FILTER_ARG_STR; ··· 568 op->str.val = strdup(str); 569 if (!op->str.val) { 570 show_error(error_str, "Failed to allocate string filter"); 571 + return TEP_ERRNO__MEM_ALLOC_FAILED; 572 } 573 /* 574 * Need a buffer to copy data for tests ··· 576 op->str.buffer = malloc(op->str.field->size + 1); 577 if (!op->str.buffer) { 578 show_error(error_str, "Failed to allocate string filter"); 579 + return TEP_ERRNO__MEM_ALLOC_FAILED; 580 } 581 /* Null terminate this buffer */ 582 op->str.buffer[op->str.field->size] = 0; ··· 595 case FILTER_CMP_NOT_REGEX: 596 show_error(error_str, 597 "Op not allowed with integers"); 598 + return TEP_ERRNO__ILLEGAL_INTEGER_CMP; 599 600 default: 601 break; ··· 616 617 out_fail: 618 show_error(error_str, "Syntax error"); 619 + return TEP_ERRNO__SYNTAX_ERROR; 620 } 621 622 static struct filter_arg * ··· 629 return arg; 630 } 631 632 + static enum tep_errno add_left(struct filter_arg *op, struct filter_arg *arg) 633 { 634 switch (op->type) { 635 case FILTER_ARG_EXP: ··· 648 /* left arg of compares must be a field */ 649 if (arg->type != FILTER_ARG_FIELD && 650 arg->type != FILTER_ARG_BOOLEAN) 651 + return TEP_ERRNO__INVALID_ARG_TYPE; 652 op->num.left = arg; 653 break; 654 default: 655 + return TEP_ERRNO__INVALID_ARG_TYPE; 656 } 657 return 0; 658 } ··· 765 FILTER_VAL_TRUE, 766 }; 767 768 + static enum tep_errno 769 reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, 770 struct filter_arg *arg, char *error_str) 771 { ··· 775 if (parent->type != FILTER_ARG_OP && 776 arg->type != FILTER_ARG_OP) { 777 show_error(error_str, "can not reparent other than OP"); 778 + return TEP_ERRNO__REPARENT_NOT_OP; 779 } 780 781 /* Get the sibling */ ··· 787 other_child = old_child->op.right; 788 } else { 789 show_error(error_str, "Error in reparent op, find other child"); 790 + return TEP_ERRNO__REPARENT_FAILED; 791 } 792 793 /* Detach arg from old_child */ ··· 808 ptr = &parent->op.left; 809 else { 810 show_error(error_str, "Error in reparent op"); 811 + return TEP_ERRNO__REPARENT_FAILED; 812 } 813 814 *ptr = arg; ··· 817 return 0; 818 } 819 820 + /* Returns either filter_vals (success) or tep_errno (failfure) */ 821 static int test_arg(struct filter_arg *parent, struct filter_arg *arg, 822 char *error_str) 823 { ··· 912 return rval; 913 default: 914 show_error(error_str, "bad arg in filter tree"); 915 + return TEP_ERRNO__BAD_FILTER_ARG; 916 } 917 return FILTER_VAL_NORM; 918 } ··· 937 arg->boolean.value = ret == FILTER_VAL_TRUE; 938 } else { 939 show_error(error_str, "Failed to allocate filter arg"); 940 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 941 } 942 break; 943 ··· 952 return ret; 953 } 954 955 + static enum tep_errno 956 process_filter(struct event_format *event, struct filter_arg **parg, 957 char *error_str, int not) 958 { ··· 966 enum filter_op_type btype; 967 enum filter_exp_type etype; 968 enum filter_cmp_type ctype; 969 + enum tep_errno ret; 970 971 *parg = NULL; 972 ··· 1004 case EVENT_DELIM: 1005 if (*token == ',') { 1006 show_error(error_str, "Illegal token ','"); 1007 + ret = TEP_ERRNO__ILLEGAL_TOKEN; 1008 goto fail; 1009 } 1010 ··· 1012 if (left_item) { 1013 show_error(error_str, 1014 "Open paren can not come after item"); 1015 + ret = TEP_ERRNO__INVALID_PAREN; 1016 goto fail; 1017 } 1018 if (current_exp) { 1019 show_error(error_str, 1020 "Open paren can not come after expression"); 1021 + ret = TEP_ERRNO__INVALID_PAREN; 1022 goto fail; 1023 } 1024 1025 ret = process_filter(event, &arg, error_str, 0); 1026 + if (ret != TEP_ERRNO__UNBALANCED_PAREN) { 1027 if (ret == 0) { 1028 show_error(error_str, 1029 "Unbalanced number of '('"); 1030 + ret = TEP_ERRNO__UNBALANCED_PAREN; 1031 } 1032 goto fail; 1033 } ··· 1064 else 1065 *parg = current_exp; 1066 free(token); 1067 + return TEP_ERRNO__UNBALANCED_PAREN; 1068 } 1069 break; 1070 ··· 1091 case OP_NONE: 1092 show_error(error_str, 1093 "Unknown op token %s", token); 1094 + ret = TEP_ERRNO__UNKNOWN_TOKEN; 1095 goto fail; 1096 } 1097 ··· 1179 1180 fail_alloc: 1181 show_error(error_str, "failed to allocate filter arg"); 1182 + ret = TEP_ERRNO__MEM_ALLOC_FAILED; 1183 goto fail; 1184 fail_syntax: 1185 show_error(error_str, "Syntax error"); 1186 + ret = TEP_ERRNO__SYNTAX_ERROR; 1187 fail: 1188 free_arg(current_op); 1189 free_arg(current_exp); ··· 1192 return ret; 1193 } 1194 1195 + static enum tep_errno 1196 process_event(struct event_format *event, const char *filter_str, 1197 struct filter_arg **parg, char *error_str) 1198 { 1199 int ret; 1200 1201 + tep_buffer_init(filter_str, strlen(filter_str)); 1202 1203 ret = process_filter(event, parg, error_str, 0); 1204 if (ret < 0) ··· 1208 if (!*parg) { 1209 *parg = allocate_arg(); 1210 if (*parg == NULL) 1211 + return TEP_ERRNO__MEM_ALLOC_FAILED; 1212 1213 (*parg)->type = FILTER_ARG_BOOLEAN; 1214 (*parg)->boolean.value = FILTER_FALSE; ··· 1217 return 0; 1218 } 1219 1220 + static enum tep_errno 1221 filter_event(struct event_filter *filter, struct event_format *event, 1222 const char *filter_str, char *error_str) 1223 { 1224 struct filter_type *filter_type; 1225 struct filter_arg *arg; 1226 + enum tep_errno ret; 1227 1228 if (filter_str) { 1229 ret = process_event(event, filter_str, &arg, error_str); ··· 1234 /* just add a TRUE arg */ 1235 arg = allocate_arg(); 1236 if (arg == NULL) 1237 + return TEP_ERRNO__MEM_ALLOC_FAILED; 1238 1239 arg->type = FILTER_ARG_BOOLEAN; 1240 arg->boolean.value = FILTER_TRUE; ··· 1242 1243 filter_type = add_filter_type(filter, event->id); 1244 if (filter_type == NULL) 1245 + return TEP_ERRNO__MEM_ALLOC_FAILED; 1246 1247 if (filter_type->filter) 1248 free_arg(filter_type->filter); ··· 1254 static void filter_init_error_buf(struct event_filter *filter) 1255 { 1256 /* clear buffer to reset show error */ 1257 + tep_buffer_init("", 0); 1258 filter->error_buffer[0] = '\0'; 1259 } 1260 1261 /** 1262 + * tep_filter_add_filter_str - add a new filter 1263 * @filter: the event filter to add to 1264 * @filter_str: the filter string that contains the filter 1265 * 1266 * Returns 0 if the filter was successfully added or a 1267 + * negative error code. Use tep_filter_strerror() to see 1268 * actual error message in case of error. 1269 */ 1270 + enum tep_errno tep_filter_add_filter_str(struct event_filter *filter, 1271 + const char *filter_str) 1272 { 1273 + struct tep_handle *pevent = filter->pevent; 1274 struct event_list *event; 1275 struct event_list *events = NULL; 1276 const char *filter_start; ··· 1279 char *event_name = NULL; 1280 char *sys_name = NULL; 1281 char *sp; 1282 + enum tep_errno rtn = 0; /* TEP_ERRNO__SUCCESS */ 1283 int len; 1284 int ret; 1285 ··· 1305 if (this_event == NULL) { 1306 /* This can only happen when events is NULL, but still */ 1307 free_events(events); 1308 + return TEP_ERRNO__MEM_ALLOC_FAILED; 1309 } 1310 memcpy(this_event, filter_str, len); 1311 this_event[len] = 0; ··· 1322 /* This can only happen when events is NULL, but still */ 1323 free_events(events); 1324 free(this_event); 1325 + return TEP_ERRNO__FILTER_NOT_FOUND; 1326 } 1327 1328 /* Find this event */ ··· 1349 1350 if (ret >= 0 && pevent->test_filters) { 1351 char *test; 1352 + test = tep_filter_make_string(filter, event->event->id); 1353 if (test) { 1354 printf(" '%s: %s'\n", event->event->name, test); 1355 free(test); ··· 1371 } 1372 1373 /** 1374 + * tep_filter_strerror - fill error message in a buffer 1375 * @filter: the event filter contains error 1376 * @err: the error code 1377 * @buf: the buffer to be filled in ··· 1379 * 1380 * Returns 0 if message was filled successfully, -1 if error 1381 */ 1382 + int tep_filter_strerror(struct event_filter *filter, enum tep_errno err, 1383 + char *buf, size_t buflen) 1384 { 1385 + if (err <= __TEP_ERRNO__START || err >= __TEP_ERRNO__END) 1386 return -1; 1387 1388 if (strlen(filter->error_buffer) > 0) { ··· 1393 return 0; 1394 } 1395 1396 + return tep_strerror(filter->pevent, err, buf, buflen); 1397 } 1398 1399 /** 1400 + * tep_filter_remove_event - remove a filter for an event 1401 * @filter: the event filter to remove from 1402 * @event_id: the event to remove a filter for 1403 * ··· 1407 * Returns 1: if an event was removed 1408 * 0: if the event was not found 1409 */ 1410 + int tep_filter_remove_event(struct event_filter *filter, 1411 + int event_id) 1412 { 1413 struct filter_type *filter_type; 1414 unsigned long len; ··· 1437 } 1438 1439 /** 1440 + * tep_filter_reset - clear all filters in a filter 1441 * @filter: the event filter to reset 1442 * 1443 * Removes all filters from a filter and resets it. 1444 */ 1445 + void tep_filter_reset(struct event_filter *filter) 1446 { 1447 int i; 1448 ··· 1454 filter->event_filters = NULL; 1455 } 1456 1457 + void tep_filter_free(struct event_filter *filter) 1458 { 1459 + tep_unref(filter->pevent); 1460 1461 + tep_filter_reset(filter); 1462 1463 free(filter); 1464 } ··· 1478 /* Can't assume that the pevent's are the same */ 1479 sys = filter_type->event->system; 1480 name = filter_type->event->name; 1481 + event = tep_find_event_by_name(filter->pevent, sys, name); 1482 if (!event) 1483 return -1; 1484 ··· 1515 } 1516 1517 /** 1518 + * tep_filter_copy - copy a filter using another filter 1519 * @dest - the filter to copy to 1520 * @source - the filter to copy from 1521 * 1522 * Returns 0 on success and -1 if not all filters were copied 1523 */ 1524 + int tep_filter_copy(struct event_filter *dest, struct event_filter *source) 1525 { 1526 int ret = 0; 1527 int i; 1528 1529 + tep_filter_reset(dest); 1530 1531 for (i = 0; i < source->filters; i++) { 1532 if (copy_filter_type(dest, source, &source->event_filters[i])) ··· 1537 1538 1539 /** 1540 + * tep_update_trivial - update the trivial filters with the given filter 1541 * @dest - the filter to update 1542 * @source - the filter as the source of the update 1543 * @type - the type of trivial filter to update. ··· 1547 * Returns 0 on success and -1 if there was a problem updating, but 1548 * events may have still been updated on error. 1549 */ 1550 + int tep_update_trivial(struct event_filter *dest, struct event_filter *source, 1551 + enum filter_trivial_type type) 1552 { 1553 + struct tep_handle *src_pevent; 1554 + struct tep_handle *dest_pevent; 1555 struct event_format *event; 1556 struct filter_type *filter_type; 1557 struct filter_arg *arg; ··· 1578 1579 if (src_pevent != dest_pevent) { 1580 /* do a look up */ 1581 + event = tep_find_event_by_name(src_pevent, 1582 + event->system, 1583 + event->name); 1584 if (!event) 1585 return -1; 1586 } 1587 1588 + str = tep_filter_make_string(source, event->id); 1589 if (!str) 1590 continue; 1591 ··· 1598 } 1599 1600 /** 1601 + * tep_filter_clear_trivial - clear TRUE and FALSE filters 1602 * @filter: the filter to remove trivial filters from 1603 * @type: remove only true, false, or both 1604 * ··· 1606 * 1607 * Returns 0 on success and -1 if there was a problem. 1608 */ 1609 + int tep_filter_clear_trivial(struct event_filter *filter, 1610 + enum filter_trivial_type type) 1611 { 1612 struct filter_type *filter_type; 1613 int count = 0; ··· 1653 return 0; 1654 1655 for (i = 0; i < count; i++) 1656 + tep_filter_remove_event(filter, ids[i]); 1657 1658 free(ids); 1659 return 0; 1660 } 1661 1662 /** 1663 + * tep_filter_event_has_trivial - return true event contains trivial filter 1664 * @filter: the filter with the information 1665 * @event_id: the id of the event to test 1666 * @type: trivial type to test for (TRUE, FALSE, EITHER) ··· 1668 * Returns 1 if the event contains a matching trivial type 1669 * otherwise 0. 1670 */ 1671 + int tep_filter_event_has_trivial(struct event_filter *filter, 1672 + int event_id, 1673 + enum filter_trivial_type type) 1674 { 1675 struct filter_type *filter_type; 1676 ··· 1697 } 1698 1699 static int test_filter(struct event_format *event, struct filter_arg *arg, 1700 + struct tep_record *record, enum tep_errno *err); 1701 1702 static const char * 1703 + get_comm(struct event_format *event, struct tep_record *record) 1704 { 1705 const char *comm; 1706 int pid; 1707 1708 + pid = tep_data_pid(event->pevent, record); 1709 + comm = tep_data_comm_from_pid(event->pevent, pid); 1710 return comm; 1711 } 1712 1713 static unsigned long long 1714 get_value(struct event_format *event, 1715 + struct format_field *field, struct tep_record *record) 1716 { 1717 unsigned long long val; 1718 ··· 1728 if (field == &cpu) 1729 return record->cpu; 1730 1731 + tep_read_number_field(field, record->data, &val); 1732 1733 if (!(field->flags & FIELD_IS_SIGNED)) 1734 return val; ··· 1748 1749 static unsigned long long 1750 get_arg_value(struct event_format *event, struct filter_arg *arg, 1751 + struct tep_record *record, enum tep_errno *err); 1752 1753 static unsigned long long 1754 get_exp_value(struct event_format *event, struct filter_arg *arg, 1755 + struct tep_record *record, enum tep_errno *err) 1756 { 1757 unsigned long long lval, rval; 1758 ··· 1800 case FILTER_EXP_NOT: 1801 default: 1802 if (!*err) 1803 + *err = TEP_ERRNO__INVALID_EXP_TYPE; 1804 } 1805 return 0; 1806 } 1807 1808 static unsigned long long 1809 get_arg_value(struct event_format *event, struct filter_arg *arg, 1810 + struct tep_record *record, enum tep_errno *err) 1811 { 1812 switch (arg->type) { 1813 case FILTER_ARG_FIELD: ··· 1816 case FILTER_ARG_VALUE: 1817 if (arg->value.type != FILTER_NUMBER) { 1818 if (!*err) 1819 + *err = TEP_ERRNO__NOT_A_NUMBER; 1820 } 1821 return arg->value.val; 1822 ··· 1825 1826 default: 1827 if (!*err) 1828 + *err = TEP_ERRNO__INVALID_ARG_TYPE; 1829 } 1830 return 0; 1831 } 1832 1833 static int test_num(struct event_format *event, struct filter_arg *arg, 1834 + struct tep_record *record, enum tep_errno *err) 1835 { 1836 unsigned long long lval, rval; 1837 ··· 1866 1867 default: 1868 if (!*err) 1869 + *err = TEP_ERRNO__ILLEGAL_INTEGER_CMP; 1870 return 0; 1871 } 1872 } 1873 1874 + static const char *get_field_str(struct filter_arg *arg, struct tep_record *record) 1875 { 1876 struct event_format *event; 1877 + struct tep_handle *pevent; 1878 unsigned long long addr; 1879 const char *val = NULL; 1880 unsigned int size; ··· 1909 1910 if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG)) 1911 /* convert to a kernel symbol */ 1912 + val = tep_find_function(pevent, addr); 1913 1914 if (val == NULL) { 1915 /* just use the hex of the string name */ ··· 1922 } 1923 1924 static int test_str(struct event_format *event, struct filter_arg *arg, 1925 + struct tep_record *record, enum tep_errno *err) 1926 { 1927 const char *val; 1928 ··· 1947 1948 default: 1949 if (!*err) 1950 + *err = TEP_ERRNO__ILLEGAL_STRING_CMP; 1951 return 0; 1952 } 1953 } 1954 1955 static int test_op(struct event_format *event, struct filter_arg *arg, 1956 + struct tep_record *record, enum tep_errno *err) 1957 { 1958 switch (arg->op.type) { 1959 case FILTER_OP_AND: ··· 1969 1970 default: 1971 if (!*err) 1972 + *err = TEP_ERRNO__INVALID_OP_TYPE; 1973 return 0; 1974 } 1975 } 1976 1977 static int test_filter(struct event_format *event, struct filter_arg *arg, 1978 + struct tep_record *record, enum tep_errno *err) 1979 { 1980 if (*err) { 1981 /* ··· 2009 2010 default: 2011 if (!*err) 2012 + *err = TEP_ERRNO__INVALID_ARG_TYPE; 2013 return 0; 2014 } 2015 } 2016 2017 /** 2018 + * tep_event_filtered - return true if event has filter 2019 * @filter: filter struct with filter information 2020 * @event_id: event id to test if filter exists 2021 * 2022 * Returns 1 if filter found for @event_id 2023 * otherwise 0; 2024 */ 2025 + int tep_event_filtered(struct event_filter *filter, int event_id) 2026 { 2027 struct filter_type *filter_type; 2028 ··· 2035 } 2036 2037 /** 2038 + * tep_filter_match - test if a record matches a filter 2039 * @filter: filter struct with filter information 2040 * @record: the record to test against the filter 2041 * 2042 + * Returns: match result or error code (prefixed with TEP_ERRNO__) 2043 * FILTER_MATCH - filter found for event and @record matches 2044 * FILTER_MISS - filter found for event and @record does not match 2045 * FILTER_NOT_FOUND - no filter found for @record's event 2046 * NO_FILTER - if no filters exist 2047 * otherwise - error occurred during test 2048 */ 2049 + enum tep_errno tep_filter_match(struct event_filter *filter, 2050 + struct tep_record *record) 2051 { 2052 + struct tep_handle *pevent = filter->pevent; 2053 struct filter_type *filter_type; 2054 int event_id; 2055 int ret; 2056 + enum tep_errno err = 0; 2057 2058 filter_init_error_buf(filter); 2059 2060 if (!filter->filters) 2061 + return TEP_ERRNO__NO_FILTER; 2062 2063 + event_id = tep_data_type(pevent, record); 2064 2065 filter_type = find_filter_type(filter, event_id); 2066 if (!filter_type) 2067 + return TEP_ERRNO__FILTER_NOT_FOUND; 2068 2069 ret = test_filter(filter_type->event, filter_type->filter, record, &err); 2070 if (err) 2071 return err; 2072 2073 + return ret ? TEP_ERRNO__FILTER_MATCH : TEP_ERRNO__FILTER_MISS; 2074 } 2075 2076 static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) ··· 2364 } 2365 2366 /** 2367 + * tep_filter_make_string - return a string showing the filter 2368 * @filter: filter struct with filter information 2369 * @event_id: the event id to return the filter string with 2370 * ··· 2373 * NULL is returned if no filter is found or allocation failed. 2374 */ 2375 char * 2376 + tep_filter_make_string(struct event_filter *filter, int event_id) 2377 { 2378 struct filter_type *filter_type; 2379 ··· 2389 } 2390 2391 /** 2392 + * tep_filter_compare - compare two filters and return if they are the same 2393 * @filter1: Filter to compare with @filter2 2394 * @filter2: Filter to compare with @filter1 2395 * ··· 2397 * 1 if the two filters hold the same content. 2398 * 0 if they do not. 2399 */ 2400 + int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2) 2401 { 2402 struct filter_type *filter_type1; 2403 struct filter_type *filter_type2;
+1 -15
tools/lib/traceevent/parse-utils.c
··· 1 /* 2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 */ 20 #include <stdio.h> 21 #include <stdlib.h>
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 #include <stdio.h> 7 #include <stdlib.h>
+10 -10
tools/lib/traceevent/plugin_cfg80211.c
··· 25 return val ? (long long) le16toh(*val) : 0; 26 } 27 28 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 29 { 30 - pevent_register_print_function(pevent, 31 - process___le16_to_cpup, 32 - PEVENT_FUNC_ARG_INT, 33 - "__le16_to_cpup", 34 - PEVENT_FUNC_ARG_PTR, 35 - PEVENT_FUNC_ARG_VOID); 36 return 0; 37 } 38 39 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 40 { 41 - pevent_unregister_print_function(pevent, process___le16_to_cpup, 42 - "__le16_to_cpup"); 43 }
··· 25 return val ? (long long) le16toh(*val) : 0; 26 } 27 28 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 29 { 30 + tep_register_print_function(pevent, 31 + process___le16_to_cpup, 32 + TEP_FUNC_ARG_INT, 33 + "__le16_to_cpup", 34 + TEP_FUNC_ARG_PTR, 35 + TEP_FUNC_ARG_VOID); 36 return 0; 37 } 38 39 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 40 { 41 + tep_unregister_print_function(pevent, process___le16_to_cpup, 42 + "__le16_to_cpup"); 43 }
+17 -17
tools/lib/traceevent/plugin_function.c
··· 33 34 #define STK_BLK 10 35 36 - struct pevent_plugin_option plugin_options[] = 37 { 38 { 39 .name = "parent", ··· 53 } 54 }; 55 56 - static struct pevent_plugin_option *ftrace_parent = &plugin_options[0]; 57 - static struct pevent_plugin_option *ftrace_indent = &plugin_options[1]; 58 59 static void add_child(struct func_stack *stack, const char *child, int pos) 60 { ··· 122 return 0; 123 } 124 125 - static int function_handler(struct trace_seq *s, struct pevent_record *record, 126 struct event_format *event, void *context) 127 { 128 - struct pevent *pevent = event->pevent; 129 unsigned long long function; 130 unsigned long long pfunction; 131 const char *func; 132 const char *parent; 133 int index = 0; 134 135 - if (pevent_get_field_val(s, event, "ip", record, &function, 1)) 136 return trace_seq_putc(s, '!'); 137 138 - func = pevent_find_function(pevent, function); 139 140 - if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) 141 return trace_seq_putc(s, '!'); 142 143 - parent = pevent_find_function(pevent, pfunction); 144 145 if (parent && ftrace_indent->set) 146 index = add_and_get_index(parent, func, record->cpu); ··· 163 return 0; 164 } 165 166 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 167 { 168 - pevent_register_event_handler(pevent, -1, "ftrace", "function", 169 - function_handler, NULL); 170 171 - traceevent_plugin_add_options("ftrace", plugin_options); 172 173 return 0; 174 } 175 176 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 177 { 178 int i, x; 179 180 - pevent_unregister_event_handler(pevent, -1, "ftrace", "function", 181 - function_handler, NULL); 182 183 for (i = 0; i <= cpus; i++) { 184 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) ··· 186 free(fstack[i].stack); 187 } 188 189 - traceevent_plugin_remove_options(plugin_options); 190 191 free(fstack); 192 fstack = NULL;
··· 33 34 #define STK_BLK 10 35 36 + struct tep_plugin_option plugin_options[] = 37 { 38 { 39 .name = "parent", ··· 53 } 54 }; 55 56 + static struct tep_plugin_option *ftrace_parent = &plugin_options[0]; 57 + static struct tep_plugin_option *ftrace_indent = &plugin_options[1]; 58 59 static void add_child(struct func_stack *stack, const char *child, int pos) 60 { ··· 122 return 0; 123 } 124 125 + static int function_handler(struct trace_seq *s, struct tep_record *record, 126 struct event_format *event, void *context) 127 { 128 + struct tep_handle *pevent = event->pevent; 129 unsigned long long function; 130 unsigned long long pfunction; 131 const char *func; 132 const char *parent; 133 int index = 0; 134 135 + if (tep_get_field_val(s, event, "ip", record, &function, 1)) 136 return trace_seq_putc(s, '!'); 137 138 + func = tep_find_function(pevent, function); 139 140 + if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) 141 return trace_seq_putc(s, '!'); 142 143 + parent = tep_find_function(pevent, pfunction); 144 145 if (parent && ftrace_indent->set) 146 index = add_and_get_index(parent, func, record->cpu); ··· 163 return 0; 164 } 165 166 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 167 { 168 + tep_register_event_handler(pevent, -1, "ftrace", "function", 169 + function_handler, NULL); 170 171 + tep_plugin_add_options("ftrace", plugin_options); 172 173 return 0; 174 } 175 176 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 177 { 178 int i, x; 179 180 + tep_unregister_event_handler(pevent, -1, "ftrace", "function", 181 + function_handler, NULL); 182 183 for (i = 0; i <= cpus; i++) { 184 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) ··· 186 free(fstack[i].stack); 187 } 188 189 + tep_plugin_remove_options(plugin_options); 190 191 free(fstack); 192 fstack = NULL;
+28 -28
tools/lib/traceevent/plugin_hrtimer.c
··· 25 #include "event-parse.h" 26 27 static int timer_expire_handler(struct trace_seq *s, 28 - struct pevent_record *record, 29 struct event_format *event, void *context) 30 { 31 trace_seq_printf(s, "hrtimer="); 32 33 - if (pevent_print_num_field(s, "0x%llx", event, "timer", 34 - record, 0) == -1) 35 - pevent_print_num_field(s, "0x%llx", event, "hrtimer", 36 - record, 1); 37 38 trace_seq_printf(s, " now="); 39 40 - pevent_print_num_field(s, "%llu", event, "now", record, 1); 41 42 - pevent_print_func_field(s, " function=%s", event, "function", 43 record, 0); 44 return 0; 45 } 46 47 static int timer_start_handler(struct trace_seq *s, 48 - struct pevent_record *record, 49 struct event_format *event, void *context) 50 { 51 trace_seq_printf(s, "hrtimer="); 52 53 - if (pevent_print_num_field(s, "0x%llx", event, "timer", 54 - record, 0) == -1) 55 - pevent_print_num_field(s, "0x%llx", event, "hrtimer", 56 - record, 1); 57 58 - pevent_print_func_field(s, " function=%s", event, "function", 59 - record, 0); 60 61 trace_seq_printf(s, " expires="); 62 - pevent_print_num_field(s, "%llu", event, "expires", record, 1); 63 64 trace_seq_printf(s, " softexpires="); 65 - pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); 66 return 0; 67 } 68 69 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 70 { 71 - pevent_register_event_handler(pevent, -1, 72 - "timer", "hrtimer_expire_entry", 73 - timer_expire_handler, NULL); 74 75 - pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", 76 - timer_start_handler, NULL); 77 return 0; 78 } 79 80 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 81 { 82 - pevent_unregister_event_handler(pevent, -1, 83 - "timer", "hrtimer_expire_entry", 84 - timer_expire_handler, NULL); 85 86 - pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", 87 - timer_start_handler, NULL); 88 }
··· 25 #include "event-parse.h" 26 27 static int timer_expire_handler(struct trace_seq *s, 28 + struct tep_record *record, 29 struct event_format *event, void *context) 30 { 31 trace_seq_printf(s, "hrtimer="); 32 33 + if (tep_print_num_field(s, "0x%llx", event, "timer", 34 + record, 0) == -1) 35 + tep_print_num_field(s, "0x%llx", event, "hrtimer", 36 + record, 1); 37 38 trace_seq_printf(s, " now="); 39 40 + tep_print_num_field(s, "%llu", event, "now", record, 1); 41 42 + tep_print_func_field(s, " function=%s", event, "function", 43 record, 0); 44 return 0; 45 } 46 47 static int timer_start_handler(struct trace_seq *s, 48 + struct tep_record *record, 49 struct event_format *event, void *context) 50 { 51 trace_seq_printf(s, "hrtimer="); 52 53 + if (tep_print_num_field(s, "0x%llx", event, "timer", 54 + record, 0) == -1) 55 + tep_print_num_field(s, "0x%llx", event, "hrtimer", 56 + record, 1); 57 58 + tep_print_func_field(s, " function=%s", event, "function", 59 + record, 0); 60 61 trace_seq_printf(s, " expires="); 62 + tep_print_num_field(s, "%llu", event, "expires", record, 1); 63 64 trace_seq_printf(s, " softexpires="); 65 + tep_print_num_field(s, "%llu", event, "softexpires", record, 1); 66 return 0; 67 } 68 69 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 70 { 71 + tep_register_event_handler(pevent, -1, 72 + "timer", "hrtimer_expire_entry", 73 + timer_expire_handler, NULL); 74 75 + tep_register_event_handler(pevent, -1, "timer", "hrtimer_start", 76 + timer_start_handler, NULL); 77 return 0; 78 } 79 80 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 81 { 82 + tep_unregister_event_handler(pevent, -1, 83 + "timer", "hrtimer_expire_entry", 84 + timer_expire_handler, NULL); 85 86 + tep_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", 87 + timer_start_handler, NULL); 88 }
+18 -18
tools/lib/traceevent/plugin_jbd2.c
··· 47 return jiffies; 48 } 49 50 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 51 { 52 - pevent_register_print_function(pevent, 53 - process_jbd2_dev_to_name, 54 - PEVENT_FUNC_ARG_STRING, 55 - "jbd2_dev_to_name", 56 - PEVENT_FUNC_ARG_INT, 57 - PEVENT_FUNC_ARG_VOID); 58 59 - pevent_register_print_function(pevent, 60 - process_jiffies_to_msecs, 61 - PEVENT_FUNC_ARG_LONG, 62 - "jiffies_to_msecs", 63 - PEVENT_FUNC_ARG_LONG, 64 - PEVENT_FUNC_ARG_VOID); 65 return 0; 66 } 67 68 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 69 { 70 - pevent_unregister_print_function(pevent, process_jbd2_dev_to_name, 71 - "jbd2_dev_to_name"); 72 73 - pevent_unregister_print_function(pevent, process_jiffies_to_msecs, 74 - "jiffies_to_msecs"); 75 }
··· 47 return jiffies; 48 } 49 50 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 51 { 52 + tep_register_print_function(pevent, 53 + process_jbd2_dev_to_name, 54 + TEP_FUNC_ARG_STRING, 55 + "jbd2_dev_to_name", 56 + TEP_FUNC_ARG_INT, 57 + TEP_FUNC_ARG_VOID); 58 59 + tep_register_print_function(pevent, 60 + process_jiffies_to_msecs, 61 + TEP_FUNC_ARG_LONG, 62 + "jiffies_to_msecs", 63 + TEP_FUNC_ARG_LONG, 64 + TEP_FUNC_ARG_VOID); 65 return 0; 66 } 67 68 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 69 { 70 + tep_unregister_print_function(pevent, process_jbd2_dev_to_name, 71 + "jbd2_dev_to_name"); 72 73 + tep_unregister_print_function(pevent, process_jiffies_to_msecs, 74 + "jiffies_to_msecs"); 75 }
+33 -33
tools/lib/traceevent/plugin_kmem.c
··· 23 24 #include "event-parse.h" 25 26 - static int call_site_handler(struct trace_seq *s, struct pevent_record *record, 27 struct event_format *event, void *context) 28 { 29 struct format_field *field; ··· 31 void *data = record->data; 32 const char *func; 33 34 - field = pevent_find_field(event, "call_site"); 35 if (!field) 36 return 1; 37 38 - if (pevent_read_number_field(field, data, &val)) 39 return 1; 40 41 - func = pevent_find_function(event->pevent, val); 42 if (!func) 43 return 1; 44 45 - addr = pevent_find_function_address(event->pevent, val); 46 47 trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); 48 return 1; 49 } 50 51 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 52 { 53 - pevent_register_event_handler(pevent, -1, "kmem", "kfree", 54 - call_site_handler, NULL); 55 56 - pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", 57 - call_site_handler, NULL); 58 59 - pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", 60 - call_site_handler, NULL); 61 62 - pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", 63 - call_site_handler, NULL); 64 65 - pevent_register_event_handler(pevent, -1, "kmem", 66 - "kmem_cache_alloc_node", 67 - call_site_handler, NULL); 68 69 - pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", 70 - call_site_handler, NULL); 71 return 0; 72 } 73 74 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 75 { 76 - pevent_unregister_event_handler(pevent, -1, "kmem", "kfree", 77 - call_site_handler, NULL); 78 79 - pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc", 80 - call_site_handler, NULL); 81 82 - pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", 83 - call_site_handler, NULL); 84 85 - pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", 86 - call_site_handler, NULL); 87 88 - pevent_unregister_event_handler(pevent, -1, "kmem", 89 - "kmem_cache_alloc_node", 90 - call_site_handler, NULL); 91 92 - pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", 93 - call_site_handler, NULL); 94 }
··· 23 24 #include "event-parse.h" 25 26 + static int call_site_handler(struct trace_seq *s, struct tep_record *record, 27 struct event_format *event, void *context) 28 { 29 struct format_field *field; ··· 31 void *data = record->data; 32 const char *func; 33 34 + field = tep_find_field(event, "call_site"); 35 if (!field) 36 return 1; 37 38 + if (tep_read_number_field(field, data, &val)) 39 return 1; 40 41 + func = tep_find_function(event->pevent, val); 42 if (!func) 43 return 1; 44 45 + addr = tep_find_function_address(event->pevent, val); 46 47 trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); 48 return 1; 49 } 50 51 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 52 { 53 + tep_register_event_handler(pevent, -1, "kmem", "kfree", 54 + call_site_handler, NULL); 55 56 + tep_register_event_handler(pevent, -1, "kmem", "kmalloc", 57 + call_site_handler, NULL); 58 59 + tep_register_event_handler(pevent, -1, "kmem", "kmalloc_node", 60 + call_site_handler, NULL); 61 62 + tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", 63 + call_site_handler, NULL); 64 65 + tep_register_event_handler(pevent, -1, "kmem", 66 + "kmem_cache_alloc_node", 67 + call_site_handler, NULL); 68 69 + tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", 70 + call_site_handler, NULL); 71 return 0; 72 } 73 74 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 75 { 76 + tep_unregister_event_handler(pevent, -1, "kmem", "kfree", 77 + call_site_handler, NULL); 78 79 + tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc", 80 + call_site_handler, NULL); 81 82 + tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", 83 + call_site_handler, NULL); 84 85 + tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", 86 + call_site_handler, NULL); 87 88 + tep_unregister_event_handler(pevent, -1, "kmem", 89 + "kmem_cache_alloc_node", 90 + call_site_handler, NULL); 91 92 + tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", 93 + call_site_handler, NULL); 94 }
+77 -77
tools/lib/traceevent/plugin_kvm.c
··· 247 return strings[i].str; 248 } 249 250 - static int print_exit_reason(struct trace_seq *s, struct pevent_record *record, 251 struct event_format *event, const char *field) 252 { 253 unsigned long long isa; 254 unsigned long long val; 255 const char *reason; 256 257 - if (pevent_get_field_val(s, event, field, record, &val, 1) < 0) 258 return -1; 259 260 - if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) 261 isa = 1; 262 263 reason = find_exit_reason(isa, val); ··· 268 return 0; 269 } 270 271 - static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, 272 struct event_format *event, void *context) 273 { 274 unsigned long long info1 = 0, info2 = 0; ··· 276 if (print_exit_reason(s, record, event, "exit_reason") < 0) 277 return -1; 278 279 - pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); 280 281 - if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 282 - && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) 283 trace_seq_printf(s, " info %llx %llx", info1, info2); 284 285 return 0; ··· 291 #define KVM_EMUL_INSN_F_CS_L (1 << 3) 292 293 static int kvm_emulate_insn_handler(struct trace_seq *s, 294 - struct pevent_record *record, 295 struct event_format *event, void *context) 296 { 297 unsigned long long rip, csbase, len, flags, failed; ··· 299 uint8_t *insn; 300 const char *disasm; 301 302 - if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) 303 return -1; 304 305 - if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) 306 return -1; 307 308 - if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) 309 return -1; 310 311 - if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) 312 return -1; 313 314 - if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) 315 return -1; 316 317 - insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); 318 if (!insn) 319 return -1; 320 ··· 330 } 331 332 333 - static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record, 334 struct event_format *event, void *context) 335 { 336 if (print_exit_reason(s, record, event, "exit_code") < 0) 337 return -1; 338 339 - pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1); 340 - pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1); 341 - pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1); 342 - pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1); 343 344 return 0; 345 } 346 347 - static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record, 348 struct event_format *event, void *context) 349 { 350 - pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1); 351 352 return kvm_nested_vmexit_inject_handler(s, record, event, context); 353 } ··· 370 }; 371 }; 372 373 - static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, 374 struct event_format *event, void *context) 375 { 376 unsigned long long val; ··· 379 }; 380 union kvm_mmu_page_role role; 381 382 - if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) 383 return -1; 384 385 role.word = (int)val; ··· 388 * We can only use the structure if file is of the same 389 * endianess. 390 */ 391 - if (pevent_is_file_bigendian(event->pevent) == 392 - pevent_is_host_bigendian(event->pevent)) { 393 394 trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", 395 role.level, ··· 406 } else 407 trace_seq_printf(s, "WORD: %08x", role.word); 408 409 - pevent_print_num_field(s, " root %u ", event, 410 - "root_count", record, 1); 411 412 - if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) 413 return -1; 414 415 trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); ··· 417 } 418 419 static int kvm_mmu_get_page_handler(struct trace_seq *s, 420 - struct pevent_record *record, 421 struct event_format *event, void *context) 422 { 423 unsigned long long val; 424 425 - if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) 426 return -1; 427 428 trace_seq_printf(s, "%s ", val ? "new" : "existing"); 429 430 - if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) 431 return -1; 432 433 trace_seq_printf(s, "sp gfn %llx ", val); ··· 444 return pte & PT_WRITABLE_MASK; 445 } 446 447 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 448 { 449 init_disassembler(); 450 451 - pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", 452 - kvm_exit_handler, NULL); 453 454 - pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 455 - kvm_emulate_insn_handler, NULL); 456 457 - pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 458 - kvm_nested_vmexit_handler, NULL); 459 460 - pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 461 - kvm_nested_vmexit_inject_handler, NULL); 462 463 - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 464 - kvm_mmu_get_page_handler, NULL); 465 466 - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", 467 - kvm_mmu_print_role, NULL); 468 469 - pevent_register_event_handler(pevent, -1, 470 - "kvmmmu", "kvm_mmu_unsync_page", 471 - kvm_mmu_print_role, NULL); 472 473 - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", 474 - kvm_mmu_print_role, NULL); 475 476 - pevent_register_event_handler(pevent, -1, "kvmmmu", 477 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, 478 NULL); 479 480 - pevent_register_print_function(pevent, 481 - process_is_writable_pte, 482 - PEVENT_FUNC_ARG_INT, 483 - "is_writable_pte", 484 - PEVENT_FUNC_ARG_LONG, 485 - PEVENT_FUNC_ARG_VOID); 486 return 0; 487 } 488 489 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 490 { 491 - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", 492 - kvm_exit_handler, NULL); 493 494 - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 495 - kvm_emulate_insn_handler, NULL); 496 497 - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 498 - kvm_nested_vmexit_handler, NULL); 499 500 - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 501 - kvm_nested_vmexit_inject_handler, NULL); 502 503 - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 504 - kvm_mmu_get_page_handler, NULL); 505 506 - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", 507 - kvm_mmu_print_role, NULL); 508 509 - pevent_unregister_event_handler(pevent, -1, 510 - "kvmmmu", "kvm_mmu_unsync_page", 511 - kvm_mmu_print_role, NULL); 512 513 - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", 514 - kvm_mmu_print_role, NULL); 515 516 - pevent_unregister_event_handler(pevent, -1, "kvmmmu", 517 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, 518 NULL); 519 520 - pevent_unregister_print_function(pevent, process_is_writable_pte, 521 - "is_writable_pte"); 522 }
··· 247 return strings[i].str; 248 } 249 250 + static int print_exit_reason(struct trace_seq *s, struct tep_record *record, 251 struct event_format *event, const char *field) 252 { 253 unsigned long long isa; 254 unsigned long long val; 255 const char *reason; 256 257 + if (tep_get_field_val(s, event, field, record, &val, 1) < 0) 258 return -1; 259 260 + if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0) 261 isa = 1; 262 263 reason = find_exit_reason(isa, val); ··· 268 return 0; 269 } 270 271 + static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record, 272 struct event_format *event, void *context) 273 { 274 unsigned long long info1 = 0, info2 = 0; ··· 276 if (print_exit_reason(s, record, event, "exit_reason") < 0) 277 return -1; 278 279 + tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); 280 281 + if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0 282 + && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0) 283 trace_seq_printf(s, " info %llx %llx", info1, info2); 284 285 return 0; ··· 291 #define KVM_EMUL_INSN_F_CS_L (1 << 3) 292 293 static int kvm_emulate_insn_handler(struct trace_seq *s, 294 + struct tep_record *record, 295 struct event_format *event, void *context) 296 { 297 unsigned long long rip, csbase, len, flags, failed; ··· 299 uint8_t *insn; 300 const char *disasm; 301 302 + if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0) 303 return -1; 304 305 + if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) 306 return -1; 307 308 + if (tep_get_field_val(s, event, "len", record, &len, 1) < 0) 309 return -1; 310 311 + if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0) 312 return -1; 313 314 + if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0) 315 return -1; 316 317 + insn = tep_get_field_raw(s, event, "insn", record, &llen, 1); 318 if (!insn) 319 return -1; 320 ··· 330 } 331 332 333 + static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record, 334 struct event_format *event, void *context) 335 { 336 if (print_exit_reason(s, record, event, "exit_code") < 0) 337 return -1; 338 339 + tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1); 340 + tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1); 341 + tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1); 342 + tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1); 343 344 return 0; 345 } 346 347 + static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record, 348 struct event_format *event, void *context) 349 { 350 + tep_print_num_field(s, "rip %llx ", event, "rip", record, 1); 351 352 return kvm_nested_vmexit_inject_handler(s, record, event, context); 353 } ··· 370 }; 371 }; 372 373 + static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record, 374 struct event_format *event, void *context) 375 { 376 unsigned long long val; ··· 379 }; 380 union kvm_mmu_page_role role; 381 382 + if (tep_get_field_val(s, event, "role", record, &val, 1) < 0) 383 return -1; 384 385 role.word = (int)val; ··· 388 * We can only use the structure if file is of the same 389 * endianess. 390 */ 391 + if (tep_is_file_bigendian(event->pevent) == 392 + tep_is_host_bigendian(event->pevent)) { 393 394 trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", 395 role.level, ··· 406 } else 407 trace_seq_printf(s, "WORD: %08x", role.word); 408 409 + tep_print_num_field(s, " root %u ", event, 410 + "root_count", record, 1); 411 412 + if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0) 413 return -1; 414 415 trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); ··· 417 } 418 419 static int kvm_mmu_get_page_handler(struct trace_seq *s, 420 + struct tep_record *record, 421 struct event_format *event, void *context) 422 { 423 unsigned long long val; 424 425 + if (tep_get_field_val(s, event, "created", record, &val, 1) < 0) 426 return -1; 427 428 trace_seq_printf(s, "%s ", val ? "new" : "existing"); 429 430 + if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0) 431 return -1; 432 433 trace_seq_printf(s, "sp gfn %llx ", val); ··· 444 return pte & PT_WRITABLE_MASK; 445 } 446 447 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 448 { 449 init_disassembler(); 450 451 + tep_register_event_handler(pevent, -1, "kvm", "kvm_exit", 452 + kvm_exit_handler, NULL); 453 454 + tep_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 455 + kvm_emulate_insn_handler, NULL); 456 457 + tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 458 + kvm_nested_vmexit_handler, NULL); 459 460 + tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 461 + kvm_nested_vmexit_inject_handler, NULL); 462 463 + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 464 + kvm_mmu_get_page_handler, NULL); 465 466 + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", 467 + kvm_mmu_print_role, NULL); 468 469 + tep_register_event_handler(pevent, -1, 470 + "kvmmmu", "kvm_mmu_unsync_page", 471 + kvm_mmu_print_role, NULL); 472 473 + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", 474 + kvm_mmu_print_role, NULL); 475 476 + tep_register_event_handler(pevent, -1, "kvmmmu", 477 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, 478 NULL); 479 480 + tep_register_print_function(pevent, 481 + process_is_writable_pte, 482 + TEP_FUNC_ARG_INT, 483 + "is_writable_pte", 484 + TEP_FUNC_ARG_LONG, 485 + TEP_FUNC_ARG_VOID); 486 return 0; 487 } 488 489 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 490 { 491 + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", 492 + kvm_exit_handler, NULL); 493 494 + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 495 + kvm_emulate_insn_handler, NULL); 496 497 + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 498 + kvm_nested_vmexit_handler, NULL); 499 500 + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 501 + kvm_nested_vmexit_inject_handler, NULL); 502 503 + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 504 + kvm_mmu_get_page_handler, NULL); 505 506 + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", 507 + kvm_mmu_print_role, NULL); 508 509 + tep_unregister_event_handler(pevent, -1, 510 + "kvmmmu", "kvm_mmu_unsync_page", 511 + kvm_mmu_print_role, NULL); 512 513 + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", 514 + kvm_mmu_print_role, NULL); 515 516 + tep_unregister_event_handler(pevent, -1, "kvmmmu", 517 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, 518 NULL); 519 520 + tep_unregister_print_function(pevent, process_is_writable_pte, 521 + "is_writable_pte"); 522 }
+14 -14
tools/lib/traceevent/plugin_mac80211.c
··· 28 static void print_string(struct trace_seq *s, struct event_format *event, 29 const char *name, const void *data) 30 { 31 - struct format_field *f = pevent_find_field(event, name); 32 int offset; 33 int length; 34 ··· 42 43 if (!strncmp(f->type, "__data_loc", 10)) { 44 unsigned long long v; 45 - if (pevent_read_number_field(f, data, &v)) { 46 trace_seq_printf(s, "invalid_data_loc"); 47 return; 48 } ··· 53 trace_seq_printf(s, "%.*s", length, (char *)data + offset); 54 } 55 56 - #define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) 57 - #define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) 58 #define SP() trace_seq_putc(s, ' ') 59 60 static int drv_bss_info_changed(struct trace_seq *s, 61 - struct pevent_record *record, 62 struct event_format *event, void *context) 63 { 64 void *data = record->data; ··· 66 print_string(s, event, "wiphy_name", data); 67 trace_seq_printf(s, " vif:"); 68 print_string(s, event, "vif_name", data); 69 - pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); 70 71 trace_seq_printf(s, "\n%*s", INDENT, ""); 72 SF("assoc"); SP(); ··· 86 return 0; 87 } 88 89 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 90 { 91 - pevent_register_event_handler(pevent, -1, "mac80211", 92 - "drv_bss_info_changed", 93 - drv_bss_info_changed, NULL); 94 return 0; 95 } 96 97 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 98 { 99 - pevent_unregister_event_handler(pevent, -1, "mac80211", 100 - "drv_bss_info_changed", 101 - drv_bss_info_changed, NULL); 102 }
··· 28 static void print_string(struct trace_seq *s, struct event_format *event, 29 const char *name, const void *data) 30 { 31 + struct format_field *f = tep_find_field(event, name); 32 int offset; 33 int length; 34 ··· 42 43 if (!strncmp(f->type, "__data_loc", 10)) { 44 unsigned long long v; 45 + if (tep_read_number_field(f, data, &v)) { 46 trace_seq_printf(s, "invalid_data_loc"); 47 return; 48 } ··· 53 trace_seq_printf(s, "%.*s", length, (char *)data + offset); 54 } 55 56 + #define SF(fn) tep_print_num_field(s, fn ":%d", event, fn, record, 0) 57 + #define SFX(fn) tep_print_num_field(s, fn ":%#x", event, fn, record, 0) 58 #define SP() trace_seq_putc(s, ' ') 59 60 static int drv_bss_info_changed(struct trace_seq *s, 61 + struct tep_record *record, 62 struct event_format *event, void *context) 63 { 64 void *data = record->data; ··· 66 print_string(s, event, "wiphy_name", data); 67 trace_seq_printf(s, " vif:"); 68 print_string(s, event, "vif_name", data); 69 + tep_print_num_field(s, "(%d)", event, "vif_type", record, 1); 70 71 trace_seq_printf(s, "\n%*s", INDENT, ""); 72 SF("assoc"); SP(); ··· 86 return 0; 87 } 88 89 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 90 { 91 + tep_register_event_handler(pevent, -1, "mac80211", 92 + "drv_bss_info_changed", 93 + drv_bss_info_changed, NULL); 94 return 0; 95 } 96 97 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 98 { 99 + tep_unregister_event_handler(pevent, -1, "mac80211", 100 + "drv_bss_info_changed", 101 + drv_bss_info_changed, NULL); 102 }
+30 -30
tools/lib/traceevent/plugin_sched_switch.c
··· 45 } 46 47 static void write_and_save_comm(struct format_field *field, 48 - struct pevent_record *record, 49 struct trace_seq *s, int pid) 50 { 51 const char *comm; ··· 61 comm = &s->buffer[len]; 62 63 /* Help out the comm to ids. This will handle dups */ 64 - pevent_register_comm(field->event->pevent, comm, pid); 65 } 66 67 static int sched_wakeup_handler(struct trace_seq *s, 68 - struct pevent_record *record, 69 struct event_format *event, void *context) 70 { 71 struct format_field *field; 72 unsigned long long val; 73 74 - if (pevent_get_field_val(s, event, "pid", record, &val, 1)) 75 return trace_seq_putc(s, '!'); 76 77 - field = pevent_find_any_field(event, "comm"); 78 if (field) { 79 write_and_save_comm(field, record, s, val); 80 trace_seq_putc(s, ':'); 81 } 82 trace_seq_printf(s, "%lld", val); 83 84 - if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) 85 trace_seq_printf(s, " [%lld]", val); 86 87 - if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) 88 trace_seq_printf(s, " success=%lld", val); 89 90 - if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) 91 trace_seq_printf(s, " CPU:%03llu", val); 92 93 return 0; 94 } 95 96 static int sched_switch_handler(struct trace_seq *s, 97 - struct pevent_record *record, 98 struct event_format *event, void *context) 99 { 100 struct format_field *field; 101 unsigned long long val; 102 103 - if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) 104 return trace_seq_putc(s, '!'); 105 106 - field = pevent_find_any_field(event, "prev_comm"); 107 if (field) { 108 write_and_save_comm(field, record, s, val); 109 trace_seq_putc(s, ':'); 110 } 111 trace_seq_printf(s, "%lld ", val); 112 113 - if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) 114 trace_seq_printf(s, "[%d] ", (int) val); 115 116 - if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) 117 write_state(s, val); 118 119 trace_seq_puts(s, " ==> "); 120 121 - if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) 122 return trace_seq_putc(s, '!'); 123 124 - field = pevent_find_any_field(event, "next_comm"); 125 if (field) { 126 write_and_save_comm(field, record, s, val); 127 trace_seq_putc(s, ':'); 128 } 129 trace_seq_printf(s, "%lld", val); 130 131 - if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) 132 trace_seq_printf(s, " [%d]", (int) val); 133 134 return 0; 135 } 136 137 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 138 { 139 - pevent_register_event_handler(pevent, -1, "sched", "sched_switch", 140 - sched_switch_handler, NULL); 141 142 - pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", 143 - sched_wakeup_handler, NULL); 144 145 - pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", 146 - sched_wakeup_handler, NULL); 147 return 0; 148 } 149 150 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 151 { 152 - pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch", 153 - sched_switch_handler, NULL); 154 155 - pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", 156 - sched_wakeup_handler, NULL); 157 158 - pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", 159 - sched_wakeup_handler, NULL); 160 }
··· 45 } 46 47 static void write_and_save_comm(struct format_field *field, 48 + struct tep_record *record, 49 struct trace_seq *s, int pid) 50 { 51 const char *comm; ··· 61 comm = &s->buffer[len]; 62 63 /* Help out the comm to ids. This will handle dups */ 64 + tep_register_comm(field->event->pevent, comm, pid); 65 } 66 67 static int sched_wakeup_handler(struct trace_seq *s, 68 + struct tep_record *record, 69 struct event_format *event, void *context) 70 { 71 struct format_field *field; 72 unsigned long long val; 73 74 + if (tep_get_field_val(s, event, "pid", record, &val, 1)) 75 return trace_seq_putc(s, '!'); 76 77 + field = tep_find_any_field(event, "comm"); 78 if (field) { 79 write_and_save_comm(field, record, s, val); 80 trace_seq_putc(s, ':'); 81 } 82 trace_seq_printf(s, "%lld", val); 83 84 + if (tep_get_field_val(s, event, "prio", record, &val, 0) == 0) 85 trace_seq_printf(s, " [%lld]", val); 86 87 + if (tep_get_field_val(s, event, "success", record, &val, 1) == 0) 88 trace_seq_printf(s, " success=%lld", val); 89 90 + if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) 91 trace_seq_printf(s, " CPU:%03llu", val); 92 93 return 0; 94 } 95 96 static int sched_switch_handler(struct trace_seq *s, 97 + struct tep_record *record, 98 struct event_format *event, void *context) 99 { 100 struct format_field *field; 101 unsigned long long val; 102 103 + if (tep_get_field_val(s, event, "prev_pid", record, &val, 1)) 104 return trace_seq_putc(s, '!'); 105 106 + field = tep_find_any_field(event, "prev_comm"); 107 if (field) { 108 write_and_save_comm(field, record, s, val); 109 trace_seq_putc(s, ':'); 110 } 111 trace_seq_printf(s, "%lld ", val); 112 113 + if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) 114 trace_seq_printf(s, "[%d] ", (int) val); 115 116 + if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0) 117 write_state(s, val); 118 119 trace_seq_puts(s, " ==> "); 120 121 + if (tep_get_field_val(s, event, "next_pid", record, &val, 1)) 122 return trace_seq_putc(s, '!'); 123 124 + field = tep_find_any_field(event, "next_comm"); 125 if (field) { 126 write_and_save_comm(field, record, s, val); 127 trace_seq_putc(s, ':'); 128 } 129 trace_seq_printf(s, "%lld", val); 130 131 + if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0) 132 trace_seq_printf(s, " [%d]", (int) val); 133 134 return 0; 135 } 136 137 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 138 { 139 + tep_register_event_handler(pevent, -1, "sched", "sched_switch", 140 + sched_switch_handler, NULL); 141 142 + tep_register_event_handler(pevent, -1, "sched", "sched_wakeup", 143 + sched_wakeup_handler, NULL); 144 145 + tep_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", 146 + sched_wakeup_handler, NULL); 147 return 0; 148 } 149 150 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 151 { 152 + tep_unregister_event_handler(pevent, -1, "sched", "sched_switch", 153 + sched_switch_handler, NULL); 154 155 + tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", 156 + sched_wakeup_handler, NULL); 157 158 + tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", 159 + sched_wakeup_handler, NULL); 160 }
+12 -12
tools/lib/traceevent/plugin_scsi.c
··· 413 return 0; 414 } 415 416 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 417 { 418 - pevent_register_print_function(pevent, 419 - process_scsi_trace_parse_cdb, 420 - PEVENT_FUNC_ARG_STRING, 421 - "scsi_trace_parse_cdb", 422 - PEVENT_FUNC_ARG_PTR, 423 - PEVENT_FUNC_ARG_PTR, 424 - PEVENT_FUNC_ARG_INT, 425 - PEVENT_FUNC_ARG_VOID); 426 return 0; 427 } 428 429 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 430 { 431 - pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb, 432 - "scsi_trace_parse_cdb"); 433 }
··· 413 return 0; 414 } 415 416 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 417 { 418 + tep_register_print_function(pevent, 419 + process_scsi_trace_parse_cdb, 420 + TEP_FUNC_ARG_STRING, 421 + "scsi_trace_parse_cdb", 422 + TEP_FUNC_ARG_PTR, 423 + TEP_FUNC_ARG_PTR, 424 + TEP_FUNC_ARG_INT, 425 + TEP_FUNC_ARG_VOID); 426 return 0; 427 } 428 429 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 430 { 431 + tep_unregister_print_function(pevent, process_scsi_trace_parse_cdb, 432 + "scsi_trace_parse_cdb"); 433 }
+10 -10
tools/lib/traceevent/plugin_xen.c
··· 119 return 0; 120 } 121 122 - int PEVENT_PLUGIN_LOADER(struct pevent *pevent) 123 { 124 - pevent_register_print_function(pevent, 125 - process_xen_hypercall_name, 126 - PEVENT_FUNC_ARG_STRING, 127 - "xen_hypercall_name", 128 - PEVENT_FUNC_ARG_INT, 129 - PEVENT_FUNC_ARG_VOID); 130 return 0; 131 } 132 133 - void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) 134 { 135 - pevent_unregister_print_function(pevent, process_xen_hypercall_name, 136 - "xen_hypercall_name"); 137 }
··· 119 return 0; 120 } 121 122 + int TEP_PLUGIN_LOADER(struct tep_handle *pevent) 123 { 124 + tep_register_print_function(pevent, 125 + process_xen_hypercall_name, 126 + TEP_FUNC_ARG_STRING, 127 + "xen_hypercall_name", 128 + TEP_FUNC_ARG_INT, 129 + TEP_FUNC_ARG_VOID); 130 return 0; 131 } 132 133 + void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) 134 { 135 + tep_unregister_print_function(pevent, process_xen_hypercall_name, 136 + "xen_hypercall_name"); 137 }
+1 -15
tools/lib/traceevent/trace-seq.c
··· 1 /* 2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 3 * 4 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU Lesser General Public 7 - * License as published by the Free Software Foundation; 8 - * version 2.1 of the License (not later!) 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU Lesser General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Lesser General Public 16 - * License along with this program; if not, see <http://www.gnu.org/licenses> 17 - * 18 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 */ 20 #include <stdio.h> 21 #include <stdlib.h>
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6 #include <stdio.h> 7 #include <stdlib.h>
+9
tools/perf/Documentation/perf-annotate.txt
··· 118 --group:: 119 Show event group information together 120 121 SEE ALSO 122 -------- 123 linkperf:perf-record[1], linkperf:perf-report[1]
··· 118 --group:: 119 Show event group information together 120 121 + --percent-type:: 122 + Set annotation percent type from following choices: 123 + global-period, local-period, global-hits, local-hits 124 + 125 + The local/global keywords set if the percentage is computed 126 + in the scope of the function (local) or the whole data (global). 127 + The period/hits keywords set the base the percentage is computed 128 + on - the samples period or the number of samples (hits). 129 + 130 SEE ALSO 131 -------- 132 linkperf:perf-record[1], linkperf:perf-report[1]
+9
tools/perf/Documentation/perf-report.txt
··· 477 Display monitored tasks stored in perf data. Displaying pid/tid/ppid 478 plus the command string aligned to distinguish parent and child tasks. 479 480 include::callchain-overhead-calculation.txt[] 481 482 SEE ALSO
··· 477 Display monitored tasks stored in perf data. Displaying pid/tid/ppid 478 plus the command string aligned to distinguish parent and child tasks. 479 480 + --percent-type:: 481 + Set annotation percent type from following choices: 482 + global-period, local-period, global-hits, local-hits 483 + 484 + The local/global keywords set if the percentage is computed 485 + in the scope of the function (local) or the whole data (global). 486 + The period/hits keywords set the base the percentage is computed 487 + on - the samples period or the number of samples (hits). 488 + 489 include::callchain-overhead-calculation.txt[] 490 491 SEE ALSO
+2 -2
tools/perf/Makefile
··· 84 endif # MAKECMDGOALS 85 86 # 87 - # The clean target is not really parallel, don't print the jobs info: 88 # 89 clean: 90 - $(make) 91 92 # 93 # The build-test target is not really parallel, don't print the jobs info,
··· 84 endif # MAKECMDGOALS 85 86 # 87 + # Explicitly disable parallelism for the clean target. 88 # 89 clean: 90 + $(make) -j1 91 92 # 93 # The build-test target is not really parallel, don't print the jobs info,
+1
tools/perf/arch/arm64/util/arm-spe.c
··· 194 sper->itr.read_finish = arm_spe_read_finish; 195 sper->itr.alignment = 0; 196 197 return &sper->itr; 198 } 199
··· 194 sper->itr.read_finish = arm_spe_read_finish; 195 sper->itr.alignment = 0; 196 197 + *err = 0; 198 return &sper->itr; 199 } 200
+3 -1
tools/perf/arch/powerpc/util/sym-handling.c
··· 141 for (i = 0; i < ntevs; i++) { 142 tev = &pev->tevs[i]; 143 map__for_each_symbol(map, sym, tmp) { 144 - if (map->unmap_ip(map, sym->start) == tev->point.address) 145 arch__fix_tev_from_maps(pev, tev, map, sym); 146 } 147 } 148 }
··· 141 for (i = 0; i < ntevs; i++) { 142 tev = &pev->tevs[i]; 143 map__for_each_symbol(map, sym, tmp) { 144 + if (map->unmap_ip(map, sym->start) == tev->point.address) { 145 arch__fix_tev_from_maps(pev, tev, map, sym); 146 + break; 147 + } 148 } 149 } 150 }
+1
tools/perf/arch/s390/util/auxtrace.c
··· 30 struct auxtrace_info_event *auxtrace_info __maybe_unused, 31 size_t priv_size __maybe_unused) 32 { 33 return 0; 34 } 35
··· 30 struct auxtrace_info_event *auxtrace_info __maybe_unused, 31 size_t priv_size __maybe_unused) 32 { 33 + auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF; 34 return 0; 35 } 36
-3
tools/perf/arch/x86/Makefile
··· 19 _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') 20 21 $(header): $(sys)/syscall_64.tbl $(systbl) 22 - @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ 23 - (diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \ 24 - || echo "Warning: Kernel ABI header at 'tools/perf/arch/x86/entry/syscalls/syscall_64.tbl' differs from latest version at 'arch/x86/entry/syscalls/syscall_64.tbl'" >&2 )) || true 25 $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ 26 27 clean::
··· 19 _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') 20 21 $(header): $(sys)/syscall_64.tbl $(systbl) 22 $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ 23 24 clean::
+4
tools/perf/builtin-annotate.c
··· 542 OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", 543 "'always' (default), 'never' or 'auto' only applicable to --stdio mode", 544 stdio__config_color, "always"), 545 OPT_END() 546 }; 547 int ret;
··· 542 OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", 543 "'always' (default), 'never' or 'auto' only applicable to --stdio mode", 544 stdio__config_color, "always"), 545 + OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period", 546 + "Set percent type local/global-period/hits", 547 + annotate_parse_percent_type), 548 + 549 OPT_END() 550 }; 551 int ret;
+3 -3
tools/perf/builtin-kmem.c
··· 729 static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, 730 unsigned int gfp_flags) 731 { 732 - struct pevent_record record = { 733 .cpu = sample->cpu, 734 .data = sample->raw_data, 735 .size = sample->raw_size, ··· 747 } 748 749 trace_seq_init(&seq); 750 - pevent_event_info(&seq, evsel->tp_format, &record); 751 752 str = strtok_r(seq.buffer, " ", &pos); 753 while (str) { ··· 1974 goto out_delete; 1975 } 1976 1977 - kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); 1978 symbol_conf.use_callchain = true; 1979 } 1980
··· 729 static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, 730 unsigned int gfp_flags) 731 { 732 + struct tep_record record = { 733 .cpu = sample->cpu, 734 .data = sample->raw_data, 735 .size = sample->raw_size, ··· 747 } 748 749 trace_seq_init(&seq); 750 + tep_event_info(&seq, evsel->tp_format, &record); 751 752 str = strtok_r(seq.buffer, " ", &pos); 753 while (str) { ··· 1974 goto out_delete; 1975 } 1976 1977 + kmem_page_size = tep_get_page_size(evsel->tp_format->pevent); 1978 symbol_conf.use_callchain = true; 1979 } 1980
+6 -3
tools/perf/builtin-report.c
··· 1124 "Time span of interest (start,stop)"), 1125 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, 1126 "Show inline function"), 1127 OPT_END() 1128 }; 1129 struct perf_data data = { ··· 1369 } 1370 1371 if (session->tevent.pevent && 1372 - pevent_set_function_resolver(session->tevent.pevent, 1373 - machine__resolve_kernel_addr, 1374 - &session->machines.host) < 0) { 1375 pr_err("%s: failed to set libtraceevent function resolver\n", 1376 __func__); 1377 return -1;
··· 1124 "Time span of interest (start,stop)"), 1125 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, 1126 "Show inline function"), 1127 + OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period", 1128 + "Set percent type local/global-period/hits", 1129 + annotate_parse_percent_type), 1130 OPT_END() 1131 }; 1132 struct perf_data data = { ··· 1366 } 1367 1368 if (session->tevent.pevent && 1369 + tep_set_function_resolver(session->tevent.pevent, 1370 + machine__resolve_kernel_addr, 1371 + &session->machines.host) < 0) { 1372 pr_err("%s: failed to set libtraceevent function resolver\n", 1373 __func__); 1374 return -1;
+3 -3
tools/perf/builtin-script.c
··· 3429 symbol_conf.use_callchain = false; 3430 3431 if (session->tevent.pevent && 3432 - pevent_set_function_resolver(session->tevent.pevent, 3433 - machine__resolve_kernel_addr, 3434 - &session->machines.host) < 0) { 3435 pr_err("%s: failed to set libtraceevent function resolver\n", __func__); 3436 err = -1; 3437 goto out_delete;
··· 3429 symbol_conf.use_callchain = false; 3430 3431 if (session->tevent.pevent && 3432 + tep_set_function_resolver(session->tevent.pevent, 3433 + machine__resolve_kernel_addr, 3434 + &session->machines.host) < 0) { 3435 pr_err("%s: failed to set libtraceevent function resolver\n", __func__); 3436 err = -1; 3437 goto out_delete;
+165 -26
tools/perf/builtin-trace.c
··· 77 struct syscall *table; 78 struct { 79 struct perf_evsel *sys_enter, 80 - *sys_exit; 81 } events; 82 } syscalls; 83 struct record_opts opts; ··· 122 bool force; 123 bool vfs_getname; 124 int trace_pgfaults; 125 - int open_id; 126 }; 127 128 struct tp_field { ··· 157 TP_UINT_FIELD__SWAPPED(32); 158 TP_UINT_FIELD__SWAPPED(64); 159 160 - static int tp_field__init_uint(struct tp_field *field, 161 - struct format_field *format_field, 162 - bool needs_swap) 163 { 164 - field->offset = format_field->offset; 165 166 - switch (format_field->size) { 167 case 1: 168 field->integer = tp_field__u8; 169 break; ··· 181 return 0; 182 } 183 184 static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) 185 { 186 return sample->raw_data + field->offset; 187 } 188 189 - static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) 190 { 191 - field->offset = format_field->offset; 192 field->pointer = tp_field__ptr; 193 return 0; 194 } 195 196 struct syscall_tp { ··· 248 perf_evsel__delete(evsel); 249 } 250 251 - static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) 252 { 253 evsel->priv = malloc(sizeof(struct syscall_tp)); 254 if (evsel->priv != NULL) { ··· 306 return -ENOENT; 307 } 308 309 - static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler) 310 { 311 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); 312 ··· 317 if (IS_ERR(evsel)) 318 return NULL; 319 320 - if (perf_evsel__init_syscall_tp(evsel, handler)) 321 goto out_delete; 322 323 return evsel; ··· 853 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); 854 } 855 856 struct syscall { 857 struct event_format *tp_format; 858 int nr_args; 859 struct format_field *args; 860 const char *name; 861 - bool is_exit; 862 struct syscall_fmt *fmt; 863 struct syscall_arg_fmt *arg_fmt; 864 }; ··· 1352 } 1353 1354 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); 1355 1356 return syscall__set_arg_fmts(sc); 1357 } ··· 1715 return err; 1716 } 1717 1718 static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, 1719 struct perf_sample *sample, 1720 struct callchain_cursor *cursor) ··· 1807 1808 ret = perf_evsel__sc_tp_uint(evsel, ret, sample); 1809 1810 - if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) { 1811 trace__set_fd_pathname(thread, ret, ttrace->filename.name); 1812 ttrace->filename.pending_open = false; 1813 ++trace->stats.vfs_getname; ··· 2042 fprintf(trace->output, "%s:", evsel->name); 2043 2044 if (perf_evsel__is_bpf_output(evsel)) { 2045 - bpf_output__fprintf(trace, sample); 2046 } else if (evsel->tp_format) { 2047 - event_format__fprintf(evsel->tp_format, sample->cpu, 2048 - sample->raw_data, sample->raw_size, 2049 - trace->output); 2050 } 2051 2052 fprintf(trace->output, "\n"); ··· 2333 struct perf_evlist *evlist = trace->evlist; 2334 struct perf_evsel *sys_enter, *sys_exit; 2335 2336 - sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter); 2337 if (sys_enter == NULL) 2338 goto out; 2339 2340 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) 2341 goto out_delete_sys_enter; 2342 2343 - sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit); 2344 if (sys_exit == NULL) 2345 goto out_delete_sys_enter; 2346 ··· 2762 "syscalls:sys_enter"); 2763 2764 if (evsel && 2765 - (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2766 perf_evsel__init_sc_tp_ptr_field(evsel, args))) { 2767 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2768 goto out; ··· 2774 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2775 "syscalls:sys_exit"); 2776 if (evsel && 2777 - (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2778 perf_evsel__init_sc_tp_uint_field(evsel, ret))) { 2779 pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2780 goto out; ··· 3014 evsel->handler = handler; 3015 } 3016 3017 /* 3018 * XXX: Hackish, just splitting the combined -e+--event (syscalls 3019 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use ··· 3244 }; 3245 bool __maybe_unused max_stack_user_set = true; 3246 bool mmap_pages_user_set = true; 3247 const char * const trace_subcommands[] = { "record", NULL }; 3248 - int err; 3249 char bf[BUFSIZ]; 3250 3251 signal(SIGSEGV, sighandler_dump_stack); ··· 3267 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) { 3268 usage_with_options_msg(trace_usage, trace_options, 3269 "cgroup monitoring only available in system-wide mode"); 3270 } 3271 3272 err = bpf__setup_stdout(trace.evlist); ··· 3318 symbol_conf.use_callchain = true; 3319 } 3320 3321 - if (trace.evlist->nr_entries > 0) 3322 evlist__set_evsel_handler(trace.evlist, trace__event_handler); 3323 3324 if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) 3325 return trace__record(&trace, argc-1, &argv[1]); ··· 3345 goto out; 3346 } 3347 } 3348 - 3349 - trace.open_id = syscalltbl__id(trace.sctbl, "open"); 3350 3351 err = target__validate(&trace.opts.target); 3352 if (err) {
··· 77 struct syscall *table; 78 struct { 79 struct perf_evsel *sys_enter, 80 + *sys_exit, 81 + *augmented; 82 } events; 83 } syscalls; 84 struct record_opts opts; ··· 121 bool force; 122 bool vfs_getname; 123 int trace_pgfaults; 124 }; 125 126 struct tp_field { ··· 157 TP_UINT_FIELD__SWAPPED(32); 158 TP_UINT_FIELD__SWAPPED(64); 159 160 + static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap) 161 { 162 + field->offset = offset; 163 164 + switch (size) { 165 case 1: 166 field->integer = tp_field__u8; 167 break; ··· 183 return 0; 184 } 185 186 + static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap) 187 + { 188 + return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap); 189 + } 190 + 191 static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) 192 { 193 return sample->raw_data + field->offset; 194 } 195 196 + static int __tp_field__init_ptr(struct tp_field *field, int offset) 197 { 198 + field->offset = offset; 199 field->pointer = tp_field__ptr; 200 return 0; 201 + } 202 + 203 + static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) 204 + { 205 + return __tp_field__init_ptr(field, format_field->offset); 206 } 207 208 struct syscall_tp { ··· 240 perf_evsel__delete(evsel); 241 } 242 243 + static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel) 244 + { 245 + struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); 246 + 247 + if (evsel->priv != NULL) { 248 + if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr")) 249 + goto out_delete; 250 + return 0; 251 + } 252 + 253 + return -ENOMEM; 254 + out_delete: 255 + zfree(&evsel->priv); 256 + return -ENOENT; 257 + } 258 + 259 + static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel) 260 + { 261 + struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); 262 + 263 + if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */ 264 + if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap)) 265 + goto out_delete; 266 + 267 + return 0; 268 + } 269 + 270 + return -ENOMEM; 271 + out_delete: 272 + zfree(&evsel->priv); 273 + return -EINVAL; 274 + } 275 + 276 + static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel) 277 + { 278 + struct syscall_tp *sc = evsel->priv; 279 + 280 + return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)); 281 + } 282 + 283 + static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler) 284 { 285 evsel->priv = malloc(sizeof(struct syscall_tp)); 286 if (evsel->priv != NULL) { ··· 258 return -ENOENT; 259 } 260 261 + static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) 262 { 263 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); 264 ··· 269 if (IS_ERR(evsel)) 270 return NULL; 271 272 + if (perf_evsel__init_raw_syscall_tp(evsel, handler)) 273 goto out_delete; 274 275 return evsel; ··· 805 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); 806 } 807 808 + /* 809 + * is_exit: is this "exit" or "exit_group"? 810 + * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. 811 + */ 812 struct syscall { 813 struct event_format *tp_format; 814 int nr_args; 815 + bool is_exit; 816 + bool is_open; 817 struct format_field *args; 818 const char *name; 819 struct syscall_fmt *fmt; 820 struct syscall_arg_fmt *arg_fmt; 821 }; ··· 1299 } 1300 1301 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); 1302 + sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat"); 1303 1304 return syscall__set_arg_fmts(sc); 1305 } ··· 1661 return err; 1662 } 1663 1664 + static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel, 1665 + struct perf_sample *sample) 1666 + { 1667 + struct thread_trace *ttrace; 1668 + struct thread *thread; 1669 + int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 1670 + struct syscall *sc = trace__syscall_info(trace, evsel, id); 1671 + char msg[1024]; 1672 + void *args; 1673 + 1674 + if (sc == NULL) 1675 + return -1; 1676 + 1677 + thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 1678 + ttrace = thread__trace(thread, trace->output); 1679 + /* 1680 + * We need to get ttrace just to make sure it is there when syscall__scnprintf_args() 1681 + * and the rest of the beautifiers accessing it via struct syscall_arg touches it. 1682 + */ 1683 + if (ttrace == NULL) 1684 + goto out_put; 1685 + 1686 + args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1687 + syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread); 1688 + fprintf(trace->output, "%s", msg); 1689 + err = 0; 1690 + out_put: 1691 + thread__put(thread); 1692 + return err; 1693 + } 1694 + 1695 static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, 1696 struct perf_sample *sample, 1697 struct callchain_cursor *cursor) ··· 1722 1723 ret = perf_evsel__sc_tp_uint(evsel, ret, sample); 1724 1725 + if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) { 1726 trace__set_fd_pathname(thread, ret, ttrace->filename.name); 1727 ttrace->filename.pending_open = false; 1728 ++trace->stats.vfs_getname; ··· 1957 fprintf(trace->output, "%s:", evsel->name); 1958 1959 if (perf_evsel__is_bpf_output(evsel)) { 1960 + if (evsel == trace->syscalls.events.augmented) 1961 + trace__fprintf_sys_enter(trace, evsel, sample); 1962 + else 1963 + bpf_output__fprintf(trace, sample); 1964 } else if (evsel->tp_format) { 1965 + if (strncmp(evsel->tp_format->name, "sys_enter_", 10) || 1966 + trace__fprintf_sys_enter(trace, evsel, sample)) { 1967 + event_format__fprintf(evsel->tp_format, sample->cpu, 1968 + sample->raw_data, sample->raw_size, 1969 + trace->output); 1970 + } 1971 } 1972 1973 fprintf(trace->output, "\n"); ··· 2242 struct perf_evlist *evlist = trace->evlist; 2243 struct perf_evsel *sys_enter, *sys_exit; 2244 2245 + sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter); 2246 if (sys_enter == NULL) 2247 goto out; 2248 2249 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) 2250 goto out_delete_sys_enter; 2251 2252 + sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit); 2253 if (sys_exit == NULL) 2254 goto out_delete_sys_enter; 2255 ··· 2671 "syscalls:sys_enter"); 2672 2673 if (evsel && 2674 + (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 || 2675 perf_evsel__init_sc_tp_ptr_field(evsel, args))) { 2676 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2677 goto out; ··· 2683 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2684 "syscalls:sys_exit"); 2685 if (evsel && 2686 + (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 || 2687 perf_evsel__init_sc_tp_uint_field(evsel, ret))) { 2688 pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2689 goto out; ··· 2923 evsel->handler = handler; 2924 } 2925 2926 + static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist) 2927 + { 2928 + struct perf_evsel *evsel; 2929 + 2930 + evlist__for_each_entry(evlist, evsel) { 2931 + if (evsel->priv || !evsel->tp_format) 2932 + continue; 2933 + 2934 + if (strcmp(evsel->tp_format->system, "syscalls")) 2935 + continue; 2936 + 2937 + if (perf_evsel__init_syscall_tp(evsel)) 2938 + return -1; 2939 + 2940 + if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) { 2941 + struct syscall_tp *sc = evsel->priv; 2942 + 2943 + if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64))) 2944 + return -1; 2945 + } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) { 2946 + struct syscall_tp *sc = evsel->priv; 2947 + 2948 + if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap)) 2949 + return -1; 2950 + } 2951 + } 2952 + 2953 + return 0; 2954 + } 2955 + 2956 /* 2957 * XXX: Hackish, just splitting the combined -e+--event (syscalls 2958 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use ··· 3123 }; 3124 bool __maybe_unused max_stack_user_set = true; 3125 bool mmap_pages_user_set = true; 3126 + struct perf_evsel *evsel; 3127 const char * const trace_subcommands[] = { "record", NULL }; 3128 + int err = -1; 3129 char bf[BUFSIZ]; 3130 3131 signal(SIGSEGV, sighandler_dump_stack); ··· 3145 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) { 3146 usage_with_options_msg(trace_usage, trace_options, 3147 "cgroup monitoring only available in system-wide mode"); 3148 + } 3149 + 3150 + evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__"); 3151 + if (IS_ERR(evsel)) { 3152 + bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf)); 3153 + pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf); 3154 + goto out; 3155 + } 3156 + 3157 + if (evsel) { 3158 + if (perf_evsel__init_augmented_syscall_tp(evsel) || 3159 + perf_evsel__init_augmented_syscall_tp_args(evsel)) 3160 + goto out; 3161 + trace.syscalls.events.augmented = evsel; 3162 } 3163 3164 err = bpf__setup_stdout(trace.evlist); ··· 3182 symbol_conf.use_callchain = true; 3183 } 3184 3185 + if (trace.evlist->nr_entries > 0) { 3186 evlist__set_evsel_handler(trace.evlist, trace__event_handler); 3187 + if (evlist__set_syscall_tp_fields(trace.evlist)) { 3188 + perror("failed to set syscalls:* tracepoint fields"); 3189 + goto out; 3190 + } 3191 + } 3192 3193 if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) 3194 return trace__record(&trace, argc-1, &argv[1]); ··· 3204 goto out; 3205 } 3206 } 3207 3208 err = target__validate(&trace.opts.target); 3209 if (err) {
+14 -3
tools/perf/check-headers.sh
··· 67 68 cmd="diff $* $file1 $file2 > /dev/null" 69 70 - test -f $file2 && 71 - eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2 72 } 73 74 check () { ··· 80 81 shift 82 83 - check_2 ../$file ../../$file $* 84 } 85 86 # Check if we have the kernel headers (tools/perf/../../include), else 87 # we're probably on a detached tarball, so no point in trying to check 88 # differences. 89 test -d ../../include || exit 0 90 91 # simple diff check 92 for i in $HEADERS; do ··· 100 check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' 101 check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"' 102 check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"'
··· 67 68 cmd="diff $* $file1 $file2 > /dev/null" 69 70 + test -f $file2 && { 71 + eval $cmd || { 72 + echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2 73 + echo diff -u $file1 $file2 74 + } 75 + } 76 } 77 78 check () { ··· 76 77 shift 78 79 + check_2 tools/$file $file $* 80 } 81 82 # Check if we have the kernel headers (tools/perf/../../include), else 83 # we're probably on a detached tarball, so no point in trying to check 84 # differences. 85 test -d ../../include || exit 0 86 + 87 + cd ../.. 88 89 # simple diff check 90 for i in $HEADERS; do ··· 94 check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' 95 check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"' 96 check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' 97 + 98 + # diff non-symmetric files 99 + check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl 100 + 101 + cd tools/perf
+55
tools/perf/examples/bpf/augmented_syscalls.c
···
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Augment the openat syscall with the contents of the filename pointer argument. 4 + * 5 + * Test it with: 6 + * 7 + * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null 8 + * 9 + * It'll catch some openat syscalls related to the dynamic linked and 10 + * the last one should be the one for '/etc/passwd'. 11 + * 12 + * This matches what is marshalled into the raw_syscall:sys_enter payload 13 + * expected by the 'perf trace' beautifiers, and can be used by them unmodified, 14 + * which will be done as that feature is implemented in the next csets, for now 15 + * it will appear in a dump done by the default tracepoint handler in 'perf trace', 16 + * that uses bpf_output__fprintf() to just dump those contents, as done with 17 + * the bpf-output event associated with the __bpf_output__ map declared in 18 + * tools/perf/include/bpf/stdio.h. 19 + */ 20 + 21 + #include <stdio.h> 22 + 23 + struct bpf_map SEC("maps") __augmented_syscalls__ = { 24 + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 25 + .key_size = sizeof(int), 26 + .value_size = sizeof(u32), 27 + .max_entries = __NR_CPUS__, 28 + }; 29 + 30 + struct syscall_enter_openat_args { 31 + unsigned long long common_tp_fields; 32 + long syscall_nr; 33 + long dfd; 34 + char *filename_ptr; 35 + long flags; 36 + long mode; 37 + }; 38 + 39 + struct augmented_enter_openat_args { 40 + struct syscall_enter_openat_args args; 41 + char filename[64]; 42 + }; 43 + 44 + int syscall_enter(openat)(struct syscall_enter_openat_args *args) 45 + { 46 + struct augmented_enter_openat_args augmented_args; 47 + 48 + probe_read(&augmented_args.args, sizeof(augmented_args.args), args); 49 + probe_read_str(&augmented_args.filename, sizeof(augmented_args.filename), args->filename_ptr); 50 + perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, 51 + &augmented_args, sizeof(augmented_args)); 52 + return 1; 53 + } 54 + 55 + license(GPL);
+9
tools/perf/examples/bpf/hello.c
···
··· 1 + #include <stdio.h> 2 + 3 + int syscall_enter(openat)(void *args) 4 + { 5 + puts("Hello, world\n"); 6 + return 0; 7 + } 8 + 9 + license(GPL);
+33
tools/perf/examples/bpf/sys_enter_openat.c
···
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Hook into 'openat' syscall entry tracepoint 4 + * 5 + * Test it with: 6 + * 7 + * perf trace -e tools/perf/examples/bpf/sys_enter_openat.c cat /etc/passwd > /dev/null 8 + * 9 + * It'll catch some openat syscalls related to the dynamic linked and 10 + * the last one should be the one for '/etc/passwd'. 11 + * 12 + * The syscall_enter_openat_args can be used to get the syscall fields 13 + * and use them for filtering calls, i.e. use in expressions for 14 + * the return value. 15 + */ 16 + 17 + #include <bpf.h> 18 + 19 + struct syscall_enter_openat_args { 20 + unsigned long long unused; 21 + long syscall_nr; 22 + long dfd; 23 + char *filename_ptr; 24 + long flags; 25 + long mode; 26 + }; 27 + 28 + int syscall_enter(openat)(struct syscall_enter_openat_args *args) 29 + { 30 + return 1; 31 + } 32 + 33 + license(GPL);
+20
tools/perf/include/bpf/bpf.h
··· 4 5 #include <uapi/linux/bpf.h> 6 7 #define SEC(NAME) __attribute__((section(NAME), used)) 8 9 #define probe(function, vars) \ 10 SEC(#function "=" #function " " #vars) function 11 12 #define license(name) \ 13 char _license[] SEC("license") = #name; \ 14 int _version SEC("version") = LINUX_VERSION_CODE; 15 16 #endif /* _PERF_BPF_H */
··· 4 5 #include <uapi/linux/bpf.h> 6 7 + /* 8 + * A helper structure used by eBPF C program to describe map attributes to 9 + * elf_bpf loader, taken from tools/testing/selftests/bpf/bpf_helpers.h: 10 + */ 11 + struct bpf_map { 12 + unsigned int type; 13 + unsigned int key_size; 14 + unsigned int value_size; 15 + unsigned int max_entries; 16 + unsigned int map_flags; 17 + unsigned int inner_map_idx; 18 + unsigned int numa_node; 19 + }; 20 + 21 #define SEC(NAME) __attribute__((section(NAME), used)) 22 23 #define probe(function, vars) \ 24 SEC(#function "=" #function " " #vars) function 25 26 + #define syscall_enter(name) \ 27 + SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name 28 + 29 #define license(name) \ 30 char _license[] SEC("license") = #name; \ 31 int _version SEC("version") = LINUX_VERSION_CODE; 32 + 33 + static int (*probe_read)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read; 34 + static int (*probe_read_str)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read_str; 35 36 #endif /* _PERF_BPF_H */
+19
tools/perf/include/bpf/stdio.h
···
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <bpf.h> 4 + 5 + struct bpf_map SEC("maps") __bpf_stdout__ = { 6 + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 7 + .key_size = sizeof(int), 8 + .value_size = sizeof(u32), 9 + .max_entries = __NR_CPUS__, 10 + }; 11 + 12 + static int (*perf_event_output)(void *, struct bpf_map *, int, void *, unsigned long) = 13 + (void *)BPF_FUNC_perf_event_output; 14 + 15 + #define puts(from) \ 16 + ({ const int __len = sizeof(from); \ 17 + char __from[__len] = from; \ 18 + perf_event_output(args, &__bpf_stdout__, BPF_F_CURRENT_CPU, \ 19 + &__from, __len & (sizeof(from) - 1)); })
+32
tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json
···
··· 1 + [ 2 + { 3 + "ArchStdEvent": "L1D_CACHE_RD", 4 + }, 5 + { 6 + "ArchStdEvent": "L1D_CACHE_WR", 7 + }, 8 + { 9 + "ArchStdEvent": "L1D_CACHE_REFILL_RD", 10 + }, 11 + { 12 + "ArchStdEvent": "L1D_CACHE_REFILL_WR", 13 + }, 14 + { 15 + "ArchStdEvent": "L1D_TLB_REFILL_RD", 16 + }, 17 + { 18 + "ArchStdEvent": "L1D_TLB_REFILL_WR", 19 + }, 20 + { 21 + "ArchStdEvent": "L1D_TLB_RD", 22 + }, 23 + { 24 + "ArchStdEvent": "L1D_TLB_WR", 25 + }, 26 + { 27 + "ArchStdEvent": "BUS_ACCESS_RD", 28 + }, 29 + { 30 + "ArchStdEvent": "BUS_ACCESS_WR", 31 + } 32 + ]
+1
tools/perf/pmu-events/arch/arm64/mapfile.csv
··· 16 0x00000000420f5160,v1,cavium/thunderx2,core 17 0x00000000430f0af0,v1,cavium/thunderx2,core 18 0x00000000480fd010,v1,hisilicon/hip08,core
··· 16 0x00000000420f5160,v1,cavium/thunderx2,core 17 0x00000000430f0af0,v1,cavium/thunderx2,core 18 0x00000000480fd010,v1,hisilicon/hip08,core 19 + 0x00000000500f0000,v1,ampere/emag,core
-2
tools/perf/tests/bitmap.c
··· 16 bm = bitmap_alloc(nbits); 17 18 if (map && bm) { 19 - bitmap_zero(bm, nbits); 20 - 21 for (i = 0; i < map->nr; i++) 22 set_bit(map->map[i], bm); 23 }
··· 16 bm = bitmap_alloc(nbits); 17 18 if (map && bm) { 19 for (i = 0; i < map->nr; i++) 20 set_bit(map->map[i], bm); 21 }
+3 -1
tools/perf/tests/code-reading.c
··· 232 u64 objdump_addr; 233 const char *objdump_name; 234 char decomp_name[KMOD_DECOMP_LEN]; 235 int ret; 236 237 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); ··· 306 return -1; 307 } 308 309 objdump_name = decomp_name; 310 } 311 ··· 314 objdump_addr = map__rip_2objdump(al.map, al.addr); 315 ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); 316 317 - if (dso__needs_decompress(al.map->dso)) 318 unlink(objdump_name); 319 320 if (ret > 0) {
··· 232 u64 objdump_addr; 233 const char *objdump_name; 234 char decomp_name[KMOD_DECOMP_LEN]; 235 + bool decomp = false; 236 int ret; 237 238 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); ··· 305 return -1; 306 } 307 308 + decomp = true; 309 objdump_name = decomp_name; 310 } 311 ··· 312 objdump_addr = map__rip_2objdump(al.map, al.addr); 313 ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); 314 315 + if (decomp) 316 unlink(objdump_name); 317 318 if (ret > 0) {
+65 -71
tools/perf/tests/kmod-path.c
··· 5 #include "dso.h" 6 #include "debug.h" 7 8 - static int test(const char *path, bool alloc_name, bool alloc_ext, 9 - bool kmod, bool comp, const char *name, const char *ext) 10 { 11 struct kmod_path m; 12 13 memset(&m, 0x0, sizeof(m)); 14 15 TEST_ASSERT_VAL("kmod_path__parse", 16 - !__kmod_path__parse(&m, path, alloc_name, alloc_ext)); 17 18 - pr_debug("%s - alloc name %d, alloc ext %d, kmod %d, comp %d, name '%s', ext '%s'\n", 19 - path, alloc_name, alloc_ext, m.kmod, m.comp, m.name, m.ext); 20 21 TEST_ASSERT_VAL("wrong kmod", m.kmod == kmod); 22 TEST_ASSERT_VAL("wrong comp", m.comp == comp); 23 - 24 - if (ext) 25 - TEST_ASSERT_VAL("wrong ext", m.ext && !strcmp(ext, m.ext)); 26 - else 27 - TEST_ASSERT_VAL("wrong ext", !m.ext); 28 29 if (name) 30 TEST_ASSERT_VAL("wrong name", m.name && !strcmp(name, m.name)); ··· 27 TEST_ASSERT_VAL("wrong name", !m.name); 28 29 free(m.name); 30 - free(m.ext); 31 return 0; 32 } 33 ··· 39 return 0; 40 } 41 42 - #define T(path, an, ae, k, c, n, e) \ 43 - TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e)) 44 45 #define M(path, c, e) \ 46 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) 47 48 int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_unused) 49 { 50 - /* path alloc_name alloc_ext kmod comp name ext */ 51 - T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL); 52 - T("/xxxx/xxxx/x-x.ko", false , true , true, false, NULL , NULL); 53 - T("/xxxx/xxxx/x-x.ko", true , false , true, false, "[x_x]", NULL); 54 - T("/xxxx/xxxx/x-x.ko", false , false , true, false, NULL , NULL); 55 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 56 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true); 57 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false); 58 59 #ifdef HAVE_ZLIB_SUPPORT 60 - /* path alloc_name alloc_ext kmod comp name ext */ 61 - T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz"); 62 - T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz"); 63 - T("/xxxx/xxxx/x.ko.gz", true , false , true, true, "[x]", NULL); 64 - T("/xxxx/xxxx/x.ko.gz", false , false , true, true, NULL , NULL); 65 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 66 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_KERNEL, true); 67 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_USER, false); 68 69 - /* path alloc_name alloc_ext kmod comp name ext */ 70 - T("/xxxx/xxxx/x.gz", true , true , false, true, "x.gz" ,"gz"); 71 - T("/xxxx/xxxx/x.gz", false , true , false, true, NULL ,"gz"); 72 - T("/xxxx/xxxx/x.gz", true , false , false, true, "x.gz" , NULL); 73 - T("/xxxx/xxxx/x.gz", false , false , false, true, NULL , NULL); 74 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 75 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_KERNEL, false); 76 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_USER, false); 77 78 - /* path alloc_name alloc_ext kmod comp name ext */ 79 - T("x.gz", true , true , false, true, "x.gz", "gz"); 80 - T("x.gz", false , true , false, true, NULL , "gz"); 81 - T("x.gz", true , false , false, true, "x.gz", NULL); 82 - T("x.gz", false , false , false, true, NULL , NULL); 83 M("x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 84 M("x.gz", PERF_RECORD_MISC_KERNEL, false); 85 M("x.gz", PERF_RECORD_MISC_USER, false); 86 87 - /* path alloc_name alloc_ext kmod comp name ext */ 88 - T("x.ko.gz", true , true , true, true, "[x]", "gz"); 89 - T("x.ko.gz", false , true , true, true, NULL , "gz"); 90 - T("x.ko.gz", true , false , true, true, "[x]", NULL); 91 - T("x.ko.gz", false , false , true, true, NULL , NULL); 92 M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 93 M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true); 94 M("x.ko.gz", PERF_RECORD_MISC_USER, false); 95 #endif 96 97 - /* path alloc_name alloc_ext kmod comp name ext */ 98 - T("[test_module]", true , true , true, false, "[test_module]", NULL); 99 - T("[test_module]", false , true , true, false, NULL , NULL); 100 - T("[test_module]", true , false , true, false, "[test_module]", NULL); 101 - T("[test_module]", false , false , true, false, NULL , NULL); 102 M("[test_module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 103 M("[test_module]", PERF_RECORD_MISC_KERNEL, true); 104 M("[test_module]", PERF_RECORD_MISC_USER, false); 105 106 - /* path alloc_name alloc_ext kmod comp name ext */ 107 - T("[test.module]", true , true , true, false, "[test.module]", NULL); 108 - T("[test.module]", false , true , true, false, NULL , NULL); 109 - T("[test.module]", true , false , true, false, "[test.module]", NULL); 110 - T("[test.module]", false , false , true, false, NULL , NULL); 111 M("[test.module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 112 M("[test.module]", PERF_RECORD_MISC_KERNEL, true); 113 M("[test.module]", PERF_RECORD_MISC_USER, false); 114 115 - /* path alloc_name alloc_ext kmod comp name ext */ 116 - T("[vdso]", true , true , false, false, "[vdso]", NULL); 117 - T("[vdso]", false , true , false, false, NULL , NULL); 118 - T("[vdso]", true , false , false, false, "[vdso]", NULL); 119 - T("[vdso]", false , false , false, false, NULL , NULL); 120 M("[vdso]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 121 M("[vdso]", PERF_RECORD_MISC_KERNEL, false); 122 M("[vdso]", PERF_RECORD_MISC_USER, false); 123 124 - T("[vdso32]", true , true , false, false, "[vdso32]", NULL); 125 - T("[vdso32]", false , true , false, false, NULL , NULL); 126 - T("[vdso32]", true , false , false, false, "[vdso32]", NULL); 127 - T("[vdso32]", false , false , false, false, NULL , NULL); 128 M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 129 M("[vdso32]", PERF_RECORD_MISC_KERNEL, false); 130 M("[vdso32]", PERF_RECORD_MISC_USER, false); 131 132 - T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL); 133 - T("[vdsox32]", false , true , false, false, NULL , NULL); 134 - T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL); 135 - T("[vdsox32]", false , false , false, false, NULL , NULL); 136 M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 137 M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false); 138 M("[vdsox32]", PERF_RECORD_MISC_USER, false); 139 140 - /* path alloc_name alloc_ext kmod comp name ext */ 141 - T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); 142 - T("[vsyscall]", false , true , false, false, NULL , NULL); 143 - T("[vsyscall]", true , false , false, false, "[vsyscall]", NULL); 144 - T("[vsyscall]", false , false , false, false, NULL , NULL); 145 M("[vsyscall]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 146 M("[vsyscall]", PERF_RECORD_MISC_KERNEL, false); 147 M("[vsyscall]", PERF_RECORD_MISC_USER, false); 148 149 - /* path alloc_name alloc_ext kmod comp name ext */ 150 - T("[kernel.kallsyms]", true , true , false, false, "[kernel.kallsyms]", NULL); 151 - T("[kernel.kallsyms]", false , true , false, false, NULL , NULL); 152 - T("[kernel.kallsyms]", true , false , false, false, "[kernel.kallsyms]", NULL); 153 - T("[kernel.kallsyms]", false , false , false, false, NULL , NULL); 154 M("[kernel.kallsyms]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 155 M("[kernel.kallsyms]", PERF_RECORD_MISC_KERNEL, false); 156 M("[kernel.kallsyms]", PERF_RECORD_MISC_USER, false);
··· 5 #include "dso.h" 6 #include "debug.h" 7 8 + static int test(const char *path, bool alloc_name, bool kmod, 9 + int comp, const char *name) 10 { 11 struct kmod_path m; 12 13 memset(&m, 0x0, sizeof(m)); 14 15 TEST_ASSERT_VAL("kmod_path__parse", 16 + !__kmod_path__parse(&m, path, alloc_name)); 17 18 + pr_debug("%s - alloc name %d, kmod %d, comp %d, name '%s'\n", 19 + path, alloc_name, m.kmod, m.comp, m.name); 20 21 TEST_ASSERT_VAL("wrong kmod", m.kmod == kmod); 22 TEST_ASSERT_VAL("wrong comp", m.comp == comp); 23 24 if (name) 25 TEST_ASSERT_VAL("wrong name", m.name && !strcmp(name, m.name)); ··· 32 TEST_ASSERT_VAL("wrong name", !m.name); 33 34 free(m.name); 35 return 0; 36 } 37 ··· 45 return 0; 46 } 47 48 + #define T(path, an, k, c, n) \ 49 + TEST_ASSERT_VAL("failed", !test(path, an, k, c, n)) 50 51 #define M(path, c, e) \ 52 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) 53 54 int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_unused) 55 { 56 + /* path alloc_name kmod comp name */ 57 + T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]"); 58 + T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL ); 59 + T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]"); 60 + T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL ); 61 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 62 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true); 63 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false); 64 65 #ifdef HAVE_ZLIB_SUPPORT 66 + /* path alloc_name kmod comp name */ 67 + T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]"); 68 + T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL ); 69 + T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]"); 70 + T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL ); 71 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 72 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_KERNEL, true); 73 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_USER, false); 74 75 + /* path alloc_name kmod comp name */ 76 + T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz"); 77 + T("/xxxx/xxxx/x.gz", false , false, 1 , NULL ); 78 + T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz"); 79 + T("/xxxx/xxxx/x.gz", false , false, 1 , NULL ); 80 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 81 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_KERNEL, false); 82 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_USER, false); 83 84 + /* path alloc_name kmod comp name */ 85 + T("x.gz", true , false, 1 , "x.gz"); 86 + T("x.gz", false , false, 1 , NULL ); 87 + T("x.gz", true , false, 1 , "x.gz"); 88 + T("x.gz", false , false, 1 , NULL ); 89 M("x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 90 M("x.gz", PERF_RECORD_MISC_KERNEL, false); 91 M("x.gz", PERF_RECORD_MISC_USER, false); 92 93 + /* path alloc_name kmod comp name */ 94 + T("x.ko.gz", true , true, 1 , "[x]"); 95 + T("x.ko.gz", false , true, 1 , NULL ); 96 + T("x.ko.gz", true , true, 1 , "[x]"); 97 + T("x.ko.gz", false , true, 1 , NULL ); 98 M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 99 M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true); 100 M("x.ko.gz", PERF_RECORD_MISC_USER, false); 101 #endif 102 103 + /* path alloc_name kmod comp name */ 104 + T("[test_module]", true , true, false, "[test_module]"); 105 + T("[test_module]", false , true, false, NULL ); 106 + T("[test_module]", true , true, false, "[test_module]"); 107 + T("[test_module]", false , true, false, NULL ); 108 M("[test_module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 109 M("[test_module]", PERF_RECORD_MISC_KERNEL, true); 110 M("[test_module]", PERF_RECORD_MISC_USER, false); 111 112 + /* path alloc_name kmod comp name */ 113 + T("[test.module]", true , true, false, "[test.module]"); 114 + T("[test.module]", false , true, false, NULL ); 115 + T("[test.module]", true , true, false, "[test.module]"); 116 + T("[test.module]", false , true, false, NULL ); 117 M("[test.module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 118 M("[test.module]", PERF_RECORD_MISC_KERNEL, true); 119 M("[test.module]", PERF_RECORD_MISC_USER, false); 120 121 + /* path alloc_name kmod comp name */ 122 + T("[vdso]", true , false, false, "[vdso]"); 123 + T("[vdso]", false , false, false, NULL ); 124 + T("[vdso]", true , false, false, "[vdso]"); 125 + T("[vdso]", false , false, false, NULL ); 126 M("[vdso]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 127 M("[vdso]", PERF_RECORD_MISC_KERNEL, false); 128 M("[vdso]", PERF_RECORD_MISC_USER, false); 129 130 + T("[vdso32]", true , false, false, "[vdso32]"); 131 + T("[vdso32]", false , false, false, NULL ); 132 + T("[vdso32]", true , false, false, "[vdso32]"); 133 + T("[vdso32]", false , false, false, NULL ); 134 M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 135 M("[vdso32]", PERF_RECORD_MISC_KERNEL, false); 136 M("[vdso32]", PERF_RECORD_MISC_USER, false); 137 138 + T("[vdsox32]", true , false, false, "[vdsox32]"); 139 + T("[vdsox32]", false , false, false, NULL ); 140 + T("[vdsox32]", true , false, false, "[vdsox32]"); 141 + T("[vdsox32]", false , false, false, NULL ); 142 M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 143 M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false); 144 M("[vdsox32]", PERF_RECORD_MISC_USER, false); 145 146 + /* path alloc_name kmod comp name */ 147 + T("[vsyscall]", true , false, false, "[vsyscall]"); 148 + T("[vsyscall]", false , false, false, NULL ); 149 + T("[vsyscall]", true , false, false, "[vsyscall]"); 150 + T("[vsyscall]", false , false, false, NULL ); 151 M("[vsyscall]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 152 M("[vsyscall]", PERF_RECORD_MISC_KERNEL, false); 153 M("[vsyscall]", PERF_RECORD_MISC_USER, false); 154 155 + /* path alloc_name kmod comp name */ 156 + T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]"); 157 + T("[kernel.kallsyms]", false , false, false, NULL ); 158 + T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]"); 159 + T("[kernel.kallsyms]", false , false, false, NULL ); 160 M("[kernel.kallsyms]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); 161 M("[kernel.kallsyms]", PERF_RECORD_MISC_KERNEL, false); 162 M("[kernel.kallsyms]", PERF_RECORD_MISC_USER, false);
-2
tools/perf/tests/mem2node.c
··· 24 bm = bitmap_alloc(nbits); 25 26 if (map && bm) { 27 - bitmap_zero(bm, nbits); 28 - 29 for (i = 0; i < map->nr; i++) { 30 set_bit(map->map[i], bm); 31 }
··· 24 bm = bitmap_alloc(nbits); 25 26 if (map && bm) { 27 for (i = 0; i < map->nr; i++) { 28 set_bit(map->map[i], bm); 29 }
+61 -15
tools/perf/ui/browsers/annotate.c
··· 15 #include <linux/kernel.h> 16 #include <linux/string.h> 17 #include <sys/ttydefaults.h> 18 19 struct disasm_line_samples { 20 double percent; ··· 116 if (!browser->navkeypressed) 117 ops.width += 1; 118 119 - annotation_line__write(al, notes, &ops); 120 121 if (ops.current_entry) 122 ab->selection = al; ··· 228 { 229 int i; 230 231 - for (i = 0; i < a->samples_nr; i++) { 232 - if (a->samples[i].percent == b->samples[i].percent) 233 continue; 234 - return a->samples[i].percent < b->samples[i].percent; 235 } 236 return 0; 237 } ··· 315 continue; 316 } 317 318 - for (i = 0; i < pos->al.samples_nr; i++) { 319 - struct annotation_data *sample = &pos->al.samples[i]; 320 321 - if (max_percent < sample->percent) 322 - max_percent = sample->percent; 323 } 324 325 if (max_percent < 0.01 && pos->al.ipc == 0) { ··· 384 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 385 386 static int sym_title(struct symbol *sym, struct map *map, char *title, 387 - size_t sz) 388 { 389 - return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 390 } 391 392 /* ··· 425 426 pthread_mutex_unlock(&notes->lock); 427 symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); 428 - sym_title(ms->sym, ms->map, title, sizeof(title)); 429 ui_browser__show_title(&browser->b, title); 430 return true; 431 } ··· 600 601 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) 602 { 603 struct map_symbol *ms = browser->priv; 604 struct symbol *sym = ms->sym; 605 char symbol_dso[SYM_TITLE_MAX_SIZE]; ··· 608 if (ui_browser__show(browser, title, help) < 0) 609 return -1; 610 611 - sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); 612 613 ui_browser__gotorc_title(browser, 0, 0); 614 ui_browser__set_color(browser, HE_COLORSET_ROOT); 615 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); 616 return 0; 617 } 618 619 static int annotate_browser__run(struct annotate_browser *browser, ··· 663 char title[256]; 664 int key; 665 666 - annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); 667 - 668 if (annotate_browser__show(&browser->b, title, help) < 0) 669 return -1; 670 ··· 739 "k Toggle line numbers\n" 740 "P Print to [symbol_name].annotation file.\n" 741 "r Run available scripts\n" 742 "? Search string backwards\n"); 743 continue; 744 case 'r': ··· 821 continue; 822 } 823 case 'P': 824 - map_symbol__annotation_dump(ms, evsel); 825 continue; 826 case 't': 827 if (notes->options->show_total_period) { ··· 839 else 840 notes->options->show_minmax_cycle = true; 841 annotation__update_column_widths(notes); 842 continue; 843 case K_LEFT: 844 case K_ESC:
··· 15 #include <linux/kernel.h> 16 #include <linux/string.h> 17 #include <sys/ttydefaults.h> 18 + #include <asm/bug.h> 19 20 struct disasm_line_samples { 21 double percent; ··· 115 if (!browser->navkeypressed) 116 ops.width += 1; 117 118 + annotation_line__write(al, notes, &ops, ab->opts); 119 120 if (ops.current_entry) 121 ab->selection = al; ··· 227 { 228 int i; 229 230 + for (i = 0; i < a->data_nr; i++) { 231 + if (a->data[i].percent == b->data[i].percent) 232 continue; 233 + return a->data[i].percent < b->data[i].percent; 234 } 235 return 0; 236 } ··· 314 continue; 315 } 316 317 + for (i = 0; i < pos->al.data_nr; i++) { 318 + double percent; 319 320 + percent = annotation_data__percent(&pos->al.data[i], 321 + browser->opts->percent_type); 322 + 323 + if (max_percent < percent) 324 + max_percent = percent; 325 } 326 327 if (max_percent < 0.01 && pos->al.ipc == 0) { ··· 380 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 381 382 static int sym_title(struct symbol *sym, struct map *map, char *title, 383 + size_t sz, int percent_type) 384 { 385 + return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name, 386 + percent_type_str(percent_type)); 387 } 388 389 /* ··· 420 421 pthread_mutex_unlock(&notes->lock); 422 symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); 423 + sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); 424 ui_browser__show_title(&browser->b, title); 425 return true; 426 } ··· 595 596 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) 597 { 598 + struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 599 struct map_symbol *ms = browser->priv; 600 struct symbol *sym = ms->sym; 601 char symbol_dso[SYM_TITLE_MAX_SIZE]; ··· 602 if (ui_browser__show(browser, title, help) < 0) 603 return -1; 604 605 + sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type); 606 607 ui_browser__gotorc_title(browser, 0, 0); 608 ui_browser__set_color(browser, HE_COLORSET_ROOT); 609 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); 610 return 0; 611 + } 612 + 613 + static void 614 + switch_percent_type(struct annotation_options *opts, bool base) 615 + { 616 + switch (opts->percent_type) { 617 + case PERCENT_HITS_LOCAL: 618 + if (base) 619 + opts->percent_type = PERCENT_PERIOD_LOCAL; 620 + else 621 + opts->percent_type = PERCENT_HITS_GLOBAL; 622 + break; 623 + case PERCENT_HITS_GLOBAL: 624 + if (base) 625 + opts->percent_type = PERCENT_PERIOD_GLOBAL; 626 + else 627 + opts->percent_type = PERCENT_HITS_LOCAL; 628 + break; 629 + case PERCENT_PERIOD_LOCAL: 630 + if (base) 631 + opts->percent_type = PERCENT_HITS_LOCAL; 632 + else 633 + opts->percent_type = PERCENT_PERIOD_GLOBAL; 634 + break; 635 + case PERCENT_PERIOD_GLOBAL: 636 + if (base) 637 + opts->percent_type = PERCENT_HITS_GLOBAL; 638 + else 639 + opts->percent_type = PERCENT_PERIOD_LOCAL; 640 + break; 641 + default: 642 + WARN_ON(1); 643 + } 644 } 645 646 static int annotate_browser__run(struct annotate_browser *browser, ··· 624 char title[256]; 625 int key; 626 627 + hists__scnprintf_title(hists, title, sizeof(title)); 628 if (annotate_browser__show(&browser->b, title, help) < 0) 629 return -1; 630 ··· 701 "k Toggle line numbers\n" 702 "P Print to [symbol_name].annotation file.\n" 703 "r Run available scripts\n" 704 + "p Toggle percent type [local/global]\n" 705 + "b Toggle percent base [period/hits]\n" 706 "? Search string backwards\n"); 707 continue; 708 case 'r': ··· 781 continue; 782 } 783 case 'P': 784 + map_symbol__annotation_dump(ms, evsel, browser->opts); 785 continue; 786 case 't': 787 if (notes->options->show_total_period) { ··· 799 else 800 notes->options->show_minmax_cycle = true; 801 annotation__update_column_widths(notes); 802 + continue; 803 + case 'p': 804 + case 'b': 805 + switch_percent_type(browser->opts, key == 'b'); 806 + hists__scnprintf_title(hists, title, sizeof(title)); 807 + annotate_browser__show(&browser->b, title, help); 808 continue; 809 case K_LEFT: 810 case K_ESC:
+1
tools/perf/util/Build
··· 87 libperf-$(CONFIG_AUXTRACE) += intel-bts.o 88 libperf-$(CONFIG_AUXTRACE) += arm-spe.o 89 libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o 90 91 ifdef CONFIG_LIBOPENCSD 92 libperf-$(CONFIG_AUXTRACE) += cs-etm.o
··· 87 libperf-$(CONFIG_AUXTRACE) += intel-bts.o 88 libperf-$(CONFIG_AUXTRACE) += arm-spe.o 89 libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o 90 + libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o 91 92 ifdef CONFIG_LIBOPENCSD 93 libperf-$(CONFIG_AUXTRACE) += cs-etm.o
+183 -122
tools/perf/util/annotate.c
··· 49 .jump_arrows = true, 50 .annotate_src = true, 51 .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, 52 }; 53 54 static regex_t file_lineno; ··· 1109 if (perf_evsel__is_group_event(evsel)) 1110 nr = evsel->nr_members; 1111 1112 - size += sizeof(al->samples[0]) * nr; 1113 1114 al = zalloc(size); 1115 if (al) { ··· 1118 al->offset = args->offset; 1119 al->line = strdup(args->line); 1120 al->line_nr = args->line_nr; 1121 - al->samples_nr = nr; 1122 } 1123 1124 return al; ··· 1298 static int 1299 annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, 1300 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 1301 - int max_lines, struct annotation_line *queue, int addr_fmt_width) 1302 { 1303 struct disasm_line *dl = container_of(al, struct disasm_line, al); 1304 static const char *prev_line; ··· 1311 const char *color; 1312 struct annotation *notes = symbol__annotation(sym); 1313 1314 - for (i = 0; i < al->samples_nr; i++) { 1315 - struct annotation_data *sample = &al->samples[i]; 1316 1317 - if (sample->percent > max_percent) 1318 - max_percent = sample->percent; 1319 } 1320 1321 - if (al->samples_nr > nr_percent) 1322 - nr_percent = al->samples_nr; 1323 1324 if (max_percent < min_pcnt) 1325 return -1; ··· 1335 if (queue == al) 1336 break; 1337 annotation_line__print(queue, sym, start, evsel, len, 1338 - 0, 0, 1, NULL, addr_fmt_width); 1339 } 1340 } 1341 ··· 1357 } 1358 1359 for (i = 0; i < nr_percent; i++) { 1360 - struct annotation_data *sample = &al->samples[i]; 1361 1362 - color = get_percent_color(sample->percent); 1363 1364 if (symbol_conf.show_total_period) 1365 color_fprintf(stdout, color, " %11" PRIu64, 1366 - sample->he.period); 1367 else if (symbol_conf.show_nr_samples) 1368 color_fprintf(stdout, color, " %7" PRIu64, 1369 - sample->he.nr_samples); 1370 else 1371 - color_fprintf(stdout, color, " %7.2f", sample->percent); 1372 } 1373 1374 printf(" : "); ··· 1629 char symfs_filename[PATH_MAX]; 1630 struct kcore_extract kce; 1631 bool delete_extract = false; 1632 int stdout_fd[2]; 1633 int lineno = 0; 1634 int nline; ··· 1663 tmp, sizeof(tmp)) < 0) 1664 goto out; 1665 1666 strcpy(symfs_filename, tmp); 1667 } 1668 ··· 1750 out_remove_tmp: 1751 close(stdout_fd[0]); 1752 1753 - if (dso__needs_decompress(dso)) 1754 unlink(symfs_filename); 1755 1756 if (delete_extract) ··· 1763 goto out_free_command; 1764 } 1765 1766 - static void calc_percent(struct sym_hist *hist, 1767 - struct annotation_data *sample, 1768 s64 offset, s64 end) 1769 { 1770 unsigned int hits = 0; 1771 u64 period = 0; 1772 1773 while (offset < end) { 1774 - hits += hist->addr[offset].nr_samples; 1775 - period += hist->addr[offset].period; 1776 ++offset; 1777 } 1778 1779 - if (hist->nr_samples) { 1780 - sample->he.period = period; 1781 - sample->he.nr_samples = hits; 1782 - sample->percent = 100.0 * hits / hist->nr_samples; 1783 } 1784 } 1785 1786 static void annotation__calc_percent(struct annotation *notes, 1787 - struct perf_evsel *evsel, s64 len) 1788 { 1789 struct annotation_line *al, *next; 1790 1791 list_for_each_entry(al, &notes->src->source, node) { 1792 s64 end; 1793 - int i; 1794 1795 if (al->offset == -1) 1796 continue; ··· 1809 next = annotation_line__next(al, &notes->src->source); 1810 end = next ? next->offset : len; 1811 1812 - for (i = 0; i < al->samples_nr; i++) { 1813 - struct annotation_data *sample; 1814 - struct sym_hist *hist; 1815 1816 - hist = annotation__histogram(notes, evsel->idx + i); 1817 - sample = &al->samples[i]; 1818 1819 - calc_percent(hist, sample, al->offset, end); 1820 } 1821 } 1822 } ··· 1870 return symbol__disassemble(sym, &args); 1871 } 1872 1873 - static void insert_source_line(struct rb_root *root, struct annotation_line *al) 1874 { 1875 struct annotation_line *iter; 1876 struct rb_node **p = &root->rb_node; ··· 1884 1885 ret = strcmp(iter->path, al->path); 1886 if (ret == 0) { 1887 - for (i = 0; i < al->samples_nr; i++) 1888 - iter->samples[i].percent_sum += al->samples[i].percent; 1889 return; 1890 } 1891 ··· 1897 p = &(*p)->rb_right; 1898 } 1899 1900 - for (i = 0; i < al->samples_nr; i++) 1901 - al->samples[i].percent_sum = al->samples[i].percent; 1902 1903 rb_link_node(&al->rb_node, parent, p); 1904 rb_insert_color(&al->rb_node, root); ··· 1910 { 1911 int i; 1912 1913 - for (i = 0; i < a->samples_nr; i++) { 1914 - if (a->samples[i].percent_sum == b->samples[i].percent_sum) 1915 continue; 1916 - return a->samples[i].percent_sum > b->samples[i].percent_sum; 1917 } 1918 1919 return 0; ··· 1978 int i; 1979 1980 al = rb_entry(node, struct annotation_line, rb_node); 1981 - for (i = 0; i < al->samples_nr; i++) { 1982 - percent = al->samples[i].percent_sum; 1983 color = get_percent_color(percent); 1984 color_fprintf(stdout, color, " %7.2f", percent); 1985 ··· 2058 evsel_name = buf; 2059 } 2060 2061 - graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", 2062 width, width, symbol_conf.show_total_period ? "Period" : 2063 symbol_conf.show_nr_samples ? "Samples" : "Percent", 2064 - d_filename, evsel_name, h->nr_samples); 2065 2066 printf("%-*.*s----\n", 2067 graph_dotted_len, graph_dotted_len, graph_dotted_line); ··· 2083 2084 err = annotation_line__print(pos, sym, start, evsel, len, 2085 opts->min_pcnt, printed, opts->max_lines, 2086 - queue, addr_fmt_width); 2087 2088 switch (err) { 2089 case 0: ··· 2160 fputs(s, fp); 2161 } 2162 2163 - int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) 2164 { 2165 struct annotation *notes = symbol__annotation(sym); 2166 - struct annotation_write_ops ops = { 2167 .first_line = true, 2168 .obj = fp, 2169 .set_color = FILE__set_color, ··· 2178 list_for_each_entry(al, &notes->src->source, node) { 2179 if (annotation_line__filter(al, notes)) 2180 continue; 2181 - annotation_line__write(al, notes, &ops); 2182 fputc('\n', fp); 2183 - ops.first_line = false; 2184 } 2185 2186 return 0; 2187 } 2188 2189 - int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) 2190 { 2191 const char *ev_name = perf_evsel__name(evsel); 2192 char buf[1024]; ··· 2209 2210 fprintf(fp, "%s() %s\nEvent: %s\n\n", 2211 ms->sym->name, ms->map->dso->long_name, ev_name); 2212 - symbol__annotate_fprintf2(ms->sym, fp); 2213 2214 fclose(fp); 2215 err = 0; ··· 2379 } 2380 2381 static void annotation__calc_lines(struct annotation *notes, struct map *map, 2382 - struct rb_root *root) 2383 { 2384 struct annotation_line *al; 2385 struct rb_root tmp_root = RB_ROOT; ··· 2389 double percent_max = 0.0; 2390 int i; 2391 2392 - for (i = 0; i < al->samples_nr; i++) { 2393 - struct annotation_data *sample; 2394 2395 - sample = &al->samples[i]; 2396 2397 - if (sample->percent > percent_max) 2398 - percent_max = sample->percent; 2399 } 2400 2401 if (percent_max <= 0.5) ··· 2404 2405 al->path = get_srcline(map->dso, notes->start + al->offset, NULL, 2406 false, true, notes->start + al->offset); 2407 - insert_source_line(&tmp_root, al); 2408 } 2409 2410 resort_source_line(root, &tmp_root); 2411 } 2412 2413 static void symbol__calc_lines(struct symbol *sym, struct map *map, 2414 - struct rb_root *root) 2415 { 2416 struct annotation *notes = symbol__annotation(sym); 2417 2418 - annotation__calc_lines(notes, map, root); 2419 } 2420 2421 int symbol__tty_annotate2(struct symbol *sym, struct map *map, ··· 2425 { 2426 struct dso *dso = map->dso; 2427 struct rb_root source_line = RB_ROOT; 2428 - struct annotation *notes = symbol__annotation(sym); 2429 char buf[1024]; 2430 2431 if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) ··· 2433 2434 if (opts->print_lines) { 2435 srcline_full_filename = opts->full_path; 2436 - symbol__calc_lines(sym, map, &source_line); 2437 print_summary(&source_line, dso->long_name); 2438 } 2439 2440 - annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); 2441 - fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); 2442 - symbol__annotate_fprintf2(sym, stdout); 2443 2444 annotated_source__purge(symbol__annotation(sym)->src); 2445 ··· 2461 2462 if (opts->print_lines) { 2463 srcline_full_filename = opts->full_path; 2464 - symbol__calc_lines(sym, map, &source_line); 2465 print_summary(&source_line, dso->long_name); 2466 } 2467 ··· 2478 } 2479 2480 2481 - double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) 2482 { 2483 double percent_max = 0.0; 2484 int i; 2485 2486 for (i = 0; i < notes->nr_events; i++) { 2487 - if (al->samples[i].percent > percent_max) 2488 - percent_max = al->samples[i].percent; 2489 } 2490 2491 return percent_max; ··· 2531 2532 static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, 2533 bool first_line, bool current_entry, bool change_color, int width, 2534 - void *obj, 2535 int (*obj__set_color)(void *obj, int color), 2536 void (*obj__set_percent_color)(void *obj, double percent, bool current), 2537 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), ··· 2539 void (*obj__write_graph)(void *obj, int graph)) 2540 2541 { 2542 - double percent_max = annotation_line__max_percent(al, notes); 2543 int pcnt_width = annotation__pcnt_width(notes), 2544 cycles_width = annotation__cycles_width(notes); 2545 bool show_title = false; ··· 2558 int i; 2559 2560 for (i = 0; i < notes->nr_events; i++) { 2561 - obj__set_percent_color(obj, al->samples[i].percent, current_entry); 2562 if (notes->options->show_total_period) { 2563 - obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); 2564 } else if (notes->options->show_nr_samples) { 2565 obj__printf(obj, "%6" PRIu64 " ", 2566 - al->samples[i].he.nr_samples); 2567 } else { 2568 - obj__printf(obj, "%6.2f ", 2569 - al->samples[i].percent); 2570 } 2571 } 2572 } else { ··· 2687 } 2688 2689 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 2690 - struct annotation_write_ops *ops) 2691 { 2692 - __annotation_line__write(al, notes, ops->first_line, ops->current_entry, 2693 - ops->change_color, ops->width, ops->obj, 2694 - ops->set_color, ops->set_percent_color, 2695 - ops->set_jumps_percent_color, ops->printf, 2696 - ops->write_graph); 2697 } 2698 2699 int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, ··· 2735 out_free_offsets: 2736 zfree(&notes->offsets); 2737 return -1; 2738 - } 2739 - 2740 - int __annotation__scnprintf_samples_period(struct annotation *notes, 2741 - char *bf, size_t size, 2742 - struct perf_evsel *evsel, 2743 - bool show_freq) 2744 - { 2745 - const char *ev_name = perf_evsel__name(evsel); 2746 - char buf[1024], ref[30] = " show reference callgraph, "; 2747 - char sample_freq_str[64] = ""; 2748 - unsigned long nr_samples = 0; 2749 - int nr_members = 1; 2750 - bool enable_ref = false; 2751 - u64 nr_events = 0; 2752 - char unit; 2753 - int i; 2754 - 2755 - if (perf_evsel__is_group_event(evsel)) { 2756 - perf_evsel__group_desc(evsel, buf, sizeof(buf)); 2757 - ev_name = buf; 2758 - nr_members = evsel->nr_members; 2759 - } 2760 - 2761 - for (i = 0; i < nr_members; i++) { 2762 - struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); 2763 - 2764 - nr_samples += ah->nr_samples; 2765 - nr_events += ah->period; 2766 - } 2767 - 2768 - if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) 2769 - enable_ref = true; 2770 - 2771 - if (show_freq) 2772 - scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); 2773 - 2774 - nr_samples = convert_unit(nr_samples, &unit); 2775 - return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, 2776 - nr_samples, unit, evsel->nr_members > 1 ? "s" : "", 2777 - ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); 2778 } 2779 2780 #define ANNOTATION__CFG(n) \ ··· 2800 2801 annotation__default_options.show_total_period = symbol_conf.show_total_period; 2802 annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; 2803 }
··· 49 .jump_arrows = true, 50 .annotate_src = true, 51 .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, 52 + .percent_type = PERCENT_PERIOD_LOCAL, 53 }; 54 55 static regex_t file_lineno; ··· 1108 if (perf_evsel__is_group_event(evsel)) 1109 nr = evsel->nr_members; 1110 1111 + size += sizeof(al->data[0]) * nr; 1112 1113 al = zalloc(size); 1114 if (al) { ··· 1117 al->offset = args->offset; 1118 al->line = strdup(args->line); 1119 al->line_nr = args->line_nr; 1120 + al->data_nr = nr; 1121 } 1122 1123 return al; ··· 1297 static int 1298 annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, 1299 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 1300 + int max_lines, struct annotation_line *queue, int addr_fmt_width, 1301 + int percent_type) 1302 { 1303 struct disasm_line *dl = container_of(al, struct disasm_line, al); 1304 static const char *prev_line; ··· 1309 const char *color; 1310 struct annotation *notes = symbol__annotation(sym); 1311 1312 + for (i = 0; i < al->data_nr; i++) { 1313 + double percent; 1314 1315 + percent = annotation_data__percent(&al->data[i], 1316 + percent_type); 1317 + 1318 + if (percent > max_percent) 1319 + max_percent = percent; 1320 } 1321 1322 + if (al->data_nr > nr_percent) 1323 + nr_percent = al->data_nr; 1324 1325 if (max_percent < min_pcnt) 1326 return -1; ··· 1330 if (queue == al) 1331 break; 1332 annotation_line__print(queue, sym, start, evsel, len, 1333 + 0, 0, 1, NULL, addr_fmt_width, 1334 + percent_type); 1335 } 1336 } 1337 ··· 1351 } 1352 1353 for (i = 0; i < nr_percent; i++) { 1354 + struct annotation_data *data = &al->data[i]; 1355 + double percent; 1356 1357 + percent = annotation_data__percent(data, percent_type); 1358 + color = get_percent_color(percent); 1359 1360 if (symbol_conf.show_total_period) 1361 color_fprintf(stdout, color, " %11" PRIu64, 1362 + data->he.period); 1363 else if (symbol_conf.show_nr_samples) 1364 color_fprintf(stdout, color, " %7" PRIu64, 1365 + data->he.nr_samples); 1366 else 1367 + color_fprintf(stdout, color, " %7.2f", percent); 1368 } 1369 1370 printf(" : "); ··· 1621 char symfs_filename[PATH_MAX]; 1622 struct kcore_extract kce; 1623 bool delete_extract = false; 1624 + bool decomp = false; 1625 int stdout_fd[2]; 1626 int lineno = 0; 1627 int nline; ··· 1654 tmp, sizeof(tmp)) < 0) 1655 goto out; 1656 1657 + decomp = true; 1658 strcpy(symfs_filename, tmp); 1659 } 1660 ··· 1740 out_remove_tmp: 1741 close(stdout_fd[0]); 1742 1743 + if (decomp) 1744 unlink(symfs_filename); 1745 1746 if (delete_extract) ··· 1753 goto out_free_command; 1754 } 1755 1756 + static void calc_percent(struct sym_hist *sym_hist, 1757 + struct hists *hists, 1758 + struct annotation_data *data, 1759 s64 offset, s64 end) 1760 { 1761 unsigned int hits = 0; 1762 u64 period = 0; 1763 1764 while (offset < end) { 1765 + hits += sym_hist->addr[offset].nr_samples; 1766 + period += sym_hist->addr[offset].period; 1767 ++offset; 1768 } 1769 1770 + if (sym_hist->nr_samples) { 1771 + data->he.period = period; 1772 + data->he.nr_samples = hits; 1773 + data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; 1774 } 1775 + 1776 + if (hists->stats.nr_non_filtered_samples) 1777 + data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; 1778 + 1779 + if (sym_hist->period) 1780 + data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; 1781 + 1782 + if (hists->stats.total_period) 1783 + data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; 1784 } 1785 1786 static void annotation__calc_percent(struct annotation *notes, 1787 + struct perf_evsel *leader, s64 len) 1788 { 1789 struct annotation_line *al, *next; 1790 + struct perf_evsel *evsel; 1791 1792 list_for_each_entry(al, &notes->src->source, node) { 1793 s64 end; 1794 + int i = 0; 1795 1796 if (al->offset == -1) 1797 continue; ··· 1788 next = annotation_line__next(al, &notes->src->source); 1789 end = next ? next->offset : len; 1790 1791 + for_each_group_evsel(evsel, leader) { 1792 + struct hists *hists = evsel__hists(evsel); 1793 + struct annotation_data *data; 1794 + struct sym_hist *sym_hist; 1795 1796 + BUG_ON(i >= al->data_nr); 1797 1798 + sym_hist = annotation__histogram(notes, evsel->idx); 1799 + data = &al->data[i++]; 1800 + 1801 + calc_percent(sym_hist, hists, data, al->offset, end); 1802 } 1803 } 1804 } ··· 1846 return symbol__disassemble(sym, &args); 1847 } 1848 1849 + static void insert_source_line(struct rb_root *root, struct annotation_line *al, 1850 + struct annotation_options *opts) 1851 { 1852 struct annotation_line *iter; 1853 struct rb_node **p = &root->rb_node; ··· 1859 1860 ret = strcmp(iter->path, al->path); 1861 if (ret == 0) { 1862 + for (i = 0; i < al->data_nr; i++) { 1863 + iter->data[i].percent_sum += annotation_data__percent(&al->data[i], 1864 + opts->percent_type); 1865 + } 1866 return; 1867 } 1868 ··· 1870 p = &(*p)->rb_right; 1871 } 1872 1873 + for (i = 0; i < al->data_nr; i++) { 1874 + al->data[i].percent_sum = annotation_data__percent(&al->data[i], 1875 + opts->percent_type); 1876 + } 1877 1878 rb_link_node(&al->rb_node, parent, p); 1879 rb_insert_color(&al->rb_node, root); ··· 1881 { 1882 int i; 1883 1884 + for (i = 0; i < a->data_nr; i++) { 1885 + if (a->data[i].percent_sum == b->data[i].percent_sum) 1886 continue; 1887 + return a->data[i].percent_sum > b->data[i].percent_sum; 1888 } 1889 1890 return 0; ··· 1949 int i; 1950 1951 al = rb_entry(node, struct annotation_line, rb_node); 1952 + for (i = 0; i < al->data_nr; i++) { 1953 + percent = al->data[i].percent_sum; 1954 color = get_percent_color(percent); 1955 color_fprintf(stdout, color, " %7.2f", percent); 1956 ··· 2029 evsel_name = buf; 2030 } 2031 2032 + graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " 2033 + "percent: %s)\n", 2034 width, width, symbol_conf.show_total_period ? "Period" : 2035 symbol_conf.show_nr_samples ? "Samples" : "Percent", 2036 + d_filename, evsel_name, h->nr_samples, 2037 + percent_type_str(opts->percent_type)); 2038 2039 printf("%-*.*s----\n", 2040 graph_dotted_len, graph_dotted_len, graph_dotted_line); ··· 2052 2053 err = annotation_line__print(pos, sym, start, evsel, len, 2054 opts->min_pcnt, printed, opts->max_lines, 2055 + queue, addr_fmt_width, opts->percent_type); 2056 2057 switch (err) { 2058 case 0: ··· 2129 fputs(s, fp); 2130 } 2131 2132 + static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, 2133 + struct annotation_options *opts) 2134 { 2135 struct annotation *notes = symbol__annotation(sym); 2136 + struct annotation_write_ops wops = { 2137 .first_line = true, 2138 .obj = fp, 2139 .set_color = FILE__set_color, ··· 2146 list_for_each_entry(al, &notes->src->source, node) { 2147 if (annotation_line__filter(al, notes)) 2148 continue; 2149 + annotation_line__write(al, notes, &wops, opts); 2150 fputc('\n', fp); 2151 + wops.first_line = false; 2152 } 2153 2154 return 0; 2155 } 2156 2157 + int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, 2158 + struct annotation_options *opts) 2159 { 2160 const char *ev_name = perf_evsel__name(evsel); 2161 char buf[1024]; ··· 2176 2177 fprintf(fp, "%s() %s\nEvent: %s\n\n", 2178 ms->sym->name, ms->map->dso->long_name, ev_name); 2179 + symbol__annotate_fprintf2(ms->sym, fp, opts); 2180 2181 fclose(fp); 2182 err = 0; ··· 2346 } 2347 2348 static void annotation__calc_lines(struct annotation *notes, struct map *map, 2349 + struct rb_root *root, 2350 + struct annotation_options *opts) 2351 { 2352 struct annotation_line *al; 2353 struct rb_root tmp_root = RB_ROOT; ··· 2355 double percent_max = 0.0; 2356 int i; 2357 2358 + for (i = 0; i < al->data_nr; i++) { 2359 + double percent; 2360 2361 + percent = annotation_data__percent(&al->data[i], 2362 + opts->percent_type); 2363 2364 + if (percent > percent_max) 2365 + percent_max = percent; 2366 } 2367 2368 if (percent_max <= 0.5) ··· 2369 2370 al->path = get_srcline(map->dso, notes->start + al->offset, NULL, 2371 false, true, notes->start + al->offset); 2372 + insert_source_line(&tmp_root, al, opts); 2373 } 2374 2375 resort_source_line(root, &tmp_root); 2376 } 2377 2378 static void symbol__calc_lines(struct symbol *sym, struct map *map, 2379 + struct rb_root *root, 2380 + struct annotation_options *opts) 2381 { 2382 struct annotation *notes = symbol__annotation(sym); 2383 2384 + annotation__calc_lines(notes, map, root, opts); 2385 } 2386 2387 int symbol__tty_annotate2(struct symbol *sym, struct map *map, ··· 2389 { 2390 struct dso *dso = map->dso; 2391 struct rb_root source_line = RB_ROOT; 2392 + struct hists *hists = evsel__hists(evsel); 2393 char buf[1024]; 2394 2395 if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) ··· 2397 2398 if (opts->print_lines) { 2399 srcline_full_filename = opts->full_path; 2400 + symbol__calc_lines(sym, map, &source_line, opts); 2401 print_summary(&source_line, dso->long_name); 2402 } 2403 2404 + hists__scnprintf_title(hists, buf, sizeof(buf)); 2405 + fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", 2406 + buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); 2407 + symbol__annotate_fprintf2(sym, stdout, opts); 2408 2409 annotated_source__purge(symbol__annotation(sym)->src); 2410 ··· 2424 2425 if (opts->print_lines) { 2426 srcline_full_filename = opts->full_path; 2427 + symbol__calc_lines(sym, map, &source_line, opts); 2428 print_summary(&source_line, dso->long_name); 2429 } 2430 ··· 2441 } 2442 2443 2444 + static double annotation_line__max_percent(struct annotation_line *al, 2445 + struct annotation *notes, 2446 + unsigned int percent_type) 2447 { 2448 double percent_max = 0.0; 2449 int i; 2450 2451 for (i = 0; i < notes->nr_events; i++) { 2452 + double percent; 2453 + 2454 + percent = annotation_data__percent(&al->data[i], 2455 + percent_type); 2456 + 2457 + if (percent > percent_max) 2458 + percent_max = percent; 2459 } 2460 2461 return percent_max; ··· 2487 2488 static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, 2489 bool first_line, bool current_entry, bool change_color, int width, 2490 + void *obj, unsigned int percent_type, 2491 int (*obj__set_color)(void *obj, int color), 2492 void (*obj__set_percent_color)(void *obj, double percent, bool current), 2493 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), ··· 2495 void (*obj__write_graph)(void *obj, int graph)) 2496 2497 { 2498 + double percent_max = annotation_line__max_percent(al, notes, percent_type); 2499 int pcnt_width = annotation__pcnt_width(notes), 2500 cycles_width = annotation__cycles_width(notes); 2501 bool show_title = false; ··· 2514 int i; 2515 2516 for (i = 0; i < notes->nr_events; i++) { 2517 + double percent; 2518 + 2519 + percent = annotation_data__percent(&al->data[i], percent_type); 2520 + 2521 + obj__set_percent_color(obj, percent, current_entry); 2522 if (notes->options->show_total_period) { 2523 + obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); 2524 } else if (notes->options->show_nr_samples) { 2525 obj__printf(obj, "%6" PRIu64 " ", 2526 + al->data[i].he.nr_samples); 2527 } else { 2528 + obj__printf(obj, "%6.2f ", percent); 2529 } 2530 } 2531 } else { ··· 2640 } 2641 2642 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 2643 + struct annotation_write_ops *wops, 2644 + struct annotation_options *opts) 2645 { 2646 + __annotation_line__write(al, notes, wops->first_line, wops->current_entry, 2647 + wops->change_color, wops->width, wops->obj, 2648 + opts->percent_type, 2649 + wops->set_color, wops->set_percent_color, 2650 + wops->set_jumps_percent_color, wops->printf, 2651 + wops->write_graph); 2652 } 2653 2654 int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, ··· 2686 out_free_offsets: 2687 zfree(&notes->offsets); 2688 return -1; 2689 } 2690 2691 #define ANNOTATION__CFG(n) \ ··· 2791 2792 annotation__default_options.show_total_period = symbol_conf.show_total_period; 2793 annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; 2794 + } 2795 + 2796 + static unsigned int parse_percent_type(char *str1, char *str2) 2797 + { 2798 + unsigned int type = (unsigned int) -1; 2799 + 2800 + if (!strcmp("period", str1)) { 2801 + if (!strcmp("local", str2)) 2802 + type = PERCENT_PERIOD_LOCAL; 2803 + else if (!strcmp("global", str2)) 2804 + type = PERCENT_PERIOD_GLOBAL; 2805 + } 2806 + 2807 + if (!strcmp("hits", str1)) { 2808 + if (!strcmp("local", str2)) 2809 + type = PERCENT_HITS_LOCAL; 2810 + else if (!strcmp("global", str2)) 2811 + type = PERCENT_HITS_GLOBAL; 2812 + } 2813 + 2814 + return type; 2815 + } 2816 + 2817 + int annotate_parse_percent_type(const struct option *opt, const char *_str, 2818 + int unset __maybe_unused) 2819 + { 2820 + struct annotation_options *opts = opt->value; 2821 + unsigned int type; 2822 + char *str1, *str2; 2823 + int err = -1; 2824 + 2825 + str1 = strdup(_str); 2826 + if (!str1) 2827 + return -ENOMEM; 2828 + 2829 + str2 = strchr(str1, '-'); 2830 + if (!str2) 2831 + goto out; 2832 + 2833 + *str2++ = 0; 2834 + 2835 + type = parse_percent_type(str1, str2); 2836 + if (type == (unsigned int) -1) 2837 + type = parse_percent_type(str2, str1); 2838 + if (type != (unsigned int) -1) { 2839 + opts->percent_type = type; 2840 + err = 0; 2841 + } 2842 + 2843 + out: 2844 + free(str1); 2845 + return err; 2846 }
+40 -14
tools/perf/util/annotate.h
··· 11 #include <linux/list.h> 12 #include <linux/rbtree.h> 13 #include <pthread.h> 14 15 struct ins_ops; 16 ··· 83 int context; 84 const char *objdump_path; 85 const char *disassembler_style; 86 }; 87 88 enum { ··· 103 u64 period; 104 }; 105 106 struct annotation_data { 107 - double percent; 108 double percent_sum; 109 struct sym_hist_entry he; 110 }; ··· 132 char *path; 133 u32 idx; 134 int idx_asm; 135 - int samples_nr; 136 - struct annotation_data samples[0]; 137 }; 138 139 struct disasm_line { ··· 143 /* This needs to be at the end. */ 144 struct annotation_line al; 145 }; 146 147 static inline struct disasm_line *disasm_line(struct annotation_line *al) 148 { ··· 200 void (*write_graph)(void *obj, int graph); 201 }; 202 203 - double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); 204 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 205 - struct annotation_write_ops *ops); 206 207 int __annotation__scnprintf_samples_period(struct annotation *notes, 208 char *bf, size_t size, 209 struct perf_evsel *evsel, 210 bool show_freq); 211 - 212 - static inline int annotation__scnprintf_samples_period(struct annotation *notes, 213 - char *bf, size_t size, 214 - struct perf_evsel *evsel) 215 - { 216 - return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); 217 - } 218 219 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 220 size_t disasm__fprintf(struct list_head *head, FILE *fp); ··· 364 int symbol__annotate_printf(struct symbol *sym, struct map *map, 365 struct perf_evsel *evsel, 366 struct annotation_options *options); 367 - int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); 368 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 369 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 370 void annotated_source__purge(struct annotated_source *as); 371 372 - int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel); 373 374 bool ui__has_annotation(void); 375 ··· 397 398 void annotation_config__init(void); 399 400 #endif /* __PERF_ANNOTATE_H */
··· 11 #include <linux/list.h> 12 #include <linux/rbtree.h> 13 #include <pthread.h> 14 + #include <asm/bug.h> 15 16 struct ins_ops; 17 ··· 82 int context; 83 const char *objdump_path; 84 const char *disassembler_style; 85 + unsigned int percent_type; 86 }; 87 88 enum { ··· 101 u64 period; 102 }; 103 104 + enum { 105 + PERCENT_HITS_LOCAL, 106 + PERCENT_HITS_GLOBAL, 107 + PERCENT_PERIOD_LOCAL, 108 + PERCENT_PERIOD_GLOBAL, 109 + PERCENT_MAX, 110 + }; 111 + 112 struct annotation_data { 113 + double percent[PERCENT_MAX]; 114 double percent_sum; 115 struct sym_hist_entry he; 116 }; ··· 122 char *path; 123 u32 idx; 124 int idx_asm; 125 + int data_nr; 126 + struct annotation_data data[0]; 127 }; 128 129 struct disasm_line { ··· 133 /* This needs to be at the end. */ 134 struct annotation_line al; 135 }; 136 + 137 + static inline double annotation_data__percent(struct annotation_data *data, 138 + unsigned int which) 139 + { 140 + return which < PERCENT_MAX ? data->percent[which] : -1; 141 + } 142 + 143 + static inline const char *percent_type_str(unsigned int type) 144 + { 145 + static const char *str[PERCENT_MAX] = { 146 + "local hits", 147 + "global hits", 148 + "local period", 149 + "global period", 150 + }; 151 + 152 + if (WARN_ON(type >= PERCENT_MAX)) 153 + return "N/A"; 154 + 155 + return str[type]; 156 + } 157 158 static inline struct disasm_line *disasm_line(struct annotation_line *al) 159 { ··· 169 void (*write_graph)(void *obj, int graph); 170 }; 171 172 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 173 + struct annotation_write_ops *ops, 174 + struct annotation_options *opts); 175 176 int __annotation__scnprintf_samples_period(struct annotation *notes, 177 char *bf, size_t size, 178 struct perf_evsel *evsel, 179 bool show_freq); 180 181 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 182 size_t disasm__fprintf(struct list_head *head, FILE *fp); ··· 340 int symbol__annotate_printf(struct symbol *sym, struct map *map, 341 struct perf_evsel *evsel, 342 struct annotation_options *options); 343 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 344 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 345 void annotated_source__purge(struct annotated_source *as); 346 347 + int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, 348 + struct annotation_options *opts); 349 350 bool ui__has_annotation(void); 351 ··· 373 374 void annotation_config__init(void); 375 376 + int annotate_parse_percent_type(const struct option *opt, const char *_str, 377 + int unset); 378 #endif /* __PERF_ANNOTATE_H */
+6
tools/perf/util/auxtrace.c
··· 56 #include "intel-pt.h" 57 #include "intel-bts.h" 58 #include "arm-spe.h" 59 60 #include "sane_ctype.h" 61 #include "symbol/kallsyms.h" ··· 203 for (i = 0; i < queues->nr_queues; i++) { 204 list_splice_tail(&queues->queue_array[i].head, 205 &queue_array[i].head); 206 queue_array[i].priv = queues->queue_array[i].priv; 207 } 208 ··· 924 return arm_spe_process_auxtrace_info(event, session); 925 case PERF_AUXTRACE_CS_ETM: 926 return cs_etm__process_auxtrace_info(event, session); 927 case PERF_AUXTRACE_UNKNOWN: 928 default: 929 return -EINVAL;
··· 56 #include "intel-pt.h" 57 #include "intel-bts.h" 58 #include "arm-spe.h" 59 + #include "s390-cpumsf.h" 60 61 #include "sane_ctype.h" 62 #include "symbol/kallsyms.h" ··· 202 for (i = 0; i < queues->nr_queues; i++) { 203 list_splice_tail(&queues->queue_array[i].head, 204 &queue_array[i].head); 205 + queue_array[i].tid = queues->queue_array[i].tid; 206 + queue_array[i].cpu = queues->queue_array[i].cpu; 207 + queue_array[i].set = queues->queue_array[i].set; 208 queue_array[i].priv = queues->queue_array[i].priv; 209 } 210 ··· 920 return arm_spe_process_auxtrace_info(event, session); 921 case PERF_AUXTRACE_CS_ETM: 922 return cs_etm__process_auxtrace_info(event, session); 923 + case PERF_AUXTRACE_S390_CPUMSF: 924 + return s390_cpumsf_process_auxtrace_info(event, session); 925 case PERF_AUXTRACE_UNKNOWN: 926 default: 927 return -EINVAL;
+1
tools/perf/util/auxtrace.h
··· 44 PERF_AUXTRACE_INTEL_BTS, 45 PERF_AUXTRACE_CS_ETM, 46 PERF_AUXTRACE_ARM_SPE, 47 }; 48 49 enum itrace_period_type {
··· 44 PERF_AUXTRACE_INTEL_BTS, 45 PERF_AUXTRACE_CS_ETM, 46 PERF_AUXTRACE_ARM_SPE, 47 + PERF_AUXTRACE_S390_CPUMSF, 48 }; 49 50 enum itrace_period_type {
+30 -18
tools/perf/util/bpf-loader.c
··· 1529 bpf_object__for_each_safe(obj, objtmp) \ 1530 bpf_map__for_each(pos, obj) 1531 1532 - #define bpf__for_each_stdout_map(pos, obj, objtmp) \ 1533 bpf__for_each_map(pos, obj, objtmp) \ 1534 if (bpf_map__name(pos) && \ 1535 - (strcmp("__bpf_stdout__", \ 1536 bpf_map__name(pos)) == 0)) 1537 1538 - int bpf__setup_stdout(struct perf_evlist *evlist) 1539 { 1540 struct bpf_map_priv *tmpl_priv = NULL; 1541 struct bpf_object *obj, *tmp; ··· 1544 int err; 1545 bool need_init = false; 1546 1547 - bpf__for_each_stdout_map(map, obj, tmp) { 1548 struct bpf_map_priv *priv = bpf_map__priv(map); 1549 1550 if (IS_ERR(priv)) 1551 - return -BPF_LOADER_ERRNO__INTERNAL; 1552 1553 /* 1554 * No need to check map type: type should have been ··· 1561 } 1562 1563 if (!need_init) 1564 - return 0; 1565 1566 if (!tmpl_priv) { 1567 - err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", 1568 - NULL); 1569 if (err) { 1570 - pr_debug("ERROR: failed to create bpf-output event\n"); 1571 - return -err; 1572 } 1573 1574 evsel = perf_evlist__last(evlist); 1575 } 1576 1577 - bpf__for_each_stdout_map(map, obj, tmp) { 1578 struct bpf_map_priv *priv = bpf_map__priv(map); 1579 1580 if (IS_ERR(priv)) 1581 - return -BPF_LOADER_ERRNO__INTERNAL; 1582 if (priv) 1583 continue; 1584 1585 if (tmpl_priv) { 1586 priv = bpf_map_priv__clone(tmpl_priv); 1587 if (!priv) 1588 - return -ENOMEM; 1589 1590 err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); 1591 if (err) { 1592 bpf_map_priv__clear(map, priv); 1593 - return err; 1594 } 1595 } else if (evsel) { 1596 struct bpf_map_op *op; 1597 1598 op = bpf_map__add_newop(map, NULL); 1599 if (IS_ERR(op)) 1600 - return PTR_ERR(op); 1601 op->op_type = BPF_MAP_OP_SET_EVSEL; 1602 op->v.evsel = evsel; 1603 } 1604 } 1605 1606 - return 0; 1607 } 1608 1609 #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) ··· 1792 return 0; 1793 } 1794 1795 - int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, 1796 - int err, char *buf, size_t size) 1797 { 1798 bpf__strerror_head(err, buf, size); 1799 bpf__strerror_end(buf, size);
··· 1529 bpf_object__for_each_safe(obj, objtmp) \ 1530 bpf_map__for_each(pos, obj) 1531 1532 + #define bpf__for_each_map_named(pos, obj, objtmp, name) \ 1533 bpf__for_each_map(pos, obj, objtmp) \ 1534 if (bpf_map__name(pos) && \ 1535 + (strcmp(name, \ 1536 bpf_map__name(pos)) == 0)) 1537 1538 + struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name) 1539 { 1540 struct bpf_map_priv *tmpl_priv = NULL; 1541 struct bpf_object *obj, *tmp; ··· 1544 int err; 1545 bool need_init = false; 1546 1547 + bpf__for_each_map_named(map, obj, tmp, name) { 1548 struct bpf_map_priv *priv = bpf_map__priv(map); 1549 1550 if (IS_ERR(priv)) 1551 + return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); 1552 1553 /* 1554 * No need to check map type: type should have been ··· 1561 } 1562 1563 if (!need_init) 1564 + return NULL; 1565 1566 if (!tmpl_priv) { 1567 + char *event_definition = NULL; 1568 + 1569 + if (asprintf(&event_definition, "bpf-output/no-inherit=1,name=%s/", name) < 0) 1570 + return ERR_PTR(-ENOMEM); 1571 + 1572 + err = parse_events(evlist, event_definition, NULL); 1573 + free(event_definition); 1574 + 1575 if (err) { 1576 + pr_debug("ERROR: failed to create the \"%s\" bpf-output event\n", name); 1577 + return ERR_PTR(-err); 1578 } 1579 1580 evsel = perf_evlist__last(evlist); 1581 } 1582 1583 + bpf__for_each_map_named(map, obj, tmp, name) { 1584 struct bpf_map_priv *priv = bpf_map__priv(map); 1585 1586 if (IS_ERR(priv)) 1587 + return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); 1588 if (priv) 1589 continue; 1590 1591 if (tmpl_priv) { 1592 priv = bpf_map_priv__clone(tmpl_priv); 1593 if (!priv) 1594 + return ERR_PTR(-ENOMEM); 1595 1596 err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); 1597 if (err) { 1598 bpf_map_priv__clear(map, priv); 1599 + return ERR_PTR(err); 1600 } 1601 } else if (evsel) { 1602 struct bpf_map_op *op; 1603 1604 op = bpf_map__add_newop(map, NULL); 1605 if (IS_ERR(op)) 1606 + return ERR_PTR(PTR_ERR(op)); 1607 op->op_type = BPF_MAP_OP_SET_EVSEL; 1608 op->v.evsel = evsel; 1609 } 1610 } 1611 1612 + return evsel; 1613 + } 1614 + 1615 + int bpf__setup_stdout(struct perf_evlist *evlist) 1616 + { 1617 + struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); 1618 + return IS_ERR(evsel) ? PTR_ERR(evsel) : 0; 1619 } 1620 1621 #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) ··· 1780 return 0; 1781 } 1782 1783 + int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, 1784 + int err, char *buf, size_t size) 1785 { 1786 bpf__strerror_head(err, buf, size); 1787 bpf__strerror_end(buf, size);
+17 -6
tools/perf/util/bpf-loader.h
··· 43 __BPF_LOADER_ERRNO__END, 44 }; 45 46 struct bpf_object; 47 struct parse_events_term; 48 #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" ··· 83 int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); 84 85 int bpf__setup_stdout(struct perf_evlist *evlist); 86 - int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, 87 - char *buf, size_t size); 88 - 89 #else 90 #include <errno.h> 91 ··· 136 bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) 137 { 138 return 0; 139 } 140 141 static inline int ··· 199 } 200 201 static inline int 202 - bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, 203 - int err __maybe_unused, char *buf, 204 - size_t size) 205 { 206 return __bpf_strerror(buf, size); 207 } 208 #endif 209 #endif
··· 43 __BPF_LOADER_ERRNO__END, 44 }; 45 46 + struct perf_evsel; 47 struct bpf_object; 48 struct parse_events_term; 49 #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" ··· 82 int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); 83 84 int bpf__setup_stdout(struct perf_evlist *evlist); 85 + struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name); 86 + int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size); 87 #else 88 #include <errno.h> 89 ··· 136 bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) 137 { 138 return 0; 139 + } 140 + 141 + static inline struct perf_evsel * 142 + bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused) 143 + { 144 + return NULL; 145 } 146 147 static inline int ··· 193 } 194 195 static inline int 196 + bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, 197 + int err __maybe_unused, char *buf, size_t size) 198 { 199 return __bpf_strerror(buf, size); 200 } 201 + 202 #endif 203 + 204 + static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size) 205 + { 206 + return bpf__strerror_setup_output_event(evlist, err, buf, size); 207 + } 208 #endif
+2
tools/perf/util/compress.h
··· 4 5 #ifdef HAVE_ZLIB_SUPPORT 6 int gzip_decompress_to_file(const char *input, int output_fd); 7 #endif 8 9 #ifdef HAVE_LZMA_SUPPORT 10 int lzma_decompress_to_file(const char *input, int output_fd); 11 #endif 12 13 #endif /* PERF_COMPRESS_H */
··· 4 5 #ifdef HAVE_ZLIB_SUPPORT 6 int gzip_decompress_to_file(const char *input, int output_fd); 7 + bool gzip_is_compressed(const char *input); 8 #endif 9 10 #ifdef HAVE_LZMA_SUPPORT 11 int lzma_decompress_to_file(const char *input, int output_fd); 12 + bool lzma_is_compressed(const char *input); 13 #endif 14 15 #endif /* PERF_COMPRESS_H */
+3 -3
tools/perf/util/data-convert-bt.c
··· 310 if (flags & FIELD_IS_DYNAMIC) { 311 unsigned long long tmp_val; 312 313 - tmp_val = pevent_read_number(fmtf->event->pevent, 314 - data + offset, len); 315 offset = tmp_val; 316 len = offset >> 16; 317 offset &= 0xffff; ··· 353 else { 354 unsigned long long value_int; 355 356 - value_int = pevent_read_number( 357 fmtf->event->pevent, 358 data + offset + i * len, len); 359
··· 310 if (flags & FIELD_IS_DYNAMIC) { 311 unsigned long long tmp_val; 312 313 + tmp_val = tep_read_number(fmtf->event->pevent, 314 + data + offset, len); 315 offset = tmp_val; 316 len = offset >> 16; 317 offset &= 0xffff; ··· 353 else { 354 unsigned long long value_int; 355 356 + value_int = tep_read_number( 357 fmtf->event->pevent, 358 data + offset + i * len, len); 359
+53 -58
tools/perf/util/dso.c
··· 189 return ret; 190 } 191 192 static const struct { 193 const char *fmt; 194 int (*decompress)(const char *input, int output); 195 } compressions[] = { 196 #ifdef HAVE_ZLIB_SUPPORT 197 - { "gz", gzip_decompress_to_file }, 198 #endif 199 #ifdef HAVE_LZMA_SUPPORT 200 - { "xz", lzma_decompress_to_file }, 201 #endif 202 - { NULL, NULL }, 203 }; 204 205 - bool is_supported_compression(const char *ext) 206 { 207 unsigned i; 208 209 - for (i = 0; compressions[i].fmt; i++) { 210 if (!strcmp(ext, compressions[i].fmt)) 211 - return true; 212 } 213 - return false; 214 } 215 216 bool is_kernel_module(const char *pathname, int cpumode) ··· 245 return m.kmod; 246 } 247 248 - bool decompress_to_file(const char *ext, const char *filename, int output_fd) 249 - { 250 - unsigned i; 251 - 252 - for (i = 0; compressions[i].fmt; i++) { 253 - if (!strcmp(ext, compressions[i].fmt)) 254 - return !compressions[i].decompress(filename, 255 - output_fd); 256 - } 257 - return false; 258 - } 259 - 260 bool dso__needs_decompress(struct dso *dso) 261 { 262 return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 263 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 264 } 265 266 - static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf) 267 { 268 int fd = -1; 269 - struct kmod_path m; 270 271 if (!dso__needs_decompress(dso)) 272 return -1; 273 274 - if (kmod_path__parse_ext(&m, dso->long_name)) 275 return -1; 276 277 - if (!m.comp) 278 - goto out; 279 280 fd = mkstemp(tmpbuf); 281 if (fd < 0) { 282 dso->load_errno = errno; 283 - goto out; 284 } 285 286 - if (!decompress_to_file(m.ext, name, fd)) { 287 dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; 288 close(fd); 289 fd = -1; 290 } 291 292 - out: 293 - free(m.ext); 294 return fd; 295 } 296 297 int dso__decompress_kmodule_fd(struct dso *dso, const char *name) 298 { 299 - char tmpbuf[] = KMOD_DECOMP_NAME; 300 - int fd; 301 - 302 - fd = decompress_kmodule(dso, name, tmpbuf); 303 - unlink(tmpbuf); 304 - return fd; 305 } 306 307 int dso__decompress_kmodule_path(struct dso *dso, const char *name, 308 char *pathname, size_t len) 309 { 310 - char tmpbuf[] = KMOD_DECOMP_NAME; 311 - int fd; 312 313 - fd = decompress_kmodule(dso, name, tmpbuf); 314 - if (fd < 0) { 315 - unlink(tmpbuf); 316 - return -1; 317 - } 318 - 319 - strncpy(pathname, tmpbuf, len); 320 close(fd); 321 - return 0; 322 } 323 324 /* ··· 331 * Returns 0 if there's no strdup error, -ENOMEM otherwise. 332 */ 333 int __kmod_path__parse(struct kmod_path *m, const char *path, 334 - bool alloc_name, bool alloc_ext) 335 { 336 const char *name = strrchr(path, '/'); 337 const char *ext = strrchr(path, '.'); ··· 371 return 0; 372 } 373 374 - if (is_supported_compression(ext + 1)) { 375 - m->comp = true; 376 ext -= 3; 377 - } 378 379 /* Check .ko extension only if there's enough name left. */ 380 if (ext > name) ··· 391 strxfrchar(m->name, '-', '_'); 392 } 393 394 - if (alloc_ext && m->comp) { 395 - m->ext = strdup(ext + 4); 396 - if (!m->ext) { 397 - free((void *) m->name); 398 - return -ENOMEM; 399 - } 400 - } 401 - 402 return 0; 403 } 404 ··· 403 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 404 405 /* _KMODULE_COMP should be next to _KMODULE */ 406 - if (m->kmod && m->comp) 407 dso->symtab_type++; 408 409 dso__set_short_name(dso, strdup(m->name), true); 410 } ··· 460 int fd = -EINVAL; 461 char *root_dir = (char *)""; 462 char *name = malloc(PATH_MAX); 463 464 if (!name) 465 return -ENOMEM; ··· 484 goto out; 485 } 486 487 strcpy(name, newpath); 488 } 489 490 fd = do_open(name); 491 492 - if (dso__needs_decompress(dso)) 493 unlink(name); 494 495 out: ··· 1212 dso->a2l_fails = 1; 1213 dso->kernel = DSO_TYPE_USER; 1214 dso->needs_swap = DSO_SWAP__UNSET; 1215 RB_CLEAR_NODE(&dso->rb_node); 1216 dso->root = NULL; 1217 INIT_LIST_HEAD(&dso->node);
··· 189 return ret; 190 } 191 192 + enum { 193 + COMP_ID__NONE = 0, 194 + }; 195 + 196 static const struct { 197 const char *fmt; 198 int (*decompress)(const char *input, int output); 199 + bool (*is_compressed)(const char *input); 200 } compressions[] = { 201 + [COMP_ID__NONE] = { .fmt = NULL, }, 202 #ifdef HAVE_ZLIB_SUPPORT 203 + { "gz", gzip_decompress_to_file, gzip_is_compressed }, 204 #endif 205 #ifdef HAVE_LZMA_SUPPORT 206 + { "xz", lzma_decompress_to_file, lzma_is_compressed }, 207 #endif 208 + { NULL, NULL, NULL }, 209 }; 210 211 + static int is_supported_compression(const char *ext) 212 { 213 unsigned i; 214 215 + for (i = 1; compressions[i].fmt; i++) { 216 if (!strcmp(ext, compressions[i].fmt)) 217 + return i; 218 } 219 + return COMP_ID__NONE; 220 } 221 222 bool is_kernel_module(const char *pathname, int cpumode) ··· 239 return m.kmod; 240 } 241 242 bool dso__needs_decompress(struct dso *dso) 243 { 244 return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 245 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 246 } 247 248 + static int decompress_kmodule(struct dso *dso, const char *name, 249 + char *pathname, size_t len) 250 { 251 + char tmpbuf[] = KMOD_DECOMP_NAME; 252 int fd = -1; 253 254 if (!dso__needs_decompress(dso)) 255 return -1; 256 257 + if (dso->comp == COMP_ID__NONE) 258 return -1; 259 260 + /* 261 + * We have proper compression id for DSO and yet the file 262 + * behind the 'name' can still be plain uncompressed object. 263 + * 264 + * The reason is behind the logic we open the DSO object files, 265 + * when we try all possible 'debug' objects until we find the 266 + * data. So even if the DSO is represented by 'krava.xz' module, 267 + * we can end up here opening ~/.debug/....23432432/debug' file 268 + * which is not compressed. 269 + * 270 + * To keep this transparent, we detect this and return the file 271 + * descriptor to the uncompressed file. 272 + */ 273 + if (!compressions[dso->comp].is_compressed(name)) 274 + return open(name, O_RDONLY); 275 276 fd = mkstemp(tmpbuf); 277 if (fd < 0) { 278 dso->load_errno = errno; 279 + return -1; 280 } 281 282 + if (compressions[dso->comp].decompress(name, fd)) { 283 dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; 284 close(fd); 285 fd = -1; 286 } 287 288 + if (!pathname || (fd < 0)) 289 + unlink(tmpbuf); 290 + 291 + if (pathname && (fd >= 0)) 292 + strncpy(pathname, tmpbuf, len); 293 + 294 return fd; 295 } 296 297 int dso__decompress_kmodule_fd(struct dso *dso, const char *name) 298 { 299 + return decompress_kmodule(dso, name, NULL, 0); 300 } 301 302 int dso__decompress_kmodule_path(struct dso *dso, const char *name, 303 char *pathname, size_t len) 304 { 305 + int fd = decompress_kmodule(dso, name, pathname, len); 306 307 close(fd); 308 + return fd >= 0 ? 0 : -1; 309 } 310 311 /* ··· 332 * Returns 0 if there's no strdup error, -ENOMEM otherwise. 333 */ 334 int __kmod_path__parse(struct kmod_path *m, const char *path, 335 + bool alloc_name) 336 { 337 const char *name = strrchr(path, '/'); 338 const char *ext = strrchr(path, '.'); ··· 372 return 0; 373 } 374 375 + m->comp = is_supported_compression(ext + 1); 376 + if (m->comp > COMP_ID__NONE) 377 ext -= 3; 378 379 /* Check .ko extension only if there's enough name left. */ 380 if (ext > name) ··· 393 strxfrchar(m->name, '-', '_'); 394 } 395 396 return 0; 397 } 398 ··· 413 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 414 415 /* _KMODULE_COMP should be next to _KMODULE */ 416 + if (m->kmod && m->comp) { 417 dso->symtab_type++; 418 + dso->comp = m->comp; 419 + } 420 421 dso__set_short_name(dso, strdup(m->name), true); 422 } ··· 468 int fd = -EINVAL; 469 char *root_dir = (char *)""; 470 char *name = malloc(PATH_MAX); 471 + bool decomp = false; 472 473 if (!name) 474 return -ENOMEM; ··· 491 goto out; 492 } 493 494 + decomp = true; 495 strcpy(name, newpath); 496 } 497 498 fd = do_open(name); 499 500 + if (decomp) 501 unlink(name); 502 503 out: ··· 1218 dso->a2l_fails = 1; 1219 dso->kernel = DSO_TYPE_USER; 1220 dso->needs_swap = DSO_SWAP__UNSET; 1221 + dso->comp = COMP_ID__NONE; 1222 RB_CLEAR_NODE(&dso->rb_node); 1223 dso->root = NULL; 1224 INIT_LIST_HEAD(&dso->node);
+5 -8
tools/perf/util/dso.h
··· 175 u16 short_name_len; 176 void *dwfl; /* DWARF debug info */ 177 struct auxtrace_cache *auxtrace_cache; 178 179 /* dso data file */ 180 struct { ··· 251 char dso__symtab_origin(const struct dso *dso); 252 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 253 char *root_dir, char *filename, size_t size); 254 - bool is_supported_compression(const char *ext); 255 bool is_kernel_module(const char *pathname, int cpumode); 256 - bool decompress_to_file(const char *ext, const char *filename, int output_fd); 257 bool dso__needs_decompress(struct dso *dso); 258 int dso__decompress_kmodule_fd(struct dso *dso, const char *name); 259 int dso__decompress_kmodule_path(struct dso *dso, const char *name, ··· 262 263 struct kmod_path { 264 char *name; 265 - char *ext; 266 - bool comp; 267 bool kmod; 268 }; 269 270 int __kmod_path__parse(struct kmod_path *m, const char *path, 271 - bool alloc_name, bool alloc_ext); 272 273 - #define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false, false) 274 - #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false) 275 - #define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true) 276 277 void dso__set_module_info(struct dso *dso, struct kmod_path *m, 278 struct machine *machine);
··· 175 u16 short_name_len; 176 void *dwfl; /* DWARF debug info */ 177 struct auxtrace_cache *auxtrace_cache; 178 + int comp; 179 180 /* dso data file */ 181 struct { ··· 250 char dso__symtab_origin(const struct dso *dso); 251 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 252 char *root_dir, char *filename, size_t size); 253 bool is_kernel_module(const char *pathname, int cpumode); 254 bool dso__needs_decompress(struct dso *dso); 255 int dso__decompress_kmodule_fd(struct dso *dso, const char *name); 256 int dso__decompress_kmodule_path(struct dso *dso, const char *name, ··· 263 264 struct kmod_path { 265 char *name; 266 + int comp; 267 bool kmod; 268 }; 269 270 int __kmod_path__parse(struct kmod_path *m, const char *path, 271 + bool alloc_name); 272 273 + #define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false) 274 + #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true) 275 276 void dso__set_module_info(struct dso *dso, struct kmod_path *m, 277 struct machine *machine);
+10 -3
tools/perf/util/event.c
··· 541 tgid, process, machine) < 0) 542 return -1; 543 544 545 - return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 546 - process, machine, mmap_data, 547 - proc_map_timeout); 548 } 549 550 if (machine__is_default_guest(machine))
··· 541 tgid, process, machine) < 0) 542 return -1; 543 544 + /* 545 + * send mmap only for thread group leader 546 + * see thread__init_map_groups 547 + */ 548 + if (pid == tgid && 549 + perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 550 + process, machine, mmap_data, 551 + proc_map_timeout)) 552 + return -1; 553 554 + return 0; 555 } 556 557 if (machine__is_default_guest(machine))
+1 -1
tools/perf/util/evlist.c
··· 803 if (*output == -1) { 804 *output = fd; 805 806 - if (perf_mmap__mmap(&maps[idx], mp, *output) < 0) 807 return -1; 808 } else { 809 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
··· 803 if (*output == -1) { 804 *output = fd; 805 806 + if (perf_mmap__mmap(&maps[idx], mp, *output, evlist_cpu) < 0) 807 return -1; 808 } else { 809 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
+1 -1
tools/perf/util/evsel.c
··· 2683 2684 struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) 2685 { 2686 - return pevent_find_field(evsel->tp_format, name); 2687 } 2688 2689 void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
··· 2683 2684 struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) 2685 { 2686 + return tep_find_field(evsel->tp_format, name); 2687 } 2688 2689 void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
+7
tools/perf/util/evsel.h
··· 452 return evsel->idx - evsel->leader->idx; 453 } 454 455 #define for_each_group_member(_evsel, _leader) \ 456 for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ 457 (_evsel) && (_evsel)->leader == (_leader); \ 458 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) 459
··· 452 return evsel->idx - evsel->leader->idx; 453 } 454 455 + /* Iterates group WITHOUT the leader. */ 456 #define for_each_group_member(_evsel, _leader) \ 457 for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ 458 + (_evsel) && (_evsel)->leader == (_leader); \ 459 + (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) 460 + 461 + /* Iterates group WITH the leader. */ 462 + #define for_each_group_evsel(_evsel, _leader) \ 463 + for ((_evsel) = _leader; \ 464 (_evsel) && (_evsel)->leader == (_leader); \ 465 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) 466
+3 -6
tools/perf/util/header.c
··· 279 if (!set) 280 return -ENOMEM; 281 282 - bitmap_zero(set, size); 283 - 284 p = (u64 *) set; 285 286 for (i = 0; (u64) i < BITS_TO_U64(size); i++) { ··· 1283 return -ENOMEM; 1284 } 1285 1286 - bitmap_zero(n->set, size); 1287 n->node = idx; 1288 n->size = size; 1289 ··· 3204 } 3205 3206 static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, 3207 - struct pevent *pevent) 3208 { 3209 struct event_format *event; 3210 char bf[128]; ··· 3218 return -1; 3219 } 3220 3221 - event = pevent_find_event(pevent, evsel->attr.config); 3222 if (event == NULL) { 3223 pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); 3224 return -1; ··· 3236 } 3237 3238 static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, 3239 - struct pevent *pevent) 3240 { 3241 struct perf_evsel *pos; 3242
··· 279 if (!set) 280 return -ENOMEM; 281 282 p = (u64 *) set; 283 284 for (i = 0; (u64) i < BITS_TO_U64(size); i++) { ··· 1285 return -ENOMEM; 1286 } 1287 1288 n->node = idx; 1289 n->size = size; 1290 ··· 3207 } 3208 3209 static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, 3210 + struct tep_handle *pevent) 3211 { 3212 struct event_format *event; 3213 char bf[128]; ··· 3221 return -1; 3222 } 3223 3224 + event = tep_find_event(pevent, evsel->attr.config); 3225 if (event == NULL) { 3226 pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); 3227 return -1; ··· 3239 } 3240 3241 static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, 3242 + struct tep_handle *pevent) 3243 { 3244 struct perf_evsel *pos; 3245
+29 -2
tools/perf/util/llvm-utils.c
··· 22 "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \ 23 "-Wno-unused-value -Wno-pointer-sign " \ 24 "-working-directory $WORKING_DIR " \ 25 - "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -" 26 27 struct llvm_param llvm_param = { 28 .clang_path = "clang", 29 .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, 30 .clang_opt = NULL, 31 .kbuild_dir = NULL, 32 .kbuild_opts = NULL, 33 .user_set_param = false, ··· 53 llvm_param.kbuild_opts = strdup(value); 54 else if (!strcmp(var, "dump-obj")) 55 llvm_param.dump_obj = !!perf_config_bool(var, value); 56 else { 57 pr_debug("Invalid LLVM config option: %s\n", value); 58 return -1; ··· 434 unsigned int kernel_version; 435 char linux_version_code_str[64]; 436 const char *clang_opt = llvm_param.clang_opt; 437 - char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; 438 char serr[STRERR_BUFSIZE]; 439 char *kbuild_dir = NULL, *kbuild_include_opts = NULL, 440 *perf_bpf_include_opts = NULL; 441 const char *template = llvm_param.clang_bpf_cmd_template; 442 char *command_echo = NULL, *command_out; 443 char *perf_include_dir = system_path(PERF_INCLUDE_DIR); 444 ··· 489 force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); 490 force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts); 491 force_set_env("WORKING_DIR", kbuild_dir ? : "."); 492 493 /* 494 * Since we may reset clang's working dir, path of source file ··· 561 free(obj_buf); 562 free(perf_bpf_include_opts); 563 free(perf_include_dir); 564 if (p_obj_buf) 565 *p_obj_buf = NULL; 566 if (p_obj_buf_sz)
··· 22 "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \ 23 "-Wno-unused-value -Wno-pointer-sign " \ 24 "-working-directory $WORKING_DIR " \ 25 + "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE" 26 27 struct llvm_param llvm_param = { 28 .clang_path = "clang", 29 + .llc_path = "llc", 30 .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, 31 .clang_opt = NULL, 32 + .opts = NULL, 33 .kbuild_dir = NULL, 34 .kbuild_opts = NULL, 35 .user_set_param = false, ··· 51 llvm_param.kbuild_opts = strdup(value); 52 else if (!strcmp(var, "dump-obj")) 53 llvm_param.dump_obj = !!perf_config_bool(var, value); 54 + else if (!strcmp(var, "opts")) 55 + llvm_param.opts = strdup(value); 56 else { 57 pr_debug("Invalid LLVM config option: %s\n", value); 58 return -1; ··· 430 unsigned int kernel_version; 431 char linux_version_code_str[64]; 432 const char *clang_opt = llvm_param.clang_opt; 433 + char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; 434 char serr[STRERR_BUFSIZE]; 435 char *kbuild_dir = NULL, *kbuild_include_opts = NULL, 436 *perf_bpf_include_opts = NULL; 437 const char *template = llvm_param.clang_bpf_cmd_template; 438 + char *pipe_template = NULL; 439 + const char *opts = llvm_param.opts; 440 char *command_echo = NULL, *command_out; 441 char *perf_include_dir = system_path(PERF_INCLUDE_DIR); 442 ··· 483 force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); 484 force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts); 485 force_set_env("WORKING_DIR", kbuild_dir ? : "."); 486 + 487 + if (opts) { 488 + err = search_program(llvm_param.llc_path, "llc", llc_path); 489 + if (err) { 490 + pr_err("ERROR:\tunable to find llc.\n" 491 + "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n" 492 + " \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n"); 493 + version_notice(); 494 + goto errout; 495 + } 496 + 497 + if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -", 498 + template, llc_path, opts) < 0) { 499 + pr_err("ERROR:\tnot enough memory to setup command line\n"); 500 + goto errout; 501 + } 502 + 503 + template = pipe_template; 504 + 505 + } 506 507 /* 508 * Since we may reset clang's working dir, path of source file ··· 535 free(obj_buf); 536 free(perf_bpf_include_opts); 537 free(perf_include_dir); 538 + free(pipe_template); 539 if (p_obj_buf) 540 *p_obj_buf = NULL; 541 if (p_obj_buf_sz)
+9
tools/perf/util/llvm-utils.h
··· 11 struct llvm_param { 12 /* Path of clang executable */ 13 const char *clang_path; 14 /* 15 * Template of clang bpf compiling. 5 env variables 16 * can be used: ··· 25 const char *clang_bpf_cmd_template; 26 /* Will be filled in $CLANG_OPTIONS */ 27 const char *clang_opt; 28 /* Where to find kbuild system */ 29 const char *kbuild_dir; 30 /*
··· 11 struct llvm_param { 12 /* Path of clang executable */ 13 const char *clang_path; 14 + /* Path of llc executable */ 15 + const char *llc_path; 16 /* 17 * Template of clang bpf compiling. 5 env variables 18 * can be used: ··· 23 const char *clang_bpf_cmd_template; 24 /* Will be filled in $CLANG_OPTIONS */ 25 const char *clang_opt; 26 + /* 27 + * If present it'll add -emit-llvm to $CLANG_OPTIONS to pipe 28 + * the clang output to llc, useful for new llvm options not 29 + * yet selectable via 'clang -mllvm option', such as -mattr=dwarfris 30 + * in clang 6.0/llvm 7 31 + */ 32 + const char *opts; 33 /* Where to find kbuild system */ 34 const char *kbuild_dir; 35 /*
+20
tools/perf/util/lzma.c
··· 3 #include <lzma.h> 4 #include <stdio.h> 5 #include <linux/compiler.h> 6 #include "compress.h" 7 #include "util.h" 8 #include "debug.h" 9 10 #define BUFSIZE 8192 11 ··· 102 err_fclose: 103 fclose(infile); 104 return err; 105 }
··· 3 #include <lzma.h> 4 #include <stdio.h> 5 #include <linux/compiler.h> 6 + #include <sys/types.h> 7 + #include <sys/stat.h> 8 + #include <fcntl.h> 9 #include "compress.h" 10 #include "util.h" 11 #include "debug.h" 12 + #include <unistd.h> 13 14 #define BUFSIZE 8192 15 ··· 98 err_fclose: 99 fclose(infile); 100 return err; 101 + } 102 + 103 + bool lzma_is_compressed(const char *input) 104 + { 105 + int fd = open(input, O_RDONLY); 106 + const uint8_t magic[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 }; 107 + char buf[6] = { 0 }; 108 + ssize_t rc; 109 + 110 + if (fd < 0) 111 + return -1; 112 + 113 + rc = read(fd, buf, sizeof(buf)); 114 + close(fd); 115 + return rc == sizeof(buf) ? 116 + memcmp(buf, magic, sizeof(buf)) == 0 : false; 117 }
+3 -1
tools/perf/util/machine.c
··· 1212 * Full name could reveal us kmod compression, so 1213 * we need to update the symtab_type if needed. 1214 */ 1215 - if (m->comp && is_kmod_dso(map->dso)) 1216 map->dso->symtab_type++; 1217 1218 return 0; 1219 }
··· 1212 * Full name could reveal us kmod compression, so 1213 * we need to update the symtab_type if needed. 1214 */ 1215 + if (m->comp && is_kmod_dso(map->dso)) { 1216 map->dso->symtab_type++; 1217 + map->dso->comp = m->comp; 1218 + } 1219 1220 return 0; 1221 }
+1 -1
tools/perf/util/machine.h
··· 265 int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 266 pid_t tid); 267 /* 268 - * For use with libtraceevent's pevent_set_function_resolver() 269 */ 270 char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp); 271
··· 265 int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 266 pid_t tid); 267 /* 268 + * For use with libtraceevent's tep_set_function_resolver() 269 */ 270 char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp); 271
+26 -18
tools/perf/util/map.c
··· 381 return map; 382 } 383 384 - int map__overlap(struct map *l, struct map *r) 385 - { 386 - if (l->start > r->start) { 387 - struct map *t = l; 388 - l = r; 389 - r = t; 390 - } 391 - 392 - if (l->end > r->start) 393 - return 1; 394 - 395 - return 0; 396 - } 397 - 398 size_t map__fprintf(struct map *map, FILE *fp) 399 { 400 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", ··· 661 static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 662 { 663 struct rb_root *root; 664 - struct rb_node *next; 665 int err = 0; 666 667 down_write(&maps->lock); 668 669 root = &maps->entries; 670 - next = rb_first(root); 671 672 while (next) { 673 struct map *pos = rb_entry(next, struct map, rb_node); 674 next = rb_next(&pos->rb_node); 675 676 - if (!map__overlap(pos, map)) 677 - continue; 678 679 if (verbose >= 2) { 680
··· 381 return map; 382 } 383 384 size_t map__fprintf(struct map *map, FILE *fp) 385 { 386 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", ··· 675 static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 676 { 677 struct rb_root *root; 678 + struct rb_node *next, *first; 679 int err = 0; 680 681 down_write(&maps->lock); 682 683 root = &maps->entries; 684 685 + /* 686 + * Find first map where end > map->start. 687 + * Same as find_vma() in kernel. 688 + */ 689 + next = root->rb_node; 690 + first = NULL; 691 + while (next) { 692 + struct map *pos = rb_entry(next, struct map, rb_node); 693 + 694 + if (pos->end > map->start) { 695 + first = next; 696 + if (pos->start <= map->start) 697 + break; 698 + next = next->rb_left; 699 + } else 700 + next = next->rb_right; 701 + } 702 + 703 + next = first; 704 while (next) { 705 struct map *pos = rb_entry(next, struct map, rb_node); 706 next = rb_next(&pos->rb_node); 707 708 + /* 709 + * Stop if current map starts after map->end. 710 + * Maps are ordered by start: next will not overlap for sure. 711 + */ 712 + if (pos->start >= map->end) 713 + break; 714 715 if (verbose >= 2) { 716
-1
tools/perf/util/map.h
··· 166 167 #define map__zput(map) __map__zput(&map) 168 169 - int map__overlap(struct map *l, struct map *r); 170 size_t map__fprintf(struct map *map, FILE *fp); 171 size_t map__fprintf_dsoname(struct map *map, FILE *fp); 172 char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
··· 166 167 #define map__zput(map) __map__zput(&map) 168 169 size_t map__fprintf(struct map *map, FILE *fp); 170 size_t map__fprintf_dsoname(struct map *map, FILE *fp); 171 char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
+2 -1
tools/perf/util/mmap.c
··· 164 auxtrace_mmap__munmap(&map->auxtrace_mmap); 165 } 166 167 - int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd) 168 { 169 /* 170 * The last one will be done at perf_mmap__consume(), so that we ··· 191 return -1; 192 } 193 map->fd = fd; 194 195 if (auxtrace_mmap__mmap(&map->auxtrace_mmap, 196 &mp->auxtrace_mp, map->base, fd))
··· 164 auxtrace_mmap__munmap(&map->auxtrace_mmap); 165 } 166 167 + int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu) 168 { 169 /* 170 * The last one will be done at perf_mmap__consume(), so that we ··· 191 return -1; 192 } 193 map->fd = fd; 194 + map->cpu = cpu; 195 196 if (auxtrace_mmap__mmap(&map->auxtrace_mmap, 197 &mp->auxtrace_mp, map->base, fd))
+2 -1
tools/perf/util/mmap.h
··· 18 void *base; 19 int mask; 20 int fd; 21 refcount_t refcnt; 22 u64 prev; 23 u64 start; ··· 61 struct auxtrace_mmap_params auxtrace_mp; 62 }; 63 64 - int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd); 65 void perf_mmap__munmap(struct perf_mmap *map); 66 67 void perf_mmap__get(struct perf_mmap *map);
··· 18 void *base; 19 int mask; 20 int fd; 21 + int cpu; 22 refcount_t refcnt; 23 u64 prev; 24 u64 start; ··· 60 struct auxtrace_mmap_params auxtrace_mp; 61 }; 62 63 + int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu); 64 void perf_mmap__munmap(struct perf_mmap *map); 65 66 void perf_mmap__get(struct perf_mmap *map);
+3
tools/perf/util/namespaces.c
··· 139 { 140 struct nsinfo *nnsi; 141 142 nnsi = calloc(1, sizeof(*nnsi)); 143 if (nnsi != NULL) { 144 nnsi->pid = nsi->pid;
··· 139 { 140 struct nsinfo *nnsi; 141 142 + if (nsi == NULL) 143 + return NULL; 144 + 145 nnsi = calloc(1, sizeof(*nnsi)); 146 if (nnsi != NULL) { 147 nnsi->pid = nsi->pid;
+10 -10
tools/perf/util/parse-events.c
··· 1991 int nr_addr_filters = 0; 1992 struct perf_pmu *pmu = NULL; 1993 1994 - if (evsel == NULL) 1995 - goto err; 1996 1997 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { 1998 if (perf_evsel__append_tp_filter(evsel, str) < 0) { ··· 2017 perf_pmu__scan_file(pmu, "nr_addr_filters", 2018 "%d", &nr_addr_filters); 2019 2020 - if (!nr_addr_filters) 2021 - goto err; 2022 2023 if (perf_evsel__append_addr_filter(evsel, str) < 0) { 2024 fprintf(stderr, ··· 2030 } 2031 2032 return 0; 2033 - 2034 - err: 2035 - fprintf(stderr, 2036 - "--filter option should follow a -e tracepoint or HW tracer option\n"); 2037 - 2038 - return -1; 2039 } 2040 2041 int parse_filter(const struct option *opt, const char *str,
··· 1991 int nr_addr_filters = 0; 1992 struct perf_pmu *pmu = NULL; 1993 1994 + if (evsel == NULL) { 1995 + fprintf(stderr, 1996 + "--filter option should follow a -e tracepoint or HW tracer option\n"); 1997 + return -1; 1998 + } 1999 2000 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { 2001 if (perf_evsel__append_tp_filter(evsel, str) < 0) { ··· 2014 perf_pmu__scan_file(pmu, "nr_addr_filters", 2015 "%d", &nr_addr_filters); 2016 2017 + if (!nr_addr_filters) { 2018 + fprintf(stderr, 2019 + "This CPU does not support address filtering\n"); 2020 + return -1; 2021 + } 2022 2023 if (perf_evsel__append_addr_filter(evsel, str) < 0) { 2024 fprintf(stderr, ··· 2024 } 2025 2026 return 0; 2027 } 2028 2029 int parse_filter(const struct option *opt, const char *str,
+24 -6
tools/perf/util/python.c
··· 11 #include "cpumap.h" 12 #include "print_binary.h" 13 #include "thread_map.h" 14 15 #if PY_MAJOR_VERSION < 3 16 #define _PyUnicode_FromString(arg) \ ··· 342 static PyObject* 343 tracepoint_field(struct pyrf_event *pe, struct format_field *field) 344 { 345 - struct pevent *pevent = field->event->pevent; 346 void *data = pe->sample.raw_data; 347 PyObject *ret = NULL; 348 unsigned long long val; ··· 352 offset = field->offset; 353 len = field->size; 354 if (field->flags & FIELD_IS_DYNAMIC) { 355 - val = pevent_read_number(pevent, data + offset, len); 356 offset = val; 357 len = offset >> 16; 358 offset &= 0xffff; ··· 365 field->flags &= ~FIELD_IS_STRING; 366 } 367 } else { 368 - val = pevent_read_number(pevent, data + field->offset, 369 - field->size); 370 if (field->flags & FIELD_IS_POINTER) 371 ret = PyLong_FromUnsignedLong((unsigned long) val); 372 else if (field->flags & FIELD_IS_SIGNED) ··· 395 evsel->tp_format = tp_format; 396 } 397 398 - field = pevent_find_any_field(evsel->tp_format, str); 399 if (!field) 400 return NULL; 401 ··· 977 return Py_BuildValue("i", evlist->nr_entries); 978 } 979 980 static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, 981 PyObject *args, PyObject *kwargs) 982 { ··· 1005 &cpu, &sample_id_all)) 1006 return NULL; 1007 1008 - md = &evlist->mmap[cpu]; 1009 if (perf_mmap__read_init(md) < 0) 1010 goto end; 1011
··· 11 #include "cpumap.h" 12 #include "print_binary.h" 13 #include "thread_map.h" 14 + #include "mmap.h" 15 16 #if PY_MAJOR_VERSION < 3 17 #define _PyUnicode_FromString(arg) \ ··· 341 static PyObject* 342 tracepoint_field(struct pyrf_event *pe, struct format_field *field) 343 { 344 + struct tep_handle *pevent = field->event->pevent; 345 void *data = pe->sample.raw_data; 346 PyObject *ret = NULL; 347 unsigned long long val; ··· 351 offset = field->offset; 352 len = field->size; 353 if (field->flags & FIELD_IS_DYNAMIC) { 354 + val = tep_read_number(pevent, data + offset, len); 355 offset = val; 356 len = offset >> 16; 357 offset &= 0xffff; ··· 364 field->flags &= ~FIELD_IS_STRING; 365 } 366 } else { 367 + val = tep_read_number(pevent, data + field->offset, 368 + field->size); 369 if (field->flags & FIELD_IS_POINTER) 370 ret = PyLong_FromUnsignedLong((unsigned long) val); 371 else if (field->flags & FIELD_IS_SIGNED) ··· 394 evsel->tp_format = tp_format; 395 } 396 397 + field = tep_find_any_field(evsel->tp_format, str); 398 if (!field) 399 return NULL; 400 ··· 976 return Py_BuildValue("i", evlist->nr_entries); 977 } 978 979 + static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) 980 + { 981 + int i; 982 + 983 + for (i = 0; i < evlist->nr_mmaps; i++) { 984 + struct perf_mmap *md = &evlist->mmap[i]; 985 + 986 + if (md->cpu == cpu) 987 + return md; 988 + } 989 + 990 + return NULL; 991 + } 992 + 993 static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, 994 PyObject *args, PyObject *kwargs) 995 { ··· 990 &cpu, &sample_id_all)) 991 return NULL; 992 993 + md = get_md(evlist, cpu); 994 + if (!md) 995 + return NULL; 996 + 997 if (perf_mmap__read_init(md) < 0) 998 goto end; 999
+71
tools/perf/util/s390-cpumsf-kernel.h
···
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Auxtrace support for s390 CPU measurement sampling facility 4 + * 5 + * Copyright IBM Corp. 2018 6 + * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> 7 + * Thomas Richter <tmricht@linux.ibm.com> 8 + */ 9 + #ifndef S390_CPUMSF_KERNEL_H 10 + #define S390_CPUMSF_KERNEL_H 11 + 12 + #define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */ 13 + #define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */ 14 + 15 + struct hws_basic_entry { 16 + unsigned int def:16; /* 0-15 Data Entry Format */ 17 + unsigned int R:4; /* 16-19 reserved */ 18 + unsigned int U:4; /* 20-23 Number of unique instruct. */ 19 + unsigned int z:2; /* zeros */ 20 + unsigned int T:1; /* 26 PSW DAT mode */ 21 + unsigned int W:1; /* 27 PSW wait state */ 22 + unsigned int P:1; /* 28 PSW Problem state */ 23 + unsigned int AS:2; /* 29-30 PSW address-space control */ 24 + unsigned int I:1; /* 31 entry valid or invalid */ 25 + unsigned int CL:2; /* 32-33 Configuration Level */ 26 + unsigned int:14; 27 + unsigned int prim_asn:16; /* primary ASN */ 28 + unsigned long long ia; /* Instruction Address */ 29 + unsigned long long gpp; /* Guest Program Parameter */ 30 + unsigned long long hpp; /* Host Program Parameter */ 31 + }; 32 + 33 + struct hws_diag_entry { 34 + unsigned int def:16; /* 0-15 Data Entry Format */ 35 + unsigned int R:15; /* 16-19 and 20-30 reserved */ 36 + unsigned int I:1; /* 31 entry valid or invalid */ 37 + u8 data[]; /* Machine-dependent sample data */ 38 + }; 39 + 40 + struct hws_combined_entry { 41 + struct hws_basic_entry basic; /* Basic-sampling data entry */ 42 + struct hws_diag_entry diag; /* Diagnostic-sampling data entry */ 43 + }; 44 + 45 + struct hws_trailer_entry { 46 + union { 47 + struct { 48 + unsigned int f:1; /* 0 - Block Full Indicator */ 49 + unsigned int a:1; /* 1 - Alert request control */ 50 + unsigned int t:1; /* 2 - Timestamp format */ 51 + unsigned int:29; /* 3 - 31: Reserved */ 52 + unsigned int bsdes:16; /* 32-47: size of basic SDE */ 53 + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ 54 + }; 55 + unsigned long long flags; /* 0 - 64: All indicators */ 56 + }; 57 + unsigned long long overflow; /* 64 - sample Overflow count */ 58 + unsigned char timestamp[16]; /* 16 - 31 timestamp */ 59 + unsigned long long reserved1; /* 32 -Reserved */ 60 + unsigned long long reserved2; /* */ 61 + union { /* 48 - reserved for programming use */ 62 + struct { 63 + unsigned long long clock_base:1; /* in progusage2 */ 64 + unsigned long long progusage1:63; 65 + unsigned long long progusage2; 66 + }; 67 + unsigned long long progusage[2]; 68 + }; 69 + }; 70 + 71 + #endif
+945
tools/perf/util/s390-cpumsf.c
···
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright IBM Corp. 2018 4 + * Auxtrace support for s390 CPU-Measurement Sampling Facility 5 + * 6 + * Author(s): Thomas Richter <tmricht@linux.ibm.com> 7 + * 8 + * Auxiliary traces are collected during 'perf record' using rbd000 event. 9 + * Several PERF_RECORD_XXX are generated during recording: 10 + * 11 + * PERF_RECORD_AUX: 12 + * Records that new data landed in the AUX buffer part. 13 + * PERF_RECORD_AUXTRACE: 14 + * Defines auxtrace data. Followed by the actual data. The contents of 15 + * the auxtrace data is dependent on the event and the CPU. 16 + * This record is generated by perf record command. For details 17 + * see Documentation/perf.data-file-format.txt. 18 + * PERF_RECORD_AUXTRACE_INFO: 19 + * Defines a table of contains for PERF_RECORD_AUXTRACE records. This 20 + * record is generated during 'perf record' command. Each record contains up 21 + * to 256 entries describing offset and size of the AUXTRACE data in the 22 + * perf.data file. 23 + * PERF_RECORD_AUXTRACE_ERROR: 24 + * Indicates an error during AUXTRACE collection such as buffer overflow. 25 + * PERF_RECORD_FINISHED_ROUND: 26 + * Perf events are not necessarily in time stamp order, as they can be 27 + * collected in parallel on different CPUs. If the events should be 28 + * processed in time order they need to be sorted first. 29 + * Perf report guarantees that there is no reordering over a 30 + * PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a 31 + * time stamp lower than this record are processed (and displayed) before 32 + * the succeeding perf record are processed. 33 + * 34 + * These records are evaluated during perf report command. 35 + * 36 + * 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for 37 + * auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info() 38 + * below. 39 + * Auxiliary trace data is collected per CPU. To merge the data into the report 40 + * an auxtrace_queue is created for each CPU. It is assumed that the auxtrace 41 + * data is in ascending order. 42 + * 43 + * Each queue has a double linked list of auxtrace_buffers. This list contains 44 + * the offset and size of a CPU's auxtrace data. During auxtrace processing 45 + * the data portion is mmap()'ed. 46 + * 47 + * To sort the queues in chronological order, all queue access is controlled 48 + * by the auxtrace_heap. This is basicly a stack, each stack element has two 49 + * entries, the queue number and a time stamp. However the stack is sorted by 50 + * the time stamps. The highest time stamp is at the bottom the lowest 51 + * (nearest) time stamp is at the top. That sort order is maintained at all 52 + * times! 53 + * 54 + * After the auxtrace infrastructure has been setup, the auxtrace queues are 55 + * filled with data (offset/size pairs) and the auxtrace_heap is populated. 56 + * 57 + * 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues. 58 + * Each record is handled by s390_cpumsf_process_event(). The time stamp of 59 + * the perf record is compared with the time stamp located on the auxtrace_heap 60 + * top element. If that time stamp is lower than the time stamp from the 61 + * record sample, the auxtrace queues will be processed. As auxtrace queues 62 + * control many auxtrace_buffers and each buffer can be quite large, the 63 + * auxtrace buffer might be processed only partially. In this case the 64 + * position in the auxtrace_buffer of that queue is remembered and the time 65 + * stamp of the last processed entry of the auxtrace_buffer replaces the 66 + * current auxtrace_heap top. 67 + * 68 + * 3. Auxtrace_queues might run of out data and are feeded by the 69 + * PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event(). 70 + * 71 + * Event Generation 72 + * Each sampling-data entry in the auxilary trace data generates a perf sample. 73 + * This sample is filled 74 + * with data from the auxtrace such as PID/TID, instruction address, CPU state, 75 + * etc. This sample is processed with perf_session__deliver_synth_event() to 76 + * be included into the GUI. 77 + * 78 + * 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining 79 + * auxiliary traces entries until the time stamp of this record is reached 80 + * auxtrace_heap top. This is triggered by ordered_event->deliver(). 81 + * 82 + * 83 + * Perf event processing. 84 + * Event processing of PERF_RECORD_XXX entries relies on time stamp entries. 85 + * This is the function call sequence: 86 + * 87 + * __cmd_report() 88 + * | 89 + * perf_session__process_events() 90 + * | 91 + * __perf_session__process_events() 92 + * | 93 + * perf_session__process_event() 94 + * | This functions splits the PERF_RECORD_XXX records. 95 + * | - Those generated by perf record command (type number equal or higher 96 + * | than PERF_RECORD_USER_TYPE_START) are handled by 97 + * | perf_session__process_user_event(see below) 98 + * | - Those generated by the kernel are handled by 99 + * | perf_evlist__parse_sample_timestamp() 100 + * | 101 + * perf_evlist__parse_sample_timestamp() 102 + * | Extract time stamp from sample data. 103 + * | 104 + * perf_session__queue_event() 105 + * | If timestamp is positive the sample is entered into an ordered_event 106 + * | list, sort order is the timestamp. The event processing is deferred until 107 + * | later (see perf_session__process_user_event()). 108 + * | Other timestamps (0 or -1) are handled immediately by 109 + * | perf_session__deliver_event(). These are events generated at start up 110 + * | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP* 111 + * | records. They are needed to create a list of running processes and its 112 + * | memory mappings and layout. They are needed at the beginning to enable 113 + * | command perf report to create process trees and memory mappings. 114 + * | 115 + * perf_session__deliver_event() 116 + * | Delivers a PERF_RECORD_XXX entry for handling. 117 + * | 118 + * auxtrace__process_event() 119 + * | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with 120 + * | time stamps from the auxiliary trace buffers. This enables 121 + * | synchronization between auxiliary trace data and the events on the 122 + * | perf.data file. 123 + * | 124 + * machine__deliver_event() 125 + * | Handles the PERF_RECORD_XXX event. This depends on the record type. 126 + * It might update the process tree, update a process memory map or enter 127 + * a sample with IP and call back chain data into GUI data pool. 128 + * 129 + * 130 + * Deferred processing determined by perf_session__process_user_event() is 131 + * finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These 132 + * are generated during command perf record. 133 + * The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all 134 + * PERF_RECORD_XXX entries stored in the ordered_event list. This list was 135 + * built up while reading the perf.data file. 136 + * Each event is now processed by calling perf_session__deliver_event(). 137 + * This enables time synchronization between the data in the perf.data file and 138 + * the data in the auxiliary trace buffers. 139 + */ 140 + 141 + #include <endian.h> 142 + #include <errno.h> 143 + #include <byteswap.h> 144 + #include <inttypes.h> 145 + #include <linux/kernel.h> 146 + #include <linux/types.h> 147 + #include <linux/bitops.h> 148 + #include <linux/log2.h> 149 + 150 + #include "cpumap.h" 151 + #include "color.h" 152 + #include "evsel.h" 153 + #include "evlist.h" 154 + #include "machine.h" 155 + #include "session.h" 156 + #include "util.h" 157 + #include "thread.h" 158 + #include "debug.h" 159 + #include "auxtrace.h" 160 + #include "s390-cpumsf.h" 161 + #include "s390-cpumsf-kernel.h" 162 + 163 + struct s390_cpumsf { 164 + struct auxtrace auxtrace; 165 + struct auxtrace_queues queues; 166 + struct auxtrace_heap heap; 167 + struct perf_session *session; 168 + struct machine *machine; 169 + u32 auxtrace_type; 170 + u32 pmu_type; 171 + u16 machine_type; 172 + bool data_queued; 173 + }; 174 + 175 + struct s390_cpumsf_queue { 176 + struct s390_cpumsf *sf; 177 + unsigned int queue_nr; 178 + struct auxtrace_buffer *buffer; 179 + int cpu; 180 + }; 181 + 182 + /* Display s390 CPU measurement facility basic-sampling data entry */ 183 + static bool s390_cpumsf_basic_show(const char *color, size_t pos, 184 + struct hws_basic_entry *basic) 185 + { 186 + if (basic->def != 1) { 187 + pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos); 188 + return false; 189 + } 190 + color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x" 191 + " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n" 192 + "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n", 193 + pos, basic->def, basic->U, 194 + basic->T ? 'T' : ' ', 195 + basic->W ? 'W' : ' ', 196 + basic->P ? 'P' : ' ', 197 + basic->I ? 'I' : ' ', 198 + basic->AS, basic->prim_asn, basic->ia, basic->CL, 199 + basic->hpp, basic->gpp); 200 + return true; 201 + } 202 + 203 + /* Display s390 CPU measurement facility diagnostic-sampling data entry */ 204 + static bool s390_cpumsf_diag_show(const char *color, size_t pos, 205 + struct hws_diag_entry *diag) 206 + { 207 + if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) { 208 + pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos); 209 + return false; 210 + } 211 + color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n", 212 + pos, diag->def, diag->I ? 'I' : ' '); 213 + return true; 214 + } 215 + 216 + /* Return TOD timestamp contained in an trailer entry */ 217 + static unsigned long long trailer_timestamp(struct hws_trailer_entry *te) 218 + { 219 + /* te->t set: TOD in STCKE format, bytes 8-15 220 + * to->t not set: TOD in STCK format, bytes 0-7 221 + */ 222 + unsigned long long ts; 223 + 224 + memcpy(&ts, &te->timestamp[te->t], sizeof(ts)); 225 + return ts; 226 + } 227 + 228 + /* Display s390 CPU measurement facility trailer entry */ 229 + static bool s390_cpumsf_trailer_show(const char *color, size_t pos, 230 + struct hws_trailer_entry *te) 231 + { 232 + if (te->bsdes != sizeof(struct hws_basic_entry)) { 233 + pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos); 234 + return false; 235 + } 236 + color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d" 237 + " dsdes:%d Overflow:%lld Time:%#llx\n" 238 + "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n", 239 + pos, 240 + te->f ? 'F' : ' ', 241 + te->a ? 'A' : ' ', 242 + te->t ? 'T' : ' ', 243 + te->bsdes, te->dsdes, te->overflow, 244 + trailer_timestamp(te), te->clock_base, te->progusage2, 245 + te->progusage[0], te->progusage[1]); 246 + return true; 247 + } 248 + 249 + /* Test a sample data block. It must be 4KB or a multiple thereof in size and 250 + * 4KB page aligned. Each sample data page has a trailer entry at the 251 + * end which contains the sample entry data sizes. 252 + * 253 + * Return true if the sample data block passes the checks and set the 254 + * basic set entry size and diagnostic set entry size. 255 + * 256 + * Return false on failure. 257 + * 258 + * Note: Old hardware does not set the basic or diagnostic entry sizes 259 + * in the trailer entry. Use the type number instead. 260 + */ 261 + static bool s390_cpumsf_validate(int machine_type, 262 + unsigned char *buf, size_t len, 263 + unsigned short *bsdes, 264 + unsigned short *dsdes) 265 + { 266 + struct hws_basic_entry *basic = (struct hws_basic_entry *)buf; 267 + struct hws_trailer_entry *te; 268 + 269 + *dsdes = *bsdes = 0; 270 + if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */ 271 + return false; 272 + if (basic->def != 1) /* No basic set entry, must be first */ 273 + return false; 274 + /* Check for trailer entry at end of SDB */ 275 + te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ 276 + - sizeof(*te)); 277 + *bsdes = te->bsdes; 278 + *dsdes = te->dsdes; 279 + if (!te->bsdes && !te->dsdes) { 280 + /* Very old hardware, use CPUID */ 281 + switch (machine_type) { 282 + case 2097: 283 + case 2098: 284 + *dsdes = 64; 285 + *bsdes = 32; 286 + break; 287 + case 2817: 288 + case 2818: 289 + *dsdes = 74; 290 + *bsdes = 32; 291 + break; 292 + case 2827: 293 + case 2828: 294 + *dsdes = 85; 295 + *bsdes = 32; 296 + break; 297 + default: 298 + /* Illegal trailer entry */ 299 + return false; 300 + } 301 + } 302 + return true; 303 + } 304 + 305 + /* Return true if there is room for another entry */ 306 + static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos) 307 + { 308 + size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry); 309 + 310 + if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz) 311 + return false; 312 + return true; 313 + } 314 + 315 + /* Dump an auxiliary buffer. These buffers are multiple of 316 + * 4KB SDB pages. 317 + */ 318 + static void s390_cpumsf_dump(struct s390_cpumsf *sf, 319 + unsigned char *buf, size_t len) 320 + { 321 + const char *color = PERF_COLOR_BLUE; 322 + struct hws_basic_entry *basic; 323 + struct hws_diag_entry *diag; 324 + unsigned short bsdes, dsdes; 325 + size_t pos = 0; 326 + 327 + color_fprintf(stdout, color, 328 + ". ... s390 AUX data: size %zu bytes\n", 329 + len); 330 + 331 + if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, 332 + &dsdes)) { 333 + pr_err("Invalid AUX trace data block size:%zu" 334 + " (type:%d bsdes:%hd dsdes:%hd)\n", 335 + len, sf->machine_type, bsdes, dsdes); 336 + return; 337 + } 338 + 339 + /* s390 kernel always returns 4KB blocks fully occupied, 340 + * no partially filled SDBs. 341 + */ 342 + while (pos < len) { 343 + /* Handle Basic entry */ 344 + basic = (struct hws_basic_entry *)(buf + pos); 345 + if (s390_cpumsf_basic_show(color, pos, basic)) 346 + pos += bsdes; 347 + else 348 + return; 349 + 350 + /* Handle Diagnostic entry */ 351 + diag = (struct hws_diag_entry *)(buf + pos); 352 + if (s390_cpumsf_diag_show(color, pos, diag)) 353 + pos += dsdes; 354 + else 355 + return; 356 + 357 + /* Check for trailer entry */ 358 + if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { 359 + /* Show trailer entry */ 360 + struct hws_trailer_entry te; 361 + 362 + pos = (pos + S390_CPUMSF_PAGESZ) 363 + & ~(S390_CPUMSF_PAGESZ - 1); 364 + pos -= sizeof(te); 365 + memcpy(&te, buf + pos, sizeof(te)); 366 + /* Set descriptor sizes in case of old hardware 367 + * where these values are not set. 368 + */ 369 + te.bsdes = bsdes; 370 + te.dsdes = dsdes; 371 + if (s390_cpumsf_trailer_show(color, pos, &te)) 372 + pos += sizeof(te); 373 + else 374 + return; 375 + } 376 + } 377 + } 378 + 379 + static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf, 380 + size_t len) 381 + { 382 + printf(".\n"); 383 + s390_cpumsf_dump(sf, buf, len); 384 + } 385 + 386 + #define S390_LPP_PID_MASK 0xffffffff 387 + 388 + static bool s390_cpumsf_make_event(size_t pos, 389 + struct hws_basic_entry *basic, 390 + struct s390_cpumsf_queue *sfq) 391 + { 392 + struct perf_sample sample = { 393 + .ip = basic->ia, 394 + .pid = basic->hpp & S390_LPP_PID_MASK, 395 + .tid = basic->hpp & S390_LPP_PID_MASK, 396 + .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN, 397 + .cpu = sfq->cpu, 398 + .period = 1 399 + }; 400 + union perf_event event; 401 + 402 + memset(&event, 0, sizeof(event)); 403 + if (basic->CL == 1) /* Native LPAR mode */ 404 + sample.cpumode = basic->P ? PERF_RECORD_MISC_USER 405 + : PERF_RECORD_MISC_KERNEL; 406 + else if (basic->CL == 2) /* Guest kernel/user space */ 407 + sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER 408 + : PERF_RECORD_MISC_GUEST_KERNEL; 409 + else if (basic->gpp || basic->prim_asn != 0xffff) 410 + /* Use heuristics on old hardware */ 411 + sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER 412 + : PERF_RECORD_MISC_GUEST_KERNEL; 413 + else 414 + sample.cpumode = basic->P ? PERF_RECORD_MISC_USER 415 + : PERF_RECORD_MISC_KERNEL; 416 + 417 + event.sample.header.type = PERF_RECORD_SAMPLE; 418 + event.sample.header.misc = sample.cpumode; 419 + event.sample.header.size = sizeof(struct perf_event_header); 420 + 421 + pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n", 422 + __func__, pos, sample.ip, basic->P, basic->CL, sample.pid, 423 + sample.tid, sample.cpumode, sample.cpu); 424 + if (perf_session__deliver_synth_event(sfq->sf->session, &event, 425 + &sample)) { 426 + pr_err("s390 Auxiliary Trace: failed to deliver event\n"); 427 + return false; 428 + } 429 + return true; 430 + } 431 + 432 + static unsigned long long get_trailer_time(const unsigned char *buf) 433 + { 434 + struct hws_trailer_entry *te; 435 + unsigned long long aux_time; 436 + 437 + te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ 438 + - sizeof(*te)); 439 + 440 + if (!te->clock_base) /* TOD_CLOCK_BASE value missing */ 441 + return 0; 442 + 443 + /* Correct calculation to convert time stamp in trailer entry to 444 + * nano seconds (taken from arch/s390 function tod_to_ns()). 445 + * TOD_CLOCK_BASE is stored in trailer entry member progusage2. 446 + */ 447 + aux_time = trailer_timestamp(te) - te->progusage2; 448 + aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9); 449 + return aux_time; 450 + } 451 + 452 + /* Process the data samples of a single queue. The first parameter is a 453 + * pointer to the queue, the second parameter is the time stamp. This 454 + * is the time stamp: 455 + * - of the event that triggered this processing. 456 + * - or the time stamp when the last proccesing of this queue stopped. 457 + * In this case it stopped at a 4KB page boundary and record the 458 + * position on where to continue processing on the next invocation 459 + * (see buffer->use_data and buffer->use_size). 460 + * 461 + * When this function returns the second parameter is updated to 462 + * reflect the time stamp of the last processed auxiliary data entry 463 + * (taken from the trailer entry of that page). The caller uses this 464 + * returned time stamp to record the last processed entry in this 465 + * queue. 466 + * 467 + * The function returns: 468 + * 0: Processing successful. The second parameter returns the 469 + * time stamp from the trailer entry until which position 470 + * processing took place. Subsequent calls resume from this 471 + * position. 472 + * <0: An error occurred during processing. The second parameter 473 + * returns the maximum time stamp. 474 + * >0: Done on this queue. The second parameter returns the 475 + * maximum time stamp. 476 + */ 477 + static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts) 478 + { 479 + struct s390_cpumsf *sf = sfq->sf; 480 + unsigned char *buf = sfq->buffer->use_data; 481 + size_t len = sfq->buffer->use_size; 482 + struct hws_basic_entry *basic; 483 + unsigned short bsdes, dsdes; 484 + size_t pos = 0; 485 + int err = 1; 486 + u64 aux_ts; 487 + 488 + if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, 489 + &dsdes)) { 490 + *ts = ~0ULL; 491 + return -1; 492 + } 493 + 494 + /* Get trailer entry time stamp and check if entries in 495 + * this auxiliary page are ready for processing. If the 496 + * time stamp of the first entry is too high, whole buffer 497 + * can be skipped. In this case return time stamp. 498 + */ 499 + aux_ts = get_trailer_time(buf); 500 + if (!aux_ts) { 501 + pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n", 502 + sfq->buffer->data_offset); 503 + aux_ts = ~0ULL; 504 + goto out; 505 + } 506 + if (aux_ts > *ts) { 507 + *ts = aux_ts; 508 + return 0; 509 + } 510 + 511 + while (pos < len) { 512 + /* Handle Basic entry */ 513 + basic = (struct hws_basic_entry *)(buf + pos); 514 + if (s390_cpumsf_make_event(pos, basic, sfq)) 515 + pos += bsdes; 516 + else { 517 + err = -EBADF; 518 + goto out; 519 + } 520 + 521 + pos += dsdes; /* Skip diagnositic entry */ 522 + 523 + /* Check for trailer entry */ 524 + if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { 525 + pos = (pos + S390_CPUMSF_PAGESZ) 526 + & ~(S390_CPUMSF_PAGESZ - 1); 527 + /* Check existence of next page */ 528 + if (pos >= len) 529 + break; 530 + aux_ts = get_trailer_time(buf + pos); 531 + if (!aux_ts) { 532 + aux_ts = ~0ULL; 533 + goto out; 534 + } 535 + if (aux_ts > *ts) { 536 + *ts = aux_ts; 537 + sfq->buffer->use_data += pos; 538 + sfq->buffer->use_size -= pos; 539 + return 0; 540 + } 541 + } 542 + } 543 + out: 544 + *ts = aux_ts; 545 + sfq->buffer->use_size = 0; 546 + sfq->buffer->use_data = NULL; 547 + return err; /* Buffer completely scanned or error */ 548 + } 549 + 550 + /* Run the s390 auxiliary trace decoder. 551 + * Select the queue buffer to operate on, the caller already selected 552 + * the proper queue, depending on second parameter 'ts'. 553 + * This is the time stamp until which the auxiliary entries should 554 + * be processed. This value is updated by called functions and 555 + * returned to the caller. 556 + * 557 + * Resume processing in the current buffer. If there is no buffer 558 + * get a new buffer from the queue and setup start position for 559 + * processing. 560 + * When a buffer is completely processed remove it from the queue 561 + * before returning. 562 + * 563 + * This function returns 564 + * 1: When the queue is empty. Second parameter will be set to 565 + * maximum time stamp. 566 + * 0: Normal processing done. 567 + * <0: Error during queue buffer setup. This causes the caller 568 + * to stop processing completely. 569 + */ 570 + static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq, 571 + u64 *ts) 572 + { 573 + 574 + struct auxtrace_buffer *buffer; 575 + struct auxtrace_queue *queue; 576 + int err; 577 + 578 + queue = &sfq->sf->queues.queue_array[sfq->queue_nr]; 579 + 580 + /* Get buffer and last position in buffer to resume 581 + * decoding the auxiliary entries. One buffer might be large 582 + * and decoding might stop in between. This depends on the time 583 + * stamp of the trailer entry in each page of the auxiliary 584 + * data and the time stamp of the event triggering the decoding. 585 + */ 586 + if (sfq->buffer == NULL) { 587 + sfq->buffer = buffer = auxtrace_buffer__next(queue, 588 + sfq->buffer); 589 + if (!buffer) { 590 + *ts = ~0ULL; 591 + return 1; /* Processing done on this queue */ 592 + } 593 + /* Start with a new buffer on this queue */ 594 + if (buffer->data) { 595 + buffer->use_size = buffer->size; 596 + buffer->use_data = buffer->data; 597 + } 598 + } else 599 + buffer = sfq->buffer; 600 + 601 + if (!buffer->data) { 602 + int fd = perf_data__fd(sfq->sf->session->data); 603 + 604 + buffer->data = auxtrace_buffer__get_data(buffer, fd); 605 + if (!buffer->data) 606 + return -ENOMEM; 607 + buffer->use_size = buffer->size; 608 + buffer->use_data = buffer->data; 609 + } 610 + pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n", 611 + __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset, 612 + buffer->size, buffer->use_size); 613 + err = s390_cpumsf_samples(sfq, ts); 614 + 615 + /* If non-zero, there is either an error (err < 0) or the buffer is 616 + * completely done (err > 0). The error is unrecoverable, usually 617 + * some descriptors could not be read successfully, so continue with 618 + * the next buffer. 619 + * In both cases the parameter 'ts' has been updated. 620 + */ 621 + if (err) { 622 + sfq->buffer = NULL; 623 + list_del(&buffer->list); 624 + auxtrace_buffer__free(buffer); 625 + if (err > 0) /* Buffer done, no error */ 626 + err = 0; 627 + } 628 + return err; 629 + } 630 + 631 + static struct s390_cpumsf_queue * 632 + s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr) 633 + { 634 + struct s390_cpumsf_queue *sfq; 635 + 636 + sfq = zalloc(sizeof(struct s390_cpumsf_queue)); 637 + if (sfq == NULL) 638 + return NULL; 639 + 640 + sfq->sf = sf; 641 + sfq->queue_nr = queue_nr; 642 + sfq->cpu = -1; 643 + return sfq; 644 + } 645 + 646 + static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf, 647 + struct auxtrace_queue *queue, 648 + unsigned int queue_nr, u64 ts) 649 + { 650 + struct s390_cpumsf_queue *sfq = queue->priv; 651 + 652 + if (list_empty(&queue->head)) 653 + return 0; 654 + 655 + if (sfq == NULL) { 656 + sfq = s390_cpumsf_alloc_queue(sf, queue_nr); 657 + if (!sfq) 658 + return -ENOMEM; 659 + queue->priv = sfq; 660 + 661 + if (queue->cpu != -1) 662 + sfq->cpu = queue->cpu; 663 + } 664 + return auxtrace_heap__add(&sf->heap, queue_nr, ts); 665 + } 666 + 667 + static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts) 668 + { 669 + unsigned int i; 670 + int ret = 0; 671 + 672 + for (i = 0; i < sf->queues.nr_queues; i++) { 673 + ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i], 674 + i, ts); 675 + if (ret) 676 + break; 677 + } 678 + return ret; 679 + } 680 + 681 + static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts) 682 + { 683 + if (!sf->queues.new_data) 684 + return 0; 685 + 686 + sf->queues.new_data = false; 687 + return s390_cpumsf_setup_queues(sf, ts); 688 + } 689 + 690 + static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp) 691 + { 692 + unsigned int queue_nr; 693 + u64 ts; 694 + int ret; 695 + 696 + while (1) { 697 + struct auxtrace_queue *queue; 698 + struct s390_cpumsf_queue *sfq; 699 + 700 + if (!sf->heap.heap_cnt) 701 + return 0; 702 + 703 + if (sf->heap.heap_array[0].ordinal >= timestamp) 704 + return 0; 705 + 706 + queue_nr = sf->heap.heap_array[0].queue_nr; 707 + queue = &sf->queues.queue_array[queue_nr]; 708 + sfq = queue->priv; 709 + 710 + auxtrace_heap__pop(&sf->heap); 711 + if (sf->heap.heap_cnt) { 712 + ts = sf->heap.heap_array[0].ordinal + 1; 713 + if (ts > timestamp) 714 + ts = timestamp; 715 + } else { 716 + ts = timestamp; 717 + } 718 + 719 + ret = s390_cpumsf_run_decoder(sfq, &ts); 720 + if (ret < 0) { 721 + auxtrace_heap__add(&sf->heap, queue_nr, ts); 722 + return ret; 723 + } 724 + if (!ret) { 725 + ret = auxtrace_heap__add(&sf->heap, queue_nr, ts); 726 + if (ret < 0) 727 + return ret; 728 + } 729 + } 730 + return 0; 731 + } 732 + 733 + static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu, 734 + pid_t pid, pid_t tid, u64 ip) 735 + { 736 + char msg[MAX_AUXTRACE_ERROR_MSG]; 737 + union perf_event event; 738 + int err; 739 + 740 + strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1); 741 + auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, 742 + code, cpu, pid, tid, ip, msg); 743 + 744 + err = perf_session__deliver_synth_event(sf->session, &event, NULL); 745 + if (err) 746 + pr_err("s390 Auxiliary Trace: failed to deliver error event," 747 + "error %d\n", err); 748 + return err; 749 + } 750 + 751 + static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample) 752 + { 753 + return s390_cpumsf_synth_error(sf, 1, sample->cpu, 754 + sample->pid, sample->tid, 0); 755 + } 756 + 757 + static int 758 + s390_cpumsf_process_event(struct perf_session *session __maybe_unused, 759 + union perf_event *event, 760 + struct perf_sample *sample, 761 + struct perf_tool *tool) 762 + { 763 + struct s390_cpumsf *sf = container_of(session->auxtrace, 764 + struct s390_cpumsf, 765 + auxtrace); 766 + u64 timestamp = sample->time; 767 + int err = 0; 768 + 769 + if (dump_trace) 770 + return 0; 771 + 772 + if (!tool->ordered_events) { 773 + pr_err("s390 Auxiliary Trace requires ordered events\n"); 774 + return -EINVAL; 775 + } 776 + 777 + if (event->header.type == PERF_RECORD_AUX && 778 + event->aux.flags & PERF_AUX_FLAG_TRUNCATED) 779 + return s390_cpumsf_lost(sf, sample); 780 + 781 + if (timestamp) { 782 + err = s390_cpumsf_update_queues(sf, timestamp); 783 + if (!err) 784 + err = s390_cpumsf_process_queues(sf, timestamp); 785 + } 786 + return err; 787 + } 788 + 789 + struct s390_cpumsf_synth { 790 + struct perf_tool cpumsf_tool; 791 + struct perf_session *session; 792 + }; 793 + 794 + static int 795 + s390_cpumsf_process_auxtrace_event(struct perf_session *session, 796 + union perf_event *event __maybe_unused, 797 + struct perf_tool *tool __maybe_unused) 798 + { 799 + struct s390_cpumsf *sf = container_of(session->auxtrace, 800 + struct s390_cpumsf, 801 + auxtrace); 802 + 803 + int fd = perf_data__fd(session->data); 804 + struct auxtrace_buffer *buffer; 805 + off_t data_offset; 806 + int err; 807 + 808 + if (sf->data_queued) 809 + return 0; 810 + 811 + if (perf_data__is_pipe(session->data)) { 812 + data_offset = 0; 813 + } else { 814 + data_offset = lseek(fd, 0, SEEK_CUR); 815 + if (data_offset == -1) 816 + return -errno; 817 + } 818 + 819 + err = auxtrace_queues__add_event(&sf->queues, session, event, 820 + data_offset, &buffer); 821 + if (err) 822 + return err; 823 + 824 + /* Dump here after copying piped trace out of the pipe */ 825 + if (dump_trace) { 826 + if (auxtrace_buffer__get_data(buffer, fd)) { 827 + s390_cpumsf_dump_event(sf, buffer->data, 828 + buffer->size); 829 + auxtrace_buffer__put_data(buffer); 830 + } 831 + } 832 + return 0; 833 + } 834 + 835 + static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused) 836 + { 837 + } 838 + 839 + static int s390_cpumsf_flush(struct perf_session *session __maybe_unused, 840 + struct perf_tool *tool __maybe_unused) 841 + { 842 + return 0; 843 + } 844 + 845 + static void s390_cpumsf_free_queues(struct perf_session *session) 846 + { 847 + struct s390_cpumsf *sf = container_of(session->auxtrace, 848 + struct s390_cpumsf, 849 + auxtrace); 850 + struct auxtrace_queues *queues = &sf->queues; 851 + unsigned int i; 852 + 853 + for (i = 0; i < queues->nr_queues; i++) 854 + zfree(&queues->queue_array[i].priv); 855 + auxtrace_queues__free(queues); 856 + } 857 + 858 + static void s390_cpumsf_free(struct perf_session *session) 859 + { 860 + struct s390_cpumsf *sf = container_of(session->auxtrace, 861 + struct s390_cpumsf, 862 + auxtrace); 863 + 864 + auxtrace_heap__free(&sf->heap); 865 + s390_cpumsf_free_queues(session); 866 + session->auxtrace = NULL; 867 + free(sf); 868 + } 869 + 870 + static int s390_cpumsf_get_type(const char *cpuid) 871 + { 872 + int ret, family = 0; 873 + 874 + ret = sscanf(cpuid, "%*[^,],%u", &family); 875 + return (ret == 1) ? family : 0; 876 + } 877 + 878 + /* Check itrace options set on perf report command. 879 + * Return true, if none are set or all options specified can be 880 + * handled on s390. 881 + * Return false otherwise. 882 + */ 883 + static bool check_auxtrace_itrace(struct itrace_synth_opts *itops) 884 + { 885 + if (!itops || !itops->set) 886 + return true; 887 + pr_err("No --itrace options supported\n"); 888 + return false; 889 + } 890 + 891 + int s390_cpumsf_process_auxtrace_info(union perf_event *event, 892 + struct perf_session *session) 893 + { 894 + struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; 895 + struct s390_cpumsf *sf; 896 + int err; 897 + 898 + if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event)) 899 + return -EINVAL; 900 + 901 + sf = zalloc(sizeof(struct s390_cpumsf)); 902 + if (sf == NULL) 903 + return -ENOMEM; 904 + 905 + if (!check_auxtrace_itrace(session->itrace_synth_opts)) { 906 + err = -EINVAL; 907 + goto err_free; 908 + } 909 + 910 + err = auxtrace_queues__init(&sf->queues); 911 + if (err) 912 + goto err_free; 913 + 914 + sf->session = session; 915 + sf->machine = &session->machines.host; /* No kvm support */ 916 + sf->auxtrace_type = auxtrace_info->type; 917 + sf->pmu_type = PERF_TYPE_RAW; 918 + sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid); 919 + 920 + sf->auxtrace.process_event = s390_cpumsf_process_event; 921 + sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event; 922 + sf->auxtrace.flush_events = s390_cpumsf_flush; 923 + sf->auxtrace.free_events = s390_cpumsf_free_events; 924 + sf->auxtrace.free = s390_cpumsf_free; 925 + session->auxtrace = &sf->auxtrace; 926 + 927 + if (dump_trace) 928 + return 0; 929 + 930 + err = auxtrace_queues__process_index(&sf->queues, session); 931 + if (err) 932 + goto err_free_queues; 933 + 934 + if (sf->queues.populated) 935 + sf->data_queued = true; 936 + 937 + return 0; 938 + 939 + err_free_queues: 940 + auxtrace_queues__free(&sf->queues); 941 + session->auxtrace = NULL; 942 + err_free: 943 + free(sf); 944 + return err; 945 + }
+21
tools/perf/util/s390-cpumsf.h
···
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright IBM Corp. 2018 4 + * Auxtrace support for s390 CPU-Measurement Sampling Facility 5 + * 6 + * Author(s): Thomas Richter <tmricht@linux.ibm.com> 7 + */ 8 + 9 + #ifndef INCLUDE__PERF_S390_CPUMSF_H 10 + #define INCLUDE__PERF_S390_CPUMSF_H 11 + 12 + union perf_event; 13 + struct perf_session; 14 + struct perf_pmu; 15 + 16 + struct auxtrace_record * 17 + s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu); 18 + 19 + int s390_cpumsf_process_auxtrace_info(union perf_event *event, 20 + struct perf_session *session); 21 + #endif
+1 -1
tools/perf/util/scripting-engines/trace-event-perl.c
··· 535 return 0; 536 } 537 538 - static int perl_generate_script(struct pevent *pevent, const char *outfile) 539 { 540 struct event_format *event = NULL; 541 struct format_field *f;
··· 535 return 0; 536 } 537 538 + static int perl_generate_script(struct tep_handle *pevent, const char *outfile) 539 { 540 struct event_format *event = NULL; 541 struct format_field *f;
+3 -3
tools/perf/util/scripting-engines/trace-event-python.c
··· 871 offset = field->offset; 872 len = field->size; 873 if (field->flags & FIELD_IS_DYNAMIC) { 874 - val = pevent_read_number(scripting_context->pevent, 875 - data + offset, len); 876 offset = val; 877 len = offset >> 16; 878 offset &= 0xffff; ··· 1588 return 0; 1589 } 1590 1591 - static int python_generate_script(struct pevent *pevent, const char *outfile) 1592 { 1593 struct event_format *event = NULL; 1594 struct format_field *f;
··· 871 offset = field->offset; 872 len = field->size; 873 if (field->flags & FIELD_IS_DYNAMIC) { 874 + val = tep_read_number(scripting_context->pevent, 875 + data + offset, len); 876 offset = val; 877 len = offset >> 16; 878 offset &= 0xffff; ··· 1588 return 0; 1589 } 1590 1591 + static int python_generate_script(struct tep_handle *pevent, const char *outfile) 1592 { 1593 struct event_format *event = NULL; 1594 struct format_field *f;
+9 -1
tools/perf/util/setup.py
··· 1 #!/usr/bin/python 2 3 from os import getenv 4 5 cc = getenv("CC") 6 if cc == "clang": 7 from _sysconfigdata import build_time_vars 8 - from re import sub 9 build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) 10 11 from distutils.core import setup, Extension 12
··· 1 #!/usr/bin/python 2 3 from os import getenv 4 + from subprocess import Popen, PIPE 5 + from re import sub 6 + 7 + def clang_has_option(option): 8 + return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if "unknown argument" in o] == [ ] 9 10 cc = getenv("CC") 11 if cc == "clang": 12 from _sysconfigdata import build_time_vars 13 build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) 14 + if not clang_has_option("-mcet"): 15 + build_time_vars["CFLAGS"] = sub("-mcet", "", build_time_vars["CFLAGS"]) 16 + if not clang_has_option("-fcf-protection"): 17 + build_time_vars["CFLAGS"] = sub("-fcf-protection", "", build_time_vars["CFLAGS"]) 18 19 from distutils.core import setup, Extension 20
+8 -8
tools/perf/util/sort.c
··· 601 { 602 struct trace_seq seq; 603 struct perf_evsel *evsel; 604 - struct pevent_record rec = { 605 .data = he->raw_data, 606 .size = he->raw_size, 607 }; ··· 610 611 trace_seq_init(&seq); 612 if (symbol_conf.raw_trace) { 613 - pevent_print_fields(&seq, he->raw_data, he->raw_size, 614 - evsel->tp_format); 615 } else { 616 - pevent_event_info(&seq, evsel->tp_format, &rec); 617 } 618 /* 619 * Trim the buffer, it starts at 4KB and we're not going to ··· 2047 struct trace_seq seq; 2048 raw_field: 2049 trace_seq_init(&seq); 2050 - pevent_print_field(&seq, he->raw_data, hde->field); 2051 str = seq.buffer; 2052 } 2053 ··· 2074 if (field->flags & FIELD_IS_DYNAMIC) { 2075 unsigned long long dyn; 2076 2077 - pevent_read_number_field(field, a->raw_data, &dyn); 2078 offset = dyn & 0xffff; 2079 size = (dyn >> 16) & 0xffff; 2080 ··· 2311 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 2312 continue; 2313 2314 - field = pevent_find_any_field(evsel->tp_format, field_name); 2315 if (field == NULL) 2316 continue; 2317 ··· 2378 if (!strcmp(field_name, "*")) { 2379 ret = add_evsel_fields(evsel, raw_trace, level); 2380 } else { 2381 - field = pevent_find_any_field(evsel->tp_format, field_name); 2382 if (field == NULL) { 2383 pr_debug("Cannot find event field for %s.%s\n", 2384 event_name, field_name);
··· 601 { 602 struct trace_seq seq; 603 struct perf_evsel *evsel; 604 + struct tep_record rec = { 605 .data = he->raw_data, 606 .size = he->raw_size, 607 }; ··· 610 611 trace_seq_init(&seq); 612 if (symbol_conf.raw_trace) { 613 + tep_print_fields(&seq, he->raw_data, he->raw_size, 614 + evsel->tp_format); 615 } else { 616 + tep_event_info(&seq, evsel->tp_format, &rec); 617 } 618 /* 619 * Trim the buffer, it starts at 4KB and we're not going to ··· 2047 struct trace_seq seq; 2048 raw_field: 2049 trace_seq_init(&seq); 2050 + tep_print_field(&seq, he->raw_data, hde->field); 2051 str = seq.buffer; 2052 } 2053 ··· 2074 if (field->flags & FIELD_IS_DYNAMIC) { 2075 unsigned long long dyn; 2076 2077 + tep_read_number_field(field, a->raw_data, &dyn); 2078 offset = dyn & 0xffff; 2079 size = (dyn >> 16) & 0xffff; 2080 ··· 2311 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 2312 continue; 2313 2314 + field = tep_find_any_field(evsel->tp_format, field_name); 2315 if (field == NULL) 2316 continue; 2317 ··· 2378 if (!strcmp(field_name, "*")) { 2379 ret = add_evsel_fields(evsel, raw_trace, level); 2380 } else { 2381 + field = tep_find_any_field(evsel->tp_format, field_name); 2382 if (field == NULL) { 2383 pr_debug("Cannot find event field for %s.%s\n", 2384 event_name, field_name);
+1 -1
tools/perf/util/sort.h
··· 276 extern struct list_head hist_entry__sort_list; 277 278 struct perf_evlist; 279 - struct pevent; 280 int setup_sorting(struct perf_evlist *evlist); 281 int setup_output_field(void); 282 void reset_output_field(void);
··· 276 extern struct list_head hist_entry__sort_list; 277 278 struct perf_evlist; 279 + struct tep_handle; 280 int setup_sorting(struct perf_evlist *evlist); 281 int setup_output_field(void); 282 void reset_output_field(void);
+17 -17
tools/perf/util/trace-event-parse.c
··· 32 static int get_common_field(struct scripting_context *context, 33 int *offset, int *size, const char *type) 34 { 35 - struct pevent *pevent = context->pevent; 36 struct event_format *event; 37 struct format_field *field; 38 ··· 41 return 0; 42 43 event = pevent->events[0]; 44 - field = pevent_find_common_field(event, type); 45 if (!field) 46 return 0; 47 *offset = field->offset; 48 *size = field->size; 49 } 50 51 - return pevent_read_number(pevent, context->event_data + *offset, *size); 52 } 53 54 int common_lock_depth(struct scripting_context *context) ··· 99 struct format_field *field; 100 unsigned long long val; 101 102 - field = pevent_find_any_field(event, name); 103 if (!field) 104 return 0ULL; 105 106 - pevent_read_number_field(field, data, &val); 107 108 return val; 109 } 110 111 unsigned long long read_size(struct event_format *event, void *ptr, int size) 112 { 113 - return pevent_read_number(event->pevent, ptr, size); 114 } 115 116 void event_format__fprintf(struct event_format *event, 117 int cpu, void *data, int size, FILE *fp) 118 { 119 - struct pevent_record record; 120 struct trace_seq s; 121 122 memset(&record, 0, sizeof(record)); ··· 125 record.data = data; 126 127 trace_seq_init(&s); 128 - pevent_event_info(&s, event, &record); 129 trace_seq_do_fprintf(&s, fp); 130 trace_seq_destroy(&s); 131 } ··· 136 return event_format__fprintf(event, cpu, data, size, stdout); 137 } 138 139 - void parse_ftrace_printk(struct pevent *pevent, 140 char *file, unsigned int size __maybe_unused) 141 { 142 unsigned long long addr; ··· 157 /* fmt still has a space, skip it */ 158 printk = strdup(fmt+1); 159 line = strtok_r(NULL, "\n", &next); 160 - pevent_register_print_string(pevent, printk, addr); 161 } 162 } 163 164 - void parse_saved_cmdline(struct pevent *pevent, 165 char *file, unsigned int size __maybe_unused) 166 { 167 char *comm; ··· 172 line = strtok_r(file, "\n", &next); 173 while (line) { 174 sscanf(line, "%d %ms", &pid, &comm); 175 - pevent_register_comm(pevent, comm, pid); 176 free(comm); 177 line = strtok_r(NULL, "\n", &next); 178 } 179 } 180 181 - int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) 182 { 183 - return pevent_parse_event(pevent, buf, size, "ftrace"); 184 } 185 186 - int parse_event_file(struct pevent *pevent, 187 char *buf, unsigned long size, char *sys) 188 { 189 - return pevent_parse_event(pevent, buf, size, sys); 190 } 191 192 - struct event_format *trace_find_next_event(struct pevent *pevent, 193 struct event_format *event) 194 { 195 static int idx;
··· 32 static int get_common_field(struct scripting_context *context, 33 int *offset, int *size, const char *type) 34 { 35 + struct tep_handle *pevent = context->pevent; 36 struct event_format *event; 37 struct format_field *field; 38 ··· 41 return 0; 42 43 event = pevent->events[0]; 44 + field = tep_find_common_field(event, type); 45 if (!field) 46 return 0; 47 *offset = field->offset; 48 *size = field->size; 49 } 50 51 + return tep_read_number(pevent, context->event_data + *offset, *size); 52 } 53 54 int common_lock_depth(struct scripting_context *context) ··· 99 struct format_field *field; 100 unsigned long long val; 101 102 + field = tep_find_any_field(event, name); 103 if (!field) 104 return 0ULL; 105 106 + tep_read_number_field(field, data, &val); 107 108 return val; 109 } 110 111 unsigned long long read_size(struct event_format *event, void *ptr, int size) 112 { 113 + return tep_read_number(event->pevent, ptr, size); 114 } 115 116 void event_format__fprintf(struct event_format *event, 117 int cpu, void *data, int size, FILE *fp) 118 { 119 + struct tep_record record; 120 struct trace_seq s; 121 122 memset(&record, 0, sizeof(record)); ··· 125 record.data = data; 126 127 trace_seq_init(&s); 128 + tep_event_info(&s, event, &record); 129 trace_seq_do_fprintf(&s, fp); 130 trace_seq_destroy(&s); 131 } ··· 136 return event_format__fprintf(event, cpu, data, size, stdout); 137 } 138 139 + void parse_ftrace_printk(struct tep_handle *pevent, 140 char *file, unsigned int size __maybe_unused) 141 { 142 unsigned long long addr; ··· 157 /* fmt still has a space, skip it */ 158 printk = strdup(fmt+1); 159 line = strtok_r(NULL, "\n", &next); 160 + tep_register_print_string(pevent, printk, addr); 161 } 162 } 163 164 + void parse_saved_cmdline(struct tep_handle *pevent, 165 char *file, unsigned int size __maybe_unused) 166 { 167 char *comm; ··· 172 line = strtok_r(file, "\n", &next); 173 while (line) { 174 sscanf(line, "%d %ms", &pid, &comm); 175 + tep_register_comm(pevent, comm, pid); 176 free(comm); 177 line = strtok_r(NULL, "\n", &next); 178 } 179 } 180 181 + int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) 182 { 183 + return tep_parse_event(pevent, buf, size, "ftrace"); 184 } 185 186 + int parse_event_file(struct tep_handle *pevent, 187 char *buf, unsigned long size, char *sys) 188 { 189 + return tep_parse_event(pevent, buf, size, sys); 190 } 191 192 + struct event_format *trace_find_next_event(struct tep_handle *pevent, 193 struct event_format *event) 194 { 195 static int idx;
+22 -22
tools/perf/util/trace-event-read.c
··· 96 }; 97 } 98 99 - static unsigned int read4(struct pevent *pevent) 100 { 101 unsigned int data; 102 ··· 105 return __data2host4(pevent, data); 106 } 107 108 - static unsigned long long read8(struct pevent *pevent) 109 { 110 unsigned long long data; 111 ··· 158 return str; 159 } 160 161 - static int read_proc_kallsyms(struct pevent *pevent) 162 { 163 unsigned int size; 164 ··· 181 return 0; 182 } 183 184 - static int read_ftrace_printk(struct pevent *pevent) 185 { 186 unsigned int size; 187 char *buf; ··· 208 return 0; 209 } 210 211 - static int read_header_files(struct pevent *pevent) 212 { 213 unsigned long long size; 214 char *header_page; ··· 235 return -1; 236 } 237 238 - if (!pevent_parse_header_page(pevent, header_page, size, 239 - pevent_get_long_size(pevent))) { 240 /* 241 * The commit field in the page is of type long, 242 * use that instead, since it represents the kernel. 243 */ 244 - pevent_set_long_size(pevent, pevent->header_page_size_size); 245 } 246 free(header_page); 247 ··· 259 return ret; 260 } 261 262 - static int read_ftrace_file(struct pevent *pevent, unsigned long long size) 263 { 264 int ret; 265 char *buf; ··· 284 return ret; 285 } 286 287 - static int read_event_file(struct pevent *pevent, char *sys, 288 - unsigned long long size) 289 { 290 int ret; 291 char *buf; ··· 310 return ret; 311 } 312 313 - static int read_ftrace_files(struct pevent *pevent) 314 { 315 unsigned long long size; 316 int count; ··· 328 return 0; 329 } 330 331 - static int read_event_files(struct pevent *pevent) 332 { 333 unsigned long long size; 334 char *sys; ··· 356 return 0; 357 } 358 359 - static int read_saved_cmdline(struct pevent *pevent) 360 { 361 unsigned long long size; 362 char *buf; ··· 399 int host_bigendian; 400 int file_long_size; 401 int file_page_size; 402 - struct pevent *pevent = NULL; 403 int err; 404 405 repipe = __repipe; ··· 439 440 pevent = tevent->pevent; 441 442 - pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); 443 - pevent_set_file_bigendian(pevent, file_bigendian); 444 - pevent_set_host_bigendian(pevent, host_bigendian); 445 446 if (do_read(buf, 1) < 0) 447 goto out; ··· 451 if (!file_page_size) 452 goto out; 453 454 - pevent_set_long_size(pevent, file_long_size); 455 - pevent_set_page_size(pevent, file_page_size); 456 457 err = read_header_files(pevent); 458 if (err) ··· 479 repipe = false; 480 481 if (show_funcs) { 482 - pevent_print_funcs(pevent); 483 } else if (show_printk) { 484 - pevent_print_printk(pevent); 485 } 486 487 pevent = NULL;
··· 96 }; 97 } 98 99 + static unsigned int read4(struct tep_handle *pevent) 100 { 101 unsigned int data; 102 ··· 105 return __data2host4(pevent, data); 106 } 107 108 + static unsigned long long read8(struct tep_handle *pevent) 109 { 110 unsigned long long data; 111 ··· 158 return str; 159 } 160 161 + static int read_proc_kallsyms(struct tep_handle *pevent) 162 { 163 unsigned int size; 164 ··· 181 return 0; 182 } 183 184 + static int read_ftrace_printk(struct tep_handle *pevent) 185 { 186 unsigned int size; 187 char *buf; ··· 208 return 0; 209 } 210 211 + static int read_header_files(struct tep_handle *pevent) 212 { 213 unsigned long long size; 214 char *header_page; ··· 235 return -1; 236 } 237 238 + if (!tep_parse_header_page(pevent, header_page, size, 239 + tep_get_long_size(pevent))) { 240 /* 241 * The commit field in the page is of type long, 242 * use that instead, since it represents the kernel. 243 */ 244 + tep_set_long_size(pevent, pevent->header_page_size_size); 245 } 246 free(header_page); 247 ··· 259 return ret; 260 } 261 262 + static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) 263 { 264 int ret; 265 char *buf; ··· 284 return ret; 285 } 286 287 + static int read_event_file(struct tep_handle *pevent, char *sys, 288 + unsigned long long size) 289 { 290 int ret; 291 char *buf; ··· 310 return ret; 311 } 312 313 + static int read_ftrace_files(struct tep_handle *pevent) 314 { 315 unsigned long long size; 316 int count; ··· 328 return 0; 329 } 330 331 + static int read_event_files(struct tep_handle *pevent) 332 { 333 unsigned long long size; 334 char *sys; ··· 356 return 0; 357 } 358 359 + static int read_saved_cmdline(struct tep_handle *pevent) 360 { 361 unsigned long long size; 362 char *buf; ··· 399 int host_bigendian; 400 int file_long_size; 401 int file_page_size; 402 + struct tep_handle *pevent = NULL; 403 int err; 404 405 repipe = __repipe; ··· 439 440 pevent = tevent->pevent; 441 442 + tep_set_flag(pevent, TEP_NSEC_OUTPUT); 443 + tep_set_file_bigendian(pevent, file_bigendian); 444 + tep_set_host_bigendian(pevent, host_bigendian); 445 446 if (do_read(buf, 1) < 0) 447 goto out; ··· 451 if (!file_page_size) 452 goto out; 453 454 + tep_set_long_size(pevent, file_long_size); 455 + tep_set_page_size(pevent, file_page_size); 456 457 err = read_header_files(pevent); 458 if (err) ··· 479 repipe = false; 480 481 if (show_funcs) { 482 + tep_print_funcs(pevent); 483 } else if (show_printk) { 484 + tep_print_printk(pevent); 485 } 486 487 pevent = NULL;
+2 -2
tools/perf/util/trace-event-scripting.c
··· 66 return -1; 67 } 68 69 - static int python_generate_script_unsupported(struct pevent *pevent 70 __maybe_unused, 71 const char *outfile 72 __maybe_unused) ··· 130 return -1; 131 } 132 133 - static int perl_generate_script_unsupported(struct pevent *pevent 134 __maybe_unused, 135 const char *outfile __maybe_unused) 136 {
··· 66 return -1; 67 } 68 69 + static int python_generate_script_unsupported(struct tep_handle *pevent 70 __maybe_unused, 71 const char *outfile 72 __maybe_unused) ··· 130 return -1; 131 } 132 133 + static int perl_generate_script_unsupported(struct tep_handle *pevent 134 __maybe_unused, 135 const char *outfile __maybe_unused) 136 {
+14 -14
tools/perf/util/trace-event.c
··· 28 29 int trace_event__init(struct trace_event *t) 30 { 31 - struct pevent *pevent = pevent_alloc(); 32 33 if (pevent) { 34 - t->plugin_list = traceevent_load_plugins(pevent); 35 t->pevent = pevent; 36 } 37 ··· 40 41 static int trace_event__init2(void) 42 { 43 - int be = traceevent_host_bigendian(); 44 - struct pevent *pevent; 45 46 if (trace_event__init(&tevent)) 47 return -1; 48 49 pevent = tevent.pevent; 50 - pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); 51 - pevent_set_file_bigendian(pevent, be); 52 - pevent_set_host_bigendian(pevent, be); 53 tevent_initialized = true; 54 return 0; 55 } 56 57 int trace_event__register_resolver(struct machine *machine, 58 - pevent_func_resolver_t *func) 59 { 60 if (!tevent_initialized && trace_event__init2()) 61 return -1; 62 63 - return pevent_set_function_resolver(tevent.pevent, func, machine); 64 } 65 66 void trace_event__cleanup(struct trace_event *t) 67 { 68 - traceevent_unload_plugins(t->plugin_list, t->pevent); 69 - pevent_free(t->pevent); 70 } 71 72 /* ··· 76 tp_format(const char *sys, const char *name) 77 { 78 char *tp_dir = get_events_file(sys); 79 - struct pevent *pevent = tevent.pevent; 80 struct event_format *event = NULL; 81 char path[PATH_MAX]; 82 size_t size; ··· 93 if (err) 94 return ERR_PTR(err); 95 96 - pevent_parse_format(pevent, &event, data, size, sys); 97 98 free(data); 99 return event; ··· 116 if (!tevent_initialized && trace_event__init2()) 117 return ERR_PTR(-ENOMEM); 118 119 - return pevent_find_event(tevent.pevent, id); 120 }
··· 28 29 int trace_event__init(struct trace_event *t) 30 { 31 + struct tep_handle *pevent = tep_alloc(); 32 33 if (pevent) { 34 + t->plugin_list = tep_load_plugins(pevent); 35 t->pevent = pevent; 36 } 37 ··· 40 41 static int trace_event__init2(void) 42 { 43 + int be = tep_host_bigendian(); 44 + struct tep_handle *pevent; 45 46 if (trace_event__init(&tevent)) 47 return -1; 48 49 pevent = tevent.pevent; 50 + tep_set_flag(pevent, TEP_NSEC_OUTPUT); 51 + tep_set_file_bigendian(pevent, be); 52 + tep_set_host_bigendian(pevent, be); 53 tevent_initialized = true; 54 return 0; 55 } 56 57 int trace_event__register_resolver(struct machine *machine, 58 + tep_func_resolver_t *func) 59 { 60 if (!tevent_initialized && trace_event__init2()) 61 return -1; 62 63 + return tep_set_function_resolver(tevent.pevent, func, machine); 64 } 65 66 void trace_event__cleanup(struct trace_event *t) 67 { 68 + tep_unload_plugins(t->plugin_list, t->pevent); 69 + tep_free(t->pevent); 70 } 71 72 /* ··· 76 tp_format(const char *sys, const char *name) 77 { 78 char *tp_dir = get_events_file(sys); 79 + struct tep_handle *pevent = tevent.pevent; 80 struct event_format *event = NULL; 81 char path[PATH_MAX]; 82 size_t size; ··· 93 if (err) 94 return ERR_PTR(err); 95 96 + tep_parse_format(pevent, &event, data, size, sys); 97 98 free(data); 99 return event; ··· 116 if (!tevent_initialized && trace_event__init2()) 117 return ERR_PTR(-ENOMEM); 118 119 + return tep_find_event(tevent.pevent, id); 120 }
+10 -10
tools/perf/util/trace-event.h
··· 13 struct plugin_list; 14 15 struct trace_event { 16 - struct pevent *pevent; 17 struct plugin_list *plugin_list; 18 }; 19 20 int trace_event__init(struct trace_event *t); 21 void trace_event__cleanup(struct trace_event *t); 22 int trace_event__register_resolver(struct machine *machine, 23 - pevent_func_resolver_t *func); 24 struct event_format* 25 trace_event__tp_format(const char *sys, const char *name); 26 ··· 34 void event_format__print(struct event_format *event, 35 int cpu, void *data, int size); 36 37 - int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 38 - int parse_event_file(struct pevent *pevent, 39 char *buf, unsigned long size, char *sys); 40 41 unsigned long long 42 raw_field_value(struct event_format *event, const char *name, void *data); 43 44 - void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 45 - void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 46 - void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size); 47 48 ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); 49 50 - struct event_format *trace_find_next_event(struct pevent *pevent, 51 struct event_format *event); 52 unsigned long long read_size(struct event_format *event, void *ptr, int size); 53 unsigned long long eval_flag(const char *flag); ··· 83 void (*process_stat)(struct perf_stat_config *config, 84 struct perf_evsel *evsel, u64 tstamp); 85 void (*process_stat_interval)(u64 tstamp); 86 - int (*generate_script) (struct pevent *pevent, const char *outfile); 87 }; 88 89 extern unsigned int scripting_max_stack; ··· 94 void setup_python_scripting(void); 95 96 struct scripting_context { 97 - struct pevent *pevent; 98 void *event_data; 99 }; 100
··· 13 struct plugin_list; 14 15 struct trace_event { 16 + struct tep_handle *pevent; 17 struct plugin_list *plugin_list; 18 }; 19 20 int trace_event__init(struct trace_event *t); 21 void trace_event__cleanup(struct trace_event *t); 22 int trace_event__register_resolver(struct machine *machine, 23 + tep_func_resolver_t *func); 24 struct event_format* 25 trace_event__tp_format(const char *sys, const char *name); 26 ··· 34 void event_format__print(struct event_format *event, 35 int cpu, void *data, int size); 36 37 + int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size); 38 + int parse_event_file(struct tep_handle *pevent, 39 char *buf, unsigned long size, char *sys); 40 41 unsigned long long 42 raw_field_value(struct event_format *event, const char *name, void *data); 43 44 + void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size); 45 + void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size); 46 + void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int size); 47 48 ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); 49 50 + struct event_format *trace_find_next_event(struct tep_handle *pevent, 51 struct event_format *event); 52 unsigned long long read_size(struct event_format *event, void *ptr, int size); 53 unsigned long long eval_flag(const char *flag); ··· 83 void (*process_stat)(struct perf_stat_config *config, 84 struct perf_evsel *evsel, u64 tstamp); 85 void (*process_stat_interval)(u64 tstamp); 86 + int (*generate_script) (struct tep_handle *pevent, const char *outfile); 87 }; 88 89 extern unsigned int scripting_max_stack; ··· 94 void setup_python_scripting(void); 95 96 struct scripting_context { 97 + struct tep_handle *pevent; 98 void *event_data; 99 }; 100
+18
tools/perf/util/zlib.c
··· 5 #include <sys/stat.h> 6 #include <sys/mman.h> 7 #include <zlib.h> 8 9 #include "util/compress.h" 10 #include "util/util.h" ··· 80 close(input_fd); 81 82 return ret == Z_STREAM_END ? 0 : -1; 83 }
··· 5 #include <sys/stat.h> 6 #include <sys/mman.h> 7 #include <zlib.h> 8 + #include <linux/compiler.h> 9 + #include <unistd.h> 10 11 #include "util/compress.h" 12 #include "util/util.h" ··· 78 close(input_fd); 79 80 return ret == Z_STREAM_END ? 0 : -1; 81 + } 82 + 83 + bool gzip_is_compressed(const char *input) 84 + { 85 + int fd = open(input, O_RDONLY); 86 + const uint8_t magic[2] = { 0x1f, 0x8b }; 87 + char buf[2] = { 0 }; 88 + ssize_t rc; 89 + 90 + if (fd < 0) 91 + return -1; 92 + 93 + rc = read(fd, buf, sizeof(buf)); 94 + close(fd); 95 + return rc == sizeof(buf) ? 96 + memcmp(buf, magic, sizeof(buf)) == 0 : false; 97 }