【Linux】驱动内核调试,是需要几板斧的

news/2024/11/16 18:49:34/

目录

前言:

一、基础打印工具

 (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---最常用

这里它有三个方向去输出,如下图所示:

①Log Buffer:

  • 该Buffer里面的内容可以存储在/proc/kmsg
  • 示例:https://blog.csdn.net/weixin_42373086/article/details/130545341?spm=1001.2014.3001.5501 在这里,使用了很多printk打印信息,可以使用dmesg命令查看。

②Console:

  • Console的实现可以很多,目前我们用到的有UART Console(串口)

③RAM Console:

  • 允许将调试日志信息写入一个被称为RAM Console的设备。
  • 这个主要用于解决系统内核崩溃问题,临终时会将一些日志存储在这里方便后续排查。

 这里有很多打印信息,谁优先打印就是一个问题。

这里printk有8个等级,从0到7,优先级依次降低。

通常通过修改/proc/sys/kernel/printk来设置打印。

cat /proc/sys/kernel/printk//打开所有的内核打印
echo 8> /proc/sys/kernel/printk

 小于阈值的打印信息,都将输出到控制台上。

(2)动态打印

①动态打印与printk之间的区别联系

  • 在系统运行时,动态打印可以由系统维护者动态打开内核子系统的打印,可以有选择性地打开某些模块的打印。
  • 而printk是全局的,只能设置打印等级。要使用动态打印,必须在内核设置时打开CONFIG_DYNAMIC_DEBUG。
  • 动态打印也有相应的设备节点:/sys/kernel/debug/dynamic_debug。常用于高速设备。

可以打印函数名(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


http://www.ppmy.cn/news/84953.html

相关文章

计算机组成原理-存储系统-外部存储虚拟存储器

目录 一、外部存储 1.1磁盘组成 1.2性能指标 1.3磁盘地址 1.4硬盘的工作原理 1.5磁盘阵列 二、 固态硬盘SSD 三、虚拟存储器(存储系统详细知识点) 3.1 页式存储器 逻辑地址-》主存(物理)地址 加入块表(TLB)的转换过程 3.2 段式存储器 3.3 段页式存储器 一、外部存储 又称…

【数据结构】向上调整建堆和向下调整建堆的天壤之别以及堆排序算法

💯 博客内容:【数据结构】向上调整建堆和向下调整建堆的天壤之别以及堆排序算法 😀 作  者:陈大大陈 🚀 个人简介:一个正在努力学技术的准前端,专注基础和实战分享 ,欢迎私信&…

linux关闭端口占用程序

在Linux中,要关闭运行在5004端口上的程序,您可以使用以下步骤: 确定占用5004端口的程序的进程ID(PID)。 您可以运行以下命令来查找正在使用5004端口的进程: sudo lsof -i :5004此命令将显示占用5004端口的…

安装部署MISP平台

我是按照官方的docker方式安装的,可以参考这个链接:https://github.com/MISP/docker-misp 安装完成后,是无法访问的,我登录到容器内查看错误日志(/var/log/apache2),我比较幸运,错误…

电脑常识:中文模式和英文模式下的符号有何区别?有何应用?

1)全角---指一个字符占用两个标准字符位置。 汉字字符和规定了全角的英文字符及国标GB2312-80中的图形符号和特殊字符都是全角字符。一般的系统命令是不用全角字符的,只是在作文字处理时才会使用全角字符。 (2)半角---指一字符占用…

瑞云科技助力番职院打造虚拟数字人,探索职业教育创新之路

3月24-25日,教育部高等学校科学研究发展中心主办、广州番禺职业技术学院承办的2022-2023年职业教育示范性虚拟仿真实训基地建设工作推进会在中国广州举行。会议旨在指导各院校建好用好管好虚拟仿真示范实训基地,以数字化、网络化、智能化赋能职业教育高质…

LeetCode54 螺旋矩阵

给你一个m行n列的矩阵matrix,请按照顺时针螺旋顺序,返回矩阵中的所有元素。 示例1 输入: matrix [[1,2,3],[4,5,6],[7,8,9] 输出: [1,2,3,6,9,8,7,4,5] 示例2 输入: matrix [[1,2,3,4],[5,6,7,8],[9,10,11,12]] 输出…

SPI FLASH认识

文章目录 基本认知spi flash读写介绍nor flash的特性 基本认知 SPI Serial PeriPheral interface 串行外围设备接口,SPI接口主要引用在EEPRom、Flash、实时时钟、AD转换器、还有数字信号处理器和数字信号解码器之间。SPI总线系统是一种同步串行外设接口,…