aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/hw_breakpoint.h
blob: 5da472e434b75099805a801b8fdd392325940d6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#ifndef _LINUX_HW_BREAKPOINT_H
#define _LINUX_HW_BREAKPOINT_H

enum {
	HW_BREAKPOINT_LEN_1 = 1,
	HW_BREAKPOINT_LEN_2 = 2,
	HW_BREAKPOINT_LEN_4 = 4,
	HW_BREAKPOINT_LEN_8 = 8,
};

enum {
	HW_BREAKPOINT_R = 1,
	HW_BREAKPOINT_W = 2,
	HW_BREAKPOINT_X = 4,
};

#ifdef __KERNEL__

#include <linux/perf_event.h>

#ifdef CONFIG_HAVE_HW_BREAKPOINT

/* As it's for in-kernel or ptrace use, we want it to be pinned */
#define DEFINE_BREAKPOINT_ATTR(name)	\
struct perf_event_attr name = {		\
	.type = PERF_TYPE_BREAKPOINT,	\
	.size = sizeof(name),		\
	.pinned = 1,			\
};

static inline unsigned long hw_breakpoint_addr(struct perf_event *bp)
{
	return bp->attr.bp_addr;
}

static inline int hw_breakpoint_type(struct perf_event *bp)
{
	return bp->attr.bp_type;
}

static inline int hw_breakpoint_len(struct perf_event *bp)
{
	return bp->attr.bp_len;
}

extern struct perf_event *
register_user_hw_breakpoint(struct perf_event_attr *attr,
			    perf_callback_t triggered,
			    struct task_struct *tsk);

/* FIXME: only change from the attr, and don't unregister */
extern struct perf_event *
modify_user_hw_breakpoint(struct perf_event *bp,
			  struct perf_event_attr *attr,
			  perf_callback_t triggered,
			  struct task_struct *tsk);

/*
 * Kernel breakpoints are not associated with any particular thread.
 */
extern struct perf_event *
register_wide_hw_breakpoint_cpu(unsigned long addr,
				int len,
				int type,
				perf_callback_t triggered,
				int cpu,
				bool active);

extern struct perf_event **
register_wide_hw_breakpoint(unsigned long addr,
			    int len,
			    int type,
			    perf_callback_t triggered,
			    bool active);

extern int register_perf_hw_breakpoint(struct perf_event *bp);
extern int __register_perf_hw_breakpoint(struct perf_event *bp);
extern void unregister_hw_breakpoint(struct perf_event *bp);
extern void unregister_wide_hw_breakpoint(struct perf_event **cpu_events);

extern int reserve_bp_slot(struct perf_event *bp);
extern void release_bp_slot(struct perf_event *bp);

extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);

static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
{
	return &bp->hw.info;
}

#else /* !CONFIG_HAVE_HW_BREAKPOINT */

static inline struct perf_event *
register_user_hw_breakpoint(struct perf_event_attr *attr,
			    perf_callback_t triggered,
			    struct task_struct *tsk)	{ return NULL; }
static inline struct perf_event *
modify_user_hw_breakpoint(struct perf_event *bp,
			  struct perf_event_attr *attr,
			  perf_callback_t triggered,
			  struct task_struct *tsk)	{ return NULL; }
static inline struct perf_event *
register_wide_hw_breakpoint_cpu(unsigned long addr,
				int len,
				int type,
				perf_callback_t triggered,
				int cpu,
				bool active)		{ return NULL; }
static inline struct perf_event **
register_wide_hw_breakpoint(unsigned long addr,
			    int len,
			    int type,
			    perf_callback_t triggered,
			    bool active)		{ return NULL; }
static inline int
register_perf_hw_breakpoint(struct perf_event *bp)	{ return -ENOSYS; }
static inline int
__register_perf_hw_breakpoint(struct perf_event *bp) 	{ return -ENOSYS; }
static inline void unregister_hw_breakpoint(struct perf_event *bp)	{ }
static inline void
unregister_wide_hw_breakpoint(struct perf_event **cpu_events)		{ }
static inline int
reserve_bp_slot(struct perf_event *bp)			{return -ENOSYS; }
static inline void release_bp_slot(struct perf_event *bp) 		{ }

static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk)	{ }

static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
{
	return NULL;
}

#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif /* __KERNEL__ */

#endif /* _LINUX_HW_BREAKPOINT_H */