1 /* 2 * perf_hooks.c 3 * 4 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com> 5 * Copyright (C) 2016 Huawei Inc. 6 */ 7 8 #include <errno.h> 9 #include <stdlib.h> 10 #include <setjmp.h> 11 #include <linux/err.h> 12 #include <linux/kernel.h> 13 #include "util/util.h" 14 #include "util/debug.h" 15 #include "util/perf-hooks.h" 16 17 static sigjmp_buf jmpbuf; 18 static const struct perf_hook_desc *current_perf_hook; 19 20 void perf_hooks__invoke(const struct perf_hook_desc *desc) 21 { 22 if (!(desc && desc->p_hook_func && *desc->p_hook_func)) 23 return; 24 25 if (sigsetjmp(jmpbuf, 1)) { 26 pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n", 27 desc->hook_name); 28 *(current_perf_hook->p_hook_func) = NULL; 29 } else { 30 current_perf_hook = desc; 31 (**desc->p_hook_func)(desc->hook_ctx); 32 } 33 current_perf_hook = NULL; 34 } 35 36 void perf_hooks__recover(void) 37 { 38 if (current_perf_hook) 39 siglongjmp(jmpbuf, 1); 40 } 41 42 #define PERF_HOOK(name) \ 43 perf_hook_func_t __perf_hook_func_##name = NULL; \ 44 struct perf_hook_desc __perf_hook_desc_##name = \ 45 {.hook_name = #name, \ 46 .p_hook_func = &__perf_hook_func_##name, \ 47 .hook_ctx = NULL}; 48 #include "perf-hooks-list.h" 49 #undef PERF_HOOK 50 51 #define PERF_HOOK(name) \ 52 &__perf_hook_desc_##name, 53 54 static struct perf_hook_desc *perf_hooks[] = { 55 #include "perf-hooks-list.h" 56 }; 57 #undef PERF_HOOK 58 59 int perf_hooks__set_hook(const char *hook_name, 60 perf_hook_func_t hook_func, 61 void *hook_ctx) 62 { 63 unsigned int i; 64 65 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { 66 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) 67 continue; 68 69 if (*(perf_hooks[i]->p_hook_func)) 70 pr_warning("Overwrite existing hook: %s\n", hook_name); 71 *(perf_hooks[i]->p_hook_func) = hook_func; 72 perf_hooks[i]->hook_ctx = hook_ctx; 73 return 0; 74 } 75 return -ENOENT; 76 } 77 78 perf_hook_func_t perf_hooks__get_hook(const char *hook_name) 79 { 80 unsigned int i; 81 82 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { 83 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) 84 continue; 85 86 return *(perf_hooks[i]->p_hook_func); 87 } 88 return ERR_PTR(-ENOENT); 89 } 90