n路运行时互操作调试的制作方法

文档序号:6495679阅读:179来源:国知局
n路运行时互操作调试的制作方法
【专利摘要】在多种类型的运行时环境中运行的同时代码调试可以由n路互操作调试环境来执行。在特定运行时内运行的代码可以与其他运行时内运行的代码同时在单个进程内被调试。提供对检查和执行控制的进程外调试支持。兼容调试器或运行时通信协议被使用。从一个运行时到另一运行时的转移可被检测到。在一个运行时中抛出的异常可被另一个运行时捕获。步进操作可在多个运行时中发生。包括来自多个运行时的各帧的调用栈可被走查。
【专利说明】n路运行时互操作调试
[0001]背景
[0002]在调试进程时,可生成调试事件。调试器通常监听调试事件,并对调试事件作出响应。调试事件可以在进程被创建时、在模块被加载时、在异常被抛出时、及在断点被遇到时等被创建。调试器使用调试事件和检查应用编程接口(API)来实现调试操作。在调试事件被分派时,被调试程序(被调试的进程)通常被停止,直到调试器继续调试事件。在被调试程序被停止时,调试器可以检查该被调试程序的状态。当被调试程序被继续时,该进程运行,直到下一个调试事件被遇到。通常,托管代码调试和本机代码调试具有不同的调试事件集合,和在停止状态和运行状态之间的不同转移方式。
[0003]本机调试通常由操作系统(OS)来实现。该OS提供用于监听和继续调试事件的调试API。在调试事件发生时,OS冻结被调试程序(正被调试的进程)。本机调试是进程外操作,即该进程被冻结并且该进程之外的代码(在OS中)检查来自被冻结进程的值。进程外调试不需要来自被调试程序的协作。本机被调试程序停止状态被称为冻结,因为该进程已被OS停止,并且没有代码在该进程内部执行,直到OS再次启动该进程。
[0004]操作系统不对已冻结进程执行虚拟机环境中(例如,Eclipse中或微软的Visual Studio?中)的调试。虚拟机环境中的调试通常由虚拟机的运行时环境来实现,并且是进程中操作。进程内部的代码执行以进行调试操作。OS没有该类型的调试何时发生的知识。被调试程序停止状态有时被称为“同步的”,因为从OS的角度来看同步进程是活的,但所有这些线程都被运行时环境停止。虚拟机调试事件可以被“构建在”本机调试事件“的上方”或使用本机调试事件来实现。
[0005]虚拟机运行时服务实现虚拟机调试操作,而不实现本机调试操作。类似地,本机调试API不提供对虚拟机环境中的调试的支持。虚拟机环境中的调试操作和本机调试操作被不同地实现。例如,在Visual Studio?中,托管步进由运行时环境API来实现,而本机步进由消费本机调试事件的本机调试库来实现。本机执行控制(对步进操作和断点的控制)通常使用OS异常处理来实现,并且在本机调试API中缺少显式支持。托管调试API显式地具有断点和步进功能。托管调试的抽象层和本机调试的抽象层中的差异防止在托管调试操作和本机调试操作之间的代码共享。
[0006]某些IDE能够在单个调试会话中调试在虚拟机运行时环境中以及在本机运行时中运行的代码。这被称为互操作调试。由于底层的冲突调试架构设计,在已知的互操作调试器中使用的机制是受限的,并且依赖于本机运行时调试器和虚拟机运行时调试器之间单调而脆弱的操作。
[0007]概述
[0008]对在多种类型的运行时环境中运行的、单个被调试程序进程内的代码的调试可以使用可扩展调试架构在相同的调试会话中同步执行。这样的同步调试在此被称为n路互操作调试。N路互操作调试可以提供包括在单个被调试程序进程中(在单个调试会话)执行的所有运行时环境的逻辑视图在内的整个被调试程序进程的整体视图。各运行时调试器之间的交互也可被查看。对虚拟机运行时环境的调试支持允许使用一组调试器接口来促进调试操作的互操作调试。虚拟机运行时环境所创建的调试支持不会干预对该进程中的其他运行时被调试程序的调试。
[0009]互操作调试允许执行控制、使从一个运行时运行的被调试程序代码步进到另一运行时、在多个运行时被调试程序中设置断点、检查来自多个运行时被调试程序的值、以及执行包含来自多个运行时调试器的代码的调用栈。运行时调试器被排定优先级,使得最高优先级的运行时调试器控制执行并展开这个栈。
[0010]符合的运行时被调试程序可以由n路互操作调试器互操作地调试。符合的运行时被调试程序是使用对检查和执行控制的进程外调试支持、使用兼容的调试器/被调试程序通信协议、可以为执行控制和栈展开检测运行时被调试程序之内和之外的边界的被调试程序。对于抛出异常的那些运行时被调试程序,各兼容的运行时调试器可以检测出从一个运行时被调试程序抛出并在另一个运行时被调试程序内捕获的异常。进程外调试不会涉及被调试程序进程中的执行代码,使得各运行时不会干预彼此的线程模型或执行模型。符合的运行时调试器可以被插入到n路互操作调试器中。
[0011]在此描述的各接口和各机制可用作用于步进调试器中的各操作的通用可扩展性模型。
[0012]提供本概述是为了以简化的形式介绍将在以下详细描述中进一步描述的选择的概念。本概述并不旨在标识所要求保护主题的关键特征或必要特征,也不旨在用于限制所要求保护主题的范围。
[0013]附图简述
[0014]在附图中:
[0015]图1示出了根据此处所公开的主题的各方面的用于n路互操作调试的系统100的示例;
[0016]图2a是根据此处所公开的主题的各方面的用于n路互操作调试的方法200的示例的流程图;
[0017]图2b示出了根据此处所公开的主题的各方面的走查调用栈250的方法的示例;
[0018]图2c示出了根据此处所公开的主题的各方面的处理异常270的方法的示例;
[0019]图3是根据此处所公开主题的各方面的计算环境的示例的框图;以及
[0020]图4是根据此处所公开的主题的各方面的集成开发环境的示例的框图。
[0021]详细描述
[0022]概览
[0023]根据此处所公开的主题的各方法,描述了可以用进程中的任何兼容运行时调试器互操作地调试的运行时调试器架构。在n路互操作兼容运行时被调试程序上运行的代码可以使用进程外操作来调试。可以使用不要求在被调试程序进程内执行代码的OS原语从被调试程序进程的外部执行包括但不限于数据检查、执行控制和栈展开的核心调试器操作。部分由于在运行时被调试程序进程中执行代码可以在该进程被停止时生成更多调试事件,以及出于其他原因,避免在运行时被调试程序进程中执行代码。进程外调试确保多个运行时被调试程序不会在调试时间干预彼此的线程模块。它还确保了检查被调试程序进程内的运行时将不会导致其他运行时调试器无法处理的副作用。
[0024]读/写进程存储器原语允许调试器读存储器/将存储器写入被调试程序进程。获取并设置线程上下文原语允许访问并修改被调试程序进程中的寄存器设置。写在OS原语上方的调试器原语包括断点和单步指令。单步操作告诉处理器执行单个指令,随后停止并通知调试器。调试API可以向调试器通知被调试程序进程中发生的一组事件,包括进程创建和破坏、模块加载和卸载、断点命中、单步完成、异常发生。来自通信信道的通知也使用进程外模型来完成,使得在断点被命中时,通知被发送到调试器,而不在被调试程序进程中运行代码。
[0025]被调试程序进程和进程外调试器之间的兼容协议被用于与n路互操作调试兼容的运行时。即,运行时被调试程序向调试器通知在被调试程序进程中调试事件已以不会导致其他运行时调试器失灵或无法通信的方式发生。可使用的与n路互操作调试兼容的一个协议是微软公司所创建的Win32?调试事件模型。
[0026]该进程中与n路互操作兼容的各运行时被调试程序之间的边界在运行时调试器控制调试操作时是可识别的。例如,如果在运行时调试器A上运行的代码调用在运行时调试器B上运行的代码,则运行时调试器B可以检测到控制已被转移到运行时调试器B中,并且运行时调试器B可以接管控制调试操作。
[0027]支持异常模型的与n路互操作调试兼容的各运行时调试器能够标识异常何时被其运行时调试器捕获。异常可以起源于一个运行时调试器,并可在另一个运行时调试器中被捕获。例如,假设在运行时被调试程序A上运行的代码调用在运行时被调试程序B上运行的代码,并且用户正步进通过在运行时被调试程序B上运行的代码。如果在该步进操作发生时抛出了异常,则那个异常可以被运行时被调试程序A捕获。在这种情况下,调试器步进操作可以在那个时刻被挂起。当运行时调试器检测到异常何时被其运行时被调试程序捕获时,可生成处理程序发现通知。来自一个运行时被调试程序的各异常可以被用作被调试的另一个运行时的各异常的实现。例如,通用语言运行时(CLR)内抛出的异常实际上是本机的结构化异常处理程序异常。因此,本机调试器不知道某步进在异常被抛出并被捕获时就完成了,直到CLR的调试器可以检查处理程序块以后。各兼容的被调试程序不必使用异常模型来指示错误。
[0028]n路互操作调试
[0029]图1示出了根据此处所公开的主题的各方面的用于n路运行时互操作调试的系统100的示例。系统100的全部或部分可以驻留在诸如以下参考图3所描述的计算机之类的一个或多个计算机上。系统100可在诸如参考图4所描述的软件开发计算机之类的软件开发计算机上执行。系统100可以整体地或部分地在诸如IDE104之类的IDE内执行或者可以整体地或部分地在IDE之外执行。IDE104可以是诸如参考图4所描述的IDE之类的IDE,或者可以是任何其它IDE。系统100的全部或部分可被实现为插件或附件。
[0030]系统100可包括诸如计算机102之类的一个或多个计算设备或计算机,包括:诸如处理器142等的一个或多个处理器、诸如存储器144之类的存储器、诸如调试器106之类的n路互操作调试器、被调试程序108、和一组调试API120。调试器106可包括一个或多个模块,包括含步进管理器110和调试监视器118的一个或多个模块。根据在此所公开的主题的各方面,在被调试程序进程中执行的开发者调试程序代码可以使用调试器106同时调试多个运行时。开发者可以从在一个运行时被调试程序中运行的代码步进到在另一个被调试程序运行时中运行代码。断点可被设置在于被调试程序进程中执行的运行时被调试程序中的任何一个、部分或全部中。被调试程序值(例如,变量值等)可在一个运行时调试程序中被检查,同时另一个运行时正被查看。与调试器106相关联的调用栈可包括来自多个运行时的代码。调试器106可包括以下中的一个或多个:本机运行时调试器114、解释器调试器116、栈提供器117和一个或多个托管运行时调试器112等。调试器106也可以包括栈提供器117。调试器106可以是可扩展的,使得一个或多个n路互操作兼容调试器可被插入到调试器106中。
[0031]被调试程序108可包括以下中的部分或所有:一个或多个托管运行时被调试程序122等、本机运行时被调试程序124和解释器被调试程序126。模块的实例可被加载到被运行时标记为转移模块(例如,托管运行时被调试程序122的转移模块136、本机运行时被调试程序124中的转移模块138、解释器被调试程序126中的转移模块140)的被调试程序进程中。也可以包括本领域公知的其他组件,但此处未示出。将理解,以上中的一个或多个可被加载到存储器144中以使得诸如处理器142等一个或多个处理器执行归于一起执行n路互操作调试的一个或多个模块的动作,如以下更全面描述的。
[0032]步进管理器110可包括在诸如托管运行时调试器112等、本机运行时调试器114和解释器调试器116的各运行时调试器之间提供通信信道的模块或类。步进管理器110可实现步进仲裁,如以下更全面描述的。步进管理器110可包括接收存储包括步进的类型(步进通过、步进进入、步进离开)、步进的单位(语句、行、或指令)及开始帧基数和地址在内的有关该步进的状态的单步请求的模块。诸如调试监视器118之类的调试监视器可包括管理调试器(例如,调试器106)和被调试程序(例如,被调试程序108)之间的通信信道的模块或类。调试监视器118可以将调试事件路由到相应的调试器处。例如,在托管运行时被调试程序122中生成的各事件可以被调试监视器118路由到托管运行时调试器112处,在本机运行时被调试程序124中生成的各事件可被托管运行时调试器112路由到本机运行时调试器114处,在解释器126中生 成的各事件可被调试监视器118路由到解释器调试器116处,并以此类推。调试监视器118可包括实现调试事件循环(例如,Win32调试事件循环)的模块或类。调试监视器118可包括可将来自调试器进程运行时的调试事件转换成与调试API120兼容的调试事件的调试监视器模块或类。
[0033]n路互操作调试器引擎105可以从调用栈窗口接收开始走查各调用栈帧(诸如,调用栈128的帧1130、帧2132……帧nl34)的请求。n路互操作调试器引擎105可以将该调用路由到栈提供器117。栈提供器117可以向每一运行时调试器(例如,托管运行时调试器112等、本机运行时调试器114、解释器运行时调试器116)询问该运行时调试器是否拥有当前位置,即当前正被执行的指令是否处于属于那个运行时调试器的帧范围内。这些运行时调试器按优先级次序被询问。当运行时调试器声明该位置处于调用栈128中时,各帧由申明运行时(当前控制的运行时调试器)从调用栈128处请求,并被声明运行时调试器处理,直到申明运行时调试器检测到不属于它的帧。各运行时调试器被排定优先级,因为一个运行时调试器可以被实现在另一个运行时调试器的上方。各运行时调试器的优先级次序是有用的,因为可能诸如解释器之类的较高级的运行时调试器要使用诸如托管或本机运行时调试器之类的另一运行时来实现。例如,在解释器运行时调试器用托管代码来实现的情况下,解释器运行时调试器可被给予在托管运行时调试器之前展开该帧的机会。假设运行时调试器A被实现在运行时调试器B的上方。运行时调试器A可获得比运行时调试器B高的优先级,以确保较高优先级的运行时调试器(即,运行时调试器A)能够进行执行控制并可展开该栈。例如,假设解释器运行时调试器是用托管代码来实现的。在这种情况下,解释器运行时调试器具有比托管代码运行时调试器高的优先级。最后,所有代码都是本机的,使得本机执行引擎和栈展开器可以是最低优先级的运行时。
[0034]在n路互操作调试器(诸如调试器106)中的各运行时调试器中的每一个表示正调试特定被调试程序进程的运行时调试器的单个实例。可在调试器106中执行的不同类型的运行时调试器的示例包括本机运行时调试器实例、虚拟机运行时调试器实例和解释器运行时调试器实例。每一运行时调试器实例负责理解并实现对特定运行时被调试程序的调试。即,托管运行时调试器112调试托管运行时被调试程序112,本机运行时调试器114调试本机运行时被调试程序124,并以此类推。
[0035]系统100可提供对检测和执行控制的进程外调试支持。进程外调试被使用,因为虽然托管运行时环境可以在被调试程序进程中实现调试支持,但这样做会引入各运行时之间的不兼容性。例如,进程内调试器在被调试应用进程内运行调试器代码。诸如本机调试器之类的进程外调试器将不允许被调试程序线程在该调试器处于断点模式时运行。因为进程内调试器可选自大量可能的线程模型中的任何一个,所以为任何进程内调试器都定义允许n路互操作调试的兼容模型是一个难以对付的问题。因此,进程外调试器模型被实现在系统100中。
[0036]符合“进程外”调试器模型的运行时的一个示例是微软的本机Win32运行时。被设计成调试在Win32操作系统上运行的本机代码的各调试器使用以下各项的组合:pdb (程序数据库)文件、保持调试和项目状态信息的文件、Win32调试AP1、以及关于用于执行诸如步进、检测变量状态之类的各种调试器任务的硬件的特征。例如,为了在本机应用中检查该栈上的本地变量,本机运行时调试器首先查找与Pdb中的变量有关的信息。Pdb中的信息包括该变量的类型、该变量在存储器中被如何格式化、以及该变量驻留在存储器中的何处。调试器使用进程外读存储器API来从被调试程序进程中获得该变量的字节。随后可如pdb中所描述那样格式化该值,并将经格式化的信息显示给用户。进程外操作的另一示例是步进本机Win32应用。为了执行步进操作,本机调试器可以查找被调试程序在pdb中的当前指令指针,以获得存储器范围映射的源行。可以使用诸如单步指令和断点指令之类的原语来使得被调试程序进程执行,直到遇到源范围的末端。
[0037]诸如解释器或虚拟机运行时环境之类的需要运行时和调试器之间的更多动态交互的运行时可以将各数据结构展示在公知的位置,以允许相应的调试器在调试时间使用进程外读存储器API来读这些数据结构。相应的运行时调试器可以从这些数据结构读并写入这些数据结构,以影响运行时行为。例如,为了在解释器源行上设置断点,调试器可以定位断点数据结构,并将信息写入该数据结构,以启用该断点。运行时被调试程序可以在执行到达该断点时触发该断点。步进可以被类似地实现。例如,调试器可以将步进信息写入定义线程的数据结构。解释器可以在步进完成时停止。可以经由进程外读存储器API来使得有关线程的栈的信息对数据检查操作可用。调试器可以选择正确的栈帧,使用进程外读存储器来使其与被调试程序中的正确栈帧对象匹配、并使用该数据结构来获取该栈帧上的变量的名称、值和类型。
[0038]基于即时(JIT)运行时可以以调试器可以使用进程外API来访问各数据结构的方式来展示这些数据结构。数据结构可以被抽象化成驻留在调试器进程中的较高级对象。调试器可以使用读和写进程存储器来消费各对象。诸如步进和断点之类的执行控制操作可以使用本机代码会使用的相同的硬件原语(单步和硬件断点)来实现。从源行到指令地址的实际映射可以基于JIT编译器的输出,并因此可以是动态的。实际映射(和步进范围)可以通过从进程外读出各数据结构来获得。
[0039]n路互操作兼容可调试运行时必须具有将各调试事件传送到调试器的方式。为了支持n路互操作,协议必须与调试该进程的其他运行时调试器兼容。确保兼容性的一种方式是实现与进程外模型一起工作、而不会导致各个运行时调试器之间的事件混淆的协议。某些运行时调试器架构出于这个目的而使用诸如命名管道之类的较高级协议,但这样的协议通常违反进程外模型。因此,根据在此公开的主题的各方面,诸如但不限于Win32调试流水线的本机调试流水线被实现。包括WaitForDebugEvent (等待调试事件)函数和ContinueDebugEvent (继续调试事件)函数在内的各函数可被用来允许调试器接收有关进程中正在发生什么的通知,并在该调试器已完成处理调试事件后继续对被调试程序的执行。调试事件包括创建进程事件、创建线程事件、加载模块事件和异常。可以使用特定异常代码将命中断点事件和完成单步事件实现在各异常上方。为了使得多个运行时调试器能够通过调试API来接收这些事件,n路互操作调试架构可以将调试事件循环从实际的运行时调试器实现中划分出来,如下面更全面描述的。
[0040]根据在此公开的主题的各方面,为了在n路互操作调试器中实现执行控制(即,互操作执行控制),转移到运行时和从运行时转移走必须是可检测的,因为开始步进操作的运行时调试器可能不是结束该步进操作的运行时调试器。例如,在步进进入操作过程中,如果遇到调用指令,则可以在该进程中可以对在另一运行时被调试程序内运行的代码作出该调用。当前处于该操作的控制之下的运行时调试器(“当前控制的运行时调试器”)必须能够放弃控制,并让另一运行时调试器接管控制。对转移到另一运行时被调试程序的检测可以用包括但不限于以下描述的那些方式的各种方式来实现。
[0041 ] 运行时被调试程序可以将标准模块(即,转移模块)用于进入点。即,在步进操作使被调试程序的指令指针抵达转移模块的任何时候,到另一运行时被调试程序的可能转变已被遇到。响应于当前控制运行时调试器可能停止步进,给予其他运行时调试器完成该步进的机会。如果没有遇到新的控制运行时调试器,则原始运行时调试器可以完成该步进。允许其他运行时调试器检查当前指令指针和接管控制的过程在此被称为“步进仲裁”。
[0042]运行时被调试程序可能具有在运行时转移时被调用的公知函数,从而使得运行时被调试程序能够将端点设置在这些函数中。当这些端点在步进操作期间被命中时,针对那个运行时的运行时调试器可以请求先前的控制运行时调试器放弃对该操作的控制。
[0043]包括但不限于CLR的解释器或其他被严密控制的运行时被调试程序可能能够将调试事件激发到转移点处的调试器中。如果步进操作发生,则运行时被调试程序的调试器可以请求之前的运行时调试器放弃对该操作的控制。当展开调用栈时,运行时的展开器可以意识到该调用栈中的有在运行时上运行的代码存在的各区域。这确保了为调用栈的特定区域调用正确的运行时展开器。由于一个运行时调试器可以被实现在另一运行时调试器的上方,较高级别的运行时调试器可以被给予防止较低级别的运行时调制器将调用栈的错误部分展开的优先级。[0044]最后,与n路互操作调试器兼容的运行时被调试程序必须能够检测运行时被调试程序中的处理程序何时捕获了一异常,即使该异常最初是从另一运行时被调试程序处被抛出的。至少一些运行时被调试程序处理某种错误。当错误发生在一个运行时环境中并且它转移到另一运行时环境中时,如果运行时能够停止该进程并处理该错误状况,则该运行时可以停止执行控制。不支持异常的运行时被调试程序不必检测所捕获的异常。能够检测所捕获的异常允许步进操作在处理程序被发现时完成,即使该异常跨过了运行时被处理程序的边界。某些运行时调试器必须在其处理程序发现通知被激发时发起仲裁,因为其异常模型被实现在另一运行时被调试程序的异常模型的上方。
[0045]图2a示出了根据此处所公开的主题的各方面的用于在n路互操作调试器中步进的方法的示例。在202,调试器响应于接收到用户请求而请求新的步进操作。可以创建保持诸如步进操作的类型(步进进入、步进离开、步进通过、步进在调用栈上的位置等)等有关步进的状态的对象。在204,向步进管理器通知该新的步进操作。可以创建保持诸如步进操作的类型(步进进入、步进离开、步进通过、及步进在调用栈上的位置等)等有关步进的状态的对象。在206,步进管理器将该新步进操作通知传递给每一运行时实例。在208,每一个被通知的运行时调试器实例可以执行预步进设置动作。预步进设置动作可以包括但不限于发起捕获处理程序发现通知、在已知的运行时被调试程序转移处设置断点、指定被调试程序转移模块等。
[0046]在210,步进管理器可以:执行最高级或初始步进仲裁;按优先级次序向每一运行时调试器实例询问被调试程序当前是否正在该运行时调试器实例的运行时内执行。当指令指针指向调用栈的属于运行时调试器的区域时,被调试程序当前正在那个运行时调试器内执行。在212,当前控制运行时调试器被选择。在214,步进管理器向所有其他运行时调试器通知该新的控制运行时调试器(即,当前控制运行时)。通知使得其他运行时能够充当当前控制运行时对特定运行时执行特殊处理。在216,当前控制运行时调试器开始步进该进程。在218,在步进期间或当前栈帧改变的任何时候遇到的每一调用指令处,当前控制运行时调试器检查以查看指令指针是否抵达另一运行时调试器所拥有的转移模块。或者,另一运行时调试器可以在断点被命中或在另一调试事件发生时,检测其运行时内的转移。
[0047]在218,响应于确定没有转移是可能的,则处理在224继续,在224,步进被控制运行时调试器完成。当步进操作在224完成时,在226当前控制运行时调试器向步进管理器通知该步进完成了。在228,步进管理器向所有其他运行时调试器通知步进被完成。在230,调试器用户界面接收步进完成通知,并进入中断模式。然而,如果在218确定转移是可能的,则步进仲裁被请求,并且处理返回220。在步进仲裁期间,步进管理器按优先级次序向每一运行时调试器询问该运行时是否声明该位置。如果没有其他运行时调试器声明该位置,则在224当前控制运行时调试器使步进结束。然而,如果在222步进管理器确定运行时转移已发生,则处理在214继续。
[0048]运行时调试器实例还可以直接使用断点、异常或另一调试事件来检测其运行时内的转移。如果转移发生,则运行时调试器实例可以针对通过步进管理器的控制而询问当前控制运行时调试器。如果当前控制运行时调试器实例同意,则步进控制被给予该新的运行时调试器实例。可以向其他运行时调试器实例通知控制运行时调试器时发生的改变。这个机制允许所有步进操作,包括步进进入、步进通过、和步进离开。将理解,(例如,如果某步进从某函数的结尾步进离开的话),该步进通过可以遇到一新的边界模块。类似地,当从当前帧步进离开时,可遇到新的边界模块。
[0049]在调试器中的检查是基于调用栈帧的。在n路互操作调试中,每一运行时调试器实例负责展开其自己的调用栈帧。n路互操作调试器的每一运行时调试器可以将当前帧标识成其自己的,使得变量检查可被路由到合适的运行时调试器实例。n路互操作架构可以提供一种供来自不同运行时调试器的各帧在整个调用栈完成后被回缝在一起的方式。还必须提供一种供“运行时粘合”帧对用户隐藏的方式。
[0050]图2b示出了根据此处所公开的主题的各方面的走查调用栈的方法250的示例。在252,调用栈窗口可以请求n路互操作调试器开始走查各帧。在254,可将该请求路由到栈提供器。在256,栈提供器可以按优先级次序向每一运行时调试器实例询问该运行时调试器实例是否拥有当前位置。将理解,每一帧是本机帧,而不管它所属于的运行时调试器。因为在步进时,一个运行时调试器可以被构建在另一运行时调试器之上,因此对各运行时排定优先级确保了由合适的运行时调试器来控制对调用栈的走查。将理解,尽管运行时可被构建在本机运行时之上,但也可能将运行时构建在诸如例如在解释器以托管代码来实现时存在的较高级运行时之上。
[0051]在258,运行时调试器声明位置,并在260请求来自调用栈的帧,直到当前帧不属于该运行时调试器为止。在262,响应于检测到不属于该运行时的帧,向栈提供器指示“运行时结束”值。在264,运行时向栈提供器通知调用栈中该运行时的代码再次开始(如果如此的话)的位置。这防止另一运行时展开不属于它的调用栈的部分。为了理解这可如何发生,假设没有向栈提供器通知栈转移点。假设托管展开器在托管到本机转移点处停止。即使存在回到托管代码的另一转移点,本机运行时仍将继续展开调用栈,直到整个栈已被处理。这由于所有代码最终是本机代码而发生。
[0052]类似地,由于解释器是用托管代码来实现的,因此即使栈应该由解释器来展开,从托管代码到经解释的代码的转移仍可由托管运行时调试器来展开。相反,根据在此公开的主题的各方面,由于栈提供器知道每一转移点,因此栈提供器可以按优先级次序向每一运行时调制器询问该运行时调试器是否愿意处理下一个调用栈帧。当运行时调试器声明了帧时,该声明运行时调试器被给予对该展开的控制。一旦所有帧已被展开,将各调用栈帧过滤掉。即,每一运行时调试器被给予隐藏运行时粘合代码或完全改变帧的内容的机会。最后,调用栈中的每一帧由匹配有问题的帧的语言表达式评估器来格式化。
[0053]在互操作调试被执行时,一个运行时调试器中抛出的异常可以在于另一运行时调试器上运行的代码中的捕获处理程序中被捕获。如果步进操作在异常被抛出时发生,则该步进通常被停止。支持异常的运行时调试器可被告知一异常何时被其运行时调试器使用该运行时调试器的异常处理程序发现通知捕获。图2c示出了根据此处所公开的主题的各方面的用于处理异常的方法270的示例。在272,步进操作开始。在274,作为响应,步进管理器向所有运行时调试器通知该步进操作已开始。在276,响应于该通知,每一运行时调试器实例可启用其捕获处理程序发现通知。异常可以被从当前步进帧调用的帧抛出,并可以被某一帧在展开已经过步进帧之前被捕获。根据此处所公开的主题的各方面,该帧的帧基数可用于检测这样的实例。帧基数为在针对该帧的任何栈操作发生之前栈指针的值。在其中调用栈以向下的方向增长的n路互操作调试系统中,与调用栈上较低处的调用相比,调用栈上较高处的调用将具有更小的帧基数。即,如果函数a调用函数b,函数b本身调用函数C,则调用栈将表现为:
[0054]c
[0055]b
[0056]a
[0057]c的帧基数将比b的帧基数小,b的帧基数将比a的帧基数小。
[0058]如果运行时的捕获处理程序发现通知在步进完成之前激发,则运行时调试器可以将当前栈帧的帧基数与该步进已开始时的栈帧的帧基数进行比较。如果当前栈帧的帧基数比开始帧的帧基数小,则异常被抛出并有被当前步进的帧调用的帧捕获,并且可被忽略。然而,如果帧基数大于或等于该步进时刻的帧基数,则异常已被转移经过该步进的点,并且该步进操作可被认为已完成。将理解,包括但不限于CLR的某些运行时使用另一运行时的异常模型来实现各异常。通常,托管异常被构建在本机异常之上,但存在其他可能性。使用另一运行时的异常模型的任何运行时可以在步进处理程序发现通知被激发之后发起步进仲裁。例如,假设(在CLR上运行的)函数A调用函数B (本机代码)。如果函数B抛出一异常,则本机运行时实例和托管运行时实例两者都将接收它们的处理程序发现通知(可能在不同的时刻)。然而,由于目标处理程序实际上是托管代码,因此本机运行时实例应该允许托管运行时结束该步进。逻辑上,对这个的实现看上去像这个在CLR中。
[0059]Try
[0060]{
[0061]调用本机代码
[0062]Catch(native filter)
[0063]{
[0064]调用托管捕获处理程序
[0065]}
[0066]如果在步进经过本机代码时,异常被抛出,则可在本机捕获块处向运行时实例发送捕获处理程序发现通知。不论何时捕获处理程序发现通知激发,步进仲裁都可以被执行。如果该位置没有被声明,则捕获块在本机代码中,并且步进结束。如果另一运行时调试器声明了该位置,则声明运行时调试器可结束步进。将理解,此处在n路交互式调试器的上下文中描述的机制还可被应用于用于通用的可扩展性模型,以用于在调试器中步进。例如,当被调试程序中正在使用改变调试行为的技术时,步进仲裁和转移模块可被该技术使用。例如,COMRPC步进可以调用可以检测RPC转移并可以使得在途中的步进操作在RPC调用的目标处结束的插件组件。
[0067]合适的计算环境的示例
[0068]为了提供有关本文所公开主题的各方面的上下文,图3以及以下讨论旨在提供其中可以实现本文所公开主题的各实施例的合适计算环境510的简要概括描述。尽管本文所公开的主题是在诸如程序模块等由一个或多个计算机或其他计算设备执行的计算机可执行指令的通用上下文中描述的,但本领域技术人员将认识到,本文所公开的主题的各部分还能够结合其他程序模块和/或硬件和软件的组合来实现。通常,程序模块包括执行特定任务或实现特定数据类型的例程、程序、对象、物理人为产物、数据结构等。通常,程序模块的功能可在各个实施例中按需进行组合或分布。计算环境510只是合适的操作环境的一个示例,并且不旨在对此处所公开的主题的使用范围或功能提出任何限制。
[0069]参考图3,描述了计算机512形式的计算设备。计算机512可包括处理单元514、系统存储器516和系统总线518。处理单元514可以是各种可用处理器中的任何一种。也可以使用双微处理器及其他多处理器体系结构作为处理单元514。系统存储器516可包括易失性存储器520和非易失性存储器522。非易失性存储器522可包括只读存储器(ROM)、可编程ROM (PROM)、电可编程ROM (EPROM)或闪存。易失性存储器520可包括可充当外高速缓冲存储器的随机存取存储器(RAM)。系统总线518将包括系统存储器516的系统物理人为产物耦合到处理单元514。系统总线518可以是几种类型的总线结构中的任何一种,包括存储器总线、存储控制器、外围总线、外总线或局部总线,并且可以使用各种可用总线体系结构中的任一种。
[0070]计算机512通常包括各种计算机可读介质,诸如易失性和非易失性介质、可移动和不可移动介质。计算机存储介质可以通过用于存储诸如计算机可读指令、数据结构、程序模块或其它数据等信息的任何方法或技术来实现。计算机存储介质包括但不限于,RAM、ROM、EEPR0M、闪存或其它存储器技术、⑶ROM、数字多功能盘(DVD)或其它光盘存储、磁盒、磁带、磁盘存储或其它磁存储设备、或可以用来储存所期望的信息并可由计算机512访问的任何其他瞬态或非瞬态介质。
[0071]将理解,图3描述了可充当用户与计算机资源之间的媒介的软件。该软件可以包括可存储在盘存储524上的操作系统528,该操作系统可分配计算机系统512的资源。盘存储524可以是通过诸如接口 526等不可移动存储器接口连接到系统总线518的硬盘驱动器。系统应用程序530利用由操作系统528通过存储在系统存储器516或者存储在盘存储524上的程序模块532和程序数据534对资源的管理。可以理解,计算机可用各种操作系统或操作系统的组合来实现。
[0072]用户可通过输入设备536向计算机512输入命令或信息。输入设备536包括但不限于定点设备,诸如鼠标、跟踪球、指示笔、触摸垫、键盘、话筒等。这些及其他输入设备通过系统总线518经由接口端口 538连接到处理单元514。接口端口 538可表示串行端口、并行端口、通用串行总线(USB)等。输出设备540可与输入设备使用相同类型的端口。提供输出适配器542以举例说明存在像监视器、扬声器、以及打印机的需要特定适配器的一些输出设备540。输出适配器542包括但不限于,在输出设备540和系统总线518之间提供连接的视频卡和声卡。其他设备和/或系统和/或设备,诸如远程计算机544,可提供输入和输出两种能力。
[0073]计算机512可以使用到诸如远程计算机544之类的一个或多个远程计算机的逻辑连接来在联网环境中操作。远程计算机544可以是个人计算机、服务器、路由器、网络PC、对等设备或其他常见的网络节点,并且通常包括许多或所有以上相对于计算机512所描述的元件,但在图3中仅示出了存储器存储设备546。远程计算机544可经由通信连接550逻辑地连接。网络接口 548涵盖诸如局域网(LAN)和广域网(WAN)这样的通信网络,但也可包括其他网络。通信连接550是指用来将网络接口 548连接到总线518的硬件/软件。连接550可以在计算机512内或外并且包括诸如调制解调器(电话、电缆、DSL和无线)和ISDN适配器、以太网卡等内和外技术。[0074]可以理解,所示网络连接仅是示例,并且可以使用在计算机之间建立通信链路的其他手段。本领域的普通技术人员可以理解,计算机512或其他客户机设备可作为计算机网络的一部分来部署。在这一点上,本文所公开的主题涉及具有任意数量的存储器或存储单元以及在任意数量的存储单元或卷上发生的任意数量的应用和进程的任何计算机系统。本文所公开的主题的各方面可应用于具有部署在网络环境中的具有远程或本地存储的服务器计算机和客户计算机的环境。本文所公开的主题的各方面也可应用于具有编程语言功能、解释和执行能力的独立计算设备。
[0075]图4示出集成开发环境(IDE)600和通用语言运行时环境602。IDE600可允许用户(例如,开发者、程序员、设计者、编码者等)在计算机系统中设计、编码、编译、测试、运行、编辑、调试或构建程序、程序集、网站、web应用和web服务。软件程序可包括用一个或多个源代码语言(例如,Visual Basic> Visual J#、C++、C#、J#、Java Script、APL、COBOL、Pascal、Eiffel、Haskell、ML、Oberon、Perl、Python、Scheme、和 Smalltalk 等)创建的源代码(组件610)。IDE600可提供本机代码开发环境,或者可提供在虚拟机上运行的托管代码开发,或者可提供其组合。IDE600可提供使用.NET框架的托管代码开发环境。可使用语言专用源编译器620从源代码组件610和本机代码组件611创建中间语言组件650,并且在执行应用时使用中间语言编译器660 (例如,即时(JIT)编译器)从中间语言组件650创建本机代码组件611 (例如,机器可执行指令)。即,当IL应用被执行时,其在被执行的同时被编译成适合正在其上执行它的平台的合适机器语言,藉此使代码能跨若干平台便携。替代地,在其他实施例中,程序可被编译成适合其目标平台的本机代码机器语言(未示出)。
[0076]用户可根据已知软件编程技术以及与特定源语言相关联的特定逻辑和句法规则经由IDE600中的用户接口 640和源代码编辑器651来创建和/或编辑源代码组件。此后,源代码组件610可经由源编译器620被编译,藉此可创建该程序的中间语言表示,诸如汇编630。汇编630可包括中间语言组件650和元数据642。
[0077]应用设计可以能够在部署前被确认。
[0078]本文所述的各种技术可结合硬件或软件,或在适当时以其组合来实现。由此,本文所公开的方法和装置或其特定方面或部分可采取包含在诸如软盘、CD-ROM、硬盘驱动器或任何其他机器可读存储介质等有形介质中的程序代码(即,指令)的形式,其中当程序代码被加载到诸如计算机等机器内并由其执行时,该机器成为用于实现本文所公开的主题的各方面的装置。如此出所用的,术语“机器可读介质”应被用来排除提供(即存储和/或传输)任何形式的传播信号的任何机制。在程序代码在可编程计算机上执行的情况下,计算设备通常将包括处理器、该处理器可读的存储介质(包括易失性和非易失性的存储器和/或存储元件)、至少一个输入设备、以及至少一个输出设备。可例如通过使用数据处理API等来利用域专用编程模型各方面的创建和/或实现的一个或多个程序可用高级过程语言或面向对象的编程语言来实现以与计算机系统通信。然而,如果需要,该程序可以用汇编语言或机器语言来实现。在任何情形中,语言可以是编译语言或解释语言,且与硬件实现相结合。
[0079]尽管用结构特征和/或方法动作专用的语言描述了本主题,但可以理解,所附权利要求书中定义的主题不必限于上述具体特征或动作。更确切而言,上述具体特征和动作是作为实现权利要求的示例形式公开的。
【权利要求】
1.一种系统,包括: 计算设备的处理器和存储器;以及 n路互操作调试器,该n路互操作调试器包括被配置成使得所述计算设备的处理器互操作地调试在单个被调试程序进程中执行的与n路互操作调试器兼容的多个运行时被调试程序的多个模块,所述n路互操作调试器提供所述单个被调试程序进程的整体视图,所述n路互操作调试器包括: 步进管理器模块,所述步进管理器模块包括所述多个运行时被调试程序的通信信道,所述步进管理器1旲块执行包括以下的最闻级步进仲裁: 按优先级次序联系所述多个运行时被调试程序中的至少一个; 从所述多个运行时被调试程序中声明对当前调试指令的所有权的所联系的运行时被调试程序接收响应,该声明运行时被调试程序包括当前控制运行时; 向所述多个运行时被调试程序通知该当前控制运行时;以及 调试监视器模块,所述调试监视器模炔基于所述n路互操作调试器和所述多个运行时被调试程序之间通用协议将调试事件路由到相应的运行时调试器。
2.如权利要求1所述的系统,其特征在于,所述步进管理器模块通过以下步骤为所述调试操作选择当前控制运行时: 按优先级次序联系所述多个运行时被调试程序中的至少一个; 从所述多个运行时被调试程序中声明对当前调试指令的所有权的所联系的运行时被调试程序接收响应,该声明运行时被调试程序包括当前控制运行时;以及向所述多个运行时被调试程序通知该当前控制运行时。
3.如权利要求1所述的系统,其特征在于,所述多个运行时被调试程序中的至少一个是虚拟机运行时被调试程序、解释运行时被调试程序或本机运行时被调试程序。
4.如权利要求1所述的系统,其特征在于,调试操作包括: 将被调试程序代码运行从一个运行时被调试程序步进到另一调试运行时; 在多个运行时被调试程序中设置断点; 检测来自多个运行时被调试程序的值; 执行包括来自所述多个运行时被调试程序的代码的调用栈。
5.一种方法,包括: 由在处理器上执行的n路互操作调试模块接收来自在单个调试进程中执行的多个运行时被调试程序中的一个的调试通信,所述调试通信符合被所述多个运行时被调试程序共享的协议,其中所述多个运行时被调试程序包括:不执行调试代码的运行时、检测到从一个运行时被调试程序到另一运行时被调试程序的转移的运行时以及检测到在其他被调试程序运行时中抛出的各异常的运行时; 通过按优先级次序联系所述多个运行时被调试程序中的至少一个来确定包括所述多个运行时被调试程序中的一个运行时被调试程序的当前控制运行时;以及 向所述多个运行时被调试程序中的至少一个通知所确定的当前控制运行时。
6.如权利要求5所述的方法,其特征在于,所述运行时被调试程序中的至少一个包括虚拟机运行时、解释器运行时或本机运行时。
7.如权利要求5所述的方法,其特征在于,在一个运行时被调试程序中抛出的异常被在所述多个运行时中的另一运行时被调试程序中捕获。
8.如权利要求5所述的方法,其特征在于,所述单个进程的调用栈包括来自所述多个运行时被调试程序的各帧。
9.如权利要求5所述的方法,其特征在于,各运行时被调试程序之间的转移被检测到。
10.一种包括当执行时使计算设备的至少一个处理器执行下列操作的计算机可执行指令的计算机可读存储介质: 由在所述至少一个处理器上执行的n路互操作调试模块接收来自在单个调试进程中执行的多个运行时被调试程序中的一个的调试通信,所述调试通信符合被所述多个运行时被调试程序共享的协议,其中所述多个运行时被调试程序包括:不执行调试代码的运行时、检测到从一个运行时被调试程序到另一运行时被调试程序的转移的运行时,以及检测到在其他被调试程序运行时中抛出的各异常的运行时; 通过按优先级次序联系所述多个运行时被调试程序中的至少一个来确定包括所述多个运行时被调试程序中的一个运行时被调试程序的当前控制运行时; 向所述多个运行时被调试程序中的至少一个通知所确定的当前控制运行时; 接收来自解释器运行时被调试程序、本机运行时被调试程序或虚拟机运行时被调试程序的调试通信。
【文档编号】G06F11/36GK103620561SQ201280030942
【公开日】2014年3月5日 申请日期:2012年6月6日 优先权日:2011年6月24日
【发明者】J·M·戴维斯, G·B·米斯凯利 申请人:微软公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1