加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 湛江站长网 (https://www.0759zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 业界 > 正文

Linux内核的栈回溯与妙用

发布时间:2018-11-15 11:24:24 所属栏目:业界 来源:今日头条
导读:副标题#e# 1 前言 说起linux内核的栈回溯功能,我想这对每个Linux内核或驱动开发人员来说,太常见了。如下演示的是linux内核崩溃的一个栈回溯打印,有了这个崩溃打印我们能很快定位到在内核哪个函数崩溃,大概在函数什么位置,大大简化了问题排查过程。 网

当内核崩溃,将会执行异常处理程序,这里以mips架构为例,崩溃函数执行流程是:

  1. do_page_fault()->die()->show_registers()->show_stacktrace()->show_backtrace() 

栈回溯的过程就是在show_backtrace()函数,arm架构最终是在dump_backtrace()函数,内核崩溃处理流程与mips不同。arm架构栈回溯过程相对来说更简单,首先讲解arm架构的栈回溯过程。

不同内核版本,内核代码有差异,本内核版本3.10.104

3.1 arm架构内核栈回溯的分析

内核实际的栈回溯代码还是有点复杂的,在正式讲解代码前,先通过一个简单演示,进一步详细的介绍栈回溯的原理。这次演示是基于fp形式的栈回溯,与上文介绍传统的fp形式栈回溯稍有差异,但是原理是一样的。

下方以伪汇编指令,演示一个完整的函数指令执行与跳转流程:C函数执行B函数,B函数执行A函数,然后A函数发生空指针崩溃。

数执行A函数,然后A函数发生空指针崩溃。

为了帮助读者理解,做一下解释,以C函数的第一条指令为例:

0x00034: C函数返回地址lr入栈指令; C函数指令1

0x00034:表示汇编指令的内存地址,反汇编的读者应该熟悉

C函数返回地址lr入栈指令:表示具体指令的意思,不再用实际汇编指令表示,理解简单

C函数指令1:表示C函数第一条指令,为了引用的简单

其中提到的lr,做过arm内核开发的读者肯定熟悉,是CPU的一个寄存器,存储函数返回地址,,当C函数跳转到B函数时,CPU自动将C函数的指令地址0x00048存入lr寄存器,这表示B函数执行完返回后,CPU将从0x00048地址取指令继续运行(mips架构是ra寄存器,先以arm为例)。

fp寄存器也是arm架构的一个CPU寄存器,英文释义是frame point,中文有称为栈帧寄存器,我们这里用来存储每个函数栈的第2片内存地址(一片内存地址4个字节,这样称呼是为了叙述方便),下方有详细讲解。为了方便读者理解,特画出函数执行过程函数栈数据示意图。

矩形框表示函数栈,初始化全为0,0x1000、0x1004等表示函数栈处于内存的地址,函数栈向下增长。每个函数前两条指令都是入栈指令,每个函数指令执行后只占用两片内存。由于C函数是初始函数,栈回溯过程C函数栈意义不大,就从C函数跳转到B函数指令开始分析。

此时fp寄存器保存的数据是C函数栈地址0x1010,原因下文会分析到。当执行C函数指令5,跳转到B函数后,栈指针sp指向地址0x100C(先假设,下文的讲解可以验证),B函数的返回地址也就是C函数的指令6的地址0x00048就会自动保存到CPU的lr寄存器,然后执行B函数指令1, 就会将0x00048存入B函数栈地址0x100C,栈指针sp减一,指向B函数栈地址0X1008。

接着执行B函数的指令2,将fp寄存器中的数据0x1010存入栈指针sp指向的内存地址0x1008,示意图已经标明。接着执行B函数指令3,将此时栈指针sp指向的地址0x1008(就是B函数的第二片内存)存入fp寄存器。

(编辑:PHP编程网 - 湛江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!