summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-05-12 18:24:45 +0200
committerOleg Nesterov <oleg@redhat.com>2014-05-14 13:57:28 +0200
commitb02ef20a9fba08948e643d3eec0efadf1da01a44 (patch)
treed0db097668940dce698fec8b00d228cd29c1dee0 /include
parentx86/traps: Kill DO_ERROR_INFO() (diff)
downloadlinux-b02ef20a9fba08948e643d3eec0efadf1da01a44.tar.xz
linux-b02ef20a9fba08948e643d3eec0efadf1da01a44.zip
uprobes/x86: Fix the wrong ->si_addr when xol triggers a trap
If the probed insn triggers a trap, ->si_addr = regs->ip is technically correct, but this is not what the signal handler wants; we need to pass the address of the probed insn, not the address of xol slot. Add the new arch-agnostic helper, uprobe_get_trap_addr(), and change fill_trap_info() and math_error() to use it. !CONFIG_UPROBES case in uprobes.h uses a macro to avoid include hell and ensure that it can be compiled even if an architecture doesn't define instruction_pointer(). Test-case: #include <signal.h> #include <stdio.h> #include <unistd.h> extern void probe_div(void); void sigh(int sig, siginfo_t *info, void *c) { int passed = (info->si_addr == probe_div); printf(passed ? "PASS\n" : "FAIL\n"); _exit(!passed); } int main(void) { struct sigaction sa = { .sa_sigaction = sigh, .sa_flags = SA_SIGINFO, }; sigaction(SIGFPE, &sa, NULL); asm ( "xor %ecx,%ecx\n" ".globl probe_div; probe_div:\n" "idiv %ecx\n" ); return 0; } it fails if probe_div() is probed. Note: show_unhandled_signals users should probably use this helper too, but we need to cleanup them first. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/uprobes.h4
1 files changed, 4 insertions, 0 deletions
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
extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
+extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs);
extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t);
extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
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
#else /* !CONFIG_UPROBES */
struct uprobes_state {
};
+
+#define uprobe_get_trap_addr(regs) instruction_pointer(regs)
+
static inline int
uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
{