Commit 3fa17c39 authored by Tony Lu's avatar Tony Lu Committed by Chris Metcalf

tile: support kprobes on tilegx

This change includes support for Kprobes, Jprobes and Return Probes.
Reviewed-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: default avatarTony Lu <zlu@tilera.com>
Signed-off-by: default avatarChris Metcalf <cmetcalf@tilera.com>
parent a61fd5e3
...@@ -125,6 +125,8 @@ config TILEGX ...@@ -125,6 +125,8 @@ config TILEGX
select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_KPROBES
select HAVE_KRETPROBES
config TILEPRO config TILEPRO
def_bool !TILEGX def_bool !TILEGX
......
...@@ -15,7 +15,6 @@ generic-y += ioctl.h ...@@ -15,7 +15,6 @@ generic-y += ioctl.h
generic-y += ioctls.h generic-y += ioctls.h
generic-y += ipcbuf.h generic-y += ipcbuf.h
generic-y += irq_regs.h generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += local.h generic-y += local.h
generic-y += msgbuf.h generic-y += msgbuf.h
generic-y += mutex.h generic-y += mutex.h
......
/*
* Copyright 2012 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
#ifndef _ASM_TILE_KDEBUG_H
#define _ASM_TILE_KDEBUG_H
#include <linux/notifier.h>
enum die_val {
DIE_OOPS = 1,
DIE_BREAK,
DIE_SSTEPBP,
DIE_PAGE_FAULT,
DIE_COMPILED_BPT
};
#endif /* _ASM_TILE_KDEBUG_H */
/*
* arch/tile/include/asm/kprobes.h
*
* Copyright 2012 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
#ifndef _ASM_TILE_KPROBES_H
#define _ASM_TILE_KPROBES_H
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/percpu.h>
#include <arch/opcode.h>
#define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE 2
#define kretprobe_blacklist_size 0
typedef tile_bundle_bits kprobe_opcode_t;
#define flush_insn_slot(p) \
flush_icache_range((unsigned long)p->addr, \
(unsigned long)p->addr + \
(MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
struct kprobe;
/* Architecture specific copy of original instruction. */
struct arch_specific_insn {
kprobe_opcode_t *insn;
};
struct prev_kprobe {
struct kprobe *kp;
unsigned long status;
unsigned long saved_pc;
};
#define MAX_JPROBES_STACK_SIZE 128
#define MAX_JPROBES_STACK_ADDR \
(((unsigned long)current_thread_info()) + THREAD_SIZE - 32 \
- sizeof(struct pt_regs))
#define MIN_JPROBES_STACK_SIZE(ADDR) \
((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \
? MAX_JPROBES_STACK_ADDR - (ADDR) \
: MAX_JPROBES_STACK_SIZE)
/* per-cpu kprobe control block. */
struct kprobe_ctlblk {
unsigned long kprobe_status;
unsigned long kprobe_saved_pc;
unsigned long jprobe_saved_sp;
struct prev_kprobe prev_kprobe;
struct pt_regs jprobe_saved_regs;
char jprobes_stack[MAX_JPROBES_STACK_SIZE];
};
extern tile_bundle_bits breakpoint2_insn;
extern tile_bundle_bits breakpoint_insn;
void arch_remove_kprobe(struct kprobe *);
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
#endif /* _ASM_TILE_KPROBES_H */
...@@ -33,6 +33,7 @@ typedef unsigned long pt_reg_t; ...@@ -33,6 +33,7 @@ typedef unsigned long pt_reg_t;
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define regs_return_value(regs) ((regs)->regs[0])
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs) #define profile_pc(regs) instruction_pointer(regs)
#define user_stack_pointer(regs) ((regs)->sp) #define user_stack_pointer(regs) ((regs)->sp)
......
...@@ -61,6 +61,7 @@ typedef tilegx_bundle_bits tile_bundle_bits; ...@@ -61,6 +61,7 @@ typedef tilegx_bundle_bits tile_bundle_bits;
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \
TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES
#define TILE_BPT_BUNDLE TILEGX_BPT_BUNDLE
/* 64-bit pattern for a { bpt ; nop } bundle. */ /* 64-bit pattern for a { bpt ; nop } bundle. */
#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL #define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
......
...@@ -71,6 +71,7 @@ typedef tilepro_bundle_bits tile_bundle_bits; ...@@ -71,6 +71,7 @@ typedef tilepro_bundle_bits tile_bundle_bits;
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES
#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \
TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES
#define TILE_BPT_BUNDLE TILEPRO_BPT_BUNDLE
/* 64-bit pattern for a { bpt ; nop } bundle. */ /* 64-bit pattern for a { bpt ; nop } bundle. */
#define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL #define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL
......
...@@ -28,5 +28,6 @@ endif ...@@ -28,5 +28,6 @@ endif
obj-$(CONFIG_TILE_USB) += usb.o obj-$(CONFIG_TILE_USB) += usb.o
obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-y += vdso/ obj-y += vdso/
This diff is collapsed.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/homecache.h>
HV_Topology smp_topology __write_once; HV_Topology smp_topology __write_once;
EXPORT_SYMBOL(smp_topology); EXPORT_SYMBOL(smp_topology);
...@@ -167,9 +168,16 @@ static void ipi_flush_icache_range(void *info) ...@@ -167,9 +168,16 @@ static void ipi_flush_icache_range(void *info)
void flush_icache_range(unsigned long start, unsigned long end) void flush_icache_range(unsigned long start, unsigned long end)
{ {
struct ipi_flush flush = { start, end }; struct ipi_flush flush = { start, end };
/* If invoked with irqs disabled, we can not issue IPIs. */
if (irqs_disabled())
flush_remote(0, HV_FLUSH_EVICT_L1I, NULL, 0, 0, 0,
NULL, NULL, 0);
else {
preempt_disable(); preempt_disable();
on_each_cpu(ipi_flush_icache_range, &flush, 1); on_each_cpu(ipi_flush_icache_range, &flush, 1);
preempt_enable(); preempt_enable();
}
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/kdebug.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -214,6 +215,43 @@ static const char *const int_name[] = { ...@@ -214,6 +215,43 @@ static const char *const int_name[] = {
#endif #endif
}; };
static int do_bpt(struct pt_regs *regs)
{
unsigned long bundle, bcode, bpt;
bundle = *(unsigned long *)instruction_pointer(regs);
/*
* bpt shoule be { bpt; nop }, which is 0x286a44ae51485000ULL.
* we encode the unused least significant bits for other purpose.
*/
bpt = bundle & ~((1ULL << 12) - 1);
if (bpt != TILE_BPT_BUNDLE)
return 0;
bcode = bundle & ((1ULL << 12) - 1);
/*
* notify the kprobe handlers, if instruction is likely to
* pertain to them.
*/
switch (bcode) {
/* breakpoint_insn */
case 0:
notify_die(DIE_BREAK, "debug", regs, bundle,
INT_ILL, SIGTRAP);
break;
/* breakpoint2_insn */
case DIE_SSTEPBP:
notify_die(DIE_SSTEPBP, "single_step", regs, bundle,
INT_ILL, SIGTRAP);
break;
default:
return 0;
}
return 1;
}
void __kprobes do_trap(struct pt_regs *regs, int fault_num, void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason) unsigned long reason)
{ {
...@@ -221,6 +259,11 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -221,6 +259,11 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
int signo, code; int signo, code;
unsigned long address = 0; unsigned long address = 0;
bundle_bits instr; bundle_bits instr;
int is_kernel = !user_mode(regs);
/* Handle breakpoints, etc. */
if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
return;
/* Re-enable interrupts, if they were previously enabled. */ /* Re-enable interrupts, if they were previously enabled. */
if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
...@@ -230,7 +273,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -230,7 +273,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
* If it hits in kernel mode and we can't fix it up, just exit the * If it hits in kernel mode and we can't fix it up, just exit the
* current process and hope for the best. * current process and hope for the best.
*/ */
if (!user_mode(regs)) { if (is_kernel) {
const char *name; const char *name;
char buf[100]; char buf[100];
if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */
......
...@@ -43,6 +43,7 @@ SECTIONS ...@@ -43,6 +43,7 @@ SECTIONS
HEAD_TEXT HEAD_TEXT
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT IRQENTRY_TEXT
__fix_text_end = .; /* tile-cpack won't rearrange before this */ __fix_text_end = .; /* tile-cpack won't rearrange before this */
TEXT_TEXT TEXT_TEXT
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/sections.h> #include <asm/sections.h>
...@@ -721,6 +722,17 @@ void do_page_fault(struct pt_regs *regs, int fault_num, ...@@ -721,6 +722,17 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
{ {
int is_page_fault; int is_page_fault;
#ifdef CONFIG_KPROBES
/*
* This is to notify the fault handler of the kprobes. The
* exception code is redundant as it is also carried in REGS,
* but we pass it anyhow.
*/
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
regs->faultnum, SIGSEGV) == NOTIFY_STOP)
return;
#endif
#ifdef __tilegx__ #ifdef __tilegx__
/* /*
* We don't need early do_page_fault_ics() support, since unlike * We don't need early do_page_fault_ics() support, since unlike
......
...@@ -37,6 +37,11 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs) ...@@ -37,6 +37,11 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
" status = 0x%lx\n", " status = 0x%lx\n",
p->addr, regs->cp0_epc, regs->cp0_status); p->addr, regs->cp0_epc, regs->cp0_status);
#endif #endif
#ifdef CONFIG_TILEGX
printk(KERN_INFO "pre_handler: p->addr = 0x%p, pc = 0x%lx,"
" ex1 = 0x%lx\n",
p->addr, regs->pc, regs->ex1);
#endif
/* A dump_stack() here will give a stack backtrace */ /* A dump_stack() here will give a stack backtrace */
return 0; return 0;
...@@ -58,6 +63,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs, ...@@ -58,6 +63,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n", printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n",
p->addr, regs->cp0_status); p->addr, regs->cp0_status);
#endif #endif
#ifdef CONFIG_TILEGX
printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
p->addr, regs->ex1);
#endif
} }
/* /*
......
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