diff options
| -rw-r--r-- | arch/x86/kernel/traps.c | 7 | ||||
| -rw-r--r-- | include/linux/uprobes.h | 4 | ||||
| -rw-r--r-- | kernel/events/uprobes.c | 10 |
3 files changed, 18 insertions, 3 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 73b3ea32245a..3fdb20548c4b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 26 | #include <linux/uprobes.h> | ||
| 26 | #include <linux/string.h> | 27 | #include <linux/string.h> |
| 27 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 28 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| @@ -148,11 +149,11 @@ static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr, | |||
| 148 | 149 | ||
| 149 | case X86_TRAP_DE: | 150 | case X86_TRAP_DE: |
| 150 | sicode = FPE_INTDIV; | 151 | sicode = FPE_INTDIV; |
| 151 | siaddr = regs->ip; | 152 | siaddr = uprobe_get_trap_addr(regs); |
| 152 | break; | 153 | break; |
| 153 | case X86_TRAP_UD: | 154 | case X86_TRAP_UD: |
| 154 | sicode = ILL_ILLOPN; | 155 | sicode = ILL_ILLOPN; |
| 155 | siaddr = regs->ip; | 156 | siaddr = uprobe_get_trap_addr(regs); |
| 156 | break; | 157 | break; |
| 157 | case X86_TRAP_AC: | 158 | case X86_TRAP_AC: |
| 158 | sicode = BUS_ADRALN; | 159 | sicode = BUS_ADRALN; |
| @@ -531,7 +532,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) | |||
| 531 | task->thread.error_code = error_code; | 532 | task->thread.error_code = error_code; |
| 532 | info.si_signo = SIGFPE; | 533 | info.si_signo = SIGFPE; |
| 533 | info.si_errno = 0; | 534 | info.si_errno = 0; |
| 534 | info.si_addr = (void __user *)regs->ip; | 535 | info.si_addr = (void __user *)uprobe_get_trap_addr(regs); |
| 535 | if (trapnr == X86_TRAP_MF) { | 536 | if (trapnr == X86_TRAP_MF) { |
| 536 | unsigned short cwd, swd; | 537 | unsigned short cwd, swd; |
| 537 | /* | 538 | /* |
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index edff2b97b864..88c3b7e8b384 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
| @@ -102,6 +102,7 @@ extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, u | |||
| 102 | extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); | 102 | extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); |
| 103 | extern bool __weak is_trap_insn(uprobe_opcode_t *insn); | 103 | extern bool __weak is_trap_insn(uprobe_opcode_t *insn); |
| 104 | extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); | 104 | extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); |
| 105 | extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); | ||
| 105 | extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); | 106 | extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); |
| 106 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); | 107 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); |
| 107 | extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); | 108 | extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); |
| @@ -130,6 +131,9 @@ extern bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *r | |||
| 130 | #else /* !CONFIG_UPROBES */ | 131 | #else /* !CONFIG_UPROBES */ |
| 131 | struct uprobes_state { | 132 | struct uprobes_state { |
| 132 | }; | 133 | }; |
| 134 | |||
| 135 | #define uprobe_get_trap_addr(regs) instruction_pointer(regs) | ||
| 136 | |||
| 133 | static inline int | 137 | static inline int |
| 134 | uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) | 138 | uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) |
| 135 | { | 139 | { |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index a13251e8bfa4..3b02c72938a8 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
| @@ -1351,6 +1351,16 @@ unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs) | |||
| 1351 | return instruction_pointer(regs) - UPROBE_SWBP_INSN_SIZE; | 1351 | return instruction_pointer(regs) - UPROBE_SWBP_INSN_SIZE; |
| 1352 | } | 1352 | } |
| 1353 | 1353 | ||
| 1354 | unsigned long uprobe_get_trap_addr(struct pt_regs *regs) | ||
| 1355 | { | ||
| 1356 | struct uprobe_task *utask = current->utask; | ||
| 1357 | |||
| 1358 | if (unlikely(utask && utask->active_uprobe)) | ||
| 1359 | return utask->vaddr; | ||
| 1360 | |||
| 1361 | return instruction_pointer(regs); | ||
| 1362 | } | ||
| 1363 | |||
| 1354 | /* | 1364 | /* |
| 1355 | * Called with no locks held. | 1365 | * Called with no locks held. |
| 1356 | * Called in context of a exiting or a exec-ing thread. | 1366 | * Called in context of a exiting or a exec-ing thread. |
