函数调用栈解析和回溯方法与装置转让专利

申请号 : CN202211187959.1

文献号 : CN115292201B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 张鹏方建滨黄春彭林唐滔崔英博

申请人 : 中国人民解放军国防科技大学

摘要 :

本申请涉及一种函数调用栈解析和回溯方法及装置,所述方法包括:通过转储异常中断或者手动中断应用程序的执行现场,并根据中断应用程序中终止函数正在执行的代码地址在可执行文件中找到所述终止函数的函数代码,并对处理后的函数代码进行分析后重构终止函数的栈桢结构,并根据该栈桢结构对执行现场重的栈空间进行解析得到返回地址以及上一层函数的栈地址,采用同样方式重构返回地址对应的上一层函数的栈桢结构并对转储的栈空间进行解析,对调用栈中的每个函数进行栈桢结构重构与解析,直到无法得到有效返回地址或栈地址,即完成调用栈回溯,采用本方法可以智能识别栈桢结构,能够在无需进行额外处理的情况下,高效、准确地获取完整的函数调用栈。

权利要求 :

1.函数调用栈解析和回溯方法,其特征在于,所述方法包括:

转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;

根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构,包括:根据程序可执行文件进行反汇编,得到所述函数的汇编指令,从函数入口开始,对所述函数的汇编指令进行扫描,识别其中所有修改栈顶寄存器的指令,并通过跟踪栈顶位置的变化以得到开栈大小,根据所有修改栈顶寄存器的指令,识别其中所述函数输入参数以及返回地址的进出栈操作,并得到所述函数输入参数以及返回地址分别在栈中相对于栈顶或栈底的偏移量,并根据对应的偏移量得到所述函数输入参数在栈空间中的存储位置以及返回地址在的存储位置;

根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;

所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。

2.根据权利要求1所述的函数调用栈解析和回溯方法,其特征在于,所述栈桢结构包括:开栈大小、函数输入参数的相对栈顶或栈底位置的偏移量、以及返回地址的相对栈顶或栈底位置的偏移量。

3.根据权利要求2所述的函数调用栈解析和回溯方法,其特征在于,所述所有修改栈顶寄存器的指令包括:专用进出栈指令,以栈顶寄存器为目的寄存器的MOV指令以及运算指令,以栈顶寄存器为基址寄存器的自增或自减访存指令。

4.根据权利要求3所述的函数调用栈解析和回溯方法,其特征在于,跟踪栈顶位置的变化以得到所述开栈大小包括:将所述函数开始时的栈顶寄存器的值,作为函数栈底位置;

识别所有修改栈顶寄存器的指令,记录栈顶位置与栈底位置的最大差值,并将所述最大差值作为所述开栈大小。

5.根据权利要求3所述的函数调用栈解析和回溯方法,其特征在于,得到所述函数输入参数以及返回地址分别相对于所述函数栈顶或栈底的偏移量包括:根据调用约定中规定的函数输入参数以及返回地址传递方式得到对应的偏移量;

若调用约定中规定使用栈传递,则所述偏移量为所述函数输入参数以及返回地址在栈中相对于栈顶或栈底的偏移量;

若调用约定中规定使用寄存器方式传递,则识别出以该寄存器为源寄存器的首次进栈操作,此时进栈操作中的偏移量为所述函数输入参数以及返回地址相对栈顶或栈底的偏移量;

若没有对应的进栈操作,则所述函数输入参数或返回地址的值保存在寄存器中。

6.根据权利要求3所述的函数调用栈解析和回溯方法,其特征在于,在获取所述函数的输入参数以及返回地址分别在栈中相对于栈顶或栈底的偏移量之后还根据该偏移量得到所述输入参数的存储位置以及返回地址的存储位置包括:分别将所述函数输入参数以及返回地址在栈中相对于栈顶或栈底的偏移量与所述函数的栈顶或栈底地址进行相加得到对应的存储位置。

7.根据权利要求6所述的函数调用栈解析和回溯方法,其特征在于,根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈地址包括:在所述转储的栈顶寄存器中获取所述终止函数的栈顶地址;

根据所述终止函数的栈顶地址以及开栈大小得到所述终止函数的栈底地址,并根据所述终止函数的栈底地址确定所述父函数的栈顶地址;

根据所述终止函数的栈底地址,以及所述终止函数输入参数的存储位置以及返回地址的存储位置从转储的所述栈空间提取所述终止函数的输入参数以及返回地址。

8.一种函数调用栈解析和回溯装置,其特征在于,所述装置包括:

执行现场转储模块,用于转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;

栈桢结构重构模块,用于根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构,包括:根据程序可执行文件进行反汇编,得到所述函数的汇编指令,从函数入口开始,对所述函数的汇编指令进行扫描,识别其中所有修改栈顶寄存器的指令,并通过跟踪栈顶位置的变化以得到开栈大小,根据所有修改栈顶寄存器的指令,识别其中所述函数输入参数以及返回地址的进出栈操作,并得到所述函数输入参数以及返回地址分别在栈中相对于栈顶或栈底的偏移量,并根据对应的偏移量得到所述函数输入参数在栈空间中的存储位置以及返回地址在的存储位置;

栈空间解析模块,用于根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;

调用栈构造模块,用于所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析,重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。

说明书 :

函数调用栈解析和回溯方法与装置

技术领域

[0001] 本申请涉及计算机技术领域,特别是涉及一种函数调用栈解析和回溯方法与装置。

背景技术

[0002] 应用程序在实际运行过程中,会存在出现硬件或软件异常的可能性,导致程序终止执行,此时需要程序的调用栈信息,来定位程序出现异常的位置。
[0003] 对于目前函数调用栈回溯技术,要么需要函数带有栈桢结构信息,要么需要限制编译器优化,要么对栈中的数据进行猜测是否为函数返回地址等,存在分析不精确、需要额外处理等限制。
[0004] 由于程序出现异常的不确定性,用户没有提前进行额外处理,导致信息缺失,难以恢复函数调用栈信息。
[0005] 因此,需要一种能够智能识别栈桢结构,在无需进行额外处理的情况下,高效、准确地获取完整的函数调用栈的方法。

发明内容

[0006] 基于此,有必要针对上述技术问题,提供一种能够在无需进行额外处理的情况下,高效、准确地获取完整的函数调用栈的方法。
[0007] 一种函数调用栈解析和回溯方法,所述方法包括:
[0008] 转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0009] 根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0010] 根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0011] 所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0012] 在其中一实施例中,所述栈桢结构包括:开栈大小、函数输入参数的相对栈顶或栈底位置的偏移量、以及返回地址的相对栈顶或栈底位置的偏移量。
[0013] 在其中一实施例中,根据所述函数的函数代码进行静态分析后重构所述函数的栈桢结构包括:
[0014] 根据程序可执行文件进行反汇编,得到所述函数的汇编指令;
[0015] 从函数入口开始,对所述函数的汇编指令进行扫描,识别其中所有修改栈顶寄存器的指令,并通过踪栈顶位置的变化以得到所述开栈大小;
[0016] 根据所有修改栈顶寄存器的指令,识别其中所述函数输入参数以及返回地址的进出栈操作,并得到所述函数输入参数以及返回地址分别在栈中相对于栈顶或栈底的偏移量。
[0017] 在其中一实施例中,所述所有修改栈顶寄存器的指令包括:专用进出栈指令,以栈顶寄存器为目的寄存器的MOV指令以及运算指令,以栈顶寄存器为基址寄存器的自增或自减访存指令。
[0018] 在其中一实施例中,跟踪栈顶位置的变化以得到所述开栈大小包括:
[0019] 将所述函数开始时的栈顶寄存器的值,作为函数栈底位置;
[0020] 识别所有修改栈顶寄存器的指令,记录栈顶位置与栈底位置的最大差值,并将所述最大差值作为所述开栈大小。
[0021] 在其中一实施例中,得到所述函数输入参数以及返回地址分别相对于所述函数栈顶或栈底的偏移量包括:
[0022] 根据调用约定中规定的函数输入参数以及返回地址传递方式得到对应的偏移量;
[0023] 若调用约定中规定使用栈传递,则所述偏移量为所述函数输入参数以及返回地址在栈中相对于栈顶或栈底的偏移量;
[0024] 若调用约定中规定使用寄存器方式传递,则识别出以该寄存器为源寄存器的首次进栈操作,此时进栈操作中的偏移量为所述函数输入参数以及返回地址相对栈顶或栈底的偏移量;
[0025] 若没有对应的进栈操作,则所述函数输入参数或返回地址的值保存在寄存器中。
[0026] 在其中一实施例中,在获取所述函数的输入参数以及返回地址分别在栈中相对于栈顶或栈底的偏移量之后还根据该偏移量得到所述输入参数的存储位置以及返回地址的存储位置包括:
[0027] 分别将所述函数输入参数以及返回地址在栈中相对于栈顶或栈底的偏移量与所述函数的栈顶或栈底地址进行相加得到对应的存储位置。
[0028] 在其中一实施例中,根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈地址包括:
[0029] 在所述转储的栈顶寄存器中获取所述终止函数的栈顶地址;
[0030] 根据所述终止函数的栈顶地址以及开栈大小得到所述终止函数的栈底地址,并根据所述终止函数的栈底地址确定所述父函数的栈顶地址;
[0031] 根据所述终止函数的栈底地址,以及所述终止函数输入参数的存储位置以及返回地址的存储位置从转储的所述栈空间提取所述终止函数的输入参数以及返回地址。
[0032] 一种函数调用栈解析和回溯装置,所述装置包括:
[0033] 执行现场转储模块,用于转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0034] 栈桢结构重构模块,用于根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0035] 栈空间解析模块,用于根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0036] 调用栈构造模块,用于所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析,重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0037] 一种计算机设备,包括存储器和处理器,所述存储器存储有计算机程序,所述处理器执行所述计算机程序时实现以下步骤:
[0038] 转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0039] 根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0040] 根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0041] 所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0042] 一种计算机可读存储介质,其上存储有计算机程序,所述计算机程序被处理器执行时实现以下步骤:
[0043] 转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0044] 根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0045] 根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0046] 所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0047] 上述函数调用栈解析和回溯方法及装置,通过转储异常中断或者手动应用程序的执行现场,并分析应用程序的可执行文件,获得应用程序中中终止函数的栈桢结构;利用函数栈桢结构对转储的栈空间进行解析,得到终止函数的返回地址以及父函数栈地址,并根据终止函数的返回地址所对应函数的栈桢结构,继续回溯,直至调用栈回溯完成。本方法可以智能识别栈桢结构,能够在无需进行额外处理的情况下,高效、准确地获取完整的函数调用栈。

附图说明

[0048] 图1为一个实施例中函数调用栈解析和回溯方法的流程示意图;
[0049] 图2为一个应用场景函数调用链示意图;
[0050] 图3为一个应用场景中栈空间结构示意图;
[0051] 图4为一个实施例中函数调用栈解析和回溯装置的结构框图;
[0052] 图5为一个实施例中计算机设备的内部结构图。

具体实施方式

[0053] 为了使本申请的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本申请进行进一步详细说明。应当理解,此处描述的具体实施例仅仅用以解释本申请,并不用于限定本申请。
[0054] 在一个实施例中,如图1所示,提供了一种函数调用栈解析和回溯方法,包括以下步骤:
[0055] 步骤S100,转储异常中断或者手动中断应用程序的执行现场,该应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0056] 步骤S110,根据终止函数正在执行的代码地址在应用程序的可执行文件中找到终止函数的函数代码,并对其进行静态代码分析后重构终止函数的栈桢结构;
[0057] 步骤S120,根据终止函数的栈桢结构对转储的栈空间进行解析,得到终止函数的返回地址以及父函数栈顶地址;
[0058] 步骤S130,返回地址为调用终止函数的函数地址,根据返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0059] 在步骤S100中,应用程序因为异常而中断,其中异常包括内存访问异常、DMA异常、非对齐异常、除零异常、非法指令异常、寄存器写冲突异常、软件异常等。
[0060] 具体的,在应用程序出现异常后,处理器都会自动跳转到异常处理服务例程中执行,在异常处理服务例程中,保存处理器所有寄存器和栈空间。在本实施例中,除了在异常情况下进行保存外,还支持在其他情况下的手动触发异常来实现保存应用程序的执行现场。手动触发软件异常后,异常处理服务例程执行完保存现场动作后,返回应用程序继续正常运行。
[0061] 在本实施例中,按照寄存器约定以及调用约定,应用程序执行现场中部分寄存器具有特殊意义。与调用栈回溯有关的重要寄存器,包括程序计数器、栈底寄存器、栈顶寄存器以及返回地址寄存器。在有的调用约定中,返回地址会保存在固定寄存器中。也有一些调用约定,将返回地址保存在函数栈的固定位置中。
[0062] 栈空间是在用户程序进行加载执行时由系统分配。系统一般会在进程地址空间的固定位置分配栈空间,即栈空间起始地址,而执行现场的栈顶寄存器保存着栈空间的结束地址。栈空间的大小上限由系统配置决定。
[0063] 应用程序执行过程中一般存在多层函数嵌套调用,构成函数调用链,例如,如图2所示,入口函数调用函数1,函数1调用函数2,函数2调用当前终止函数,构成从入口函数到终止函数的函数调用链。如图3所示,为栈空间结构示意图,在本实施例中,先重构应用程序中断时函数调用链最低层的函数栈桢结构,再利用该函数的栈桢结构对程序栈空间进行解析,得到该函数的返回地址以及开栈大小,进而可以通过计算得到上一层函数(也就是父函数)的执行代码位置及栈顶地址,重复此过程直到解析完调用链中的所有函数,完成函数调用栈回溯。
[0064] 在本实施例中,栈桢结构包括:开栈大小、函数输入参数的相对栈顶或栈底位置的偏移量、以及返回地址的相对栈顶或栈底位置的偏移量。
[0065] 在步骤S110中,通过使用反汇编工具objdump对终止函数的函数代码进行反汇编得到对应的汇编代码,扫描汇编代码,可得到应用程序中所有的函数信息,包括函数名、函数起始地址、函数结束地址。步骤S100中,转储的程序计数寄存器中存储的是正在执行的代码地址,根据该地址可定位到对应的函数,也就是终止函数,并相应获得该函数的汇编指令。
[0066] 为了降低分析算法的复杂度,从终止函数起始地址开始分析,遇到跳转指令或函数调用指令时结束分析,可以避免处理复杂的控制流。一般此时已经完成了开栈操作,以及传入参数寄存器的入栈操作,因此可以获得足够的栈桢结构信息。
[0067] 进一步的,首先假设栈底地址为65536(可以为任意常量,此处仅仅为示例),在分析前将栈顶寄存器初始化栈底地址,然后对汇编指令进行扫描,识别其中所有修改栈顶寄存器的指令,并通过踪栈顶位置的变化以得到开栈大小。同时根据所有修改栈顶寄存器的指令,识别其中终止函数输入参数以及返回地址的进出栈操作,并得到终止函数输入参数以及返回地址分别在栈中相对于栈底的偏移量,并根据对应的偏移量得到终止函数输入参数在栈空间中的存储位置以及返回地址在栈空间中的存储位置。
[0068] 具体的,所有修改栈顶寄存器的指令包括:专用进出栈指令,以栈顶寄存器为目的寄存器的MOV指令以及运算指令,以栈顶寄存器为基址寄存器的自增或自减访存指令。
[0069] 进一步的,跟踪栈顶位置的变化以得到开栈大小包括:将终止函数开始时的栈顶寄存器的值,作为函数栈底地址,识别所有修改栈顶寄存器的指令,记录栈顶位置与栈底位置的最大差值,并将最大差值作为所述开栈大小。
[0070] 进一步的,得到终止函数输入参数以及返回地址分别在栈中相对于栈底的偏移量包括:根据调用约定中规定的终止函数输入参数以及返回地址传递方式得到对应的偏移量。
[0071] 若调用约定中规定使用栈传递,则偏移量为终止函数输入参数以及返回地址在栈中相对于栈底的偏移量;
[0072] 若调用约定中规定使用寄存器方式传递,则识别出以该寄存器为源寄存器的首次进栈操作,此时偏移量为所述终止函数输入参数以及返回地址在栈顶位置;
[0073] 若没有对应的进栈操作,则偏移量保存在寄存器中。
[0074] 具体的,对汇编指令进行扫描包括:首先将所有寄存器的值初始化为整型最大值,栈顶寄存器的值初始化为65536,然后根据汇编指令的语义,修改寄存器值。对于MOV指令,则将源寄存器的值或者常量的值,赋值给目的寄存器;对于运算指令,如果有源寄存器的值为整型最大值,则直接将目的寄存器的值置为最大值,否则按照指令的语义计算目的寄存器的值;对于LD/ST指令,如果地址寄存器不为栈顶寄存器,则忽略该操作,否则根据自增自减操作,修改栈顶寄存器的值,并且说明该指令是进栈出栈操作;对于部分处理器提供的专用进出栈指令,如PUSH/POP指令,根据进出栈行为,修改栈顶寄存器的值。
[0075] 对于进栈操作,如果源寄存器是调用约定中规定的返回地址寄存器或者参数寄存器,则记录此时栈顶寄存器值与栈顶寄存器初始值的差,作为返回地址或者参数在栈中相对栈底的偏移量。
[0076] 在本实施例中,根据对应的偏移量得到终止函数输入参数的存储位置以及返回地址的存储位置包括:分别将终止函数输入参数以及返回地址在栈中相对于栈底的偏移量与终止函数的栈底地址进行相加得到在程序栈空间中对应的存储位置。
[0077] 在步骤S120中,根据终止函数的栈桢结构对转储的栈空间进行解析,得到终止函数的返回地址以及父函数栈顶地址包括:在转储的栈顶寄存器中获取终止函数的栈顶地址,根据终止函数的栈顶以及开栈大小得到终止函数的栈底地址,并根据终止函数的栈底地址确定父函数(也就是上一层函数)的栈顶地址;根据终止函数的栈底地址,以及终止函数输入参数的存储位置以及返回地址的存储位置从转储的栈空间提取终止函数的输入参数的值以及返回地址。
[0078] 其中,还根据转储的栈空间的起始地址,与函数栈底地址的差值,得到函数栈在转储的栈空间中的位置。
[0079] 如果返回地址或者参数没有入栈,则从转储的返回地址寄存器或参数寄存器中,获得返回地址以及函数参数的值。
[0080] 在获得返回地址和上一层函数的栈顶地址后,根据该返回地址可确定对应的函数,并通过步骤S110到S120获得该函数的栈桢结构、返回地址以及上一层函数的栈顶位置,再重复步骤S110到S120,直至无法找到返回地址所对应函数后,则认为调用栈回溯完成,此时将得到中断应用程序的函数调用链以及调用链中每个函数的调用参数、正在执行的代码位置等。
[0081] 应该理解的是,虽然图1的流程图中的各个步骤按照箭头的指示依次显示,但是这些步骤并不是必然按照箭头指示的顺序依次执行。除非本文中有明确的说明,这些步骤的执行并没有严格的顺序限制,这些步骤可以以其它的顺序执行。而且,图1中的至少一部分步骤可以包括多个子步骤或者多个阶段,这些子步骤或者阶段并不必然是在同一时刻执行完成,而是可以在不同的时刻执行,这些子步骤或者阶段的执行顺序也不必然是依次进行,而是可以与其它步骤或者其它步骤的子步骤或者阶段的至少一部分轮流或者交替地执行。
[0082] 在一个实施例中,如图4所示,提供了一种函数调用栈解析和回溯装置,包括:执行现场转储模块200、栈桢结构重构模块210、栈空间解析模块220和调用栈构造模块230,其中:
[0083] 执行现场转储模块200,用于转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0084] 栈桢结构重构模块210,用于根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0085] 栈空间解析模块220,用于根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0086] 调用栈构造模块230,用于所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0087] 关于函数调用栈解析和回溯装置的具体限定可以参见上文中对于函数调用栈解析和回溯方法的限定,在此不再赘述。上述函数调用栈解析和回溯装置中的各个模块可全部或部分通过软件、硬件及其组合来实现。上述各模块可以硬件形式内嵌于或独立于计算机设备中的处理器中,也可以以软件形式存储于计算机设备中的存储器中,以便于处理器调用执行以上各个模块对应的操作。
[0088] 在一个实施例中,提供了一种计算机设备,该计算机设备可以是终端,其内部结构图可以如图5所示。该计算机设备包括通过系统总线连接的处理器、存储器、网络接口、显示屏和输入装置。其中,该计算机设备的处理器用于提供计算和控制能力。该计算机设备的存储器包括非易失性存储介质、内存储器。该非易失性存储介质存储有操作系统和计算机程序。该内存储器为非易失性存储介质中的操作系统和计算机程序的运行提供环境。该计算机设备的网络接口用于与外部的终端通过网络连接通信。该计算机程序被处理器执行时以实现一种函数调用栈解析和回溯方法。该计算机设备的显示屏可以是液晶显示屏或者电子墨水显示屏,该计算机设备的输入装置可以是显示屏上覆盖的触摸层,也可以是计算机设备外壳上设置的按键、轨迹球或触控板,还可以是外接的键盘、触控板或鼠标等。
[0089] 本领域技术人员可以理解,图5中示出的结构,仅仅是与本申请方案相关的部分结构的框图,并不构成对本申请方案所应用于其上的计算机设备的限定,具体的计算机设备可以包括比图中所示更多或更少的部件,或者组合某些部件,或者具有不同的部件布置。
[0090] 在一个实施例中,提供了一种计算机设备,包括存储器和处理器,存储器中存储有计算机程序,该处理器执行计算机程序时实现以下步骤:
[0091] 转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0092] 根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0093] 根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0094] 所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0095] 在一个实施例中,提供了一种计算机可读存储介质,其上存储有计算机程序,计算机程序被处理器执行时实现以下步骤:
[0096] 转储异常中断或者手动中断应用程序的执行现场,所述应用程序的执行现场包括:栈空间以及多个处理器寄存器,其中,所述处理器寄存器包括分别有程序计数寄存器和栈顶寄存器,所述程序计数寄存器中保存有当前中断应用程序中终止函数正在执行的代码地址,所述栈顶寄存器保存的是当前中断应用程序中终止函数的栈顶地址;
[0097] 根据所述终止函数正在执行的代码地址在所述应用程序的可执行文件中找到所述终止函数的函数代码,并对其进行静态代码分析后重构所述终止函数的栈桢结构;
[0098] 根据所述终止函数的栈桢结构对转储的所述栈空间进行解析,得到所述终止函数的返回地址以及父函数栈顶地址;
[0099] 所述返回地址为调用所述终止函数的函数地址,根据所述返回地址得到对应函数的函数代码,采用同样方式重构栈桢结构并对转储的栈空间进行解析;重复此操作,直到无法得到有效返回地址或栈顶地址,即完成调用栈回溯。
[0100] 本领域普通技术人员可以理解实现上述实施例方法中的全部或部分流程,是可以通过计算机程序来指令相关的硬件来完成,所述的计算机程序可存储于一非易失性计算机可读取存储介质中,该计算机程序在执行时,可包括如上述各方法的实施例的流程。其中,本申请所提供的各实施例中所使用的对存储器、存储、数据库或其它介质的任何引用,均可包括非易失性和/或易失性存储器。非易失性存储器可包括只读存储器(ROM)、可编程ROM(PROM)、电可编程ROM(EPROM)、电可擦除可编程ROM(EEPROM)或闪存。易失性存储器可包括随机存取存储器(RAM)或者外部高速缓冲存储器。作为说明而非局限,RAM以多种形式可得,诸如静态RAM(SRAM)、动态RAM(DRAM)、同步DRAM(SDRAM)、双数据率SDRAM(DDRSDRAM)、增强型SDRAM(ESDRAM)、同步链路(Synchlink) DRAM(SLDRAM)、存储器总线(Rambus)直接RAM(RDRAM)、直接存储器总线动态RAM(DRDRAM)、以及存储器总线动态RAM(RDRAM)等。
[0101] 以上实施例的各技术特征可以进行任意的组合,为使描述简洁,未对上述实施例中的各个技术特征所有可能的组合都进行描述,然而,只要这些技术特征的组合不存在矛盾,都应当认为是本说明书记载的范围。
[0102] 以上所述实施例仅表达了本申请的几种实施方式,其描述较为具体和详细,但并不能因此而理解为对发明专利范围的限制。应当指出的是,对于本领域的普通技术人员来说,在不脱离本申请构思的前提下,还可以做出若干变形和改进,这些都属于本申请的保护范围。因此,本申请专利的保护范围应以所附权利要求为准。