mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
tile: support kprobes on tilegx
This change includes support for Kprobes, Jprobes and Return Probes. Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Tony Lu <zlu@tilera.com> Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
@@ -125,6 +125,8 @@ config TILEGX
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_DYNAMIC_FTRACE
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
|
||||
config TILEPRO
|
||||
def_bool !TILEGX
|
||||
|
||||
@@ -15,7 +15,6 @@ generic-y += ioctl.h
|
||||
generic-y += ioctls.h
|
||||
generic-y += ipcbuf.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += kdebug.h
|
||||
generic-y += local.h
|
||||
generic-y += msgbuf.h
|
||||
generic-y += mutex.h
|
||||
|
||||
28
arch/tile/include/asm/kdebug.h
Normal file
28
arch/tile/include/asm/kdebug.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 */
|
||||
79
arch/tile/include/asm/kprobes.h
Normal file
79
arch/tile/include/asm/kprobes.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#define regs_return_value(regs) ((regs)->regs[0])
|
||||
#define instruction_pointer(regs) ((regs)->pc)
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
#define user_stack_pointer(regs) ((regs)->sp)
|
||||
|
||||
@@ -61,6 +61,7 @@ typedef tilegx_bundle_bits tile_bundle_bits;
|
||||
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
|
||||
#define TILE_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. */
|
||||
#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
|
||||
|
||||
@@ -71,6 +71,7 @@ typedef tilepro_bundle_bits tile_bundle_bits;
|
||||
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES
|
||||
#define TILE_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. */
|
||||
#define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL
|
||||
|
||||
@@ -28,5 +28,6 @@ endif
|
||||
obj-$(CONFIG_TILE_USB) += usb.o
|
||||
obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
|
||||
obj-y += vdso/
|
||||
|
||||
528
arch/tile/kernel/kprobes.c
Normal file
528
arch/tile/kernel/kprobes.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/homecache.h>
|
||||
|
||||
HV_Topology smp_topology __write_once;
|
||||
EXPORT_SYMBOL(smp_topology);
|
||||
@@ -167,9 +168,16 @@ static void ipi_flush_icache_range(void *info)
|
||||
void flush_icache_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
struct ipi_flush flush = { start, end };
|
||||
preempt_disable();
|
||||
on_each_cpu(ipi_flush_icache_range, &flush, 1);
|
||||
preempt_enable();
|
||||
|
||||
/* 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();
|
||||
on_each_cpu(ipi_flush_icache_range, &flush, 1);
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/uaccess.h>
|
||||
@@ -214,6 +215,43 @@ static const char *const int_name[] = {
|
||||
#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,
|
||||
unsigned long reason)
|
||||
{
|
||||
@@ -221,6 +259,11 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
||||
int signo, code;
|
||||
unsigned long address = 0;
|
||||
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. */
|
||||
if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
|
||||
@@ -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
|
||||
* current process and hope for the best.
|
||||
*/
|
||||
if (!user_mode(regs)) {
|
||||
if (is_kernel) {
|
||||
const char *name;
|
||||
char buf[100];
|
||||
if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */
|
||||
|
||||
@@ -43,6 +43,7 @@ SECTIONS
|
||||
HEAD_TEXT
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
IRQENTRY_TEXT
|
||||
__fix_text_end = .; /* tile-cpack won't rearrange before this */
|
||||
TEXT_TEXT
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kdebug.h>
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/sections.h>
|
||||
@@ -721,6 +722,17 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
|
||||
{
|
||||
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__
|
||||
/*
|
||||
* 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)
|
||||
" status = 0x%lx\n",
|
||||
p->addr, regs->cp0_epc, regs->cp0_status);
|
||||
#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 */
|
||||
return 0;
|
||||
@@ -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",
|
||||
p->addr, regs->cp0_status);
|
||||
#endif
|
||||
#ifdef CONFIG_TILEGX
|
||||
printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
|
||||
p->addr, regs->ex1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user