Patent Description:
Various types of computer programming exist. One type of computer programming that has widespread acceptance is accomplished by programming applications within the context of an application framework. For example, the. NET framework available from Microsoft Corporation of Redmond Washington is one example of a framework which can be used to create applications. When programming applications for a framework, often a programmer will generate source code. The source code is compiled to intermediate language code, or bytecode. Bytecode is executed by a runtime virtual machine (for example, a Java virtual machine or common language runtime (CLR)) on a host computer system, where the runtime virtual machine compiles the bytecode to native machine code (for example in a just in time (jit) fashion) for execution by the specific computer system on which the runtime virtual machine is running. Note that different runtime virtual machines can do this in different ways. For example, the Java virtual machine interprets bytecode, and selectively compiles to native machine code when it determines that it is advantageous to do so. NET runtime virtual machine compiles the bytecode to machine code before executing.

Application programmers typically have needed to debug applications while developing the applications and/or as a result of problems that arise when using the applications in the field. To accomplish this, the application programmers will use a debugger, which includes a debugger virtual machine that is able to emulate execution of an application. Note that the debugger virtual machine is an emulator that emulates functionality of runtime virtual machines, and thus, is not itself a runtime virtual machine. A debugger virtual machine is a virtual machine capable of interpreting bytecode and emulating execution of that bytecode given a previous process state. It may or may not share implementation details with the runtime virtual machine A debugger virtual machine allows the programmer to step through code to attempt to identify where problems or errors occur. In particular, a developer can step at high-level, source code, which is translated to bytecode by the source compiler and then jit compiled to machine language. In some embodiments, the debugger virtual machine allows the developer to step through all of the layers at once. The view of the bytecode is super imposed on top of the jit compiled native machine language code. The view of the source language code is then super-imposed on top of that. However, the machine language code is not directly executed, but rather the debugger virtual machine emulates the execution.

Tracking down and correcting undesired software behaviors is a core activity in software development. Undesired software behaviors can include many things, such as execution crashes, runtime exceptions, slow execution performance, incorrect data results, data corruption, and the like. Undesired software behaviors might be triggered by a vast variety of factors such as data inputs, user inputs, race conditions (e.g., when accessing shared resources), etc. Given the variety of triggers, undesired software behaviors can be rare and seemingly random, and extremely difficult to reproduce. As such, it can be very time-consuming and difficult for a developer to identify a given undesired software behavior. Once an undesired software behavior has been identified, it can again be time-consuming and difficult to determine its root cause(s).

Developers have classically used a variety of approaches to identify undesired software behaviors, and to then identify the location(s) in an application's code that cause the undesired software behavior. For example, a developer might test different portions of an application's code against different inputs (e.g., unit testing). As another example, a developer might reason about execution of an application's code in a debugger (e.g., by setting breakpoints/watchpoints, by stepping through lines of code, etc. as the code executes). As another example, a developer might observe code execution behaviors (e.g., timing, coverage) in a profiler. As another example, a developer might insert diagnostic code (e.g., trace statements) into the application's code.

Traditionally, source level debuggers have only allowed execution in the forward direction. That is, a starting point will be selected, state will be loaded for the starting point, and the bytecode will either be executed on a runtime virtual machine or the application execution will be emulated using a debugger virtual machine. The state of the application can be monitored as the application is executed and/or emulated. Bytecode debugger virtual machines have typically not been able to allow reverse execution of the program. Enabling reverse execution is difficult because forward execution tends to destroy previous state. Thus, if an application is stepped back to before a bytecode instruction which changes state, previous state which was changed by the instruction has been lost and cannot be changed to the state that existed prior to the instruction.

<CIT> describes that various technologies pertain to time travel debugging in a managed runtime system. <CIT> describes that a computer program is executed in a forward direction to create a current state of registers and memory for the program. <CIT>describes a method for debugging a machine code of a program that has been subjected to an optimizing action, wherein the machine code may have been reordered, duplicated, eliminated or transformed so as not to correspond with the program's source code order. <CIT> describes a computer implemented process for detecting errors in a computer system.

The invention is set out in the appended set of independent claims.

One embodiment illustrated herein includes a method of performing reverse execution debugging of an application. The method includes identifying a snapshot of application state for the application. The method further includes emulating execution of the application, using bytecode, in a forward direction from the snapshot to an end point, causing generation of historical execution state at various points along the emulation of the application. The method further includes collecting the historical execution state. The method further includes using the collected historical execution state, emulating reverse execution of the application by substituting collected historical execution state, when needed, to restore previous state needed as a result of emulation of reverse execution of the application.

One example embodiment illustrated herein enables reversible debugging by using recorded data, including periodic (or otherwise obtained) snapshots of application execution along with a collection of runtime virtual machine external state (i.e., data that cannot be reproduced by emulating execution of the application). Embodiments may record full snapshots of an entity's memory space and processor registers while it executes. Runtime virtual machine external state may be produced at kernel calls or at other places of non-determinism. In general, any time execution leaves and reenters execution of the runtime virtual machine, runtime virtual machine external state is potentially produced. At these points in execution, runtime virtual machine external state can be recorded. Note that in some embodiments, full snapshots may be taken at points of nondeterminism, with respect to the runtime virtual machine, such that the collection of snapshots would include all runtime virtual machine external state. However, these embodiments would have substantial overhead required. Therefore, it may be preferable to take periodic snapshots that capture all relevant state along with separate recoding of individual pieces of runtime virtual machine external state, recorded at points of nondeterminism, with respect to the runtime virtual machine.

Note that as will be discussed in further detail below, embodiments may be somewhat selective in recording data. For example, some embodiments will only record data for later debugging for user generated application code. For example, while user generated application code may make various calls to various libraries and functions within the framework for the runtime virtual machine, execution of those functions is not of interest due to the fact that it represents code which the user is not actively developing. Thus, in some embodiments, snapshots and collection of runtime virtual machine external state will not be collected for portions of the runtime virtual machine code that are not user generated portions of the runtime virtual machine code. Note that some embodiments allow this to be modified. For example, a user may wish to collect snapshots and runtime virtual machine external state in code other than user generated code. The user can indicate that additional code should have data collected for debugging. In some embodiments, collecting data for user code may be a default setting such that collection of data for other code requires the user to modify collection of data beyond the default.

Note that recorded debugging data can be used in a number of different fashions. For example, in some embodiments, a user may simply collect the debugging data as the user actively develops an application. That is, as the user is developing an application, the user can also execute portions of the application to collect debugging data for the application. The user can then use the debugging data to step through an emulated execution of the application. Alternatively or additionally, the recorded debugging data can be provided to another entity for debugging. In yet another alternative or additional embodiment, the recorded debugging data can be provided to an automated execution inspection entity configured to use the recorded debugging data to emulate execution of the application in an automated fashion to check for certain characteristics, results, or other desired information.

If the application is a process executed by a runtime virtual machine (for example. NET runtime or Java VM), it's possible to capture only the state related to the runtime virtual machine rather than the entire process. After these snapshots are created, it is possible to replay forward from the snapshot using a debugger virtual machine, which is an emulator of the runtime virtual machine (i.e., a secondary diagnostic virtual machine configured to emulate the runtime virtual machine). The emulated bytecode instructions of the debugger virtual machine are typically more simply emulated than execution of the actual native code executed by the framework runtime virtual machine of the host machine enabling lower overhead replay than the traditional techniques of native emulation.

Immediate state is generated and preserved as historical state by forward emulation using a debugger virtual machine from a snapshot, where the preserved historical state can be used to restore previous state that would have otherwise been unavailable. Thus, once embodiments are able to emulate forward from a snapshot, the emulation can preserve historical state necessary (i.e., previous state) to execute in reverse enabling a full fidelity reversible debugging scenario.

Embodiments can obtain and preserve collected state in various different ways. For example, in some embodiments, collecting the historical execution state is done by collecting the execution state into a stack such that the previous state can be restored by popping elements of the historical execution state from the stack as needed. Collecting the historical execution state includes collecting the historical execution state by iteratively emulating execution, using a debugger virtual machine, from the snapshot toward an endpoint, where each iteration of emulated execution emulates execution of progressively smaller portions of the application. For example, in some embodiments an instruction count may be kept for each iteration. A successive iteration emulates execution of one less instruction. Reverse execution of the application is emulated by surfacing state as a result of each iteration.

<FIG> illustrates a runtime virtual machine <NUM> implemented on a computer system <NUM>. In this example, the runtime virtual machine <NUM> may be a common language runtime virtual machine such as those available in the. NET runtime available from Microsoft Corporation of Redmond Washington or a Java virtual machine. These runtimes virtual machines manage the execution of managed code, such as. NET applications. An example of an application <NUM> is illustrated. The runtime virtual machine <NUM> executes bytecode on a real machine (i.e., the computer system <NUM>). This is done by either interpreting the bytecode within the runtime virtual machine <NUM>, or compiling and executing it for the specific machine on which the runtime virtual machine <NUM> is executing. Thus, the application <NUM> has a bytecode representation. Typically, bytecode is created by compiling source code to bytecode.

The runtime virtual machine <NUM> can convert compiled bytecode into native machine instructions which can then be executed as appropriate by the computer system <NUM>. For example, in some embodiments, the runtime virtual machine <NUM> can perform jit compilation to convert the bytecode of the application <NUM> to machine instructions for execution on a processor of the computer system <NUM>.

Referring now to <FIG>, an example execution <NUM> of the application <NUM> is illustrated. In the example execution, bytecode instructions from the application <NUM> are converted to native machine instructions which are executed by the computer system <NUM>. As the native machine instructions are executed, the state of the runtime virtual machine <NUM> will change. In some embodiments, snapshots (illustrated in the present example at <NUM>-<NUM>, <NUM>-<NUM>, <NUM>-<NUM>, through <NUM>-n) are taken. In some embodiments, these snapshots may be taken on a periodic basis. Alternatively or additionally, the snapshots may be taken based on breakpoints set in machine instructions. For example, a developer can identify locations in the application <NUM> where breakpoints should occur. The appropriate machine instructions can be identified, and breakpoints can occur at these locations to generate a snapshot of the runtime virtual machine <NUM>, where after execution of the application can be resumed. Alternatively or additionally, snapshots may be taken at points where execution leaves and/or returns to the runtime virtual machine.

During the execution <NUM> of the application <NUM> there may be various points during the execution where runtime virtual machine external state (i.e., state that cannot be recreated by emulation of the application) is generated. This runtime virtual machine external state will be needed later when attempting to debug the application <NUM>. That is, embodiments may need to collect runtime virtual machine external state when executing an application, when the application will be later emulated, because that state will not be available during emulation. Namely, that runtime virtual machine external state is generated during execution only and cannot be sufficiently emulated by a debugger.

Runtime virtual machine external state (which as used herein is any nondeterministic from the perspective of the runtime virtual machine, and includes external state that cannot be recreated by virtually re-executing the process during replay) can be generated as a result of a number of different actions. For example, kernel calls may result in the generation of runtime virtual machine external state. When execution of the application <NUM> enters or exits the runtime virtual machine, runtime virtual machine external state may be generated. Calls to an API may generate runtime virtual machine external state. Instructions generating a random number may result in runtime virtual machine external state. Instructions identifying a date, time, etc. may result in generation of runtime virtual machine external state. Reading or writing file I/O may result in the generation of runtime virtual machine external state. Shared memory reads may result in the generation of runtime virtual machine external state. Multithreading can result in the generation of runtime virtual machine external state.

Thus, the debugger <NUM> that is configured to periodically (or use other criteria) capture the snapshots <NUM>-<NUM>, and the runtime virtual machine external state, generally illustrated at <NUM>, as a result of identifying some instruction, event, etc. that results in the generation of runtime virtual machine external state. The snapshots, referred to generally as snapshots <NUM>, and runtime virtual machine external state <NUM> can be preserved for later use in emulation of the application <NUM>. Additionally, as will be illustrated below, emulation of the application <NUM> can be used to generate historical state. Historical state is typically generated by managed code elements of the application <NUM> and this can be collected by emulation of the application <NUM> without the need to actually execute the application <NUM>. That is, a debugger <NUM>, implemented with a debugger virtual machine <NUM> can emulate the runtime virtual machine <NUM> and execution of the application <NUM> without actually needing to perform a full execution requiring compilation of the application <NUM> to native machine instructions. Note that the debugger virtual machine <NUM> capable of interpreting bytecode and emulating execution of that bytecode given a previous process state. It may or may not share implementation details with the runtime virtual machine <NUM>. As will be illustrated later, this collected historical state can then be used to emulate reverse execution of the application <NUM>.

Referring now to <FIG>, one example of emulating forward and reverse execution of the application <NUM> is illustrated. <FIG> illustrates the emulation <NUM>. To perform emulation <NUM>, the debugger <NUM> may emulate execution using the debugger virtual machine <NUM>. Note that emulation does not necessarily require the application <NUM> to have its bytecode compiled to native machine language as the debugger virtual machine <NUM>, so long as it has available data in the snapshots <NUM> and the runtime virtual machine external state <NUM>, can accurately emulate execution of the application without needing to execute machine level instructions. In the example illustrated, assume that a developer wishes to emulate execution of the application <NUM> between the snapshot <NUM>-<NUM> and <NUM>-<NUM>. Note that while in this example emulation is illustrated between two snapshots, emulation can be performed between a snapshot and any other ending point selected by the developer. The ending point does not necessarily need to be a snapshot, but could be any point selected by the developer using the debugger <NUM>.

In the illustrated example, the debugger virtual machine <NUM> will load the state from the snapshot <NUM>-<NUM> to begin execution emulation of execution of the application <NUM>. The debugger virtual machine <NUM> then begins to step through the bytecode of the application <NUM>. As the debugger virtual machine <NUM> steps through the bytecode of the application <NUM>, when runtime virtual machine external state <NUM> is needed, that state can be applied to the state of the debugger virtual machine <NUM> as appropriate.

When emulation <NUM> is performed in the forward direction, any changes in state are added to the stack <NUM>.

Referring now to <FIG> various states of the stack <NUM> are illustrated at different times during the emulation <NUM>. At time T0, the stack <NUM> is empty. At time T1, an instruction <NUM>-<NUM> (<FIG>) from the application <NUM> changes some state value from the value <NUM> to some other value. Thus, the value <NUM> is pushed on to the stack <NUM> as illustrated at time T1. At time T2 runtime virtual machine external state <NUM>-<NUM> (<FIG>) is changed from <NUM> to some new value. Thus, the value <NUM> is pushed to the stack as illustrated at time T2. At time T3, the instruction <NUM>-<NUM> (<FIG>) changes some state value from <NUM> to some other value. Therefore, the value <NUM> is pushed to the stack <NUM> as illustrated at time T3. At time T4, virtual machine external state <NUM>-<NUM> (<FIG>) is changed from <NUM> to some other value. Therefore, the value of <NUM> is pushed to the stack <NUM> as illustrated at T4. At time T5, virtual machine external state <NUM>-<NUM> (<FIG>) is changed from <NUM> to some other value. Therefore, <NUM> is pushed to the stack <NUM>. At time T6, the instruction <NUM>-<NUM> (<FIG>) changes some state value from <NUM> to some other value. Therefore, the value <NUM> is pushed to the stack <NUM>. The stack <NUM> subsequent to the time T6 contains all of the values of state that were previously destroyed by emulating execution of instructions that change state as well as when runtime virtual machine external state was changed.

The emulation <NUM> can now reverse emulation and can restore previous state. For example, if reverse emulation is begun at some point after T6, when the reverse emulation reaches the instruction <NUM>-<NUM> it will pop the value <NUM> from the stack <NUM> to restore the state that was changed by the instruction <NUM>-<NUM>. Continuing further in the reverse emulation example, operations creating the runtime virtual machine external state <NUM>-<NUM> can be identified, and the next value, in this case <NUM>, is popped from the stack to restore the virtual machine external state that existed prior to the virtual machine external state <NUM>-<NUM> to the value of <NUM>. Reverse emulation can continue in this fashion back to the snapshot <NUM>-<NUM>. At any point in the reverse emulation, the debugger <NUM> can be used examine the debugger virtual machine <NUM> state for debugging purposes.

A more detailed version of the example previously illustrated is now illustrated.

<FIG> illustrates that at T0, the snapshot <NUM>-<NUM> includes virtual machine state, or heap state including state indicating that A=<NUM>, C=<NUM>, and F=<NUM>. At time <NUM>, the instruction <NUM>-<NUM> is emulated changing the value ofF from <NUM> to <NUM>. As such, as illustrated in <FIG>, <NUM> is pushed onto the stack <NUM> at time T1. Some embodiments may include a slot which stores the differences between state in the snapshot <NUM>-<NUM> and the current state of the debugger virtual machine <NUM>. Therefore, the value of F is changed at time T1 to <NUM> in the slot <NUM>. At time T2, runtime virtual machine external state <NUM>-<NUM> is changed from a value of E=<NUM> to E=<NUM>. As such, the value of the E=<NUM> is added to the slot <NUM> at time T2 while the value of <NUM> is pushed to the stack <NUM>. Processing continues as illustrated previously pushing values to the stack <NUM> and changing values in the slot <NUM>. Reverse emulation can be performed as described previously, by popping values from the stack <NUM>. As reverse emulation is performed, values will also be replaced in the slot <NUM>. For example when the application steps back in reverse to before the instruction <NUM>-<NUM>, the value in the stack slot <NUM> C=<NUM> will be changed to the value C=<NUM> to reflect the current state of C as a result of popping <NUM> from the stack <NUM> and restoring the state of C to the value that existed just prior to the instruction <NUM>-<NUM> being emulated.

As noted above, the state of the debugger virtual machine <NUM> can be discovered at any time by reference to the slot <NUM>, the appropriate indeterminate state, and/or the snapshot <NUM>-<NUM>. For example, consider a case where forward execution has proceeded until just after time T3. Reverse execution may have been performed until just prior to time T3. At that time, the snapshot would appear as shown in <FIG>, and the slot <NUM> would also appear as shown in <FIG>. When evaluating the state of the debugger virtual machine <NUM>, values in the slot take priority over values in the snapshot <NUM>-<NUM>. Thus, the state of the debugger virtual machine <NUM> would have values of A=<NUM>, C=<NUM>, E=<NUM>, and F=<NUM>. In particular, forward emulation of the application would result in the slot <NUM> illustrated at T3 in <FIG>. As illustrated in <FIG>, the value <NUM> would have been pushed to the stack <NUM> by the instruction <NUM>-<NUM>. Stepping back before the instruction <NUM>-<NUM> would cause the value of <NUM> to be popped from the stack <NUM> into the value A. The slot <NUM> would be updated to reflect this change in state in the value of A. In this fashion, a programmer could examine the state of the debugger virtual machine <NUM> using the snapshot <NUM>-<NUM> and the slot <NUM>.

Collecting the historical execution state includes collecting the historical execution state by iteratively emulating execution from the snapshot toward the endpoint, where each iteration of emulated execution emulates execution of progressively smaller portions of the application, such that reverse execution of the application is emulated by surfacing state as a result of each iteration.

In particular, this embodiment does not need the stack <NUM>, but rather performs iterative operations in emulating smaller portions of the application to emulate reverse execution of the application <NUM>. Again, as illustrated in <FIG>, in this example emulation <NUM> by the debugger virtual machine <NUM> proceeds from the snapshot <NUM>-<NUM> past the instruction <NUM>-<NUM> (<FIG>). In the example illustrated using <FIG>, emulation from after the instruction <NUM>-<NUM> in a reverse fashion back to the snapshot <NUM>-<NUM> is illustrated. As illustrated in <FIG>, forward emulation is performed in a first iteration <NUM>-<NUM> from the snapshot <NUM>-<NUM> until past the instruction <NUM>-<NUM> (<FIG>). This results in the state of the debugger virtual machine <NUM> being such that the value of A=<NUM>, B=<NUM>, C=<NUM>, D=<NUM>, E=<NUM>, and F=<NUM>. As in the previous example, these changes to state caused by emulating the emulation <NUM> can be preserved in a slot <NUM>, although in other embodiments inspection of debugger virtual machine <NUM> state can occur in other fashions. To simulate a reverse execution emulation step, a second iteration <NUM>-<NUM> can be performed by performing a forward emulation from the snapshot <NUM>-<NUM> to a point before the instruction <NUM>-<NUM>. In some embodiments, an instruction count may be maintained for each iteration. Each subsequent iteration may emulate one less instruction than the previous iteration.

Continuing with the example, to simulate yet another reverse emulation step, an iteration <NUM><NUM>-<NUM> can be performed by emulating in a forward direction up to the runtime virtual machine external state <NUM>-<NUM> (<FIG>). To simulate yet another reverse emulation step, the fourth iteration <NUM>-<NUM> can be performed by emulating in a forward direction up to, and including the instruction <NUM>-<NUM> (<FIG>). To simulate yet another reverse emulation step, the fifth iteration <NUM>-<NUM> can be performed by performing a forward emulation from the snapshot <NUM>-<NUM> up to and including the change to the runtime virtual machine external state <NUM>-<NUM> (<FIG>). To simulate yet another reverse emulation step, the sixth iteration <NUM>-<NUM> can be performed by performing a forward emulation from the snapshot <NUM>-<NUM> up to and including the instruction <NUM>-<NUM> (<FIG>).

In this way, a code developer can cause a debugger to emulate reverse execution of the application <NUM> by performing an appropriate number, and appropriate selection of iterations. For example, if the developer wanted to perform reverse emulation from the instruction <NUM>-<NUM> to the before the instruction <NUM>-<NUM>, then the developer could cause the emulator to perform iterations <NUM><NUM>-<NUM>, <NUM><NUM>-<NUM>, and <NUM><NUM>-<NUM>, in that order. The developer could inspect state of the debugger virtual machine <NUM> over time resulting from these iterative forward emulations to implement a de facto reverse emulation of the application <NUM>.

Note that in some embodiments, recording of runtime virtual machine external state and snapshot data by executing an application can be accomplished together with emulating the application. For example, some embodiments may be able to accomplish live debugging of an application. An example of this is illustrated in <FIG> which illustrates the emulation <NUM> performed in conjunction with the execution <NUM>. In particular, emulation of bytecode instructions on a debugger virtual machine <NUM> is performed as illustrated at <NUM>, while execution of machine level instructions are performed on a runtime virtual machine <NUM> as illustrated at <NUM> when needed. For example, when the emulation <NUM> proceeds to a point where the snapshot <NUM>-<NUM> needs to be generated, the emulator can set a breakpoint <NUM>-<NUM> in the execution <NUM> to gather runtime virtual machine state for the snapshot <NUM>-<NUM>. The emulation can then proceed up until runtime virtual machine external state <NUM>-<NUM> is needed. At this point, the emulation knows that it cannot obtain the runtime virtual machine external state <NUM>-<NUM> on its own and needs the application to be executed by the runtime virtual machine <NUM>. Thus, the emulator can set the breakpoint <NUM>-<NUM> and cause execution of the application on the runtime virtual machine <NUM> up until the breakpoint <NUM>-<NUM>. At this point, the emulator can obtain the runtime virtual machine external state <NUM>-<NUM>, and continue emulation using the debugger virtual machine <NUM>. The emulation can continue until it is determined that the runtime virtual machine external state <NUM>-<NUM> is needed. Again, the emulator can set a breakpoint <NUM>-<NUM>, and cause the execution <NUM> on the runtime virtual machine <NUM> to continue up to that point. At this point, execution of the application breaks and the emulator can obtain the runtime virtual machine external state <NUM>-<NUM>. Again, emulation <NUM> can continue, using the debugger virtual machine <NUM>, until the emulator determines that it needs the runtime virtual machine external state <NUM>-<NUM>. The emulator can set a breakpoint <NUM>-<NUM> in the execution <NUM> and cause the execution <NUM> to proceed on the runtime virtual machine <NUM>. Execution of the application breaks at the breakpoint <NUM>-<NUM>, at which point the emulator can recover the runtime virtual machine external state <NUM>-<NUM>.

Reverse execution can proceed in the fashions described above such that either a stack or multiple iterations of emulation can be performed as illustrated previously. Note that, in particular, only a single execution needs to be performed even though multiple iterations of the emulation <NUM> are performed. In particular, the runtime virtual machine external state <NUM>-<NUM>, <NUM>-<NUM>, and <NUM>-<NUM> can be preserved with a single execution <NUM> rather than multiple executions of the application.

Note that in some embodiments, multiple traces can be collected then debugged in one session. For example, embodiments can switch between divergent branches of execution and explore them independently.

Referring now to <FIG>, a method <NUM> is illustrated.

The method <NUM> includes acts for collecting runtime virtual machine external state for an application running in an application runtime virtual machine, for use in emulation of the application. The method <NUM> includes identifying application bytecode for which runtime virtual machine external state is to be collected (act <NUM>).

The method <NUM> further includes executing machine code generated from the bytecode to generate the runtime virtual machine external state (act <NUM>). For example, this may include compiling the bytecode to machine code, such as jit compiling bytecode to native machine code as needed to gather the runtime virtual machine external state.

The method <NUM> further includes collecting the runtime virtual machine external state (act <NUM>).

The method <NUM> further includes storing the runtime virtual machine external state for use in emulating the application (act <NUM>). For the example, the runtime virtual machine external state may be collected and stored persistently into a database, flat file, or other appropriate data structure.

The method <NUM> may be practiced where identifying bytecode for which state is to be collected comprises identifying runtime virtual machine boundaries in execution of the application, and collecting application state between those runtime virtual machine boundaries. That is, runtime virtual machine external state, in some embodiments, will only be identified and collected for managed runtime virtual machine code.

The method <NUM> may be practiced where identifying bytecode for which state is to be collected comprises identifying user generated code boundaries in execution of the application, and collecting application state between those user generated code boundaries. That is, runtime virtual machine external state, in some embodiments, will only be identified and collected for managed runtime virtual machine code created by a particular user. Other code that exists as part of the runtime virtual machine, even though it is managed code, will not have state collected, in these embodiments. This may be done, for example, when there is a desire to debug user code for a particular user. In this way, code that is not user code, which will not be debugged, does not have state collected to avoid collecting additional data that is unlikely to be used or needed for debugging.

The method <NUM> may be practiced where identifying bytecode for which state is to be collected comprises identifying user identified code. For example, a user could select code using selection user interface elements such as checkboxes, highlighting, or inline instrumentation.

The method <NUM> may be practiced where emulation of the application is performed in conjunction with executing the application to collect the runtime virtual machine external state. This may be done to allow for live debugging. An example of this is illustrated above in conjunction with the description of <FIG>. In some such embodiments, an emulator used for emulating the application sets breakpoints in the machine code when the emulator identifies locations in the bytecode where runtime virtual machine external state is required. This causes a break in executing the machine code for collecting the runtime virtual machine external state.

In some such embodiments, an emulator identifies locations in the bytecode where runtime virtual machine external state is required by identifying code that performs at least one of: obtaining a random number, obtaining a time, obtaining data from another source external to runtime virtual machine code in the application runtime virtual machine, identifying shared memory reads, or identifying points where multithreading occurs.

Referring now to <FIG>, a method <NUM> is illustrated. The method <NUM> includes acts for performing reverse execution debugging of an application. The method includes identifying a snapshot of application state for the application (act <NUM>).

The method <NUM> further includes emulating execution of the application, using bytecode, in a forward direction from the snapshot to an end point, causing generation of historical execution state at various points along the emulation of the application (act <NUM>).

The method <NUM> further includes collecting the historical execution state (act <NUM>).

The method <NUM> further includes using the collected historical execution state, emulating reverse execution of the application by substituting collected historical execution state, when needed, to restore previous state needed as a result of emulation of reverse execution of the application (act <NUM>).

The method <NUM> may be practiced where collecting the historical execution state comprises collecting the historical execution state into a stack such that the previous state can be restored by popping elements of the historical execution state from the stack. An example of this is illustrated in <FIG>. In such embodiments, where multiple threads are being executed, a stack may be implemented for each thread being emulated.

In embodiments using a stack, the method <NUM> may be performed where an element is popped from the stack when emulated reverse execution identifies an instruction that changes application state. This causes historical state to replace state of the application to restore the application state to the historical state.

The method <NUM> is practiced where collecting the historical execution state comprises collecting the historical execution state by iteratively emulating execution from the snapshot toward the endpoint, where each iteration of emulated execution emulates execution of progressively smaller portions of the application, such that reverse execution of the application is emulated by surfacing state as a result of each iteration. An example of this is illustrated in <FIG> and the accompanying description. In some such embodiments, each iteration emulates execution of one less bytecode instruction than the previous iteration.

The method <NUM> may further include collecting runtime virtual machine external state for the application by executing machine application code for the application in conjunction with emulating execution of the application. An example of this is illustrated in <FIG>, where real time debugging can be accomplished.

When information is transferred or provided over a network or another communications connection (either hardwired, wireless, or a combination of hardwired or wireless) to a computer, the computer properly views the connection as a transmission medium. Transmissions media can include a network and/or data links which can be used to carry desired program code means in the form of computer-executable instructions or data structures and which can be accessed by a general purpose or special purpose computer.

Claim 1:
A method of performing reverse execution debugging of an application, the method comprising:
identifying a snapshot of application state for the application;
emulating execution of the application, at an intermediate level code, in a forward direction from the snapshot to an end point, causing generation of historical execution state at various points along the emulation of the application;
collecting the historical execution state by iteratively emulating execution from the snapshot toward the endpoint, where each iteration of emulated execution emulates execution of progressively smaller portions of the application, such that reverse execution of the application is emulated by surfacing state as a result of each iteration; and
using the collected historical execution state, emulating reverse execution of the application by substituting collected historical execution state, when needed, to restore previous state needed as a result of emulation of reverse execution of the application.