您的位置:首页 > 其它

How to use ftrace to trace your kernel module(使用Ftrace跟踪你的内核模块)

2011-09-06 22:05 453 查看
AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>

CONTENT: How to use ftrace to trace your kernel module(使用Ftrace跟踪你的内核模块)

NOTE: linux-3.0

LAST MODIFIED:09-06-2011

-----------------------------------------------------------------------------------------------------------

Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)


===============================================================

在下面的内核模块中我们故意设计了一个“除零错误”。并使用Ftrace来跟踪这个错误。

内核模块在/sys/kernel/下创建了kobj4ftrace文件夹,kobj4ftrace下有一个data文件。

你可以向data输入一个整数(echo 3 > data),然后读出data的值(24/3=8)8。

但是在内核模块中没有检查分母是否为零,这样当我们输入0,再读出结果时,将会触发一个“除零错误”。

----------- tl.c ---------------

/*
This is a simple module used for showing How to
use Ftrace to trace your driver.
-----------------------------------------------------
Function: you can "echo your_data > /sys/kernel/kobj4ftrace/data"
This module will divide 24 with 'your_data' and store
the result in
/sys/kernel/kobj4ftrace/data.
To check the result you can use 'cat' cmd.
How to use:
$echo 2 > /sys/kernel/kobj4ftrace/data
$cat /sys/kernel/kobj4ftrace/data
12  // <=== 24/2

Compile: # make  -Wall -C /lib/modules/`uname -r`/build  M=`pwd` modules
!!! Note: Here is a bug: when your data is 0, then there will be a
'Divide Fault'.
*/
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>

static int data = 0;
int devide(int data)
{
return 24/data;
}

int caculater(int data)
{
int result;

result = devide(data);
return result;
}
static ssize_t data_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int result;
result = caculater(data);
return sprintf(buf, "%d\n", result);
}

static ssize_t data_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%du", &data);
return count;
}

static struct kobj_attribute data_attribute =
__ATTR(data, 0666, data_show, data_store);

static struct attribute *attrs[] = {
&data_attribute.attr,
NULL,	/* need to NULL terminate the list of attributes */
};

static struct attribute_group attr_group = {
.attrs = attrs,
};

static struct kobject *my_kobj;

static int __init my_init(void)
{
int retval;
/* file is located under /sys/kernel/ */
my_kobj = kobject_create_and_add("kobj4ftrace", kernel_kobj);
if (!my_kobj)
return -ENOMEM;

/* Create the files associated with this kobject */
retval = sysfs_create_group(my_kobj, &attr_group);
if (retval)
kobject_put(my_kobj);

return retval;
}

static void __exit my_exit(void)
{
kobject_put(my_kobj);
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Joseph <ganggexiongqi@gmail.com>");


----------------- 操作步骤 ---------------------

Trace the kernel bug:

# mount -t debugfs nodev /sys/kernel/debug

# cd /sys/kernel/debug/tracing

Load your module:

#insmod tl.ko

Set the trace filter

# echo ':mod:tl' > set_ftrace_filter //注意,tl为你要跟踪的模块的名字

Check the filter to see functions in your module.

# cat set_ftrace_filter



devide



caculater

data_store

data_show

Choose a the tracer:

#echo function_graph > current_tracer

Enable trace:

#sysctl kernel.ftrace_enabled=1

Trace begin:

#echo 1 >tracing_enabled

#cat trace_pipe > /tmp/trace_result&

Do something:

# cd /sys/kernel/kobj4ftrace

# echo 2 > data

# cat data

12 // '24/2 = 12'

Make an error:

# echo 0 > data

# cat data // 24/0 ----> divide error!!!!!

Terminate the tracing:

#echo 0 > tracing_enabled

Analysis the tracing result:

#vim /tmp/trace_result

ERR | data_store();

------------------------------------------

0) bash-3234 => cat-3688

------------------------------------------

0) 9.898 us | data_show();

------------------------------------------

0) cat-3688 => bash-3234

------------------------------------------

0) 8.028 us | data_store();

------------------------------------------

0) bash-3234 => cat-3689

------------------------------------------

0) | data_show() { // 注意: 这里就是出现问题的地方!!!


-----------------------------------------------------------------------------------



但是,这里我有个问题没有搞清楚,为什么结果不是:

...



data_show(){

caculater() {

devide() {

结果中只是跟踪到了,最上层的data_show,这是为什么呢???

--------动态地跟踪你的内核模块------------
还是上面的例子tl.c
比如你想知道每次调用data_store函数时 data的值到底是多少?
这时你可以添加一个probe到kprobe_events
#cd /sys/kernel/debug/tracing
#echo “p:myprobe tl:data_store data=@data" > kprobe_events
#echo 1 > events/kprobes/myprobe/enable //使能
//do something


#echo 8 > /sys/kernel/kobj4ftrace/data
#vim trace //读取跟踪结果

# tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<...>-8096 [000] 195687.878983: myprobe2: (data_store+0x0/0x30 [tl]) data=8

------------------------------------------------------------------------------------------------------------------
MORE INFO about how to use kprobe your can ref this 'Documentation/trace/kprobetrace.txt'

------------------------------------------------------------------

--------------------------跟踪一个函数和它调用的所有子函数 //
使用ftrace跟踪模块的初始化代码

//sys_init_module和sys_delete_module这两个系统调用在用户空间是怎么使用的

可以用来跟踪内核模块的初始化代码,和清除代码。

sys_init_module函数中完成模块的全部初始化工作后(包括把模块加入全局的模块列表,调用模块本身的初始化函数),把模块状态置为MODULE_STATE_LIVE,最后,使用rmmod工具卸载模块时,会调用系统调用delete_module,会把模块的状态置为MODULE_STATE_GOING。这是模块内部维护的一个状态。

-----------------------------------------------------------------------

#echo 0 > tracing_enabled

#echo 1 > /proc/sys/kernel/ftrace_enabled

# echo function_graph > current_tracer

#echo sys_init_module > set_graph_function

#echo smp_apic_timer_interrupt > set_ftrace_notrace

#echo > trace

#echo 1 > tracing_on

#echo 1 > tracing_enabled

// #insmod your_module_name.ko

// #rmmod your_module_name

#echo 0 > tracing_enabled

--------- 找到是那个函数调用了指定的函数 // "sys_init_module" and "sys_delete_module"

#echo 0 > tracing_enabled

#echo 1 > /proc/sys/kernel/ftrace_enabled

#echo sys_init_module > set_ftrace_filter

# echo sys_delete_module >> set_ftrace_filter

# echo function > current_tracer

#echo 1 > options/func_stack_trace

#echo 1 > tracing_enabled

// insmod tl.ko

// rmmod tl

#echo 0 > tracing_enabled

# vim trace // Check the trace result

1 # tracer: function

2 #

3 # TASK-PID CPU# TIMESTAMP FUNCTION

4 # | | | | |

5 insmod-3494 [000] 852.444934: sys_init_module <-sysenter_do_call

6 insmod-3494 [000] 852.444938: <stack trace>

7 => sysenter_do_call

8 rmmod-3496 [000] 853.739722: sys_delete_module <-sysenter_do_call

9 rmmod-3496 [000] 853.739726: <stack trace>

10 => sysenter_do_call

可以看出 是 sysenter_do_call 调用了sys_init_module 和 sys_delete_module
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: