一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

利用跟踪代码的记录执行来仿真非跟踪代码的制作方法

2021-11-10 03:00:00 来源:中国专利 TAG:

利用跟踪代码的记录执行来仿真非跟踪代码


背景技术:

1.追踪和纠正不期望的软件行为是软件开发中的核心活动。不期望的软件行为可以包括很多事情,诸如执行崩溃、运行时异常、执行性能缓慢、数据结果不正确、数据损坏等。不期望的软件行为可能由多种因素触发,诸如数据输入、用户输入、竞争条件(例如,当访问共享资源时)等。鉴于触发的多样性,不期望的软件行为可能稀有并且看似随机,并且极难重现。因此,对于开发者标识给定的不期望软件行为,可以是非常耗时的和困难的。一旦不期望的软件行为已经被标识,确定其(多个)根本原因就可以再次是耗时的和困难的。
2.开发者通常使用各种方法来标识不期望的软件行为,然后标识应用代码中引起不期望软件行为的(多个)位置。例如,开发者可以针对不同的输入来测试应用代码的不同部分(例如,单元测试)。作为另一示例,开发者可以在调试器中对应用代码的执行进行推理(例如,在代码执行时,通过设置断点/观察点,通过单步执行代码行等)。作为另一示例,开发者可以在分析器中观察代码执行行为(例如,时序、覆盖率)。作为另一示例,开发者可以将诊断代码(例如,跟踪语句)插入到应用的代码中。
3.虽然常规诊断工具(例如,调试器、分析器等)已经在“实时”前向执行代码上操作,但一种新兴形式的诊断工具使能了“历史”调试(也被称为“时间旅行”或“反向”调试),其中(多个)程序线程的至少一部分的执行被记录到一个或多个跟踪文件中(即记录执行)。使用一些跟踪技术,记录执行可以包含“位准确(bit

accurate)”的历史跟踪数据,这使得(多个)跟踪线程的(多个)记录部分能够被虚拟地“重放”,直到单独的指令的粒度(例如,机器代码指令、中间语言代码指令等)。因此,使用“位准确”跟踪数据,诊断工具可以使得开发者能够推理关于主题代码的记录先前执行,而不是该代码的“实时”前向执行。例如,历史调试器可以使能前向和反向断点/观察点两者,可以使得代码能够向前和向后步进两者,等等。另一方面,历史分析器可以能够从先前执行的代码导出代码执行行为(例如,时序、覆盖率)。


技术实现要素:

4.本文描述的至少一些实施例利用历史调试技术,基于来自相关的跟踪代码的记录执行的跟踪数据,来仿真非跟踪代码的执行。换句话说,实施例可以使用第一代码的记录执行来指导没有被跟踪到该记录执行中的第二代码的仿真。在实施例中,第一代码和第二代码具有差异,但在功能上相关。例如,它们可以使用不同的编译器和/或不同的编译器设置从相同的源代码编译,或者可以从相同源代码项目的不同版本编译。如本文将解释的,利用相关的跟踪代码的记录执行来仿真非跟踪代码可以用于许多有用目的,诸如标识编译器缺陷(例如,当不同的编译器标志、编译器版本或编译器产品导致从相同源代码产生功能不同的二进制文件)、确定源代码改变是否解决了不期望的软件行为和/或引入了新的不期望的软件行为,或者使得能够基于优化代码的跟踪来调试非优化代码。
5.在一些实施例中,方法、系统和计算机程序产品使用在第一可执行代码的执行期间收集的跟踪数据来仿真第二可执行代码的执行。特别地,第一可执行代码的先前执行的
可重放记录执行被访问。可重放记录执行包括一个或多个输入,该一个或多个输入在第一可执行代码的先前执行期间由一个或多个第一可执行指令消耗。与第一可执行代码不同的第二可执行代码也被访问。第二可执行代码的执行没有被记录在可重放记录执行中。使用来自可重放记录执行的一个或多个输入来仿真第二可执行代码的执行。实施例可以报告第二可执行代码的仿真执行与第一可执行代码的先前执行之间的一个或多个差异,或者可以报告第二可执行代码的仿真执行与第一可执行代码的先前执行之间的等效性。
6.提供本发明内容以简化的形式介绍一些概念,这些概念将在下面的具体实施方式中进一步被描述。本发明内容不旨在标识所要求保护的主题的关键特征或必要特征,也不旨在用于帮助确定所要求保护的主题的范围。
附图说明
7.为了描述可以获取本发明的上述及其他优点和特征的方式,将通过参考在附图中图示的本发明的特定实施例来对以上简要描述的本发明进行更具体的描述。应当理解,这些附图仅描绘了本发明的典型实施例,并且因此不应当认被为是对本发明范围的限制,将通过使用附图以附加的特征和细节来描述和解释本发明,其中:
8.图1a图示了示例计算环境,该示例计算环境促进利用相关的跟踪代码的记录执行来仿真非跟踪代码;
9.图1b图示了示例调试组件;
10.图2图示了示例计算环境,其中图1a的计算机系统通过一个或多个网络被连接到一个或多个其他计算机系统;
11.图3图示了记录执行的示例;
12.图4图示了两个应用的代码中的对应函数之间的映射的示例,其中函数基于其输入和输出而被标识;以及
13.图5图示了示例方法的流程图,该示例方法用于使用在第一可执行代码的执行期间收集的跟踪数据来仿真第二可执行代码的执行。
具体实施方式
14.本文描述的至少一些实施例利用历史调试技术,来基于来自相关跟踪代码的记录执行的跟踪数据,来仿真非跟踪代码的执行。换句话说,实施例可以使用第一代码的记录执行来指导没有被跟踪到该记录执行中的第二代码的仿真。在实施例中,第一代码和第二代码具有差异,但在功能上相关。例如,它们可以使用不同的编译器和/或不同的编译器设置从相同的源代码被编译,或者可以从相同的源代码项目的不同版本被编译。如本文将解释的,利用相关的跟踪代码的记录执行来仿真非跟踪代码可以用于许多有用目的,诸如标识编译器缺陷(例如,当不同的编译器标志、编译器版本或编译器产品导致从相同源代码产生功能不同的二进制文件)、确定源代码改变是否解决了不期望的软件行为和/或引入了新的不期望的软件行为,或者使得能够基于优化代码的跟踪来调试非优化代码。
15.如所指示的,本文的实施例在可执行实体的记录执行上操作。在本描述中以及在所附权利要求中,“记录执行”可以指代存储(多个)代码指令的先前执行的记录的任何数据,或者可以被用于至少部分地重建先前执行的(多个)代码指令的先前执行的任何数据。
一般地,这些代码指令是可执行实体的一部分,并且在(多个)物理或虚拟处理器上作为线程和/或进程(例如,作为机器代码指令)执行,或在管理运行时执行(例如,作为中间语言代码指令)。
16.由本文的实施例使用的记录执行可以由各种历史调试技术生成。一般地,历史调试技术在各个时间处记录或重建实体的执行状态,以便使得能够在以后从该执行状态至少部分地仿真该实体的执行。该虚拟执行的保真度取决于可用的记录执行状态而变化。
17.例如,在本文中被称为时间旅行调试的一类历史调试技术连续地记录实体执行的位准确跟踪。然后,在以后可以使用该位准确跟踪来忠实地重放该实体的先前执行,直到单独的代码指令的保真度。例如,位准确跟踪可以记录足以重现针对线程的先前执行中至少一个点的初始处理器状态的信息(例如,通过记录处理器寄存器的快照),以及由线程的指令(在它们在该时间点之后执行时)读取的数据值(例如,存储器读取)。然后,可以基于向指令提供所记录的读取,使用该位准确跟踪来重放线程的代码指令(从初始处理器状态开始)的执行。
18.在本文中被称为分支跟踪调试的另一类历史调试技术,依赖于基于从转储(dump)或快照(例如,线程的崩溃转储)向后工作来重建实体的执行状态的至少一部分,该转储或快照包括处理器分支跟踪(即,包括分支是否被采用的记录)。这些技术从来自该转储或快照的值(例如,存储器和寄存器)开始,并且使用分支跟踪来至少部分地确定代码执行流程,迭代地重放实体的代码指令并且向后和向前,以便重建由该代码使用的中间数据值(例如,寄存器和存储器),直到那些值达到稳定状态为止。这些技术在它们向后可以重建多远的数据值,以及可以重建多少数据值方面可能受到限制。尽管如此,重建的历史执行数据可以被用于历史调试。
19.在本文中被称为重放和快照调试的又一类历史调试技术,在它执行时,周期性地记录实体的存储器空间和处理器寄存器的完整快照。如果实体依赖于来自实体自身存储器以外的其他源的数据,或者来自非确定性源的数据,则这些技术也可以将这种数据与快照一起记录。然后,这些技术使用快照中的数据来重放在快照之间的实体的代码的执行。
20.图1a图示了示例计算环境100a,其促进利用相关的跟踪代码的记录执行来仿真非跟踪代码。如所描绘的,计算环境100a可以包括或利用专用或通用计算机系统101,其包括计算机硬件,诸如例如一个或多个处理器102、系统存储器103、持久性存储装置104,和/或(多个)网络设备105,它们使用一个或多个通信总线106被通信耦合。
21.在本发明范围内的实施例可以包括用于携带或存储计算机可执行指令和/或数据结构的物理和其他计算机可读介质。这种计算机可读介质可以是可以由通用或专用计算机系统访问的任何可用介质。存储计算机可执行指令和/或数据结构的计算机可读介质是计算机存储介质。携带计算机可执行指令和/或数据结构的计算机可读介质是传输介质。因此,作为示例而非限制,本发明的实施例可以包括至少两种截然不同的计算机可读介质:计算机存储介质和传输介质。
22.计算机存储介质是存储计算机可执行指令和/或数据结构的物理存储介质(例如,系统存储器103和/或持久性存储装置104)。物理存储介质包括计算机硬件,诸如ram、rom、eeprom、固态驱动器(“ssd”)、闪存、相变存储器(“pcm”)、光盘存储装置、磁盘存储装置或其他磁存储设备,或任何其他(多个)硬件存储设备,其可以被用于以计算机可执行指令或数
据结构的形式存储程序代码,程序代码可以由通用或专用计算机系统访问和执行以实现本发明的所公开的功能。
23.传输介质可以包括网络和/或数据链路,它们可以被用于携带计算机可执行指令或数据结构形式的程序代码,并且可以被通用或专用计算机系统访问。“网络”被定义为使得能够在计算机系统和/或模块和/或其他电子设备之间传输电子数据的一个或多个数据链路。当信息通过网络或另一通信连接(硬连线、无线或硬连线或无线的组合)传送或提供给计算机系统时,计算机系统可以将该连接视为传输介质。上述的组合也应当被包括在计算机可读介质的范围内。
24.此外,一旦到达各种计算机系统组件,计算机可执行指令或数据结构形式的程序代码就可以被自动地从传输介质传送到计算机存储介质(或反之)。例如,通过网络或数据链路接收的计算机可执行指令或数据结构可以被缓存在网络接口模块(例如,(多个)网络设备105)内的ram中,然后最终被传送到计算机系统ram(例如,系统存储器103)和/或在计算机系统处的易失性较低的计算机存储介质(例如,持久性存储装置104)。因此,应当理解,计算机存储介质可以被包括在也(或甚至主要)利用传输介质的计算机系统组件中。
25.例如,计算机可执行指令包括指令和数据,当该指令和数据在一个或多个处理器处执行时,使通用计算机系统、专用计算机系统或专用处理设备执行某些功能或功能组。计算机可执行指令可以是例如机器代码指令(例如,二进制文件)、中间格式指令(诸如汇编语言),或甚至源代码。
26.本领域技术人员应当理解,可以在具有许多类型的计算机系统配置的网络计算环境中实践本发明,计算机系统配置包括个人计算机、台式计算机、膝上型计算机、消息处理器、手持式设备、多处理器系统、基于微处理器或可编程的消费类电子产品、网络pc、小型计算机、大型计算机、移动电话、pda、平板电脑、寻呼机、路由器、交换机等。也可以在通过网络(通过硬连线数据链路、无线数据链路,或通过硬连线和无线数据链路的组合)链接的本地和远程计算机系统两者都执行任务的分布式系统环境中实践本发明。如此,在分布式系统环境中,计算机系统可以包括多个组成计算机系统。在分布式系统环境中,程序模块可以位于本地和远程存储设备两者中。
27.本领域技术人员还应当理解,本发明可以在云计算环境中被实践。云计算环境可以是分布式的,尽管这不是必需的。当分布式时,云计算环境可以在组织内在国际上分布和/或具有跨多个组织拥有的组件。在本描述和所附权利要求中,“云计算”被定义为一种模型,用于使能对可配置计算资源(例如,网络、服务器、存储装置、应用和服务)的共享池的按需网络访问。“云计算”的定义不限于在正确部署时可以从这种模型获取的其他众多优势中的任何一个。
28.云计算模型可以由各种特征组成,诸如按需自助服务、广泛的网络访问、资源池、快速弹性、可衡量的服务等。云计算模型还可以以各种服务模型的形式出现,诸如例如软件即服务(“saas”)、平台即服务(“paas”)和基础设施即服务(“iaas”)。也可以使用诸如私有云、社区云、公共云、混合云等不同的部署模型来部署云计算模型。
29.诸如云计算环境的一些实施例可以包括一种系统,该系统包括一个或多个主机,每个主机均能够运行一个或多个虚拟机。在操作期间,虚拟机仿真操作性计算系统,该操作性计算系统支持操作系统并且可能还支持一个或多个其他应用。在一些实施例中,每个主
机包括管理程序,该管理程序使用从虚拟机的角度抽象出的物理资源来仿真用于虚拟机的虚拟资源。管理程序还可以在虚拟机之间提供适当的隔离。因此,从任何给定虚拟机的角度来看,管理程序提供了虚拟机正在与物理资源接合的错觉,即使虚拟机仅与物理资源的表象(例如,虚拟资源)接合。物理资源的示例包括处理能力、存储器、磁盘空间、网络带宽、媒体驱动器等。
30.如图1a中所示,每个处理器102可以包括(除其他外)一个或多个处理单元107(例如,处理器核)和一个或多个高速缓存108。每个处理单元107经由高速缓存108加载和执行机器代码指令。在这些机器代码指令在一个或多个执行单元107b处的执行期间,指令可以使用内部处理器寄存器107a作为临时存储位置,并且可以经由高速缓存108来读取和写入系统存储器103中的各个位置。一般地,高速缓存108临时地高速缓存系统存储器103的多个部分;例如,高速缓存108可以包括“代码”部分,其高速缓存系统存储器103的存储应用代码的部分,并且可以包括“数据”部分,其高速缓存系统存储器103的存储应用运行时数据的部分。如果处理单元107需要尚未被存储在高速缓存108中的数据(例如,代码或应用运行时数据),则处理单元107可以发起“高速缓存未命中”,使得从系统存储器103取回所需数据

同时潜在地将一些其他数据从高速缓存108“驱逐”回系统存储器103。
31.如所图示的,持久性存储装置104可以存储表示可执行软件组件的计算机可执行指令和/或数据结构;对应地,在(多个)处理器102执行该软件期间,这些计算机可执行指令和/或数据结构的一个或多个部分可以被加载到系统存储器103中。例如,持久性存储装置104被示出为存储计算机可执行指令和/或数据结构(对应于调试组件109、仿真组件110和应用113)以及一个或多个记录执行114(例如,使用上面描述的历史调试技术中的一种或多种技术生成)。
32.一般地,调试组件109利用仿真组件110,以便基于从记录执行114中的一个或多个记录执行获取的执行状态数据,来仿真应用113的代码的执行。因此,图1a示出了,调试组件109和仿真组件110被加载到系统存储器103(即,调试组件109’和仿真组件110’)中,并且应用113在仿真组件110’(即,应用113’)内被仿真。
33.持久性存储装置104和系统存储器103也被示出为潜在地存储与跟踪器组件111和应用112相对应的计算机可执行指令和/或数据。这些组件以虚线被示出,因为它们可能存在于一些其他计算机系统,而不是存在于计算机系统101(尽管除存在于计算机系统101之外,它们也可以存在于其他(多个)计算机系统中)。通常,跟踪器组件111将应用112的(多个)先前执行记录或跟踪到(多个)记录执行114中(例如,使用一种或多种类型的上面描述的历史调试技术)。例如,如果计算机系统101包括跟踪器组件111和应用112,则这些组件可以被加载到系统存储器103中(即,跟踪器组件111’和应用112’);然后,如由应用112’和记录执行114’之间的箭头所指示,跟踪器组件111’可以将应用112’在(多个)处理器102处的执行记录到记录执行114’中(然后可以将其保持到持久性存储装置104作为记录执行114)。
34.备选地,计算机系统101可以从另一计算机系统(例如,使用(多个)网络设备105)接收记录执行114中的一个或多个记录执行。例如,图2图示了示例计算环境200,其中图1a的计算机系统101通过一个或多个网络201被连接到一个或多个其他计算机系统202(即,202a

202n)。如所示的,在示例200中,每个计算机系统202包括跟踪器组件111和应用112的副本。如此,计算机系统101可以通过(多个)网络201从这些(多个)计算机系统202接收应用
112的一个或多个记录执行114。
35.返回到图1a,如由应用112和应用113之间的箭头所指示的,这些应用在功能上相关。例如,应用112和应用113可以在功能上相关,因为它们是从相同的源代码被编译的,但具有不同的编译器设置。例如,应用112可以是具有使能的一个或多个编译器优化标志的构建(例如,“生产构建”),同时应用113可以是具有禁用的这些编译器优化标志的构建(例如,“调试”构建)。附加地或备选地,应用112可以利用一个版本的编译器被编译,同时应用113利用另一版本的编译器被编译。附加地或备选地,应用112和应用113可以一起利用不同的编译器产品被编译。作为另一示例,应用112和应用113可能在功能上相关,因为它们从相同代码的不同版本被编译。例如,应用112可以从一个版本的源代码被构建,同时应用113从包括修复(诸如,缺陷修复和/或性能改进)的更新版本的源代码被构建。
36.应注意,虽然调试组件109、仿真组件110和/或跟踪器组件111可以均是独立的组件或应用,但它们也可以备选地被集成到相同的应用中(诸如调试套件),或者可以被集成到另一软件组件中——诸如操作系统组件、管理程序、云结构等。如此,本领域技术人员还应当理解,本发明可以在计算机系统101是其一部分的云计算环境中被实践。
37.之前提到,调试组件109利用仿真组件110,以便使用来自记录执行114中的一个或多个记录执行的执行状态数据来仿真应用113的代码的执行。然而,也如所讨论的,在实施例中,记录执行114可以与应用112(而不是应用113)的先前执行相对应。如此,根据本文的实施例,调试组件109可以使用与应用112的先前执行相关的执行状态数据,以便指导与应用113(而不是应用112)相对应的可执行代码的仿真。因此,调试组件109可以有效地使用仿真组件110来基于相关的跟踪代码(即,应用112)的记录执行(即,记录执行114)来指导非跟踪代码(即,应用113)的仿真。
38.鉴于本文的公开内容,应当理解,利用相关的跟踪代码的记录执行来仿真非跟踪代码可以被用于许多调试目的。例如,它可以被用于检测/标识编译器中的缺陷或差异。例如,如果应用112和应用113两者都是从相同的源代码被编译的,但是利用不同的编译器产品、不同的编译器设置和/或不同的编译器版本,则应用112和应用113在它们的执行期间应当都表现出等效的行为。然而,如果与应用112在其记录执行期间产生的结果相比,基于记录执行114的应用113的仿真产生了不同的结果,则存在编译器缺陷的证据(或者,编译器产品或版本之间至少存在功能性差异)。
39.在另一示例中,利用相关的跟踪代码的记录执行来仿真非跟踪代码可以被用于测试源代码改变,该源代码改变应当仅进行性能改进。例如,如果应用113从一个版本的源代码被编译,该版本与从其被编译的应用112的源代码的版本相比仅包括性能改进,那么当应用113使用在应用112的执行期间收集的跟踪数据被仿真时,应用113应当表现出与应用112等效的行为;如果存在差异,则性能改进引起了行为改变,该行为改变可能已经引入了(多个)缺陷/(多个)退化。
40.在另一示例中,利用相关的跟踪代码的记录执行来仿真非跟踪代码可以被用于测试源代码改变,该源代码改变应当仅进行缺陷修复。例如,假设记录执行114包括应用112的10个记录执行,其中两个表现出一些不期望的行为(例如,缺陷)。如果应用113从包括针对该缺陷的修复的源代码版本被编译,则应用113在使用该两个记录执行(在此期间应用112表现出不期望的行为)仿真时不应当表现出不期望的行为;否则,该缺陷很可能未被修复。
此外,当使用其他8个记录执行来仿真应用113时,应用113应当表现出与应用112等效的行为;否则,缺陷修复可能引入了新的(多个)缺陷/(多个)退化。
41.在另一示例中,基于在优化代码的执行期间捕获的跟踪数据,利用相关的跟踪代码的记录执行114来仿真非跟踪代码可以被用于调试使用非优化代码的记录执行114。如本领域技术人员应当理解的,人类用户可能难以推理关于在使能的编译器优化的情况下编译的代码的执行。例如,当在调试器中使优化代码的执行可视化时,所执行的代码流可能看起来与人类用户交互的源代码的期望代码流不对应。因此,例如,应用112可以是处于活跃使用的编译器优化的“生产”构建,其执行被跟踪到记录执行114中。因为应用112包括优化代码,人类用户可能难以推理关于被跟踪到记录执行114中的执行行为(例如,如果调试组件109引起使用记录执行114来仿真应用112)。然而,实施例可以使用该记录执行114中的跟踪数据来仿真应用113的执行,这可以是在没有使能的优化设置的情况下被编译的“调试”构建——使得对于人类用户更容易推理关于被跟踪到记录执行114中的执行行为。
42.为了演示调试组件109可以如何利用相关的跟踪代码(例如,应用112)的记录执行来完成非跟踪代码(例如,应用113)的仿真,图1b图示了示例100b,其提供图1a的调试组件109的附加的细节。所描绘的调试组件109包括各种组件(例如,数据访问115、分析116、替代117、输入/输出比较118、输出119等),各种组件表示调试组件109可以根据本文描述的各种实施例实现的各种功能。应当理解,所描绘的组件——包括它们的身份、子组件和布置——仅被呈现为帮助描述本文描述的调试组件109的各种实施例,并且这些组件不限于软件和/或硬件可以实现本文描述的调试组件109或其特定功能的各种实施例。
43.数据访问组件115包括跟踪访问子组件115a和代码访问子组件115b。跟踪访问子组件115a访问记录执行,诸如应用112的先前执行的记录执行114。图3图示了可以由跟踪访问子组件115a访问的记录执行300的一个示例,其中记录执行300可以使用时间旅行调试技术而已经被生成。
44.在图3的示例中,记录执行300包括多个数据流301(即,301a

301n)。在实施例中,每个数据流301记录从应用112的代码执行的不同线程的执行。例如,数据流301a可以记录应用112的第一线程的执行,同时数据流301n记录应用112的第n线程。如所示的,数据流301a包括多个数据分组302。由于记录(log in)在每个数据分组302中的特定数据可以变化,所以它们被示为具有变化的大小。一般地,当使用时间旅行调试技术时,每个数据分组302至少记录作为应用112的该第一线程的一部分执行的一个或多个可执行指令的输入(例如,寄存器值、存储器值等)。如所示的,数据流301a还可以包括一个或多个关键帧303(例如,303a、303b),每个关键帧记录足够的信息,诸如寄存器值和/或存储器值的快照,该信息使得线程的先前执行能够被仿真组件110从关键帧的点开始向前重放。
45.在实施例中,记录执行114可以包括被执行的实际代码。因此,在图3中,每个数据分组302被示为包括非阴影数据输入部分304和阴影代码部分305。在实施例中,每个数据分组302的代码部分305可以包括可执行指令,该可执行指令基于对应的数据输入而被执行。然而,在其他实施例中,记录执行114可以省略被执行的实际代码,而是依赖于对应用112的代码(例如,来自持久性存储装置104)的单独访问。在这些其他实施例中,每个数据分组可以例如指定适当的(多个)可执行指令的地址或偏移。
46.返回到图1b,数据访问组件115的代码访问子组件115b获取应用112和应用113两
者的代码。如果由跟踪访问子组件115a获取的记录执行114包括应用112的代码(例如,代码部分305),则代码访问子组件115b可以从记录执行114提取应用112的代码。备选地,代码访问子组件115b可以从持久性存储装置104获取应用112的代码。在任一情况下,代码访问子组件115b可以从持久性存储装置104获取应用113的代码。
47.基于由代码访问子组件115b访问的代码,分析组件116标识应用112和应用113中不同代码段之间的映射,该映射可用于使用执行状态数据(例如,数据分组302的数据输入部分304)来仿真应用113的代码,该执行状态数据在应用112的执行期间被记录在记录执行114中。如所示的,例如,分析组件116包括函数标识子组件116a。函数标识子组件116a标识应用112和应用113的代码中的对应的“函数”之间的映射(基于标识这些函数的输入和输出)。
48.例如,图4图示了应用112和应用113的代码中的对应的“函数”之间的映射的示例400,其中基于它们的输入和输出来标识函数。特别地,图4示出了应用112的代码的表示401a,以及应用113的代码的表示401b。图4还示出了在两个表示401中的不同的代码块(函数)之间存在对应关系。例如,表示401a中的函数402

a1对应于表示401b中的函数402

b1,表示401a中的函数402

a2对应于表示401b中的函数402

b2,等等。值得注意的是,虽然为了清楚起见,所标识的函数之间存在线性对应关系,但不需要如此。例如,在备选映射中,可以是:函数402

a9对应于函数402

b1,并且函数402

a1对应于函数402

b9,使得函数402

a9和函数402

b1之间的箭头将与函数402

a1和函数402

b9之间的箭头交叉。
49.如本文所使用的,“函数”被定义为一个或多个执行段的集合,每个段包括具有零个或多个“输入”和一个或多个“输出”的一个或多个可执行指令块。应用112的代码中的函数可以映射到应用113的代码中的对应函数(如果这些函数都从相同的(多个)输入读取并且写入到相同的(多个)输出,即使这些函数中的代码不相同)。例如,在图4中,每个函数402具有对应的(多个)输入集403和对应的(多个)输出集404。例如,应用112中的函数402

a1具有输入集403

1和输出集404

1,应用112中的函数402

a2具有(多个)输入集403

2和输出集404

2等。如所示的,应用112和应用113之间的对应函数具有相同的输入集和输出集。例如,应用113中的函数402

b1具有与应用112中的函数402

a1相同的输入集和输出集(即,输入403

1和输出404

1),应用113中的函数402

b2具有与应用112中的函数402

a2相同的输入集和输出集(即,输入403

2和输出404

2)等。通常,函数标识子组件116a试图映射在行为上密切相关的函数。
50.如本文所使用的,“输入”被定义为函数(如上面所定义的)从中读取,并且在读取之前函数本身没有对其写入的任何数据位置。这些数据位置可以包括,例如,在进入函数时存在的寄存器,和/或函数从中读取但它本身没有分配的任何存储器位置。如果函数分配存储器,然后在初始化它之前从该存储器读取,则可能出现边缘情况。在这些情况下,实施例可以将对未初始化存储器的读取视为输入,或视为缺陷。如本文所使用的,“输出”被定义为函数写入的任何数据位置(例如,寄存器和/或存储器位置),函数稍后不会解除分配该数据位置。例如,在函数入口处的堆栈分配,跟随着对分配区域的写入,跟随着在函数退出处的堆栈解除分配,不会被视为函数输出。
51.在实施例中,函数标识组件116a可以依赖于操作系统的已知应用二进制接口(abi)和处理器指令集架构(isa),(多个)应用112/113针对该两者被编译,以便知道哪些
(多个)寄存器是函数的(多个)输入和/或哪些(多个)寄存器是来自函数的(多个)输出——这减少了单独地追踪寄存器的需要。因此,例如,代替单独地追踪寄存器,函数标识组件116a可以使用针对其编译了(多个)应用112/113的abi,以确定(多个)应用112/113使用哪些(多个)寄存器来将参数传递到函数,和/或(多个)应用112/113使用哪些(多个)寄存器来返回值。在实施例中,调试符号可以被用于补充或替换abi信息。值得注意的是,即使调用函数忽略被调用函数的返回值,abi和/或符号仍可以被用于确定被用于存储被调用函数的返回值的寄存器的内容是否已经改变。
52.如所提及的,给定函数可以是一个或多个可执行指令的一个或多个段的集合。有时,为了标识从一个应用干净地映射到另一应用的函数,可以采用多个段。例如,可能的是,特定段可以在一个应用(例如,应用112)中可标识,而该应用未干净地映射到其他应用(例如,应用113)。如此,对于在应用之间映射的“函数”(即,具有相同的输入和输出,并且进行相同的工作),该段本身将是糟糕的选择。即使从相同的源代码被编译,这种差异也可以由于编译器优化设置而出现,其中应用113中的代码由编译器以不直接映射到应用112的方式被转换。例如,虽然有区别的代码段(具有定义的输入集和输出集)可以在应用112(例如,非优化代码)中可标识,但在应用113(例如,优化代码)中,它可以被完全优化掉。备选地,虽然应用112中的第一代码段可以具有与应用113中的第二代码段共同的输入集和输出集,但应用112中的第一代码段可以做一些工作,这些工作已经从应用113中的第二代码段被优化掉,并且被放置到应用113中的第三代码段中;例如,一些工作可能已经脱离循环。因此,为了促进这两个应用之间的干净函数映射,被标识为映射到另一应用的给定“函数”实际上可以是多个段的集合。例如,在上述示例中,其中在应用113中编译器将代码完全优化掉,或者编译器将工作从应用113中的第二代码块移动到应用113中的第三代码块,实际上可能需要将应用112和应用113中的一个或两者中的两个(或更多个)段组合,以便在应用112和应用113之间达到共同的函数,该共同的函数具有可映射的输入集和输出集,并且进行等效的工作。
53.在实施例中,当将函数定义为段的集合时,这可以包括性地、排他性地或介于两者之间的某处来完成。例如,假设函数标识子组件116a可以标识应用112中的三个段——a、b和c——在跟踪执行期间,其中段a调用段b,并且其中段b中调用段c。在该情况下,应用112中的单个“函数”(并且与应用113进行映射)可以被定义为段a、段b和段c中的代码块的总和(即,包括在跟踪执行期间段a调用的一切)。备选地,用于与应用113映射的单个“函数”可以被定义为仅段a中的代码块(即,排除在跟踪执行期间函数a调用的段)。再次备选地,用于与应用113映射的单个“函数”可以被定义为段a和段b(而不是段c)中的代码块的总和(即,部分包括和部分排除)。
54.在实施例中,函数标识组件116a可以定义和映射包括指令序列的函数,该指令序列在它们的执行内具有一个或多个间隙。例如,函数可以包括在它们执行的中间进行内核调用(不被记录)的指令序列。为了说明,函数402

a1可以将文件句柄和字符作为输入,并且包括将文件的每个字节与输入字符进行比较以查找在文件中该字符的出现的指令。因为它们依赖于文件数据,因此这些指令可以进行一个或多个内核调用来读取文件(例如,使用句柄作为内核调用的参数)。该函数402

a1(与其(多个)间隙一起)然后可以被映射到函数402

b1

函数402

b1可以是那些指令的备选实现/编译,具有它们自己的(多个)间隙。为了
标识/映射具有间隙的函数,函数标识组件116a可以需要确保这些间隙在函数402

a1和402

b1中的每个函数中关于比较操作被正确排序,因此文件数据在函数402

a1和402

b1中的每个函数中以相同的顺序被处理。由于函数402

a1和函数402

b1的输入集403

a和输出集404

1没有改变,任何差异都将是函数内部的,并且这些差异(例如,不同的本地数据结构)最终被解除分配(例如,堆栈弹出是解除分配),因此差异不会影响函数的输出。注意,在实施例中,在(多个)记录执行113中追踪了由内核调用改变的任何寄存器值。然而,函数标识组件115a可以附加地或备选地使用abi和/或调试符号,以追踪跨内核调用保留了哪些寄存器值。例如,跨内核调用保留了堆栈指针(即,x85上的esp或arm上的r13)。
55.在实施例中,输入和输出是可组成的。例如,如果应用112中的单个函数被包括性地定义为段a、段b和段c中的整个代码,那么该函数的输入集可以被定义为包括段a、段b和段c的输入中的每个输入的组合的输入集,并且其输出集可以被定义为包括段a、段b和段c的输出中的每个输出的组合的输出集。应当理解,当到段b的输入(或输出)由段a分配(或解除分配),或者如果它由段b分配并且由段a解除分配,则到段b的输入(或输出)可以从输入集(或输出集)省略。还应当理解,在更广泛的函数(即,包括段)内调用的段,并且不是更广泛的函数的输入(或输出)的段的任何输入(或输出),可以从针对更广泛的函数的输入集(或输出集)省略,或者可以以其他方式作为更广泛的函数的内部进行追踪。
56.由于函数内联化,也可以出现复杂情况,特别是当子函数不打算被调试组件109分析时(例如,因为它来自第三方库)。例如,假设函数a的第一段(a1)在调用子函数b之前执行,并且然后函数a的第二段(a2)在函数b返回后执行。在这里,段a1和段a2可以被视为独立的函数,它们本身具有自己的输入集和输出集。如果函数b将a1的任何输出作为输入,则需要在调用到函数b之前产生那些输出;类似地,如果函数a2将函数b的任何输出作为输入,那么这些输出需要在函数b的调用之后出现。
57.在这些定义的上下文中,如果组成函数的给定可执行指令块是确定性的,则当在其输入中给定相同的数据值时,它们应当始终在其输出中产生相同的数据值。如果该可执行指令块以功能等效的方式被转换(例如,由于编译器优化、由于编译器的差异,和/或由于修复缺陷或改进性能而不改变函数整体的行为的源代码转换),当给出这些相同的输入数据值时,它们仍然应当产生这些相同的输出数据值。
58.例如,在图4中,在应用113的表示401b中的函数402

b1、402

b5和402

b9利用星号示出,这指示与应用112的表示401a中的其对应函数(即,402

a1、402

a5和402

a9)相比,这些函数中的可执行指令已经被转换。在实施例中,与应用112相比,这些转换可以是应用113被不同编译器标志或不同编译器版本或编译器类型编译的结果,导致针对函数402

b1、402

b5和402

b9生成了与函数402

a1、402

a5和402

a9不同的可执行指令。附加地或备选地,在实施例中,这些转换可以是应用113从修改的源代码编译的结果,该修改的源代码包括修复或改进,导致针对函数402

b1、402

b5和402

b9生成了与函数402

a1、402

a5和402

a9不同的可执行指令。
59.值得注意的是,可执行指令块可以包括已知是非确定性的一个或多个单独的指令。例如,x86 rtdsc指令在被调用时返回时间戳计数器(tsc)。因此,rtdsc指令每次被调用时,它会返回在其调用之前不容易预测的不同值。在实施例中,调试组件109能够标识和处理一些已知的非确定性指令,从而能够将两个对应的函数(例如,函数402

a1和402

b1)视
为确定性的,即使它们包含非确定性指令。例如,除了各种指令的输入之外,记录执行114还可以存储非确定性指令的“副作用”(包括输出)。因此,如果非确定性指令在对应函数(例如,402

a1和402

b1)中出现相同次数,则仿真组件110可以仿真返回记录的副作用的这些非确定性指令。备选地,针对非确定性指令,仿真组件110可以产生虚构但试探有效值。例如,针对rtdsc指令,试探有效值可以是一个值,该值大于上次在记录执行中调用该指令时返回的值,但小于下一次在记录执行中调用该指令时返回的值。当然,仿真组件110也可以拒绝执行非确定性指令的仿真。
60.调试组件109还可以处理由于对存储器映射硬件寄存器的读取/写入而可能出现的复杂性。例如,可能的是,函数402

a1在第一硬件环境中经由硬件存储器映射寄存器来访问在一个地址处的寄存器,同时函数402

b1在第二硬件环境中访问在另一地址处的寄存器(例如,因为它未被存储器映射到第二硬件环境中的第一存储器地址)。在实施例中,仿真组件110可以识别函数402

b1中的读取对应于函数402

a1中的读取,即使它们是针对不同的地址,并且使用记录执行114来返回记录值,该记录值在仿真从函数402

b1中的非存储器映射寄存器读取时,由函数402

a1从存储器映射寄存器读取。
61.基于由分析组件116标识的函数402(包括输入403和输出404),替代组件117使用仿真组件110来“重放”记录执行114,同时利用应用113的代码来替代应用112的代码。例如,假设记录执行114包括与函数402

a1在应用112的执行期间的先前执行有关的执行状态数据。通常,为了重放函数402

a1的可执行指令的该先前执行,根据需要,仿真组件110将使用记录的数据输入(例如,数据分组302的数据输入部分304),来向与由函数402

a1的可执行指令消耗的输入403

1相对应的数据位置提供数据值。然后,仿真组件110将使用这些数据值来仿真这些指令的执行,以便在与输出404

1相对应的数据位置中产生数据值。
62.然而,在实施例中,在函数402

b1的可执行指令的仿真期间,替代组件117不是使用函数402

a1的可执行指令,而是根据需要,使仿真组件110使用这些相同的记录的数据输入来提供数据值。可以对函数402

b1至402

b9中的任一函数重复该过程。
63.注意,如果函数402

b1的可执行指令在功能上等效于函数402

a1的可执行指令,则使用这些记录的数据输入对函数402

b1的可执行指令的仿真,应当在由函数402

a1生成的输出404

1中产生相同的数据值。输入/输出比较组件118可以将当仿真函数402

b1时生成的输出与由函数402

a1生成的输出进行比较,以确定情况是否如此。如果输入/输出比较组件118确定在接收相同输入时输出相同,则函数402

a2的可执行指令看起来确实等效于函数402

a1的可执行指令(至少对于这些输入)。如果在接收相同输入时输出不相同,则可以肯定地确定函数402

a2的可执行指令不等效于函数402

a1的可执行指令。在实施例中,输出函数402

a1可以从记录执行114获取,或者也可以通过对函数402

a1的可执行指令进行仿真来获取。
64.如所提及的,函数可以包括间隙,诸如由对非跟踪内核调用的调用引起的间隙。在实施例中,仿真组件116可以使用一种或多种技术来优雅地处理这些间隙。作为第一示例,仿真组件116可以从访问的记录执行113确定向内核调用提供了什么输入,并且然后由仿真组件116基于那些输入来仿真内核调用。作为第二示例,仿真组件116可以将内核调用视为可以在访问的记录执行113中的其他事件中被排序的事件,并且不是仿真内核调用,而是仿真组件116可以确保由内核调用做出的任何可见的改变(例如,改变的存储器值、改变的寄
存器值等)被暴露,作为内核调用之后执行的代码的输入。作为第三示例,仿真组件116可以设置适当的环境上下文,然后使用这些输入对正在运行的内核进行实际调用。作为第四示例,仿真组件可以简单地提示用户针对内核调用的结果。
65.输出组件119可以使用从应用112的执行的记录执行114获取的输入数据值来输出仿真应用113的代码的结果。例如,输出组件119可以提供由输入/输出比较组件118生成的任何结果,和/或可以将应用113的代码的仿真的结果提供给时间旅行调试组件或用户界面,例如,使能应用113的代码(而不是应用112的代码)上的前向和反向断点。如果输出组件119提供由输入/输出比较组件118生成的结果,它可以报告在应用113的仿真期间生成的输出与应用112在其记录执行期间生成的输出之间的任何差异,或者它可以报告这些输出相同。
66.在实施例中,调试器109可以被配置成:从(多个)记录执行114验证应用代码(例如,应用112/113)在其被执行和/或仿真时是否实际遵循一个或多个参数注释和/或契约。如本文所使用的,术语“参数注释”和“契约”指代特定代码注释,其定义代码元素或段应当如何表现。例如,代码注释可以指定前置条件(例如,在进入方法或属性时必须满足的要求)、后置条件(例如,方法或属性代码退出时的期望)、对象不变量(例如,针对处于良好状态的类的预期状态)等。示例参数注释技术是c/c 中的sal annotations,契约的示例是.net/c#中的code contracts。例如,基于来自应用113的代码的基于记录执行114的仿真,调试器109可以能够标识应用113的代码中的特定指令,该特定指令没有执行契约或违反该代码中指定的契约。类似地,基于应用112的执行的输出(例如,如被记录在记录执行114中,或如由代码基于记录执行114的后续仿真生成的),调试器109可以能够标识在应用112的代码中的特定指令,该特定指令没有执行契约或违反该代码中指定的契约。如此,调试器109可以利用参数注释和/或代码契约来暴露潜在的代价高昂和/或难以发现的缺陷。
67.图5图示了示例方法500的流程图,用于使用在第一可执行代码的执行期间收集的跟踪数据来仿真第二可执行代码的执行。现在结合图1

图4描述方法500。
68.如图5中所示,方法500包括访问第一代码的先前执行的可重放跟踪的动作501。在一些实施例中,动作501包括访问第一可执行代码的先前执行的可重放记录执行,该可重放记录执行包括在第一可执行代码的先前执行期间由一个或多个第一可执行指令消耗的一个或多个输入。例如,数据访问组件115可以访问应用112的先前执行的记录执行114(例如,使用跟踪访问子组件115a)。如图3中所示,该记录执行114可以包括至少一个数据流301a,数据流301a包括多个数据分组302,每个数据分组302可以包括数据输入部分304,数据输入部分304记录针对可执行指令的输入,该可执行指令作为应用112的先前执行的一部分而被执行。
69.方法500还包括访问第二代码的动作502。在一些实施例中,动作502包括访问与第一可执行代码不同的第二可执行代码,第二可执行代码的执行没有被记录在可重放记录执行中。例如,数据访问组件115可以访问应用113(例如,使用代码访问子组件115b),应用113的先前执行没有被记录在访问的记录执行114中。
70.如所讨论的,应用113(即,第二代码)可以在功能上与应用112(即,第一代码)相关,诸如从与应用112相同的源代码被编译,但是利用不同的编译器标志、编译器版本或编译器类型编译;和/或从应用112的源代码的修改版本被编译。因此,在动作502中,第一可执
行代码和第二可执行代码可以从相同的源代码被编译,但是利用以下各项中的一项或多项:(i)不同编译器设置,或者(ii)不同编译器。如果利用不同的编译器编译,则不同的编译器可能基于以下各项中的至少一项而不同:(i)编译器版本或者(ii)编译器类型。附加地或备选地,在动作502中,第一可执行代码可以从源代码的第一版本被编译,同时第二可执行代码从源代码的第二版本被编译,源代码的第二版本与源代码的第一版本不同。
71.方法500还包括使用可重放跟踪来仿真第二代码的动作503。在一些实施例中,动作503包括使用来自可重放记录执行的一个或多个输入来仿真第二可执行代码的执行。例如,替代组件117可以使用仿真组件110来仿真应用113的代码的执行,同时使用来自记录执行114(即,在应用112的执行期间获取的)的执行状态数据。该仿真可以包括:使用在第一可执行代码的先前执行期间由一个或多个第一可执行指令消耗的一个或多个输入,作为在一个或多个第二可执行指令的执行的仿真期间针对第二可执行代码的一个或多个第二可执行指令的输入。
72.如所讨论的,可以通过分析组件标识应用112和应用113中的彼此对应的“函数”(基于这些函数具有相同的输入和输出),来达到该替代。因此,如图5中所示,动作503可以包括标识(多个)第一代码中与第二代码中的(多个)第二函数相对应的(多个)第一函数的动作503a,并且可以包括使用(多个)第一函数的跟踪输入来仿真(多个)第二函数的动作503b。在一些实施例中,动作503a可以包括:标识第一可执行代码中的第一可执行指令的第一块(例如,函数402

a1),该第一块具有与第二可执行代码中的第二可执行指令的第二块(例如,函数402

b1)相同的输入集(例如,输入403

a)和相同的输出集(例如,输出404

a),并且动作503b可以包括:使用在第一可执行代码的先前执行期间被提供给第一可执行指令的第一块(例如,函数402

a1)的特定输入(例如,从记录执行114获得),来仿真可执行指令的第二块(例如,函数402

b1)的执行。
73.方法500还可以包括报告第二代码的输出和第一代码的输出之间的任何差异的动作504。在一些实施例中,动作504包括:报告第二可执行代码的仿真执行与第一可执行代码的先前执行之间的一个或多个差异,或者报告第二可执行代码的仿真执行与第一可执行代码的先前执行之间的等效性。如所示的,动作504可以包括将来自(多个)第二函数的(多个)输出与来自(多个)第一函数的(多个)输出进行比较的动作504a。在一些实施例中,动作504a包括:将在使用特定输入时由可执行指令的第一块产生的第一输出与在使用特定输入时由可执行指令的第二块的仿真执行产生的第二输出进行比较,以标识以下各项中的一项:(i)可执行指令的第二块的仿真执行与可执行指令的第一块的先前执行之间的一个或多个差异,或者(ii)可执行指令的第二块的仿真执行与可执行指令的第一块的先前执行之间的等效性。例如,输入/输出比较组件118可以将在使用跟踪输入403

1时函数402

b1的仿真的输出404

1,与函数402

a1在其在使用相同的输入403

1并且使用针对这些输入的相同值时的先前执行期间产生的输出404

1进行比较。然后,输出组件119可以呈现这些输出之间的任何差异,或者如果没有差异,则指示当给定相同的输入时,函数402

a1和函数402

b1等效地执行。如所讨论的,函数402

a1的输出404

1可以从记录执行114被获取,或者从仿真组件110对函数402

a1的仿真被获取。因此,动作504可以包括:基于使用特定输入来仿真可执行指令的第一块的执行来获取第一输出。
74.在应用113的代码的执行期间,替代组件117可能需要考虑一些不同场景,这些不
同场景由应用113中的代码的转换(与应用112中的代码相比)产生。在一个示例场景中,如果应用113是非优化代码(而应用112被优化),则应用113的代码的执行可能消耗更多的堆栈空间。因为堆栈指针是相对的,所以替代组件117可能需要考虑针对堆栈指针的基址的差异。在另一示例场景中,应用112和应用113中的代码可以通过相对地址(例如,作为从程序计数器的偏移)来访问数据(例如,全局变量和/或类成员)。由于记录执行114基于由应用112使用的地址来存储该数据,所以应用113的代码针对该数据可能具有错误的偏移。例如,假设应用112基于从程序计数器47个字节的偏移来访问特定数据,同时应用113基于从程序计数器148个字节的偏移来访问该相同的数据。为了应用113的正确仿真,替代组件117需要考虑针对该相对访问中的差异。在一些实施例中,替代组件117可以对应用112和应用113的代码执行静态分析,并且在应用113的代码中平移该偏移(视情况而定)。在其他实施例中,替代组件117可以以与应用112的数据对齐的方式,将应用113的代码映射到一些其他存储器位置(通常将是不可访问的)。然后,当应用113进行相对数据访问时,执行该映射的代码被执行以执行访问,其中相对地址被正确对齐。例如,这可以通过在应用113的数据段中使用存储器范围断点来完成,该存储器范围断点在被触发时重定向到映射的代码。因此,在方法500中,仿真可执行指令的第二块的执行可以包括以下各项中的一项:平移第二可执行代码中的指针偏移,以与由第一可执行代码使用的指针偏移对齐;或者将第二可执行代码映射为与由第一可执行代码使用的存储器偏移对齐。其他示例场景包括:处理不同编译器之间混叠行为的差异、处理不同编译器在存储器中放置数据的顺序、处理不同编译器如何布置类的差异等。在任何这些场景中,符号可以被用于标识和解决应用112和应用113之间的差异。在实施例中,这些差异也可以由编译器明确标识。
75.作为使用符号来标识/解决应用112和应用112之间的差异的示例,假设应用113包括访问全局变量的新代码。该访问将针对已知范围的存储器地址,诸如库的数据段。在该情况下,仿真组件110可以捕获对该存储器地址范围的任何访问。替代组件117可以使用应用113的符号来确定被访问的全局变量的特定存储器地址。替代组件117还可以使用应用112的符号来确定旧代码中针对该相同全局变量的先前存储器地址。然后,替代组件117可以使仿真组件110使用旧存储器地址而不是新存储器地址来服务该存储器访问(读取/写入)。因此,已经使用符号来跨库的两个版本以平移全局变量的存储器布局。在实施例中,所有访问都可能需要经过映射,因为在对“新”地址的两次访问之间可能存在对“旧”地址的访问(例如,经由指针)。值得注意的是,该方法可以在任一方向上工作——即,使用旧地址并且经由符号将对新地址的访问映射到旧地址,或者使用新地址并且经由符号将对旧地址的访问映射到新地址。
76.在实施例中,调试组件109可以包括能够对记录执行114执行查询的一个或多个查询功能(未示出)。例如,这些查询功能可以标识存储器分配和解除分配,并且可以确定是否存在不具有对应的解除分配的任何分配(即存储器泄漏)。在实施例中,这些查询功能可以被扩展以在应用113的仿真执行上执行这种查询。如此,这些查询功能可以作为“检查器”进行操作,以验证应用113是否修复和/或引入了问题,诸如存储器泄漏。
77.因此,本文描述的实施例利用历史调试技术以基于来自相关的跟踪代码的记录执行的跟踪数据来仿真非跟踪代码的执行。因此,本文描述的实施例使用第一代码的记录执行来指导未被跟踪到该记录执行中的第二代码的仿真。由于第一代码和第二代码可能具有
差异,但可能在功能上相关,因此利用相关的跟踪代码的记录执行来仿真非跟踪代码可以被用于:标识编译器缺陷(例如,当不同的编译器标志、编译器版本或编译器产品导致从相同的源代码产生功能不同的二进制文件时)、确定源代码改变是否解决了不期望的软件行为和/或引入了新的不期望的软件行为、使得能够基于优化代码的跟踪来调试非优化代码,等等。
78.尽管已经以特定于结构特征和/或方法论动作的语言描述了主题,但应当理解,所附权利要求中定义的主题不必受限于上述特征或动作,或者上述动作的顺序。而是,所描述的特征和动作作为实现权利要求的示例形式而被公开。
79.在不脱离本发明的精神或基本特性的情况下,本发明可以以其他特定形式来被实现。所描述的实施例在所有方面仅应当被认为是说明性而非限制性的。因此,本发明的范围由所附权利要求书而不是由前面的描述指示。落入权利要求相同含义和范围内的所有改变都应当被包含在其范围内。
再多了解一些

本文用于企业家、创业者技术爱好者查询,结果仅供参考。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献