【Linux】驱动内核调试,是需要几板斧的 | 您所在的位置:网站首页 › linux怎么改文件时间 › 【Linux】驱动内核调试,是需要几板斧的 |
目录 前言: 一、基础打印工具 (1)printk---最常用 ①Log Buffer: ②Console: ③RAM Console: (2)动态打印 ①动态打印与printk之间的区别联系 ②动态打印常用的例子 ③动态打印转为printk正常打印 (3)dump_stack---分析源码的利器 (4)操作寄存器命令---硬件测试 ①devmem---系统层面 ②ioremap---内核层面 ③ /dey/mem---应用层面 二、特殊场景下的打印工具 (1)Oops内核崩溃: (2)休眠唤醒: (3)Linux错误码: (4)Linux kernel中计算代码运行时间: (5)debugfs 前言:在VS code编程时我们编写程序时都有输出打印信息,方便查找问题,在驱动开发中,亦有调试的手段和方法,这些是我们解决和排查问题的利器。 工欲善其事,必先利其器,所以驱动内核调试方法的掌握,是非常有必要的。 参考学习: https://xuesong.blog.csdn.net/article/details/113062813 https://xuesong.blog.csdn.net/article/details/109522945?spm=1001.2014.3001.5502 Linux内核常用调试手段介绍-Linux笔记 开发环境: imx6ull pro开发板 Linux 4.9.88内核 一、基础打印工具 (1)printk---最常用这里它有三个方向去输出,如下图所示: 这里有很多打印信息,谁优先打印就是一个问题。 这里printk有8个等级,从0到7,优先级依次降低。 通常通过修改/proc/sys/kernel/printk来设置打印。 cat /proc/sys/kernel/printk //打开所有的内核打印 echo 8> /proc/sys/kernel/printk小于阈值的打印信息,都将输出到控制台上。 可以打印函数名(f)、行号(l)、模块名字(m)以及线程ID(t)。 ②动态打印常用的例子1.打开一个文件中所有动态打印语句 echo -n "file gadget.c +p">2.打开一个模块中所有动态打印语句 echo -n "module dwc3 +p">3.打开一个函数中所有动态打印语句 echo "func svc_process +p">4.打开文件路径中包含usb的文件里所有的动态打印语句 echo -n "*usb* +p"> ③动态打印转为printk正常打印开机的时候,没法操作这个动态打印的节点,能否把动态打印转换成默认的printk正常打印,这个如何实现? 在c文件开头添加: //重定义 #undef dev_dbg #define dev_dbg dev_info #undef pr_debug #define pr_debug pr_info (3)dump_stack---分析源码的利器分析一个函数的底层调用,离不开dump_stack,因为它是对内核调用栈的打印;当我们不清楚系统回调函数上下文,使用这个方法是非常好的。 具体demo案例:参照文章 https://xuesong.blog.csdn.net/article/details/113062813 (4)操作寄存器命令---硬件测试 ①devmem---系统层面它的原理以及应用场景: 硬件工程师将硬件设计好时,需要进行简单的测试,来查看CPU是否可以正确地读取新硬件系统。 正规的Linux操作方式下,是要有硬件的驱动程序才能完成这个需求。测试需求只是为了实现简单硬件寄存器读写工作时,devmem命令就非常的适用了。它的原理就是把硬件的地址空间ioremap映射到用户空间。具体使用方法,可以参照: https://xuesong.blog.csdn.net/article/details/113283070 ②ioremap---内核层面实现的核心代码: #define GPIO0_DDR_BASE ((uint32_t)0xE7A01014) static volatile uint32_t *GPIO0_ddr_vreg; uint32_t val = 0; GPIO0_ddr_vreg = (uint32_t *)ioremap(GPIO0_DDR_BASE, 4); val = readl(GPIO0_ddr_vreg); printk("val = %ld\n",val); ③ /dey/mem---应用层面应用层操作寄存器首先需要将内核映射到核外空间,内核已经提供了一个 /dey/mem 的文件接口,这个文件相当于整个系统内存所在,将该文件打开然后指定需要映射的内存的位置即可。需要注意的是,一般 map 映射的是一段内存地址空间。 具体使用方法: https://xuesong.blog.csdn.net/article/details/114156170 二、特殊场景下的打印工具 (1)Oops内核崩溃:当我们遇到内核崩溃,比如空指针异常、内存访问越界。这时我们只能靠崩溃之后打印出来异常调用栈信息来定位Oops的位置和原因。 举个例子: 在第三行error:Oops信息 kernel BUG at../drivers/mmc/host/sdhci.c 那一行可以简要告知我们是哪里发生问题触发Oops。 (2)休眠唤醒:我们使用的多个模块都会使用到休眠唤醒,每个休眠唤醒都会有相应的休眠唤醒锁。如果想知道当前模块休眠唤醒失败是由哪个斥锁导致的,可以应用下面的命令实现: awk '$6 !=0{print $1""$6}' /sys/kernel/debug/wakeup_sources (3)Linux错误码:错误代码由内核或用户空间应用程序(通过error变量)解释。错误处理在软件开发中非常重要,而不仅仅是在内核开发中。幸运的是,内核提供的几种错误,几乎涵盖了可能遇到的所有错误,有时需要把它们打印出来以帮助进行调试。 相应文件的路径: include/uapi/asm-generic/errno-base.h include/uapi/sm-generic/error.h具体如下: 相应所有错误码说明,可参考: Linux错误代码及其含义_linux enxio_wsqyouth的博客-CSDN博客 (4)Linux kernel中计算代码运行时间:对内核或驱动代码做性能优化时,常常要测量一段代码执行时所消耗的时间。 常用的函数为ktime_get(),在一段代码前后各使用 ktime_get() 获取时间,计算其差值,就是这段代码运行消耗的时间。ktime_get() 能够精确到纳秒级。 (5)debugfs内核中有三个常用的伪文件系统: procfs, debugfs和sysfs。 debugfs是内核开发中专门用来调试的文件系统接口,其他的工具或者接口,多数都依赖于debugfs。 具体如何使用,参考文章: https://xuesong.blog.csdn.net/article/details/124112698 |
CopyRight 2018-2019 实验室设备网 版权所有 |