一种基于硬件的高级程序动态控制流追踪方法和装置

文档序号:25343018发布日期:2021-06-04 21:51阅读:170来源:国知局
一种基于硬件的高级程序动态控制流追踪方法和装置

1.本发明涉及基于硬件的高级程序执行的动态控制流追踪。


背景技术:

2.现代cpu大多配备了硬件追踪模块,比如intel processor trace (pt)和arm embedded tracemacrocell (etm),这些模块提供了高效率的控制流追踪能力。而控制流追踪技术在广泛的软件工程活动中发挥着重要的作用,包括测试、调试、性能分析等。比如我们获取了某个程序完整的控制流追踪信息,那么各种各样的执行信息如方法和语句覆盖、路径覆盖和调用信息都可以轻而易举的计算出。
3.现有的追踪技术主要包括两类:软件追踪和硬件追踪。软件追踪通常会对用户源代码进行插桩,通常依赖于编译器架构并且具有高昂的运行开销。硬件追踪相较于软件追踪,利用硬件追踪模块,具有更小的运行开销和通用性,并且不需要对源代码进行插桩修改。
4.到目前为止,基于硬件的追踪仅仅应用于可以直接运行在硬件上的本地程序。这是因为处理器只能处理硬件指令,而对本地程序而言,这些指令可以在源代码编译中产生的编译调试信息的帮助下轻松映射回源代码。但是随着诸如java,go和scala之类的高级语言在现代计算中起到日益重要的作用,迫切地需要对硬件模块进行扩展,使其能够为高级语言提供高效率的控制流追踪。
5.利用硬件追踪高级语言程序存在着巨大的挑战,主要是由高级语言运行时的复杂性导致的。例如执行java程序的java虚拟机(jvm),它在解释执行和jit(justintime)编译执行之间切换:jvm开始为解释执行,当一段代码或者方法变为热点代码或方法时,切换到jit编译模式,直接执行编译过的代码。同时,对于这类高级语言,cpu实际执行的指令与用户高级语言代码存在巨大差距,这不仅体现在机器码与字节码上的结构化差异上,还体现在不同编译策略下产生的代码的不同。比如在jvm中解释执行直接利用模版生成代码,而jit编译会对编译的代码进行多次优化。更麻烦的是运行时可能在代码中插入各种检查代码(比如读写障碍和边界检查),导致开发者所写的代码和实际cpu执行的存在巨大结构差异。


技术实现要素:

6.本发明所要解决的问题:对基于解释执行的高级语言程序实现硬件追踪。
7.为解决上述问题,本发明采用的方案如下:根据本发明的一种基于硬件的高级程序动态控制流追踪方法,包括如下步骤:s1:获取待追踪的程序;s2:对所述待追踪的程序进行静态分析,生成控制流图、类继承图和调用关系图;s3:收集通过虚拟机执行所述待追踪的程序时的字节码指令模版、执行信息和追踪数据;
s4:根据所生成的控制流图和所收集的字节码指令模版、追踪数据和执行信息,生成执行流图;s5:输出所述的执行流图;其中,所述步骤s3包括如下步骤:s31:启动虚拟机,然后对所启动的虚拟机进程进行处理器硬件追踪的初始化,使得处理器硬件追踪虚拟机进程得到的处理器控制流的追踪数据能够输至指定的追踪数据缓冲区,并由追踪数据转存模块将所述追踪数据缓冲区中的追踪数据转存至磁盘中;s32:当虚拟机进程对待追踪的程序初始化时,导出字节码指令模版;s33:当所述虚拟机对待追踪的程序初始化后,对所述虚拟机进程进行执行信息初始化,使得所述虚拟机进程执行程序生成机器码指令时,将字节码指令与机器码指令之间的映射信息输至指定的执行信息缓冲区,并由执行信息转存模块将所述执行信息缓冲区中的执行信息转存至磁盘中;所述执行信息为字节码指令与机器码指令之间的映射信息;s34:通过所述虚拟机进程执行所述待追踪的程序并开启处理器硬件追踪,通过所述追踪数据转存模块和所述执行信息缓存模块将所述待追踪的程序执行过程中的追踪数据和执行信息存入磁盘中;所述步骤s4包括如下步骤:s41:根据所述追踪数据的线程切换信息和时间戳信息,提取出属于待追踪的程序的追踪数据;s42:根据按内存地址信息确定所提取的追踪数据为解释执行数据还是实时执行数据;对于解释执行数据,根据所述字节码指令模版找到对应的字节码指令;对于实时执行数据,则对其进行解码,然后根据所述的字节码指令与机器码指令之间的映射信息,得到对应的字节码指令;s43:将字节码指令拼接成字节码指令流,然后字节码指令流在所述控制流图中找到相应的节点,并记录执行流数据生成执行流图节点;所述执行流数据包括执行次序标号和执行的时间戳。
8.进一步,根据本发明的基于硬件的高级程序动态控制流追踪方法,所述步骤s5中,输出所述的执行流图前,对所述执行流图判断是否存在执行流数据缺失的情形,若存在执行流数据缺失的情形则尽可能地补齐,包括如下步骤:s51:根据所述追踪数据的线程切换信息和时间戳信息,对所述的执行流图中的节点分线程按执行流数据的时间戳信息进行排序;s52:判断每个线程所排序的节点在时间戳上是否连续,若不连续,则标记为缺失点;s53:判断缺失点的前后连续节点是否存在执行流数据,若与缺失点其前后连续节点中有节点存在执行流数据,则将该执行流数据补入该缺失点。
9.根据本发明的一种基于硬件的高级程序动态控制流追踪装置,包括如下模块:m1,用于:获取待追踪的程序;m2,用于:对所述待追踪的程序进行静态分析,生成控制流图、类继承图和调用关系图;m3,用于:收集通过虚拟机执行所述待追踪的程序时的字节码指令模版、执行信息
和追踪数据;m4,用于:根据所生成的控制流图和所收集的字节码指令模版、追踪数据和执行信息,生成执行流图;m5,用于:输出所述的执行流图;其中,所述模块m3包括如下模块:m31,用于:启动虚拟机,然后对所启动的虚拟机进程进行处理器硬件追踪的初始化,使得处理器硬件追踪虚拟机进程得到的处理器控制流的追踪数据能够输至指定的追踪数据缓冲区,并由追踪数据转存模块将所述追踪数据缓冲区中的追踪数据转存至磁盘中;m32,用于:当虚拟机进程对待追踪的程序初始化时,导出字节码指令模版;m33,用于:当所述虚拟机对待追踪的程序初始化后,对所述虚拟机进程进行执行信息初始化,使得所述虚拟机进程执行程序生成机器码指令时,将字节码指令与机器码指令之间的映射信息输至指定的执行信息缓冲区,并由执行信息转存模块将所述执行信息缓冲区中的执行信息转存至磁盘中;所述执行信息为字节码指令与机器码指令之间的映射信息;m34,用于:通过所述虚拟机进程执行所述待追踪的程序并开启处理器硬件追踪,通过所述追踪数据转存模块和所述执行信息缓存模块将所述待追踪的程序执行过程中的追踪数据和执行信息存入磁盘中;所述模块m4包括如下模块:m41,用于:根据所述追踪数据的线程切换信息和时间戳信息,提取出属于待追踪的程序的追踪数据;m42,用于:根据按内存地址信息确定所提取的追踪数据为解释执行数据还是实时执行数据;对于解释执行数据,根据所述字节码指令模版找到对应的字节码指令;对于实时执行数据,则对其进行解码,然后根据所述的字节码指令与机器码指令之间的映射信息,得到对应的字节码指令;m43,用于:将字节码指令拼接成字节码指令流,然后字节码指令流在所述控制流图中找到相应的节点,并记录执行流数据生成执行流图节点;所述执行流数据包括执行次序标号和执行的时间戳。
10.进一步,根据本发明的基于硬件的高级程序动态控制流追踪装置,所述模块m5中,输出所述的执行流图前,对所述执行流图判断是否存在执行流数据缺失的情形,若存在执行流数据缺失的情形则尽可能地补齐,包括如下模块:m51,用于:根据所述追踪数据的线程切换信息和时间戳信息,对所述的执行流图中的节点分线程按执行流数据的时间戳信息进行排序;m52,用于:判断每个线程所排序的节点在时间戳上是否连续,若不连续,则标记为缺失点;m53,用于:判断缺失点的前后连续节点是否存在执行流数据,若与缺失点其前后连续节点中有节点存在执行流数据,则将该执行流数据补入该缺失点。
11.本发明的技术效果如下:1、本发明通过虚拟机执行待追踪程序收集字节码指令模版、执行信息和追踪数据,然后结合控制流图生成执行流图,从而实现对高级语言程序实现硬件追踪。
12.2、通过缺失补齐,减少因追踪数据磁盘导出速度不足而导致的缺失问题对执行流图产生的影响。
附图说明
13.图1是本发明实施例的流程和数据流向图。
14.图2是本发明实施例中的示例待追踪程序。
15.图3是图2中的程序经静态分析后得到的控制流图。
具体实施方式
16.下面结合附图对本发明做进一步详细说明。
17.本实施例一种基于硬件的高级程序动态控制流追踪方法是对java语言程序的动态控制流追踪,通过运行于intel处理器的计算机上的软件程序实现。与intel处理器对应的,硬件追踪基于intel processor trace (intel pt)开发包。与java语言程序对应的,虚拟机为java虚拟机。参照图1,本实施例的方法包括如下步骤:s1:获取待追踪的程序;s2:对所述待追踪的程序进行静态分析,生成控制流图、类继承图和调用关系图;s3:收集通过虚拟机执行所述待追踪的程序时的字节码指令模版、执行信息和追踪数据;s4:根据所生成的控制流图和所收集的字节码指令模版、追踪数据和执行信息,通过动态和静态数据融合,生成执行流图;s5:对执行流图缺失补缺后输出。
18.需要指出的是,步骤s4的输入基于步骤s2和s3的输出,而对于步骤s2和s3之间不存在输入输出关系,因此步骤s2和s3顺序可以交换。步骤s2和s3顺序交换后,也就是先通过虚拟机执行待追踪的程序收集字节码指令模版、执行信息和追踪数据,然后再执行对待追踪的程序的静态分析,此种顺序对本发明没有什么影响。
19.本实施例所针对的是java语言程序,因此,要求待追踪的程序为.class文件所组成的java语言源程序包。对于.java文件的源程序,需要将其转换成.class文件。对于.jar文件的源程序包,则需要事先进行解压缩处理。上述步骤s1中的“获取”表示“待追踪的程序”为本发明的输入。因此将.java文件或者.jar文件如何转换成.class文件不是本发明所讨论的范畴,不再赘述。
20.步骤s2中,对.class文件所组成的java语言源程序包中的各个.class文件进行逐个分析:对.class文件中每个类,收集其继承关系;对类中的每个方法,分析其字节码指令,生成控制流图,并收集每个方法以及其调用的函数信息;然后根据各个方法和函数的控制流图以及函数和/或方法的调用关系,最后得到整体的控制流图。控制流图是由节点和节点关系所组成的图。每个节点是由一段字节码指令序列组成的程序块。参照图2和图3,图2中的程序经静态分析后得到的控制流图如图3所示。图3中的每个方框为一个程序基本块组成的节点。每个程序基本块由依次排列的字节码指令所组成。上述步骤s2通过对程序进行静态分析获得控制流图的过程为本领域技术人员所熟悉,本说明书不再赘述。
21.步骤s3中,输出的信息包括字节码指令模版、执行信息和追踪数据。步骤s3包括如
下步骤:s31:启动虚拟机,然后对所启动的虚拟机进程进行处理器硬件追踪的初始化,使得处理器硬件追踪虚拟机进程得到的处理器控制流的追踪数据能够输至指定的追踪数据缓冲区,并由追踪数据转存模块将追踪数据缓冲区中的追踪数据转存至磁盘中。
22.s32:当虚拟机进程对待追踪的程序初始化时,导出字节码指令模版。
23.s33:当虚拟机对待追踪的程序初始化后,对虚拟机进程进行执行信息初始化,使得虚拟机进程执行程序生成机器码指令时,将字节码指令与机器码指令之间的映射信息输至指定的执行信息缓冲区,并由执行信息转存模块将执行信息缓冲区中的执行信息转存至磁盘中;执行信息为字节码指令与机器码指令之间的映射信息。
24.s34:通过虚拟机进程执行待追踪的程序并开启处理器硬件追踪,通过追踪数据转存模块和执行信息缓存模块将待追踪的程序执行过程中的追踪数据和执行信息存入磁盘中。
25.上述步骤s31至s34中,虚拟机本实施例中即为java虚拟机。
26.步骤s31中,对所启动的虚拟机进程进行处理器硬件追踪的初始化,本实施例通过调用intel pt中的perf_event_open系统函数实现。perf_event_open系统函数定义如下:
푖푛푡 perf_event_open(
푠푡푟푢푐푡 perf_event_attr
ꢀ∗ꢀ
attr, 푝푖
d_
푡푝푖
d,
푖푛푡푐푝푢
, 푖푛푡 group_fd, unsigned long flags)其中,参数pid和cpu用于确定监控的进程以及cpu核。本实施例中,pid也就是java虚拟机进程的进程号。通过设置perf_event_attr参数中的inherit属性,监控java虚拟机进程主线程fork出的所有线程。通过设置perf_event_attr参数,在内存中开辟控制流数据缓冲区。java虚拟机进程fork出的所有线程,以及java虚拟机执行java程序各个线程时,各线程的控制流信息都将存储至该缓冲区内。
27.此外,为解决缓冲区内存空间占用不足的问题。本发明通过追踪数据转存模块将该缓冲区内的控制流数据转存至磁盘中。这里的追踪数据包括:线程切换信息和控制流数据。控制流数据包括函数的调用信息以及转跳指令的转跳信息。
28.需要指出的是,在perf_event_open函数中,线程切换信息需要另一缓冲区进行存储。也就是,线程切换信息的缓冲区和前述的控制流数据缓冲区组成了本发明前述的追踪数据缓冲区。
29.步骤s32中,java虚拟机进程初始化时,java虚拟机进程在内存中分配固定大小的内存空间存储字节码指令模版。对于确定的java虚拟机,其创建的字节码指令模版是一致的。因此本实施例在java虚拟机进程初始化时导出字节码指令模版。然后在java虚拟机载入待追踪的java应用程序时,导出其对应待追踪的java应用程序的字节码指令模版的首地址即可得到对应的字节码指令模版。此外,本实施例的具体实施方式下,在java虚拟机进程初始化时,需要将字节码指令模版传送至intel pt中,载入待追踪的java应用程序时,需要将相应的首地址传送至intel pt中。
30.在java虚拟机的解释模式下,java虚拟机进程利用代码模版为每一种字节码指令生成一小段机器码,并在java虚拟机进程初始化后存储在内存中,即字节码指令模版,执行字节码时会直接跳转到对应机器码地址执行机器码。也就是字节码指令模版是字节码指令与机器码指令的快速对应表。
31.java虚拟机进程在执行java应用程序时,当某个方法或者函数被调用次数达到一定次数时,或者某个程序段的程序循环次数达到一定次数时,java虚拟机进程将该段代码视为热点代码,java虚拟机进程将热点代码通过编译器直接转换成机器码指令,下一次再执行该段代码时,直接转跳至该机器码指令的地址执行,从而提高java虚拟机执行java程序的效率。步骤s33中,字节码指令与机器码指令之间的映射信息是指java虚拟机进程将热点代码通过编译器直接转换成机器码指令时所导出的字节码指令与机器码指令之间的映射信息。
32.步骤s31、s32和s33都是步骤s3的初始化的过程,步骤s34为java虚拟机进程实际执行java应用程序的过程。步骤s34通过前述步骤s31、s32和s33的初始化配置使得java虚拟机进程执行java应用程序时,能够导出处理器硬件的追踪数据和执行信息。此外,通常步骤s34中需要通过调用ioctl函数开启intel pt的处理器硬件追踪。java应用程序执行结束时,需要调用ioctl函数关闭intel pt的处理器硬件追踪。
33.此外,需要指出的是,通过虚拟机进程执行待追踪的程序时,所产生的追踪数据较多,而追踪数据转存模块的转存速度可能跟不上所产生的追踪数据,由此,可能导致追踪数据缓冲区内的数据未经磁盘存储后就被覆盖,从而导致追踪数据转存模块所转存的数据有所缺失。
34.此外,本实施例中,追踪数据转存模块和执行信息缓存模块均采用进程实现。追踪数据缓冲区和执行信息缓冲区采用共享内存的方式。
35.步骤s4是对步骤s2和s3输出的数据进行分析的过程,包括如下步骤:s41:根据追踪数据的线程切换信息和其时间戳信息,提取出属于待追踪的程序的追踪数据;s42:根据按内存地址信息确定所提取的追踪数据为解释执行数据还是实时执行数据;对于解释执行数据,根据字节码指令模版找到对应的字节码指令;对于实时执行数据,则对其进行解码,然后根据的字节码指令与机器码指令之间的映射信息,得到对应的字节码指令;s43:将字节码指令拼接成字节码指令流,然后字节码指令流在控制流图中找到相应的节点,并记录执行流数据生成执行流图节点。
36.前述步骤s31中通过perf_event_open进行intel pt初始化配置时,设定了对java虚拟机进程中所有的线程进行控制流跟踪。步骤s3输出的追踪数据包括java虚拟机进程中所有线程的处理器控制流追踪数据。因此需要在步骤s41中,从这些线程的追踪数据中提取出属于待追踪程序的追踪数据。具体提取的方法依据追踪数据的线程切换信息根据线程切换信息中的线程入口字节码指令地址。判断该线程入口与字节码指令模版的首地址比较是否属于待追踪程序的字节码指令模版地址空间。此外,步骤s41中,需要从磁盘中载入追踪数据。
37.步骤s42中,首先将追踪数据按照线程切换和时间戳信息划分为多段,再将每段内的数据按内存地址信息划分为解释执行数据和实时执行数据。追踪数据中的控制流数据本身为机器码指令。如果该机器码指令的内存地址能够在字节码指令模版的地址空间中找到,属于某个字节码指令和机器码指令的对应信息中的机器码指令,则该控制流数据为解释执行数据,否则为实时执行数据。对于解析执行数据,直接从字节码指令模版所找到的字
节码指令和机器码指令的对应信息中提取出对应的字节码指令。对于实时执行数据,采用英特尔开源pt解码库libipt进行解码,然后根据前述执行信息,也就是,字节码指令与机器码指令之间的映射信息得到对应的字节码指令。
38.步骤s43中,字节码指令拼接成字节码指令流时,首先将其按照函数调用/返回指令进行划分拼接,划分成一个个函数。划分函数时,由于追踪数据的缺失,字节码指令可能存在缺失的情形,通过遍历前述调用关系图中的各个函数,对函数或方法的上下文匹配找到对应的函数。然后再将按照函数或方法拼接而成的字节码指令流和该函数或方法的控制流图的各个节点进行匹配。然后根据字节码指令流对照各个节点的顺序标记执行的次序,并将相应字节码指令流的时间戳信息加入至该节点。控制流图各个节点标记执行次序和添加了时间戳信息后即成为执行流图。也就是,相比于控制流图,执行流图的每个节点包括了执行次序标号和执行的时间戳。执行次序标号和执行的时间戳也即为执行流数据。比如图3中,节点b01至b06分别为6个节点,其中某次执行时,按照节点b01、b03、b04、b06的次序执行,则节点b01、b03、b04、b06的执行次序标号分别为1,2,3,4;而对于节点b02和b05未经执行,则执行次序标号设为

1。
39.需要指出的是,由于java应用程序存在多线程执行的情形和函数或方法的控制流图存在多次执行的情形,为此,执行流图中的每个节点标记的执行次序信息和执行时间戳信息有多个,组成集合。
40.步骤s5中的执行流数据缺失是由前述的追踪数据缺失所导致的。比如,图3中,某次执行时,根据追踪数据得到字节码指令流匹配后,得到的执行次序为:节点b01、节点b03、节点b06。显而易见地,这其中必然缺失了节点b04的执行。此时,节点b04的可以对照参照节点b03或节点b06的执行流数据,直接将节点b03或节点b06的执行流数据作为节点b04的执行流数据。考虑到执行流图中,每个节点可能包含多个执行流数据,为此本实施例采用如下方法:s51:根据所述追踪数据的线程切换信息和时间戳信息,对所述的执行流图中的节点分线程按执行流数据的时间戳信息进行排序;s52:判断每个线程所排序的节点在时间戳上是否连续,若不连续,则标记为缺失点;s53:判断缺失点的前后连续节点是否存在执行流数据,若与缺失点其前后连续节点中有节点存在执行流数据,则将该执行流数据补入该缺失点。
41.需要指出的是,上述的执行流数据缺失补齐处理过程中,可能由于追踪数据缺失较多,而无法补齐的情形。因此上述过程也只能尽可能地进行缺失补齐,而无法补充完整。
42.此外,还需要指出的是,若追踪数据转存模块转存数据的速度够快,追踪数据缓冲区足够大,此时,追踪数据不会缺失,此时,不需要前述的追踪数据缺失补齐过程,可以直接输出执行流图。
当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1