Skip to content

Commit

Permalink
powerpc: Use kprobe blacklist for exception handlers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nicholas Piggin authored and Michael Ellerman committed Sep 19, 2016
1 parent e1c0d66 commit 03465f8
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 15 deletions.
6 changes: 3 additions & 3 deletions arch/powerpc/include/asm/asm-prototypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ void SMIException(struct pt_regs *regs);
void handle_hmi_exception(struct pt_regs *regs);
void instruction_breakpoint_exception(struct pt_regs *regs);
void RunModeException(struct pt_regs *regs);
void __kprobes single_step_exception(struct pt_regs *regs);
void __kprobes program_check_exception(struct pt_regs *regs);
void single_step_exception(struct pt_regs *regs);
void program_check_exception(struct pt_regs *regs);
void alignment_exception(struct pt_regs *regs);
void StackOverflow(struct pt_regs *regs);
void nonrecoverable_exception(struct pt_regs *regs);
Expand All @@ -72,7 +72,7 @@ void unrecoverable_exception(struct pt_regs *regs);
void kernel_bad_stack(struct pt_regs *regs);
void system_reset_exception(struct pt_regs *regs);
void machine_check_exception(struct pt_regs *regs);
void __kprobes emulation_assist_interrupt(struct pt_regs *regs);
void emulation_assist_interrupt(struct pt_regs *regs);

/* signals, syscalls and interrupts */
#ifdef CONFIG_PPC64
Expand Down
9 changes: 6 additions & 3 deletions arch/powerpc/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
/*
* Handle debug exception notifications.
*/
int __kprobes hw_breakpoint_handler(struct die_args *args)
int hw_breakpoint_handler(struct die_args *args)
{
int rc = NOTIFY_STOP;
struct perf_event *bp;
Expand Down Expand Up @@ -290,11 +290,12 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
rcu_read_unlock();
return rc;
}
NOKPROBE_SYMBOL(hw_breakpoint_handler);

/*
* Handle single-step exceptions following a DABR hit.
*/
static int __kprobes single_step_dabr_instruction(struct die_args *args)
static int single_step_dabr_instruction(struct die_args *args)
{
struct pt_regs *regs = args->regs;
struct perf_event *bp = NULL;
Expand Down Expand Up @@ -329,11 +330,12 @@ static int __kprobes single_step_dabr_instruction(struct die_args *args)

return NOTIFY_STOP;
}
NOKPROBE_SYMBOL(single_step_dabr_instruction);

/*
* Handle debug exception notifications.
*/
int __kprobes hw_breakpoint_exceptions_notify(
int hw_breakpoint_exceptions_notify(
struct notifier_block *unused, unsigned long val, void *data)
{
int ret = NOTIFY_DONE;
Expand All @@ -349,6 +351,7 @@ int __kprobes hw_breakpoint_exceptions_notify(

return ret;
}
NOKPROBE_SYMBOL(hw_breakpoint_exceptions_notify);

/*
* Release the user breakpoints used by ptrace
Expand Down
21 changes: 14 additions & 7 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static int die_owner = -1;
static unsigned int die_nest_count;
static int die_counter;

static unsigned __kprobes long oops_begin(struct pt_regs *regs)
static unsigned long oops_begin(struct pt_regs *regs)
{
int cpu;
unsigned long flags;
Expand All @@ -144,8 +144,9 @@ static unsigned __kprobes long oops_begin(struct pt_regs *regs)
pmac_backlight_unblank();
return flags;
}
NOKPROBE_SYMBOL(oops_begin);

static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
static void oops_end(unsigned long flags, struct pt_regs *regs,
int signr)
{
bust_spinlocks(0);
Expand Down Expand Up @@ -196,8 +197,9 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
panic("Fatal exception");
do_exit(signr);
}
NOKPROBE_SYMBOL(oops_end);

static int __kprobes __die(const char *str, struct pt_regs *regs, long err)
static int __die(const char *str, struct pt_regs *regs, long err)
{
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
Expand All @@ -221,6 +223,7 @@ static int __kprobes __die(const char *str, struct pt_regs *regs, long err)

return 0;
}
NOKPROBE_SYMBOL(__die);

void die(const char *str, struct pt_regs *regs, long err)
{
Expand Down Expand Up @@ -802,7 +805,7 @@ void RunModeException(struct pt_regs *regs)
_exception(SIGTRAP, regs, 0, 0);
}

void __kprobes single_step_exception(struct pt_regs *regs)
void single_step_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

Expand All @@ -819,6 +822,7 @@ void __kprobes single_step_exception(struct pt_regs *regs)
bail:
exception_exit(prev_state);
}
NOKPROBE_SYMBOL(single_step_exception);

/*
* After we have successfully emulated an instruction, we have to
Expand Down Expand Up @@ -1140,7 +1144,7 @@ static int emulate_math(struct pt_regs *regs)
static inline int emulate_math(struct pt_regs *regs) { return -1; }
#endif

void __kprobes program_check_exception(struct pt_regs *regs)
void program_check_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
unsigned int reason = get_reason(regs);
Expand Down Expand Up @@ -1260,16 +1264,18 @@ void __kprobes program_check_exception(struct pt_regs *regs)
bail:
exception_exit(prev_state);
}
NOKPROBE_SYMBOL(program_check_exception);

/*
* This occurs when running in hypervisor mode on POWER6 or later
* and an illegal instruction is encountered.
*/
void __kprobes emulation_assist_interrupt(struct pt_regs *regs)
void emulation_assist_interrupt(struct pt_regs *regs)
{
regs->msr |= REASON_ILLEGAL;
program_check_exception(regs);
}
NOKPROBE_SYMBOL(emulation_assist_interrupt);

void alignment_exception(struct pt_regs *regs)
{
Expand Down Expand Up @@ -1668,7 +1674,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
mtspr(SPRN_DBCR0, current->thread.debug.dbcr0);
}

void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
void DebugException(struct pt_regs *regs, unsigned long debug_status)
{
current->thread.debug.dbsr = debug_status;

Expand Down Expand Up @@ -1729,6 +1735,7 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
} else
handle_debug(regs, debug_status);
}
NOKPROBE_SYMBOL(DebugException);
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */

#if !defined(CONFIG_TAU_INT)
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
* The return value is 0 if the fault was handled, or the signal
* number if this is a kernel fault that can't be handled here.
*/
int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
enum ctx_state prev_state = exception_enter();
Expand Down Expand Up @@ -498,8 +498,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
bail:
exception_exit(prev_state);
return rc;

}
NOKPROBE_SYMBOL(do_page_fault);

/*
* bad_page_fault is called when we have a bad access from the kernel.
Expand Down

0 comments on commit 03465f8

Please sign in to comment.