Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Use kprobe blacklist for exception handlers

Currently we mark the C implementations of some exception handlers as
__kprobes. This has the effect of putting them in the ".kprobes.text"
section, which separates them from the rest of the text.

Instead we can use the blacklist macros to add the symbols to a
blacklist which kprobes will check. This allows the linker to move
exception handler functions close to callers and avoids trampolines in
larger kernels.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Reword change log a bit]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Nicholas Piggin and committed by
Michael Ellerman
03465f89 e1c0d66f

+25 -15
+3 -3
arch/powerpc/include/asm/asm-prototypes.h
··· 54 54 void handle_hmi_exception(struct pt_regs *regs); 55 55 void instruction_breakpoint_exception(struct pt_regs *regs); 56 56 void RunModeException(struct pt_regs *regs); 57 - void __kprobes single_step_exception(struct pt_regs *regs); 58 - void __kprobes program_check_exception(struct pt_regs *regs); 57 + void single_step_exception(struct pt_regs *regs); 58 + void program_check_exception(struct pt_regs *regs); 59 59 void alignment_exception(struct pt_regs *regs); 60 60 void StackOverflow(struct pt_regs *regs); 61 61 void nonrecoverable_exception(struct pt_regs *regs); ··· 72 72 void kernel_bad_stack(struct pt_regs *regs); 73 73 void system_reset_exception(struct pt_regs *regs); 74 74 void machine_check_exception(struct pt_regs *regs); 75 - void __kprobes emulation_assist_interrupt(struct pt_regs *regs); 75 + void emulation_assist_interrupt(struct pt_regs *regs); 76 76 77 77 /* signals, syscalls and interrupts */ 78 78 #ifdef CONFIG_PPC64
+6 -3
arch/powerpc/kernel/hw_breakpoint.c
··· 206 206 /* 207 207 * Handle debug exception notifications. 208 208 */ 209 - int __kprobes hw_breakpoint_handler(struct die_args *args) 209 + int hw_breakpoint_handler(struct die_args *args) 210 210 { 211 211 int rc = NOTIFY_STOP; 212 212 struct perf_event *bp; ··· 290 290 rcu_read_unlock(); 291 291 return rc; 292 292 } 293 + NOKPROBE_SYMBOL(hw_breakpoint_handler); 293 294 294 295 /* 295 296 * Handle single-step exceptions following a DABR hit. 296 297 */ 297 - static int __kprobes single_step_dabr_instruction(struct die_args *args) 298 + static int single_step_dabr_instruction(struct die_args *args) 298 299 { 299 300 struct pt_regs *regs = args->regs; 300 301 struct perf_event *bp = NULL; ··· 330 329 331 330 return NOTIFY_STOP; 332 331 } 332 + NOKPROBE_SYMBOL(single_step_dabr_instruction); 333 333 334 334 /* 335 335 * Handle debug exception notifications. 336 336 */ 337 - int __kprobes hw_breakpoint_exceptions_notify( 337 + int hw_breakpoint_exceptions_notify( 338 338 struct notifier_block *unused, unsigned long val, void *data) 339 339 { 340 340 int ret = NOTIFY_DONE; ··· 351 349 352 350 return ret; 353 351 } 352 + NOKPROBE_SYMBOL(hw_breakpoint_exceptions_notify); 354 353 355 354 /* 356 355 * Release the user breakpoints used by ptrace
+14 -7
arch/powerpc/kernel/traps.c
··· 117 117 static unsigned int die_nest_count; 118 118 static int die_counter; 119 119 120 - static unsigned __kprobes long oops_begin(struct pt_regs *regs) 120 + static unsigned long oops_begin(struct pt_regs *regs) 121 121 { 122 122 int cpu; 123 123 unsigned long flags; ··· 144 144 pmac_backlight_unblank(); 145 145 return flags; 146 146 } 147 + NOKPROBE_SYMBOL(oops_begin); 147 148 148 - static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, 149 + static void oops_end(unsigned long flags, struct pt_regs *regs, 149 150 int signr) 150 151 { 151 152 bust_spinlocks(0); ··· 197 196 panic("Fatal exception"); 198 197 do_exit(signr); 199 198 } 199 + NOKPROBE_SYMBOL(oops_end); 200 200 201 - static int __kprobes __die(const char *str, struct pt_regs *regs, long err) 201 + static int __die(const char *str, struct pt_regs *regs, long err) 202 202 { 203 203 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); 204 204 #ifdef CONFIG_PREEMPT ··· 223 221 224 222 return 0; 225 223 } 224 + NOKPROBE_SYMBOL(__die); 226 225 227 226 void die(const char *str, struct pt_regs *regs, long err) 228 227 { ··· 805 802 _exception(SIGTRAP, regs, 0, 0); 806 803 } 807 804 808 - void __kprobes single_step_exception(struct pt_regs *regs) 805 + void single_step_exception(struct pt_regs *regs) 809 806 { 810 807 enum ctx_state prev_state = exception_enter(); 811 808 ··· 822 819 bail: 823 820 exception_exit(prev_state); 824 821 } 822 + NOKPROBE_SYMBOL(single_step_exception); 825 823 826 824 /* 827 825 * After we have successfully emulated an instruction, we have to ··· 1144 1140 static inline int emulate_math(struct pt_regs *regs) { return -1; } 1145 1141 #endif 1146 1142 1147 - void __kprobes program_check_exception(struct pt_regs *regs) 1143 + void program_check_exception(struct pt_regs *regs) 1148 1144 { 1149 1145 enum ctx_state prev_state = exception_enter(); 1150 1146 unsigned int reason = get_reason(regs); ··· 1264 1260 bail: 1265 1261 exception_exit(prev_state); 1266 1262 } 1263 + NOKPROBE_SYMBOL(program_check_exception); 1267 1264 1268 1265 /* 1269 1266 * This occurs when running in hypervisor mode on POWER6 or later 1270 1267 * and an illegal instruction is encountered. 1271 1268 */ 1272 - void __kprobes emulation_assist_interrupt(struct pt_regs *regs) 1269 + void emulation_assist_interrupt(struct pt_regs *regs) 1273 1270 { 1274 1271 regs->msr |= REASON_ILLEGAL; 1275 1272 program_check_exception(regs); 1276 1273 } 1274 + NOKPROBE_SYMBOL(emulation_assist_interrupt); 1277 1275 1278 1276 void alignment_exception(struct pt_regs *regs) 1279 1277 { ··· 1674 1668 mtspr(SPRN_DBCR0, current->thread.debug.dbcr0); 1675 1669 } 1676 1670 1677 - void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) 1671 + void DebugException(struct pt_regs *regs, unsigned long debug_status) 1678 1672 { 1679 1673 current->thread.debug.dbsr = debug_status; 1680 1674 ··· 1735 1729 } else 1736 1730 handle_debug(regs, debug_status); 1737 1731 } 1732 + NOKPROBE_SYMBOL(DebugException); 1738 1733 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ 1739 1734 1740 1735 #if !defined(CONFIG_TAU_INT)
+2 -2
arch/powerpc/mm/fault.c
··· 205 205 * The return value is 0 if the fault was handled, or the signal 206 206 * number if this is a kernel fault that can't be handled here. 207 207 */ 208 - int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, 208 + int do_page_fault(struct pt_regs *regs, unsigned long address, 209 209 unsigned long error_code) 210 210 { 211 211 enum ctx_state prev_state = exception_enter(); ··· 498 498 bail: 499 499 exception_exit(prev_state); 500 500 return rc; 501 - 502 501 } 502 + NOKPROBE_SYMBOL(do_page_fault); 503 503 504 504 /* 505 505 * bad_page_fault is called when we have a bad access from the kernel.