]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: add support for passing return value from trap handlers
authorKris Van Hees <kris.van.hees@oracle.com>
Thu, 22 Dec 2016 07:20:57 +0000 (02:20 -0500)
committerKris Van Hees <kris.van.hees@oracle.com>
Sat, 24 Dec 2016 02:51:47 +0000 (21:51 -0500)
Prior to this patch, trap handlers were called to service traps without
any mechanism to report back to the lowest level trap entry point.  The
DTrace FBT implementation on x86 needs to be able to do just that because
FBT probes are enabled by replacing a one-byte assembler instruction with
a one-byte instruction that causes a trap.  After the trap is handled, we
need to emulate the instruction that was replaced prior to returning to
the original instruction stream.  Because different instructions may occur
at FBT probe points, we need to be able to report back to the trap entry
point which instruction was replaced by the trap.

Handlers that do not use notify_die() always return 0.  Those who do use
notify_die() to call handlers have been modified to return the value that
the handler passed on its return.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Reviewed-By: Dan Duval <dan.duval@oracle.com>
Orabug: 25312278

arch/x86/include/asm/mce.h
arch/x86/include/asm/traps.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/kvm.c
arch/x86/kernel/nmi.c
arch/x86/kernel/traps.c
arch/x86/mm/fault.c

index 1f5a86d518db379ea65c100158df0c60988bb810..f0552a007adc8dde4c0ee2eb47e045e3bc590d97 100644 (file)
@@ -213,8 +213,8 @@ extern void mce_disable_bank(int bank);
  */
 
 /* Call the installed machine check handler for this CPU setup. */
-extern void (*machine_check_vector)(struct pt_regs *, long error_code);
-void do_machine_check(struct pt_regs *, long);
+extern int (*machine_check_vector)(struct pt_regs *, long error_code);
+int do_machine_check(struct pt_regs *, long);
 
 /*
  * Threshold handler
index 4e49d7dff78e5f30ffb6353c37277eaf6ab264aa..bb3af3db6f2216fbe5fd2b5fde1545afdc090650 100644 (file)
@@ -56,41 +56,41 @@ asmlinkage void trace_page_fault(void);
 #define trace_async_page_fault async_page_fault
 #endif
 
-dotraplinkage void do_divide_error(struct pt_regs *, long);
-dotraplinkage void do_debug(struct pt_regs *, long);
-dotraplinkage void do_nmi(struct pt_regs *, long);
-dotraplinkage void do_int3(struct pt_regs *, long);
-dotraplinkage void do_overflow(struct pt_regs *, long);
-dotraplinkage void do_bounds(struct pt_regs *, long);
-dotraplinkage void do_invalid_op(struct pt_regs *, long);
-dotraplinkage void do_device_not_available(struct pt_regs *, long);
-dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
-dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
-dotraplinkage void do_segment_not_present(struct pt_regs *, long);
-dotraplinkage void do_stack_segment(struct pt_regs *, long);
+dotraplinkage int do_divide_error(struct pt_regs *, long);
+dotraplinkage int do_debug(struct pt_regs *, long);
+dotraplinkage int do_nmi(struct pt_regs *, long);
+dotraplinkage int do_int3(struct pt_regs *, long);
+dotraplinkage int do_overflow(struct pt_regs *, long);
+dotraplinkage int do_bounds(struct pt_regs *, long);
+dotraplinkage int do_invalid_op(struct pt_regs *, long);
+dotraplinkage int do_device_not_available(struct pt_regs *, long);
+dotraplinkage int do_coprocessor_segment_overrun(struct pt_regs *, long);
+dotraplinkage int do_invalid_TSS(struct pt_regs *, long);
+dotraplinkage int do_segment_not_present(struct pt_regs *, long);
+dotraplinkage int do_stack_segment(struct pt_regs *, long);
 #ifdef CONFIG_X86_64
-dotraplinkage void do_double_fault(struct pt_regs *, long);
+dotraplinkage int do_double_fault(struct pt_regs *, long);
 asmlinkage struct pt_regs *sync_regs(struct pt_regs *);
 #endif
-dotraplinkage void do_general_protection(struct pt_regs *, long);
-dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage int do_general_protection(struct pt_regs *, long);
+dotraplinkage int do_page_fault(struct pt_regs *, unsigned long);
 #ifdef CONFIG_TRACING
-dotraplinkage void trace_do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage int trace_do_page_fault(struct pt_regs *, unsigned long);
 #else
-static inline void trace_do_page_fault(struct pt_regs *regs, unsigned long error)
+static inline int trace_do_page_fault(struct pt_regs *regs, unsigned long error)
 {
-       do_page_fault(regs, error);
+       return do_page_fault(regs, error);
 }
 #endif
-dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
-dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
-dotraplinkage void do_alignment_check(struct pt_regs *, long);
+dotraplinkage int do_spurious_interrupt_bug(struct pt_regs *, long);
+dotraplinkage int do_coprocessor_error(struct pt_regs *, long);
+dotraplinkage int do_alignment_check(struct pt_regs *, long);
 #ifdef CONFIG_X86_MCE
-dotraplinkage void do_machine_check(struct pt_regs *, long);
+dotraplinkage int do_machine_check(struct pt_regs *, long);
 #endif
-dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
+dotraplinkage int do_simd_coprocessor_error(struct pt_regs *, long);
 #ifdef CONFIG_X86_32
-dotraplinkage void do_iret_error(struct pt_regs *, long);
+dotraplinkage int do_iret_error(struct pt_regs *, long);
 #endif
 
 static inline int get_si_code(unsigned long condition)
index 20190bdac9d58ecabddd3cbe6692d0f52bb687ad..d99513d1b5230ace20d6f7b2297f3e060a4395a4 100644 (file)
@@ -1022,7 +1022,7 @@ static void mce_clear_state(unsigned long *toclear)
  * MCE broadcast. However some CPUs might be broken beyond repair,
  * so be always careful when synchronizing with others.
  */
-void do_machine_check(struct pt_regs *regs, long error_code)
+int do_machine_check(struct pt_regs *regs, long error_code)
 {
        struct mca_config *cfg = &mca_cfg;
        struct mce m, *final;
@@ -1205,6 +1205,7 @@ out:
        ist_end_non_atomic();
 done:
        ist_exit(regs, prev_state);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(do_machine_check);
 
@@ -1672,14 +1673,15 @@ static void __mcheck_cpu_init_timer(void)
 }
 
 /* Handle unconfigured int18 (should never happen) */
-static void unexpected_machine_check(struct pt_regs *regs, long error_code)
+static int unexpected_machine_check(struct pt_regs *regs, long error_code)
 {
        pr_err("CPU#%d: Unexpected int18 (Machine Check)\n",
               smp_processor_id());
+       return 0;
 }
 
 /* Call the installed machine check handler for this CPU setup. */
-void (*machine_check_vector)(struct pt_regs *, long error_code) =
+int (*machine_check_vector)(struct pt_regs *, long error_code) =
                                                unexpected_machine_check;
 
 /*
index e2532a7c7475843cd0c301b8300ffbb57e643936..db13325f8254e4ad711554af4756a760cec86d17 100644 (file)
@@ -254,7 +254,7 @@ u32 kvm_read_and_reset_pf_reason(void)
 EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason);
 NOKPROBE_SYMBOL(kvm_read_and_reset_pf_reason);
 
-dotraplinkage void
+dotraplinkage int
 do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
        enum ctx_state prev_state;
@@ -277,6 +277,8 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
                rcu_irq_exit();
                break;
        }
+
+       return 0;
 }
 NOKPROBE_SYMBOL(do_async_page_fault);
 
index d05bd2e2ee91e642b0162a00021043e79d3b4b3a..684bb77a781164789aead88063cbda8de8339178 100644 (file)
@@ -478,12 +478,12 @@ static DEFINE_PER_CPU(unsigned long, nmi_cr2);
 static DEFINE_PER_CPU(int, update_debug_stack);
 #endif
 
-dotraplinkage notrace void
+dotraplinkage notrace int
 do_nmi(struct pt_regs *regs, long error_code)
 {
        if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {
                this_cpu_write(nmi_state, NMI_LATCHED);
-               return;
+               return 0;
        }
        this_cpu_write(nmi_state, NMI_EXECUTING);
        this_cpu_write(nmi_cr2, read_cr2());
@@ -522,6 +522,7 @@ nmi_restart:
                write_cr2(this_cpu_read(nmi_cr2));
        if (this_cpu_dec_return(nmi_state))
                goto nmi_restart;
+       return 0;
 }
 NOKPROBE_SYMBOL(do_nmi);
 
index 324ab524768756b1987efbee11f06ce3ba24562b..9a94ec19be08d5450ef390cf415539435f687b65 100644 (file)
@@ -286,26 +286,28 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 }
 NOKPROBE_SYMBOL(do_trap);
 
-static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
+static int do_error_trap(struct pt_regs *regs, long error_code, char *str,
                          unsigned long trapnr, int signr)
 {
        enum ctx_state prev_state = exception_enter();
        siginfo_t info;
+       int ret;
 
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
-                       NOTIFY_STOP) {
+       ret = notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr);
+       if ((ret & NOTIFY_STOP_MASK) != NOTIFY_STOP_MASK) {
                conditional_sti(regs);
                do_trap(trapnr, signr, str, regs, error_code,
                        fill_trap_info(regs, signr, trapnr, &info));
        }
 
        exception_exit(prev_state);
+       return notifier_to_errno(ret);
 }
 
 #define DO_ERROR(trapnr, signr, str, name)                             \
-dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
+dotraplinkage int do_##name(struct pt_regs *regs, long error_code)     \
 {                                                                      \
-       do_error_trap(regs, error_code, str, trapnr, signr);            \
+       return do_error_trap(regs, error_code, str, trapnr, signr);     \
 }
 
 DO_ERROR(X86_TRAP_DE,     SIGFPE,  "divide error",             divide_error)
@@ -319,7 +321,7 @@ DO_ERROR(X86_TRAP_AC,     SIGBUS,  "alignment check",               alignment_check)
 
 #ifdef CONFIG_X86_64
 /* Runs on IST stack */
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+dotraplinkage int do_double_fault(struct pt_regs *regs, long error_code)
 {
        static const char str[] = "double fault";
        struct task_struct *tsk = current;
@@ -347,7 +349,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
                regs->ip = (unsigned long)general_protection;
                regs->sp = (unsigned long)&normal_regs->orig_ax;
 
-               return;
+               return 0;
        }
 #endif
 
@@ -366,10 +368,12 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
         */
        for (;;)
                die(str, regs, error_code);
+
+       return 0;
 }
 #endif
 
-dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
+dotraplinkage int do_bounds(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
        struct xsave_struct *xsave_buf;
@@ -439,7 +443,7 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
 
 exit:
        exception_exit(prev_state);
-       return;
+       return 0;
 exit_trap:
        /*
         * This path out is for all the cases where we could not
@@ -450,13 +454,15 @@ exit_trap:
         */
        do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
        exception_exit(prev_state);
+       return 0;
 }
 
-dotraplinkage void
+dotraplinkage int
 do_general_protection(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk;
        enum ctx_state prev_state;
+       int ret = 0;
 
        prev_state = exception_enter();
        conditional_sti(regs);
@@ -474,8 +480,9 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
                tsk->thread.error_code = error_code;
                tsk->thread.trap_nr = X86_TRAP_GP;
-               if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
-                              X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
+               ret = notify_die(DIE_GPF, "general protection fault", regs,
+                                        error_code, X86_TRAP_GP, SIGSEGV);
+               if ((ret & NOTIFY_STOP_MASK) != NOTIFY_STOP_MASK)
                        die("general protection fault", regs, error_code);
                goto exit;
        }
@@ -495,13 +502,15 @@ do_general_protection(struct pt_regs *regs, long error_code)
        force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
 exit:
        exception_exit(prev_state);
+       return notifier_to_errno(ret);
 }
 NOKPROBE_SYMBOL(do_general_protection);
 
 /* May run on IST stack. */
-dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
+dotraplinkage int notrace do_int3(struct pt_regs *regs, long error_code)
 {
        enum ctx_state prev_state;
+       int ret = 0;
 
 #ifdef CONFIG_DYNAMIC_FTRACE
        /*
@@ -510,10 +519,10 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
         */
        if (unlikely(atomic_read(&modifying_ftrace_code)) &&
            ftrace_int3_handler(regs))
-               return;
+               return 0;
 #endif
        if (poke_int3_handler(regs))
-               return;
+               return 0;
 
        prev_state = ist_enter(regs);
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
@@ -527,9 +536,12 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
                goto exit;
 #endif
 
-       if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
-                       SIGTRAP) == NOTIFY_STOP)
+       ret = notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
+                        SIGTRAP);
+       if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) {
+               ret = notifier_to_errno(ret);
                goto exit;
+       }
 
        /*
         * Let others (NMI) know that the debug stack is in use
@@ -542,6 +554,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
        debug_stack_usage_dec();
 exit:
        ist_exit(regs, prev_state);
+       return ret;
 }
 NOKPROBE_SYMBOL(do_int3);
 
@@ -614,7 +627,7 @@ NOKPROBE_SYMBOL(fixup_bad_iret);
  *
  * May run on IST stack.
  */
-dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
+dotraplinkage int do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
        enum ctx_state prev_state;
@@ -698,6 +711,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
 
 exit:
        ist_exit(regs, prev_state);
+       return 0;
 }
 NOKPROBE_SYMBOL(do_debug);
 
@@ -790,16 +804,17 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
        force_sig_info(SIGFPE, &info, task);
 }
 
-dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage int do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
        math_error(regs, error_code, X86_TRAP_MF);
        exception_exit(prev_state);
+       return 0;
 }
 
-dotraplinkage void
+dotraplinkage int
 do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
        enum ctx_state prev_state;
@@ -807,9 +822,10 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
        prev_state = exception_enter();
        math_error(regs, error_code, X86_TRAP_XF);
        exception_exit(prev_state);
+       return 0;
 }
 
-dotraplinkage void
+dotraplinkage int
 do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 {
        conditional_sti(regs);
@@ -817,6 +833,7 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
        /* No need to warn about this any longer. */
        pr_info("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
+       return 0;
 }
 
 asmlinkage __visible void __attribute__((weak)) smp_thermal_interrupt(void)
@@ -869,7 +886,7 @@ void math_state_restore(void)
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
-dotraplinkage void
+dotraplinkage int
 do_device_not_available(struct pt_regs *regs, long error_code)
 {
        enum ctx_state prev_state;
@@ -886,7 +903,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
                info.regs = regs;
                math_emulate(&info);
                exception_exit(prev_state);
-               return;
+               return 0;
        }
 #endif
        math_state_restore(); /* interrupts still off */
@@ -894,6 +911,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
        conditional_sti(regs);
 #endif
        exception_exit(prev_state);
+       return 0;
 }
 NOKPROBE_SYMBOL(do_device_not_available);
 
index 08fbe2d9344d9acfaabbe078bbc2c40f88390bf3..9cf6ad536ad64f03ff73e99e0de003121b6f29c4 100644 (file)
@@ -1302,7 +1302,7 @@ good_area:
 }
 NOKPROBE_SYMBOL(__do_page_fault);
 
-dotraplinkage void notrace
+dotraplinkage int notrace
 do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
        unsigned long address = read_cr2(); /* Get the faulting address */
@@ -1319,6 +1319,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
        prev_state = exception_enter();
        __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
+       return 0;
 }
 NOKPROBE_SYMBOL(do_page_fault);
 
@@ -1333,7 +1334,7 @@ trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
                trace_page_fault_kernel(address, regs, error_code);
 }
 
-dotraplinkage void notrace
+dotraplinkage int notrace
 trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
        /*
@@ -1349,6 +1350,7 @@ trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
        trace_page_fault_entries(address, regs, error_code);
        __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
+       return 0;
 }
 NOKPROBE_SYMBOL(trace_do_page_fault);
 #endif /* CONFIG_TRACING */