前言

在编写linux驱动程序时,最让人头疼的,莫不是内核发生了oops错误,并打印了一大堆错误信息如下:

Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = 23b16ac7
[00000000] *pgd=00000000
Internal error: Oops: 80000005 [#1] PREEMPT SMP ARM
Modules linked in: ssd1306fb_spi(O+) g_multi snd_soc_fsl_asrc snd_soc_core snd_pcm_dmaengine snd_pcm snd_timer [last unloaded: ssd1306fb_spi]
CPU: 0 PID: 476 Comm: insmod Tainted: G           O      4.19.35-imx6 #1stable
Hardware name: Freescale i.MX6 UltraLite (Device Tree)
PC is at   (null)
LR is at bit_putcs+0x270/0x40c
pc : [<00000000>]    lr : [<80497a6c>]    psr: 600f0013
sp : 86edba18  ip : 00000001  fp : 86008800
r10: 00000000  r9 : 000000ff  r8 : 00000001
r7 : 00000010  r6 : 876e9120  r5 : 87692010  r4 : ffffffff
r3 : 00000000  r2 : 00000000  r1 : 86edba7c  r0 : 8741a000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c53c7d  Table: 8686406a  DAC: 00000051
Process insmod (pid: 476, stack limit = 0xa0438ff4)
Stack: (0x86edba18 to 0x86edc000)
...
[<80497a6c>] (bit_putcs) from [<80491a60>] (fbcon_putcs+0xf4/0x10c)
[<801ae464>] (do_init_module) from [<801ad38c>] (load_module+0x2174/0x257c)
[<801ad38c>] (load_module) from [<801ada18>] (sys_finit_module+0xc4/0x110)
[<801ada18>] (sys_finit_module) from [<80101000>] (ret_fast_syscall+0x0/0x54)
Exception stack(0x86edbfa8 to 0x86edbff0)
bfa0:                   336e7f00 00000000 00000003 004cc7e0 00000000 7ebc7c38
bfc0: 336e7f00 00000000 00000000 0000017b 0238b160 00000000 7ebc7db8 00000000
bfe0: 7ebc7be8 7ebc7bd8 004c4e41 76ca0d92
Code: bad PC value
---[ end trace 701ce5fc9b7e7151 ]---

常见的方法是利用objdump工具进行反汇编,然后使用gbd的list指令加上出错函数和偏移量,就可以定位出错的具体位置,前提是有源代码的情况下。
上面的oops打印信息展示了内核出错时程序的调用关系和出错的原因。可以看到内核发生错误是在fbcon_putcs+0xf4/0x10c处,并且是因为访问了NULL指针所导致的错误,其中0xf4表示的是位于该函数第0x18字节处,0x10c表示该函数共0x10c个字节。尽管如此,我们还是不知道具体是到底是哪里使用了NULL指针。有没有什么工具可以利用这些信息定位到具体是某个文件的某一行呢?说到这里,不得不吐槽一下,嵌入式真是一步一个脚印(坑)!使用单片机时,有硬件错误HardFault;本想着进入linux世界,起码会好点,结果还是泪。。。得益于之前调试HardFault的cmBackTrace工具,该工具本质上是利用addr2line和输出的函数调用栈信息,还原发生错误时的现场信息,定位问题代码位置。抱着尝试的态度,有了这篇文章,作为记录。

addr2line工具

addr2line工具是一个可以将指令的地址和可执行映像转换为文件名、函数名和源代码行数的工具,更多的介绍,可以进行百度/谷歌。下面列举之后会用到的参数以及对应含义:

参数 作用
-e 指定需要转换地址的可执行文件名
-f 在显示文件名、行号输出信息的同时显示函数名信息
-p 输出信息更加人性化
-a 在函数名、文件和行号信息之前,显示地址,以十六进制形式

内核配置CONFIG_DEBUG_INFO

使用addr2line工具之前,请确保内核配置正确:CONFIG_DEBUG_INFO=y,该配置使能以调试方式编译内核,这样编译生成的vmlinux文件才会带有调试信息。make menuconfig位置位于:Kernel hacking > Compile-time checks and compiler options>[] Compile the kernel with debug info处。

使用addr2line进行定位


可以看到addr2line工具,为我们定位到文件drivers/video/fbdev/core/bitblit.c的第192行。该文件的第192行位于函数bit_putcs之中。

static void bit_putcs(struct vc_data *vc, struct fb_info *info,const unsigned short *s, int count, int yy, int xx,int fg, int bg)
{/* 省略部分代码 */
184     if (!mod)
185         bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
186                   width, cellsize, &image, buf, dst);
187     else
188         bit_putcs_unaligned(vc, info, s, attribute, cnt,
189                     pitch, width, cellsize, &image,
190                     buf, dst);
191
192     image.dx += cnt * vc->vc_font.width;/* 省略部分代码 */
}

在bit_puts函数的第192行之前调用了函数bit_putcs_unaligned,bit_putcs_unaligned函数的结尾调用了函数指针info->fbops->fb_imageblit。

static inline void bit_putcs_unaligned(struct vc_data *vc,struct fb_info *info, const u16 *s,u32 attr, u32 cnt, u32 d_pitch,u32 s_pitch, u32 cellsize,struct fb_image *image, u8 *buf,u8 *dst)
{/* 省略部分代码 */info->fbops->fb_imageblit(info, image);
}

而我编写的驱动模块,fb_ops结构体确实没有对成员fb_imageblit进行赋值,最终成功定位到使用NULL指针的具体位置。实际测试,将一个空函数赋值给fb_fbops函数的成员fb_imageblit,加载模块时,内核也不提示oops错误,证明找对地方了。

static struct fb_ops fb_fbops = {.owner = THIS_MODULE,.fb_read = fb_sys_read,
};

Linux驱动之oops错误:addr2line工具定位错误相关推荐

  1. linux宕机时Oops分析及问题定位

    以下面这个例子说明(下面这个例子就是造一个野指针所引发的错误): /** test-debug-scr.c** Copyright (C) 2012 - 2021 Reuuimlla Limited* ...

  2. 服务器网页500错误修复工具,HTTP500错误是什么?如何修复

    500 Internal Server Error是一个非常普通的HTTP状态代码,表示网站的服务器出了点问题,但是服务器不能更准确地说明的问题是什么. 您可以通过以下几种常见方式来查看HTTP 50 ...

  3. linux驱动调试--oops信息

    在移植dm9000 时被一个错误困扰了很久,当时手里只有printk调试手段,觉得自己应该升级下了,先学习了根据oops信息来调试. 先构造一个错误,insmod后抛出如下信息 我们着重看这几句 PC ...

  4. 爱国者u盘linux驱动,爱国者优盘镜像写入工具(WriteUSBImage)

    爱国者优盘镜像写入工具(WriteUSBImage)是一款通过电脑制作系统恢复U盘的工具,制作过程非常简单,通过"WriteUSBImage"的程序,插入一个4GB及更大容量的U盘 ...

  5. addr2line快速定位进程异常位置

    一.addr2line简介 1.addr2line可以通过解析地址来定位异常发生在哪个文件,哪个函数,哪一行:不过只对编译时带-g参数的进程或者库文件有效,因此想使用addr2line定义进程发生cr ...

  6. linux 内核 addr2line,Android或Linux调试addr2line工具锁定命令的使用

    关于调试:调试中addr2line命令的使用. 问题引出:i850的wifi定位开启后,在使用goole maps时出现rootfs重启现象,打印的log信息如下: ///////////////// ...

  7. linux oops 自动重启,Linux 死机复位(oops、panic)问题定位指南

    一个计算机系统和一个人类社会其实是差不多的,系统在运行中碰到的各种bug相当于人类社会中的各种案件:user space发生的bug危害性一般,可能就相当于一般的民事案件:kernel层面发生bug引 ...

  8. Linux系统安装驱动过程中ko文件加载错误(Required key not available)的解决办法

    Linux系统安装驱动过程中ko文件加载错误(Required key not available)的解决办法 问题描述 在Ubuntu上使用CP210x USB转UART设备时需要安装驱动程序(CP ...

  9. linux内存管理、分析、泄露定位与工具整理

    linux内存管理.分析.泄露定位与工具整理 linux内存管理相关知识 1. 进程的内存申请与分配 2. 当前系统总内存的统计 linux内存分析 linux内存泄漏相关知识 内存泄露的分类 val ...

最新文章

  1. oracle 10g磁盘管理,Oracle 10g UNDO表空间过大导致磁盘空间不足的解决
  2. gstreamer 获取帧数据_Android App卡顿率(顺滑度、顺滑度)并整理数据
  3. LDA-math-神奇的Gamma函数
  4. Object类、常用API
  5. 如何正确认识C语言在当今编程领域的地位
  6. css3 实现水晶按钮
  7. Revit二次开发示例:APIAppStartup
  8. linux 清空进程recv q,Linux中ss命令Recv-Q和Send-Q详解
  9. 表面粗糙度的基本评定参数是_表面粗糙度100个常见问题
  10. The method getContextPath() is undefined for the type ServletContext
  11. 【转】Eclipse,MyEclipse快捷键及字体设置
  12. ctf-web-sql注入
  13. html字幕文本,HTML字幕
  14. 泱泱大中华,美丽我的家 - 俗晒网速,感受幸福
  15. 得到网页的最新更新时间
  16. WSL2 中 docker volume 的位置
  17. Linux虚拟机命令行联网
  18. libpcap流量统计
  19. BPM:系统集成平台,订单高效协同管理
  20. 错误:All elements are null

热门文章

  1. C语言实现关机功能(超详解)
  2. 2020年黑马python视频教程5.0新版课程_黑马Python5.0课程(全套)+ 课件资料
  3. 一个完整的程序化交易系统包含了哪些因素?
  4. 新的博客 fatkun.com
  5. 学习Linux的第五课时
  6. 麦肯锡七步法——《金字塔原理》
  7. 华为鸿蒙os产品,华为鸿蒙OS发布 首先应用于智慧屏产品
  8. 备份数据库的sql server语句
  9. Bitvise SSH Client连接不上linux,“请求被积极拒绝”
  10. 关于html页面转为 jsp页面中文乱码问题