1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _LINUX_HW_BREAKPOINT_H |
3 | #define _LINUX_HW_BREAKPOINT_H |
4 | |
5 | #include <linux/perf_event.h> |
6 | #include <uapi/linux/hw_breakpoint.h> |
7 | |
8 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
9 | |
10 | extern int __init init_hw_breakpoint(void); |
11 | |
12 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) |
13 | { |
14 | memset(attr, 0, sizeof(*attr)); |
15 | |
16 | attr->type = PERF_TYPE_BREAKPOINT; |
17 | attr->size = sizeof(*attr); |
18 | /* |
19 | * As it's for in-kernel or ptrace use, we want it to be pinned |
20 | * and to call its callback every hits. |
21 | */ |
22 | attr->pinned = 1; |
23 | attr->sample_period = 1; |
24 | } |
25 | |
26 | static inline void ptrace_breakpoint_init(struct perf_event_attr *attr) |
27 | { |
28 | hw_breakpoint_init(attr); |
29 | attr->exclude_kernel = 1; |
30 | } |
31 | |
32 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) |
33 | { |
34 | return bp->attr.bp_addr; |
35 | } |
36 | |
37 | static inline int hw_breakpoint_type(struct perf_event *bp) |
38 | { |
39 | return bp->attr.bp_type; |
40 | } |
41 | |
42 | static inline unsigned long hw_breakpoint_len(struct perf_event *bp) |
43 | { |
44 | return bp->attr.bp_len; |
45 | } |
46 | |
47 | extern struct perf_event * |
48 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
49 | perf_overflow_handler_t triggered, |
50 | void *context, |
51 | struct task_struct *tsk); |
52 | |
53 | /* FIXME: only change from the attr, and don't unregister */ |
54 | extern int |
55 | modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); |
56 | extern int |
57 | modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr, |
58 | bool check); |
59 | |
60 | /* |
61 | * Kernel breakpoints are not associated with any particular thread. |
62 | */ |
63 | extern struct perf_event * |
64 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
65 | perf_overflow_handler_t triggered, |
66 | void *context, |
67 | int cpu); |
68 | |
69 | extern struct perf_event * __percpu * |
70 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
71 | perf_overflow_handler_t triggered, |
72 | void *context); |
73 | |
74 | extern int register_perf_hw_breakpoint(struct perf_event *bp); |
75 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); |
76 | extern void unregister_hw_breakpoint(struct perf_event *bp); |
77 | extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); |
78 | |
79 | extern int dbg_reserve_bp_slot(struct perf_event *bp); |
80 | extern int dbg_release_bp_slot(struct perf_event *bp); |
81 | extern int reserve_bp_slot(struct perf_event *bp); |
82 | extern void release_bp_slot(struct perf_event *bp); |
83 | |
84 | extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); |
85 | |
86 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) |
87 | { |
88 | return &bp->hw.info; |
89 | } |
90 | |
91 | #else /* !CONFIG_HAVE_HW_BREAKPOINT */ |
92 | |
93 | static inline int __init init_hw_breakpoint(void) { return 0; } |
94 | |
95 | static inline struct perf_event * |
96 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
97 | perf_overflow_handler_t triggered, |
98 | void *context, |
99 | struct task_struct *tsk) { return NULL; } |
100 | static inline int |
101 | modify_user_hw_breakpoint(struct perf_event *bp, |
102 | struct perf_event_attr *attr) { return -ENOSYS; } |
103 | static inline int |
104 | modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr, |
105 | bool check) { return -ENOSYS; } |
106 | |
107 | static inline struct perf_event * |
108 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
109 | perf_overflow_handler_t triggered, |
110 | void *context, |
111 | int cpu) { return NULL; } |
112 | static inline struct perf_event * __percpu * |
113 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
114 | perf_overflow_handler_t triggered, |
115 | void *context) { return NULL; } |
116 | static inline int |
117 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } |
118 | static inline int |
119 | __register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } |
120 | static inline void unregister_hw_breakpoint(struct perf_event *bp) { } |
121 | static inline void |
122 | unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) { } |
123 | static inline int |
124 | reserve_bp_slot(struct perf_event *bp) {return -ENOSYS; } |
125 | static inline void release_bp_slot(struct perf_event *bp) { } |
126 | |
127 | static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } |
128 | |
129 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) |
130 | { |
131 | return NULL; |
132 | } |
133 | |
134 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
135 | #endif /* _LINUX_HW_BREAKPOINT_H */ |
136 | |