aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/traps.c7
-rw-r--r--include/linux/uprobes.h4
-rw-r--r--kernel/events/uprobes.c10
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
102extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); 102extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
103extern bool __weak is_trap_insn(uprobe_opcode_t *insn); 103extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
104extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); 104extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
105extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs);
105extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); 106extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t);
106extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 107extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
107extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); 108extern 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 */
131struct uprobes_state { 132struct uprobes_state {
132}; 133};
134
135#define uprobe_get_trap_addr(regs) instruction_pointer(regs)
136
133static inline int 137static inline int
134uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) 138uprobe_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
1354unsigned 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.