栈回溯方法、装置、设备、存储介质和程序产品与流程

未命名 10-10 阅读:205 评论:0


1.本技术涉及计算机技术领域,尤其涉及一种栈回溯方法、装置、设备、存储介质和程序产品。


背景技术:

2.在嵌入式底层开发在软件开发、调试及测试过程中,经常会遇到因软件的设计缺陷而出现的各种宕机现象。对于嵌入式mcu软件系统的宕机问题,目前主要是根据cpu核心寄存器的内容,再结合反汇编代码,采用栈回溯的方式检索出函数之间的调用的层次关系,来排查和修复代码的设计缺陷。
3.目前,如何快速、准确地回溯函数的调用关系,已成为函待解决的技术问题。


技术实现要素:

4.本技术提供一种栈回溯方法、装置、设备、存储介质和程序产品,提高栈回溯的效率和准确率。本技术的技术方案如下:
5.本技术实施例还提供一种栈回溯方法,包括:
6.从当前函数的当前执行指令地址对所述当前函数的指令文本进行指令回溯,查找所述指令文本中是否包含压栈指令;
7.若是,则将所述当前函数的当前执行指令地址回溯到所述压栈指令的地址,且从所述压栈指令中解析出压栈数量;
8.根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。
9.可选地,所述从所述压栈指令中解析出压栈数量,包括:
10.根据所述压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
11.根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量。
12.可选地,所述根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量,包括:
13.将所述寄存器掩码从十六进制转换为二进制,得到二进制编码;
14.根据二进制编码,确定所述当前函数的栈帧被压入的寄存器的数量;
15.根据所述前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算所述当前函数的栈帧的压栈数量。
16.可选地,所述根据所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:
17.对所述指令文本从所述当前执行指令地址至所述当前函数的开始执行指令地址进行遍历;
18.若遍历到设定指令码,则根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址;
19.若未遍历到设定指令码,则根据所述压栈数量,确定所述当前函数的上一级函数
的返回地址。
20.可选地,所述根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:
21.根据所述压栈数量和所述设定指令码的数量,确定所述栈顶指针位移相对值;
22.根据所述栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
23.将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。
24.可选地,所述根据所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:
25.根据所述压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
26.将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。
27.本技术实施例还提供一种栈回溯装置,包括:
28.回溯模块,从当前函数的当前执行指令地址对所述当前函数的指令文本进行指令回溯,查找所述指令文本中是否包含压栈指令;
29.解析模块,若查找到指令文本中包含压栈指令,则用于将所述当前函数的当前执行指令地址回溯到所述压栈指令的地址,且从所述压栈指令中解析出压栈数量;
30.确定模块,用于根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。
31.可选地,所述解析模块包括解析子模块和确定子模块;
32.所述解析子模块,用于根据所述压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
33.所述确定子模块,用于根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量。
34.可选地,所述确定子模块在根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量时,用于:
35.将所述寄存器掩码从十六进制转换为二进制,得到二进制编码;
36.根据二进制编码,确定所述当前函数的栈帧被压入的寄存器的数量;
37.根据所述前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算所述当前函数的栈帧的压栈数量。
38.可选地,所述确定模块包括遍历子模块和地址确定子模块;
39.所述遍历子模块,用于对所述指令文本从所述当前执行指令地址至所述当前函数的开始执行指令地址进行遍历;
40.若遍历到设定指令码,所述地址确定子模块用于根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址;
41.若未遍历到设定指令码,所述地址确定子模块用于根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。
42.可选地,所述地址确定子模块在根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址时,用于:
43.根据所述压栈数量和所述设定指令码的数量,确定所述栈顶指针位移相对值;
44.根据所述栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
45.将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。
46.可选地,所述地址确定子模块在根据所述压栈数量,确定所述当前函数的上一级函数的返回地址时,用于:
47.根据所述压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
48.将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。
49.本技术实施例还提供一种电子设备,包括:存储器和处理器;
50.所述存储器,用于存储计算机程序;
51.所述处理器,用于执行所述计算机程序,以实现上述的方法中的各步骤。
52.本技术实施例还提供一种计算机可读存储介质,其上存储有计算机程序,其特征在于,所述计算机程序被处理器执行时实现上述方法中的各步骤。
53.本技术实施例还提供一种计算机程序产品,包括计算机程序/指令,其特征在于,所述计算机程序/指令被处理器执行时实现上述的方法中的各步骤。
54.本技术的实施例提供的技术方案至少带来以下有益效果:
55.在本技术的一些实施例中,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;若指令文本中包含压栈指令,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;基于压栈数量确定当前函数的上一级函数的返回地址,准确地确定出上一级函数的返回地址,较快的回溯函数的调用关系。
56.应当理解的是,以上的一般描述和后文的细节描述仅是示例性和解释性的,并不能限制本技术。
附图说明
57.此处的附图被并入说明书中并构成本说明书的一部分,示出了符合本技术的实施例,并与说明书一起用于解释本技术的原理,并不构成对本技术的不当限定。
58.图1为本技术示例性实施例提供的一种栈回溯方法的流程示意图;
59.图2为本技术示例性实施例提供的另一种栈回溯方法的流程示意图;
60.图3为本技术示例性实施例提供的另一种栈回溯方法的流程示意图;
61.图4a为本技术示例性实施例提供的一种栈回溯装置40的框架示意图;
62.图4b为本技术示例性实施例提供的一种解析模块42的框架示意图;
63.图4c为本技术示例性实施例提供的一种确定模块43的框架示意图;
64.图5为本技术示例性实施例提供的一种电子设备的结构示意图。
具体实施方式
65.为了使本领域普通人员更好地理解本技术的技术方案,下面将结合附图,对本申
请实施例中的技术方案进行清楚、完整地描述。
66.需要说明的是,本技术的说明书和权利要求书及上述附图中的术语“第一”、“第二”等是用于区别类似的对象,而不必用于描述特定的顺序或先后次序。应该理解这样使用的数据在适当情况下可以互换,以便这里描述的本技术的实施例能够以除了在这里图示或描述的那些以外的顺序实施。以下示例性实施例中所描述的实施方式并不代表与本技术相一致的所有实施方式。相反,它们仅是与如所附权利要求书中所详述的、本技术的一些方面相一致的装置和方法的例子。
67.在嵌入式底层开发在软件开发、调试及测试过程中,经常会遇到因软件的设计缺陷而出现的各种宕机现象。对于嵌入式mcu软件系统的宕机问题,目前主要是根据cpu核心寄存器的内容,再结合反汇编代码,采用栈回溯的方式检索出函数之间的调用的层次关系,来排查和修复代码的设计缺陷。
68.目前,主要有以下几种栈回溯的方式:
69.方式一:基于dwarf cfi的栈回溯方式;
70.方式二:基于arm ehabi的栈回溯方式;
71.方式三:基于frame pointer的栈回溯方式;
72.方式四:基于stack pointer的栈回溯方式。
73.需要说明的是,pc(program counter,程序计数器),程序当前运行的指令会放入到pc寄存器中。
74.fp(frame pointer,帧指针)。通常指向一个函数的栈帧底部,表示一个函数栈的开始位置。
75.sp(stack pointer,栈顶指针)。指向当前栈空间的顶部位置,当进行push和pop时会一起移动。
76.lr(link register,连接寄存器)。在进行函数调用时,会将函数返回后要执行的下一条指令放入lr中,对应x86架构下的返回地址。
77.在前两种方式需要在编译阶段生成特殊的代码段,所以会增大整个代码文件的长度。由于代码尺寸增加,在一般的资源受限的嵌入式设备上就会遇到取舍问题,在cortex-m设备上20%的flash资源占用较高。
78.在gcc编译器生成代码中,fp寄存器的保存值是压栈后的地址,由于压栈寄存器的个数不同,所以回溯根本无法正确定位lr寄存器,而在clang编译器上的行为反倒不同,fp帧指针会直接加回栈顶指向lr寄存器,其中,clang编译器是一个c语言、c++、objective-c语言的轻量级编译器。所以如果使用clang是可以正常完成栈回朔的,而arm的clang是需要license,在传统的低成本芯片中,没有人会花大价格来购买arm的toolchain(工具链),再加上fp的加入会导致应用程序的执行性能变慢,所以clang的方案也无法成型。
79.在上述栈回溯方式四中,基于stack pointer的栈回朔方法,由于所有的父节点函数调用都需要将lr寄存器压栈,所以我们只需要通过sp栈顶指针遍历栈帧来查找lr寄存器即可。基于stack pointer的栈回朔方法也存在一个弊端,在传统编程过程中,我们会在函数中申请很多栈上变量,在变量没有正常初始化的情况下,栈上的值都是随即数,这就有一个问题了,如果随即数刚好是上一次函数调用后压栈的lr寄存器,那么通过lr寄存器的方案将会错误的将这个地址当作当前函数的lr寄存器而被记录下来:
80.示例代码如下:
[0081][0082]
info和cb都是没有被初始化的,在这个情况下如果初值是上次入栈的lr寄存器,那么回朔将失败。
[0083]
i don't understand this objection.for a simple function the additional overhead is literally nothing-for example《https://godbolt.org/z/bhvm2t》,gcc generates:
[0084]
push{r3,r4,r7,lr}
[0085]
add r7,sp,#0
[0086]
while clang adds a small constant to make r7 point to the previous r7 on the stack,with lrimmediately above-zero overhead:
[0087]
push{r4,r6,r7,lr}
[0088]
add r7,sp,#8
[0089]
for a more complex function where the compiler has to spill r8-r11 one extra instruction isrequired to generate the right frame layout-gcc generates:
[0090]
push{r3,r4,r5,r6,r7,r8,r9,lr}
[0091]
add r7,sp,#0
[0092]
while clang generates:
[0093]
push
ꢀꢀꢀꢀ
{r4,r5,r6,r7,lr}
[0094]
add
ꢀꢀꢀꢀꢀ
r7,sp,#12
[0095]
push.w{r8,r9,r11}
[0096]
结合上述栈回溯方法存在的技术问题,在本技术的一些实施例中,从当前函数的
当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;若指令文本中包含压栈指令,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;基于压栈数量确定当前函数的上一级函数的返回地址,准确地确定出上一级函数的返回地址,较快的回溯函数的调用关系。
[0097]
以下结合附图,详细说明本技术各实施例提供的技术方案。
[0098]
图1为本技术示例性实施例提供的一种栈回溯方法的流程示意图。如图1所示,栈回溯方法包括:
[0099]
s101:从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;
[0100]
s102:若指令文本中包含压栈指令,将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;
[0101]
s103:若指令文本中不包含压栈指令,停止回溯过程;
[0102]
s104:根据压栈数量,确定当前函数的上一级函数的返回地址。
[0103]
在本实施例中,上述栈回溯方法可应用于系统发生异常宕机时的调用栈回溯的场景,该方法可以由嵌入式系统的调用栈回溯装置来执行,该装置可以采用软件和/或硬件实现,一般可集成在电子设备中。示例性地,用于实现根据本技术实施例的嵌入式系统的调用栈回溯方法,电子设备可以被实现为诸如平板电脑、个人电脑等智能终端上。
[0104]
在本实施例中,指定编译命令对程序源代码文件进行编译,得到编译结果文件。在我加入指定编译命令,也即启用fp寄存器所限定的栈帧,就可以得到当前函数的栈帧指针,从而得到当前函数的栈帧。
[0105]
需要说明的是,指令stmdb sp!,{r0-r12,lr}的含义为:
[0106]
sp=sp-4,先压lr,sp=lr(即将lr中的内容放入sp所指的内存地址)。sp=sp-4,再压r12,sp=r12。sp=sp-4,再压r11,sp=r11.....sp=sp-4,最后压r0,sp=r0。
[0107]
在本技术的一些实施例中,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本是否包含压栈指令。例如,sp栈顶指针的值为48,即sp=48,pc寄存器中保存的当前执行指令地址为0x10834830,即pc=0x10834830。从0x10834830开始从高地址向低地址进行指令回溯,
[0108]
10834826:e92d 43b0 stmdb sp!,{r4,r5,r7,r8,r9,lr}
[0109]
....
[0110]
10834830。
[0111]
当回溯到地址10834826,发现该地址指向的指令码为e92d(stmdb),那么就认为这是一个压栈指令。
[0112]
在一些实施例中,从压栈指令中解析出压栈数量。一种可实现的方式为,根据压栈指令的语法规则,从压栈指令中解析出寄存器掩码;根据寄存器掩码,确定对当前函数的栈帧的压栈数量。
[0113]
需要说明的是以指令stmdb举例,语法是stmdb《c》《rn》{!},《registers》
[0114]
10834826:e92d 43b0 stmdb sp!,{r4,r5,r7,r8,r9,lr}
[0115]
其中,43b0就是寄存器掩码
[0116]
十六进制寄存器掩码43b0=二进制编码100001110110000;
[0117]
其中每个1就代表了一个入栈寄存器
[0118]
111011=(r4,r5,r7,r8,r9)
[0119]
10000=lr。
[0120]
可选地,据寄存器掩码,确定对当前函数的栈帧的压栈数量。一种可实现的方式为,将寄存器掩码从十六进制转换为二进制,得到二进制编码;根据二进制编码,确定当前函数的栈帧被压入的寄存器的数量;根据前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算当前函数的栈帧的压栈数量。
[0121]
例如,10834826:e92d 43b0 stmdb sp!,{r4,r5,r7,r8,r9,lr}
[0122]
....
[0123]
10834830;
[0124]
通过e92d 43b0,将寄存器掩码从十六进制转换为二进制:
[0125]
十六进制寄存器掩码43b0=二进制编码100001110110000;
[0126]
其中,二进制编码中包括6个1,说明当前栈帧被压入了6个寄存器,6个寄存器在32位操作系统上,每个寄存器为4个字节,压栈数量为4*6=24个。
[0127]
在一些实施例中,根据压栈数量,确定当前函数的上一级函数的返回地址,对指令文本从当前执行指令地址至当前函数的开始执行指令地址进行遍历;若遍历到设定指令码,则根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址;若未遍历到设定指令码,则根据压栈数量,确定当前函数的上一级函数的返回地址。
[0128]
需要说明的是,设定指令码包括但不限于以下几种:
[0129]
#define imask_t_push_lo 0xff00/*push{reglist}(not lr)*/
[0130]
#define imask_t_push 0xff00/*push{reglist}(inc lr)*/
[0131]
#define imask_t_vpush_16 0xffbf8f00/*vpush d*/
[0132]
#define imask_t_vpush_8 0xffbf8f00/*vpush s*/
[0133]
#define imask_t_sub_sp_16 0xff80/*sub sp,#*/
[0134]
#define imask_t_sub_sp_32 0xf2ff8f00/*subw sp,sp,#*/
[0135]
#define imask_t_sub_w_sp_32 0xfbff8f00/*sub.w sp,sp,#*/。
[0136]
在上述实施例中,根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址。一种可实现的方式为,根据压栈数量和设定指令码的数量,确定栈顶指针位移相对值;根据栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0137]
例如,10834826:e92d 43b0 stmdb sp!,{r4,r5,r7,r8,r9,lr}
[0138]
1083482a:b086
ꢀꢀꢀꢀꢀꢀꢀꢀ
sub sp,#24
[0139]
10834830
[0140]
若遍历到设定指令码,当前的sp=48,若压栈数量为24,则sp=48-24=24,sp=24,sub指令在代码中将sp减去了24,所以在带有sub的栈上,我们需要拿sp=24再加上24,最终就能找到lr寄存器的位置。
[0141]
在上述实施例中,根据压栈数量,确定当前函数的上一级函数的返回地址。一种可实现的方式为,根据压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位
置;将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0142]
例如,当前的sp=48,若压栈数量为24,则sp=48-24=24,sp=24的位置即为当前函数的上一级函数的返回地址,即lr寄存器的位置。
[0143]
以下结合具体例子,对本技术栈回溯方法作出说明:
[0144]
sp栈顶指针的值为48,即sp=48,pc寄存器中保存的当前执行指令地址为0x10834830,即pc=0x10834830。从0x10834830开始从高地址向低地址进行指令回溯,
[0145]
10834826:e92d 43b0 stmdb sp!,{r4,r5,r7,r8,r9,lr}
[0146]
....
[0147]
10834830。
[0148]
当回溯到地址10834826,发现该地址指向的指令码为e92d(stmdb),那么就认为这是一个压栈指令。
[0149]
通过e92d 43b0,将寄存器掩码从十六进制转换为二进制:
[0150]
十六进制寄存器掩码43b0=二进制编码100001110110000;
[0151]
其中,二进制编码中包括6个1,说明当前栈帧被压入了6个寄存器,6个寄存器在32位操作系统上,每个寄存器为4个字节,压栈数量为4*6=24个。
[0152]
若遍历到设定指令码,当前的sp=48,若压栈数量为24,则sp=48-24=24,sp=24,sub指令在代码中将sp减去了24,所以在带有sub的栈上,我们需要拿sp=24再加上24,最终就能找到lr寄存器的位置。
[0153]
基于上述各实施例的描述,图2为本技术示例性实施例提供的另一种栈回溯方法的流程示意图。如图2所示,该方法包括:
[0154]
s201:从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;
[0155]
s202:若指令文本包括压栈指令,将当前函数的当前执行指令地址回溯到压栈指令的地址;
[0156]
s203:根据压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
[0157]
s204:根据寄存器掩码,确定对当前函数的栈帧的压栈数量;
[0158]
s205:根据压栈数量,确定当前函数的上一级函数的返回地址。
[0159]
在本实施例中,关于本实施例的各步骤的实现方式均可参见前述各实施例的描述,本实施例也可取得前述各实施例对应的有益效果,在此不再赘述。
[0160]
基于上述各实施例的描述,图3为本技术示例性实施例提供的另一种栈回溯方法的流程示意图。如图3所示,该方法包括:
[0161]
s301:从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;
[0162]
s302:若指令文本包括压栈指令,将当前函数的当前执行指令地址回溯到压栈指令的地址;
[0163]
s303:根据压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
[0164]
s304:根据寄存器掩码,确定对当前函数的栈帧的压栈数量;
[0165]
s305:对指令文本从当前执行指令地址至当前函数的开始执行指令地址进行遍历;
[0166]
s306:若遍历到设定指令码,则根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址;
[0167]
s307:若未遍历到设定指令码,则根据压栈数量,确定当前函数的上一级函数的返回地址。
[0168]
在本实施例中,关于本实施例的各步骤的实现方式均可参见前述各实施例的描述,本实施例也可取得前述各实施例对应的有益效果,在此不再赘述。
[0169]
在本技术的上述方法实施例中,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;若指令文本中包含压栈指令,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;基于压栈数量确定当前函数的上一级函数的返回地址,准确地确定出上一级函数的返回地址,较快的回溯函数的调用关系。
[0170]
图4a为本技术示例性实施例提供的一种栈回溯装置40的框架示意图。参见图4a,该装置包括回溯模块41,解析模块42和确定模块43。
[0171]
其中,回溯模块41,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;
[0172]
解析模块42,若查找到指令文本中包含压栈指令,则用于将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;
[0173]
确定模块43,用于根据压栈数量,确定当前函数的上一级函数的返回地址。
[0174]
可选地,图4b为本技术示例性实施例提供的一种解析模块42的框架示意图。解析模块42包括解析子模块421和确定子模块422;
[0175]
解析子模块421,用于根据压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
[0176]
确定子模块422,用于根据寄存器掩码,确定对当前函数的栈帧的压栈数量。
[0177]
可选地,确定子模块422在根据寄存器掩码,确定对当前函数的栈帧的压栈数量时,用于:
[0178]
将寄存器掩码从十六进制转换为二进制,得到二进制编码;
[0179]
根据二进制编码,确定当前函数的栈帧被压入的寄存器的数量;
[0180]
根据前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算当前函数的栈帧的压栈数量。
[0181]
可选地,图4c为本技术示例性实施例提供的一种确定模块43的框架示意图。确定模块43包括遍历子模块431和地址确定子模块432;
[0182]
遍历子模块431,用于对指令文本从当前执行指令地址至当前函数的开始执行指令地址进行遍历;
[0183]
若遍历到设定指令码,地址确定子模块432用于根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址;
[0184]
若未遍历到设定指令码,地址确定子模块432用于根据压栈数量,确定当前函数的上一级函数的返回地址。
[0185]
可选地,地址确定子模块432在根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址时,用于:
[0186]
根据压栈数量和设定指令码的数量,确定栈顶指针位移相对值;
[0187]
根据栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
[0188]
将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0189]
可选地,地址确定子模块432在根据压栈数量,确定当前函数的上一级函数的返回地址时,用于:
[0190]
根据压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
[0191]
将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0192]
关于上述实施例中的装置,其中各个模块执行操作的具体方式已经在有关该方法的实施例中进行了详细描述,此处将不做详细阐述说明。
[0193]
图5为本技术示例性实施例提供的一种电子设备的结构示意图。如图5所示,该电子设备包括:存储器501和处理器502。另外,该电子设备还包括电源组件503、通信组件504和显示屏505等必要组件。
[0194]
存储器501,用于存储计算机程序,并可被配置为存储其它各种数据以支持在电子设备上的操作。这些数据的示例包括用于在电子设备上操作的任何应用程序或方法的指令。
[0195]
存储器501,可以由任何类型的易失性或非易失性存储设备或者它们的组合实现,如静态随机存取存储器(sram),电可擦除可编程只读存储器(eeprom),可擦除可编程只读存储器(eprom),可编程只读存储器(prom),只读存储器(rom),磁存储器,快闪存储器,磁盘或光盘。
[0196]
通信组件504,用于与其他设备进行数据传输。
[0197]
处理器502,可执行存储器501中存储的计算机指令,以用于:从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;
[0198]
若是,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;
[0199]
根据压栈数量,确定当前函数的上一级函数的返回地址。
[0200]
可选地,处理器502在从压栈指令中解析出压栈数量时,用于:
[0201]
根据压栈指令的语法规则,从压栈指令中解析出寄存器掩码;
[0202]
根据寄存器掩码,确定对当前函数的栈帧的压栈数量。
[0203]
可选地,处理器502根据寄存器掩码,确定对当前函数的栈帧的压栈数量时,用于:
[0204]
将寄存器掩码从十六进制转换为二进制,得到二进制编码;
[0205]
根据二进制编码,确定当前函数的栈帧被压入的寄存器的数量;
[0206]
根据前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算当前函数的栈帧的压栈数量。
[0207]
可选地,处理器502在根据压栈数量,确定当前函数的上一级函数的返回地址时,用于:
[0208]
对指令文本从当前执行指令地址至当前函数的开始执行指令地址进行遍历;
[0209]
若遍历到设定指令码,则根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址;
[0210]
若未遍历到设定指令码,则根据压栈数量,确定当前函数的上一级函数的返回地址。
[0211]
可选地,处理器502根据设定指令码的数量和压栈数量,确定当前函数的上一级函数的返回地址时,用于:
[0212]
根据压栈数量和设定指令码的数量,确定栈顶指针位移相对值;
[0213]
根据栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
[0214]
将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0215]
可选地,处理器502在根据压栈数量,确定当前函数的上一级函数的返回地址时,用于:
[0216]
根据压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;
[0217]
将更新后的栈顶指针的位置所指向的地址,作为当前函数的上一级函数的返回地址。
[0218]
相应地,本技术实施例还提供一种存储有计算机程序的计算机可读存储介质。当计算机可读存储介质存储计算机程序,且计算机程序被一个或多个处理器执行时,致使一个或多个处理器执行图1方法实施例中的各步骤。
[0219]
相应地,本技术实施例还提供一种计算机程序产品,计算机程序产品包括计算机程序/指令,计算机程序/指令被处理器执行图1的方法实施例中的各步骤。
[0220]
上述图5中的通信组件被配置为便于通信组件所在设备和其他设备之间有线或无线方式的通信。通信组件所在设备可以接入基于通信标准的无线网络,如wifi,2g、3g、4g/lte、5g等移动通信网络,或它们的组合。在一个示例性实施例中,通信组件经由广播信道接收来自外部广播管理系统的广播信号或广播相关信息。在一个示例性实施例中,通信组件还包括近场通信(nfc)模块,以促进短程通信。例如,在nfc模块可基于射频识别(rfid)技术,红外数据协会(irda)技术,超宽带(uwb)技术,蓝牙(bt)技术和其他技术来实现。
[0221]
上述图5中的电源组件,为电源组件所在设备的各种组件提供电力。电源组件可以包括电源管理系统,一个或多个电源,及其他与为电源组件所在设备生成、管理和分配电力相关联的组件。
[0222]
上述图5中的显示屏包括屏幕,其屏幕可以包括液晶显示屏(lcd)和触摸面板(tp)。如果屏幕包括触摸面板,屏幕可以被实现为触摸屏,以接收来自用户的输入信号。触摸面板包括一个或多个触摸传感器以感测触摸、滑动和触摸面板上的手势。触摸传感器可以不仅感测触摸或滑动动作的边界,而且还检测与触摸或滑动操作相关的持续时间和压力。
[0223]
上述电子设备还可以包括音频组件。
[0224]
音频组件,可被配置为输出和/或输入音频信号。例如,音频组件包括一个麦克风(mic),当音频组件所在设备处于操作模式,如呼叫模式、记录模式和语音识别模式时,麦克风被配置为接收外部音频信号。所接收的音频信号可以被进一步存储在存储器或经由通信
组件发送。在一些实施例中,音频组件还包括一个扬声器,用于输出音频信号。
[0225]
在本技术的上述装置、设备、存储介质和程序产品实施例中,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;若指令文本中包含压栈指令,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;基于压栈数量确定当前函数的上一级函数的返回地址,准确地确定出上一级函数的返回地址,较快的回溯函数的调用关系。
[0226]
本领域内的技术人员应明白,本发明的实施例可提供为方法、系统、或计算机程序产品。因此,本发明可采用完全硬件实施例、完全软件实施例、或结合软件和硬件方面的实施例的形式。而且,本发明可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、cd-rom、光学存储器等)上实施的计算机程序产品的形式。
[0227]
本发明是参照根据本发明实施例的方法、设备(系统)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的装置。
[0228]
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令装置的制造品,该指令装置实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
[0229]
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
[0230]
在一个典型的配置中,计算设备包括一个或多个处理器(cpu)、输入/输出接口、网络接口和内存。
[0231]
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(ram)和/或非易失性内存等形式,如只读存储器(rom)或闪存(flash ram)。内存是计算机可读介质的示例。
[0232]
计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(pram)、静态随机存取存储器(sram)、动态随机存取存储器(dram)、其他类型的随机存取存储器(ram)、只读存储器(rom)、电可擦除可编程只读存储器(eeprom)、快闪记忆体或其他内存技术、只读光盘只读存储器(cd-rom)、数字多功能光盘(dvd)或其他光学存储、磁盒式磁带,磁带磁磁盘存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
[0233]
需要说明的是,在本文中,诸如“第一”和“第二”等之类的关系术语仅仅用来将一
个实体或者操作与另一个实体或操作区分开来,而不一定要求或者暗示这些实体或操作之间存在任何这种实际的关系或者顺序。而且,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个
……”
限定的要素,并不排除在包括要素的过程、方法、物品或者设备中还存在另外的相同要素。
[0234]
以上仅是本技术的具体实施方式,使本领域技术人员能够理解或实现本技术。对这些实施例的多种修改对本领域的技术人员来说将是显而易见的,本文中所定义的一般原理可以在不脱离本技术的精神或范围的情况下,在其它实施例中实现。因此,本技术将不会被限制于本文的这些实施例,而是要符合与本文所公开的原理和新颖特点相一致的最宽的范围。

技术特征:
1.一种栈回溯方法,其特征在于,包括:从当前函数的当前执行指令地址对所述当前函数的指令文本进行指令回溯,查找所述指令文本中是否包含压栈指令;若是,则将所述当前函数的当前执行指令地址回溯到所述压栈指令的地址,且从所述压栈指令中解析出压栈数量;根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。2.根据权利要求1所述的方法,其特征在于,所述从所述压栈指令中解析出压栈数量,包括:根据所述压栈指令的语法规则,从压栈指令中解析出寄存器掩码;根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量。3.根据权利要求2所述的方法,其特征在于,所述根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量,包括:将所述寄存器掩码从十六进制转换为二进制,得到二进制编码;根据二进制编码,确定所述当前函数的栈帧被压入的寄存器的数量;根据所述前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算所述当前函数的栈帧的压栈数量。4.根据权利要求1所述的方法,其特征在于,所述根据所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:对所述指令文本从所述当前执行指令地址至所述当前函数的开始执行指令地址进行遍历;若遍历到设定指令码,则根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址;若未遍历到设定指令码,则根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。5.根据权利要求4所述的方法,其特征在于,所述根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:根据所述压栈数量和所述设定指令码的数量,确定所述栈顶指针位移相对值;根据所述栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。6.根据权利要求4所述的方法,其特征在于,所述根据所述压栈数量,确定所述当前函数的上一级函数的返回地址,包括:根据所述压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。7.一种栈回溯装置,其特征在于,包括:回溯模块,从当前函数的当前执行指令地址对所述当前函数的指令文本进行指令回溯,查找所述指令文本中是否包含压栈指令;
解析模块,若查找到指令文本中包含压栈指令,则用于将所述当前函数的当前执行指令地址回溯到所述压栈指令的地址,且从所述压栈指令中解析出压栈数量;确定模块,用于根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。8.根据权利要求7所述的栈回溯装置,其特征在于,所述解析模块包括解析子模块和确定子模块;所述解析子模块,用于根据所述压栈指令的语法规则,从压栈指令中解析出寄存器掩码;所述确定子模块,用于根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量。9.根据权利要求8所述的栈回溯装置,其特征在于,所述确定子模块在根据所述寄存器掩码,确定对所述当前函数的栈帧的压栈数量时,用于:将所述寄存器掩码从十六进制转换为二进制,得到二进制编码;根据二进制编码,确定所述当前函数的栈帧被压入的寄存器的数量;根据所述前函数的栈帧被压入的寄存器的数量和当前操作系统位数,计算所述当前函数的栈帧的压栈数量。10.根据权利要求7所述的栈回溯装置,其特征在于,所述确定模块包括遍历子模块和地址确定子模块;所述遍历子模块,用于对所述指令文本从所述当前执行指令地址至所述当前函数的开始执行指令地址进行遍历;若遍历到设定指令码,所述地址确定子模块用于根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址;若未遍历到设定指令码,所述地址确定子模块用于根据所述压栈数量,确定所述当前函数的上一级函数的返回地址。11.根据权利要求10所述的栈回溯装置,其特征在于,所述地址确定子模块在根据所述设定指令码的数量和所述压栈数量,确定所述当前函数的上一级函数的返回地址时,用于:根据所述压栈数量和所述设定指令码的数量,确定所述栈顶指针位移相对值;根据所述栈顶指针位移相对值,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。12.根据权利要求10所述的栈回溯装置,其特征在于,所述地址确定子模块在根据所述压栈数量,确定所述当前函数的上一级函数的返回地址时,用于:根据所述压栈数量,对栈顶指针的位置进行更新,得到更新后的栈顶指针的位置;将所述更新后的栈顶指针的位置所指向的地址,作为所述当前函数的上一级函数的返回地址。13.一种电子设备,其特征在于,包括:存储器和处理器;所述存储器,用于存储计算机程序;所述处理器,用于执行所述计算机程序,以实现如权利要求1-6中任一项所述的方法中的各步骤。14.一种计算机可读存储介质,其上存储有计算机程序,其特征在于,所述计算机程序
被处理器执行时实现权利要求1-6中任一项所述的方法中的各步骤。15.一种计算机程序产品,包括计算机程序/指令,其特征在于,所述计算机程序/指令被处理器执行时实现权利要求1-6中任一项所述的方法中的各步骤。

技术总结
本申请涉及计算机技术领域,尤其涉及一种栈回溯方法、装置、设备、存储介质和程序产品。在本申请的一些实施例中,从当前函数的当前执行指令地址对当前函数的指令文本进行指令回溯,查找指令文本中是否包含压栈指令;若指令文本中包含压栈指令,则将当前函数的当前执行指令地址回溯到压栈指令的地址,且从压栈指令中解析出压栈数量;基于压栈数量确定当前函数的上一级函数的返回地址,准确地确定出上一级函数的返回地址,较快的回溯函数的调用关系。较快的回溯函数的调用关系。较快的回溯函数的调用关系。


技术研发人员:安超
受保护的技术使用者:北京小米移动软件有限公司
技术研发日:2022.03.23
技术公布日:2023/10/7
版权声明

本文仅代表作者观点,不代表航空之家立场。
本文系作者授权航家号发表,未经原创作者书面授权,任何单位或个人不得引用、复制、转载、摘编、链接或以其他任何方式复制发表。任何单位或个人在获得书面授权使用航空之家内容时,须注明作者及来源 “航空之家”。如非法使用航空之家的部分或全部内容的,航空之家将依法追究其法律责任。(航空之家官方QQ:2926969996)

飞行汽车 https://www.autovtol.com/

分享:

扫一扫在手机阅读、分享本文

相关推荐