• Linux驱动调试方法(高级字符设备八)


      在编写Linux驱动程序时,通常都使用 printk 函数打印相应的提示信息从而对驱动进行调试,除了printk 函数之外,还有其他的方式来调试驱动呢。

    一、dump_stack 函数

      作用:打印内核调用堆栈,并打印函数的调用关系。
    这里以最简单的 helloworld 驱动为例进行 dump_stack 函数演示,实验代码如下所示:

    #include 
    #include 
    static int __init helloworld_init(void)
    {
        printk(KERN_EMERG "helloworld_init\r\n");
        dump_stack();
        return 0;
    }
    static void __exit helloworld_exit(void)
    {
        printk(KERN_EMERG "helloworld_exit\r\n");
    }
    module_init(helloworld_init);
    module_exit(helloworld_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      驱动加载之后打印信息如下所示:
    在这里插入图片描述
      可以看到 helloworld_init 函数的调用关系就都打印了出来。

    二、WARN_ON(condition)函数

      WARN_ON (condition)函数作用:在括号中的条件成立时,内核会抛出栈回溯,打印函数的调用关系。通常用于内核抛出一个警告,暗示某种不太合理的事情发生了。
      WARN_ON 实际上也是调用 dump_stack,只是多了参数condition 判断条件是否成立,例如 WARN_ON (1)则条件判断成功,函数会成功执行。
      这里仍然以最简单的 helloworld 驱动为例进行 WARN_ON 函数演示,代码如下所示:

    #include 
    #include 
    static int __init helloworld_init(void)
    {
        printk(KERN_EMERG "helloworld_init\r\n");
        WARN_ON(1);
        return 0;
    }
    static void __exit helloworld_exit(void)
    {
        printk(KERN_EMERG "helloworld_exit\r\n");
    }
    module_init(helloworld_init);
    module_exit(helloworld_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      驱动加载之后打印信息
    在这里插入图片描述
      可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来。

    三、BUG_ON (condition)函数

      内核中有许多地方调用类似 BUG_ON()的语句,它非常像一个内核运行时的断言,意味着本来不该执行到 BUG_ON()这条语句,一旦 BUG_ON()执行内核就会立刻抛出oops,导致栈的回溯和错误信息的打印。大部分体系结构把 BUG()和 BUG_ON()定义成某种非法操作,这样自然会产生需要的 oops。参数 condition 判断条件是否成立,例如BUG_ON(1)则条件判断成功,函数会成功执行。
      这里仍然以最简单的 helloworld 驱动为例进行 BUGON 函数演示,实验代码如下所示:

    #include 
    #include 
    static int __init helloworld_init(void)
    {
        printk(KERN_EMERG "helloworld_init\r\n");
        BUGON(1);
        return 0;
    }
    static void __exit helloworld_exit(void)
    {
        printk(KERN_EMERG "helloworld_exit\r\n");
    }
    module_init(helloworld_init);
    module_exit(helloworld_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      驱动加载之后打印信息如下
    在这里插入图片描述
      可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来。

    四、panic (fmt…)函数

      panic (fmt…)函数:输出打印会造成系统死机并将函数的调用关系以及寄存器值就都打印了出来。

    #include 
    #include 
    static int __init helloworld_init(void)
    {
        printk(KERN_EMERG "helloworld_init\r\n");
        panic("!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        return 0;
    }
    static void __exit helloworld_exit(void)
    {
        printk(KERN_EMERG "helloworld_exit\r\n");
    }
    module_init(helloworld_init);
    module_exit(helloworld_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      驱动加载之后打印信息如下
    在这里插入图片描述
      可以看到 helloworld_init 函数的调用关系以及寄存器值就都打印了出来,信息打印完成之后会发现系统已经崩溃了,终端已经无法再进行输入。

  • 相关阅读:
    Docker网络功能
    IDEA 之 在不更改操作系统用户名的情况下更改 ${USER} 变量?
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    鸿蒙HarmonyOS实战-Web组件(页面跳转和浏览记录)
    canaladapter 同步mysql(一对多关系)到es,es 添加逗号分词查询
    主动扫描技术nmap详解
    ELK企业级日志分析系统
    艾美捷Cy5.5单琥珀酰亚基酯 Cy5.5 NHS酯解决方案
    2024环境,资源与绿色能源国际会议(ICERGE2024)
    本周大新闻|传Cambria采用升级版XR2芯片,TGS增设VR虚拟展厅
  • 原文地址:https://blog.csdn.net/xxxx123041/article/details/134047511