]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: perf: Enable dynamic tracepoints when using perf probe
authorDave Aldridge <david.j.aldridge@oracle.com>
Wed, 25 Jan 2017 10:30:13 +0000 (02:30 -0800)
committerChuck Anderson <chuck.anderson@oracle.com>
Thu, 9 Mar 2017 03:30:09 +0000 (19:30 -0800)
This commit enables the use of dynamic tracepoints (kprobes) when
using the perf probe command.

Orabug: 24925615

Signed-off-by: Dave Aldridge <david.j.aldridge@oracle.com>
Signed-off-by: Eric Saint Etienne <eric.saint.etienne@oracle.com>
Reviewed-by: Rob Gardner <rob.gardner@oracle.com>
Signed-off-by: Allen Pais <allen.pais@oracle.com>
arch/sparc/Kconfig
arch/sparc/include/asm/kprobes.h
arch/sparc/include/asm/ptrace.h
arch/sparc/kernel/kprobes.c

index 2d976677c51156477de90050afc72eea36955e3d..2939fffbd39cde1ba5ee7750bcbd7b28d2888999 100644 (file)
@@ -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
index a145d798e1123a9f189e4d546092f689551289f6..e01ae85b870111dcdd078b7f5ec2f39eb72434cd 100644 (file)
@@ -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 {
index 3125cc2c18c418c278f34019a682dd7f7e42adb1..d8cae07615b305d509f4c46170346eeccfd4c17d 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/threads.h>
 #include <asm/switch_to.h>
 
+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;
index cd83be527586ee0be802266d8bc5f35c1b1b1121..8fcd30024a4b547269ffa2704b0aabd144f6d404 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/signal.h>
 #include <asm/cacheflush.h>
 #include <asm/uaccess.h>
+#include <asm/stacktrace.h>
 
 /* 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;
+}
+