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