程序调用栈创建方法、栈回溯方法和装置与流程

文档序号:33422240发布日期:2023-03-11 00:09阅读:40来源:国知局
程序调用栈创建方法、栈回溯方法和装置与流程

1.本技术涉及信息技术领域,尤其涉及一种程序调用栈创建方法、栈回溯方法和装置。


背景技术:

2.调用栈是在程序执行过程中,为可执行文件中的代码和数据在内存中分配的存储空间。调用栈中包括多个栈帧,每个栈帧对应一个函数。两个相邻栈帧分别对应的函数具有调用关系。
3.在程序代码中,当一种高级编程语言编写的函数调用由另一种高级编程语言编写函数时,或者当运行时库对应的高级编程语言和程序代码对应的高级编程语言不同时,在程序代码执行过程中,为程序代码所维护的调用栈中的会出现不同类型的栈帧。在此种场景下,若出现栈回溯(stack trace)需求,栈回溯过程中对调用栈中各栈帧类型的识别会成为影响栈回溯性能的关键因素。
4.现有技术中,对于上述具有不同类型栈帧的调用栈,主要通过两种方式来在栈回溯过程中识别调用栈中各栈帧的栈帧类型:(1)基于程序计数(program count,pc)寄存器地址搜索;(2)基于运行时维护相同栈帧类型的数据链表。
5.采用上述现有技术进行栈帧类型识别时,需要在运行时中维护pc数据表或数据链表,因而对非栈回溯场景有较大影响,且利用上述方式一进行栈回溯时速度较慢。


技术实现要素:

6.本技术实施例提供了一种程序调用栈创建方法、栈回溯方法和装置,可以在满足对非回栈场景无影响的前提下,最大限度的提升栈回溯性能。
7.第一方面,本技术提供了一种程序调用栈的创建方法,所述方法包括:获取第一程序,所述第一程序中包括第一函数;在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于所述第二函数的第二栈帧以及对应于第三函数的第三栈帧,其中,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述运行时库中的函数或所述第一程序中的函数,所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型。
8.其中,栈帧的类型与栈帧对应的函数的高级编程语言的种类相匹配;例如,当一个栈帧对应的函数是由java编写的,那么该栈帧对应的栈帧类型为java栈帧。
9.其中,第一程序可以包括由一种或多种高级编程语言所编写的多个函数。
10.应当理解,本技术实施例在运行第一程序过程中,会在第一函数和第三函数之间
添加一个第二函数,使得第一函数和第二函数之间具有调用关系,第二函数和第三函数之间具有调用关系,也即是表明在高级语言代码中第一函数和第三函数具有调用关系。
11.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
12.其中,第二函数可以是通过编译器和手写汇编生成的汇编指令(即由汇编语言所表示),该汇编指令后续可通过汇编器翻译成二进制可执行文件(或称为机器码)。利用编译器或手写汇编生成相应添加的边界函数(即第二函数),而不是在高级语言代码(即第一程序)中实现,可以提升边界函数的可复用性。
13.应当理解,对于调用关系为:第一函数调用第二函数、第二函数调用第三函数的三个函数而言,程序运行过程中,第一函数首先被执行,在运行第一函数的过程中,调用第二函数以执行第二函数,在执行第二函数的过程中,再调用第三函数以执行第三函数,可见,在此种场景下,从时序来说,第三函数为后被执行的函数。
14.从技术效果上看,对于在高级语言代码中具有两个调用关系的函数,即第一函数和第三函数而言,当其分别对应的高级编程语言的种类不同时,在为包含第一函数的第一程序创建调用栈的过程中,会在第一函数和第三函数之间添加一个函数(即第二函数),并保存指向第二函数的第一返回地址以及该第一返回地址对应的标签。由于该第一返回地址对应的标签指示了第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,因而对于后续需要进行栈回溯的场景,可以基于第一返回地址对应的标签来识别第一栈帧、第二栈帧和第三栈帧的栈帧类型。相对于现有技术在栈回溯过程中需要在运行时库中维护大型返回地址数据表或数据结构,并通过查表来确定栈帧类型的方式,本技术实施例可以消除运行时库中返回地址数据表或数据结构的维护开销以及所需的查表时长,从而有效缩短栈回溯时长,可以在对非栈回溯场景无影响的前提下,大幅提升栈回溯性能。
15.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中包含的返回地址。
16.从技术效果上看,第一函数、第二函数和第三函数可以具有上述两种调用关系,但第一返回地址为后被执行的函数对应栈帧中的返回地址,因而在后续栈回溯过程中,由于先获得的是后被执行函数对应栈帧中的返回地址,因而可以基于该返回地址对应的标签确定先被执行函数对应栈帧的栈帧类型,有效缩短栈回溯时长,提升栈回溯性能。
17.在一种可行的实施方式中,所述第一返回地址保存于返回地址集合,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述每个返回地址对应的标签指示了所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示了所述每个返回地址指向的函数的调用函数对应栈帧的栈帧类型。
18.应当理解,对于具有与上述第一函数、第二函数和第三函数关系相同的任意其它三个函数而言,该其它三个函数中最后被执行函数对应栈帧中包含的返回地址以及返回地址对应的标签也会保存于返回地址集合中。
19.从技术效果上看,利用返回地址集合保存所有指向边界函数(即程序运行过程中
添加的函数)的返回地址,由于返回地址集合中每个返回地址对应的标签具有与第一返回地址对应标签相同的特性,因而在后续栈回溯过程中,可以直接判断当前栈帧中返回地址是否位于返回地址集合中来确定相应栈帧的栈帧类型,相对现有技术而言,可以有效缩短栈回溯的时长,答复提升栈回溯性能。
20.在一种可行的实施方式中,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关;所述方法还包括:对所述第四栈帧进行栈回溯,包括:获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;当所述第二返回地址属于所述返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第四栈帧中的返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
21.其中,边界函数为运行第一程序过程中添加的函数,第四栈帧为上述调用栈中的任意非边界函数对应的栈帧。
22.其中,当第一函数调用第二函数,第二函数调用第三函数时,在栈回溯过程中,第四栈帧、第五栈帧和第六栈帧可以分别为第三栈帧、第二栈帧和第一栈帧;当第三函数调用第二函数,第二函数调用第一函数时,在栈回溯过程中,第四栈帧、第五栈帧和第六栈帧可以分别为上述的第一栈帧、第二栈帧和第三栈帧。
23.从技术效果上看,由于在创建调用栈的过程中将指向边界函数的返回地址加入返回地址集合中,因而在栈回溯过程中可以直接根据返回地址是否属于返回地址集合,以及返回地址集合中返回地址对应的标签确定相关栈帧的栈帧类型,相对于现有技术中在运行时库中维护大型返回地址数据表或数据结构,并通过查表来确定栈帧类型的方式,本技术实施例可以消除运行时库中返回地址数据表或数据结构的维护开销以及所需的查表时长,从而有效缩短栈回溯时长,可以在对非栈回溯场景无影响的前提下,大幅提升栈回溯性能。
24.在一种可行的实施方式中,所述第二类型和所述第三类型是所述第二返回地址对应的标签所指示的两个栈帧类型。
25.其中,第二返回地址对应的标签可以是数据报文格式,该报文中的信息可以指示第四栈帧、第五栈帧和第六栈帧对应的栈帧类型,对于分别指示第四栈帧、第五栈帧和第六栈帧的栈帧类型的报文信息的顺序,本技术不限定。
26.在一种可行的实施方式中,获取所述第四栈帧中的帧指针fp;若所述fp指向所述调用栈的栈底,结束所述第四栈帧的栈回溯过程。
27.从技术效果上看,在基于返回地址确定相应栈帧的类型之前,可以通过fp来判断当前栈帧是否位于调用栈的栈底,从而保证当栈回溯过程到达调用栈的栈底时,顺利结束栈回溯过程。
28.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与所述运行时库的高级编程语言的种类有关。
29.从技术效果上看,在启动栈回溯过程时,由于调用栈栈顶处栈帧对应的函数为运
行时库中的函数,因而通过将调用栈栈顶处栈帧的类型设置为与运行时库中函数对应高级编程语言相同的栈帧类型,确保后续未遇到边界函数时,将当前栈帧对应函数的调用函数对应栈帧的类型直接设置为第一类型,从而确保栈回溯过程中准确识别每个栈帧的栈帧类型。
30.第二方面,本技术提供了一种调用栈的栈回溯方法,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关,所述方法包括:获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;当所述第二返回地址属于返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第二返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
31.在一种可行的实施方式中,所述第二类型和所述第三类型为所述第二返回地址对应的标签所指示的两个栈帧类型;所述每个返回地址对应的标签指示所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示所述每个返回地址指向的函数的调用者函数对应栈帧的栈帧类型。
32.在一种可行的实施方式中,获取所述第四栈帧中的帧指针fp;若所述fp指向所述调用栈的栈底时,结束所述栈回溯过程。
33.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与运行时库的高级编程语言的种类有关。
34.在一种可行的实施方式中,所述调用栈是在调用运行时库运行第一程序的过程中创建的,所述第一程序中包括第一函数,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于第二函数的第二栈帧,以及对应于第三函数的第三栈帧,其中,所述第二函数在创建所述调用栈的过程中添加的函数,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述第一程序中的函数或所述运行时库中的函数,且所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,所述第一返回地址属于所述返回地址集合。
35.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中的返回地址。
36.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于
编译后的高级语言代码库或者编译后的运行时代码库中。
37.第三方面,本技术提供了一种程序调用栈创建装置,所述装置包括:获取单元,用于获取第一程序,所述第一程序中包括第一函数;处理单元,用于在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于所述第二函数的第二栈帧以及对应于第三函数的第三栈帧,其中,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述运行时库中的函数或所述第一程序中的函数,所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;存储单元,用于保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型。
38.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中包含的返回地址。
39.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
40.在一种可行的实施方式中,所述第一返回地址保存于返回地址集合,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述每个返回地址对应的标签指示了所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示了所述每个返回地址指向的函数的调用函数对应栈帧的栈帧类型。
41.在一种可行的实施方式中,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关;所述处理单元,还用于对所述第四栈帧进行栈回溯;在所述栈回溯过程中,所述处理单元具体用于:指示所述获取单元获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;以及当所述第二返回地址属于所述返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第四栈帧中的返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
42.在一种可行的实施方式中,所述第二类型和所述第三类型是所述第二返回地址对应的标签所指示的两个栈帧类型。
43.在一种可行的实施方式中,所述获取单元,还用于获取所述第四栈帧中的帧指针fp;所述处理单元,还用于在所述fp指向所述调用栈的栈底时,结束所述第四栈帧的栈回溯过程。
44.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与所述运行时库的高级编程语言的种类有关。
45.第四方面,本技术实施例提供一种栈回溯装置,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关;所述装置包括:获取单元,用于获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;处理单元,用于当所述第二返回地址属于返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;或者当所述第二返回地址不属于所述返回地址集合时,所述处理单元将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
46.在一种可行的实施方式中,所述第二类型和所述第三类型为所述第二返回地址对应的标签所指示的两个栈帧类型;所述每个返回地址对应的标签指示所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示所述每个返回地址指向的函数的调用者函数对应栈帧的栈帧类型。
47.在一种可行的实施方式中,所述获取单元,还用于获取所述第四栈帧中的帧指针fp;所述处理单元,还用于在所述fp指向所述调用栈的栈底时,结束所述第四栈帧的栈回溯过程。
48.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与运行时库的高级编程语言的种类有关。
49.在一种可行的实施方式中,所述调用栈是在调用运行时库运行第一程序的过程中创建的,所述第一程序中包括第一函数,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于第二函数的第二栈帧,以及对应于第三函数的第三栈帧,其中,所述第二函数在创建所述调用栈的过程中添加的函数,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述第一程序中的函数或所述运行时库中的函数,且所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;所述装置还包括存储单元,所述存储单元用于:保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,所述第一返回地址属于所述返回地址集合。
50.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中的返回地址。
51.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于
编译后的高级语言代码库或者编译后的运行时代码库中。
52.第五方面,本技术提供了一种芯片系统,所述芯片系统包括至少一个处理器,存储器和接口电路,所述存储器、所述接口电路和所述至少一个处理器通过线路互联,所述至少一个存储器中存储有指令;所述指令被所述处理器执行时,上述第一方面和/或第二方面中任一所述的方法得以实现。
53.第六方面,本技术提供了一种计算机可读存储介质,所述计算机可读存储介质中存储有程序指令,当所述程序指令在一个或多个处理器上运行时,实现上述第一方面和/或第二方面中任一项所述的方法。
54.第七方面,本技术提供了一种计算机程序产品,其特征在于,当所述计算机程序产品在计算机设备上运行时,上述第一方面和/或第二方面中任一项所述的方法得以实现。
附图说明
55.以下对本技术实施例用到的附图进行介绍。
56.图1是本技术实施例中的一种系统架构示意图;
57.图2是本技术实施例中的一种程序调用栈的结构示意图;
58.图3是本技术实施例中一种程序调用栈创建方法的流程示意图;
59.图4是本技术实施例中一种程序调用栈进行栈回溯的流程图;
60.图5是本技术实施例中一种栈回溯过程的示意图;
61.图6是本技术实施例中一种栈回溯方法的流程示意图;
62.图7是本技术实施例中一种程序调用栈创建装置的结构示意图;
63.图8是本技术实施例中一种栈回溯装置的结构示意图;
64.图9是本技术实施例中一种计算机设备的硬件结构示意图。
具体实施方式
65.下面结合本技术实施例中的附图对本技术实施例进行描述。本技术的说明书和权利要求书及所述附图中的术语“第一”、“第二”和“第三”是用于区别不同对象,而不是用于描述特定顺序;同理,“第四”“第五”和“第六”也是用于区别不同对象,而不是用于描述特定顺序。此外,术语“包括”和“具有”以及它们任何变形,意图在于覆盖不排他的包含。例如包含了一系列步骤或单元的过程、方法、系统、产品或设备没有限定于已列出的步骤或单元,而是可选地还包括没有列出的步骤或单元,或可选地还包括对于这些过程、方法、产品或设备固有的其它步骤或单元。在本文中提及“实施例”意味着,结合实施例描述的特定特征、结构或特性可以包含在本技术的至少一个实施例中。在说明书中的各个位置出现该短语并不一定均是指相同的实施例,也不是与其它实施例互斥的独立的或备选的实施例。本领域技术人员显式地和隐式地理解的是,本文所描述的实施例可以与其它实施例相结合。
66.首先对本技术实施例中的相关术语进行解释:
67.(1)栈帧:指为一个函数调用单独分配的那部分栈空间。每个函数对应的栈帧可以用于保存函数的局部变量、向被调用函数传递的参数、返回函数的返回值,以及保存函数的返回地址。
68.(2)栈回溯:也成为回栈。指基于程序调用栈向上回溯每一层函数的栈帧的过程。
69.(3)混合栈:当高级语言代码中包含由不同高级编程语言编写的函数,或高级语言代码的编程语言与运行时函数的编程语言不同时,在运行此段高级语言代码过程中,所创建的调用栈中包含不同类型的栈帧,此种调用栈即为混合栈,在混合栈中每个栈帧的类型与该栈帧所对应函数的高级编程语言相匹配。
70.(4)返回地址:返回地址是指从被调用函数返回后,调用函数应该继续执行的指令地址,即调用点指令(发生函数调用的代码所对应的指令)的下一条指令的地址,即被调用函数对应栈帧中包含的返回地址指向调用函数。
71.(5)运行时runtime库:也称为运行时环境,运行时系统,也简称为运行时,是支撑高级语言代码执行的代码库,大部分场景下它的编程语言不同于需要执行代码的高级语言。
72.(6)运行时函数:运行时中的函数,大部分场景下运行时库中的函数不同于需要执行的高级语言程序中的函数。
73.(7)编译器:用来编译需执行的高级语言代码和支撑高级语言代码执行的运行时代码库的工具。编译后,高级语言代码和运行时代码库都变为二进制可执行程序。
74.(8)帧指针(frame pointer,fp):指向当前栈帧的栈底。
75.(9)栈指针(stack pointer,sp):指向调用栈的栈顶。
76.(10)代码逻辑:程序员直接用高级语言编写的产品代码,使得该代码在产品中的实现预期的行为。产品可以是各种终端设备,如手机、电脑、手表、手环或车载终端等。
77.(11)高级编程语言(high-level programming language,hlpl):是一种独立于机器,面向过程或对象的编程语言。它是以人类的日常语言为基础的一种编程语言,使用一般人易于接受的文字或字符来表示,有较高的可读性,以方便对电脑认知较浅的人亦可以大概明白其内容。其可以包括basic、java、c、c++、python等。而汇编语言则是一种介于高级编程语言和机器语言(也称机器码)之间的编程语言,通常不认为属于高级编程语言。
78.下面对与本技术相关的现有技术作简单介绍。现有技术中在混合栈的栈回溯过程中,识别栈帧类型的方式主要有两种:
79.(一)基于pc地址搜索
80.此种方式需要在运行时库中创建并维护一个大型的pc数据表,数据表中保存了每个栈帧中返回地址和栈帧类型的对应关系。在栈回溯过程中,在数据表中搜索指向每个函数的返回地址,来确定该返回地址所位于栈帧的栈帧类型。
81.由于此种方式需要运行时维护pc数据表,因而每次系统库(保存高级语言代码编译后的机器码)加载或卸载时都需要对该表进行更新,而该数据表只有在栈回溯的过程中会被使用,非回栈场景中,会增加运行时的额外开销。此外,在栈回溯过程中,每个栈帧中的返回地址都需要在pc数据表中搜索一遍才能确认该栈帧的类型,会导致回栈性能较差。
82.(二)运行时库中维护数据链表
83.此方案需要在运行时库维护一个栈帧类型的数据链表,每次系统库中的业务代码调进运行时的时候,在该链表中插入系统库中高级语言的栈帧信息,当从运行时返回系统库中的业务代码时,再将该链表中的信息删除掉。当系统库中的业务代码发起回栈时,在栈回溯操作中,直接从栈帧类型的数据链表中拿到高级语言的栈信息,并开始回栈。
84.因为在每次业务代码调用运行时库中的函数时都要更新链表数据,而如果后续没
有发起栈回溯操作的时,此种更新操作则是属于无意义的开销,因此,该方案对非栈回溯场景的性能影响较大。
85.请参见图1,图1为本技术实施例中的一种系统架构示意图。如图1所示,系统架构100包括系统库110和运行时库120。系统库110中包含用于执行的业务代码111(即下文实施例中的第二程序),即对高级语言代码(即下文实施例中的第一程序)编译后得到的机器码。运行时库120为业务代码111的执行提供相应的运行环境;具体地,运行时库120可以提供相应接口,以供业务代码111执行时调用运行时库中的函数121。
86.在执行业务代码111的过程中,会为业务代码111创建对应的调用栈,该调用栈中包括多个栈帧,该多个栈帧中的每个栈帧分别对应业务代码或运行时库中的一个函数。业务代码执行过程中,可以根据具体地业务需求执行或者不执行栈回溯过程。
87.下面介绍本技术实施例的应用场景。
88.本技术实施例可以应用于各种需要进行栈回溯的场景中,例如程序崩溃或调用栈异常等,具体可以是垃圾回收(garbage collection,gc)等需要进行栈回溯的场景。
89.(1)程序崩溃
90.当程序执行过程中发生崩溃时,可以执行栈回溯以打印并保存错误程序的信息,即可以精确定位哪一级函数在调用中出现了崩溃。
91.(2)调用栈异常
92.当程序执行的执行过程并未崩溃,代码可以正常执行,运行过程出现了预期异常时,可以进行栈回溯来获取整个运行过程的相关信息。
93.垃圾回收:指运行垃圾回收gc算法来释放存储器中超级块的过程,具体指将多个超级块中的有效页搬移到一个空闲超级块中,以释放该多个超级块,并用来承载后续有效数据的写入。
94.请参见图2,图2为本技术实施例中的一种程序调用栈的结构示意图。如图2所示,程序调用栈可以包括多个栈帧。下面以调用栈中的三个相邻栈帧(栈帧1、栈帧2和栈帧3)为例来描述调用栈的结构。
95.如图2所示,从栈底到栈顶,依次为栈帧3、栈帧2和栈帧1,其分别对应函数3、函数2和函数1,即栈帧3中存储与函数3相关的参数、栈帧2中存储与函数2相关的参数、栈帧1中存储于函数1相关的参数。此三个函数的调用关系为:函数3调用函数2、函数2调用函数1。
96.其中,每个栈帧中保存有返回地址、帧指针和n个参数,n为正整数。每个栈帧中的返回地址指向该栈帧对应函数的调用函数。例如,在函数2调用函数1过程中,调用结束后,调用点指令的下一条指令的存储地址会映射为返回地址1,返回地址1在函数1执行完毕后返回函数2,以使函数2继续运行。栈指针fp指向当前栈帧的栈底,例如,帧指针1指向栈帧1的栈底地址。
97.请参见图3,图3是本技术实施例中一种程序调用栈创建方法的流程示意图。如图3所示,方法300包括步骤s310、s320和s330。
98.步骤s310:获取第一程序,所述第一程序中包括第一函数。
99.其中,第一程序可以是由程序开发者利用高级编程语言编写的程序,该高级语言可以是basic、java、c、c++或python等,本技术对此不限定。第一程序中可以包括多层具有调用关系的函数,该多层具有调用关系的函数可以由一种高级编程语言进行编写,也可以
由多种不同的高级编程语言进行编写,本技术对此不限定。
100.步骤s320:在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于所述第二函数的第二栈帧以及对应于第三函数的第三栈帧,其中,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述运行时库中的函数或所述第一程序中的函数,所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同。
101.具体地,上述在调用运行时库运行第一程序的过程中,添加第二函数以及创建调用栈,包括:对由高级语言编写的第一程序进行编译,得到编译后的二进制可执行程序;同时对由高级语言编写的运行时库进行编译,得到编译后的运行时代码库(二进制)。然后,由处理器等硬件调用编译后的运行时代码库,以运行上述第一程序对应的二进制可执行文件,并创建调用栈,调用栈中包括运行过程中每个被执行函数对应的栈帧。
102.其中,上述编译过程可以包括预处理阶段、编译阶段、汇编阶段和链接阶段,本技术对编译过程不进行展开赘述。
103.其中,二进制可执行程序为可以直接由处理器等硬件执行的机器语言指令,即二进制可执行文件。
104.其中,运行时库可以为第一程序的运行提供相应的运行环境。具体地,运行时库可以包含第一程序执行的时所需要的代码库,框架,平台等。应当注意,在运行第一程序时,同时也需要对运行时库进行相应的编译,然后基于编译后的运行时库为第一程序的运行提供相应的运行环境。
105.具体地,在基于编译后的运行时库来执行第一程序的过程中,可以调用运行时库提供的接口来调用编译后运行时库中的相应函数来支撑第一程序的执行。
106.其中,第一函数为第一程序中的任意一个函数。
107.其中,第一函数和第三函数在高级语言代码中为具有调用关系的两个函数。具体地,第一函数和第三函数可以为第一程序中的两个具有调用关系的函数,或者第一函数为第一程序中的函数,第三函数为运行时库中的函数。
108.上述在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,具体包括:对于在高级语言中具有调用关系,且由不同高级语言编写的第一函数和第三函数而言,在运行过程中,会在第一函数和第三函数之间添加第二函数。同时在调用栈中为第二函数维护对应的第二栈帧。
109.其中,第二栈帧对应的第二函数与第一栈帧对应的第一函数具有调用关系,且第二栈帧对应的第二函数与第三栈帧对应的第三函数具有调用关系。
110.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中包含的返回地址。
111.具体地,对于上述描述的第一函数、第二函数和第三函数,其可以具有以下两种调用关系:
112.(一)第一函数调用第二函数,第二函数调用第三函数
113.第一返回地址为第三函数对应的第三栈帧中包含的返回地址,第三栈帧中包含的返回地址指向第二函数,第二栈帧中包含的返回地址指向第一函数。
114.此种情况下,第一函数和第三函数所属于的代码库可以包含两种情况:(1)第一函数和第三函数可以同时为第一程序中的函数,即在第一程序中,第一函数调用第三函数,且第一函数和第三函数对应的高级编程语言不同,例如,第一函数可以是通过java语言编写的,第三函数是通过c++编写的。(2)第一函数为第一程序中的函数,第三函数为运行时库中的函数。在第一程序执行的过程中第一函数会调用运行时库中的第三函数,由于第一函数对应的高级编程语言和第三函数对应的高级编程语言不同,可以在第一函数的第三函数之间添加第二函数,使得第一函数通过第二函数来调用第三函数;此时,第一函数为第一程序中多层函数调用关系中的最后一层函数。
115.(二)第三函数调用第二函数,第二函数调用第一函数
116.第一返回地址为第一函数对应的第一栈帧中包含的返回地址,第一栈帧中包含的返回地址指向第二函数,第二栈帧中包含的返回地址指向第三函数。
117.此种情况下,第一函数和第三函数所属于的代码库可以包含两种情况:(1)第一函数和第三函数可以同时为第一程序中的函数,即在第一程序中,第三函数调用第一函数,且第一函数和第三函数对应的高级编程语言不同,例如,第一函数可以是通过java语言编写的,第三函数是通过c++编写的。(2)第一函数为第一程序中的函数,第三函数为运行时库中的函数。在第一程序执行的过程中运行时库中的第三函数会调用第一程序中的第一函数,由于第一函数对应的高级编程语言和第三函数对应的高级编程语言不同,可以在第一函数的第三函数之间添加第二函数,使得第三函数通过第二函数来调用第一函数;此时,第一函数为第一程序中多层函数调用关系中的第一层函数。
118.其中,第一函数对应的高级编程语言指编写第一函数的高级编程语言,本技术实施例中的其它函数对应的高级编程语言同理,此处不再赘述。
119.从技术效果上看,第一函数、第二函数和第三函数可以具有上述两种调用关系,但第一返回地址为后被执行的函数对应栈帧中的返回地址,因而在后续栈回溯过程中,由于先获得的是后被执行函数对应栈帧中的返回地址,因而可以基于该返回地址对应的标签确定先被执行函数对应栈帧的栈帧类型,有效缩短栈回溯时长,提升栈回溯性能。
120.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
121.其中,第二函数也可称为边界函数。第二函数可以是通过编译器和手写汇编生成的汇编指令(即由汇编语言所表示),该汇编指令后续可通过汇编器翻译成二进制可执行文件(或称为机器码)。第二函数与第一程序中的代码逻辑、运行时库中的代码逻辑都无关,即第二函数不存在于由高级语言编写的代码库和运行时库中。
122.从技术效果上看,利用编译器或手写汇编生成相应添加的边界函数(即第二函数),而不是在高级语言代码(即第一程序)中实现,可以提升边界函数的可复用性。
123.步骤s330:保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型。
124.上述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,具体指:(1)当第一函数调用第二函数,第二函数调用第三函数时,后被执行的函数为第三函数。具体地,在程序运行过程中,第一函数首先被执行,在运行第一函数的过程中,会调用第二函数以执行第二函数,在执行第二函数的过程中,再调用第三函数以执行第三函数,在此种场景下,从时序上看,第三函数为后被执行的函数;或者,(2)当第三函数调用第二函数,第二函数调用第一函数时,后被执行的函数为第一函数。在程序运行过程中,第三函数首先被执行,在运行第三函数的过程中,会通过调用第二函数来执行第二函数,在执行第二函数的过程中,会通过调用第一函数来执行第一函数,从时序上看,第一函数为后被执行的函数。
125.具体地,在运行第一程序以及创建调用栈的过程中,保存第一返回地址和第一返回地址对应的标签,第一返回地址对应的标签指示了第一栈帧的类型、第二栈帧的类型和第三栈帧的类型。
126.其中,栈帧的类型和与栈帧对应的函数的高级编程语言相匹配。例如,当一个栈帧对应的函数是由java编写的,那么该栈帧对应的栈帧类型为java栈帧。
127.下面通过两个示例来描述返回地址对应的标签的可行的数据报文格式:
128.示例一:当第三函数调用第二函数,第二函数调用第一函数时,第一返回地址位于第一栈帧中,第一返回地址对应的标签可以是unwindpcforn2cstub,该标签中的字符“n”可以用于指示第三函数为native,即运行时库中的函数,此时第三栈帧的类型与编写运行时库的高级编程语言相匹配;标签中的字符“c”可以用于指示第一函数为由高级语言编写的第一程序中的函数,因而第一栈帧的类型与第一程序对应高级编程语言的种类相匹配;标签中的字符“stub”可以用于指示第二函数为边界函数(或称为stub函数),第二栈帧的类型为边界栈帧(或stub栈帧)。
129.示例二:当第一函数调用第二函数,第二函数调用第三函数时,第一返回地址位于第三栈帧中,第一返回地址对应的标签可以是unwindpcforc2nstub,该标签中的字符“c”可以用于指示第一函数为native,即运行时库中的函数,此时第一栈帧的类型与编写运行时库的高级编程语言相匹配;标签中的字符“n”可以用于指示第三函数为由高级语言编写的第一程序中的函数,因而第三栈帧的类型与第一程序对应高级编程语言的种类相匹配;标签中的字符“stub”可以用于指示第二函数为边界函数(或称为stub函数),第二栈帧的类型为边界栈帧(或stub栈帧)。
130.应当理解,上述示例只是列举出了返回地址对应标签的两种可行的数据报文格式,本领域技术人员可以采用其它数据报文格式来表征返回地址集合中每个返回地址对应的标签,或采用不同字符指示相应栈帧的栈帧类型,本技术对此不限定。
131.在一种可行的实施方式中,所述第一返回地址保存于返回地址集合,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述每个返回地址对应的标签指示了所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示了所述每个返回地址指向的函数的调用函数对应栈帧的栈帧类型。
132.其中,边界函数即为创建调用栈过程中添加的函数,其与第一程序中的代码逻辑、运行时库中的代码逻辑都无关,即边界函数不存在于由高级语言编写的代码库和运行时库
中。边界函数包括上述实施例中的第二函数。
133.其中,代码逻辑指程序开发者利用高级编程语言所编写程序所实现的功能。
134.其中,上述边界函数的调用函数指调用边界函数的函数,上述边界函数的被调用函数指边界函数所调用的函数。
135.其中,上述每个返回地址对应的标签指示了每个返回地址指向的函数对应栈帧的栈帧类型,以及指示了所述每个返回地址指向的函数的调用函数对应栈帧的栈帧类型,具体可参见第一返回地址对应标签的具体描述,此处不再赘述。
136.从技术效果上看,利用返回地址集合保存所有指向边界函数(即程序运行过程中添加的函数)的返回地址,由于返回地址集合中每个返回地址对应的标签具有与第一返回地址对应标签相同的特性,因而在后续栈回溯过程中,可以直接判断当前栈帧中返回地址是否位于返回地址集合中来确定相应栈帧的栈帧类型,相对现有技术而言,可以有效缩短栈回溯的时长,答复提升栈回溯性能。
137.对于需要进行栈回溯的业务场景,可以对第一程序运行过程中创建的调用栈进行栈回溯。栈回溯的过程从调用栈的栈顶开始,到栈底结束。
138.下面将以第四栈帧为例详细描述调用栈中的栈回溯过程。
139.在一种可行的实施方式中,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关;所述方法还包括:对所述第四栈帧进行栈回溯,包括:获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;当所述第二返回地址属于所述返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第四栈帧中的返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
140.其中,上述所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关,具体指:第四栈帧可以为任意非边界函数在调用栈中对应的栈帧。这是由于在创建调用栈过程中添加的边界函数是由编译器或手写汇编实现的,因而没有对应的高级编程语言,且边界函数对应栈帧的栈帧类型在非边界函数对应栈帧的栈回溯过程中已经识别出。
141.具体地,首先获取第四栈帧中包含的第二返回地址,然后判断第二返回地址是否位于返回地址集合中。主要包含两种情况:
142.(1)若第二返回地址不属于返回地址集合,说明第二返回地址所指向的第五函数不是边界函数,即编写第四函数的高级编程语言和编写第五函数的高级编程语言相同,因而第四栈帧的栈帧类型和第五栈帧的栈帧类型相同,可以将第五栈帧的栈帧类型设置为与第一栈帧的类型相同的第一类型。此外,第四函数和第五函数同属于第一程序中的函数或同属于运行时库中的函数。
143.(2)若第二返回地址属于返回地址集合中,说明第二返回地址所指向的第五函数为边界函数,将第五函数对应的第五栈帧的栈帧类型设置为第二类型,其中,第二类型由第二返回地址对应的标签确定。调用第五函数的第六函数所对应的高级编程语言与第四函数
对应的高级编程语言不同,可以基于第二返回地址对应的标签将第六栈帧设置为第三类型,第三类型与第一类型不同。其中,通过第二返回地址对应的标签确定第二类型和第三类型的具体过程可参见前述实施例中第一返回地址对应标签的相应过程,此处不再赘述。此时,第四函数和第六函数可以为同属于第一程序中的函数,或者第四函数为第一程序中的函数且第六函数为运行时库中函数,或者第四函数为运行时库中的函数且第六函数为第一程序中的函数。从技术效果上看,由于在创建调用栈的过程中将指向边界函数的返回地址加入返回地址集合中,因而在栈回溯过程中可以直接根据返回地址是否属于返回地址集合,以及返回地址集合中返回地址对应的标签确定相关栈帧的栈帧类型,相对于现有技术中在运行时库中维护大型返回地址数据表或数据结构,并通过查表来确定栈帧类型的方式,本技术实施例可以消除运行时库中返回地址数据表或数据结构的维护开销以及所需的查表时长,从而有效缩短栈回溯时长,可以在对非栈回溯场景无影响的前提下,大幅提升栈回溯性能。
144.其中,当第一函数调用第二函数,第二函数调用第三函数时,在栈回溯过程中,第四栈帧、第五栈帧和第六栈帧可以分别为第三栈帧、第二栈帧和第一栈帧;当第三函数调用第二函数,第二函数调用第一函数时,在栈回溯过程中,第四栈帧、第五栈帧和第六栈帧可以分别为上述的第一栈帧、第二栈帧和第三栈帧。
145.在一种可行的实施方式中,所述第二类型和所述第三类型是所述第二返回地址对应的标签所指示的两个栈帧类型。
146.具体地,基于第二返回地址对应标签中包含的字符来确定上述第二类型和第三类型,具体过程可参见上述第一返回地址对应标签的数据报文格式的描述,此处不再赘述。
147.在一种可行的实施方式中,所述方法还包括:获取所述第四栈帧中的帧指针fp;若所述fp指向所述调用栈的栈底,结束所述第四栈帧的栈回溯过程。
148.具体地,在判断第四栈帧中包含的第二返回地址是否属于返回地址集合之前,获取第四栈帧中包含的帧指针(frame pointer,fp),基于第四栈帧中的fp判断第四栈帧是否位于调用栈的栈底。此时共包括两种情况:
149.(1)当fp指示第四栈帧位于调用栈的栈底时,结束第四栈帧的栈回溯过程。
150.(2)当fp指示第四栈帧不是调用栈的栈底时,开始判断第四栈帧中包含的第二返回地址是否属于返回地址集合中,并相应确定第五栈帧和第六栈帧的栈帧类型,具体确定过程参见前述实施例,此处不再赘述。
151.可选地,上述基于fp判断第四栈帧是否位于调用栈的栈底,包括:判断fp是否等于预设值来确定第四栈帧是否位于调用栈的栈底。进一步地,该预设值可以等于0;当fp等于0时,指示第四栈帧位于调用栈的栈底;当fp不等于0时,指示第四栈帧不是调用栈的栈底。
152.从技术效果上看,在基于返回地址确定相应栈帧的类型之前,可以通过fp来判断当前栈帧是否位于调用栈的栈底,从而保证当栈回溯过程到达调用栈的栈底时,顺利结束栈回溯过程。
153.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与所述运行时库的高级编程语言的种类有关。
154.具体地,在对调用栈开始进行栈回溯时,会调用运行时库接口,即调用栈的栈顶处的栈帧对应的函数为编译后运行时库中的函数,因而对于首次进行栈回溯的栈帧,其栈帧
类型与运行时库的高级编程语言的种类相匹配,例如,运行时库的高级编程语言为c++,此时第一类型为c++栈帧。
155.应当理解,调用栈中其它非边界函数对应栈帧的栈回溯过程与上述第四栈帧的栈回溯过程对应相同,此处不再赘述。
156.从技术效果上看,在启动栈回溯过程时,由于调用栈栈顶处栈帧对应的函数为运行时库中的函数,因而通过将调用栈栈顶处栈帧的类型设置为与运行时库中函数对应高级编程语言相同的栈帧类型,确保后续未遇到边界函数时,将当前栈帧对应函数的调用函数对应栈帧的类型直接设置为第一类型,从而确保栈回溯过程中准确识别每个栈帧的栈帧类型。
157.从技术效果上看,在本技术实施例中,对于在高级语言代码中具有两个调用关系的函数,即第一函数和第三函数而言,当其分别对应的高级编程语言的种类不同时,在为包含第一函数的第一程序创建调用栈的过程中,会在第一函数和第三函数之间添加一个函数(即第二函数),并保存指向第二函数的第一返回地址以及该第一返回地址对应的标签。由于该第一返回地址对应的标签指示了第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,因而对于后续需要进行栈回溯的场景,可以基于第一返回地址对应的标签来识别第一栈帧、第二栈帧和第三栈帧的栈帧类型。相对于现有技术在栈回溯过程中需要在运行时库中维护大型返回地址数据表或数据结构,并通过查表来确定栈帧类型的方式,本技术实施例可以消除运行时库中返回地址数据表或数据结构的维护开销以及所需的查表时长,从而有效缩短栈回溯时长,可以在对非栈回溯场景无影响的前提下,大幅提升栈回溯性能。
158.请参见图4,图4为本技术实施例中一种程序调用栈进行栈回溯的流程图。如图4所示,程序调用栈的栈回溯过程可以用图4所示的流程来进行描述,包括步骤:s410、s420、s430、s440、s450和步骤s460。
159.步骤s410:启动程序调用栈的栈回溯过程。
160.步骤s420:获取指向调用栈中栈顶处栈帧所对应函数的返回地址和帧指针。
161.具体地,利用运行时库接口获取指向调用栈中栈顶处栈帧所对应函数的返回地址和帧指针,其未被保存于调用栈中。下文步骤中将返回地址指向函数称为当前函数,将返回地址指向函数所对应的栈帧称为当前栈帧。
162.步骤s430:基于返回地址判断其指向的函数是否为边界函数。
163.具体地,通过判断返回地址是否属于返回地址集合中来判断该返回地址指向的函数是否为边界函数。
164.若是,则执行步骤s431:基于返回地址对应的标签设置当前栈帧的栈帧类型和当前函数的调用函数对应栈帧的栈帧类型;若否,则执行步骤s432:将当前栈帧的栈帧类型设置为与包含该返回地址的栈帧相同的栈帧类型;应当理解,在首次栈回溯过程中,此时返回地址为保存于调用栈中,当前栈帧的栈帧类型与运行时库的高级编程语言相匹配。
165.步骤s440:获取指向调用函数的返回地址和帧指针。
166.具体地,若步骤s440承接步骤s431,则此时调用函数的返回地址和帧指针位于当前函数的调用函数对应的栈帧中。若步骤s440承接步骤s432,则此时调用函数的返回地址和帧指针位于当前栈帧中,即从当前栈帧中获取指向调用函数的返回地址和帧指针。
167.步骤s450:基于指向调用函数的帧指针判断是否为调用栈的栈底。
168.若是,则执行步骤s460:结束调用栈的栈回溯过程。若否,则返回步骤s430。
169.具体地,上述步骤中的详细执行过程可参见前述实施例中的描述,此处不再赘述。
170.请参见图5,图5为本技术实施例中一种栈回溯过程示意图。如图5所示,图5中共包括三列:从左到右,依次为第一列、第二列和第三列。第二列为程序(可以是上述实施例中的第一程序)运行过程中所创建的调用栈,第一列为与第二列调用栈中各栈帧分别对应的函数、第三列为栈回溯过程中所识别出的调用栈中各栈帧的栈帧类型。
171.其中,高级语言函数1和高级语言函数2可以为第一程序中的函数,运行时函数1-运行时函数4为运行时库中的函数,边界函数1-边界函数3为创建调用栈过程中添加的函数。
172.应当理解,根据前述实施例可知,在创建调用栈过程中,指向边界函数1的返回地址、指向边界函数2的返回地址和指向边界函数3的返回地址(栈帧4、栈帧6和栈帧8中包含的返回地址)被加入到返回地址集合中;而指向其余函数的返回地址未被加入返回地址集合中。此外,栈帧1中包含的帧指针指示栈帧1为调用栈的栈底。
173.下面结合图5来描述调用栈的栈回溯过程:
174.首先调用运行时库的接口,获取指向运行时函数4对应的返回地址和帧指针,其不存在于调用栈中,即在图5所示函数调用方向中,指向最后一层函数的返回地址和帧指针未保存于调用栈中。由于指向运行时函数4的返回地址不属于返回地址集合,可以该返回地址指向的函数不是边界函数,此时将与运行时函数4对应的栈帧9的类型设置为运行时栈帧(即与运行时库对应的高级编程语言相匹配,例如,当编写运行时库的高级编程语言为c++,则此时运行时栈帧为c++栈帧)。
175.获取指向运行时函数4的调用函数(即运行时函数3)的返回地址和帧指针,即栈帧9中包含的返回地址和帧指针。由于栈帧9中包含的帧指针指示栈帧9不是调用栈的栈底,且栈帧9中返回地址不属于返回地址集合,说明该返回地址指向的函数不是边界函数,即编写运行时函数3的高级编程语言和运行时函数4的高级编程语言相同,此时将栈帧8的类型设置为与栈帧9相同的运行时栈帧。
176.获取指向运行时函数3的调用函数的返回地址和帧指针,即栈帧8中包含的返回地址和帧指针。由于栈帧8中包含的帧指针指示栈帧8不是调用栈的栈底,且栈帧8中包含的返回地址属于返回地址集合,说明该返回地址对应的函数为边界函数(即边界函数3),基于该返回地址对应的标签识别出栈帧7的栈帧类型和栈帧6的栈帧类型,具体地,此时可以识别出栈帧7的类型为第二类型(可以由返回地址对应标签中的特定字符指示),栈帧6的栈帧类型为高级语言栈帧2(即高级语言栈帧2与高级语言函数2对应的高级编程语言相匹配),且编写高级语言函数2的高级编程语言和编写运行时函数3的高级编程语言不同。
177.获取指向高级语言函数2的调用函数的返回地址和帧指针,即栈帧6中包含的返回地址和帧指针。由于栈帧6中包含的帧指针指示栈帧6不是调用栈的栈底,且栈帧6中的返回地址属于返回地址集合,说明该返回地址指向的函数是边界函数(即边界函数2),基于该返回地址对应的标签识别出栈帧5的栈帧类型和栈帧4的栈帧类型,具体地,此时可以识别出栈帧5的类型为第二类型,栈帧4的栈帧类型为高级语言栈1(即高级语言栈帧1与高级语言函数1对应的高级编程语言相匹配),且编写高级语言函数1的高级编程语言和编写高级语
言函数2的高级编程语言不同。
178.获取指向高级语言函数1的调用函数的返回地址和帧指针,即栈帧4中包含的返回地址和帧指针。由于栈帧4中包含的帧指针指示栈帧4不是调用栈的栈底,且栈帧4中的返回地址属于返回地址集合,说明该返回地址指向的函数是边界函数(即边界函数1),基于该返回地址对应的标签识别出栈帧3的栈帧类型和栈帧2的栈帧类型,具体地,此时可以识别出栈帧3的类型为第二类型,栈帧2的栈帧类型为运行时栈帧,且编写运行时函数2的高级编程语言和编写高级语言函数1的高级编程语言不同。
179.获取指向运行时函数2的调用函数的返回地址和帧指针,即栈帧2中包含的返回地址和帧指针。由于栈帧2中包含的帧指针指示栈帧2不是调用栈的栈底,且栈帧2中的返回地址不属于返回地址集合,说明该返回地址指向的函数不是边界函数,即编写运行时函数1的高级编程语言与编写运行时函数2的高级编程语言相同。将利用栈帧1的栈帧类型设置为与栈帧2相同的栈帧类型,即运行时栈帧。
180.获取指向运行时函数1的调用函数的返回地址和帧指针,即栈帧1中包含的返回地址和帧指针。由于栈帧1中包含的帧指针指示栈帧1为调用栈的栈底,结束调用栈的栈回溯过程。
181.请参见图6,图6是本技术实施例中一种栈回溯方法的流程示意图。调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关。如图6所示,栈回溯方法600包括:
182.获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数。当所述第二返回地址属于返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第二返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
183.在一种可行的实施方式中,所述第二类型和所述第三类型为所述第二返回地址对应的标签所指示的两个栈帧类型;所述每个返回地址对应的标签指示所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示所述每个返回地址指向的函数的调用者函数对应栈帧的栈帧类型。
184.在一种可行的实施方式中,获取所述第四栈帧中的帧指针fp;若所述fp指向所述调用栈的栈底时,结束所述栈回溯过程。
185.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与运行时库的高级编程语言的种类有关。
186.在一种可行的实施方式中,所述调用栈是在调用运行时库运行第一程序的过程中创建的,所述第一程序中包括第一函数,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于第二函数的第二栈帧,以及对应于第三函数的第三栈帧,其中,所述第二函数在创建所述调用栈的过程中添加的函数,所述第一函数和所述第二函数之间存在调用关
系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述第一程序中的函数或所述运行时库中的函数,且所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,所述第一返回地址属于所述返回地址集合。
187.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中的返回地址。
188.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
189.具体地,方法600的具体过程请参见前述实施例中的描述,此处不再赘述。
190.请参见图7,图7是本技术实施例中一种程序调用栈创建装置的结构示意图。如图7所示,装置700包括:
191.获取单元710,用于获取第一程序,所述第一程序中包括第一函数;处理单元720,用于在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于所述第二函数的第二栈帧以及对应于第三函数的第三栈帧,其中,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述运行时库中的函数或所述第一程序中的函数,所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;存储单元730,用于保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型。
192.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中包含的返回地址。
193.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
194.在一种可行的实施方式中,所述第一返回地址保存于返回地址集合,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述每个返回地址对应的标签指示了所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示了所述每个返回地址指向的函数的调用函数对应栈帧的栈帧类型。
195.在一种可行的实施方式中,所述调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关;所述处理单元720,还用于对所述第四栈帧进行栈回溯;在所述栈回溯
过程中,所述处理单元720具体用于:指示所述获取单元710获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;以及当所述第二返回地址属于所述返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第四栈帧中的返回地址不属于所述返回地址集合时,将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
196.在一种可行的实施方式中,所述第二类型和所述第三类型是所述第二返回地址对应的标签所指示的两个栈帧类型。
197.在一种可行的实施方式中,所述获取单元710,还用于获取所述第四栈帧中的帧指针fp;所述处理单元720,还用于在所述fp指向所述调用栈的栈底时,结束所述第四栈帧的栈回溯过程。
198.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与所述运行时库的高级编程语言的种类有关。
199.具体地,上述装置700具体的执行过程可以参见前述方法300对应的描述,此处不再赘述。
200.请参见图8,图8是本技术实施例中一种栈回溯装置的结构示意图。调用栈中包括对应于第四函数的第四栈帧,所述第四栈帧的栈帧类型为第一类型,所述第四栈帧的栈帧类型与所述第四函数对应的高级编程语言的种类有关。如图8所示,装置800包括:
201.获取单元810,用于获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数。处理单元820,用于当所述第二返回地址属于返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述返回地址集合中的每个返回地址指向的函数均为边界函数,所述边界函数的调用函数和所述边界函数的被调用函数对应不同种类的高级编程语言,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;或者当所述第二返回地址不属于所述返回地址集合时,所述处理单元将第五栈帧的栈帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
202.在一种可行的实施方式中,所述第二类型和所述第三类型为所述第二返回地址对应的标签所指示的两个栈帧类型;所述每个返回地址对应的标签指示所述每个返回地址指向的函数对应栈帧的栈帧类型,以及指示所述每个返回地址指向的函数的调用者函数对应栈帧的栈帧类型。
203.在一种可行的实施方式中,所述获取单元810,还用于获取所述第四栈帧中的帧指针fp;所述处理单元,还用于在所述fp指向所述调用栈的栈底时,结束所述第四栈帧的栈回溯过程。
204.在一种可行的实施方式中,当所述第四栈帧为所述调用栈的栈顶处的栈帧时,所述第一类型与运行时库的高级编程语言的种类有关。
205.在一种可行的实施方式中,所述调用栈是在调用运行时库运行第一程序的过程中创建的,所述第一程序中包括第一函数,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于第二函数的第二栈帧,以及对应于第三函数的第三栈帧,其中,所述第二函数在创建所述调用栈的过程中添加的函数,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述第一程序中的函数或所述运行时库中的函数,且所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同;所述装置还包括存储单元830,所述存储单元830用于:保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型,所述第一返回地址属于所述返回地址集合。
206.在一种可行的实施方式中,所述第一函数调用所述第二函数,所述第二函数调用所述第三函数,所述第一返回地址为所述第三栈帧中包含的返回地址,或者,所述第三函数调用所述第二函数,所述第二函数调用所述第一函数,所述第一返回地址为所述第一栈帧中的返回地址。
207.在一种可行的实施方式中,所述第二函数通过编译器或手写汇编生成,并存储于编译后的高级语言代码库或者编译后的运行时代码库中。
208.具体地,上述装置800具体的执行过程可以参见前述方法600对应的描述,此处不再赘述。
209.请参见图9,图9是本技术实施例中一种计算机设备的硬件结构示意图。如图9所示,设备900包括处理器901、存储器902、接口电路903和总线904。其中,处理器901、存储器902和接口电路903通过总线904进行数据传输。
210.处理器901,用于获取第一程序,所述第一程序中包括第一函数;在调用运行时库运行所述第一程序的过程中,添加第二函数以及创建调用栈,其中,所述调用栈中包括对应于所述第一函数的第一栈帧,对应于所述第二函数的第二栈帧以及对应于第三函数的第三栈帧,其中,所述第一函数和所述第二函数之间存在调用关系,所述第二函数和所述第三函数之间存在调用关系,所述第三函数为所述运行时库中的函数或所述第一程序中的函数,所述第一函数对应的高级编程语言和所述第三函数对应的高级编程语言不同。存储器902,用于保存第一返回地址以及所述第一返回地址对应的标签,所述第一返回地址为所述第一函数和所述第三函数中,后被执行的函数对应的栈帧中包含的返回地址,所述第一返回地址对应的标签指示了所述第一栈帧的栈帧类型、所述第二栈帧的栈帧类型和所述第三栈帧的栈帧类型。
211.处理器901,还用于对所述第四栈帧进行栈回溯,包括:获取所述第四栈帧中的第二返回地址,所述第二返回地址指向第五函数,所述第五函数为调用所述第四函数的函数;当所述第二返回地址属于所述返回地址集合时,将第五栈帧的栈帧类型设置为第二类型,所述第五栈帧为所述第五函数对应的栈帧,所述第二类型指示所述第五函数为所述边界函数,以及,将第六栈帧的栈帧类型设置为第三类型,所述第六栈帧为第六函数对应的栈帧,所述第六函数为调用所述第五函数的函数,所述第六栈帧的栈帧类型与所述第四栈帧的栈帧类型不同;当所述第四栈帧中的返回地址不属于所述返回地址集合时,将第五栈帧的栈
帧类型设置为所述第一类型,所述第五栈帧为所述第五函数对应的栈帧。
212.具体地,本技术实施例中计算机设备900上处理器和存储器的具体运行过程可以参见前述方法实施例300和600中的对应过程,此处不再赘述。
213.本技术提供了一种计算机可读存储介质,所述计算机可读存储介质中存储有程序指令,当所述程序指令在一个或多个处理器上运行时,以实现上述图3和/或图6方法实施例中的部分或全部步骤。
214.本技术提供了一种计算机程序产品,当所述计算机程序产品在计算机设备上运行时,上述图3和/或图6方法中的部分或全部步骤得以实现。
215.在上述实施例中,对各个实施例的描述都各有侧重,某个实施例中没有详述的部分,可以参见其它实施例的相关描述。需要说明的是,对于前述的各方法实施例,为了简单描述,故将其都表述为一系列的动作组合,但是本领域技术人员应该知悉,本技术并不受所描述的动作顺序的限制,因为依据本技术,某些步骤可能可以采用其它顺序或者同时进行。其次,本领域技术人员也应该知悉,说明书中所描述的实施例均属于优选实施例,所涉及的动作和模块并不一定是本技术所必须的。
216.在本技术所提供的几个实施例中,应该理解到,所揭露的装置,可通过其它的方式实现。例如,以上所描述的装置实施例仅仅是示意性的,例如上述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性或其它的形式。
217.上述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部单元来实现本实施例方案的目的。
218.以上所述,以上实施例仅用以说明本技术的技术方案,而非对其限制;尽管参照前述实施例对本技术进行了详细的说明,本领域的普通技术人员应当理解:其依然可以对前述各实施例所记载的技术方案进行修改,或者对其中部分技术特征进行等同替换;而这些修改或者替换,并不使相应技术方案的本质脱离本技术各实施例技术方案的精神和范围。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1