首页
社区
课程
招聘
[原创]使用GDK7调试Linux内核之printk函数
发表于: 2021-7-5 17:56 7406

[原创]使用GDK7调试Linux内核之printk函数

2021-7-5 17:56
7406

1.      在USB接口上插入Mercury的无线网卡。

l  Windows中可直接运行网卡驱动,在等待网卡驱动安装完成以后就可以连接WiFi了。

l  初始的Ubuntu中由于没有Wine,故无法直接运行.exe应用程序;同时通过在终端输入ifconfig命令时提示安装net-tools,于是可以发现Ubuntu是非常“干净”的?

2.      进入设置=>进入WiFi面板=>显示未发现WiFi适配器=>在终端输入lsusb,发现USB无线网卡设备可以被识别出来=>没有安装网卡驱动=>无法连接WiFi =>尝试使用其他方法连接网络来安装网卡驱动。

3.      尝试给GDK7连接网络。

l  让GDK7通过网线与路由器连接,从而连接网络=>实际可行但我这不行=>否掉此方案。

l  手机开启个人热点并开启USB网络共享,然后通过数据线与GDK7连接,从而连接网络=>可以但涉及下载及更新,比较耗费流量=>选择此方案。

4.      通过手机热点及数据线如愿的让Ubuntu连接上了网络。

5.      进入清华大学开源软件镜像站=>点击Ubuntu旁边的问号进入Ubuntu镜像使用帮助页面=>选择合适的Ubuntu版本(GDK7自带的Ubuntu版本默认是18.04.1LTS)=>复制文本内容。

l  或通过下方链接直接进入Ubuntu镜像使用帮助页面。

https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/

6.      打开终端=>输入cd /etc/apt,进入apt文件夹=>输入ls,查看apt文件夹下的文件=>输入sudo gedit sources.list,修改软件源配置文件=>将文件中原本的文本替换成第5步中复制的文本=>保存并退出=>输入sudo apt-get update,更新本地软件源列表=>输入sudo apt-get upgrade更新已安装的软件至新版本(中途需要按Y),软件更新的版本取决于本地软件源的情况。

l  由于更新所以我的Linux内核版本从5.0.0-23升级到了5.3.0-62。

7.      从下方链接进入水星网络的官方网站后,找到合适的驱动下载并安装。

https://www.mercurycom.com.cn/

8.      成功连接WiFi。

1.      根据http://advdbg.org/blogs/advdbg_system/articles/7147.aspx(参考文献中的2)下载Linux的符号文件。

l  若出现仓库“……”没有Release文件的情况则在ddebs.list中注释/删除对应的仓库内容。

l  Linux的内核符号文件默认下载在/usr/lib/debug/boot目录下。

l  Linux其他的符号文件默认下载在/usr/lib/debug/modules目录下。

2.      将Linux的内核符号文件复制到调试主机下;文件在调试主机内的位置无要求。

1.      打开终端=>输入uname -a,来查看当前系统的Linux内核版本。

2.      下载并安装对应内核版本的Linux内核源代码。

l  选择合适的镜像源,修改软件源配置文件/etc/apt/sources.list并保存。

l  sudo apt-get update // 更新。

l  apt search linux-source // 查找对应内核版本的的Linux内核源代码。

l  sudo apt install linux-source-x.x.x // 安装Linux内核源代码。

l  cd /usr/src/linux-source-x.x.x // 找到Linux内核源代码包linux-source-x.x.x.tar.bz2。

3.      将Linux内核源代码包复制到调试主机下,文件在调试主机内的位置无要求。

printk函数是专供内核程序实现打印功能的函数(内核态模式下实现打印功能),显然printk函数只能在内核代码中使用;printk函数主要的作用是将信息记录到日志中及对外打印信息;Linux系统日志架构的说明见图2.1。

图2.1 Linux系统日志架构的说明

假如你熟悉C语言那么你一定对printf函数非常的熟悉,printk函数与printf函数不能说一模一样,只能说非常相似=>print kernel(内核)与print format(格式化),两个函数同属于print这一个大家族。

l  printk函数在内核态模式下实现打印功能;printf在用户态下实现打印功能。

l  CPU运行时所处的特权级为内核级0级时,使用者才可调用printk;CPU运行时所处的特权级为应用级3级时,使用者才可调用printf。

l  printk函数可控制打印的信息是否出现在终端上,只有当日志级别小于控制台级别时,printk函数打印的信息才会在终端上显示。

 

print家族的简单说明

1.      print类函数的家族成员:

l  printB/vprintB

l  sprintB/vsprintB

l  fprintB/vfprintB

2.      print类函数的标准格式:AprintB

A:大概可分为空/s/f/v=>

l  空:默认情况;代表向标准化设备(如显示器)输出打印的信息。

l  s:全称为string;代表向字符串缓冲区输出打印的信息。

l  f:全称为file;代表输出打印的信息。

l  v:全称为va_arg;意思是接受va_list参数,将可变参数函数的格式调用变为接受可变参数的固定参数函数的格式调用。

B:k/f=>全称为kernel(内核)/format(格式化)。

1.      printk函数的原型:

asmlinkage __visible int printk(const char *fmt, ...)

{

       printk_func_t vprintk_func;

       va_list args;

       int r;

       va_start(args, fmt);

 

       /*

        * If a caller overrides the per_cpu printk_func, then it needs

        * to disable preemption when calling printk(). Otherwise

        * the printk_func should be set to the default. No need to

        * disable preemption here.

        */

       vprintk_func = this_cpu_read(printk_func);

       r = vprintk_func(fmt, args);

       va_end(args);

 

       return r;

}

 

2.      示例赏析:

vprintk_emit (facility=0, level=-1, dict=0x0, dictlen=0,

fmt=0xc18b0fa2 "\001\066brd: module loaded\n", args=0xe644bee4 "")

l  Facility = 0 代表信息源自内核

l  Level = -1, 是来自printk的调用时,指定的默认日志级别,vprintk_emit函数内部会尝试从fmt参数中提取level值

 

3.      日志级别(共8个级别)=> /include/linux/kernel.h:

#defineKERN_EMERG"<0>"         /*紧急事件消息;系统崩溃之前提示,表示系统不可用*/

#defineKERN_ALERT"<1>"           /*报告消息;表示必须立即采取措施*/

#defineKERN_CRIT"<2>"              /*临界条件;一般涉及严重的硬件或软件操作失败*/

#defineKERN_ERR"<3>"               /*错误条件;驱动程序常用KERN_ERR来报告硬件的错误*/

#defineKERN_WARNING"<4>"    /*警告条件;对可能出现问题的情况进行警告*/

#defineKERN_NOTICE"<5>"        /*正常且重要的条件;常用于与安全相关的消息*/

#defineKERN_INFO"<6>"            /*提示信息;如驱动程序启动时,打印硬件信息*/

#defineKERN_DEBUG"<7>"         /*调试级别的消息*/

 

4.      消息头结构:

struct printk_log {

       u64 ts_nsec;          /*时间戳(纳秒)*/

       u16 len;                /* 全部记录的长度 */

       u16 text_len;          /*文本缓存区的长度*/

       u16 dict_len;          /* 字典缓冲区的长度 */

       u8 facility;             /* 系统日志的来源*/

       u8 flags:5;             /* 内部记录 */

       u8 level:3;             /*系统日志的级别 */

};

 

5.      cat /proc/sys/kernel/printk=>4 4 1 7

l  左数第1个数字4称为控制台日志级别。此数值决定打印到控制台的任何消息的最低优先级;优先级越低,日志级别的数字越高。

l  左数第2个数字4决定了不维持特定日志级别的所有消息的默认日志级别。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-7-5 18:04 被birdring编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
如此好的文章为什么连优秀都没有?
2021-8-6 18:12
1
雪    币: 2875
活跃值: (7828)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
pureGavin 如此好的文章为什么连优秀都没有?
因为我看不懂
2021-8-6 19:09
0
游客
登录 | 注册 方可回帖
返回
//