oops堆栈分析实例

2023-10-07 07:32
文章标签 分析 实例 堆栈 oops

本文主要是介绍oops堆栈分析实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文基于Linux-4.0,根据一个crash现场的实例,根据堆栈中的数据,反推整个函数调用流程,由于本例子存在oops,也会直接打印出backtrace,最终可以与我们的分析结果做一下比较,看看分析是否正确。

/ # echo c > /proc/sysrq-trigger
sysrq: SysRq : Trigger a crash
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = ffff8000779f9000
[00000000] *pgd=00000000b79fb003, *pud=00000000b7cb3003, *pmd=0000000000000000
Internal error: Oops: 94000046 [#1] PREEMPT SMP
Modules linked in:
CPU: 1 PID: 642 Comm: sh Not tainted 4.0.0 #1
Hardware name: linux,dummy-virt (DT)
task: ffff800077f46300 ti: ffff800077804000 task.ti: ffff800077804000
PC is at sysrq_handle_crash+0x14/0x1c
LR is at __handle_sysrq+0x124/0x194
pc : [<ffff800000377cd4>] lr : [<ffff800000378688>] pstate: 60000145
sp : ffff800077807dd0
x29: ffff800077807dd0 x28: ffff800077804000
x27: ffff80000056d000 x26: 0000000000000040
x25: 000000000000011a x24: 0000000000000015
x23: 0000000000000000 x22: 0000000000000007
x21: 0000000000000063 x20: ffff8000007ae000
x19: ffff8000007c18e8 x18: 00000000005fd000
x17: 0000000000602000 x16: ffff80000019705c
x15: 0000000000001000 x14: 0ffffffffffffffe
x13: 0000000000000038 x12: 0101010101010101
x11: ffff8000007ae000 x10: 000000000000007c
x9 : 0000000000000002 x8 : 0000000000000001
x7 : 000000000000007c x6 : 0000000000000030
x5 : 0000000000002208 x4 : 0000000000000000
x3 : 0000000000000000 x2 : ffff800077804000
x1 : 0000000000000000 x0 : 0000000000000001Process sh (pid: 642, stack limit = 0xffff800077804028)
Stack: (0xffff800077807dd0 to 0xffff800077808000)
7dc0:                                     77807e10 ffff8000 00378b04 ffff8000
7de0: 00000002 00000000 fffffffb ffffffff 77807ec8 ffff8000 1c84b550 00000000
7e00: 60000000 00000000 1c84b550 00000000 77807e30 ffff8000 001f2f5c ffff8000
7e20: 785b8c00 ffff8000 1c84b550 00000000 77807e50 ffff8000 00196650 ffff8000
7e40: 78607d00 ffff8000 00000002 00000000 77807e90 ffff8000 001970a0 ffff8000
7e60: 78607d00 ffff8000 78607d00 ffff8000 1c84b550 00000000 00000002 00000000
7e80: 60000000 00000000 00000000 00000000 da4cd8c0 0000ffff 00085c30 ffff8000
7ea0: 00000000 00000000 1c84b550 00000000 ffffffff ffffffff 00409398 00000000
7ec0: 00200200 00000000 00000000 00000000 00000001 00000000 1c84b550 00000000
7ee0: 00000002 00000000 00000000 00000000 1c84b550 00000000 1c84b560 00000000
7f00: 80808080 00808080 fefeff62 fefefefe 00000040 00000000 fefefeff fefefefe
7f20: 7f7f7f7f 7f7f7f7f 01010101 01010101 00000008 00000000 00000400 00000000
7f40: 00502b5c 00000050 00001000 00000000 00000000 00000000 00602000 00000000
7f60: 005fd000 00000000 00000001 00000000 1c84b550 00000000 00000002 00000000
7f80: 00601000 00000000 1c84b550 00000000 00000020 00000000 00000000 00000000
7fa0: 00601000 00000000 005820f0 00000000 da4cdfba 0000ffff da4cd8c0 0000ffff
7fc0: 0044a504 00000000 da4cd180 0000ffff 00409398 00000000 60000000 00000000
7fe0: 00000001 00000000 00000040 00000000 00000000 00000000 00000000 00000000
Call trace:
[<ffff800000377cd4>] sysrq_handle_crash+0x14/0x1c
[<ffff800000378b00>] write_sysrq_trigger+0x50/0x64
[<ffff8000001f2f58>] proc_reg_write+0x54/0x84
[<ffff80000019664c>] vfs_write+0x98/0x1d8
[<ffff80000019709c>] SyS_write+0x40/0xa0
Code: 52800020 b903a420 d5033e9f d2800001 (39000020)
---[ end trace 2fd7253656805fb6 ]---

SP和FP(x29)寄存器中的值都是ffff800077807dd0,从后面信息可以进行堆栈回溯:

ffff8000 77807dd0 --- FP
ffff8000 77807e10 --- FP'(从FP寄存器地址处读取)
ffff8000 77807e30 --- FP''(从FP'寄存器地址处读取)
ffff8000 77807e50 --- FP'''(从FP''寄存器地址处读取)
ffff8000 77807e90 --- FP''''(从FP'''寄存器地址处读取)
0000ffff da4cd8c0 --- 该值已经不是内核地址了,所以已经超出了内核堆栈区域

我们找到了FP地址后,可以进一步找到LR寄存器中保存的返回地址:

ffff8000 00378b04 --- FP + 8
ffff8000 001f2f5c --- FP' + 8
ffff8000 00196650 --- FP'' + 8
ffff8000 001970a0 --- FP''' + 8

接下来看是一个一个查看对应的堆栈调用关系,从第一个LR地址开始查看,进入gdb调试vmlinux:

aarch64-linux-gnu-gdb vmlinux

跳转关系1
使用反汇编指令:

(gdb) disassemble 0xffff800000378b04
Dump of assembler code for function write_sysrq_trigger:0xffff800000378ab0 <+0>:	stp	x29, x30, [sp,#-32]!0xffff800000378ab4 <+4>:	mov	x29, sp0xffff800000378ab8 <+8>:	str	x19, [sp,#16]0xffff800000378abc <+12>:	mov	x19, x20xffff800000378ac0 <+16>:	cbz	x2, 0xffff800000378b04 <write_sysrq_trigger+84>0xffff800000378ac4 <+20>:	mov	x0, sp0xffff800000378ac8 <+24>:	mov	x2, x10xffff800000378acc <+28>:	and	x3, x0, #0xffffffffffffc0000xffff800000378ad0 <+32>:	mov	x0, #0xfffffffffffffff2    	// #-140xffff800000378ad4 <+36>:	ldr	x3, [x3,#8]0xffff800000378ad8 <+40>:	adds	x2, x2, #0x10xffff800000378adc <+44>:	ccmp	x2, x3, #0x2, cc0xffff800000378ae0 <+48>:	cset	x4, ls0xffff800000378ae4 <+52>:	cbz	x4, 0xffff800000378b08 <write_sysrq_trigger+88>0xffff800000378ae8 <+56>:	mov	w2, #0x0                   	// #00xffff800000378aec <+60>:	ldrb	w3, [x1]0xffff800000378af0 <+64>:	uxtb	w3, w30xffff800000378af4 <+68>:	cbnz	w2, 0xffff800000378b08 <write_sysrq_trigger+88>0xffff800000378af8 <+72>:	mov	w1, #0x0                   	// #00xffff800000378afc <+76>:	mov	w0, w30xffff800000378b00 <+80>:	bl	0xffff800000378564 <__handle_sysrq>0xffff800000378b04 <+84>:	mov	x0, x190xffff800000378b08 <+88>:	ldr	x19, [sp,#16]0xffff800000378b0c <+92>:	ldp	x29, x30, [sp],#320xffff800000378b10 <+96>:	ret

关键的在如下的位置:

   0xffff800000378b00 <+80>:	bl	0xffff800000378564 <__handle_sysrq>0xffff800000378b04 <+84>:	mov	x0, x19

我们对应的LR地址为0xffff800000378b04,该值-4就应该是跳转指令:所以上一级函数是write_sysrq_trigger,跳转进入的函数symbol为__handle_sysrq。

跳转关系2

使用反汇编指令:

(gdb) disassemble 0xffff8000001f2f5c
Dump of assembler code for function proc_reg_write:0xffff8000001f2f04 <+0>:	stp	x29, x30, [sp,#-32]!0xffff8000001f2f08 <+4>:	mov	w4, #0x0                   	// #00xffff8000001f2f0c <+8>:	mov	x29, sp0xffff8000001f2f10 <+12>:	stp	x19, x20, [sp,#16]0xffff8000001f2f14 <+16>:	ldr	x5, [x0,#32]0xffff8000001f2f18 <+20>:	ldur	x19, [x5,#-32]0xffff8000001f2f1c <+24>:	add	x5, x19, #0x640xffff8000001f2f20 <+28>:	add	w6, w4, #0x10xffff8000001f2f24 <+32>:	dmb	ish0xffff8000001f2f28 <+36>:	ldxr	w7, [x5]0xffff8000001f2f2c <+40>:	cmp	w7, w40xffff8000001f2f30 <+44>:	b.ne	0xffff8000001f2f3c <proc_reg_write+56>0xffff8000001f2f34 <+48>:	stxr	w8, w6, [x5]0xffff8000001f2f38 <+52>:	cbnz	w8, 0xffff8000001f2f28 <proc_reg_write+36>0xffff8000001f2f3c <+56>:	dmb	ish0xffff8000001f2f40 <+60>:	cmp	w4, w70xffff8000001f2f44 <+64>:	b.ne	0xffff8000001f2f78 <proc_reg_write+116>0xffff8000001f2f48 <+68>:	ldr	x4, [x19,#40]0xffff8000001f2f4c <+72>:	mov	x20, #0xfffffffffffffffb    	// #-50xffff8000001f2f50 <+76>:	ldr	x4, [x4,#24]0xffff8000001f2f54 <+80>:	cbz	x4, 0xffff8000001f2f60 <proc_reg_write+92>0xffff8000001f2f58 <+84>:	blr	x40xffff8000001f2f5c <+88>:	mov	x20, x00xffff8000001f2f60 <+92>:	mov	x0, x190xffff8000001f2f64 <+96>:	bl	0xffff8000001f2bf4 <unuse_pde>0xffff8000001f2f68 <+100>:	mov	x0, x200xffff8000001f2f6c <+104>:	ldp	x19, x20, [sp,#16]0xffff8000001f2f70 <+108>:	ldp	x29, x30, [sp],#320xffff8000001f2f74 <+112>:	ret0xffff8000001f2f78 <+116>:	mov	w4, w70xffff8000001f2f7c <+120>:	tbz	w7, #31, 0xffff8000001f2f20 <proc_reg_write+28>0xffff8000001f2f80 <+124>:	mov	x20, #0xfffffffffffffffb    	// #-50xffff8000001f2f84 <+128>:	b	0xffff8000001f2f68 <proc_reg_write+100>
End of assembler dump.

关键的在如下的位置:

   0xffff8000001f2f58 <+84>:	blr	x40xffff8000001f2f5c <+88>:	mov	x20, x0

我们对应的LR地址为0xffff8000001f2f5c,该值-4就应该是跳转指令:blr x4 实际上是指跳转到x4寄存器中的一个地址处。返回地址位于proc_reg_write函数中,因此该函数应该就是上一级调用的函数,至于这个x4寄存器地址对应的symbol,实际上就是write_sysrq_trigger,因为是从它返回过来的。

跳转关系3

使用反汇编指令:

(gdb) disassemble 0xffff800000196650
Dump of assembler code for function vfs_write:0xffff8000001965b4 <+0>:	stp	x29, x30, [sp,#-64]!0xffff8000001965b8 <+4>:	mov	x29, sp0xffff8000001965bc <+8>:	stp	x19, x20, [sp,#16]0xffff8000001965c0 <+12>:	stp	x21, x22, [sp,#32]0xffff8000001965c4 <+16>:	str	x23, [sp,#48]0xffff8000001965c8 <+20>:	ldr	w4, [x0,#68]0xffff8000001965cc <+24>:	tbz	w4, #1, 0xffff80000019676c <vfs_write+440>0xffff8000001965d0 <+28>:	tbz	w4, #18, 0xffff800000196774 <vfs_write+448>0xffff8000001965d4 <+32>:	mov	x4, sp0xffff8000001965d8 <+36>:	and	x5, x4, #0xffffffffffffc0000xffff8000001965dc <+40>:	mov	x4, x10xffff8000001965e0 <+44>:	ldr	x5, [x5,#8]0xffff8000001965e4 <+48>:	adds	x4, x4, x20xffff8000001965e8 <+52>:	ccmp	x4, x5, #0x2, cc0xffff8000001965ec <+56>:	cset	x6, ls0xffff8000001965f0 <+60>:	cbz	x6, 0xffff800000196750 <vfs_write+412>0xffff8000001965f4 <+64>:	mov	x21, x30xffff8000001965f8 <+68>:	mov	x22, x10xffff8000001965fc <+72>:	mov	x3, x20xffff800000196600 <+76>:	mov	x1, x00xffff800000196604 <+80>:	mov	x19, x00xffff800000196608 <+84>:	mov	x2, x210xffff80000019660c <+88>:	mov	w0, #0x1                   	// #10xffff800000196610 <+92>:	bl	0xffff8000001964c4 <rw_verify_area>0xffff800000196614 <+96>:	sxtw	x20, w00xffff800000196618 <+100>:	tbnz	x20, #63, 0xffff8000001966c0 <vfs_write+268>0xffff80000019661c <+104>:	ldr	x1, [x19,#32]0xffff800000196620 <+108>:	ldrh	w0, [x1]0xffff800000196624 <+112>:	and	w0, w0, #0xf0000xffff800000196628 <+116>:	cmp	w0, #0x8, lsl #120xffff80000019662c <+120>:	b.eq	0xffff800000196758 <vfs_write+420>0xffff800000196630 <+124>:	ldr	x0, [x19,#40]0xffff800000196634 <+128>:	ldr	x4, [x0,#24]0xffff800000196638 <+132>:	cbz	x4, 0xffff8000001966d8 <vfs_write+292>0xffff80000019663c <+136>:	mov	x2, x200xffff800000196640 <+140>:	mov	x3, x210xffff800000196644 <+144>:	mov	x1, x220xffff800000196648 <+148>:	mov	x0, x190xffff80000019664c <+152>:	blr	x40xffff800000196650 <+156>:	mov	x20, x0

关键的在如下的位置:

   0xffff80000019664c <+152>:	blr	x40xffff800000196650 <+156>:	mov	x20, x0

我们对应的LR地址为0xffff800000196650,该值-4就应该是跳转指令:blr x4 ,至于这个x4寄存器地址对应的symbol,实际上就是proc_reg_write,该函数运行结束后会返回到vfs_write中,因此上一级的函数是vfs_write。

跳转关系4

使用反汇编指令:

(gdb) disassemble 0xffff8000001970a0
Dump of assembler code for function SyS_write:0xffff80000019705c <+0>:	stp	x29, x30, [sp,#-64]!0xffff800000197060 <+4>:	mov	x29, sp0xffff800000197064 <+8>:	stp	x19, x20, [sp,#16]0xffff800000197068 <+12>:	stp	x21, x22, [sp,#32]0xffff80000019706c <+16>:	mov	x21, x10xffff800000197070 <+20>:	mov	x22, x20xffff800000197074 <+24>:	bl	0xffff8000001b2f14 <__fdget_pos>0xffff800000197078 <+28>:	ands	x20, x0, #0xfffffffffffffffc0xffff80000019707c <+32>:	mov	x19, x00xffff800000197080 <+36>:	b.eq	0xffff8000001970f4 <SyS_write+152>0xffff800000197084 <+40>:	add	x3, x29, #0x400xffff800000197088 <+44>:	ldr	x4, [x20,#112]0xffff80000019708c <+48>:	mov	x1, x210xffff800000197090 <+52>:	mov	x2, x220xffff800000197094 <+56>:	mov	x0, x200xffff800000197098 <+60>:	str	x4, [x3,#-8]!0xffff80000019709c <+64>:	bl	0xffff8000001965b4 <vfs_write>0xffff8000001970a0 <+68>:	mov	x21, x00xffff8000001970a4 <+72>:	tbnz	x21, #63, 0xffff8000001970b0 <SyS_write+84>0xffff8000001970a8 <+76>:	ldr	x0, [x29,#56]0xffff8000001970ac <+80>:	str	x0, [x20,#112]0xffff8000001970b0 <+84>:	tbnz	w19, #1, 0xffff8000001970cc <SyS_write+112>0xffff8000001970b4 <+88>:	tbnz	w19, #0, 0xffff8000001970d8 <SyS_write+124>0xffff8000001970b8 <+92>:	mov	x0, x210xffff8000001970bc <+96>:	ldp	x19, x20, [sp,#16]0xffff8000001970c0 <+100>:	ldp	x21, x22, [sp,#32]0xffff8000001970c4 <+104>:	ldp	x29, x30, [sp],#640xffff8000001970c8 <+108>:	ret0xffff8000001970cc <+112>:	add	x0, x20, #0x480xffff8000001970d0 <+116>:	bl	0xffff8000005611bc <mutex_unlock>0xffff8000001970d4 <+120>:	tbz	w19, #0, 0xffff8000001970b8 <SyS_write+92>0xffff8000001970d8 <+124>:	mov	x0, x200xffff8000001970dc <+128>:	bl	0xffff800000198128 <fput>0xffff8000001970e0 <+132>:	mov	x0, x210xffff8000001970e4 <+136>:	ldp	x19, x20, [sp,#16]0xffff8000001970e8 <+140>:	ldp	x21, x22, [sp,#32]0xffff8000001970ec <+144>:	ldp	x29, x30, [sp],#640xffff8000001970f0 <+148>:	ret0xffff8000001970f4 <+152>:	mov	x21, #0xfffffffffffffff7    	// #-90xffff8000001970f8 <+156>:	b	0xffff8000001970b8 <SyS_write+92>
End of assembler dump.

关键的在如下的位置:

   0xffff80000019709c <+64>:	bl	0xffff8000001965b4 <vfs_write>0xffff8000001970a0 <+68>:	mov	x21, x0

我们对应的LR地址为0xffff8000001970a0,该值-4就应该是跳转指令:bl 0xffff8000001965b4 <vfs_write> ,这里看起来就很清晰了,从SyS_write函数跳转到vfs_write函数,完成之后又返回到了SyS_write函数,因此上一级的函数是SyS_write。

总结

从上面的分析过程,我们可以梳理出函数的调用关系如下:

SyS_write --> vfs_write --> proc_reg_write --> write_sysrq_trigger --> __handle_sysrq --> sysrq_handle_crash

看看这个结果是不是与dumpstack中的一致,说明整个分析过程是正确的。哈哈~

这篇关于oops堆栈分析实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/156965

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断