调试方法

printk

可在打印的字符串前加上等级

cat /proc/sys/kernel/printk能看到当前的等级信息,可修改为8

内核封装了printk的宏,自定义其打印格式,比如加上设备名称

DEBUG_LL和EARLY_PRINTK;为了在内核初始化控制台驱动driver/tty/serial之前打印,则需要打开这两个配置并在bootargs设置earlyprintk

dump_stack

打印函数调用关系

strace

显示程序发出的所有系统调用及其参数和返回值;-t每个调用执行时间,-T调用中花费的时间等;不仅可以调试刚开始的程序,也可以绑定pid调试正在运行的程序;虽然无法直接追踪到设备驱动的函数,但可以根据系统调用最终也会调用file_operations中的对应函数,系统调用的结果就是这些函数的执行结果

Ioctl

驱动中的ioctl函数可以将驱动的一些信息返回给用户程序,也可以让用户程序通过ioctl系统调用设置一些驱动的参数

Oops

会体现出错原因,cpu序号,错误位置(pc会指出函数加偏移,通过反汇编就能找到具体位置),寄存器值,函数调用关系等

内核中许多类似BUG()的语句,一旦调用就会抛出oops,比如BUG_ON()一旦括号里的内容成立,就会抛出oops;如果指向抛出栈回溯,不想panic(),可以使用WARN_ON抛出内核警告

Kgdb

一般支持串口和网口,为支持kgdb,串口驱动实现轮询收发单个字符的成员poll_get_char/poll_put_char

目标板在bootargs设置kgdboc=ttyS0,15200,kgdbcon;通过echo g > /proc/sysrq-trigger进入调试状态

如果想在开机就进入等待主机gdb的连接的调试状态,可以在bootargs设置kgdbwait

调试机运行arm-eabi-gdb ./vmlinux  set remotebaud 115200  target remote /dev/tty*(调试机串口设备节点)。就可以像gdb调试应用程序一样调试内核了

虚拟文件系统

文件系统用于内核向用户空间暴露一些内核的信息

Sysfs

可通过/sys/class/gpio设置读取gpio的value,比如 echo 1 > gpio626/value

 

proc

存储的是当前内核运行状态的一些特殊文件,以查看系统和进程的信息,很多命令都是分析该文件系统下的文件完成的,如ps,top,uptime,free(/proc/meminfo)

某些文件可以改变内核的运行状态;每个运行的进程都在/proc有一个pid命名的目录

Debugfs

sys/kernel/debug文件系统类似字符设备驱动一样,但不需要设备号,只需要实现一个file_operations,然后通过debugfs_create_file就可以在debugfs中建立一个文件结点,就像字符设备驱动那样,只需要对这个文件结点进行open就可以进行read、write、ioctl等操作

内核hacking

kernel hacking选项提供一些选项给未初始化的自旋锁/信号量/死锁报错;Magic SysRq key在死锁的情况下,打印一些定位问题;Debug shared IRQ handlers可用于调试共享中断

仿真器调试

主机---仿真器(DSTREAM)---JTAG;之后用DS-5图形化调试器进行调试,用于查看代码,栈回溯,查看内存,寄存器,表达式变量,分析内核线程,设置断点等;DS-5也提供了Streamline Performmance Analyzer用来分析和优化在cortex-A平台上运行的linux和andriod系统

ebpf

基本概念

内核中实现了一个cBPF/eBPF虚拟机;用户态通过系统调用bpf()将BPF目标码注入到内核当中;内核通过JIT(Just-In-Time)将BPF目编码转换成本地指令码;如果当前架构不支持JIT转换内核则会使用一个解析器(interpreter)来模拟运行,这种运行效率较低;内核在packet filter和tracing等应用中提供了一系列的钩子来运行BPF代码。

 

kprobe

用户指定一个探测点,并把一个用户定义的处理函数关联到该探测点,当内核执行到该探测点时,相应的关联函数被执行,然后继续执行正常的代码路径;当安装一个kprobes探测点时,kprobe首先备份被探测的指令,然后使用断点指令(即在i386和x86_64的int3指令)来取代被探测指令的头一个或几个字节。当CPU执行到探测点时,将因运行断点指令而执行trap操作,那将导致保存CPU的寄存器,调用相应的trap处理函数,而trap处理函数将调用相应的notifier_call_chain(内核中一种异步工作机制)中注册的所有notifier函数。当kprobe注册的notifier被执行时,它首先执行关联到探测点的pre_handler函数,并把相应的kprobe struct和保存的寄存器作为该函数的参数,接着,kprobe单步执行被探测指令的备份,最后,kprobe执行post_handler。等所有这些运行完毕后,紧跟在被探测指令后的指令流将被正常执行

ftrace

它使用gcc的-pg选项让内核中的每个函数在执行前都调用一个特殊的函数mcount();ftrace支持动态trace功能;COFNIG_DYNAMIC_FTRACE被选中后,内核编译时会调用recordmcount.pl脚本,将每个函数的地址写入一个特殊的段:__mcount_loc;ftrace记录函数调用堆栈信息,并将结果写入ring buffer。用户可以通过debugfs的trace文件读取该ring buffer中的内容。

perf

Linux的一款性能分析工具,能够进行函数级和指令级的热点查找,可以用来分析程序中热点函数的CPU占用率,从而定位性能瓶颈;其基本原理是:每隔一个固定时间,就是CPU上产生一个中断,看当前是哪个进程、哪个函数,然后给对应的进程和函数加一个统计值,这样就知道CPU有多少时间在某个进程或某个函数上了

posted on 2022-03-08 22:08  lzd626  阅读(467)  评论(0编辑  收藏  举报