X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=include%2Flinux%2Fkprobes.h;h=1b672f74a32f0d76d27c277c759c6c3a24135674;hb=f653398c86a1c104f0992bd788dd4bb065449be4;hp=fba39f87efec2cc3f572c6d053b9ab0d30620f27;hpb=b94cce926b2b902b79380ccba370d6f9f2980de0;p=safe%2Fjmp%2Flinux-2.6 diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index fba39f8..1b672f7 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -29,14 +29,34 @@ * and Prasanna S Panchamukhi * added function-return probes. */ -#include +#include #include #include #include +#include #include +#include +#include +#ifdef CONFIG_KPROBES #include +/* kprobe_status settings */ +#define KPROBE_HIT_ACTIVE 0x00000001 +#define KPROBE_HIT_SS 0x00000002 +#define KPROBE_REENTER 0x00000004 +#define KPROBE_HIT_SSDONE 0x00000008 + +/* Attach to insert probes on any functions which should be ignored*/ +#define __kprobes __attribute__((__section__(".kprobes.text"))) +#else /* CONFIG_KPROBES */ +typedef int kprobe_opcode_t; +struct arch_specific_insn { + int dummy; +}; +#define __kprobes +#endif /* CONFIG_KPROBES */ + struct kprobe; struct pt_regs; struct kretprobe; @@ -56,21 +76,34 @@ struct kprobe { /* list of kprobes for multi-handler support */ struct list_head list; + /*count the number of times this probe was temporarily disarmed */ + unsigned long nmissed; + /* location of the probe point */ kprobe_opcode_t *addr; + /* Allow user to indicate symbol name of the probe point */ + const char *symbol_name; + + /* Offset into the symbol */ + unsigned int offset; + /* Called before addr is executed. */ kprobe_pre_handler_t pre_handler; /* Called after addr is executed, unless... */ kprobe_post_handler_t post_handler; - /* ... called if executing addr causes a fault (eg. page fault). - * Return 1 if it handled fault, otherwise kernel will see it. */ + /* + * ... called if executing addr causes a fault (eg. page fault). + * Return 1 if it handled fault, otherwise kernel will see it. + */ kprobe_fault_handler_t fault_handler; - /* ... called if breakpoint trap occurs in probe handler. - * Return 1 if it handled break, otherwise kernel will see it. */ + /* + * ... called if breakpoint trap occurs in probe handler. + * Return 1 if it handled break, otherwise kernel will see it. + */ kprobe_break_handler_t break_handler; /* Saved opcode (which has been replaced with breakpoint) */ @@ -78,8 +111,29 @@ struct kprobe { /* copy of the original instruction */ struct arch_specific_insn ainsn; + + /* + * Indicates various status flags. + * Protected by kprobe_mutex after this kprobe is registered. + */ + u32 flags; }; +/* Kprobe status flags */ +#define KPROBE_FLAG_GONE 1 /* breakpoint has already gone */ +#define KPROBE_FLAG_DISABLED 2 /* probe is temporarily disabled */ + +/* Has this kprobe gone ? */ +static inline int kprobe_gone(struct kprobe *p) +{ + return p->flags & KPROBE_FLAG_GONE; +} + +/* Is this kprobe disabled ? */ +static inline int kprobe_disabled(struct kprobe *p) +{ + return p->flags & (KPROBE_FLAG_DISABLED | KPROBE_FLAG_GONE); +} /* * Special probe type that uses setjmp-longjmp type tricks to resume * execution at a specified entry with a matching prototype corresponding @@ -92,38 +146,12 @@ struct kprobe { */ struct jprobe { struct kprobe kp; - kprobe_opcode_t *entry; /* probe handling code to jump to */ + void *entry; /* probe handling code to jump to */ }; -#ifdef ARCH_SUPPORTS_KRETPROBES -extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs); -extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs, - unsigned long flags); -extern struct task_struct *arch_get_kprobe_task(void *ptr); -extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs); -extern void arch_kprobe_flush_task(struct task_struct *tk, spinlock_t *kp_lock); -#else /* ARCH_SUPPORTS_KRETPROBES */ -static inline void kretprobe_trampoline(void) -{ -} -static inline int trampoline_probe_handler(struct kprobe *p, - struct pt_regs *regs) -{ - return 0; -} -static inline void trampoline_post_handler(struct kprobe *p, - struct pt_regs *regs, unsigned long flags) -{ -} -static inline void arch_prepare_kretprobe(struct kretprobe *rp, - struct pt_regs *regs) -{ -} -static inline void arch_kprobe_flush_task(struct task_struct *tk) -{ -} -#define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL) -#endif /* ARCH_SUPPORTS_KRETPROBES */ +/* For backward compatibility with old code using JPROBE_ENTRY() */ +#define JPROBE_ENTRY(handler) (handler) + /* * Function-return probe - * Note: @@ -137,77 +165,185 @@ static inline void arch_kprobe_flush_task(struct task_struct *tk) struct kretprobe { struct kprobe kp; kretprobe_handler_t handler; + kretprobe_handler_t entry_handler; int maxactive; int nmissed; + size_t data_size; struct hlist_head free_instances; - struct hlist_head used_instances; + spinlock_t lock; }; struct kretprobe_instance { - struct hlist_node uflist; /* either on free list or used list */ struct hlist_node hlist; struct kretprobe *rp; - void *ret_addr; - void *stack_addr; + kprobe_opcode_t *ret_addr; + struct task_struct *task; + char data[0]; +}; + +struct kretprobe_blackpoint { + const char *name; + void *addr; +}; + +struct kprobe_blackpoint { + const char *name; + unsigned long start_addr; + unsigned long range; }; #ifdef CONFIG_KPROBES -/* Locks kprobe: irq must be disabled */ -void lock_kprobes(void); -void unlock_kprobes(void); +DECLARE_PER_CPU(struct kprobe *, current_kprobe); +DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); -/* kprobe running now on this CPU? */ -static inline int kprobe_running(void) +/* + * For #ifdef avoidance: + */ +static inline int kprobes_built_in(void) { - extern unsigned int kprobe_cpu; - return kprobe_cpu == smp_processor_id(); + return 1; +} + +#ifdef CONFIG_KRETPROBES +extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, + struct pt_regs *regs); +extern int arch_trampoline_kprobe(struct kprobe *p); +#else /* CONFIG_KRETPROBES */ +static inline void arch_prepare_kretprobe(struct kretprobe *rp, + struct pt_regs *regs) +{ +} +static inline int arch_trampoline_kprobe(struct kprobe *p) +{ + return 0; +} +#endif /* CONFIG_KRETPROBES */ + +extern struct kretprobe_blackpoint kretprobe_blacklist[]; + +static inline void kretprobe_assert(struct kretprobe_instance *ri, + unsigned long orig_ret_address, unsigned long trampoline_address) +{ + if (!orig_ret_address || (orig_ret_address == trampoline_address)) { + printk("kretprobe BUG!: Processing kretprobe %p @ %p\n", + ri->rp, ri->rp->kp.addr); + BUG(); + } +} + +#ifdef CONFIG_KPROBES_SANITY_TEST +extern int init_test_probes(void); +#else +static inline int init_test_probes(void) +{ + return 0; } +#endif /* CONFIG_KPROBES_SANITY_TEST */ extern int arch_prepare_kprobe(struct kprobe *p); -extern void arch_copy_kprobe(struct kprobe *p); -extern void arch_remove_kprobe(struct kprobe *p); +extern void arch_arm_kprobe(struct kprobe *p); +extern void arch_disarm_kprobe(struct kprobe *p); +extern int arch_init_kprobes(void); extern void show_registers(struct pt_regs *regs); +extern kprobe_opcode_t *get_insn_slot(void); +extern void free_insn_slot(kprobe_opcode_t *slot, int dirty); +extern void kprobes_inc_nmissed_count(struct kprobe *p); -/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ +/* Get the kprobe at this addr (if any) - called with preemption disabled */ struct kprobe *get_kprobe(void *addr); +void kretprobe_hash_lock(struct task_struct *tsk, + struct hlist_head **head, unsigned long *flags); +void kretprobe_hash_unlock(struct task_struct *tsk, unsigned long *flags); struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk); +/* kprobe_running() will just return the current_kprobe on this CPU */ +static inline struct kprobe *kprobe_running(void) +{ + return (__get_cpu_var(current_kprobe)); +} + +static inline void reset_current_kprobe(void) +{ + __get_cpu_var(current_kprobe) = NULL; +} + +static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void) +{ + return (&__get_cpu_var(kprobe_ctlblk)); +} + int register_kprobe(struct kprobe *p); void unregister_kprobe(struct kprobe *p); +int register_kprobes(struct kprobe **kps, int num); +void unregister_kprobes(struct kprobe **kps, int num); int setjmp_pre_handler(struct kprobe *, struct pt_regs *); int longjmp_break_handler(struct kprobe *, struct pt_regs *); int register_jprobe(struct jprobe *p); void unregister_jprobe(struct jprobe *p); +int register_jprobes(struct jprobe **jps, int num); +void unregister_jprobes(struct jprobe **jps, int num); void jprobe_return(void); +unsigned long arch_deref_entry_point(void *); int register_kretprobe(struct kretprobe *rp); void unregister_kretprobe(struct kretprobe *rp); +int register_kretprobes(struct kretprobe **rps, int num); +void unregister_kretprobes(struct kretprobe **rps, int num); -struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); -struct kretprobe_instance *get_rp_inst(void *sara); -struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk); -void add_rp_inst(struct kretprobe_instance *ri); void kprobe_flush_task(struct task_struct *tk); -void recycle_rp_inst(struct kretprobe_instance *ri); -#else /* CONFIG_KPROBES */ -static inline int kprobe_running(void) +void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); + +int disable_kprobe(struct kprobe *kp); +int enable_kprobe(struct kprobe *kp); + +void dump_kprobe(struct kprobe *kp); + +#else /* !CONFIG_KPROBES: */ + +static inline int kprobes_built_in(void) +{ + return 0; +} +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { return 0; } +static inline struct kprobe *get_kprobe(void *addr) +{ + return NULL; +} +static inline struct kprobe *kprobe_running(void) +{ + return NULL; +} static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; } +static inline int register_kprobes(struct kprobe **kps, int num) +{ + return -ENOSYS; +} static inline void unregister_kprobe(struct kprobe *p) { } +static inline void unregister_kprobes(struct kprobe **kps, int num) +{ +} static inline int register_jprobe(struct jprobe *p) { return -ENOSYS; } +static inline int register_jprobes(struct jprobe **jps, int num) +{ + return -ENOSYS; +} static inline void unregister_jprobe(struct jprobe *p) { } +static inline void unregister_jprobes(struct jprobe **jps, int num) +{ +} static inline void jprobe_return(void) { } @@ -215,11 +351,43 @@ static inline int register_kretprobe(struct kretprobe *rp) { return -ENOSYS; } +static inline int register_kretprobes(struct kretprobe **rps, int num) +{ + return -ENOSYS; +} static inline void unregister_kretprobe(struct kretprobe *rp) { } +static inline void unregister_kretprobes(struct kretprobe **rps, int num) +{ +} static inline void kprobe_flush_task(struct task_struct *tk) { } -#endif /* CONFIG_KPROBES */ -#endif /* _LINUX_KPROBES_H */ +static inline int disable_kprobe(struct kprobe *kp) +{ + return -ENOSYS; +} +static inline int enable_kprobe(struct kprobe *kp) +{ + return -ENOSYS; +} +#endif /* CONFIG_KPROBES */ +static inline int disable_kretprobe(struct kretprobe *rp) +{ + return disable_kprobe(&rp->kp); +} +static inline int enable_kretprobe(struct kretprobe *rp) +{ + return enable_kprobe(&rp->kp); +} +static inline int disable_jprobe(struct jprobe *jp) +{ + return disable_kprobe(&jp->kp); +} +static inline int enable_jprobe(struct jprobe *jp) +{ + return enable_kprobe(&jp->kp); +} + +#endif /* _LINUX_KPROBES_H */