From 5c5900144e8624eccdc35fbd518229062f8b8c2e Mon Sep 17 00:00:00 2001 From: Alexander Aksenov Date: Thu, 3 Jul 2014 15:23:28 +0400 Subject: [PATCH] [STYLE] Kprobe: doxygen comments Change-Id: I597197ca4b43d9aa3b2e3af754da0724f9b0d5ef Signed-off-by: Alexander Aksenov --- kprobe/arch/asm-arm/swap_kprobes.c | 193 +++++++++++++++++++++++++++++--- kprobe/arch/asm-arm/swap_kprobes.h | 158 +++++++++++++++++++++++--- kprobe/arch/asm-arm/trampoline_arm.h | 21 ++-- kprobe/arch/asm-x86/swap_kprobes.c | 149 ++++++++++++++++++++----- kprobe/arch/asm-x86/swap_kprobes.h | 83 +++++++------- kprobe/swap_kdebug.h | 26 +++-- kprobe/swap_kprobes.c | 162 +++++++++++++++++++++------ kprobe/swap_kprobes.h | 207 ++++++++++++++++++++--------------- kprobe/swap_kprobes_deps.c | 65 +++++++++-- kprobe/swap_kprobes_deps.h | 23 ++-- kprobe/swap_slots.c | 77 ++++++++----- kprobe/swap_slots.h | 60 +++++----- 12 files changed, 914 insertions(+), 310 deletions(-) diff --git a/kprobe/arch/asm-arm/swap_kprobes.c b/kprobe/arch/asm-arm/swap_kprobes.c index 0103fe2..c569e36 100644 --- a/kprobe/arch/asm-arm/swap_kprobes.c +++ b/kprobe/arch/asm-arm/swap_kprobes.c @@ -1,6 +1,15 @@ -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/arch/asm-arm/swap_kprobes.c +/** + * kprobe/arch/asm-arm/swap_kprobes.c + * @author Ekaterina Gorelkina : initial implementation for ARM/MIPS + * @author Alexey Gerenkov User-Space Probes initial implementation; Support x86. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Alexander Shirshikov : initial implementation for Thumb + * @author Stanislav Andreev : added time debug profiling support; BUG() message fix + * @author Stanislav Andreev : redesign of kprobe functionality - + * kprobe_handler() now called via undefined instruction hooks + * @author Stanislav Andreev : hash tables search implemented for uprobes + * + * @section LICENSE * * 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 @@ -16,17 +25,13 @@ * 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, 2006-2010 - * - * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM/MIPS - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts - * 2010-2011 Alexander Shirshikov : initial implementation for Thumb - * 2012 Stanislav Andreev : added time debug profiling support; BUG() message fix - * 2012 Stanislav Andreev : redesign of kprobe functionality - - * kprobe_handler() now called via undefined instruction hooks - * 2012 Stanislav Andreev : hash tables search implemented for uprobes + * @section COPYRIGHT + * + * Copyright (C) Samsung Electronics, 2006-2014 + * + * @section DESCRIPTION + * + * SWAP kprobe implementation for ARM architecture. */ #include @@ -47,7 +52,7 @@ #include #include -#define SUPRESS_BUG_MESSAGES +#define SUPRESS_BUG_MESSAGES /**< Debug-off definition */ #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) @@ -204,6 +209,14 @@ static int make_branch_tarmpoline(unsigned long addr, unsigned long insn, return ok; } +/** + * @brief Creates ARM trampoline. + * + * @param addr Probe address. + * @param insn Instuction at this address. + * @param tramp Pointer to memory for trampoline. + * @return 0 on success, error code on error. + */ int arch_make_trampoline_arm(unsigned long addr, unsigned long insn, unsigned long *tramp) { @@ -293,6 +306,13 @@ int arch_make_trampoline_arm(unsigned long addr, unsigned long insn, } EXPORT_SYMBOL_GPL(arch_make_trampoline_arm); +/** + * @brief Creates trampoline for kprobe. + * + * @param p Pointer to kprobe. + * @param sm Pointer to slot manager + * @return 0 on success, error code on error. + */ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm) { unsigned long addr = (unsigned long)p->addr; @@ -318,6 +338,13 @@ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm) return 0; } +/** + * @brief Prepares singlestep for current CPU. + * + * @param p Pointer to kprobe. + * @param regs Pointer to CPU registers data. + * @return Void. + */ void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) { int cpu = smp_processor_id(); @@ -331,18 +358,39 @@ void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) } EXPORT_SYMBOL_GPL(prepare_singlestep); +/** + * @brief Saves previous kprobe. + * + * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe. + * @param p_run Pointer to kprobe. + * @return Void. + */ void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p_run) { kcb->prev_kprobe.kp = swap_kprobe_running(); kcb->prev_kprobe.status = kcb->kprobe_status; } +/** + * @brief Restores previous kprobe. + * + * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe. + * @return Void. + */ void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { __get_cpu_var(swap_current_kprobe) = kcb->prev_kprobe.kp; kcb->kprobe_status = kcb->prev_kprobe.status; } +/** + * @brief Sets currently running kprobe. + * + * @param p Pointer to currently running kprobe. + * @param regs Pointer to CPU registers data. + * @param kcb Pointer to kprobe_ctlblk. + * @return Void. + */ void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { __get_cpu_var(swap_current_kprobe) = p; @@ -398,6 +446,13 @@ no_kprobe: return 1; } +/** + * @brief Trap handler. + * + * @param regs Pointer to CPU register data. + * @param instr Instruction. + * @return kprobe_handler result. + */ int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr) { int ret; @@ -424,6 +479,13 @@ int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr) return ret; } +/** + * @brief Probe pre handler. + * + * @param p Pointer to fired kprobe. + * @param regs Pointer to CPU registers data. + * @return 0. + */ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); @@ -446,11 +508,23 @@ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) return 0; } +/** + * @brief Jprobe return stub. + * + * @return Void. + */ void swap_jprobe_return(void) { } EXPORT_SYMBOL_GPL(swap_jprobe_return); +/** + * @brief Break handler stub. + * + * @param p Pointer to fired kprobe. + * @param regs Pointer to CPU registers data. + * @return 0. + */ int swap_longjmp_break_handler (struct kprobe *p, struct pt_regs *regs) { return 0; @@ -461,6 +535,12 @@ EXPORT_SYMBOL_GPL(swap_longjmp_break_handler); extern void mem_text_write_kernel_word(unsigned long *addr, unsigned long word); #endif +/** + * @brief Arms kprobe. + * + * @param p Pointer to target kprobe. + * @return Void. + */ void swap_arch_arm_kprobe(struct kprobe *p) { #ifdef CONFIG_STRICT_MEMORY_RWX @@ -471,6 +551,12 @@ void swap_arch_arm_kprobe(struct kprobe *p) #endif } +/** + * @brief Disarms kprobe. + * + * @param p Pointer to target kprobe. + * @return Void. + */ void swap_arch_disarm_kprobe(struct kprobe *p) { #ifdef CONFIG_STRICT_MEMORY_RWX @@ -481,6 +567,11 @@ void swap_arch_disarm_kprobe(struct kprobe *p) #endif } +/** + * @brief Kretprobe trampoline. Provides jumping to probe handler. + * + * @return Void. + */ void __naked swap_kretprobe_trampoline(void) { __asm__ __volatile__ ( @@ -494,6 +585,14 @@ void __naked swap_kretprobe_trampoline(void) : : : "memory"); } +/** + * @brief Prepares kretprobes, saves ret address, makes function return to + * trampoline. + * + * @param ri Pointer to kretprobe_instance. + * @param regs Pointer to CPU registers data. + * @return Void. + */ void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { @@ -544,6 +643,11 @@ static struct kj_cb_data * __used kjump_handler(struct kj_cb_data *data) return data; } +/** + * @brief Trampoline for kjump kprobes. + * + * @return Void. + */ void kjump_trampoline(void); __asm( "kjump_trampoline: \n" @@ -553,12 +657,27 @@ __asm( "nop \n" /* for kjump_kprobe */ ); +/** + * @brief Gets kjump address. + * + * @return Kjump address. + */ unsigned long get_kjump_addr(void) { return (unsigned long)&kjump_trampoline; } EXPORT_SYMBOL_GPL(get_kjump_addr); +/** + * @brief Registers callback for kjump probes. + * + * @param ret_addr Kjump probe return address. + * @param regs Pointer to CPU registers data. + * @param cb Kjump probe callback of jumper_cb_t type. + * @param data Pointer to data that should be saved in kj_cb_data. + * @param size Size of the data. + * @return 0. + */ int set_kjump_cb(unsigned long ret_addr, struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size) { @@ -654,6 +773,12 @@ static unsigned long __used jump_handler(struct cb_data *data) } /* FIXME: restore condition flags */ + +/** + * @brief Jumper trampoline. + * + * @return Void. + */ void jump_trampoline(void); __asm( "jump_trampoline: \n" @@ -669,12 +794,27 @@ __asm( "bx lr \n" ); +/** + * @brief Get jumper address. + * + * @return Jumper address. + */ unsigned long get_jump_addr(void) { return (unsigned long)&jump_trampoline; } EXPORT_SYMBOL_GPL(get_jump_addr); +/** + * @brief Set jumper probe callback. + * + * @param ret_addr Jumper probe return address. + * @param regs Pointer to CPU registers data. + * @param cb Jumper callback of jumper_cb_t type. + * @param data Data that should be stored in cb_data. + * @param size Size of the data. + * @return 0. + */ int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size) { @@ -698,13 +838,24 @@ EXPORT_SYMBOL_GPL(set_jump_cb); - +/** + * @brief Registers hook on specified instruction. + * + * @param hook Pointer to struct undef_hook. + * @return Void. + */ void swap_register_undef_hook(struct undef_hook *hook) { __swap_register_undef_hook(hook); } EXPORT_SYMBOL_GPL(swap_register_undef_hook); +/** + * @brief Unregisters hook. + * + * @param hook Pointer to struct undef_hook. + * @return Void. + */ void swap_unregister_undef_hook(struct undef_hook *hook) { __swap_unregister_undef_hook(hook); @@ -720,6 +871,11 @@ static struct undef_hook undef_ho_k = { .fn = kprobe_trap_handler }; +/** + * @brief Initializes kprobes module for ARM arch. + * + * @return 0 on success, error code on error. + */ int swap_arch_init_kprobes(void) { int ret; @@ -749,6 +905,11 @@ int swap_arch_init_kprobes(void) return 0; } +/** + * @brief Uninitializes kprobe module. + * + * @return Void. + */ void swap_arch_exit_kprobes(void) { kjump_exit(); diff --git a/kprobe/arch/asm-arm/swap_kprobes.h b/kprobe/arch/asm-arm/swap_kprobes.h index a97420e..dcfccdc 100644 --- a/kprobe/arch/asm-arm/swap_kprobes.h +++ b/kprobe/arch/asm-arm/swap_kprobes.h @@ -1,9 +1,11 @@ -#ifndef _SWAP_ASM_ARM_KPROBES_H -#define _SWAP_ASM_ARM_KPROBES_H - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/arch/asm-arm/swap_kprobes.h +/** + * @file kprobe/arch/asm-arm/swap_kprobes.h + * @author Ekaterina Gorelkina : initial implementation for ARM/MIPS + * @author Alexey Gerenkov User-Space Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Alexander Shirshikov : initial implementation for Thumb + * + * @section LICENSE * * 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 @@ -19,102 +21,192 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * * Copyright (C) Samsung Electronics, 2006-2010 * - * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM/MIPS - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * - * 2010-2011 Alexander Shirshikov : initial implementation for Thumb + * ARM arch-dependent kprobes interface declaration. */ + +#ifndef _SWAP_ASM_ARM_KPROBES_H +#define _SWAP_ASM_ARM_KPROBES_H + #include #include typedef unsigned long kprobe_opcode_t; #ifdef CONFIG_CPU_S3C2443 +/** Breakpoint instruction */ #define BREAKPOINT_INSTRUCTION 0xe1200070 #else +/** Breakpoint instruction */ #define BREAKPOINT_INSTRUCTION 0xffffdeff #endif /* CONFIG_CPU_S3C2443 */ #ifndef KPROBES_RET_PROBE_TRAMP #ifdef CONFIG_CPU_S3C2443 +/** Undefined instruction */ #define UNDEF_INSTRUCTION 0xe1200071 #else +/** Undefined instruction */ #define UNDEF_INSTRUCTION 0xfffffffe #endif /* CONFIG_CPU_S3C2443 */ #endif /* KPROBES_RET_PROBE_TRAMP */ +/** Maximum insn size */ #define MAX_INSN_SIZE 1 +/** Uprobes trampoline length */ #define UPROBES_TRAMP_LEN 9 * 4 -# define UPROBES_TRAMP_INSN_IDX 2 -# define UPROBES_TRAMP_SS_BREAK_IDX 4 -# define UPROBES_TRAMP_RET_BREAK_IDX 5 +/** Uprobes trampoline insn idx */ +#define UPROBES_TRAMP_INSN_IDX 2 +/** Uprobes trampoline ss break idx */ +#define UPROBES_TRAMP_SS_BREAK_IDX 4 +/** Uprobes trampoline ret break idx */ +#define UPROBES_TRAMP_RET_BREAK_IDX 5 +/** Kprobes trampoline length */ #define KPROBES_TRAMP_LEN 9 * 4 +/** Kprobes trampoline insn idx */ # define KPROBES_TRAMP_INSN_IDX UPROBES_TRAMP_INSN_IDX +/** Kprobes trampoline ss break idx */ # define KPROBES_TRAMP_SS_BREAK_IDX UPROBES_TRAMP_SS_BREAK_IDX /* TODO: remove (not needed for kprobe) */ # define KPROBES_TRAMP_RET_BREAK_IDX UPROBES_TRAMP_RET_BREAK_IDX +/** User register offset */ #define UREGS_OFFSET 8 +/** + * @struct prev_kprobe + * @brief Stores previous kprobe. + * @var prev_kprobe::kp + * Pointer to kprobe struct. + * @var prev_kprobe::status + * Kprobe status. + */ struct prev_kprobe { struct kprobe *kp; unsigned long status; }; +/** + * @brief Gets task pc. + * + * @param p Pointer to task_struct + * @return Value in pc. + */ static inline unsigned long arch_get_task_pc(struct task_struct *p) { return task_thread_info(p)->cpu_context.pc; } +/** + * @brief Sets task pc. + * + * @param p Pointer to task_struct. + * @param val Value that should be set. + * @return Void. + */ static inline void arch_set_task_pc(struct task_struct *p, unsigned long val) { task_thread_info(p)->cpu_context.pc = val; } +/** + * @brief Gets syscall registers. + * + * @param sp Pointer to stack. + * @return Pointer to CPU regs data. + */ static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp) { return (struct pt_regs *)(sp + UREGS_OFFSET); } +/** + * @brief Gets stack pointer. + * + * @param regs Pointer to CPU registers data. + * @return Stack address. + */ static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs) { return regs->ARM_sp; } +/** + * @brief Gets instruction pointer. + * + * @param regs Pointer to CPU registers data. + * @return Pointer to pc. + */ static inline unsigned long swap_get_instr_ptr(struct pt_regs *regs) { return regs->ARM_pc; } +/** + * @brief Sets instruction pointer. + * + * @param regs Pointer to CPU registers data. + * @param val Address that should be stored in pc. + * @return Void. + */ static inline void swap_set_instr_ptr(struct pt_regs *regs, unsigned long val) { regs->ARM_pc = val; } +/** + * @brief Gets return address. + * + * @param regs Pointer to CPU registers data. + * @return Return address. + */ static inline unsigned long swap_get_ret_addr(struct pt_regs *regs) { return regs->ARM_lr; } +/** + * @brief Sets return address. + * + * @param regs Pointer to CPU registers data. + * @param val New return address. + * @return Void. + */ static inline void swap_set_ret_addr(struct pt_regs *regs, unsigned long val) { regs->ARM_lr = val; } +/** + * @brief Gets specified argument. + * + * @param regs Pointer to CPU registers data. + * @param num Number of the argument. + * @return Argument value. + */ static inline unsigned long swap_get_arg(struct pt_regs *regs, int num) { return regs->uregs[num]; } +/** + * @brief Sets specified argument. + * + * @param regs Pointer to CPU registers data. + * @param num Number of the argument. + * @param val New argument value. + * @return Void. + */ static inline void swap_set_arg(struct pt_regs *regs, int num, unsigned long val) { @@ -465,15 +557,28 @@ static inline void swap_set_arg(struct pt_regs *regs, int num, # define THUMB2_INSN_REG_RM(insn) ((insn & 0x000f0000) >> 16) -/* per-cpu kprobe control block */ + + +/** + * @struct kprobe_ctlblk + * @brief Per-cpu kprobe control block. + * @var kprobe_ctlblk::kprobe_status + * Kprobe status. + * @var kprobe_ctlblk::prev_kprobe + * Previous kprobe. + */ struct kprobe_ctlblk { unsigned long kprobe_status; struct prev_kprobe prev_kprobe; }; -/* Architecture specific copy of original instruction */ +/** + * @struct arch_specific_insn + * @brief Architecture specific copy of original instruction. + * @var arch_specific_insn::insn + * Copy of the original instruction. + */ struct arch_specific_insn { - /* copy of the original instruction */ kprobe_opcode_t *insn; }; @@ -484,6 +589,11 @@ struct undef_hook; void swap_register_undef_hook(struct undef_hook *hook); void swap_unregister_undef_hook(struct undef_hook *hook); +/** + * @brief Arch-dependend module deps initialization stub. + * + * @return 0. + */ static inline int arch_init_module_deps(void) { return 0; @@ -511,6 +621,13 @@ void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ct void __naked swap_kretprobe_trampoline(void); +/** + * @brief Gets arguments of kernel functions. + * + * @param regs Pointer to CPU registers data. + * @param n Number of the argument. + * @return Argument value. + */ static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n) { switch (n) { @@ -527,6 +644,13 @@ static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n) return *((unsigned long *)regs->ARM_sp + n - 4); } +/** + * @brief swap_get_karg wrapper. + * + * @param regs Pointer to CPU registers data. + * @param n Number of the argument. + * @return Argument value. + */ static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n) { return swap_get_karg(regs, n); diff --git a/kprobe/arch/asm-arm/trampoline_arm.h b/kprobe/arch/asm-arm/trampoline_arm.h index f507f4a..257aca8 100644 --- a/kprobe/arch/asm-arm/trampoline_arm.h +++ b/kprobe/arch/asm-arm/trampoline_arm.h @@ -1,6 +1,12 @@ -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/arch/asm-arm/trampoline_arm.h +/** + * @file kprobe/arch/asm-arm/trampoline_arm.h + * @author Ekaterina Gorelkina : initial implementation for ARM/MIPS + * @author Alexey Gerenkov User-Space + * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Alexander Shirshikov : initial implementation for Thumb + * + * @section LICENSE * * 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 @@ -16,14 +22,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * * Copyright (C) Samsung Electronics, 2006-2010 * - * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM/MIPS - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * - * 2010-2011 Alexander Shirshikov : initial implementation for Thumb + * Provides intefrace for trampoline_arm.S */ #ifndef __ASM_ARM_TRAMPOLINE_ARM_H diff --git a/kprobe/arch/asm-x86/swap_kprobes.c b/kprobe/arch/asm-x86/swap_kprobes.c index 3f1226a..813d023 100644 --- a/kprobe/arch/asm-x86/swap_kprobes.c +++ b/kprobe/arch/asm-x86/swap_kprobes.c @@ -1,6 +1,11 @@ -/* - * Kernel Probes (KProbes) - * arch/x86/kernel/kprobes.c +/** + * arch/asm-x86/swap_kprobes.c + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Stanislav Andreev : added time debug profiling support; BUG() message fix + * + * @section LICENSE * * 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 @@ -16,33 +21,13 @@ * 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) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/arch/asm-x86/swap_kprobes.c - * - * 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. + * @section COPYRIGHT * - * 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) IBM Corporation, 2002, 2004 * - * Copyright (C) Samsung Electronics, 2006-2010 + * @section DESCRIPTION * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts - * 2012 Stanislav Andreev : added time debug profiling support; BUG() message fix + * SWAP krpobes arch-dependend part for x86. */ #include @@ -54,7 +39,7 @@ #include #include #include -#define SUPRESS_BUG_MESSAGES +#define SUPRESS_BUG_MESSAGES /**< Debug-off definition. */ extern struct kprobe * per_cpu__current_kprobe; extern struct kprobe * per_cpu__current_kprobe; @@ -66,6 +51,7 @@ static void *(*swap_text_poke)(void *addr, const void *opcode, size_t len); static void (*swap_show_registers)(struct pt_regs * regs); +/** Stack address. */ #define stack_addr(regs) ((unsigned long *)kernel_stack_pointer(regs)) /* @@ -126,8 +112,11 @@ static __always_inline void set_jmp_op (void *from, void *to) jop->op = RELATIVEJUMP_INSTRUCTION; } -/* - * returns non-zero if opcodes can be boosted. +/** + * @brief Check if opcode can be boosted. + * + * @param opcodes Opcode to check. + * @return Non-zero if opcode can be boosted. */ int swap_can_boost(kprobe_opcode_t *opcodes) { @@ -227,6 +216,13 @@ static int is_IF_modifier (kprobe_opcode_t opcode) return 0; } +/** + * @brief Creates trampoline for kprobe. + * + * @param p Pointer to kprobe. + * @param sm Pointer to slot manager + * @return 0 on success, error code on error. + */ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm) { /* insn: must be on special executable page on i386. */ @@ -242,6 +238,13 @@ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm) return 0; } +/** + * @brief Prepares singlestep for current CPU. + * + * @param p Pointer to kprobe. + * @param regs Pointer to CPU registers data. + * @return Void. + */ void prepare_singlestep (struct kprobe *p, struct pt_regs *regs) { int cpu = smp_processor_id(); @@ -265,6 +268,13 @@ void prepare_singlestep (struct kprobe *p, struct pt_regs *regs) } EXPORT_SYMBOL_GPL(prepare_singlestep); +/** + * @brief Saves previous kprobe. + * + * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe. + * @param p_run Pointer to kprobe. + * @return Void. + */ void save_previous_kprobe (struct kprobe_ctlblk *kcb, struct kprobe *cur_p) { if (kcb->prev_kprobe.kp != NULL) @@ -280,6 +290,12 @@ void save_previous_kprobe (struct kprobe_ctlblk *kcb, struct kprobe *cur_p) } +/** + * @brief Restores previous kprobe. + * + * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe. + * @return Void. + */ void restore_previous_kprobe (struct kprobe_ctlblk *kcb) { __get_cpu_var(swap_current_kprobe) = kcb->prev_kprobe.kp; @@ -288,6 +304,14 @@ void restore_previous_kprobe (struct kprobe_ctlblk *kcb) kcb->prev_kprobe.status = 0; } +/** + * @brief Sets currently running kprobe. + * + * @param p Pointer to currently running kprobe. + * @param regs Pointer to CPU registers data. + * @param kcb Pointer to kprobe_ctlblk. + * @return Void. + */ void set_current_kprobe (struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { __get_cpu_var(swap_current_kprobe) = p; @@ -297,6 +321,12 @@ void set_current_kprobe (struct kprobe *p, struct pt_regs *regs, struct kprobe_c kcb->kprobe_saved_eflags &= ~IF_MASK; } +/** + * @brief Kprobe handler. + * + * @param regs Pointer to CPU register data. + * @return 1 on success. + */ int kprobe_handler (struct pt_regs *regs) { struct kprobe *p = 0; @@ -452,6 +482,13 @@ no_kprobe: return ret; } +/** + * @brief Probe pre handler. + * + * @param p Pointer to fired kprobe. + * @param regs Pointer to CPU registers data. + * @return 0. + */ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of (p, struct jprobe, kp); @@ -487,8 +524,18 @@ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) return 1; } +/** + * @brief Jprobe return end. + * + * @return Void. + */ void swap_jprobe_return_end(void); +/** + * @brief Jprobe return code. + * + * @return Void. + */ void swap_jprobe_return(void) { struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk(); @@ -763,6 +810,13 @@ static struct notifier_block kprobe_exceptions_nb = { .priority = INT_MAX }; +/** + * @brief Longjump break handler. + * + * @param p Pointer to fired kprobe. + * @param regs Pointer to CPU registers data. + * @return 0 on success. + */ int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk(); @@ -794,12 +848,24 @@ int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) return 0; } +/** + * @brief Arms kprobe. + * + * @param p Pointer to target kprobe. + * @return Void. + */ void swap_arch_arm_kprobe(struct kprobe *p) { swap_text_poke(p->addr, ((unsigned char[]){BREAKPOINT_INSTRUCTION}), 1); } +/** + * @brief Disarms kprobe. + * + * @param p Pointer to target kprobe. + * @return Void. + */ void swap_arch_disarm_kprobe(struct kprobe *p) { swap_text_poke(p->addr, &p->opcode, 1); @@ -810,6 +876,14 @@ static __used void *trampoline_probe_handler_x86(struct pt_regs *regs) return (void *)trampoline_probe_handler(NULL, regs); } +/** + * @brief Prepares kretprobes, saves ret address, makes function return to + * trampoline. + * + * @param ri Pointer to kretprobe_instance. + * @param regs Pointer to CPU registers data. + * @return Void. + */ void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { @@ -830,6 +904,11 @@ void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri, *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline; } +/** + * @brief Initializes x86 module deps. + * + * @return 0 on success, negative error code on error. + */ int arch_init_module_deps() { const char *sym; @@ -860,11 +939,21 @@ not_found: return -ESRCH; } +/** + * @brief Initializes kprobes module for ARM arch. + * + * @return 0 on success, error code on error. + */ int swap_arch_init_kprobes(void) { return register_die_notifier (&kprobe_exceptions_nb); } +/** + * @brief Uninitializes kprobe module. + * + * @return Void. + */ void swap_arch_exit_kprobes(void) { unregister_die_notifier (&kprobe_exceptions_nb); diff --git a/kprobe/arch/asm-x86/swap_kprobes.h b/kprobe/arch/asm-x86/swap_kprobes.h index 1cf5a77..c7b0693 100644 --- a/kprobe/arch/asm-x86/swap_kprobes.h +++ b/kprobe/arch/asm-x86/swap_kprobes.h @@ -1,30 +1,10 @@ -#ifndef _SWAP_ASM_X86_KPROBES_H -#define _SWAP_ASM_X86_KPROBES_H - -/* - * Kernel Probes (KProbes) - * include/linux/kprobes.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. +/** + * @file kprobe/arch/asm-x86/swap_kprobes.h + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts * - * Copyright (C) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/arch/asm-x86/swap_kprobes.c + * @section LICENSE * * 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 @@ -40,18 +20,26 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * + * Copyright (C) IBM Corporation, 2002, 2004 * Copyright (C) Samsung Electronics, 2006-2010 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * - + * Arch-dependent kprobes interface for x86 arch. */ +#ifndef _SWAP_ASM_X86_KPROBES_H +#define _SWAP_ASM_X86_KPROBES_H + + #include #include +/** + * @brief Opcode type. + */ typedef u8 kprobe_opcode_t; #define BREAKPOINT_INSTRUCTION 0xcc @@ -177,12 +165,27 @@ static inline int swap_fp_backtrace(struct task_struct *task, return i; } +/** + * @struct prev_kprobe + * @brief Stores previous kprobe. + * @var prev_kprobe::kp + * Pointer to kprobe struct. + * @var prev_kprobe::status + * Kprobe status. + */ struct prev_kprobe { struct kprobe *kp; unsigned long status; }; -/* per-cpu kprobe control block */ +/** + * @struct kprobe_ctlblk + * @brief Per-cpu kprobe control block. + * @var kprobe_ctlblk::kprobe_status + * Kprobe status. + * @var kprobe_ctlblk::prev_kprobe + * Previous kprobe. + */ struct kprobe_ctlblk { unsigned long kprobe_status; struct prev_kprobe prev_kprobe; @@ -194,17 +197,23 @@ struct kprobe_ctlblk { }; -/* Architecture specific copy of original instruction */ +/** + * @struct arch_specific_insn + * @brief Architecture specific copy of original instruction. + * @var arch_specific_insn::insn + * Copy of the original instruction. + * @var arch_specific_insn::boostable + * If this flag is not 0, this kprobe can be boost when its + * post_handler and break_handler is not set. + */ struct arch_specific_insn { - /* copy of the original instruction */ kprobe_opcode_t *insn; - /* - * If this flag is not 0, this kprobe can be boost when its - * post_handler and break_handler is not set. - */ int boostable; }; +/** + * @brief Entry point. + */ typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); int arch_init_module_deps(void); diff --git a/kprobe/swap_kdebug.h b/kprobe/swap_kdebug.h index 8c7b3ff..4e76cb9 100644 --- a/kprobe/swap_kdebug.h +++ b/kprobe/swap_kdebug.h @@ -1,9 +1,10 @@ -#ifndef _SWAP_KPROBE_DEBUG_H -#define _SWAP_KPROBE_DEBUG_H - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_kdebug.h +/** + * @file kprobe/swap_kdebug.h + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * + * @section LICENSE * * 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 @@ -19,13 +20,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * * Copyright (C) Samsung Electronics, 2006-2010 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * -*/ + * Header for debug purposes. + */ + + +#ifndef _SWAP_KPROBE_DEBUG_H +#define _SWAP_KPROBE_DEBUG_H //#define _DEBUG diff --git a/kprobe/swap_kprobes.c b/kprobe/swap_kprobes.c index ef545a6..b5983e4 100644 --- a/kprobe/swap_kprobes.c +++ b/kprobe/swap_kprobes.c @@ -1,27 +1,11 @@ -/* - * Kernel Probes (KProbes) - * kernel/kprobes.c - * - * 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. +/** + * kprobe/swap_kprobes.c + * @author Ekaterina Gorelkina : initial implementation for ARM and MIPS + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts * - * Copyright (C) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_kprobes.h + * @section LICENSE * * 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 @@ -37,16 +21,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * + * Copyright (C) IBM Corporation, 2002, 2004 * Copyright (C) Samsung Electronics, 2006-2010 * - * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM and MIPS - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * + * SWAP kprobe implementation. Dynamic kernel functions instrumentation. */ - #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #include @@ -65,13 +49,21 @@ #include "swap_kprobes.h" #include "swap_kprobes_deps.h" - +/** + * @var sched_addr + * @brief Scheduler address. + */ unsigned long sched_addr; static unsigned long exit_addr; static unsigned long do_group_exit_addr; static unsigned long sys_exit_group_addr; static unsigned long sys_exit_addr; +/** + * @var sm + * @brief Current slot manager. Slots are the places where trampolines are + * located. + */ struct slot_manager sm; DEFINE_PER_CPU(struct kprobe *, swap_current_kprobe) = NULL; @@ -83,6 +75,10 @@ static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; +/** + * @var kprobe_count + * @brief Count of kprobes. + */ atomic_t kprobe_count; EXPORT_SYMBOL_GPL(kprobe_count); @@ -159,17 +155,31 @@ static inline void reset_kprobe_instance(void) __get_cpu_var(kprobe_instance) = NULL; } -/* swap_kprobe_running() will just return the current_kprobe on this CPU */ +/** + * @brief Gets the current kprobe on this CPU. + * + * @return Pointer to the current kprobe. + */ struct kprobe *swap_kprobe_running(void) { return __get_cpu_var(swap_current_kprobe); } +/** + * @brief Sets the current kprobe to NULL. + * + * @return Void. + */ void swap_reset_current_kprobe(void) { __get_cpu_var(swap_current_kprobe) = NULL; } +/** + * @brief Gets kprobe_ctlblk for the current CPU. + * + * @return Current CPU struct kprobe_ctlblk. + */ struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void) { return &__get_cpu_var(kprobe_ctlblk); @@ -181,6 +191,13 @@ struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void) * OR * - with preemption disabled - from arch/xxx/kernel/kprobes.c */ + +/** + * @brief Gets kprobe. + * + * @param addr Probe address. + * @return Kprobe for addr. + */ struct kprobe *swap_get_kprobe(void *addr) { struct hlist_head *head; @@ -265,7 +282,12 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) return ret; } -/* Walks the list and increments nmissed count for multiprobe case */ +/** + * @brief Walks the list and increments nmissed count for multiprobe case. + * + * @param p Pointer to the missed kprobe. + * @return Void. + */ void swap_kprobes_inc_nmissed_count(struct kprobe *p) { struct kprobe *kp; @@ -495,6 +517,12 @@ static void remove_kprobe(struct kprobe *p) swap_slot_free(&sm, p->ainsn.insn); } +/** + * @brief Registers kprobe. + * + * @param p Pointer to the target kprobe. + * @return 0 on success, error code on error. + */ int swap_register_kprobe(struct kprobe *p) { struct kprobe *old_p; @@ -581,6 +609,12 @@ static void swap_unregister_valid_kprobe(struct kprobe *p, struct kprobe *old_p) p->addr = NULL; } +/** + * @brief Unregistes kprobe. + * + * @param kp Pointer to the target kprobe. + * @return Void. + */ void swap_unregister_kprobe(struct kprobe *kp) { struct kprobe *old_p, *list_p; @@ -602,6 +636,12 @@ unreg_valid_kprobe: } EXPORT_SYMBOL_GPL(swap_unregister_kprobe); +/** + * @brief Registers jprobe. + * + * @param jp Pointer to the target jprobe. + * @return swap_register_kprobe result. + */ int swap_register_jprobe(struct jprobe *jp) { /* Todo: Verify probepoint is a function entry point */ @@ -612,6 +652,12 @@ int swap_register_jprobe(struct jprobe *jp) } EXPORT_SYMBOL_GPL(swap_register_jprobe); +/** + * @brief Unregisters jprobe. + * + * @param jp Pointer to the target jprobe. + * @return Void. + */ void swap_unregister_jprobe(struct jprobe *jp) { swap_unregister_kprobe(&jp->kp); @@ -652,6 +698,13 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) return 0; } +/** + * @brief Trampoline probe handler. + * + * @param p Pointer to the fired kprobe. + * @param regs Pointer to CPU registers data. + * @return orig_ret_address + */ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; @@ -776,6 +829,12 @@ static int alloc_nodes_kretprobe(struct kretprobe *rp) return 0; } +/** + * @brief Registers kretprobes. + * + * @param rp Pointer to the target kretprobe. + * @return 0 on success, error code on error. + */ int swap_register_kretprobe(struct kretprobe *rp) { int ret = 0; @@ -848,6 +907,14 @@ static void swap_disarm_krp(struct kretprobe *rp) } } +/** + * @brief Kretprobes unregister top. Unregisters kprobes. + * + * @param rps Pointer to the array of pointers to the target kretprobes. + * @param size Size of rps array. + * @param rp_disarm Disarm flag. If set kretprobe is disarmed. + * @return Void. + */ void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size, int rp_disarm) { @@ -864,12 +931,25 @@ void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size, } EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_top); +/** + * @brief swap_unregister_kretprobes_top wrapper for a single kretprobe. + * + * @param rp Pointer to the target kretprobe. + * @param rp_disarm Disarm flag. + * @return Void. + */ void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm) { swap_unregister_kretprobes_top(&rp, 1, rp_disarm); } EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_top); +/** + * @brief Kretprobe unregister bottom. Here is kretprobe memory is released. + * + * @param rp Pointer to the target kretprobe. + * @return Void. + */ void swap_unregister_kretprobe_bottom(struct kretprobe *rp) { unsigned long flags; @@ -886,6 +966,13 @@ void swap_unregister_kretprobe_bottom(struct kretprobe *rp) } EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_bottom); +/** + * @brief swap_unregister_kretprobe_bottom wrapper for several kretprobes. + * + * @param rps Pointer to the array of the target kretprobes pointers. + * @param size Size of rps array. + * @return Void. + */ void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size) { const size_t end = ((size_t) 0) - 1; @@ -895,6 +982,13 @@ void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size) } EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_bottom); +/** + * @brief Unregisters kretprobes. + * + * @param rpp Pointer to the array of the target kretprobes pointers. + * @param size Size of rpp array. + * @return Void. + */ void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size) { swap_unregister_kretprobes_top(rpp, size, 1); @@ -906,6 +1000,12 @@ void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size) } EXPORT_SYMBOL_GPL(swap_unregister_kretprobes); +/** + * @brief swap_unregister_kretprobes wrapper for a single kretprobe. + * + * @param rp Pointer to the target kretprobe. + * @return Void. + */ void swap_unregister_kretprobe(struct kretprobe *rp) { swap_unregister_kretprobes(&rp, 1); diff --git a/kprobe/swap_kprobes.h b/kprobe/swap_kprobes.h index 5d6aea5..4e99c60 100644 --- a/kprobe/swap_kprobes.h +++ b/kprobe/swap_kprobes.h @@ -1,30 +1,11 @@ -#ifndef _SWAP_KPROBES_H -#define _SWAP_KPROBES_H - -/* - * Kernel Probes (KProbes) - * include/linux/kprobes.h +/** + * @file kprobe/swap_kprobes.h + * @author Ekaterina Gorelkina : initial implementation for ARM and MIPS + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts * - * 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) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_kprobes.h + * @section LICENSE * * 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 @@ -40,16 +21,20 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * + * Copyright (C) IBM Corporation, 2002, 2004 * Copyright (C) Samsung Electronics, 2006-2010 * - * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM and MIPS - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * + * SWAP kprobe interface definition. */ +#ifndef _SWAP_KPROBES_H +#define _SWAP_KPROBES_H + #include // LINUX_VERSION_CODE, KERNEL_VERSION() #include #include @@ -69,81 +54,118 @@ /* kprobe_status settings */ +/** Kprobe hit active */ #define KPROBE_HIT_ACTIVE 0x00000001 +/** Kprobe hit ss */ #define KPROBE_HIT_SS 0x00000002 +/** Kprobe reenter */ #define KPROBE_REENTER 0x00000004 +/** Kprobe hit ss done */ #define KPROBE_HIT_SSDONE 0x00000008 +/** High word */ #define HIWORD(x) (((x) & 0xFFFF0000) >> 16) +/** Low word */ #define LOWORD(x) ((x) & 0x0000FFFF) +/** Invalid value */ #define INVALID_VALUE 0xFFFFFFFF +/** Invalid pointer */ #define INVALID_POINTER (void*)INVALID_VALUE +/** Jprobe entry */ #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry +/** Retprobe stack depth */ #define RETPROBE_STACK_DEPTH 64 struct kprobe; struct pt_regs; struct kretprobe; struct kretprobe_instance; + +/** + * @brief Kprobe pre-handler pointer. + */ typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *); + +/** + * @brief Kprobe break handler pointer. + */ typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *); + +/** + * @brief Kprobe post handler pointer. + */ typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *, unsigned long flags); + +/** + * @brief Kprobe fault handler pointer. + */ typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *, int trapnr); + +/** + * @brief Kretprobe handler pointer. + */ typedef int (*kretprobe_handler_t) (struct kretprobe_instance *, struct pt_regs *); +/** + * @struct kprobe + * @brief Main kprobe struct. + */ struct kprobe { - struct hlist_node hlist; - /*list of probes to search by instruction slot*/ + struct hlist_node hlist; /**< Hash list.*/ + /** List of probes to search by instruction slot.*/ struct hlist_node is_hlist; - /* list of kprobes for multi-handler support */ + /** List of kprobes for multi-handler support.*/ struct list_head list; - /* Indicates that the corresponding module has been ref counted */ + /** Indicates that the corresponding module has been ref counted.*/ unsigned int mod_refcounted; - /*count the number of times this probe was temporarily disarmed */ + /** Count the number of times this probe was temporarily disarmed.*/ unsigned long nmissed; - /* location of the probe point */ + /** Location of the probe point. */ kprobe_opcode_t *addr; - /* Allow user to indicate symbol name of the probe point */ + /** Allow user to indicate symbol name of the probe point.*/ char *symbol_name; - /* Offset into the symbol */ + /** Offset into the symbol.*/ unsigned int offset; - /* Called before addr is executed. */ + /** Called before addr is executed.*/ kprobe_pre_handler_t pre_handler; - /* Called after addr is executed, unless... */ + /** Called after addr is executed, unless...*/ kprobe_post_handler_t post_handler; - /* ... called if executing addr causes a fault (eg. page fault). - * Return 1 if it handled fault, otherwise kernel will see it. */ + /** ... called if executing addr causes a fault (eg. page fault).*/ kprobe_fault_handler_t fault_handler; - /* ... called if breakpoint trap occurs in probe handler. - * Return 1 if it handled break, otherwise kernel will see it. */ + /** Return 1 if it handled fault, otherwise kernel will see it.*/ kprobe_break_handler_t break_handler; - /* Saved opcode (which has been replaced with breakpoint) */ + /** Saved opcode (which has been replaced with breakpoint).*/ kprobe_opcode_t opcode; - /* copy of the original instruction */ + /** Copy of the original instruction.*/ struct arch_specific_insn ainsn; - // override single-step target address, - // may be used to redirect control-flow to arbitrary address after probe point - // without invocation of original instruction; - // useful for functions replacement - // if jprobe.entry should return address of function or NULL - // if original function should be called - // not supported for X86, not tested for MIPS + /** Override single-step target address, may be used to redirect + * control-flow to arbitrary address after probe point without + * invocation of original instruction; useful for functions + * replacement. If jprobe.entry should return address of function or + * NULL if original function should be called. + * Not supported for X86, not tested for MIPS. */ kprobe_opcode_t *ss_addr[NR_CPUS]; - // safe/unsafe to use probe #ifdef CONFIG_ARM + /** Safe/unsafe to use probe on ARM.*/ unsigned safe_arm:1; + /** Safe/unsafe to use probe on Thumb.*/ unsigned safe_thumb:1; #endif }; +/** + * @brief Kprobe pre-entry handler pointer. + */ typedef unsigned long (*kprobe_pre_entry_handler_t) (void *priv_arg, struct pt_regs * regs); -/* - * Special probe type that uses setjmp-longjmp type tricks to resume + +/** + * @struct jprobe + * @brief Special probe type that uses setjmp-longjmp type tricks to resume * execution at a specified entry with a matching prototype corresponding * to the probed function - a trick to enable arguments to become * accessible seamlessly by probe handling logic. @@ -151,23 +173,28 @@ typedef unsigned long (*kprobe_pre_entry_handler_t) (void *priv_arg, struct pt_r * Because of the way compilers allocate stack space for local variables * etc upfront, regardless of sub-scopes within a function, this mirroring * principle currently works only for probes placed on function entry points. - */ + */ struct jprobe { - struct kprobe kp; - // probe handling code to jump to - kprobe_opcode_t *entry; - // handler whichw willb bec called before 'entry' + struct kprobe kp; /**< This probes kprobe.*/ + kprobe_opcode_t *entry; /**< Probe handling code to jump to.*/ + /** Handler which will be called before 'entry'. */ kprobe_pre_entry_handler_t pre_entry; - void *priv_arg; + void *priv_arg; /**< Private args.*/ }; + +/** + * @struct jprobe_instance + * @brief Jprobe instance struct. + */ struct jprobe_instance { // either on free list or used list - struct hlist_node uflist; - struct hlist_node hlist; - struct jprobe *jp; + struct hlist_node uflist; /**< Jprobes hash list. */ + struct hlist_node hlist; /**< Jprobes hash list. */ + struct jprobe *jp; /**< Pointer to the target jprobe. */ + /** Pointer to the target task_struct. */ struct task_struct *task; }; @@ -175,45 +202,49 @@ struct jprobe_instance -/* - * Function-return probe - - * Note: - * User needs to provide a handler function, and initialize maxactive. - * maxactive - The maximum number of instances of the probed function that - * can be active concurrently. - * nmissed - tracks the number of times the probed function's return was - * ignored, due to maxactive being too low. - * +/** + * @struct kretprobe + * @brief Function-return probe + * Note: User needs to provide a handler function, and initialize maxactive. */ struct kretprobe { - struct kprobe kp; - kretprobe_handler_t handler; - kretprobe_handler_t entry_handler; + struct kprobe kp; /**< Kprobe of this kretprobe.*/ + kretprobe_handler_t handler; /**< Handler of this kretprobe.*/ + kretprobe_handler_t entry_handler; /**< Entry handler of this kretprobe.*/ + /** The maximum number of instances of the probed function that can be + * active concurrently. */ int maxactive; + /** Tracks the number of times the probed function's return was ignored, + * due to maxactive being too low. */ int nmissed; - size_t data_size; + size_t data_size; /**< Size of the data. */ + /** List of this probe's free_instances. */ struct hlist_head free_instances; + /** List of this probe's used_instances. */ struct hlist_head used_instances; #ifdef CONFIG_ARM - // probe with noreturn (bl,blx) - unsigned arm_noret:1; - unsigned thumb_noret:1; + unsigned arm_noret:1; /**< No-return flag for ARM.*/ + unsigned thumb_noret:1; /**< No-return flag for Thumb.*/ #endif }; +/** + * @struct kretprobe_instance + * @brief Instance of kretprobe. + */ struct kretprobe_instance { // either on free list or used list - struct hlist_node uflist; - struct hlist_node hlist; - struct kretprobe *rp; - unsigned long *ret_addr; - unsigned long *sp; - struct task_struct *task; - char data[0]; + struct hlist_node uflist; /**< Kretprobe hash list.*/ + struct hlist_node hlist; /**< Kretprobe hash list.*/ + struct kretprobe *rp; /**< Pointer to this instance's kretprobe.*/ + unsigned long *ret_addr; /**< Return address.*/ + unsigned long *sp; /**< Stack pointer.*/ + struct task_struct *task; /**< Pointer to the target task_struct.*/ + char data[0]; /**< Pointer to data.*/ }; diff --git a/kprobe/swap_kprobes_deps.c b/kprobe/swap_kprobes_deps.c index b199a48..6334434 100644 --- a/kprobe/swap_kprobes_deps.c +++ b/kprobe/swap_kprobes_deps.c @@ -1,6 +1,10 @@ -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_kprobes_deps.h +/** + * kprobe/swap_kprobes_deps.c + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * + * @section LICENSE * * 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 @@ -16,12 +20,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * * Copyright (C) Samsung Electronics, 2006-2010 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * + * SWAP kprobe kernel-dependent dependencies. */ #include @@ -304,7 +309,11 @@ IMP_MOD_DEP_WRAPPER (vm_normal_page, vma, addr, pte) - +/** + * @brief Initializes module dependencies. + * + * @return 0. + */ int init_module_dependencies(void) { @@ -432,6 +441,19 @@ static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long add #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +/** + * @brief Gets user pages uprobe. + * + * @param tsk Pointer to the task_struct. + * @param mm Pointer to the mm_struct. + * @param start Starting address. + * @param nr_pages Pages number. + * @param gup_flags Flags. + * @param pages Pointer to the array of pointers to the target page structs. + * @param vmas Pointer to the array of pointers to the target vm_area_struct. + * @param nonblocking Pointer to int. + * @return negative error code on error, positive result otherwise. + */ long __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, @@ -1015,6 +1037,19 @@ static int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm #endif #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */ +/** + * @brief Gets user pages uprobe. + * + * @param tsk Pointer to the task_struct. + * @param mm Pointer to the mm_struct. + * @param start Starting address. + * @param len Length. + * @param write Write flag. + * @param force Force flag. + * @param pages Pointer to the array of pointers to the target page structs. + * @param vmas Pointer to the array of pointers to the target vm_area_struct. + * @return negative error code on error, positive result otherwise. + */ int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) @@ -1115,6 +1150,16 @@ static void write_data_current(unsigned long addr, void *buf, int len) } #endif +/** + * @brief Read-write task memory. + * + * @param tsk Pointer to the target task task_struct. + * @param addr Address to read-write. + * @param buf Pointer to buffer where to put-get data. + * @param len Buffer length. + * @param write Write flag. If 0 - reading, if 1 - writing. + * @return Read-write size, error code on error. + */ int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) { struct mm_struct *mm; @@ -1193,6 +1238,12 @@ int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr, void * return buf - old_buf; } +/** + * @brief Page present. + * + * @param mm Pointer to the target mm_struct. + * @param address Address. + */ int page_present (struct mm_struct *mm, unsigned long address) { pgd_t *pgd; diff --git a/kprobe/swap_kprobes_deps.h b/kprobe/swap_kprobes_deps.h index 06a57e6..70824de 100644 --- a/kprobe/swap_kprobes_deps.h +++ b/kprobe/swap_kprobes_deps.h @@ -1,9 +1,10 @@ -#ifndef _SWAP_KPROBES_DEPS_H -#define _SWAP_KPROBES_DEPS_H - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_kprobes_deps.h +/** + * @file kprobe/swap_kprobes_deps.h + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * + * @section LICENSE * * 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 @@ -19,14 +20,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * * Copyright (C) Samsung Electronics, 2006-2010 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * @section DESCRIPTION * + * SWAP kprobe kernel-dependent dependencies. */ +#ifndef _SWAP_KPROBES_DEPS_H +#define _SWAP_KPROBES_DEPS_H + #include // LINUX_VERSION_CODE, KERNEL_VERSION() #include #include diff --git a/kprobe/swap_slots.c b/kprobe/swap_slots.c index a54ec5d..2fcbb75 100644 --- a/kprobe/swap_slots.c +++ b/kprobe/swap_slots.c @@ -1,27 +1,11 @@ -/* - * Kernel Probes (KProbes) - * kernel/kprobes.c +/** + * kprobe/swap_slots.c + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Vyacheslav Cherkashin new memory allocator for slots * - * 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) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_slots.c + * @section LICENSE * * 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 @@ -37,12 +21,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * + * Copyright (C) IBM Corporation, 2002, 2004 * Copyright (C) Samsung Electronics, 2006-2012 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts - * 2012-2013 Vyacheslav Cherkashin new memory allocator for slots + * @section DESCRIPTION + * + * SWAP slots implementation. */ @@ -55,6 +41,22 @@ #include "swap_kprobes_deps.h" +/** + * @struct chunk + * @brief Chunk of memory for trampolines. + * @var chunk::data + * Chunk data. + * @var chunk::first_available + * Index of the first available block. + * @var chunk::count_available + * Count of the blocks. + * @var chunk::lock + * Chunk's lock. + * @var chunk::size + * Count of the blocks in chunk. + * @var chunk::index + * Pointer to allocated memory. + */ struct chunk { unsigned long *data; unsigned long first_available; @@ -65,6 +67,14 @@ struct chunk { unsigned long *index; }; +/** + * @struct fixed_alloc + * @brief Item of fixed allocs list. + * @var fixed_alloc::hlist + * Fixed alloc hash list node. + * @var fixed_alloc::chunk + * Chunk. + */ struct fixed_alloc { struct hlist_node hlist; @@ -167,6 +177,12 @@ static void free_fixed_alloc(struct slot_manager *sm, struct fixed_alloc *fa) } +/** + * @brief Allocates slot for slot manager. + * + * @param[in,out] sm Slot manager that should be filled. + * @return Pointer to allocated slot. + */ void *swap_slot_alloc(struct slot_manager *sm) { void *free_slot; @@ -190,6 +206,13 @@ void *swap_slot_alloc(struct slot_manager *sm) } EXPORT_SYMBOL_GPL(swap_slot_alloc); +/** + * @brief Releases allocated slot. + * + * @param sm Pointer to the target slot manager. + * @param slot Pointer to the target slot. + * @return Void. + */ void swap_slot_free(struct slot_manager *sm, void *slot) { struct fixed_alloc *fa; diff --git a/kprobe/swap_slots.h b/kprobe/swap_slots.h index 3e48059..129a439 100644 --- a/kprobe/swap_slots.h +++ b/kprobe/swap_slots.h @@ -1,30 +1,11 @@ -#ifndef _SWAP_SLOTS_H -#define _SWAP_SLOTS_H - -/* - * Kernel Probes (KProbes) - * include/linux/kprobes.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. +/** + * @file kprobe/swap_slots.h + * @author Alexey Gerenkov User-Space Probes initial implementation; + * Support x86/ARM/MIPS for both user and kernel spaces. + * @author Ekaterina Gorelkina : redesign module for separating core and arch parts + * @author Vyacheslav Cherkashin new memory allocator for slots * - * 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) IBM Corporation, 2002, 2004 - */ - -/* - * Dynamic Binary Instrumentation Module based on KProbes - * modules/kprobe/swap_slots.h + * @section LICENSE * * 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 @@ -40,16 +21,35 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * @section COPYRIGHT + * + * Copyright (C) IBM Corporation, 2002, 2004 * Copyright (C) Samsung Electronics, 2006-2010 * - * 2008-2009 Alexey Gerenkov User-Space - * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts - * 2012-2013 Vyacheslav Cherkashin new memory allocator for slots + * @section DESCRIPTION + * + * SWAP slots interface declaration. */ +#ifndef _SWAP_SLOTS_H +#define _SWAP_SLOTS_H + #include +/** + * @struct slot_manager + * @brief Manage slots. + * @var slot_manager::slot_size + * Size of the slot. + * @var slot_manager::alloc + * Memory allocation callback. + * @var slot_manager::free + * Memory release callback. + * @var slot_manager::page_list + * List of pages. + * @var slot_manager::data + * Slot manager data. task_struct pointer usually stored here. + */ struct slot_manager { unsigned long slot_size; /* FIXME: allocated in long (4 byte) */ void *(*alloc)(struct slot_manager *sm); -- 2.7.4