嵌入式开发常用调试方法
调试方法
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系统