Linux内核使用gdb调试

栏目: C · 发布时间: 7年前

内容简介:这里记录平时使用gdb调试内核KE的步骤和方法. 有不足的地方也请大家指出和完善.1 必备工具和文件Gdb,addr2line,vmlinux以及内核coredump文件

这里记录平时使用gdb调试内核KE的步骤和方法. 有不足的地方也请大家指出和完善.

1 必备 工具 和文件

Gdb,addr2line,vmlinux以及内核coredump文件

在64位平台,gdb和addr2line 分别使用aarch64-linux-android-gdb

aarch64-linux-android-addr2line.

2. 调试过程

MTK平台coredump文件名为: SYS_MINI_RDUMP,用GAT工具解析DB文件得到.

2.1 启动GDB

aarch64-linux-android-gdb vmlinux  coredump 

aarch64-linux-android-gdb ./vmlinux./aee_exp_backup/db.fatal.00.KE/20151107_170222_178/db.fatal.00.KE.dbg.DEC/SYS_MINI_RDUMP

控制台输出内容:

#0 0xffffffc00088d2c8 in eth_start_xmit(skb=0xffffffc023ba8300, net=0xffffffc06d3d2000)

at kernel-3.10/drivers/usb/gadget/u_ether.c:893

(gdb)

可以看出异常点在u__ether.c文件893行.

2.2 gdb常用指令

bt :    打印堆栈调用信息.

down : 跳转到下一级FP指针

up    :  回到上一级FP指针

P    :   打印变量值

x    :  打印内存内容   

x / (n,f,u为可选参数)

n: 需要显示的内存单元个数,也就是从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义

f:显示格式

x(hex) 按十六进制格式显示变量。

d(decimal) 按十进制格式显示变量。

u(unsigned decimal) 按十进制格式显示无符号整型。

o(octal) 按八进制格式显示变量。

t(binary) 按二进制格式显示变量。

a(address) 按十六进制格式显示变量。

c(char) 按字符格式显示变量。

f(float) 按浮点数格式显示变量

u:每个单元的大小,按字节数来计算。默认是4 bytes。GDB会从指定内存地址开始读取指定字节,并把其当作一个值取出来,并使用格式f来显示

b:1 byte     h:2 bytes     w:4 bytes g:8 bytes

比如x/3uh 0x54320表示从内存地址0x54320读取内容,h表示以双字节为单位,3表示输出3个单位,u表示按照十六进制显示。

list     :  以 c语言 列出当前函数内容(c语言)

disassemble :以汇编方式列出当前函数内容

2.3 异常点分析

可以从last_kmsg或者db文件解析出的SYS_KERNEL_LOG中得知异常类型.重要信息为PC和寄存器值.

Unable to handle kernel NULL pointerdereference at virtual address 000000e4

[6464.203080]<0>-(0)[3:ksoftirqd/0]PC is at eth_start_xmit+0x1fc/0x748

[6464.203112]<0>-(0)[3:ksoftirqd/0]LR is at eth_start_xmit+0x1d8/0x748

[6464.203143]<0>-(0)[3:ksoftirqd/0]pc : [] lr :[] pstate: 800001c5

[6464.203168]<0>-(0)[3:ksoftirqd/0]sp : ffffffc071877b40

[ 6464.203192]<0>-(0)[3:ksoftirqd/0]x29:ffffffc071877b40 x28: 00000000000005bc

[6464.203231]<0>-(0)[3:ksoftirqd/0]x27: 00000000000005bc x26:ffffffc01ee14c40

[6464.203270]<0>-(0)[3:ksoftirqd/0]x25: ffffffc06ee12510 x24:ffffffc06d3d2730

[ 6464.203308]<0>-(0)[3:ksoftirqd/0]x23:ffffffc023ba8300 x22: ffffffc06d3d2720

[6464.203347]<0>-(0)[3:ksoftirqd/0]x21: ffffffc06d3d2000 x20:ffffffc06d3d2700

[6464.203385]<0>-(0)[3:ksoftirqd/0]x19: ffffffc00141e000 x18:0000000000000000

[ 6464.203422]<0>-(0)[3:ksoftirqd/0]x17:0000007f7ed6fcf8 x16: ffffffc000278828

[6464.203459]<0>-(0)[3:ksoftirqd/0]x15: 0000007f7eda9a24 x14:228f252b6f65a378

[6464.203498]<0>-(0)[3:ksoftirqd/0]x13: 9939719eb9fc9521 x12:0260832913e230f2

[6464.203535]<0>-(0)[3:ksoftirqd/0]x11: 63530fe2e6e696f3 x10:399aa79385bb3861

[6464.203573]<0>-(0)[3:ksoftirqd/0]x9 : 01a6b3c12e057068 x8 :2421eada8933ba1d

[6464.203610]<0>-(0)[3:ksoftirqd/0]x7 : e4324d79f1892abb x6 :ffffffc0393165bc

[6464.203646]<0>-(0)[3:ksoftirqd/0]x5 : 0000000000000000 x4 :0000000000000003

[6464.203682]<0>-(0)[3:ksoftirqd/0]x3 : 0000000000000002 x2 :0000000000000000

[6464.203718]<0>-(0)[3:ksoftirqd/0]x1 : 0000000000000140 x0 :ffffffc06d3d2000

启动gdb时会显示最后出现点, 以上面的异常来分析,u_ether.c:893

C语言代码为:

if ((dev->tx_skb_hold_count dl_max_pkts_per_xfer) && (length <(dev->port_usb->dl_max_transfer_len - dev->net->mtu)))

从上面的log看,是由NULL指针引起. 这里涉及到三个指针,dev, dev->port_usb, dev->net.

那么怎么查找到底是哪个指针有问题了?

2.3.1直接打印变量值

p dev

$1 =

可以看出已经被编译器优化了,无法用p直接打印

2.3.2 PC+偏移量法

首先确定偏移量:

p&(((struct eth_dev *)0)->net)

$1 = (struct net_device **) 0x10

(gdb) p &(((struct eth_dev*)0)->port_usb)

$2 = (struct gether **) 0x8

p (((struct gether*)0)->dl_max_transfer_len)

Cannot access memory at address 0xe4

p (((struct net_device *)0)->mtu)

Cannot access memory at address 0x1b8

可以看出dev->net和port_usb的偏移量为16和8,

dl_max_transfer_len和mtu的偏移量为:0xe4 ,0x1b8

在log中提示无法处理虚拟地址为0x000000e4

Unable to handle kernel NULL pointerdereference at virtual address 000000e4

而dl_max_transfer_len的偏移量刚好为0xe4,则可以证明port_usb为空指针.

2.3.3 汇编+偏移量+寄存器

用disassemble 打印出当前函数的汇编语言(这里只列举部分)

再查找16,8, 228(0xe4),440(0x1b8)

0xffffffc00088d27c <+432>:         bl      0xffffffc0004803c0

0xffffffc00088d280 <+436>:       ldr    w28, [x23,#104]

0xffffffc00088d284 <+440>:       ldr    w1, [x26,#-56]

0xffffffc00088d288 <+444>:       mov x0, x23

0xffffffc00088d28c <+448>:       add  w28, w28, w1

0xffffffc00088d290 <+452>:       str    w28, [x26,#-56]

0xffffffc00088d294 <+456>:       mov w27, w28

0xffffffc00088d298 <+460>:       bl      0xffffffc0009ce020

0xffffffc00088d29c <+464>:       mov x0, x22

0xffffffc00088d2a0 <+468>:       bl      0xffffffc000b52434<_raw_spin_lock_irqsave>

0xffffffc00088d2a4 <+472>:       mov x1, x0

0xffffffc00088d2a8 <+476>:       ldr    w2, [x20,#88]  /*dev->tx_skb_hold_count */

0xffffffc00088d2ac <+480>:       ldr    w4, [x20,#136]

0xffffffc00088d2b0 <+484>:       add  w2, w2, #0x1

0xffffffc00088d2b4 <+488>:       str    w2, [x20,#88]

0xffffffc00088d2b8 <+492>:       cmp w2, w4

0xffffffc00088d2bc <+496>:       b.cs  0xffffffc00088d2dc

---Type to continue, or q to quit---

0xffffffc00088d2c0 <+500>:       ldr    x2, [x20,#8] /*dev->port_usb*/

0xffffffc00088d2c4 <+504>:       ldr    x0, [x20,#16]/*dev->net*/

=> 0xffffffc00088d2c8<+508>:        ldr    w2, [x2,#228]/*dev->port_usb->dl_max_transfer_len*/

0xffffffc00088d2cc <+512>:       ldr    w0, [x0,#440]/*dev->net->mtu*/

PC在0xffffffc00088d2c8出现异常,说明x2寄存器为NULL,可以证明dev->port_usb为NULL 。

另外这里寄存器x20保存有dev的指针,x20的值为ffffffc06d3d2700 ,也可尝试用p打印这个地址,port_usb的确为NULL.

p *(struct eth_dev*)0xffffffc06d3d2700

$10 = {lock = {{rlock = {raw_lock = {lock =0}, break_lock = 0}}}, port_usb = 0x0, net =0xffffffc06d3d2000, gadget = 0xffffffc06ee132a0, req_lock = {{rlock = {

raw_lock = {lock = 1}, break_lock= 0}}}, reqrx_lock = {{rlock = {raw_lock = {lock = 0}, break_lock = 0}}},tx_reqs = {next = 0xffffffc06d3d2730,

prev = 0xffffffc06d3d2730}, rx_reqs = {next = 0xffffffc06d3d2740, prev =0xffffffc06d3d2740}, tx_qlen = 1, no_tx_req_used = 0, tx_skb_hold_count = 1,

tx_req_bufsize = 4740, rx_frames = {next = 0xffffffc06d3d2760, prev =0xffffffc06d3d2760, qlen = 0, lock = {{rlock = {raw_lock = {lock = 0},break_lock = 0}}}},

header_len = 0, ul_max_pkts_per_xfer = 1, dl_max_pkts_per_xfer = 3, wrap= 0x0, unwrap = 0x0, work = {data = {counter = 68719476704}, entry = {

next = 0xffffffc06d3d27a8, prev = 0xffffffc06d3d27a8}, func =0xffffffc00089dda8 }, rx_work = {data = {counter = 512}, entry= {

next = 0xffffffc06d3d27c8, prev = 0xffffffc06d3d27c8}, func =0xffffffc00088db5c }, rx_work1 = {data = {counter = 512},entry = {

next = 0xffffffc06d3d27e8, prev = 0xffffffc06d3d27e8}, func = 0xffffffc00089dd74}, todo = 0, zlp = false,

host_mac = "\246\030\003", }

3. 调试总结

1 调试时需要确定vmlinux与DB文件对应.不然无法精准定位, 打开vmlinux ,搜索SMP关键字,可以确认vmlinu的编译时间.

2. 内存标示

有时用p打印出变量的值全部为0x6b6b6b6b,这说明内存已经被其他地方释放

内核有定义.

#define POISON_INUSE 0x5a

/* for use-uninitialised poisoning */

#define POISON_FREE 0x6b

/* for use-after-free poisoning */

#define POISON_END 0xa5  

/* end-byte of poisoning */

本文永久更新链接: http://embeddedlinux.org.cn/emb-linux/kernel-driver/201901/25-8503.html


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Computation and Programming Using Python

Introduction to Computation and Programming Using Python

John V. Guttag / The MIT Press / 2013-7 / USD 25.00

This book introduces students with little or no prior programming experience to the art of computational problem solving using Python and various Python libraries, including PyLab. It provides student......一起来看看 《Introduction to Computation and Programming Using Python》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具