用Ftrace跟踪内核模块

 

转载自:http://blog.csdn.net/defeattroy/archive/2010/05/23/5618099.aspx

对一个名为epl.ko的内核模块进行trace的过程如下:

1 首先确保你打开相应的内核选项: kernel_hacking/Trace下面。如果需要重编内核。

注意重编内核后重编你的模块。

2 设置ftrace

mount -t debugfs debugfs /sys/kernel/debug #要使用 ftrace首先需要mount这个debugfs

ln -s /sys/kernel/debug /debug #方便期间做个链接

cd /debug

echo function_graph > current_tracer #输出函数调用图,需要打开内核选项FUNCTION_GRAPH_TRACER

3 提取模块里的函数列表

如果没有设置过滤表(默认加载debugfs后),available_filter_functions文件包含了所有可追踪的函数名称,默认情况下这个链表覆盖了所有内核的可trace函数。如果我们插入一个模块,那么ftrace会自动把我们我们这个模块的函数符号加到available_filter_functions中。提取一个内核模块的函数可以有两种方法,一种是用nm命令,一种是比较插入模块前后available_filter_functions的差异,两种方法都提供给读者如下:

1)比较插入模块前后available_filter_functions的差异

cat available_filter_functions > /tmp/funcs_without_epl
insmod epl.ko
cat available_filter_functions > /tmp/funcs_with_epl
diff /tmp/funcs_without_epl /tmp/funcs_with_epl > epl_funcs
删除 epl_funcs文件里由diff产生的无用信息。

2) 使用nm命令导出epl.ko里的符号

参考 [附表:nm基本用法]

nm导出的是ko里的所有符号,我们只需要函数符号

nm -s epl.ko | grep " T " | awk '{ print $3 }' > nm_funcs
nm -s epl.ko | grep " t " | awk '{ print $3 }' >> nm_funcs

为了比较两者产生的差别,首先排下序

sort nm_funcs > nm_funcs_sorted
sort epl_funcs > epl_funcs_sorted
diff -Nur nm_funcs_sorted epl_funcs_sorted

我们可能发现nm_funcs包含了一些epl_funcs没有的函数,这些函数正式kernel里面本来有的内核函数,所以如果你只想trace你的模块的函数,那么推荐使用方法1。

4 开始trace

insmod epl.ko

cat /tmp/epl_funcs > set_ftrace_filter
echo 1 >tracing_enabled #开始trace
cat trace_pipe > /tmp/ftrace_result.txt & #设置一个管道重定向,防止溢出

tracing & waiting....

echo 0 >tracing_enabled #结束trace

说明:一个ko插入kernel以后才可以给 set_ftrace_filter设置函数过滤表,因为没插入以前内核没有epl.ko的函数符号,故设置set_ftrace_filter失败,所以需要先插入模块以后再enable trace,但是这样又有一个问题:我们也想trace模块插入时候的执行情况时,我们还不能在插入模块前设置过滤表,那么怎么办呢?需要得到这个答案需要首先确认:在默认情况下,也就是设置ftrace为trace所有可trace的函数后,我们插入模块时候ftrace是不是马上把这个ko的函数表加进可trace列表,同时也能够trace这些函数?如果可以,那我们可以先预先准备好filter list(即我们文中所述的epl_funcs),插入模块后然后再设置set_ftrace_filter过滤表,这样会在ftrace的结果的前一段会有我们不希望trace的函数(内核函数),或者删除,或者提取出我们模块初始化部分即可。作者在实践过程中发现有时候ftrace的结果输出没有显示函数符号表,这个问题还有待进一步确认...希望对这方便有深入了解的网友不吝赐教,mqyoung at gmail.com。

如下是我在学习使用过程中做的一些笔记和备忘,也许对您有用


需要了解的几个文件:
===============
set_ftrace_filter:
limit the trace to only those functions.

set_ftrace_notrace:
An effect opposite to that of set_ftrace_filter. Any function that is
added here will not be traced. If a function exists in both files,
the function will _not_ be traced.

set_ftrace_pid:
Only trace a single thread.

available_filter_functions:
This lists the funtions that ftrace has processed and can trace. These
are the function names that you can pass to "set_ftrace_filter" or
"set_ftrace_notrace".


Ftrace 提供的几种Tracer
=================
"function"
"function_graph"

"sched_switch"
context switches and wakeups between tasks
"irqsoff"
disable intrrupts and saves the trace with the longest max latency.
See tracing_max_latency.
"preemptoff"
"preemptirqsoff"

"wakeup"
Records the max latency that it takes for the highest priority task to
get scheduled after it has been woken up.
"hw-branch-tracer"

"nop"
"trace nothing" tracer. To remove all tracers from tracing simply echo
"nop" into current_tracer.

参考资料:

[1] nm http://hi.baidu.com/zzgmtv/blog/item/d021d7437d38d91f72f05d57.html
[2] ftrace kernel_src/Documentation/trace/ftrace.txt

附表:nm基本用法

对于每一个符号,nm列出其值(the symbol value),类型(the symbol type)和其名字(the symbol name)。


符号
类型
说明
A
该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符号值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量表中的位置。
B
该符号的值出现在非初始化数据段 (bss) 中。例如,在一个文件中定义全局 static int test 。则该符号 test 的类型为 b ,位于 bss section 中。其值表示该符号在 bss 段中的偏移。一般而言, bss 段分配于 RAM
C
该符号为 common common symbol 是未初始话数据段。该符号没有包含于一个普通 section 中。只有在链接过程中才进行分配。符号的值表示该符号需要的字节数。例如在一个 c 文件中,定义 int test ,并且该符号在别的地方会被引用,则该符号类型即为 C 。否则其类型为 B
D
该符号位于初始话数据段中。一般来说,分配到 data section 中。例如定义全局 int baud_table[5] = {9600, 19200, 38400, 57600, 115200} ,则会分配于初始化数据段中
G
该符号也位于初始化数据段中。主要用于 small object 提高访问 small data object 的一种方式。
I
该符号是对另一个符号的间接引用。
N
该符号是一个 debugging 符号。
R
该符号位于只读数据区。例如定义全局 const int test[] = {123, 123}; test 就是一个只读数据区的符号。注意在 cygwin 下如果使用 gcc 直接编译成 MZ 格式时,源文件中的 test 对应 _test ,并且其符号类型为 D ,即初始化数据段中。但是如果使用 m6812-elf-gcc 这样的交叉编译工具,源文件中的 test 对应目标文件的 test, 即没有添加下划线,并且其符号类型为 R 。一般而言,位于 rodata section 。值得注意的是,如果在一个函数中定义 const char *test = “abc”, const char test_int = 3 。使用 nm 都不会得到符号信息,但是字符串“ abc ”分配于只读存储器中, test rodata section 中,大小为 4
S
符号位于非初始化数据区,用于 small object
T
该符号位于代码区 text section
U
该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当前文件调用另一个文件中定义的函数,在这个被调用的函数在当前就是未定义的;但是在定义它的文件中类型是 T 。但是对于全局变量来说,在定义它的文件中,其符号类型为 C ,在使用它的文件中,其类型为 U
V
该符号是一个 weak object
W
The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
-
该符号是 a.out 格式文件中的 stabs symbol
?
该符号类型没有定义

你可能感兴趣的:(function,object,filter,table,Graph,debugging)