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