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

Linux内核的栈回溯与妙用

发布时间:2018-11-14 12:40:53 所属栏目:业界 来源:今日头条
导读:1 媒介 提及linux内核的栈回溯成果,我想这对每个Linux内核或驱动开拓职员来说,太常见了。如下演示的是linux内核瓦解的一个栈回溯打印,有了这个瓦解打印我们能很快定位到在内核哪个函数瓦解,或许在函数什么位置,大大简化了题目排查进程。 网上或多或少

假设函数挪用进程C->B->A,其它每个函数中只有一个printk打印。这种环境下函数的入栈和unwind段的信息就很法则和简朴,这里就以简朴的来讲授,便于领略。此时每个函数第一条指令一样平常是push{r4,lr},这暗示将lr和r4寄存器入栈,此时体系会将跟push{r4,lr}指令相干的编码数据0x80a8b0b0存入C函数的unwind段中,0x7fffff10跟偏移有关,可是现适用处不大。0x80a8b0b0疏散成0x80,0xa8 ,0xb0又有差异的意义,最重要的是0xa8,暗示出栈指令pop {r4 r14},r14就是lr寄存器,与push{r4,lr}入栈指令正好相反。C函数跳转到B函数后,会把B函数的返回地点0xbf004068存入B函数栈。

B函数凭证同样的要领执行,当执行到A函数最后,几个函数的栈信息和unwind段信息就如图所示。假设在A函数中瓦解了,会起首按照瓦解的pc值,找到瓦解A函数的unwind段(每个函数的指令地点和unwind段都是对应的,内核有尺度的函数可以查找)。如图所示,从地点0xbf00416c的A函数unwind段中取出数据0x80a8b0b0,说明出个中的0xa8,就知道对应的pop {r4 r14}出栈指令,响应就知道函数入栈时执行的是push{r4,lr}指令,个中有两个重要信息,一个是函数入栈时只有lr和r4寄存器入栈,而且函数栈巨细是2*4=8个字节,函数瓦解时栈指针sp指向瓦解函数A的栈顶,按照sp就能找到lr寄存器存储在A函数栈的数据0xbf004038,就是瓦解函数的返回地点,上一级函数B的指令地点,而sp+ 2*4就是上一级B函数的栈顶。

知道了B函数的指令地点和栈顶地点,就能按照指令地点找到B函数的unwind段,说明出B函数的入栈指令,凭证同样的要领,就能找到C函数的返回地点和栈顶。

这只是几个很简朴unwind栈回溯进程的演示,省去了许多细节,读者想研究清晰的话,可以阅读内核arm架构unwind_frame函数实现流程,个中最焦点的是在unwind_exec_insn函数,按照0xa8,0xb0这些跟函数入栈进程有关的编码数据,说明入栈进程的具体信息,计较出函数lr寄存器生涯在栈中的地点和上一级函数的栈顶地点。

差异的入栈指令在函数的unwind段对应差异的编码,0x80a8b0b0只是个中较量简朴的的编码,尚有0x80acb0b0,0x80aab0b0等等许多。可以执行 readelf -u .ARM.unwind_idx vmlinux查察内核init段函数的unwind段数据。好比:

这就暗示match_dev_by_uuid函数在unwind段编码数据是0x808ab0b0,0xc0008af8是该函数指令首地点。个中有效的是0xa8 ,暗示pop {r4,r14}出栈指令,0xb0暗示unwind段竣事。

为了利便读者说明对应的栈回溯内核源码,这里把要害点列出,并添加须要注释。内核版本3.10.104。

  1. arch/arm/kernel/unwind.c 

2.3 fp和unwind情势栈回溯的较量

上文先容了两种常用的栈回溯情势的根基道理,并帮助了例子声名。基于fp寄存器的栈回溯和unwind情势的栈回溯,各有利益和弱点。fp情势的栈回溯,基于APCS类型,入栈进程必必要将pc、lr、fp等4个寄存器入栈(着实没须要这样做,只需把lr和fp入栈),而且耗损的入栈指令要多(除了入栈pc、lr、fp等4个寄存器,还得将栈底地点生涯到fp),同时还挥霍了寄存器,至少fp寄存器是挥霍了,不能参加指令数据运算,CPU寄存器是很名贵的,多一个对加速指令数据运算是有起劲意义的。

而unwind情势的栈回溯,就没有这些弱点,仅仅只是将入栈相干的指令的编码生涯到unwind段中,不消把无关的寄存器生涯到栈中,也不消挥霍fp寄存器。

unwind情势栈回溯是有弱点的,起首栈回溯的速率必定比fp情势栈回溯慢,领略难度要比fp情势大许多,而且,站在开拓者角度,行使前还得对每个入栈指令编码,这都是必要事变量的。可是站在行使者角度,这些弱点影响并不大,以是此刻有许多arm32体系用的是unwind情势的栈回溯。

3 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函数指令开始说明。

(编辑:河北网)

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

热点阅读