From 92a1dc95e0d50c4ceea9414e8b5ea5a51608694e Mon Sep 17 00:00:00 2001 From: Dave Aldridge Date: Wed, 25 Jan 2017 02:30:13 -0800 Subject: [PATCH] sparc64: perf: Enable dynamic tracepoints when using perf probe This commit enables the use of dynamic tracepoints (kprobes) when using the perf probe command. Orabug: 24925615 Signed-off-by: Dave Aldridge Signed-off-by: Eric Saint Etienne Reviewed-by: Rob Gardner Signed-off-by: Allen Pais --- arch/sparc/Kconfig | 1 + arch/sparc/include/asm/kprobes.h | 8 ++++--- arch/sparc/include/asm/ptrace.h | 2 ++ arch/sparc/kernel/kprobes.c | 39 ++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 2d976677c5115..2939fffbd39cd 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -67,6 +67,7 @@ config SPARC64 select HAVE_SYSCALL_TRACEPOINTS select HAVE_CONTEXT_TRACKING select HAVE_DEBUG_KMEMLEAK + select HAVE_REGS_AND_STACK_ACCESS_API select SPARSE_IRQ select RTC_DRV_CMOS select RTC_DRV_BQ4802 diff --git a/arch/sparc/include/asm/kprobes.h b/arch/sparc/include/asm/kprobes.h index a145d798e1123..e01ae85b87011 100644 --- a/arch/sparc/include/asm/kprobes.h +++ b/arch/sparc/include/asm/kprobes.h @@ -6,14 +6,13 @@ typedef u32 kprobe_opcode_t; +#define __ARCH_WANT_KPROBES_INSN_SLOT #define BREAKPOINT_INSTRUCTION 0x91d02070 /* ta 0x70 */ #define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */ #define MAX_INSN_SIZE 2 #define kretprobe_blacklist_size 0 -#define arch_remove_kprobe(p) do {} while (0) - #define flush_insn_slot(p) \ do { flushi(&(p)->ainsn.insn[0]); \ flushi(&(p)->ainsn.insn[1]); \ @@ -21,10 +20,13 @@ do { flushi(&(p)->ainsn.insn[0]); \ void kretprobe_trampoline(void); +struct kprobe; +void __kprobes arch_remove_kprobe(struct kprobe *p); + /* Architecture specific copy of original instruction*/ struct arch_specific_insn { /* copy of the original instruction */ - kprobe_opcode_t insn[MAX_INSN_SIZE]; + kprobe_opcode_t *insn; }; struct prev_kprobe { diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index 3125cc2c18c41..d8cae07615b30 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -9,6 +9,8 @@ #include #include +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n); + static inline int pt_regs_trap_type(struct pt_regs *regs) { return regs->magic & 0x1ff; diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index cd83be527586e..8fcd30024a4b5 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -12,6 +12,7 @@ #include #include #include +#include /* We do not have hardware single-stepping on sparc64. * So we implement software single-stepping with breakpoint @@ -51,6 +52,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if ((unsigned long) p->addr & 0x3UL) return -EILSEQ; + p->ainsn.insn = get_insn_slot(); + if (!p->ainsn.insn) + return -ENOMEM; + p->ainsn.insn[0] = *p->addr; flushi(&p->ainsn.insn[0]); @@ -61,6 +66,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return 0; } +void __kprobes arch_remove_kprobe(struct kprobe *p) +{ + if (p->ainsn.insn) { + free_insn_slot(p->ainsn.insn, 0); + p->ainsn.insn = NULL; + } +} + void __kprobes arch_arm_kprobe(struct kprobe *p) { *p->addr = BREAKPOINT_INSTRUCTION; @@ -601,3 +614,29 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) return 0; } + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) +{ + unsigned long ksp, nth_entry_addr; + + stack_trace_flush(); + + ksp = kernel_stack_pointer(regs); + ksp += STACK_BIAS; + nth_entry_addr = ksp + (n * sizeof(unsigned long)); + + if (object_is_on_stack((void *)nth_entry_addr)) + return *(unsigned long *)nth_entry_addr; + else + return 0; +} + -- 2.50.1