如何查看内核的调用栈

本文介绍了一种在内核调试中追踪函数调用栈的方法,包括通过ejtag读取寄存器信息,反汇编内核代码,以及通过栈指针回溯函数调用关系,详细解析了从start_kernel到cpu_wait的调用流程。

如何查看函数的调用栈

也就是根据当前cpu内寄存器的值,如何反推函数的调用栈,这种调试方法在内核调试过程中是很常见的,也算是常用的技巧。这个在追查死机等问题,可以用的上。

(1)通过ejtag来读取当前pc的地址以及sp,ra寄存器的信息

首先,我们的机器起来以后,我们用ejtag调试工具查看一下当前的寄存器的内容如下:

cpu0 -set
#set
zero:0x0 at:0x5400cce1 v0:0xffffffff818d0000 v1:0x1 
a0:0x0 a1:0x140000000000000 a2:0x0 a3:0x1 
t0:0x0 t1:0x30 t2:0x20 t3:0x2f72657070617773 
t4:0x0 t5:0xffffffff80f33d70 t6:0x0 t7:0x1 
s0:0xffffffff80f30010 s1:0xffffffff80f50000 s2:0xffffffff80f30000 s3:0xffffffff80f55838 
s4:0xffffffff81810000 s5:0x1 s6:0xffffffff81810000 s7:0xffffffff80e2ee28 
t8:0x0 t9:0xffffffff80216438 k0:0xffffffff80f33e00 k1:0xffffffff80f33e00 
gp:0xffffffff80f30000 sp:0xffffffff80f33e00 s8:0x0 ra:0xffffffff802b855c 
status:0x5400cce1 lo:0x58028e44 hi:0x0 badvaddr:0xfff19a8000 
cause:0x10000000 pc:0xffffffff80214760 epc:0xffffffff80214760

根据上面的值可以看出当前pc的地址也就是pc寄存器:pc:0xffffffff80214760这个地址。这个地址是属于内核态的地址。然后我们在ejtag下反汇编一下这地址没看看具体执行的是什么指令。反汇编如下:

cpu0 -disas 0xffffffff80214760 0x10
#disas 0xffffffff80214760 0x10
0xffffffff80214760: 03e00008 jr      ra
0xffffffff80214764: 00000000 nop     
0xffffffff80214768: 00000000 nop     
0xffffffff8021476c: 00000000 nop     
0xffffffff80214770: 00000000 nop     
0xffffffff80214774: 00000000 nop     
0xffffffff80214778: 00000000 nop     
0xffffffff8021477c: 00000000 nop     
0xffffffff80214780: 403a7000 dmfc0   k0,C0_EPC
0xffffffff80214784: 3c1b8021 lui     k1,0x8021    # 32801
0xffffffff80214788: 677b4740 daddiu  k1,k1,0x4740 # 18240
0xffffffff8021478c: 375a001f ori     k0,k0,0x1f   # 31
0xffffffff80214790: 3b5a001f xori    k0,k0,0x1f   # 31
0xffffffff80214794: 175b0002 bne     k0,k1,802147a0# 0x802147a0
0xffffffff80214798: 00000000 nop     
0xffffffff8021479c: 40ba7000 dmtc0   k0,C0_EPC

如上所示,我们这里反汇编了16条指令,地址从0xffffffff80214760开始。那么这个时候,我们需要将心在运行的内核vmlinux文件拷贝出来,用编译内核的反汇编工具,反汇编内核。使用
mips64el-redhat-linux-objdump -D vmlinux > k.log来反汇编内核内核代码并输出到k.log文件中。查看当前的地址是不是这条指令,如果是说明我们反汇编的内核就是我们现在运行的内核,否则就要检查内核或者编译器是否正确。
下面是我反汇编的内核片段:
在这里插入图片描述
如上图所示,图片中0xffffffff80214760地址刚好就是我们咋ejtag下反汇编出来的代码指令,说明我们现在反汇编的内核和运行的内核完全一致。

(2)通过sp地址来回溯函数的调用关系

下面我们就通过sp地址也就是函数的栈来查看函数的调用层次关系,还是回到上面的ejtag set出来的寄存器值,sp的值为
sp:0xffffffff80f33e00,也就是说当前函数栈指针的位置在ffffffff80f33e00,那么这个位置是属于哪个函数的栈呢,我们就要看0xffffffff80214760这个指令所在的函数,查看反汇编代码发现,这个函数在__r4k_wait这个函数内,但是这个函数进来的时候却没有操作栈指针,也就是说这个函数是一个内联函数,其本身没有栈,自身的代码被编译到了其调用位置的函数内的。那么这个时候我们要找谁调用这个函数了,就要看反汇编的代码,看看这个函数中ra的值位于哪个函数内。ra寄存器存放的是调用这个函数的地址跳转指令的吓一跳指令的地址。这时查看ra寄存器的值为 ra:0xffffffff802b855c ,这时我们查看ffffffff802b855c这个地址的指令,其代码如下:

 193036 fffffffff802b8530:_8e2258d4 _lw__v0,22740(s1)
 193037 ffffffff802b8534:_14400026 _bnez__v0,ffffffff802b85d0 <cpu_startup_entry+0x168>
 193038 ffffffff802b8538:_00000000 _nop
 193039 ffffffff802b853c:_de020000 _ld__v0,0(s0)
 193040 ffffffff802b8540:_30420004 _andi__v0,v0,0x4
 193041 ffffffff802b8544:_1440002a _bnez__v0,ffffffff802b85f0 <cpu_startup_entry+0x188>
 193042 ffffffff802b8548:_00000000 _nop
 193043 ffffffff802b854c:_0c0c05ac _jal_ffffffff803016b0 <rcu_idle_enter>
 193044 ffffffff802b8550
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值