aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/uprobes.h
diff options
context:
space:
mode:
authorSrikar Dronamraju <srikar@linux.vnet.ibm.com>2012-03-13 14:00:11 -0400
committerIngo Molnar <mingo@elte.hu>2012-03-14 02:41:36 -0400
commit0326f5a94ddea33fa331b2519f4172f4fb387baa (patch)
tree5485c637754a126c90852e5285842e8462d2826a /include/linux/uprobes.h
parentef15eda98217f5183f457e7a2de8b79555ef908b (diff)
uprobes/core: Handle breakpoint and singlestep exceptions
Uprobes uses exception notifiers to get to know if a thread hit a breakpoint or a singlestep exception. When a thread hits a uprobe or is singlestepping post a uprobe hit, the uprobe exception notifier sets its TIF_UPROBE bit, which will then be checked on its return to userspace path (do_notify_resume() ->uprobe_notify_resume()), where the consumers handlers are run (in task context) based on the defined filters. Uprobe hits are thread specific and hence we need to maintain information about if a task hit a uprobe, what uprobe was hit, the slot where the original instruction was copied for xol so that it can be singlestepped with appropriate fixups. In some cases, special care is needed for instructions that are executed out of line (xol). These are architecture specific artefacts, such as handling RIP relative instructions on x86_64. Since the instruction at which the uprobe was inserted is executed out of line, architecture specific fixups are added so that the thread continues normal execution in the presence of a uprobe. Postpone the signals until we execute the probed insn. post_xol() path does a recalc_sigpending() before return to user-mode, this ensures the signal can't be lost. Uprobes relies on DIE_DEBUG notification to notify if a singlestep is complete. Adds x86 specific uprobe exception notifiers and appropriate hooks needed to determine a uprobe hit and subsequent post processing. Add requisite x86 fixups for xol for uprobes. Specific cases needing fixups include relative jumps (x86_64), calls, etc. Where possible, we check and skip singlestepping the breakpointed instructions. For now we skip single byte as well as few multibyte nop instructions. However this can be extended to other instructions too. Credits to Oleg Nesterov for suggestions/patches related to signal, breakpoint, singlestep handling code. Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> Cc: Linux-mm <linux-mm@kvack.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Christoph Hellwig <hch@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20120313180011.29771.89027.sendpatchset@srdronam.in.ibm.com [ Performed various cleanliness edits ] Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/linux/uprobes.h')
-rw-r--r--include/linux/uprobes.h55
1 files changed, 52 insertions, 3 deletions
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index eac525f41b94..5ec778fdce6f 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -28,8 +28,9 @@
28#include <linux/rbtree.h> 28#include <linux/rbtree.h>
29 29
30struct vm_area_struct; 30struct vm_area_struct;
31
31#ifdef CONFIG_ARCH_SUPPORTS_UPROBES 32#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
32#include <asm/uprobes.h> 33# include <asm/uprobes.h>
33#endif 34#endif
34 35
35/* flags that denote/change uprobes behaviour */ 36/* flags that denote/change uprobes behaviour */
@@ -39,6 +40,8 @@ struct vm_area_struct;
39 40
40/* Dont run handlers when first register/ last unregister in progress*/ 41/* Dont run handlers when first register/ last unregister in progress*/
41#define UPROBE_RUN_HANDLER 0x2 42#define UPROBE_RUN_HANDLER 0x2
43/* Can skip singlestep */
44#define UPROBE_SKIP_SSTEP 0x4
42 45
43struct uprobe_consumer { 46struct uprobe_consumer {
44 int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); 47 int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
@@ -52,13 +55,42 @@ struct uprobe_consumer {
52}; 55};
53 56
54#ifdef CONFIG_UPROBES 57#ifdef CONFIG_UPROBES
58enum uprobe_task_state {
59 UTASK_RUNNING,
60 UTASK_BP_HIT,
61 UTASK_SSTEP,
62 UTASK_SSTEP_ACK,
63 UTASK_SSTEP_TRAPPED,
64};
65
66/*
67 * uprobe_task: Metadata of a task while it singlesteps.
68 */
69struct uprobe_task {
70 enum uprobe_task_state state;
71 struct arch_uprobe_task autask;
72
73 struct uprobe *active_uprobe;
74
75 unsigned long xol_vaddr;
76 unsigned long vaddr;
77};
78
55extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); 79extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
56extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); 80extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify);
57extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); 81extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
58extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 82extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
59extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 83extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
60extern int uprobe_mmap(struct vm_area_struct *vma); 84extern int uprobe_mmap(struct vm_area_struct *vma);
61#else /* CONFIG_UPROBES is not defined */ 85extern void uprobe_free_utask(struct task_struct *t);
86extern void uprobe_copy_process(struct task_struct *t);
87extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
88extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
89extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
90extern void uprobe_notify_resume(struct pt_regs *regs);
91extern bool uprobe_deny_signal(void);
92extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
93#else /* !CONFIG_UPROBES */
62static inline int 94static inline int
63uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) 95uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
64{ 96{
@@ -72,5 +104,22 @@ static inline int uprobe_mmap(struct vm_area_struct *vma)
72{ 104{
73 return 0; 105 return 0;
74} 106}
75#endif /* CONFIG_UPROBES */ 107static inline void uprobe_notify_resume(struct pt_regs *regs)
108{
109}
110static inline bool uprobe_deny_signal(void)
111{
112 return false;
113}
114static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
115{
116 return 0;
117}
118static inline void uprobe_free_utask(struct task_struct *t)
119{
120}
121static inline void uprobe_copy_process(struct task_struct *t)
122{
123}
124#endif /* !CONFIG_UPROBES */
76#endif /* _LINUX_UPROBES_H */ 125#endif /* _LINUX_UPROBES_H */