mirror of
https://github.com/gatieme/LDD-LinuxDeviceDrivers.git
synced 2026-09-24 14:13:54 +08:00
kernel debug tools...
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile for the LDD-LinuxDeviceDrivers.
|
||||
#
|
||||
# Author: gatieme
|
||||
# Create: 2016-07-29 15:50:46
|
||||
# Last modified: 2016-07-29 16:10:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
ROOT=..
|
||||
#PLATFORM=$(shell $(ROOT)/systype.sh)
|
||||
#include $(ROOT)/Make.defines.$(PLATFORM)
|
||||
|
||||
# my driver description
|
||||
DRIVER_VERSION := "1.0.0"
|
||||
DRIVER_AUTHOR := "Gatieme @ AderStep Inc..."
|
||||
DRIVER_DESC := "Linux input module for Elo MultiTouch(MT) devices"
|
||||
DRIVER_LICENSE := "Dual BSD/GPL"
|
||||
|
||||
|
||||
MODULE_NAME := test
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
#CFG_FLAGS += -O2 -I./
|
||||
#EXTRA_CFLAGS += $(C_FLAGS) $(CFG_INC) $(CFG_INC)
|
||||
|
||||
|
||||
|
||||
obj-m := $(MODULE_NAME).o #print_vmarea.o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
modules_install:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules_install
|
||||
|
||||
|
||||
|
||||
insmod:
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
reinsmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
github:
|
||||
cd $(ROOT) && make github
|
||||
|
||||
rmmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
|
||||
test :
|
||||
sudo ../injector/memInjector -l stack -m random -t word_0 --time 1 --timeout 3 -p 1
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
|
||||
.PHNOY:
|
||||
modules modules_install clean
|
||||
|
||||
|
||||
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile for the LDD-LinuxDeviceDrivers.
|
||||
#
|
||||
# Author: gatieme
|
||||
# Create: 2016-07-29 15:50:46
|
||||
# Last modified: 2016-07-29 16:10:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
ROOT=..
|
||||
#PLATFORM=$(shell $(ROOT)/systype.sh)
|
||||
#include $(ROOT)/Make.defines.$(PLATFORM)
|
||||
|
||||
# my driver description
|
||||
DRIVER_VERSION := "1.0.0"
|
||||
DRIVER_AUTHOR := "Gatieme @ AderStep Inc..."
|
||||
DRIVER_DESC := "Linux input module for Elo MultiTouch(MT) devices"
|
||||
DRIVER_LICENSE := "Dual BSD/GPL"
|
||||
|
||||
|
||||
MODULE_NAME := data_breakpoint
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
#CFG_FLAGS += -O2 -I./
|
||||
#EXTRA_CFLAGS += $(C_FLAGS) $(CFG_INC) $(CFG_INC)
|
||||
|
||||
|
||||
|
||||
obj-m := $(MODULE_NAME).o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
modules_install:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules_install
|
||||
|
||||
|
||||
|
||||
insmod:
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
reinsmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
github:
|
||||
cd $(ROOT) && make github
|
||||
|
||||
rmmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
|
||||
test :
|
||||
sudo ../injector/memInjector -l stack -m random -t word_0 --time 1 --timeout 3 -p 1
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
|
||||
.PHNOY:
|
||||
modules modules_install clean
|
||||
|
||||
|
||||
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* data_breakpoint.c - Sample HW Breakpoint file to watch kernel data address
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* usage: insmod data_breakpoint.ko ksym=<ksym_name>
|
||||
*
|
||||
* This file is a kernel module that places a breakpoint over ksym_name kernel
|
||||
* variable using Hardware Breakpoint register. The corresponding handler which
|
||||
* prints a backtrace is invoked every time a write operation is performed on
|
||||
* that variable.
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2009
|
||||
*
|
||||
* Author: K.Prasad <prasad@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
// http://lxr.free-electrons.com/source/samples/hw_breakpoint/data_breakpoint.c
|
||||
#include <linux/module.h> /* Needed by all modules */
|
||||
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
||||
#include <linux/init.h> /* Needed for the macros */
|
||||
#include <linux/kallsyms.h>
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
|
||||
struct perf_event * __percpu *sample_hbp;
|
||||
|
||||
static char ksym_name[KSYM_NAME_LEN] = "pid_max";
|
||||
module_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO);
|
||||
MODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any"
|
||||
" write operations on the kernel symbol");
|
||||
|
||||
static void sample_hbp_handler(struct perf_event *bp,
|
||||
struct perf_sample_data *data,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
printk(KERN_INFO "%s value is changed\n", ksym_name);
|
||||
dump_stack();
|
||||
printk(KERN_INFO "Dump stack from sample_hbp_handler\n");
|
||||
}
|
||||
|
||||
static int __init hw_break_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
struct perf_event_attr attr;
|
||||
|
||||
hw_breakpoint_init(&attr);
|
||||
attr.bp_addr = kallsyms_lookup_name(ksym_name);
|
||||
attr.bp_len = HW_BREAKPOINT_LEN_4;
|
||||
attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
|
||||
|
||||
sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL);
|
||||
if (IS_ERR((void __force *)sample_hbp)) {
|
||||
ret = PTR_ERR((void __force *)sample_hbp);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "HW Breakpoint for %s write installed\n", ksym_name);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
printk(KERN_INFO "Breakpoint registration failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit hw_break_module_exit(void)
|
||||
{
|
||||
unregister_wide_hw_breakpoint(sample_hbp);
|
||||
printk(KERN_INFO "HW Breakpoint for %s write uninstalled\n", ksym_name);
|
||||
}
|
||||
|
||||
module_init(hw_break_module_init);
|
||||
module_exit(hw_break_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("K.Prasad");
|
||||
MODULE_DESCRIPTION("ksym breakpoint");
|
||||
@@ -0,0 +1,78 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile for the LDD-LinuxDeviceDrivers.
|
||||
#
|
||||
# Author: gatieme
|
||||
# Create: 2016-07-29 15:50:46
|
||||
# Last modified: 2016-07-29 16:10:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
ROOT=..
|
||||
#PLATFORM=$(shell $(ROOT)/systype.sh)
|
||||
#include $(ROOT)/Make.defines.$(PLATFORM)
|
||||
|
||||
# my driver description
|
||||
DRIVER_VERSION := "1.0.0"
|
||||
DRIVER_AUTHOR := "Gatieme @ AderStep Inc..."
|
||||
DRIVER_DESC := "Linux input module for Elo MultiTouch(MT) devices"
|
||||
DRIVER_LICENSE := "Dual BSD/GPL"
|
||||
|
||||
|
||||
MODULE_NAME := jprobe-exam
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
#CFG_FLAGS += -O2 -I./
|
||||
#EXTRA_CFLAGS += $(C_FLAGS) $(CFG_INC) $(CFG_INC)
|
||||
|
||||
|
||||
|
||||
obj-m := $(MODULE_NAME).o #print_vmarea.o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
modules_install:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules_install
|
||||
|
||||
|
||||
|
||||
insmod:
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
reinsmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
github:
|
||||
cd $(ROOT) && make github
|
||||
|
||||
rmmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
|
||||
test :
|
||||
sudo ../injector/memInjector -l stack -m random -t word_0 --time 1 --timeout 3 -p 1
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
|
||||
.PHNOY:
|
||||
modules modules_install clean
|
||||
|
||||
|
||||
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* jprobe-exam.c */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct jprobe jp;
|
||||
|
||||
asmlinkage long jprobe_sys_open(const char __user *filename, int flags, int mode)
|
||||
{
|
||||
int len = PATH_MAX;
|
||||
char * tmpfilename = NULL;
|
||||
|
||||
if (TASK_SIZE - (unsigned long) filename < PATH_MAX) {
|
||||
len = TASK_SIZE - (unsigned long) filename;
|
||||
}
|
||||
|
||||
tmpfilename = kmalloc(len, GFP_ATOMIC);
|
||||
if (tmpfilename == NULL) return 0;
|
||||
|
||||
if (copy_from_user(tmpfilename, filename, len)) return 0;
|
||||
|
||||
printk("process '%s' call open('%s', %d, %d)\n", current->comm, tmpfilename, flags, mode);
|
||||
jprobe_return();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
jp.entry = (kprobe_opcode_t *) jprobe_sys_open;
|
||||
jp.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("sys_open");
|
||||
if (!jp.kp.addr) {
|
||||
printk("Couldn't find the address of sys_open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = register_jprobe(&jp)) <0) {
|
||||
printk("register_jprobe failed, returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
printk("Registered a jprobe.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
unregister_jprobe(&jp);
|
||||
printk("jprobe unregistered\n");
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,78 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile for the LDD-LinuxDeviceDrivers.
|
||||
#
|
||||
# Author: gatieme
|
||||
# Create: 2016-07-29 15:50:46
|
||||
# Last modified: 2016-07-29 16:10:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
ROOT=..
|
||||
#PLATFORM=$(shell $(ROOT)/systype.sh)
|
||||
#include $(ROOT)/Make.defines.$(PLATFORM)
|
||||
|
||||
# my driver description
|
||||
DRIVER_VERSION := "1.0.0"
|
||||
DRIVER_AUTHOR := "Gatieme @ AderStep Inc..."
|
||||
DRIVER_DESC := "Linux input module for Elo MultiTouch(MT) devices"
|
||||
DRIVER_LICENSE := "Dual BSD/GPL"
|
||||
|
||||
|
||||
MODULE_NAME := kprobe-exam
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
#CFG_FLAGS += -O2 -I./
|
||||
#EXTRA_CFLAGS += $(C_FLAGS) $(CFG_INC) $(CFG_INC)
|
||||
|
||||
|
||||
|
||||
obj-m := $(MODULE_NAME).o #print_vmarea.o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
modules_install:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules_install
|
||||
|
||||
|
||||
|
||||
insmod:
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
reinsmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
sudo insmod $(MODULE_NAME).ko
|
||||
|
||||
github:
|
||||
cd $(ROOT) && make github
|
||||
|
||||
rmmod:
|
||||
sudo rmmod $(MODULE_NAME)
|
||||
|
||||
test :
|
||||
sudo ../injector/memInjector -l stack -m random -t word_0 --time 1 --timeout 3 -p 1
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
|
||||
.PHNOY:
|
||||
modules modules_install clean
|
||||
|
||||
|
||||
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
https://www.ibm.com/developerworks/cn/linux/l-cn-systemtap1/
|
||||
|
||||
|
||||
kprobe使用实例
|
||||
本文附带的包包含了三个示例模块,kprobe-exam.c是kprobes使用示例,jprobe-exam.c是jprobes使用示例,kretprobe-exam.c是kretprobes使用示例,读者可以下载该包并执行如下指令来实验这些模块:
|
||||
$ tar -jxvf kprobes-examples.tar.bz2
|
||||
$ cd kprobes-examples
|
||||
$ make
|
||||
…
|
||||
$ su -
|
||||
…
|
||||
$ insmod kprobe-example.ko
|
||||
$ dmesg
|
||||
…
|
||||
$ rmmod kprobe-example
|
||||
$ dmesg
|
||||
…
|
||||
$ insmod jprobe-example.ko
|
||||
$ cat kprobe-example.c
|
||||
$dmesg
|
||||
…
|
||||
$ rmmod jprobe-example
|
||||
$ dmesg
|
||||
…
|
||||
$ insmod kretprobe-example.ko
|
||||
$ dmesg
|
||||
…
|
||||
$ ls -Rla / > /dev/null &
|
||||
$ dmesg
|
||||
…
|
||||
$ rmmod kretprobe-example
|
||||
$ dmesg
|
||||
…
|
||||
$
|
||||
示例模块kprobe-exame.c探测schedule()函数,在探测点执行前后分别输出当前正在运行的进程、所在的CPU以及preempt_count(),当卸载该模块时将输出该模块运行时间以及发生的调度次数。这是该模块在作者系统上的输出:
|
||||
kprobe registered
|
||||
current task on CPU#1: swapper (before scheduling), preempt_count = 0
|
||||
current task on CPU#1: swapper (after scheduling), preempt_count = 0
|
||||
current task on CPU#0: insmod (before scheduling), preempt_count = 0
|
||||
current task on CPU#0: insmod (after scheduling), preempt_count = 0
|
||||
current task on CPU#1: klogd (before scheduling), preempt_count = 0
|
||||
current task on CPU#1: klogd (after scheduling), preempt_count = 0
|
||||
current task on CPU#1: klogd (before scheduling), preempt_count = 0
|
||||
current task on CPU#1: klogd (after scheduling), preempt_count = 0
|
||||
current task on CPU#1: klogd (before scheduling), preempt_count = 0
|
||||
…
|
||||
Scheduling times is 5918 during of 7655 milliseconds.
|
||||
kprobe unregistered
|
||||
示例模块jprobe-exam.c是一个jprobes探测例子,它示例了获取系统调用open的参数,但读者不要试图在实际的应用中这么使用,因为copy_from_user可能导致睡眠,而kprobe并不允许在探测点处理函数中这么做(请参看前面内容了解详细描述)。
|
||||
|
||||
这是该模块在作者系统上的输出:
|
||||
Registered a jprobe.
|
||||
process 'cat' call open('/etc/ld.so.cache', 0, 0)
|
||||
process 'cat' call open('/lib/libc.so.6', 0, -524289)
|
||||
process 'cat' call open('/usr/lib/locale/locale-archive', 32768, 1)
|
||||
process 'cat' call open('/usr/share/locale/locale.alias', 0, 438)
|
||||
process 'cat' call open('/usr/lib/locale/en_US.UTF-8/LC_CTYPE', 0, 0)
|
||||
process 'cat' call open('/usr/lib/locale/en_US.utf8/LC_CTYPE', 0, 0)
|
||||
process 'cat' call open('/usr/lib/gconv/gconv-modules.cache', 0, 0)
|
||||
process 'cat' call open('kprobe-exam.c', 32768, 0)
|
||||
…
|
||||
process 'rmmod' call open('/etc/ld.so.cache', 0, 0)
|
||||
process 'rmmod' call open('/lib/libc.so.6', 0, -524289)
|
||||
process 'rmmod' call open('/proc/modules', 0, 438)
|
||||
jprobe unregistered
|
||||
示例模块kretprobe-exam.c是一个返回探测例子,它探测系统调用open并输出返回值小于0的情况。它也有意设置maxactive为1,以便示例丢失探测运行的情况,当然,只有系统并发运行多个sys_open才可能导致这种情况,因此,读者需要有SMP的系统或者有超线程支持才能看到这种情况。如果读者比较仔细,会看到在前面的命令有”ls -Rla / > /dev/null & ,那是专门为了导致出现丢失探测运行的。
|
||||
|
||||
这是该模块在作者系统上的输出:
|
||||
Registered a return probe.
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
sys_open returns -2
|
||||
…
|
||||
kretprobe unregistered
|
||||
Missed 11 sys_open probe instances.
|
||||
回页首
|
||||
小结
|
||||
本文详细地讲解了kprobe的方方面面并给出实际的例子代码帮助读者学习和使用kprobe。本文是系列文章“Linux下的一个全新的性能测量和调式诊断工具 -- Systemtap”之一,有兴趣的读者可以阅读该系列文章之二和三。
|
||||
@@ -0,0 +1,73 @@
|
||||
/* kprobe-exam.c */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
|
||||
|
||||
static struct kprobe kp;
|
||||
static struct timeval start, end;
|
||||
static int schedule_counter = 0;
|
||||
|
||||
int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
printk("current task on CPU#%d: %s (before scheduling), preempt_count = %d\n", smp_processor_id(), current->comm, preempt_count());
|
||||
schedule_counter++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
|
||||
{
|
||||
printk("current task on CPU#%d: %s (after scheduling), preempt_count = %d\n", smp_processor_id(), current->comm, preempt_count());
|
||||
}
|
||||
|
||||
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
||||
{
|
||||
printk("A fault happened during probing.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
kp.pre_handler = handler_pre;
|
||||
kp.post_handler = handler_post;
|
||||
kp.fault_handler = handler_fault;
|
||||
kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("schedule");
|
||||
|
||||
if (kp.addr == NULL)
|
||||
{
|
||||
printk("Couldn't get the address of schedule.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = register_kprobe(&kp) < 0))
|
||||
{
|
||||
printk("register_kprobe failed, returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do_gettimeofday(&start);
|
||||
|
||||
printk("kprobe registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
unregister_kprobe(&kp);
|
||||
do_gettimeofday(&end);
|
||||
printk("Scheduling times is %d during of %ld milliseconds.\n", schedule_counter, ((end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec))/1000);
|
||||
printk("kprobe unregistered\n");
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,18 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
obj-m := kretprobe-exam.o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,48 @@
|
||||
/*kretprobe-exam.c*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kallsyms.h>
|
||||
|
||||
static struct kretprobe kretp;
|
||||
|
||||
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
|
||||
{
|
||||
// Substitute the appropriate register name for your architecture --
|
||||
// e.g., regs->rax for x86_64, regs->gpr[3] for ppc64.
|
||||
int retval = (int) regs->ax;
|
||||
if (retval < 0) {
|
||||
printk("sys_open returns %d\n", retval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
kretp.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("sys_open");
|
||||
if (!kretp.kp.addr) {
|
||||
printk("Couldn't find sys_open.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
kretp.handler = ret_handler,
|
||||
kretp.maxactive = 1;
|
||||
|
||||
if ((ret = register_kretprobe(&kretp)) < 0) {
|
||||
printk("register_kretprobe failed, returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
printk("Registered a return probe.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
unregister_kretprobe(&kretp);
|
||||
printk("kretprobe unregistered\n");
|
||||
printk("Missed %d sys_open probe instances.\n", kretp.nmissed);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
|
||||
int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
printk("current task on CPU#%d: %s (before), preempt_count = %d\n",
|
||||
smp_processor_id( ), current->comm, preempt_count( ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
|
||||
{
|
||||
printk("current task on CPU#%d: %s (after), preempt_count = %d\n",
|
||||
smp_processor_id( ), current->comm, preempt_count( ));
|
||||
}
|
||||
|
||||
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
||||
{
|
||||
printk("A fault happened during probing.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Jumper probe for do_fork.
|
||||
* Mirror principle enables access to arguments of the probed routine
|
||||
* from the probe handler.
|
||||
*/
|
||||
|
||||
/* Proxy routine having the same arguments as actual do_fork() routine */
|
||||
static long jdo_fork(unsigned long clone_flags, unsigned long stack_start,
|
||||
struct pt_regs *regs, unsigned long stack_size,
|
||||
int __user *parent_tidptr, int __user *child_tidptr)
|
||||
{
|
||||
printk(KERN_INFO "jprobe: clone_flags = 0x%lx, "
|
||||
"stack_size = 0x%lx, "
|
||||
"regs = 0x%p\n",
|
||||
clone_flags, stack_size, regs);
|
||||
|
||||
/* Always end with a call to jprobe_return(). */
|
||||
jprobe_return( );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
asmlinkage __visible void __sched jschedule(void)
|
||||
{
|
||||
|
||||
/* Always end with a call to jprobe_return(). */
|
||||
jprobe_return( );
|
||||
|
||||
//return 0;
|
||||
}
|
||||
|
||||
static struct jprobe my_jprobe = {
|
||||
.entry = jdo_fork,
|
||||
/* 注意 symbol_name与addr不能同时存在
|
||||
* 参见kprobe_addr函数--http://lxr.free-electrons.com/source/kernel/kprobes.c#L1359
|
||||
* 否则会提示参数错误ERR_PTR(-EINVAL);
|
||||
* 内核中errno的值在http://lxr.free-electrons.com/source/include/uapi/asm-generic/errno-base.h#L25
|
||||
* */
|
||||
.kp = {
|
||||
.symbol_name = "_do_fork",
|
||||
//.addr
|
||||
.pre_handler = handler_pre,
|
||||
.post_handler = handler_post,
|
||||
.fault_handler = handler_fault,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init jprobe_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
//my_jprobe.kp.symbol_name = "_do_fork";
|
||||
//my_jprobe.kp.addr = kallsyms_lookup_name("_do_fork");
|
||||
#if 0
|
||||
my_jprobe.kp.pre_handler = handler_pre;
|
||||
my_jprobe.kp.post_handler = handler_post;
|
||||
my_jprobe.kp.fault_handler = handler_fault;
|
||||
#endif
|
||||
|
||||
if(my_jprobe.kp.symbol_name == NULL)
|
||||
{
|
||||
my_jprobe.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("_do_fork");
|
||||
printk("find _do_fork address at 0x%p\n", my_jprobe.kp.addr);
|
||||
}
|
||||
|
||||
ret = register_jprobe(&my_jprobe);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "register_jprobe failed, returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n",
|
||||
my_jprobe.kp.addr, my_jprobe.entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit jprobe_exit(void)
|
||||
{
|
||||
unregister_jprobe(&my_jprobe);
|
||||
printk(KERN_INFO "jprobe at %p unregistered\n", my_jprobe.kp.addr);
|
||||
}
|
||||
|
||||
module_init(jprobe_init)
|
||||
module_exit(jprobe_exit)
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* NOTE: This example is works on x86 and powerpc.
|
||||
* Here's a sample kernel module showing the use of kprobes to dump a
|
||||
* stack trace and selected registers when do_fork() is called.
|
||||
*
|
||||
* For more information on theory of operation of kprobes, see
|
||||
* Documentation/kprobes.txt
|
||||
*
|
||||
* You will see the trace data in /var/log/messages and on the console
|
||||
* whenever do_fork() is invoked to create a new process.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
/* For each probe you need to allocate a kprobe structure */
|
||||
static struct kprobe kp = {
|
||||
.symbol_name = "do_fork",
|
||||
};
|
||||
|
||||
/* kprobe pre_handler: called just before the probed instruction is executed */
|
||||
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx,"
|
||||
" flags = 0x%lx\n",
|
||||
p->addr, regs->ip, regs->flags);
|
||||
#endif
|
||||
#ifdef CONFIG_PPC
|
||||
printk(KERN_INFO "pre_handler: p->addr = 0x%p, nip = 0x%lx,"
|
||||
" msr = 0x%lx\n",
|
||||
p->addr, regs->nip, regs->msr);
|
||||
#endif
|
||||
#ifdef CONFIG_MIPS
|
||||
printk(KERN_INFO "pre_handler: p->addr = 0x%p, epc = 0x%lx,"
|
||||
" status = 0x%lx\n",
|
||||
p->addr, regs->cp0_epc, regs->cp0_status);
|
||||
#endif
|
||||
|
||||
/* A dump_stack() here will give a stack backtrace */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* kprobe post_handler: called after the probed instruction is executed */
|
||||
static void handler_post(struct kprobe *p, struct pt_regs *regs,
|
||||
unsigned long flags)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
printk(KERN_INFO "post_handler: p->addr = 0x%p, flags = 0x%lx\n",
|
||||
p->addr, regs->flags);
|
||||
#endif
|
||||
#ifdef CONFIG_PPC
|
||||
printk(KERN_INFO "post_handler: p->addr = 0x%p, msr = 0x%lx\n",
|
||||
p->addr, regs->msr);
|
||||
#endif
|
||||
#ifdef CONFIG_MIPS
|
||||
printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n",
|
||||
p->addr, regs->cp0_status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* fault_handler: this is called if an exception is generated for any
|
||||
* instruction within the pre- or post-handler, or when Kprobes
|
||||
* single-steps the probed instruction.
|
||||
*/
|
||||
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
||||
{
|
||||
printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
|
||||
p->addr, trapnr);
|
||||
/* Return 0 because we don't handle the fault. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init kprobe_init(void)
|
||||
{
|
||||
int ret;
|
||||
kp.pre_handler = handler_pre;
|
||||
kp.post_handler = handler_post;
|
||||
kp.fault_handler = handler_fault;
|
||||
|
||||
ret = register_kprobe(&kp);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit kprobe_exit(void)
|
||||
{
|
||||
unregister_kprobe(&kp);
|
||||
printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
|
||||
}
|
||||
|
||||
module_init(kprobe_init)
|
||||
module_exit(kprobe_exit)
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user