内核笔记](四)——内核常见调试手段(printf、dump_stack、devmem)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 内核笔记](四)——内核常见调试手段(printf、dump_stack、devmem)

一、内核调试——printk


0a2653c851af460fa595bd959398a8f1.png

printk在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似

printk函数主要做两件事情:第一件就是将信息记录到log中,而第二件事就是调用控制台驱动来将信息输出。


1.日志级别


printk相比printf来说还多了个:日志级别的设置,用来控制printk打印的这条信息是否在终端上显示的,当日志级别的数值小于控制台级别时,printk要打印的信息才会在控制台打印出来,否则不会显示在控制台!


在我们内核中一共有8种级别,他们分别为


#define KERN_EMERG  "<0>" /* system is unusable   */
#define KERN_ALERT  "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions    */
#define KERN_ERR  "<3>" /* error conditions   */
#define KERN_WARNING  "<4>" /* warning conditions   */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational    */
#define KERN_DEBUG  "<7>" /* debug-level messages   */


2.控制台等级


#define MINIMUM_CONSOLE_LOGLEVEL  1   /*可以使用的最小日志级别*/
#define DEFAULT_CONSOLE_LOGLEVEL  7 /*比KERN_DEBUG 更重要的消息都被打印*/
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL,/*控制台日志级别,优先级高于该值的消息将在控制台显示*/
/*默认消息日志级别,printk没定义优先级时,打印这个优先级以上的消息*/
DEFAULT_MESSAGE_LOGLEVEL,
/*最小控制台日志级别,控制台日志级别可被设置的最小值(最高优先级)*/
MINIMUM_CONSOLE_LOGLEVEL,
DEFAULT_CONSOLE_LOGLEVEL,/* 默认的控制台日志级别*/
};


二、动态打印


在系统运行时候,动态打印可以由系统维护者动态打开内核子系统的打印,可以有选择性地打开某些模块的打印,而printk是 全局的,只能设置打印等级。要使用动态打印,必须在内核配置时打开CONFIG_ DYNAMIC_ _DEBUG宏。 .


0a2653c851af460fa595bd959398a8f1.png

p:打开动态打印语句。.

f:打印函数名

l:打印行号

m:打印模块名字

t:打印线程ID


2.1 dynamic动态打印转为printk正常打印.


0eacb84100b54626af849e6b562bf92a.png


三、dump_stack


对于大型驱动,想要知道某个回调函数由谁调用,非常困难。到底有没有办法知道呢?回答是肯定的,通过内核提供的接口dump_stack()可以满足要求。其实能够想到使用dump_stack()来跟踪,是根据当内核发生panic时候,也会主动调用该接口,所以我们可以在调试过程中主动调用该接口来进行测试。


0a2653c851af460fa595bd959398a8f1.png


四、devmem


在Linux开发中着实用到的调试工具并不是很多。devmem的方式是提供给驱动开发人员,在应用层能够侦测内存地址中的数据变化,以此来检测驱动中对内存或者相关配置的正确性验证。是应用程序通过mmap函数实现对/dev/mem驱动中mmap方法的使用,映射了设备的内存到用户空间,实现对这些物理地址的读写操作。

memdev:直接读写内存。


使用方法

devmem的使用方式:

语法: devmem ADDRESS [WIDTH [VALUE]]

ADDRESS :要直接读写的地址

WIDTH :指定读写资料的位数(8/16/32…

VALUE :要写入的资料


读32位: devmem 0x98000000

读16位: devmem 0x98000000 16

读8位: devmem 0x98000000 8


写32位: devmem 0x98000000 32 0x12345678

写16位: devmem 0x98000000 16 0x1234

写8位: devmem 0x98000000 8 0x12


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
Linux Anolis
性能优化特性之:EXT4 Fast Commit
本文介绍了倚天实例上进行IO优化的特性:Fast Commit,并对其优化原理、使用方法进行了详细阐述
|
编译器 vr&ar C++
CMake构建Makefile深度解析:从底层原理到复杂项目(二)
CMake构建Makefile深度解析:从底层原理到复杂项目
553 0
|
3月前
|
Ubuntu 开发工具
Ubuntu 22.04 aarch64版本操作系统下编译ZLMediaKit教程
通过上述步骤,你可以在Ubuntu 22.04 aarch64版本上成功编译ZLMediaKit,这是一个相对简单而直接的过程,但可能会遇到一些需要根据具体系统环境和要求调整的地方。
563 0
|
运维 前端开发 关系型数据库
高效调试与分析:利用ftrace进行Linux内核追踪(上)
高效调试与分析:利用ftrace进行Linux内核追踪
|
存储 监控 Cloud Native
剖析Linux网络包接收过程:掌握数据如何被捕获和分发的全过程(上)
剖析Linux网络包接收过程:掌握数据如何被捕获和分发的全过程
|
安全 数据安全/隐私保护 UED
什么是OTA升级管理系统?
【7月更文挑战第20天】什么是OTA升级管理系统?
676 6
|
Linux 项目管理 开发者
Linux内核基础篇——printk调试
Linux内核基础篇——printk调试
|
编译器 C语言
mixing declarations and code is a C99 extension
mixing declarations and code is a C99 extension
797 0
|
存储 Linux Android开发
Rockchip u-boot阶段命令行和代码方式读取u盘内容并解析
Rockchip u-boot阶段命令行和代码方式读取u盘内容并解析
2247 2
|
Linux Android开发
全志平台A40I : I2C通讯问题调试笔记
全志平台A40I : I2C通讯问题调试笔记
666 0