diff options
| author | Ingo Molnar <mingo@kernel.org> | 2014-06-05 05:18:03 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2014-06-05 06:26:27 -0400 |
| commit | c56d34064b6eb9f9cde9e35bbfe16eedf3d81f94 (patch) | |
| tree | 9877ef9e1b238e14a1878f10d51ea55fbca5f619 | |
| parent | b13fa91421213a8d1fd05086050f05e994f3b72d (diff) | |
| parent | a03b1e1c372b60183b8141cdd161316429fab5ac (diff) | |
Merge branch 'perf/uprobes' into perf/core
These bits from Oleg are fully cooked, ship them to Linus.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | arch/x86/include/asm/traps.h | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/uprobes.h | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/process_64.c | 7 | ||||
| -rw-r--r-- | arch/x86/kernel/traps.c | 110 | ||||
| -rw-r--r-- | arch/x86/kernel/uprobes.c | 506 | ||||
| -rw-r--r-- | include/linux/uprobes.h | 4 | ||||
| -rw-r--r-- | kernel/events/uprobes.c | 35 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 46 |
8 files changed, 402 insertions, 317 deletions
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 58d66fe06b61..a7b212db9e04 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h | |||
| @@ -98,7 +98,6 @@ static inline int get_si_code(unsigned long condition) | |||
| 98 | 98 | ||
| 99 | extern int panic_on_unrecovered_nmi; | 99 | extern int panic_on_unrecovered_nmi; |
| 100 | 100 | ||
| 101 | void math_error(struct pt_regs *, int, int); | ||
| 102 | void math_emulate(struct math_emu_info *); | 101 | void math_emulate(struct math_emu_info *); |
| 103 | #ifndef CONFIG_X86_32 | 102 | #ifndef CONFIG_X86_32 |
| 104 | asmlinkage void smp_thermal_interrupt(void); | 103 | asmlinkage void smp_thermal_interrupt(void); |
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 93bee7b93854..7be3c079e389 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
| @@ -41,18 +41,18 @@ struct arch_uprobe { | |||
| 41 | u8 ixol[MAX_UINSN_BYTES]; | 41 | u8 ixol[MAX_UINSN_BYTES]; |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | u16 fixups; | ||
| 45 | const struct uprobe_xol_ops *ops; | 44 | const struct uprobe_xol_ops *ops; |
| 46 | 45 | ||
| 47 | union { | 46 | union { |
| 48 | #ifdef CONFIG_X86_64 | ||
| 49 | unsigned long rip_rela_target_address; | ||
| 50 | #endif | ||
| 51 | struct { | 47 | struct { |
| 52 | s32 offs; | 48 | s32 offs; |
| 53 | u8 ilen; | 49 | u8 ilen; |
| 54 | u8 opc1; | 50 | u8 opc1; |
| 55 | } branch; | 51 | } branch; |
| 52 | struct { | ||
| 53 | u8 fixups; | ||
| 54 | u8 ilen; | ||
| 55 | } def; | ||
| 56 | }; | 56 | }; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 9c0280f93d05..9b53940981b7 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
| @@ -413,12 +413,11 @@ void set_personality_ia32(bool x32) | |||
| 413 | set_thread_flag(TIF_ADDR32); | 413 | set_thread_flag(TIF_ADDR32); |
| 414 | 414 | ||
| 415 | /* Mark the associated mm as containing 32-bit tasks. */ | 415 | /* Mark the associated mm as containing 32-bit tasks. */ |
| 416 | if (current->mm) | ||
| 417 | current->mm->context.ia32_compat = 1; | ||
| 418 | |||
| 419 | if (x32) { | 416 | if (x32) { |
| 420 | clear_thread_flag(TIF_IA32); | 417 | clear_thread_flag(TIF_IA32); |
| 421 | set_thread_flag(TIF_X32); | 418 | set_thread_flag(TIF_X32); |
| 419 | if (current->mm) | ||
| 420 | current->mm->context.ia32_compat = TIF_X32; | ||
| 422 | current->personality &= ~READ_IMPLIES_EXEC; | 421 | current->personality &= ~READ_IMPLIES_EXEC; |
| 423 | /* is_compat_task() uses the presence of the x32 | 422 | /* is_compat_task() uses the presence of the x32 |
| 424 | syscall bit flag to determine compat status */ | 423 | syscall bit flag to determine compat status */ |
| @@ -426,6 +425,8 @@ void set_personality_ia32(bool x32) | |||
| 426 | } else { | 425 | } else { |
| 427 | set_thread_flag(TIF_IA32); | 426 | set_thread_flag(TIF_IA32); |
| 428 | clear_thread_flag(TIF_X32); | 427 | clear_thread_flag(TIF_X32); |
| 428 | if (current->mm) | ||
| 429 | current->mm->context.ia32_compat = TIF_IA32; | ||
| 429 | current->personality |= force_personality32; | 430 | current->personality |= force_personality32; |
| 430 | /* Prepare the first "return" to user space */ | 431 | /* Prepare the first "return" to user space */ |
| 431 | current_thread_info()->status |= TS_COMPAT; | 432 | current_thread_info()->status |= TS_COMPAT; |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 57409f6b8c62..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> |
| @@ -136,6 +137,37 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, | |||
| 136 | return -1; | 137 | return -1; |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 140 | static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr, | ||
| 141 | siginfo_t *info) | ||
| 142 | { | ||
| 143 | unsigned long siaddr; | ||
| 144 | int sicode; | ||
| 145 | |||
| 146 | switch (trapnr) { | ||
| 147 | default: | ||
| 148 | return SEND_SIG_PRIV; | ||
| 149 | |||
| 150 | case X86_TRAP_DE: | ||
| 151 | sicode = FPE_INTDIV; | ||
| 152 | siaddr = uprobe_get_trap_addr(regs); | ||
| 153 | break; | ||
| 154 | case X86_TRAP_UD: | ||
| 155 | sicode = ILL_ILLOPN; | ||
| 156 | siaddr = uprobe_get_trap_addr(regs); | ||
| 157 | break; | ||
| 158 | case X86_TRAP_AC: | ||
| 159 | sicode = BUS_ADRALN; | ||
| 160 | siaddr = 0; | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | |||
| 164 | info->si_signo = signr; | ||
| 165 | info->si_errno = 0; | ||
| 166 | info->si_code = sicode; | ||
| 167 | info->si_addr = (void __user *)siaddr; | ||
| 168 | return info; | ||
| 169 | } | ||
| 170 | |||
| 139 | static void __kprobes | 171 | static void __kprobes |
| 140 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | 172 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, |
| 141 | long error_code, siginfo_t *info) | 173 | long error_code, siginfo_t *info) |
| @@ -168,60 +200,42 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | |||
| 168 | } | 200 | } |
| 169 | #endif | 201 | #endif |
| 170 | 202 | ||
| 171 | if (info) | 203 | force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk); |
| 172 | force_sig_info(signr, info, tsk); | ||
| 173 | else | ||
| 174 | force_sig(signr, tsk); | ||
| 175 | } | 204 | } |
| 176 | 205 | ||
| 177 | #define DO_ERROR(trapnr, signr, str, name) \ | 206 | static void do_error_trap(struct pt_regs *regs, long error_code, char *str, |
| 178 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 207 | unsigned long trapnr, int signr) |
| 179 | { \ | 208 | { |
| 180 | enum ctx_state prev_state; \ | 209 | enum ctx_state prev_state = exception_enter(); |
| 181 | \ | 210 | siginfo_t info; |
| 182 | prev_state = exception_enter(); \ | 211 | |
| 183 | if (notify_die(DIE_TRAP, str, regs, error_code, \ | 212 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) != |
| 184 | trapnr, signr) == NOTIFY_STOP) { \ | 213 | NOTIFY_STOP) { |
| 185 | exception_exit(prev_state); \ | 214 | conditional_sti(regs); |
| 186 | return; \ | 215 | do_trap(trapnr, signr, str, regs, error_code, |
| 187 | } \ | 216 | fill_trap_info(regs, signr, trapnr, &info)); |
| 188 | conditional_sti(regs); \ | 217 | } |
| 189 | do_trap(trapnr, signr, str, regs, error_code, NULL); \ | 218 | |
| 190 | exception_exit(prev_state); \ | 219 | exception_exit(prev_state); |
| 191 | } | 220 | } |
| 192 | 221 | ||
| 193 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | 222 | #define DO_ERROR(trapnr, signr, str, name) \ |
| 194 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 223 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ |
| 195 | { \ | 224 | { \ |
| 196 | siginfo_t info; \ | <||
