You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf update from Thomas Gleixner:
"The perf crowd presents:
Kernel updates:
- Removal of jprobes
- Cleanup and consolidatation the handling of kprobes
- Cleanup and consolidation of hardware breakpoints
- The usual pile of fixes and updates to PMUs and event descriptors
Tooling updates:
- Updates and improvements all over the place. Nothing outstanding,
just the (good) boring incremental grump work"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (103 commits)
perf trace: Do not require --no-syscalls to suppress strace like output
perf bpf: Include uapi/linux/bpf.h from the 'perf trace' script's bpf.h
perf tools: Allow overriding MAX_NR_CPUS at compile time
perf bpf: Show better message when failing to load an object
perf list: Unify metric group description format with PMU event description
perf vendor events arm64: Update ThunderX2 implementation defined pmu core events
perf cs-etm: Generate branch sample for CS_ETM_TRACE_ON packet
perf cs-etm: Generate branch sample when receiving a CS_ETM_TRACE_ON packet
perf cs-etm: Support dummy address value for CS_ETM_TRACE_ON packet
perf cs-etm: Fix start tracing packet handling
perf build: Fix installation directory for eBPF
perf c2c report: Fix crash for empty browser
perf tests: Fix indexing when invoking subtests
perf trace: Beautify the AF_INET & AF_INET6 'socket' syscall 'protocol' args
perf trace beauty: Add beautifiers for 'socket''s 'protocol' arg
perf trace beauty: Do not print NULL strarray entries
perf beauty: Add a generator for IPPROTO_ socket's protocol constants
tools include uapi: Grab a copy of linux/in.h
perf tests: Fix complex event name parsing
perf evlist: Fix error out while applying initial delay and LBR
...
This commit is contained in:
@@ -80,6 +80,26 @@ After the instruction is single-stepped, Kprobes executes the
|
||||
"post_handler," if any, that is associated with the kprobe.
|
||||
Execution then continues with the instruction following the probepoint.
|
||||
|
||||
Changing Execution Path
|
||||
-----------------------
|
||||
|
||||
Since kprobes can probe into a running kernel code, it can change the
|
||||
register set, including instruction pointer. This operation requires
|
||||
maximum care, such as keeping the stack frame, recovering the execution
|
||||
path etc. Since it operates on a running kernel and needs deep knowledge
|
||||
of computer architecture and concurrent computing, you can easily shoot
|
||||
your foot.
|
||||
|
||||
If you change the instruction pointer (and set up other related
|
||||
registers) in pre_handler, you must return !0 so that kprobes stops
|
||||
single stepping and just returns to the given address.
|
||||
This also means post_handler should not be called anymore.
|
||||
|
||||
Note that this operation may be harder on some architectures which use
|
||||
TOC (Table of Contents) for function call, since you have to setup a new
|
||||
TOC for your function in your module, and recover the old one after
|
||||
returning from it.
|
||||
|
||||
Return Probes
|
||||
-------------
|
||||
|
||||
@@ -262,7 +282,7 @@ is optimized, that modification is ignored. Thus, if you want to
|
||||
tweak the kernel's execution path, you need to suppress optimization,
|
||||
using one of the following techniques:
|
||||
|
||||
- Specify an empty function for the kprobe's post_handler or break_handler.
|
||||
- Specify an empty function for the kprobe's post_handler.
|
||||
|
||||
or
|
||||
|
||||
@@ -474,7 +494,7 @@ error occurs during registration, all probes in the array, up to
|
||||
the bad probe, are safely unregistered before the register_*probes
|
||||
function returns.
|
||||
|
||||
- kps/rps/jps: an array of pointers to ``*probe`` data structures
|
||||
- kps/rps: an array of pointers to ``*probe`` data structures
|
||||
- num: the number of the array entries.
|
||||
|
||||
.. note::
|
||||
@@ -566,12 +586,11 @@ the same handler) may run concurrently on different CPUs.
|
||||
Kprobes does not use mutexes or allocate memory except during
|
||||
registration and unregistration.
|
||||
|
||||
Probe handlers are run with preemption disabled. Depending on the
|
||||
architecture and optimization state, handlers may also run with
|
||||
interrupts disabled (e.g., kretprobe handlers and optimized kprobe
|
||||
handlers run without interrupt disabled on x86/x86-64). In any case,
|
||||
your handler should not yield the CPU (e.g., by attempting to acquire
|
||||
a semaphore).
|
||||
Probe handlers are run with preemption disabled or interrupt disabled,
|
||||
which depends on the architecture and optimization state. (e.g.,
|
||||
kretprobe handlers and optimized kprobe handlers run without interrupt
|
||||
disabled on x86/x86-64). In any case, your handler should not yield
|
||||
the CPU (e.g., by attempting to acquire a semaphore, or waiting I/O).
|
||||
|
||||
Since a return probe is implemented by replacing the return
|
||||
address with the trampoline's address, stack backtraces and calls
|
||||
|
||||
@@ -45,8 +45,6 @@ struct prev_kprobe {
|
||||
|
||||
struct kprobe_ctlblk {
|
||||
unsigned int kprobe_status;
|
||||
struct pt_regs jprobe_saved_regs;
|
||||
char jprobes_stack[MAX_STACK_SIZE];
|
||||
struct prev_kprobe prev_kprobe;
|
||||
};
|
||||
|
||||
|
||||
@@ -225,24 +225,18 @@ int __kprobes arc_kprobe_handler(unsigned long addr, struct pt_regs *regs)
|
||||
|
||||
/* If we have no pre-handler or it returned 0, we continue with
|
||||
* normal processing. If we have a pre-handler and it returned
|
||||
* non-zero - which is expected from setjmp_pre_handler for
|
||||
* jprobe, we return without single stepping and leave that to
|
||||
* the break-handler which is invoked by a kprobe from
|
||||
* jprobe_return
|
||||
* non-zero - which means user handler setup registers to exit
|
||||
* to another instruction, we must skip the single stepping.
|
||||
*/
|
||||
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||
setup_singlestep(p, regs);
|
||||
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||
} else {
|
||||
reset_current_kprobe();
|
||||
preempt_enable_no_resched();
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if (kprobe_running()) {
|
||||
p = __this_cpu_read(current_kprobe);
|
||||
if (p->break_handler && p->break_handler(p, regs)) {
|
||||
setup_singlestep(p, regs);
|
||||
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* no_kprobe: */
|
||||
@@ -386,38 +380,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
unsigned long sp_addr = regs->sp;
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
|
||||
regs->ret = (unsigned long)(jp->entry);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __kprobes jprobe_return(void)
|
||||
{
|
||||
__asm__ __volatile__("unimp_s");
|
||||
return;
|
||||
}
|
||||
|
||||
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
unsigned long sp_addr;
|
||||
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
sp_addr = regs->sp;
|
||||
memcpy((void *)sp_addr, kcb->jprobes_stack, MIN_STACK_SIZE(sp_addr));
|
||||
preempt_enable_no_resched();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __used kretprobe_trampoline_holder(void)
|
||||
{
|
||||
__asm__ __volatile__(".global kretprobe_trampoline\n"
|
||||
@@ -483,9 +445,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
|
||||
kretprobe_assert(ri, orig_ret_address, trampoline_address);
|
||||
regs->ret = orig_ret_address;
|
||||
|
||||
reset_current_kprobe();
|
||||
kretprobe_hash_unlock(current, &flags);
|
||||
preempt_enable_no_resched();
|
||||
|
||||
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
|
||||
hlist_del(&ri->hlist);
|
||||
|
||||
@@ -111,14 +111,17 @@ static inline void decode_ctrl_reg(u32 reg,
|
||||
asm volatile("mcr p14, 0, %0, " #N "," #M ", " #OP2 : : "r" (VAL));\
|
||||
} while (0)
|
||||
|
||||
struct perf_event_attr;
|
||||
struct notifier_block;
|
||||
struct perf_event;
|
||||
struct pmu;
|
||||
|
||||
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||
int *gen_len, int *gen_type);
|
||||
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
|
||||
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
|
||||
extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
|
||||
extern int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw);
|
||||
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
|
||||
unsigned long val, void *data);
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ struct prev_kprobe {
|
||||
struct kprobe_ctlblk {
|
||||
unsigned int kprobe_status;
|
||||
struct prev_kprobe prev_kprobe;
|
||||
struct pt_regs jprobe_saved_regs;
|
||||
char jprobes_stack[MAX_STACK_SIZE];
|
||||
};
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *);
|
||||
|
||||
@@ -51,7 +51,6 @@ struct arch_probes_insn {
|
||||
* We assume one instruction can consume at most 64 bytes stack, which is
|
||||
* 'push {r0-r15}'. Instructions consume more or unknown stack space like
|
||||
* 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe.
|
||||
* Both kprobe and jprobe use this macro.
|
||||
*/
|
||||
#define MAX_STACK_SIZE 64
|
||||
|
||||
|
||||
@@ -456,14 +456,13 @@ static int get_hbp_len(u8 hbp_len)
|
||||
/*
|
||||
* Check whether bp virtual address is in kernel space.
|
||||
*/
|
||||
int arch_check_bp_in_kernelspace(struct perf_event *bp)
|
||||
int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned long va;
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
|
||||
va = info->address;
|
||||
len = get_hbp_len(info->ctrl.len);
|
||||
va = hw->address;
|
||||
len = get_hbp_len(hw->ctrl.len);
|
||||
|
||||
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
|
||||
}
|
||||
@@ -518,42 +517,42 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||
/*
|
||||
* Construct an arch_hw_breakpoint from a perf_event.
|
||||
*/
|
||||
static int arch_build_bp_info(struct perf_event *bp)
|
||||
static int arch_build_bp_info(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
|
||||
/* Type */
|
||||
switch (bp->attr.bp_type) {
|
||||
switch (attr->bp_type) {
|
||||
case HW_BREAKPOINT_X:
|
||||
info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_EXECUTE;
|
||||
break;
|
||||
case HW_BREAKPOINT_R:
|
||||
info->ctrl.type = ARM_BREAKPOINT_LOAD;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_LOAD;
|
||||
break;
|
||||
case HW_BREAKPOINT_W:
|
||||
info->ctrl.type = ARM_BREAKPOINT_STORE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_STORE;
|
||||
break;
|
||||
case HW_BREAKPOINT_RW:
|
||||
info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Len */
|
||||
switch (bp->attr.bp_len) {
|
||||
switch (attr->bp_len) {
|
||||
case HW_BREAKPOINT_LEN_1:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_1;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_1;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_2:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_2;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_2;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_4:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_8:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_8;
|
||||
if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE)
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_8;
|
||||
if ((hw->ctrl.type != ARM_BREAKPOINT_EXECUTE)
|
||||
&& max_watchpoint_len >= 8)
|
||||
break;
|
||||
default:
|
||||
@@ -566,24 +565,24 @@ static int arch_build_bp_info(struct perf_event *bp)
|
||||
* by the hardware and must be aligned to the appropriate number of
|
||||
* bytes.
|
||||
*/
|
||||
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE &&
|
||||
info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
|
||||
info->ctrl.len != ARM_BREAKPOINT_LEN_4)
|
||||
if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE &&
|
||||
hw->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
|
||||
hw->ctrl.len != ARM_BREAKPOINT_LEN_4)
|
||||
return -EINVAL;
|
||||
|
||||
/* Address */
|
||||
info->address = bp->attr.bp_addr;
|
||||
hw->address = attr->bp_addr;
|
||||
|
||||
/* Privilege */
|
||||
info->ctrl.privilege = ARM_BREAKPOINT_USER;
|
||||
if (arch_check_bp_in_kernelspace(bp))
|
||||
info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
|
||||
hw->ctrl.privilege = ARM_BREAKPOINT_USER;
|
||||
if (arch_check_bp_in_kernelspace(hw))
|
||||
hw->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
|
||||
|
||||
/* Enabled? */
|
||||
info->ctrl.enabled = !bp->attr.disabled;
|
||||
hw->ctrl.enabled = !attr->disabled;
|
||||
|
||||
/* Mismatch */
|
||||
info->ctrl.mismatch = 0;
|
||||
hw->ctrl.mismatch = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -591,9 +590,10 @@ static int arch_build_bp_info(struct perf_event *bp)
|
||||
/*
|
||||
* Validate the arch-specific HW Breakpoint register settings.
|
||||
*/
|
||||
int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
int ret = 0;
|
||||
u32 offset, alignment_mask = 0x3;
|
||||
|
||||
@@ -602,14 +602,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
return -ENODEV;
|
||||
|
||||
/* Build the arch_hw_breakpoint. */
|
||||
ret = arch_build_bp_info(bp);
|
||||
ret = arch_build_bp_info(bp, attr, hw);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Check address alignment. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8)
|
||||
alignment_mask = 0x7;
|
||||
offset = info->address & alignment_mask;
|
||||
offset = hw->address & alignment_mask;
|
||||
switch (offset) {
|
||||
case 0:
|
||||
/* Aligned */
|
||||
@@ -617,19 +617,19 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
case 1:
|
||||
case 2:
|
||||
/* Allow halfword watchpoints and breakpoints. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
|
||||
break;
|
||||
case 3:
|
||||
/* Allow single byte watchpoint. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info->address &= ~alignment_mask;
|
||||
info->ctrl.len <<= offset;
|
||||
hw->address &= ~alignment_mask;
|
||||
hw->ctrl.len <<= offset;
|
||||
|
||||
if (is_default_overflow_handler(bp)) {
|
||||
/*
|
||||
@@ -640,7 +640,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
return -EINVAL;
|
||||
|
||||
/* We don't allow mismatch breakpoints in kernel space. */
|
||||
if (arch_check_bp_in_kernelspace(bp))
|
||||
if (arch_check_bp_in_kernelspace(hw))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
@@ -655,8 +655,8 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
* reports them.
|
||||
*/
|
||||
if (!debug_exception_updates_fsr() &&
|
||||
(info->ctrl.type == ARM_BREAKPOINT_LOAD ||
|
||||
info->ctrl.type == ARM_BREAKPOINT_STORE))
|
||||
(hw->ctrl.type == ARM_BREAKPOINT_LOAD ||
|
||||
hw->ctrl.type == ARM_BREAKPOINT_STORE))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,9 +47,6 @@
|
||||
(unsigned long)(addr) + \
|
||||
(size))
|
||||
|
||||
/* Used as a marker in ARM_pc to note when we're in a jprobe. */
|
||||
#define JPROBE_MAGIC_ADDR 0xffffffff
|
||||
|
||||
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
|
||||
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||
|
||||
@@ -289,8 +286,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
break;
|
||||
case KPROBE_REENTER:
|
||||
/* A nested probe was hit in FIQ, it is a BUG */
|
||||
pr_warn("Unrecoverable kprobe detected at %p.\n",
|
||||
p->addr);
|
||||
pr_warn("Unrecoverable kprobe detected.\n");
|
||||
dump_kprobe(p);
|
||||
/* fall through */
|
||||
default:
|
||||
/* impossible cases */
|
||||
@@ -303,10 +300,10 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
|
||||
/*
|
||||
* If we have no pre-handler or it returned 0, we
|
||||
* continue with normal processing. If we have a
|
||||
* pre-handler and it returned non-zero, it prepped
|
||||
* for calling the break_handler below on re-entry,
|
||||
* so get out doing nothing more here.
|
||||
* continue with normal processing. If we have a
|
||||
* pre-handler and it returned non-zero, it will
|
||||
* modify the execution path and no need to single
|
||||
* stepping. Let's just reset current kprobe and exit.
|
||||
*/
|
||||
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||
@@ -315,20 +312,9 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
p->post_handler(p, regs, 0);
|
||||
}
|
||||
reset_current_kprobe();
|
||||
}
|
||||
reset_current_kprobe();
|
||||
}
|
||||
} else if (cur) {
|
||||
/* We probably hit a jprobe. Call its break handler. */
|
||||
if (cur->break_handler && cur->break_handler(cur, regs)) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||
singlestep(cur, regs, kcb);
|
||||
if (cur->post_handler) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
cur->post_handler(cur, regs, 0);
|
||||
}
|
||||
}
|
||||
reset_current_kprobe();
|
||||
} else {
|
||||
/*
|
||||
* The probe was removed and a race is in progress.
|
||||
@@ -521,117 +507,6 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
|
||||
regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
|
||||
}
|
||||
|
||||
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
long sp_addr = regs->ARM_sp;
|
||||
long cpsr;
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
|
||||
regs->ARM_pc = (long)jp->entry;
|
||||
|
||||
cpsr = regs->ARM_cpsr | PSR_I_BIT;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/* Set correct Thumb state in cpsr */
|
||||
if (regs->ARM_pc & 1)
|
||||
cpsr |= PSR_T_BIT;
|
||||
else
|
||||
cpsr &= ~PSR_T_BIT;
|
||||
#endif
|
||||
regs->ARM_cpsr = cpsr;
|
||||
|
||||
preempt_disable();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __kprobes jprobe_return(void)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
__asm__ __volatile__ (
|
||||
/*
|
||||
* Setup an empty pt_regs. Fill SP and PC fields as
|
||||
* they're needed by longjmp_break_handler.
|
||||
*
|
||||
* We allocate some slack between the original SP and start of
|
||||
* our fabricated regs. To be precise we want to have worst case
|
||||
* covered which is STMFD with all 16 regs so we allocate 2 *
|
||||
* sizeof(struct_pt_regs)).
|
||||
*
|
||||
* This is to prevent any simulated instruction from writing
|
||||
* over the regs when they are accessing the stack.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"sub r0, %0, %1 \n\t"
|
||||
"mov sp, r0 \n\t"
|
||||
#else
|
||||
"sub sp, %0, %1 \n\t"
|
||||
#endif
|
||||
"ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
|
||||
"str %0, [sp, %2] \n\t"
|
||||
"str r0, [sp, %3] \n\t"
|
||||
"mov r0, sp \n\t"
|
||||
"bl kprobe_handler \n\t"
|
||||
|
||||
/*
|
||||
* Return to the context saved by setjmp_pre_handler
|
||||
* and restored by longjmp_break_handler.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"ldr lr, [sp, %2] \n\t" /* lr = saved sp */
|
||||
"ldrd r0, r1, [sp, %5] \n\t" /* r0,r1 = saved lr,pc */
|
||||
"ldr r2, [sp, %4] \n\t" /* r2 = saved psr */
|
||||
"stmdb lr!, {r0, r1, r2} \n\t" /* push saved lr and */
|
||||
/* rfe context */
|
||||
"ldmia sp, {r0 - r12} \n\t"
|
||||
"mov sp, lr \n\t"
|
||||
"ldr lr, [sp], #4 \n\t"
|
||||
"rfeia sp! \n\t"
|
||||
#else
|
||||
"ldr r0, [sp, %4] \n\t"
|
||||
"msr cpsr_cxsf, r0 \n\t"
|
||||
"ldmia sp, {r0 - pc} \n\t"
|
||||
#endif
|
||||
:
|
||||
: "r" (kcb->jprobe_saved_regs.ARM_sp),
|
||||
"I" (sizeof(struct pt_regs) * 2),
|
||||
"J" (offsetof(struct pt_regs, ARM_sp)),
|
||||
"J" (offsetof(struct pt_regs, ARM_pc)),
|
||||
"J" (offsetof(struct pt_regs, ARM_cpsr)),
|
||||
"J" (offsetof(struct pt_regs, ARM_lr))
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
long stack_addr = kcb->jprobe_saved_regs.ARM_sp;
|
||||
long orig_sp = regs->ARM_sp;
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
|
||||
if (regs->ARM_pc == JPROBE_MAGIC_ADDR) {
|
||||
if (orig_sp != stack_addr) {
|
||||
struct pt_regs *saved_regs =
|
||||
(struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp;
|
||||
printk("current sp %lx does not match saved sp %lx\n",
|
||||
orig_sp, stack_addr);
|
||||
printk("Saved registers for jprobe %p\n", jp);
|
||||
show_regs(saved_regs);
|
||||
printk("Current registers\n");
|
||||
show_regs(regs);
|
||||
BUG();
|
||||
}
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
memcpy((void *)stack_addr, kcb->jprobes_stack,
|
||||
MIN_STACK_SIZE(stack_addr));
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __kprobes arch_trampoline_kprobe(struct kprobe *p)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -1461,7 +1461,6 @@ fail:
|
||||
print_registers(&result_regs);
|
||||
|
||||
if (mem) {
|
||||
pr_err("current_stack=%p\n", current_stack);
|
||||
pr_err("expected_memory:\n");
|
||||
print_memory(expected_memory, mem_size);
|
||||
pr_err("result_memory:\n");
|
||||
|
||||
@@ -119,13 +119,16 @@ static inline void decode_ctrl_reg(u32 reg,
|
||||
|
||||
struct task_struct;
|
||||
struct notifier_block;
|
||||
struct perf_event_attr;
|
||||
struct perf_event;
|
||||
struct pmu;
|
||||
|
||||
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||
int *gen_len, int *gen_type, int *offset);
|
||||
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
|
||||
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
|
||||
extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
|
||||
extern int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw);
|
||||
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
|
||||
unsigned long val, void *data);
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ struct kprobe_ctlblk {
|
||||
unsigned long saved_irqflag;
|
||||
struct prev_kprobe prev_kprobe;
|
||||
struct kprobe_step_ctx ss_ctx;
|
||||
struct pt_regs jprobe_saved_regs;
|
||||
};
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *);
|
||||
|
||||
@@ -343,14 +343,13 @@ static int get_hbp_len(u8 hbp_len)
|
||||
/*
|
||||
* Check whether bp virtual address is in kernel space.
|
||||
*/
|
||||
int arch_check_bp_in_kernelspace(struct perf_event *bp)
|
||||
int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned long va;
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
|
||||
va = info->address;
|
||||
len = get_hbp_len(info->ctrl.len);
|
||||
va = hw->address;
|
||||
len = get_hbp_len(hw->ctrl.len);
|
||||
|
||||
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
|
||||
}
|
||||
@@ -421,53 +420,53 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||
/*
|
||||
* Construct an arch_hw_breakpoint from a perf_event.
|
||||
*/
|
||||
static int arch_build_bp_info(struct perf_event *bp)
|
||||
static int arch_build_bp_info(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
|
||||
/* Type */
|
||||
switch (bp->attr.bp_type) {
|
||||
switch (attr->bp_type) {
|
||||
case HW_BREAKPOINT_X:
|
||||
info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_EXECUTE;
|
||||
break;
|
||||
case HW_BREAKPOINT_R:
|
||||
info->ctrl.type = ARM_BREAKPOINT_LOAD;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_LOAD;
|
||||
break;
|
||||
case HW_BREAKPOINT_W:
|
||||
info->ctrl.type = ARM_BREAKPOINT_STORE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_STORE;
|
||||
break;
|
||||
case HW_BREAKPOINT_RW:
|
||||
info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
|
||||
hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Len */
|
||||
switch (bp->attr.bp_len) {
|
||||
switch (attr->bp_len) {
|
||||
case HW_BREAKPOINT_LEN_1:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_1;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_1;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_2:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_2;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_2;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_3:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_3;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_3;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_4:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_5:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_5;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_5;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_6:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_6;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_6;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_7:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_7;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_7;
|
||||
break;
|
||||
case HW_BREAKPOINT_LEN_8:
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_8;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_8;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -478,37 +477,37 @@ static int arch_build_bp_info(struct perf_event *bp)
|
||||
* AArch32 also requires breakpoints of length 2 for Thumb.
|
||||
* Watchpoints can be of length 1, 2, 4 or 8 bytes.
|
||||
*/
|
||||
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
|
||||
if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
|
||||
if (is_compat_bp(bp)) {
|
||||
if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
|
||||
info->ctrl.len != ARM_BREAKPOINT_LEN_4)
|
||||
if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
|
||||
hw->ctrl.len != ARM_BREAKPOINT_LEN_4)
|
||||
return -EINVAL;
|
||||
} else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) {
|
||||
} else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
|
||||
/*
|
||||
* FIXME: Some tools (I'm looking at you perf) assume
|
||||
* that breakpoints should be sizeof(long). This
|
||||
* is nonsense. For now, we fix up the parameter
|
||||
* but we should probably return -EINVAL instead.
|
||||
*/
|
||||
info->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Address */
|
||||
info->address = bp->attr.bp_addr;
|
||||
hw->address = attr->bp_addr;
|
||||
|
||||
/*
|
||||
* Privilege
|
||||
* Note that we disallow combined EL0/EL1 breakpoints because
|
||||
* that would complicate the stepping code.
|
||||
*/
|
||||
if (arch_check_bp_in_kernelspace(bp))
|
||||
info->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
|
||||
if (arch_check_bp_in_kernelspace(hw))
|
||||
hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
|
||||
else
|
||||
info->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
|
||||
hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
|
||||
|
||||
/* Enabled? */
|
||||
info->ctrl.enabled = !bp->attr.disabled;
|
||||
hw->ctrl.enabled = !attr->disabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -516,14 +515,15 @@ static int arch_build_bp_info(struct perf_event *bp)
|
||||
/*
|
||||
* Validate the arch-specific HW Breakpoint register settings.
|
||||
*/
|
||||
int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||
const struct perf_event_attr *attr,
|
||||
struct arch_hw_breakpoint *hw)
|
||||
{
|
||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||
int ret;
|
||||
u64 alignment_mask, offset;
|
||||
|
||||
/* Build the arch_hw_breakpoint. */
|
||||
ret = arch_build_bp_info(bp);
|
||||
ret = arch_build_bp_info(bp, attr, hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -537,42 +537,42 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
* that here.
|
||||
*/
|
||||
if (is_compat_bp(bp)) {
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8)
|
||||
alignment_mask = 0x7;
|
||||
else
|
||||
alignment_mask = 0x3;
|
||||
offset = info->address & alignment_mask;
|
||||
offset = hw->address & alignment_mask;
|
||||
switch (offset) {
|
||||
case 0:
|
||||
/* Aligned */
|
||||
break;
|
||||
case 1:
|
||||
/* Allow single byte watchpoint. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
break;
|
||||
case 2:
|
||||
/* Allow halfword watchpoints and breakpoints. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
|
||||
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
|
||||
if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE)
|
||||
alignment_mask = 0x3;
|
||||
else
|
||||
alignment_mask = 0x7;
|
||||
offset = info->address & alignment_mask;
|
||||
offset = hw->address & alignment_mask;
|
||||
}
|
||||
|
||||
info->address &= ~alignment_mask;
|
||||
info->ctrl.len <<= offset;
|
||||
hw->address &= ~alignment_mask;
|
||||
hw->ctrl.len <<= offset;
|
||||
|
||||
/*
|
||||
* Disallow per-task kernel breakpoints since these would
|
||||
* complicate the stepping code.
|
||||
*/
|
||||
if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target)
|
||||
if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -275,7 +275,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
|
||||
break;
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
|
||||
pr_warn("Unrecoverable kprobe detected.\n");
|
||||
dump_kprobe(p);
|
||||
BUG();
|
||||
break;
|
||||
@@ -395,9 +395,9 @@ static void __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
/*
|
||||
* If we have no pre-handler or it returned 0, we
|
||||
* continue with normal processing. If we have a
|
||||
* pre-handler and it returned non-zero, it prepped
|
||||
* for calling the break_handler below on re-entry,
|
||||
* so get out doing nothing more here.
|
||||
* pre-handler and it returned non-zero, it will
|
||||
* modify the execution path and no need to single
|
||||
* stepping. Let's just reset current kprobe and exit.
|
||||
*
|
||||
* pre_handler can hit a breakpoint and can step thru
|
||||
* before return, keep PSTATE D-flag enabled until
|
||||
@@ -405,16 +405,8 @@ static void __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
*/
|
||||
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||
setup_singlestep(p, regs, kcb, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ((le32_to_cpu(*(kprobe_opcode_t *) addr) ==
|
||||
BRK64_OPCODE_KPROBES) && cur_kprobe) {
|
||||
/* We probably hit a jprobe. Call its break handler. */
|
||||
if (cur_kprobe->break_handler &&
|
||||
cur_kprobe->break_handler(cur_kprobe, regs)) {
|
||||
setup_singlestep(cur_kprobe, regs, kcb, 0);
|
||||
return;
|
||||
} else
|
||||
reset_current_kprobe();
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -465,74 +457,6 @@ kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr)
|
||||
return DBG_HOOK_HANDLED;
|
||||
}
|
||||
|
||||
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
/*
|
||||
* Since we can't be sure where in the stack frame "stacked"
|
||||
* pass-by-value arguments are stored we just don't try to
|
||||
* duplicate any of the stack. Do not use jprobes on functions that
|
||||
* use more than 64 bytes (after padding each to an 8 byte boundary)
|
||||
* of arguments, or pass individual arguments larger than 16 bytes.
|
||||
*/
|
||||
|
||||
instruction_pointer_set(regs, (unsigned long) jp->entry);
|
||||
preempt_disable();
|
||||
pause_graph_tracing();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __kprobes jprobe_return(void)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
/*
|
||||
* Jprobe handler return by entering break exception,
|
||||
* encoded same as kprobe, but with following conditions
|
||||
* -a special PC to identify it from the other kprobes.
|
||||
* -restore stack addr to original saved pt_regs
|
||||
*/
|
||||
asm volatile(" mov sp, %0 \n"
|
||||
"jprobe_return_break: brk %1 \n"
|
||||
:
|
||||
: "r" (kcb->jprobe_saved_regs.sp),
|
||||
"I" (BRK64_ESR_KPROBES)
|
||||
: "memory");
|
||||
|
||||
unreachable();
|
||||
}
|
||||
|
||||
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
long stack_addr = kcb->jprobe_saved_regs.sp;
|
||||
long orig_sp = kernel_stack_pointer(regs);
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
extern const char jprobe_return_break[];
|
||||
|
||||
if (instruction_pointer(regs) != (u64) jprobe_return_break)
|
||||
return 0;
|
||||
|
||||
if (orig_sp != stack_addr) {
|
||||
struct pt_regs *saved_regs =
|
||||
(struct pt_regs *)kcb->jprobe_saved_regs.sp;
|
||||
pr_err("current sp %lx does not match saved sp %lx\n",
|
||||
orig_sp, stack_addr);
|
||||
pr_err("Saved registers for jprobe %p\n", jp);
|
||||
__show_regs(saved_regs);
|
||||
pr_err("Current registers\n");
|
||||
__show_regs(regs);
|
||||
BUG();
|
||||
}
|
||||
unpause_graph_tracing();
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool arch_within_kprobe_blacklist(unsigned long addr)
|
||||
{
|
||||
if ((addr >= (unsigned long)__kprobes_text_start &&
|
||||
|
||||
@@ -82,8 +82,6 @@ struct prev_kprobe {
|
||||
#define ARCH_PREV_KPROBE_SZ 2
|
||||
struct kprobe_ctlblk {
|
||||
unsigned long kprobe_status;
|
||||
struct pt_regs jprobe_saved_regs;
|
||||
unsigned long jprobes_saved_stacked_regs[MAX_PARAM_RSE_SIZE];
|
||||
unsigned long *bsp;
|
||||
unsigned long cfm;
|
||||
atomic_t prev_kprobe_index;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
#define __IA64_BREAK_KDB 0x80100
|
||||
#define __IA64_BREAK_KPROBE 0x81000 /* .. 0x81fff */
|
||||
#define __IA64_BREAK_JPROBE 0x82000
|
||||
|
||||
/*
|
||||
* OS-specific break numbers:
|
||||
|
||||
@@ -25,7 +25,7 @@ obj-$(CONFIG_NUMA) += numa.o
|
||||
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
|
||||
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
|
||||
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Jprobe specific operations
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) Intel Corporation, 2005
|
||||
*
|
||||
* 2005-May Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy
|
||||
* <anil.s.keshavamurthy@intel.com> initial implementation
|
||||
*
|
||||
* Jprobes (a.k.a. "jump probes" which is built on-top of kprobes) allow a
|
||||
* probe to be inserted into the beginning of a function call. The fundamental
|
||||
* difference between a jprobe and a kprobe is the jprobe handler is executed
|
||||
* in the same context as the target function, while the kprobe handlers
|
||||
* are executed in interrupt context.
|
||||
*
|
||||
* For jprobes we initially gain control by placing a break point in the
|
||||
* first instruction of the targeted function. When we catch that specific
|
||||
* break, we:
|
||||
* * set the return address to our jprobe_inst_return() function
|
||||
* * jump to the jprobe handler function
|
||||
*
|
||||
* Since we fixed up the return address, the jprobe handler will return to our
|
||||
* jprobe_inst_return() function, giving us control again. At this point we
|
||||
* are back in the parents frame marker, so we do yet another call to our
|
||||
* jprobe_break() function to fix up the frame marker as it would normally
|
||||
* exist in the target function.
|
||||
*
|
||||
* Our jprobe_return function then transfers control back to kprobes.c by
|
||||
* executing a break instruction using one of our reserved numbers. When we
|
||||
* catch that break in kprobes.c, we continue like we do for a normal kprobe
|
||||
* by single stepping the emulated instruction, and then returning execution
|
||||
* to the correct location.
|
||||
*/
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/break.h>
|
||||
|
||||
/*
|
||||
* void jprobe_break(void)
|
||||
*/
|
||||
.section .kprobes.text, "ax"
|
||||
ENTRY(jprobe_break)
|
||||
break.m __IA64_BREAK_JPROBE
|
||||
END(jprobe_break)
|
||||
|
||||
/*
|
||||
* void jprobe_inst_return(void)
|
||||
*/
|
||||
GLOBAL_ENTRY(jprobe_inst_return)
|
||||
br.call.sptk.many b0=jprobe_break
|
||||
END(jprobe_inst_return)
|
||||
|
||||
GLOBAL_ENTRY(invalidate_stacked_regs)
|
||||
movl r16=invalidate_restore_cfm
|
||||
;;
|
||||
mov b6=r16
|
||||
;;
|
||||
br.ret.sptk.many b6
|
||||
;;
|
||||
invalidate_restore_cfm:
|
||||
mov r16=ar.rsc
|
||||
;;
|
||||
mov ar.rsc=r0
|
||||
;;
|
||||
loadrs
|
||||
;;
|
||||
mov ar.rsc=r16
|
||||
;;
|
||||
br.cond.sptk.many rp
|
||||
END(invalidate_stacked_regs)
|
||||
|
||||
GLOBAL_ENTRY(flush_register_stack)
|
||||
// flush dirty regs to backing store (must be first in insn group)
|
||||
flushrs
|
||||
;;
|
||||
br.ret.sptk.many rp
|
||||
END(flush_register_stack)
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
#include <asm/sections.h>
|
||||
#include <asm/exception.h>
|
||||
|
||||
extern void jprobe_inst_return(void);
|
||||
|
||||
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
|
||||
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||
|
||||
@@ -480,12 +478,9 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
kretprobe_assert(ri, orig_ret_address, trampoline_address);
|
||||
|
||||
reset_current_kprobe();
|
||||
kretprobe_hash_unlock(current, &flags);
|
||||
preempt_enable_no_resched();
|
||||
|
||||
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
|
||||
hlist_del(&ri->hlist);
|
||||
@@ -819,14 +814,6 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
|
||||
prepare_ss(p, regs);
|
||||
kcb->kprobe_status = KPROBE_REENTER;
|
||||
return 1;
|
||||
} else if (args->err == __IA64_BREAK_JPROBE) {
|
||||
/*
|
||||
* jprobe instrumented function just completed
|
||||
*/
|
||||
p = __this_cpu_read(current_kprobe);
|
||||
if (p->break_handler && p->break_handler(p, regs)) {
|
||||
goto ss_probe;
|
||||
}
|
||||
} else if (!is_ia64_break_inst(regs)) {
|
||||
/* The breakpoint instruction was removed by
|
||||
* another cpu right after we hit, no further
|
||||
@@ -861,15 +848,12 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
|
||||
set_current_kprobe(p, kcb);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
|
||||
if (p->pre_handler && p->pre_handler(p, regs))
|
||||
/*
|
||||
* Our pre-handler is specifically requesting that we just
|
||||
* do a return. This is used for both the jprobe pre-handler
|
||||
* and the kretprobe trampoline
|
||||
*/
|
||||
if (p->pre_handler && p->pre_handler(p, regs)) {
|
||||
reset_current_kprobe();
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ss_probe:
|
||||
#if !defined(CONFIG_PREEMPT)
|
||||
if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) {
|
||||
/* Boost up -- we can execute copied instructions directly */
|
||||
@@ -992,7 +976,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
||||
case DIE_BREAK:
|
||||
/* err is break number from ia64_bad_break() */
|
||||
if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12)
|
||||
|| args->err == __IA64_BREAK_JPROBE
|
||||
|| args->err == 0)
|
||||
if (pre_kprobes_handler(args))
|
||||
ret = NOTIFY_STOP;
|
||||
@@ -1040,74 +1023,6 @@ unsigned long arch_deref_entry_point(void *entry)
|
||||
return ((struct fnptr *)entry)->ip;
|
||||
}
|
||||
|
||||
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
unsigned long addr = arch_deref_entry_point(jp->entry);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
struct param_bsp_cfm pa;
|
||||
int bytes;
|
||||
|
||||
/*
|
||||
* Callee owns the argument space and could overwrite it, eg
|
||||
* tail call optimization. So to be absolutely safe
|
||||
* we save the argument space before transferring the control
|
||||
* to instrumented jprobe function which runs in
|
||||
* the process context
|
||||
*/
|
||||
pa.ip = regs->cr_iip;
|
||||
unw_init_running(ia64_get_bsp_cfm, &pa);
|
||||
bytes = (char *)ia64_rse_skip_regs(pa.bsp, pa.cfm & 0x3f)
|
||||
- (char *)pa.bsp;
|
||||
memcpy( kcb->jprobes_saved_stacked_regs,
|
||||
pa.bsp,
|
||||
bytes );
|
||||
kcb->bsp = pa.bsp;
|
||||
kcb->cfm = pa.cfm;
|
||||
|
||||
/* save architectural state */
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
|
||||
/* after rfi, execute the jprobe instrumented function */
|
||||
regs->cr_iip = addr & ~0xFULL;
|
||||
ia64_psr(regs)->ri = addr & 0xf;
|
||||
regs->r1 = ((struct fnptr *)(jp->entry))->gp;
|
||||
|
||||
/*
|
||||
* fix the return address to our jprobe_inst_return() function
|
||||
* in the jprobes.S file
|
||||
*/
|
||||
regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ia64 does not need this */
|
||||
void __kprobes jprobe_return(void)
|
||||
{
|
||||
}
|
||||
|
||||
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
int bytes;
|
||||
|
||||
/* restoring architectural state */
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
|
||||
/* restoring the original argument space */
|
||||
flush_register_stack();
|
||||
bytes = (char *)ia64_rse_skip_regs(kcb->bsp, kcb->cfm & 0x3f)
|
||||
- (char *)kcb->bsp;
|
||||
memcpy( kcb->bsp,
|
||||
kcb->jprobes_saved_stacked_regs,
|
||||
bytes );
|
||||
invalidate_stacked_regs();
|
||||
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct kprobe trampoline_p = {
|
||||
.pre_handler = trampoline_probe_handler
|
||||
};
|
||||
|
||||
@@ -68,16 +68,6 @@ struct prev_kprobe {
|
||||
unsigned long saved_epc;
|
||||
};
|
||||
|
||||
#define MAX_JPROBES_STACK_SIZE 128
|
||||
#define MAX_JPROBES_STACK_ADDR \
|
||||
(((unsigned long)current_thread_info()) + THREAD_SIZE - 32 - sizeof(struct pt_regs))
|
||||
|
||||
#define MIN_JPROBES_STACK_SIZE(ADDR) \
|
||||
((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \
|
||||
? MAX_JPROBES_STACK_ADDR - (ADDR) \
|
||||
: MAX_JPROBES_STACK_SIZE)
|
||||
|
||||
|
||||
#define SKIP_DELAYSLOT 0x0001
|
||||
|
||||
/* per-cpu kprobe control block */
|
||||
@@ -86,12 +76,9 @@ struct kprobe_ctlblk {
|
||||
unsigned long kprobe_old_SR;
|
||||
unsigned long kprobe_saved_SR;
|
||||
unsigned long kprobe_saved_epc;
|
||||
unsigned long jprobe_saved_sp;
|
||||
struct pt_regs jprobe_saved_regs;
|
||||
/* Per-thread fields, used while emulating branches */
|
||||
unsigned long flags;
|
||||
unsigned long target_epc;
|
||||
u8 jprobes_stack[MAX_JPROBES_STACK_SIZE];
|
||||
struct prev_kprobe prev_kprobe;
|
||||
};
|
||||
|
||||
|
||||
@@ -326,19 +326,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
preempt_enable_no_resched();
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
if (addr->word != breakpoint_insn.word) {
|
||||
/*
|
||||
* The breakpoint instruction was removed by
|
||||
* another cpu right after we hit, no further
|
||||
* handling of this interrupt is appropriate
|
||||
*/
|
||||
ret = 1;
|
||||
goto no_kprobe;
|
||||
}
|
||||
p = __this_cpu_read(current_kprobe);
|
||||
if (p->break_handler && p->break_handler(p, regs))
|
||||
goto ss_probe;
|
||||
} else if (addr->word != breakpoint_insn.word) {
|
||||
/*
|
||||
* The breakpoint instruction was removed by
|
||||
* another cpu right after we hit, no further
|
||||
* handling of this interrupt is appropriate
|
||||
*/
|
||||
ret = 1;
|
||||
}
|
||||
goto no_kprobe;
|
||||
}
|
||||
@@ -364,10 +358,11 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
|
||||
|
||||
if (p->pre_handler && p->pre_handler(p, regs)) {
|
||||
/* handler has already set things up, so skip ss setup */
|
||||
reset_current_kprobe();
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ss_probe:
|
||||
prepare_singlestep(p, regs, kcb);
|
||||
if (kcb->flags & SKIP_DELAYSLOT) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
@@ -468,51 +463,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
kcb->jprobe_saved_sp = regs->regs[29];
|
||||
|
||||
memcpy(kcb->jprobes_stack, (void *)kcb->jprobe_saved_sp,
|
||||
MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp));
|
||||
|
||||
regs->cp0_epc = (unsigned long)(jp->entry);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Defined in the inline asm below. */
|
||||
void jprobe_return_end(void);
|
||||
|
||||
void __kprobes jprobe_return(void)
|
||||
{
|
||||
/* Assembler quirk necessitates this '0,code' business. */
|
||||
asm volatile(
|
||||
"break 0,%0\n\t"
|
||||
".globl jprobe_return_end\n"
|
||||
"jprobe_return_end:\n"
|
||||
: : "n" (BRK_KPROBE_BP) : "memory");
|
||||
}
|
||||
|
||||
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
if (regs->cp0_epc >= (unsigned long)jprobe_return &&
|
||||
regs->cp0_epc <= (unsigned long)jprobe_return_end) {
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
memcpy((void *)kcb->jprobe_saved_sp, kcb->jprobes_stack,
|
||||
MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp));
|
||||
preempt_enable_no_resched();
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function return probe trampoline:
|
||||
* - init_kprobes() establishes a probepoint here
|
||||
@@ -595,9 +545,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
|
||||
kretprobe_assert(ri, orig_ret_address, trampoline_address);
|
||||
instruction_pointer(regs) = orig_ret_address;
|
||||
|
||||
reset_current_kprobe();
|
||||
kretprobe_hash_unlock(current, &flags);
|
||||
preempt_enable_no_resched();
|
||||
|
||||
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
|
||||
hlist_del(&ri->hlist);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user