From 1c7192082e7f7abe829096b4c70a8986b9a05f33 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Thu, 20 Feb 2014 17:21:49 +0400 Subject: [PATCH] ARM64: implement brk hook Create interface for using software breakpoint Change-Id: Ic080dc6f79746c9cadacd336facdef49557aaa01 Signed-off-by: Vyacheslav Cherkashin --- kprobe/Kbuild | 3 +- kprobe/arch/arm64/swap-asm/dbg_interface.c | 137 +++++++++++++++++++++++++++++ kprobe/arch/arm64/swap-asm/dbg_interface.h | 64 ++++++++++++++ 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 kprobe/arch/arm64/swap-asm/dbg_interface.c create mode 100644 kprobe/arch/arm64/swap-asm/dbg_interface.h diff --git a/kprobe/Kbuild b/kprobe/Kbuild index 489db75..2501018 100644 --- a/kprobe/Kbuild +++ b/kprobe/Kbuild @@ -16,7 +16,8 @@ endif #ifeq ($(CONFIG_STRICT_MEMORY_RWX), y) ### ARM64 -swap_kprobe-$(CONFIG_ARM64) += arch/arm64/swap-asm/swap_kprobes.o +swap_kprobe-$(CONFIG_ARM64) += arch/arm64/swap-asm/swap_kprobes.o \ + arch/arm64/swap-asm/dbg_interface.o ### X86 diff --git a/kprobe/arch/arm64/swap-asm/dbg_interface.c b/kprobe/arch/arm64/swap-asm/dbg_interface.c new file mode 100644 index 0000000..438b7b8 --- /dev/null +++ b/kprobe/arch/arm64/swap-asm/dbg_interface.c @@ -0,0 +1,137 @@ +/* + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include +#include +#include "dbg_interface.h" + + + + +/* ============================================================================ + * = BRK IMPLEMENT = + * ============================================================================ + */ +static LIST_HEAD(brk_list); +static DEFINE_RWLOCK(brk_list_lock); + +void dbg_brk_hook_reg(struct brk_hook *hook) +{ + write_lock(&brk_list_lock); + list_add(&hook->list, &brk_list); + write_unlock(&brk_list_lock); +} +EXPORT_SYMBOL_GPL(dbg_brk_hook_reg); + +void dbg_brk_hook_unreg(struct brk_hook *hook) +{ + write_lock(&brk_list_lock); + list_del(&hook->list); + write_unlock(&brk_list_lock); +} +EXPORT_SYMBOL_GPL(dbg_brk_hook_unreg); + +static enum dbg_code call_brk_hook(struct pt_regs *regs, unsigned int esr) +{ + struct brk_hook *hook; + enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr) = NULL; + + read_lock(&brk_list_lock); + list_for_each_entry(hook, &brk_list, list) + if (((esr & hook->esr_mask) == hook->esr_val) && + ((regs->pstate & hook->spsr_mask) == hook->spsr_val)) + fn = hook->fn; + read_unlock(&brk_list_lock); + + return fn ? fn(regs, esr) : DBG_ERROR; +} + + +typedef int (*dbg_fn_t)(unsigned long addr, unsigned int esr, + struct pt_regs *regs); + +static dbg_fn_t *brk_handler_ptr; +static dbg_fn_t orig_brk_handler; + +static int brk_handler(unsigned long addr, unsigned int esr, + struct pt_regs *regs) +{ + /* call the registered breakpoint handler */ + if (call_brk_hook(regs, esr) == DBG_HANDLED) + return 0; + + return orig_brk_handler(addr, esr, regs); +} + +static void init_brk(dbg_fn_t *fn) +{ + brk_handler_ptr = fn; + orig_brk_handler = *brk_handler_ptr; + *brk_handler_ptr = brk_handler; +} + +static void uninit_brk(void) +{ + *brk_handler_ptr = orig_brk_handler; +} + + + + + + +/* ============================================================================ + * = INIT / EXIT = + * ============================================================================ + */ +int dbg_iface_init(void) +{ + struct fault_info { + int (*fn)(unsigned long addr, unsigned int esr, + struct pt_regs *regs); + int sig; + int code; + const char *name; + }; + + struct fault_info *debug_finfo; + struct fault_info *finfo_brk; + + debug_finfo = (struct fault_info *)swap_ksyms("debug_fault_info"); + if (debug_finfo == NULL) { + pr_err("cannot found 'debug_fault_info'\n"); + return -EINVAL; + } + + finfo_brk = &debug_finfo[DBG_ESR_EVT_BRK]; + + init_brk(&finfo_brk->fn); + + return 0; +} + +void dbg_iface_uninit(void) +{ + uninit_brk(); +} diff --git a/kprobe/arch/arm64/swap-asm/dbg_interface.h b/kprobe/arch/arm64/swap-asm/dbg_interface.h new file mode 100644 index 0000000..185d5ae --- /dev/null +++ b/kprobe/arch/arm64/swap-asm/dbg_interface.h @@ -0,0 +1,64 @@ +#ifndef _ASM_DBG_INTERFACE_H +#define _ASM_DBG_INTERFACE_H + +/* + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Vyacheslav Cherkashin + * + */ + + +#include +#include + + +#define ESR_ELx_IL (1 << 25) +#define ESR_ELx_EC_BRK 0xf0000000 +#define ESR_ELx_EC_MASK 0xfc000000 +#define BRK_COMM_MASK 0x0000ffff + +#define DBG_BRK_ESR_MASK (ESR_ELx_EC_MASK | ESR_ELx_IL | BRK_COMM_MASK) +#define DBG_BRK_ESR(x) (ESR_ELx_EC_BRK | ESR_ELx_IL | (BRK_COMM_MASK & (x))) + +#define MAKE_BRK(v) ((((v) & 0xffff) << 5) | 0xd4200000) + + +enum dbg_code { + DBG_HANDLED, + DBG_ERROR, +}; + + +struct brk_hook { + struct list_head list; + u32 spsr_mask; + u32 spsr_val; + u32 esr_mask; + u32 esr_val; + enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr); +}; + + +void dbg_brk_hook_reg(struct brk_hook *hook); +void dbg_brk_hook_unreg(struct brk_hook *hook); + +int dbg_iface_init(void); +void dbg_iface_uninit(void); + + +#endif /* _ASM_DBG_INTERFACE_H */ -- 2.7.4