From 97365e81366f5ca16a9ce66cff4dd4c5b0d9f4db Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jul 2017 17:01:41 -0300 Subject: perf evsel: Set attr.exclude_kernel when probing max attr.precise_ip We should set attr.exclude_kernel when probing for attr.precise_ip level, otherwise !CAP_SYS_ADMIN users will not default to skidless samples in capable hardware. The increase in the paranoid level in commit 0161028b7c8a ("perf/core: Change the default paranoia level to 2") broke this, fix it by excluding kernel samples when probing. Before: $ perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data (6 samples) ] $ perf evlist -v cycles:u: sample_freq: 4000, sample_type: IP|TID|TIME|PERIOD, exclude_kernel: 1 After: $ perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data (8 samples) ] $ perf evlist -v cycles:ppp: sample_freq: 4000, sample_type: IP|TID|TIME|PERIOD, exclude_kernel: 1, precise_ip: 3 ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ $ To further clarify: we always set .exclude_kernel when non !CAP_SYS_ADMIN users profile, its just on the attr.precise_ip probing that we weren't doing so, fix it. Cc: Adrian Hunter Cc: Andy Lutomirski Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Fixes: 7f8d1ade1b19 ("perf tools: By default use the most precise "cycles" hw counter available") Link: http://lkml.kernel.org/n/tip-t2qttwhbnua62o5gt75cueml@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cda44b0e821c..91192415f38d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -269,6 +269,7 @@ struct perf_evsel *perf_evsel__new_cycles(void) struct perf_event_attr attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, + .exclude_kernel = 1, }; struct perf_evsel *evsel; -- cgit v1.2.3 From 1934adf78e33fa69570a763c7ac5353212416bb0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 4 Jul 2017 15:11:31 +0200 Subject: perf unwind: Do not fail due to missing unwind support We currently fail the MMAP event processing if we don't have the MMAP event's specific arch unwind support compiled in. That's wrong and can lead to unresolved mmaps in report output for 32bit binaries on 64bit server, like in this example on x86_64 server: $ cat ex.c int main(int argc, char **argv) { while (1) {} } $ gcc -o ex -m32 ex.c $ perf record ./ex ^C[ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.371 MB perf.data (9322 samples) ] Before: $ perf report --stdio SNIP # Overhead Command Shared Object Symbol # ........ ....... ................ ...................... # 100.00% ex [unknown] [.] 0x00000000080483de 0.00% ex [unknown] [.] 0x00000000f76dba4f 0.00% ex [unknown] [.] 0x00000000f76e4c11 0.00% ex [unknown] [.] 0x00000000f76daa30 After: $ perf report --stdio SNIP # Overhead Command Shared Object Symbol # ........ ....... ............. ............... # 100.00% ex ex [.] main 0.00% ex ld-2.24.so [.] _dl_start 0.00% ex ld-2.24.so [.] do_lookup_x 0.00% ex ld-2.24.so [.] _start The fix is not to fail, just warn if there's not unwind support compiled in. Reported-by: Michael Lyle Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: He Kuang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170704131131.27508-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libunwind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 6d542a4e0648..8aef572d0889 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -50,7 +50,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map, if (!ops) { pr_err("unwind: target platform=%s is not supported\n", arch); - return -1; + return 0; } out_register: unwind__register_ops(thread, ops); -- cgit v1.2.3 From 659b957f20c78fd470083c80af5e79eedfb39e5b Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 7 Jul 2017 22:37:24 +0530 Subject: kprobes: Rename [arch_]function_offset_within_entry() to [arch_]kprobe_on_func_entry() Rename function_offset_within_entry() to scope it to kprobe namespace by using kprobe_ prefix, and to also simplify it. Suggested-by: Ingo Molnar Suggested-by: Masami Hiramatsu Signed-off-by: Naveen N. Rao Cc: Ananth N Mavinakayanahalli Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/3aa6c7e2e4fb6e00f3c24fa306496a66edb558ea.1499443367.git.naveen.n.rao@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- arch/powerpc/kernel/kprobes.c | 2 +- include/linux/kprobes.h | 4 ++-- kernel/kprobes.c | 8 ++++---- kernel/trace/trace_kprobe.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 01addfb0ed0a..586508e949f0 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -221,7 +221,7 @@ static nokprobe_inline void set_current_kprobe(struct kprobe *p, struct pt_regs 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 CONFIG_KPROBES_ON_FTRACE diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 541df0b5b815..bd2684700b74 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -267,8 +267,8 @@ extern int arch_init_kprobes(void); extern void show_registers(struct pt_regs *regs); extern void kprobes_inc_nmissed_count(struct kprobe *p); extern bool arch_within_kprobe_blacklist(unsigned long addr); -extern bool arch_function_offset_within_entry(unsigned long offset); -extern bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); +extern bool arch_kprobe_on_func_entry(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); diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 6756d750b31b..a519219169fd 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1888,12 +1888,12 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) } 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; } -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); @@ -1901,7 +1901,7 @@ bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsign return false; 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 true; @@ -1914,7 +1914,7 @@ int register_kretprobe(struct kretprobe *rp) int i; 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; if (kretprobe_blacklist_size) { diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index b53c8d369163..2c5221819be5 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -720,7 +720,7 @@ static int create_trace_kprobe(int argc, char **argv) return ret; } 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"); return -EINVAL; } -- cgit v1.2.3 From 0f73ff80b751b39ff539a550e65c5bd131ff0316 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 7 Jul 2017 22:37:25 +0530 Subject: kprobes: Simplify register_jprobes() Re-factor jprobe registration functions as the current version is getting too unwieldy. Move the actual jprobe registration to register_jprobe() and re-organize code accordingly. Suggested-by: Ingo Molnar Signed-off-by: Naveen N. Rao Cc: Ananth N Mavinakayanahalli Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/089cae4bfe73767f765291ee0e6fb0c3d240e5f1.1499443367.git.naveen.n.rao@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a519219169fd..db3cd3e60bdd 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1771,24 +1771,13 @@ unsigned long __weak arch_deref_entry_point(void *entry) int register_jprobes(struct jprobe **jps, int num) { - struct jprobe *jp; int ret = 0, i; if (num <= 0) 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 */ - if (kallsyms_lookup_size_offset(addr, NULL, &offset) && - offset == 0) { - jp->kp.pre_handler = setjmp_pre_handler; - jp->kp.break_handler = longjmp_break_handler; - ret = register_kprobe(&jp->kp); - } else - ret = -EINVAL; + ret = register_jprobe(jps[i]); if (ret < 0) { if (i > 0) @@ -1796,13 +1785,26 @@ int register_jprobes(struct jprobe **jps, int num) break; } } + return ret; } EXPORT_SYMBOL_GPL(register_jprobes); int register_jprobe(struct jprobe *jp) { - return register_jprobes(&jp, 1); + unsigned long addr, offset; + struct kprobe *kp = &jp->kp; + + /* Verify probepoint is a function entry point */ + addr = arch_deref_entry_point(jp->entry); + + if (kallsyms_lookup_size_offset(addr, NULL, &offset) && offset == 0) { + kp->pre_handler = setjmp_pre_handler; + kp->break_handler = longjmp_break_handler; + return register_kprobe(kp); + } + + return -EINVAL; } EXPORT_SYMBOL_GPL(register_jprobe); -- cgit v1.2.3 From dbf580623d5fee785218d1a47a2bcdf36d85c0e9 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 7 Jul 2017 22:37:26 +0530 Subject: kprobes: Ensure that jprobe probepoints are at function entry Similar to commit 90ec5e89e393c ("kretprobes: Ensure probe location is at function entry"), ensure that the jprobe probepoint is at function entry. Signed-off-by: Naveen N. Rao Cc: Ananth N Mavinakayanahalli Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/a4525af6c5a42df385efa31251246cf7cca73598.1499443367.git.naveen.n.rao@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index db3cd3e60bdd..a1606a4224e1 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1795,10 +1795,14 @@ int register_jprobe(struct jprobe *jp) unsigned long addr, offset; struct kprobe *kp = &jp->kp; - /* Verify probepoint is a function entry point */ + /* + * 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) { + 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); -- cgit v1.2.3