aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-record.c11
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/perf-hooks.c44
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/perf-hooks-list.h3
-rw-r--r--tools/perf/util/perf-hooks.c84
-rw-r--r--tools/perf/util/perf-hooks.h37
9 files changed, 187 insertions, 0 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 67d2a9003294..fa26865364b6 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -37,6 +37,7 @@
37#include "util/llvm-utils.h" 37#include "util/llvm-utils.h"
38#include "util/bpf-loader.h" 38#include "util/bpf-loader.h"
39#include "util/trigger.h" 39#include "util/trigger.h"
40#include "util/perf-hooks.h"
40#include "asm/bug.h" 41#include "asm/bug.h"
41 42
42#include <unistd.h> 43#include <unistd.h>
@@ -206,6 +207,12 @@ static void sig_handler(int sig)
206 done = 1; 207 done = 1;
207} 208}
208 209
210static void sigsegv_handler(int sig)
211{
212 perf_hooks__recover();
213 sighandler_dump_stack(sig);
214}
215
209static void record__sig_exit(void) 216static void record__sig_exit(void)
210{ 217{
211 if (signr == -1) 218 if (signr == -1)
@@ -833,6 +840,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
833 signal(SIGCHLD, sig_handler); 840 signal(SIGCHLD, sig_handler);
834 signal(SIGINT, sig_handler); 841 signal(SIGINT, sig_handler);
835 signal(SIGTERM, sig_handler); 842 signal(SIGTERM, sig_handler);
843 signal(SIGSEGV, sigsegv_handler);
836 844
837 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) { 845 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) {
838 signal(SIGUSR2, snapshot_sig_handler); 846 signal(SIGUSR2, snapshot_sig_handler);
@@ -970,6 +978,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
970 978
971 trigger_ready(&auxtrace_snapshot_trigger); 979 trigger_ready(&auxtrace_snapshot_trigger);
972 trigger_ready(&switch_output_trigger); 980 trigger_ready(&switch_output_trigger);
981 perf_hooks__invoke_record_start();
973 for (;;) { 982 for (;;) {
974 unsigned long long hits = rec->samples; 983 unsigned long long hits = rec->samples;
975 984
@@ -1114,6 +1123,8 @@ out_child:
1114 } 1123 }
1115 } 1124 }
1116 1125
1126 perf_hooks__invoke_record_end();
1127
1117 if (!err && !quiet) { 1128 if (!err && !quiet) {
1118 char samples[128]; 1129 char samples[128];
1119 const char *postfix = rec->timestamp_filename ? 1130 const char *postfix = rec->timestamp_filename ?
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 8a4ce492f7b2..af3ec94869aa 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -42,6 +42,7 @@ perf-y += backward-ring-buffer.o
42perf-y += sdt.o 42perf-y += sdt.o
43perf-y += is_printable_array.o 43perf-y += is_printable_array.o
44perf-y += bitmap.o 44perf-y += bitmap.o
45perf-y += perf-hooks.o
45 46
46$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build 47$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
47 $(call rule_mkdir) 48 $(call rule_mkdir)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 778668a2a966..dab83f7042fa 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -230,6 +230,10 @@ static struct test generic_tests[] = {
230 .func = test__bitmap_print, 230 .func = test__bitmap_print,
231 }, 231 },
232 { 232 {
233 .desc = "Test perf hooks",
234 .func = test__perf_hooks,
235 },
236 {
233 .func = NULL, 237 .func = NULL,
234 }, 238 },
235}; 239};
diff --git a/tools/perf/tests/perf-hooks.c b/tools/perf/tests/perf-hooks.c
new file mode 100644
index 000000000000..9338cb2c25ab
--- /dev/null
+++ b/tools/perf/tests/perf-hooks.c
@@ -0,0 +1,44 @@
1#include <signal.h>
2#include <stdlib.h>
3
4#include "tests.h"
5#include "debug.h"
6#include "util.h"
7#include "perf-hooks.h"
8
9static void sigsegv_handler(int sig __maybe_unused)
10{
11 pr_debug("SIGSEGV is observed as expected, try to recover.\n");
12 perf_hooks__recover();
13 signal(SIGSEGV, SIG_DFL);
14 raise(SIGSEGV);
15 exit(-1);
16}
17
18static int hook_flags;
19
20static void the_hook(void)
21{
22 int *p = NULL;
23
24 hook_flags = 1234;
25
26 /* Generate a segfault, test perf_hooks__recover */
27 *p = 0;
28}
29
30int test__perf_hooks(int subtest __maybe_unused)
31{
32 signal(SIGSEGV, sigsegv_handler);
33 perf_hooks__set_hook("test", the_hook);
34 perf_hooks__invoke_test();
35
36 /* hook is triggered? */
37 if (hook_flags != 1234)
38 return TEST_FAIL;
39
40 /* the buggy hook is removed? */
41 if (perf_hooks__get_hook("test"))
42 return TEST_FAIL;
43 return TEST_OK;
44}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 7c196c585472..3a1f98f291ba 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -91,6 +91,7 @@ int test__cpu_map_print(int subtest);
91int test__sdt_event(int subtest); 91int test__sdt_event(int subtest);
92int test__is_printable_array(int subtest); 92int test__is_printable_array(int subtest);
93int test__bitmap_print(int subtest); 93int test__bitmap_print(int subtest);
94int test__perf_hooks(int subtest);
94 95
95#if defined(__arm__) || defined(__aarch64__) 96#if defined(__arm__) || defined(__aarch64__)
96#ifdef HAVE_DWARF_UNWIND_SUPPORT 97#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 1dc67efad634..b2a47aac8d1c 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -123,6 +123,8 @@ libperf-$(CONFIG_LIBELF) += genelf.o
123libperf-$(CONFIG_DWARF) += genelf_debug.o 123libperf-$(CONFIG_DWARF) += genelf_debug.o
124endif 124endif
125 125
126libperf-y += perf-hooks.o
127
126CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 128CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
127# avoid compiler warnings in 32-bit mode 129# avoid compiler warnings in 32-bit mode
128CFLAGS_genelf_debug.o += -Wno-packed 130CFLAGS_genelf_debug.o += -Wno-packed
diff --git a/tools/perf/util/perf-hooks-list.h b/tools/perf/util/perf-hooks-list.h
new file mode 100644
index 000000000000..2867c07ee84e
--- /dev/null
+++ b/tools/perf/util/perf-hooks-list.h
@@ -0,0 +1,3 @@
1PERF_HOOK(record_start)
2PERF_HOOK(record_end)
3PERF_HOOK(test)
diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c
new file mode 100644
index 000000000000..4ce88e37dd63
--- /dev/null
+++ b/tools/perf/util/perf-hooks.c
@@ -0,0 +1,84 @@
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 "util/util.h"
13#include "util/debug.h"
14#include "util/perf-hooks.h"
15
16static sigjmp_buf jmpbuf;
17static const struct perf_hook_desc *current_perf_hook;
18
19void perf_hooks__invoke(const struct perf_hook_desc *desc)
20{
21 if (!(desc && desc->p_hook_func && *desc->p_hook_func))
22 return;
23
24 if (sigsetjmp(jmpbuf, 1)) {
25 pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n",
26 desc->hook_name);
27 *(current_perf_hook->p_hook_func) = NULL;
28 } else {
29 current_perf_hook = desc;
30 (**desc->p_hook_func)();
31 }
32 current_perf_hook = NULL;
33}
34
35void perf_hooks__recover(void)
36{
37 if (current_perf_hook)
38 siglongjmp(jmpbuf, 1);
39}
40
41#define PERF_HOOK(name) \
42perf_hook_func_t __perf_hook_func_##name = NULL; \
43struct perf_hook_desc __perf_hook_desc_##name = \
44 {.hook_name = #name, .p_hook_func = &__perf_hook_func_##name};
45#include "perf-hooks-list.h"
46#undef PERF_HOOK
47
48#define PERF_HOOK(name) \
49 &__perf_hook_desc_##name,
50
51static struct perf_hook_desc *perf_hooks[] = {
52#include "perf-hooks-list.h"
53};
54#undef PERF_HOOK
55
56int perf_hooks__set_hook(const char *hook_name,
57 perf_hook_func_t hook_func)
58{
59 unsigned int i;
60
61 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
62 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
63 continue;
64
65 if (*(perf_hooks[i]->p_hook_func))
66 pr_warning("Overwrite existing hook: %s\n", hook_name);
67 *(perf_hooks[i]->p_hook_func) = hook_func;
68 return 0;
69 }
70 return -ENOENT;
71}
72
73perf_hook_func_t perf_hooks__get_hook(const char *hook_name)
74{
75 unsigned int i;
76
77 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
78 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
79 continue;
80
81 return *(perf_hooks[i]->p_hook_func);
82 }
83 return ERR_PTR(-ENOENT);
84}
diff --git a/tools/perf/util/perf-hooks.h b/tools/perf/util/perf-hooks.h
new file mode 100644
index 000000000000..1d482b26b4b9
--- /dev/null
+++ b/tools/perf/util/perf-hooks.h
@@ -0,0 +1,37 @@
1#ifndef PERF_UTIL_PERF_HOOKS_H
2#define PERF_UTIL_PERF_HOOKS_H
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8typedef void (*perf_hook_func_t)(void);
9struct perf_hook_desc {
10 const char * const hook_name;
11 perf_hook_func_t * const p_hook_func;
12};
13
14extern void perf_hooks__invoke(const struct perf_hook_desc *);
15extern void perf_hooks__recover(void);
16
17#define PERF_HOOK(name) \
18extern struct perf_hook_desc __perf_hook_desc_##name; \
19static inline void perf_hooks__invoke_##name(void) \
20{ \
21 perf_hooks__invoke(&__perf_hook_desc_##name); \
22}
23
24#include "perf-hooks-list.h"
25#undef PERF_HOOK
26
27extern int
28perf_hooks__set_hook(const char *hook_name,
29 perf_hook_func_t hook_func);
30
31extern perf_hook_func_t
32perf_hooks__get_hook(const char *hook_name);
33
34#ifdef __cplusplus
35}
36#endif
37#endif