Commit c3931a87 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Thomas Gleixner:
 "A couple of fixes for perf and kprobes:

   - Add he missing exclude_kernel attribute for the precise_ip level so
     !CAP_SYS_ADMIN users get the proper results.

   - Warn instead of failing completely when perf has no unwind support
     for a particular architectiure built in.

   - Ensure that jprobes are at function entry and not at some random
     place"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  kprobes: Ensure that jprobe probepoints are at function entry
  kprobes: Simplify register_jprobes()
  kprobes: Rename [arch_]function_offset_within_entry() to [arch_]kprobe_on_func_entry()
  perf unwind: Do not fail due to missing unwind support
  perf evsel: Set attr.exclude_kernel when probing max attr.precise_ip
parents c8b2ba83 dbf58062
...@@ -217,7 +217,7 @@ static nokprobe_inline void set_current_kprobe(struct kprobe *p, struct pt_regs ...@@ -217,7 +217,7 @@ static nokprobe_inline void set_current_kprobe(struct kprobe *p, struct pt_regs
kcb->kprobe_saved_msr = regs->msr; kcb->kprobe_saved_msr = regs->msr;
} }
bool arch_function_offset_within_entry(unsigned long offset) bool arch_kprobe_on_func_entry(unsigned long offset)
{ {
#ifdef PPC64_ELF_ABI_v2 #ifdef PPC64_ELF_ABI_v2
#ifdef CONFIG_KPROBES_ON_FTRACE #ifdef CONFIG_KPROBES_ON_FTRACE
......
...@@ -267,8 +267,8 @@ extern int arch_init_kprobes(void); ...@@ -267,8 +267,8 @@ extern int arch_init_kprobes(void);
extern void show_registers(struct pt_regs *regs); extern void show_registers(struct pt_regs *regs);
extern void kprobes_inc_nmissed_count(struct kprobe *p); extern void kprobes_inc_nmissed_count(struct kprobe *p);
extern bool arch_within_kprobe_blacklist(unsigned long addr); extern bool arch_within_kprobe_blacklist(unsigned long addr);
extern bool arch_function_offset_within_entry(unsigned long offset); extern bool arch_kprobe_on_func_entry(unsigned long offset);
extern bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
extern bool within_kprobe_blacklist(unsigned long addr); extern bool within_kprobe_blacklist(unsigned long addr);
......
...@@ -1771,24 +1771,13 @@ unsigned long __weak arch_deref_entry_point(void *entry) ...@@ -1771,24 +1771,13 @@ unsigned long __weak arch_deref_entry_point(void *entry)
int register_jprobes(struct jprobe **jps, int num) int register_jprobes(struct jprobe **jps, int num)
{ {
struct jprobe *jp;
int ret = 0, i; int ret = 0, i;
if (num <= 0) if (num <= 0)
return -EINVAL; return -EINVAL;
for (i = 0; i < num; i++) {
unsigned long addr, offset;
jp = jps[i];
addr = arch_deref_entry_point(jp->entry);
/* Verify probepoint is a function entry point */ for (i = 0; i < num; i++) {
if (kallsyms_lookup_size_offset(addr, NULL, &offset) && ret = register_jprobe(jps[i]);
offset == 0) {
jp->kp.pre_handler = setjmp_pre_handler;
jp->kp.break_handler = longjmp_break_handler;
ret = register_kprobe(&jp->kp);
} else
ret = -EINVAL;
if (ret < 0) { if (ret < 0) {
if (i > 0) if (i > 0)
...@@ -1796,13 +1785,30 @@ int register_jprobes(struct jprobe **jps, int num) ...@@ -1796,13 +1785,30 @@ int register_jprobes(struct jprobe **jps, int num)
break; break;
} }
} }
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(register_jprobes); EXPORT_SYMBOL_GPL(register_jprobes);
int register_jprobe(struct jprobe *jp) int register_jprobe(struct jprobe *jp)
{ {
return register_jprobes(&jp, 1); unsigned long addr, offset;
struct kprobe *kp = &jp->kp;
/*
* Verify probepoint as well as the jprobe handler are
* valid function entry points.
*/
addr = arch_deref_entry_point(jp->entry);
if (kallsyms_lookup_size_offset(addr, NULL, &offset) && offset == 0 &&
kprobe_on_func_entry(kp->addr, kp->symbol_name, kp->offset)) {
kp->pre_handler = setjmp_pre_handler;
kp->break_handler = longjmp_break_handler;
return register_kprobe(kp);
}
return -EINVAL;
} }
EXPORT_SYMBOL_GPL(register_jprobe); EXPORT_SYMBOL_GPL(register_jprobe);
...@@ -1888,12 +1894,12 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) ...@@ -1888,12 +1894,12 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
} }
NOKPROBE_SYMBOL(pre_handler_kretprobe); NOKPROBE_SYMBOL(pre_handler_kretprobe);
bool __weak arch_function_offset_within_entry(unsigned long offset) bool __weak arch_kprobe_on_func_entry(unsigned long offset)
{ {
return !offset; return !offset;
} }
bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset) bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
{ {
kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset); kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset);
...@@ -1901,7 +1907,7 @@ bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsign ...@@ -1901,7 +1907,7 @@ bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsign
return false; return false;
if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) || if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) ||
!arch_function_offset_within_entry(offset)) !arch_kprobe_on_func_entry(offset))
return false; return false;
return true; return true;
...@@ -1914,7 +1920,7 @@ int register_kretprobe(struct kretprobe *rp) ...@@ -1914,7 +1920,7 @@ int register_kretprobe(struct kretprobe *rp)
int i; int i;
void *addr; void *addr;
if (!function_offset_within_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset)) if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset))
return -EINVAL; return -EINVAL;
if (kretprobe_blacklist_size) { if (kretprobe_blacklist_size) {
......
...@@ -720,7 +720,7 @@ static int create_trace_kprobe(int argc, char **argv) ...@@ -720,7 +720,7 @@ static int create_trace_kprobe(int argc, char **argv)
return ret; return ret;
} }
if (offset && is_return && if (offset && is_return &&
!function_offset_within_entry(NULL, symbol, offset)) { !kprobe_on_func_entry(NULL, symbol, offset)) {
pr_info("Given offset is not valid for return probe.\n"); pr_info("Given offset is not valid for return probe.\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -273,6 +273,7 @@ struct perf_evsel *perf_evsel__new_cycles(void) ...@@ -273,6 +273,7 @@ struct perf_evsel *perf_evsel__new_cycles(void)
struct perf_event_attr attr = { struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE, .type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES, .config = PERF_COUNT_HW_CPU_CYCLES,
.exclude_kernel = 1,
}; };
struct perf_evsel *evsel; struct perf_evsel *evsel;
......
...@@ -50,7 +50,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map, ...@@ -50,7 +50,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map,
if (!ops) { if (!ops) {
pr_err("unwind: target platform=%s is not supported\n", arch); pr_err("unwind: target platform=%s is not supported\n", arch);
return -1; return 0;
} }
out_register: out_register:
unwind__register_ops(thread, ops); unwind__register_ops(thread, ops);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment