目录
printk
printk是Linux内核的一个系统调用,也是内核代码调试时最常用的技巧。
对于循环中的变量,或者被多次调用的函数里面的变量,
有时候只需要打印一次,不然可能要打印很久,这个时候就用printk_once函数即可。
printk的格式说明符 :
int
%d 或者 %x( 注: %d 是十进制, %x 是十六进制 )
u32 或者 unsigned int
%u 或者 %x
long
%ld 或者 %lx
unsigned long
%lu 或者 %lx
s64 或者 long long
%lld 或者 %llx
u64 或者 unsigned long long
%llu 或者 %llx
size_t
%zu 或者 %zx
ssize_t
%zd 或者 %zx
原始指针值
%p
dump_stack
对于调用关系比较复杂的函数,在目标函数里面调用dump_stack()可以查看目标函数的调用链
但是如果情况更复杂,涉及到很多函数指针的传递和钩子函数,那么dump_stack的作用也是有限。
kallsyms
kallsyms是linux的一个子系统,顾名思义,kernel_all_syms,也就是内核的所有符号。
kallsyms子系统的功能是把内核代码的所有符号(其实不是所有,没仔细研究,不过重要的都有了)抽取出来,做成一个符号表,从而方便调试。
除了调试之外,Linux程序也可以直接查找这个符号表。
在livepatch中就是通过查找这个符号表,根据符号名得到符号的地址。
开启kallsyms子系统的方法:
内核配置系统中设置CONFIG_KALLSYMS=y,CONFIG_KALLSYMS_ALL=y
gdb调试+vmlinux
vmlinux是个elf文件,它的符号表中包含了所有内核符号。
注意linux中很多文件是没有后缀的,比如我见到的这个elf文件的文件名是“vmlinux-3.10.62”,没有后缀。
既然是elf文件那就可以用下面两种方法直接查看符号表:
方法一:readelf
访问elf文件所在目录,执行“readelf -a 文件名”即可查看elf文件的内容。
-a选项表示显示所有信息。
在最后面就是elf里面的符号表。
方法二:objdump
要想看得更仔细,可以用gdb调试工具。
(1)进入vmlinux所在目录
(2)执行 arm-wrs-linux-gnu-gdb vmlinux-3.10.62
(3)输入 list*(函数名+函数内偏移) 即可查看特定位置的代码
ko反汇编
进入ko文件所在目录
执行 arm-wrs-linux-gnu-gdb ko文件名
执行 disassemble 函数名 即可把ko中定义的函数反汇编