Skip to content

Commit

Permalink
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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
  ...
  • Loading branch information
torvalds committed Aug 13, 2018
2 parents de5d1b3 + ec2cb7a commit 8603596
Show file tree
Hide file tree
Showing 133 changed files with 2,606 additions and 1,867 deletions.
35 changes: 27 additions & 8 deletions Documentation/kprobes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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::
Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions arch/arc/include/asm/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
50 changes: 5 additions & 45 deletions arch/arc/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: */
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions arch/arm/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions arch/arm/include/asm/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
1 change: 0 additions & 1 deletion arch/arm/include/asm/probes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
78 changes: 39 additions & 39 deletions arch/arm/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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:
Expand All @@ -566,34 +565,35 @@ 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;
}

/*
* 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;

Expand All @@ -602,34 +602,34 @@ 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 */
break;
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)) {
/*
Expand All @@ -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;

/*
Expand All @@ -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;
}

Expand Down
Loading

0 comments on commit 8603596

Please sign in to comment.