HK40035552B - Execution control with cross-level trace mapping - Google Patents

Execution control with cross-level trace mapping

Info

Publication number
HK40035552B
HK40035552B HK62021024900.4A HK62021024900A HK40035552B HK 40035552 B HK40035552 B HK 40035552B HK 62021024900 A HK62021024900 A HK 62021024900A HK 40035552 B HK40035552 B HK 40035552B
Authority
HK
Hong Kong
Prior art keywords
trace
execution
replay
program
code
Prior art date
Application number
HK62021024900.4A
Other languages
Chinese (zh)
Other versions
HK40035552A (en
Inventor
尼尔森 P·
戴维斯 J·
迈尔斯 D·
莱 T·
陈 D·
莫拉 J·
福尔克 N·
Original Assignee
微软技术许可有限责任公司
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by 微软技术许可有限责任公司 filed Critical 微软技术许可有限责任公司
Publication of HK40035552A publication Critical patent/HK40035552A/en
Publication of HK40035552B publication Critical patent/HK40035552B/en

Links

Abstract

Described technologies aid execution control during replays of traced program behavior. Cross-level mapping correlates source code, an intermediate representation, and native instructions in a trace. The trace includes a record of native code instructions which were executed by a runtime-managed program. The trace does not include any executing instance of the runtime. Breakpoints are set to align trace locations with source code expressions or statements, and to skip over garbage collection and other code unlikely to interest a developer. A live debugging environment is adapted to support trace-based reverse execution. An execution controller in a debugger or other tool may utilize breakpoint ranges, cross-level mappings, backward step-out support, and other items to control a replay execution of the trace. Aspects of familiar compilers or familiar runtimes may be re-purposed for innovative execution control which replays previously generated native code, as opposed to their established purpose of generating native code.

Description

Execution control with cross-level tracing mapping
Technical Field
Embodiments of this disclosure relate to execution control with cross-level tracking mapping.
Background Technology
Computer software is typically complex. Part of this complexity may stem from the nature of the work a program is designed to perform—for example, tracking a large number of real-world items or ongoing transactions over hours or longer, coordinating activities with other complex software, controlling complex hardware, and so on. Complexity also arises in almost any real-world use of software because many details are introduced and must be properly managed to instruct the computer hardware how to perform real-world work that would have been far less precise when initially described in English or another natural language. In other words, the conversion from a high-level description to a low-level implementation executable by a computer system inevitably introduces complexity. Even the source code of programming languages, which are more precise than natural languages, remains at a relatively high level and is therefore ambiguous, open to various interpretations and implementations. As the source code is translated into low-level instructions directly executable by computing hardware, many details are introduced and choices are made during the translation process.
Complexity introduces the possibility of commonly recognized programming errors (also known as "defects" or bugs). The process of identifying the cause of a defect and attempting to modify the program to remedy or remove its effects is called "debugging." Specialized software tools that assist in debugging are called "debuggers." The program being debugged is called a "debugging object."
Debugging is often easiest when developers can run a debug object at will, either slowly or at full speed, or pause its execution at will, and can inspect all its state information at any point during its execution. This is known as "real-time process debugging." However, such complete access to a debug object is often unavailable. For example, a debug object might be production software, which cannot be debugged in real-time without violating service agreements or harming the reputation, security, or financial condition of stakeholders. Pausing a real-time process debug object for even a few seconds at a time while a developer examines variable values, checks which functions are called with which parameter values, reviews source code, considers possible interpretations of defects, and designs tests that might help identify, remedy, or eliminate defects could cause unacceptable harm.
Therefore, state information is sometimes logged while the debug object is executing so that it can be examined later without essentially pausing the debug object's execution. Creating such a log may slow down the debug object, but it can provide useful information without compromising production performance goals as much as real-time debugging. For example, the debug object can be paused long enough to create a memory dump that copies some or all memory values associated with the debugger to disk at a specific point in time. Some aspects of the debug object's execution can also be logged in an execution trace. In cases where the debug object is not a real-time process, some debuggers support using such a trace to replay the traced execution of the debug object. Some debuggers allow the debug object's execution to be replayed forward or backward, enabling "time travel," "reverse," or "historical" debugging.
However, because execution traces may contain less information than is sometimes available during real-time process debugging, and because they record state information at a low level, technical challenges arise when debuggers or other software tools attempt to control replay execution (i.e., execution based on the recorded trace). Depending on the implementation, execution control operations that developers are familiar with and frequently use during real-time debugging may be less accurate or simply unavailable when attempted during trace-based replay.
Therefore, advancements in using low-level execution tracing to effectively and accurately achieve high-level execution control through debuggers or other replay or logging tools can help improve the information available to developers or automated performance monitoring tools. Consequently, such advancements will tend to improve the functionality of computer systems by supporting a more accurate understanding of their behavior and by enabling the mitigation or elimination of system defects.
Summary of the Invention
Some of the techniques described herein involve mapping locations in the program's source code to corresponding locations in the program's execution tracing, thereby improving the accuracy of execution control in tracing-based debugging. Some teachings involve specific breakpoint setting procedures that set one or more breakpoints at locations aligned with source code expressions or statements. Technical mechanisms for adapting to real-time debugging environments to support tracing-based reverse execution are described. Specific technical tools and techniques are described herein in response to the challenges of replaying debug object execution forward or backward or both forward and backward based on execution tracing. Other technical activities related to the teachings herein will also become apparent to those skilled in the art.
Some embodiments described herein use or provide trace replay execution control capabilities that utilize a processor, memory, traces recorded during the execution of a program at runtime, program source code, mappings between source code and its intermediate representations and traces, and an execution controller in a debugger or other tool. The runtime contains supporting code that provides dynamic compilation or memory garbage collection services as the traced program is executed and the trace is captured. A trace may include a record of native code instructions executed by the program. A trace may include a record of data accessed during program execution while the debug object is being executed. A trace may include one or more memory dumps or snapshots. A trace may be stored in one or more files or portions of non-volatile or volatile memory. The execution controller is configured to control the replay execution of the trace in response to a request from a tool. During replay, breakpoints configured to help align grouped native instructions with their corresponding source code entries are used, with the source code and trace native code instructions or other trace entries associated through source intermediate mappings and intermediate native mappings.
Some embodiments described herein use or perform computer-implemented trace replay execution control. The managed program being traced is identified. A managed program (also called a “runtime management” program) is a program configured to execute in conjunction with calls to the runtime. The managed program being traced is a program that is being traced or configured to be traced. A trace replay execution control request is received in a software tool. Based on the trace replay execution control request, a mapping is made between the source code of the managed program being traced and an intermediate representation of that source code, and another mapping is made between that intermediate representation and the trace. The trace does not include any execution instances of the runtime. Replay of the trace can be controlled by, for example, simulating the trace activity in a direction and number corresponding to the trace replay execution control request (e.g., taking a step forward, or repeating the entire routine by stepping over it), or by setting breakpoints at the trace locations, or by performing both of the above.
The examples given are merely illustrative. This "Summary" is not intended to identify key or essential features of the claimed subject matter, nor is it intended to limit the scope of the claimed subject matter. Rather, this "Summary" is provided to introduce some technical concepts in a simplified form, which will be further described in the "Detailed Description" below. The invention is defined by the claims, and in the event of any conflict between the Summary and the claims, the claims shall prevail.
Attached Figure Description
A more specific description will be given with reference to the accompanying drawings. These drawings are only illustrative of selected aspects and therefore cannot fully define the coverage or scope. Although dashed lines indicate that some items are optional, any item recited in the claims or any item that a person skilled in the art would consider non-optional for embodying the claims should be understood to be present in some form in an embodiment of the claims.
Figure 1 is a block diagram showing a computer system and also showing the configured storage media;
Figure 2 is a block diagram illustrating aspects of real-time process debugging;
Figure 3 is a block diagram illustrating aspects of debugging based on a copy of the memory made at a single point in time;
Figure 4 is a block diagram illustrating aspects of an example architecture for trace-based debugging, including the main request and response between the debugger and the replay adapter;
Figure 5 is a block diagram showing various memory cells that can be referenced during debugging or in tracing;
Figure 6 is a block diagram illustrating a machine-level request that can seek information from the execution trace or impose execution control during the replay of the execution trace.
Figure 7 is a block diagram illustrating the response to a machine-level request;
Figure 8 is a block diagram illustrating an example tracking replay execution control system;
Figure 9 is a block diagram illustrating some of the control operations performed during the tracking and replay process;
Figure 10 is a block diagram illustrating some aspects of thread tracing data;
Figure 11 is a block diagram illustrating some aspects of one or more intermediate representations;
Figure 12 is a block diagram illustrating some aspects of a real-time process debugging environment adapted to use traces that support reverse execution debugging;
Figure 13 is a flowchart illustrating an example trace replay execution control method; and
Figure 14 is a flowchart further illustrating some of the tracking replay execution control methods.
Detailed Implementation
Overview
Debugging in a production cloud environment presents significant technical challenges. For example, suppose a specific request R for an online shopping cart is not working. How can developers debug the processing of request R without slowing down the processing of all other requests and minimizing the slowdown in the processing of request R? To find the defect, developers use information about what is happening internally in the code, such as a way to look at the values of variables at one or more points of interest during the processing of request R.
The trace-based debugging innovations discussed here help overcome technical challenges that traditional methods cannot solve. For example, many traditional debuggers and debugging methods allow developers to set halt breakpoints to obtain information about variable values. A halt breakpoint is an instruction to pause execution, giving developers time to examine memory contents at a given point in processing and consider possible interpretations of what is observed. However, in a production environment, halt breakpoints may pause the processing of a large number of requests, cause requests to fail completely (e.g., timeout), or cause execution to take a different path—none of which are desirable. Even pausing only a single thread can lead to unwanted aborted requests and produce unpredictable side effects that hinder debugging, degrade performance, or both.
Some familiar debugging methods involve adding print statements at specific points in the code to print the value of a particular variable, or adding other code, for example, to test the value of a variable to see if it is the value the developer expected at that point in the code. However, these methods may require recompiling and redeploying the code, which is undesirable in production environments, especially if recompiling and redeploying are to be done multiple times as part of an iterative debugging process to find and fix individual defects.
Developers can inject operations into request handling code at execution time to create a copy of some or all of the memory relevant to the request. This copy can include a "snapshot" 304 (an in-memory copy of a process that shares memory allocation pages with the original process via copy-on-write) or a "dump" file 302 (a serialized copy of the process), or both. Some traditional debuggers can read dump files or snapshots and, given appropriate metadata, present the memory contents in a specific format that shows variable values converted from binary to an informative structure including variable names and displayed based on the variable's corresponding data type. However, dumping memory to a file is time-consuming, slowing down not only request R but also the processing of all requests in the example scenario. While taking a snapshot is much faster than creating a dump file, it can require many attempts by the developer to find useful points in the processing to obtain a memory snapshot that reveals the defect, and snapshots consume space in RAM. To view memory at another point in time other than execution time, captured in a dump file or snapshot, another copy of the memory can be created.
Real-time processes are used to view memory at any point in time during the real-time process. In many modern computing systems, as illustrated in the example in Figure 2, the real-time debug object 202, in addition to depending on the operating system, also includes a runtime 204. The runtime 204 provides garbage collection or dynamic code compilation (i.e., JIT compilation or compilation of intermediate language code) or both. Garbage collection may utilize object reachability analysis, object reference counting, or other strategies. Some configurations include an interpreted runtime 204, and those skilled in the art will recognize that the teachings herein can be applied to exercise execution control over the interpreted runtime by overlaying the interpreter's view onto the native trace and using breakpoints within the interpreter itself. Additionally, some runtimes (e.g., runtimes) do not always JIT compile their IL representation (what Java terminology calls "bytecode"). Instead, the runtime may choose to interpret bytecode for less frequently used functions. In this case, execution control may be exercised over the runtime code itself, and a mapping may be made from native code to internal runtime data structures to IL to source code. The mapping from native code to internal runtime data structures to IL can be considered an example of an intermediate native mapping 812, and the mapping from IL to source code can be considered an example of a source intermediate mapping 810.
Unlike processes lacking runtime capabilities, which can be directly controlled by the debugger through the insertion of pause breakpoints, runtime-dependent processes cannot be directly controlled by the debugger 200 because their runtime is effectively hidden from the debugger's memory entries 206, such as memory locations, memory contents, and instruction pointers. To show the developer what is in memory during debugging, the debugger sends a main request 214 to the runtime requesting the current memory values. The runtime sends these values back to the debugger in a main response 216, and the debugger displays the values it received in the response message in a user interface 210.
As a specific example of the drawbacks of the previous approach, consider runtime 204, which is implemented as a virtual machine executing intermediate language (IL). IL code cannot be easily debugged using a traditional native code debugger because that debugger is intended for debugging the virtual machine/runtime, not the IL code.
The runtime also controls the execution of the real-time debug object. Traditional debuggers for IL or languages that compile to IL work by establishing a communication channel between the debugger and the runtime inside the debug object. The runtime within the debug object performs most of the work required to provide the debugging experience. In one example, to set a breakpoint at offset 28 in the intermediate language (IL) instruction in method Foo, a message is sent to the runtime requesting it to set the breakpoint at offset 28 in Foo. The thread within the runtime then receives the message, translates Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. Similarly, to perform familiar execution control operations, such as stepping, stepping in, stepping out, and stepping skipping, the debugger sends a main request 214 to the runtime requesting the operation. The runtime 204 performs the operation and sends an updated status to the debugger in a main response 216, and the debugger displays the result indicated in the response message in a user interface 210.
User interface 210 graphically displays to the user a representation of the debugger's debug object program state. Examples of program states include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, a set of variables in each frame of the call stack, and the values of these variables. The user interface may include windows displaying local data of the routine, watched variables and their values, source code, expression evaluators, and other information about the live debug object 202.
In some implementations, the runtime translation section of debugger 200 is responsible for translating between low-level concepts (such as memory units and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, one or more call stacks for each thread, and the IL instructions to be executed next. Note that the call stack of the abstract runtime layer is not necessarily the same as the call stack at the abstract source code level; for example, the virtual machine's call stack may not match the virtual call stack of the IL code being executed within the virtual machine.
Creating an execution trace 418 of the process is possible. The trace can then be replayed using a simulation of the computer system 102. Sometimes, the trace process is written in source code 212, a high-level language that needs to be executed by the runtime 204 in real-time debugging object 202. The trace itself can be difficult to debug because the trace data reflects a view at a low level (e.g., runtime or just-in-time compiled code or both), rather than the high-level language in which the program was written. Some tracing techniques do not provide a high-level view of the process that the user 104 might prefer. Most high-level runtimes require the runtime itself to provide information about the program running within its framework. Therefore, regular debugging may require the process to be executed within the runtime, which is not optional when debugging is based on a trace rather than a real-time process.
Like any other process, runtime can be traced. However, debugging software other than runtime is more common than debugging runtime. The tracing process can include or exclude tracing some or all of the code that is part of the runtime itself.
This functionality does not apply to situations where there is no trace file currently running. To control the execution of a live process that is executing code that depends on a runtime 204 error, the debugger can send a message to the runtime requesting an action such as "step" or "run," which the runtime then performs on behalf of the debugger.
The ability for a debugger to send messages to the runtime to perform actions on behalf of the debugger does not apply to trace files for which there is no currently executing runtime. Dump files 302 and snapshots 304 are similar to traces in that the runtime is unavailable. A runtime can be represented as a dump, snapshot, or trace, but it is not currently executing and therefore cannot be invoked in the traditional way.
Nevertheless, the trace file 420 can be made part of the debugging environment. Some trace-based debugging embodiments discussed here extend debugging power, allowing the debugger to replay execution from the trace file, starting from one or more points in execution time chosen by the developer, and then moving forward or backward in increments chosen by the developer within the trace execution. One approach is to insert a replay layer between the trace and a high-level language debugger. The replay layer understands runtime execution control messages, thereby allowing high-level control over the traced process.
In some cases, developers can use a "time travel" debugger to control execution replay, running forward or backward in execution time as the recorded trace 418 is replayed. This leverages the debugger's ability to present program state information and memory, such as instruction pointers (multiple), in useful high-level (e.g., named and data-data-based) variable representations, not only for snapshots as before but now for continuous replays of segments of execution time recorded during code execution. Debugging can be made more efficient by aligning grouped trace data with corresponding source code structures (such as expressions and statements). Developers can examine memory values captured in the trace at multiple points in a high-level representation based on the low-level data recorded in the trace file.
As the trace is replayed, the included replay layer can be used to control the state of the debug object. With this adaptation, debugger 200 can apply a runtime (high-level) view of the process trace that has been recorded as machine-level operations. For the purposes of this application only, "machine-level" operations are operations specified at the machine-specific level. Generally, "native" and "machine-level" are used interchangeably herein relative to instructions or code.
Some may view some of the embodiments described herein in a broader context. For example, concepts such as controlled execution, recorded execution, and replaying recorded execution may be considered relevant to specific embodiments. However, this does not accord with the availability of a broad context and seeks proprietary rights to abstract concepts; they are not. Rather, this disclosure focuses on providing suitable specific embodiments whose technical effects fully or partially solve specific technical problems, such as how to automatically associate high-level control requests with machine-level tracing, and other problems addressed herein. Other media, systems, and methods relating to controlled execution, recorded execution, or replaying recorded execution are not within the scope of this invention. Thus, ambiguity, mere abstraction, lack of technical features, and the associated problems of proof are also avoided upon proper understanding of this disclosure.
Technical features
The technical features of the embodiments described herein will be apparent to those skilled in the art and will also be apparent to various interested readers in a variety of ways. Some embodiments address technical activities rooted in computing technology and improve the functionality of computing systems by aiding in debugging these systems, thereby improving system uptime, system accuracy, and power utilization relative to the computational results produced. For example, some embodiments provide system debuggability functionality that helps reduce the amount of time developers spend locating defects while debugging by allowing replay execution to move backward to the desired point rather than restarting from the beginning of execution and moving forward to that point. Some embodiments improve system debuggability by accurately aligning trace data with corresponding source code statements. Some embodiments provide additional debugging functionality in the system, such as the ability to set breakpoint address ranges instead of setting breakpoints at one address at a time.
Some embodiments include technical components, such as computing hardware, that interact with the software in a manner that goes beyond typical interactions within a general-purpose computer. For example, in addition to general interactions (such as general memory allocation, general memory reads and writes, general instruction execution, and some form of I/O), some embodiments described herein also implement backward step-out replay operations as disclosed herein.
Some of the technical effects provided by the embodiments include: more efficient use of debugging time, reduced re-tracing to obtain additional trace data, and improved debugger functionality for exploring defect causality.
Some embodiments include technical adaptations. Some embodiments include a replay layer adapter that accepts requests formatted for runtime, i.e., in a message format compatible with familiar debugger runtime communication, and responds to these requests in a format that can be used by the runtime during real-time debugging. In some embodiments, the replay adapter provides an interface that hides the differences between real-time process debugging, dump-based debugging, and time-travel tracing-based debugging. Some embodiments include a mapping between source code, intermediate representations(s), and trace data.
From the provided description, other advantages of the technical features based on the teachings will also be apparent to those skilled in the art.
Acronyms and Abbreviations
The following defines some acronyms and abbreviations. Other abbreviations may be defined elsewhere in this document, or may not require any definition and will be understood by those skilled in the art.
ALU: Arithmetic and Logic Unit
API: Application Programming Interface
BIOS: Basic Input/Output System
CD: Compressed disc
CPU: Central Processing Unit
DAC: Data Access Component
DVD: Digital Multifunction Disc or Digital Video Disc
FPGA: Field Programmable Gate Array
FPU: Floating-point processing unit
GPU: Graphics Processing Unit
GUI: Graphical User Interface
IDE: Integrated Development Environment, sometimes also called an "interactive development environment".
IL: Intermediate Language
OS: Operating System
RAM: Random Access Memory
ROM: Read-Only Memory
Additional terms
Reference is made herein to exemplary embodiments such as those shown in the accompanying drawings, and specific language is used to describe them. However, changes and further modifications to the features illustrated herein, as well as additional technical applications of the abstract principles illustrated by specific embodiments herein, that may occur to those skilled in the art, should be considered within the scope of the claims.
The meanings of the terms are stated in this disclosure, and these statements should be carefully considered when reading the claims. Specific examples are given, but those skilled in the art will understand that other examples may also fall within the meanings of the terms used and within the scope of one or more claims. The terms herein do not necessarily have the same meaning as they do in their general use (especially in non-technical use), in a particular industry, or in a particular dictionary or encyclopedia. Reference numerals may be used with a variety of wording to help indicate the breadth of the terminology. Omission of reference numerals from a given text does not necessarily mean that the text does not discuss the figures. The inventors claim and exercise their rights to their own lexicographical compilations. Terms in quotation marks are explicitly defined, but may also be implicitly defined without quotation marks. Terms may be defined explicitly or implicitly in the “Detailed Description” and/or elsewhere in the application.
As used herein, "computer system" can include, for example, one or more servers, motherboards, processing nodes, laptop computers, tablets, personal computers (portable or non-portable), personal digital assistants, smartphones, smartwatches, smart bracelets, cellular or mobile phones, other mobile devices having at least a processor and memory, video game systems, augmented reality systems, holographic projection systems, televisions, wearable computing systems, Internet of Things nodes, and/or other devices that provide one or more processors that are at least partially controlled by instructions. Instructions may take the form of firmware or other software in memory and/or dedicated circuitry.
A "multithreaded" computer system is a computer system that supports multiple threads of execution. The term "thread" should be understood to include any sequence of instructions that can be performed or scheduled (and possibly synchronized), and may also be referred to as, for example, as a "procedure" or "coroutine". Threads can run in parallel, sequentially, or in a combination of parallel execution (e.g., multiprocessing) and sequential execution (e.g., time-sliced).
A processor is a unit for processing threads, and is the core of implementations such as simultaneous multithreading. Processors comprise hardware. A given chip can contain one or more processors. Processors can be general-purpose or customized for specific purposes, such as vector processing, graphics processing, signal processing, floating-point arithmetic, encryption, I/O processing, etc.
The "kernel" includes the operating system, virtual machine monitor, virtual machine, BIOS code, and similar hardware interface software.
"Code" refers to processor instructions, data (including constants, variables, and data structures), or both. "Code" and "software" are used interchangeably in this document. Executable code, interpreted code, and firmware are some examples of code. Code that is interpreted or compiled for execution is called "source code."
The term "program" is used extensively in this article to include applications, kernels, drivers, interrupt handlers, firmware, state machines, libraries, and other code written by programmers (also known as developers) and/or automatically generated.
"Service" refers to consumable programs provided in a cloud computing environment or other network environment.
An "execution time point" refers to a specific point in time that is executed for a processing unit or thread, especially in relation to tracing execution. References to "specific execution time" or "execution time t" in this document refer to execution time points. For example, an execution time point can be implemented as a timecode variable or timecode value, or as a relative position in other records of tracing or execution activity. An execution time point ta "earlier than" or "later than" an execution time point tb indicates that the relative order of the two execution time points is determined. Similarly, a "younger" execution time point is a later execution time point than an "older" execution time point.
Information regarding the order of events in a tracing may be incomplete. Therefore, a tracing may have enough information to determine that event A precedes event B, or that event D follows event C. However, the relative order of events may also be partially or completely uncertain, even when considering a tracing. A tracing may show that event E does not follow event F, but this does not necessarily mean that E precedes event F; similarly, without a tracing also showing that K follows J, a tracing may show that event K does not precede event J. A tracing may also lack sufficient information to establish any order of two specific events relative to each other.
A "timecode" represents a monotonically changing value that can be used to impose order on at least some events in an execution tracing. It can be expected that timecodes are typically monotonically increasing values, but they can also be implemented as monotonically decreasing values. Some examples of timecodes include instruction counters, clock times (also known as clock ticks), and completely artificial (not register- or instruction-based) monotonic values. Depending on the tracing, all or some, or no, of the traced events may have corresponding associated timecodes. When timecodes exist, they can be unique, or they may simply be monotonic due to some timecode values being repeated.
A "memory cell" refers to an addressable unit of memory. Examples include bytes or words in RAM or ROM, processor registers, cache lines, and other addressable memory cells.
An emulator performs a simulation that provides the same functionality as the original hardware, but uses a different implementation or different hardware, or both. An example is a CPU emulator, which functions similarly to a CPU and can be used to execute code like the original CPU hardware, but with a different implementation; for example, the emulator can run on completely different physical hardware.
Unless otherwise stated, as used herein, “include” allows for additional elements (i.e., include means contain).
"Optimization" means improvement, not necessarily perfection. For example, an already optimized program or algorithm can be further improved.
For example, the term "process" is sometimes used herein as a term in the field of computer science and, in a technical sense, encompasses users of computational resources, namely coroutines, threads, tasks, interrupt handlers, application processes, kernel processes, procedures, and object methods. "Process" is also used herein as a term in patent law, for example, when describing process claims in contrast to system claims or claims of articles of manufacture (configured storage media). Similarly, the term "method" is sometimes used herein as a technical term in the field of computer science (a "routine") and also as a term in the field of patent law ("process"). Those skilled in the art will understand the meaning intended for use in particular contexts and will also understand that (in the sense of patent law) a given claimed process or method can sometimes be implemented using one or more processes or methods (in the sense of computer science).
Contrary to the absence of automation, "automatically" refers to the use of automation (e.g., general-purpose computing hardware configured by software for the specific operations and technical effects discussed herein). In particular, steps performed "automatically," while potentially initiated or interactively guided by a human, are not manually executed on paper or in the human mind. Automated steps are performed by machines to achieve one or more technical effects that would be impossible without such technological interaction.
Those skilled in the art will understand that technical effects are the presumptive purpose of technical embodiments. For example, the fact that an embodiment involves computation, and that some computations can also be performed without technical components (e.g., by paper and pencil, or even as mental steps), does not eliminate the presence of technical effects or alter the specificity and technical nature of the embodiment. Operations such as searching trace data at a sufficiently fast speed to allow replay within one or two orders of magnitude of the original execution speed, and computations for grouping native instructions for the trace and aligning instruction groups with corresponding source code items, should be understood herein to require, in addition to their inherent digital nature, a speed and accuracy unattainable by human thought processes (human thought cannot directly interface with trace files or other digital storage to retrieve necessary trace data). This is well understood by those skilled in the art, but others may sometimes benefit from being informed or reminded of the facts. Unless otherwise stated, contrary to mere thought experiments, embodiments are assumed to be capable of large-scale operation in a production environment or a test laboratory within a production environment.
"Computationally" also implies the use of computing devices (at least a processor and memory) and excludes results obtained solely by human thought or action. For example, performing arithmetic with paper and pencil, as understood herein, is not computationally arithmetic. Computational results are faster, broader, deeper, more accurate, more consistent, more comprehensive, and/or provide technical effects beyond the reach of human performance. A "computational step" is a step performed computationally. Neither "automatically" nor "computationally" necessarily means "immediately." "Computationally" and "automatically" are used interchangeably in this document.
"Actively" means without a direct request from the user. In fact, the user may not even be aware that an active step in an embodiment is possible until the result of the step has been presented to the user. Unless otherwise stated, any computational and/or automatic steps described herein may also be performed actively.
Throughout the document, the optional phrase "(multiple)" is used to indicate the presence of one or more of the indicated features. For example, "(multiple) processors" means "one or more processors" or equivalently "at least one processor".
For purposes of U.S. law and practice, the use of the term “step” in the claims or elsewhere herein is not intended to invoke means plus function, steps plus function, or to require interpretation under 35 U.S.C. 112(6)/112(f). Any presumption of such effect is hereby expressly rejected.
For the purposes of U.S. law and practice, claims are not intended to invoke a means-plus-function interpretation unless the phrase “means for…” is used. Claim language intended to be interpreted as means-plus-function language (if any) will explicitly state this intention by using the phrase “means for…”. When a means-plus-function interpretation is adopted, whether by using “means for…” and/or by the court’s legal interpretation of the claim language, the means listed in the specification for a given noun or given verb shall be understood to be linked to the claim language and hereby linked in any way that: appears in the same box in the drawing block diagram, is denoted by the same or similar name, or is denoted by the same reference numerals. For example, if a claim limitation refers to “zac widget” and that claim limitation is subject to a means-plus-function interpretation, then all structures identified anywhere “zac widget” is mentioned in any block, paragraph, or example in the specification, or bound together by any reference numerals assigned to the zac widget, shall be considered part of the structures identified in the zac widget application and contribute to defining the equivalent itemset of the zac widget structure.
Throughout this document, unless otherwise expressly stated, any reference to a step in the process is assumed to be that the step can be performed directly by the interested party, and/or indirectly by a party through an intervention mechanism and/or intervention entity, and still within the scope of that step. That is, unless explicitly stated as directly performed, the step does not need to be performed directly by the interested party. For example, steps involving actions performed by the interested party concerning a destination or other subject, such as alignment, clearing, compiling, continuing, controlling, debugging, simulating, encountering, exceeding, executing, acquiring, grouping, identifying, mapping, receiving, recording, replaying, requesting, responding, sending, setting, specifying, stepping (and variations such as stepping in, stepping out, stepping skipping), terminating, tracing (and alignment, aligned, clearing, cleared, etc.), may involve intervention actions performed by another party, such as forwarding, copying, uploading, downloading, encoding, decoding, compressing, decompressing, encrypting, decrypting, authenticating, invoking, etc., but should still be understood as being performed directly by the interested party.
Whenever data or instructions are referenced, it should be understood that, for example, these items configure computer-readable storage memory and/or computer-readable storage media to convert them into a particular article, as opposed to simply existing on paper, in a person's mind, merely energy, or merely a signal propagating on a wire. For the purposes of U.S. patent protection, according to the interpretation of the U.S. Patent and Trademark Office (USPTO) in the re Nuijten case, memory or other computer-readable storage media is not a propagation of a signal, carrier wave, or merely energy outside the scope of the patentable subject matter. In the United States, no claim covers the signal itself, and any claim interpretation that asserts the contrary is unreasonable. Unless expressly stated otherwise in a claim granted outside the United States, the claims do not cover the signal itself.
Furthermore, although there are obvious contrary provisions elsewhere herein, it should be understood that there is a clear distinction between (a) computer-readable storage media and computer-readable repositories and (b) transmission media (also referred to as signal media or energy-only). A transmission medium is a computer-readable medium or energy-only that propagates a signal or carrier wave. Conversely, computer-readable storage media and computer-readable repositories are not computer-readable media that propagate a signal or carrier wave. Unless expressly stated otherwise in the claims, “computer-readable medium” means computer-readable storage media, not the propagation of a signal itself, nor energy-only.
The term "example" in this document is illustrative. The term "example" is not to be used interchangeably with "invention." Examples may be freely shared or borrowed to create other examples (provided the result is operable), even if the resulting combinations of aspects are not explicitly described herein. It is necessary for a person skilled in the art to perceive that every licensed combination is essential, contrary to the policy of acknowledging that patent specifications are written for those skilled in the art. Formal calculations of combinations and informal intuition regarding the number of possible combinations, even those arising from a small number of composable features, will indicate that there are numerous combinations of aspects described herein. Therefore, requiring an explicit description of each combination contradicts the policy of requiring a concise patent specification and demanding knowledge of the relevant technical field from the reader.
List of reference numerals
The following list is provided for convenience and support of the accompanying drawings and as part of the specification text, which describe innovations by referencing multiple items. However, items not listed herein may still be part of a given embodiment. For clarity and readability, the given reference numerals are cited near some (but not all) of the referenced items in the text. Different examples or instances of the given items may use the same reference numerals. The list of reference numerals is:
100: Operating environment, also known as computing environment
102: Computer system, also known as computing system or computing architecture.
104: User
106: Peripheral equipment
108: Generally refers to the internet.
110: Processor
112: Computer-readable storage media, such as RAM, hard disk
114: Removably configurable computer-readable storage media
116: Processor-executable instructions; may be on removable media or in other memory (volatile or non-volatile or both).
118: Data
120: (Multiple) kernels, such as (multiple) operating systems, BIOS, device drivers.
122: Tools, such as antivirus software, profilers, debuggers, editors, compilers, interpreters, security penetration testers, obfuscators, automated performance monitoring tools, etc., can be adapted to use the execution control taught in this article.
124: Applications, such as word processors, web browsers, spreadsheets
126: Display screen
128: Computing hardware, not otherwise associated with reference numerals 106, 108, 110, 112, 114.
200: Debugger, also referring to debugging activities.
202: Real-time debugging of object programs or procedures
204: Runtime, such as the Common Language Runtime, a virtual machine, or other virtual machines that dynamically translate code for execution (trademark of Oracle U.S., Inc.)
206: Memory items, such as application or system data structures.
208: Data Access Components for the Debugger
210: Debugger User Interface
212: Source code, related information such as metadata and symbol tables.
214: A master request from the debugger for information about a source of debug object, such as a live debug object, dump file reader software, snapshot reader software, or trace file reader software.
216: A response to a master request that seeks information from a debug object's information source or state change; also known as a "master response," such as in a response at the abstraction level of the master request, rather than in a first, initial, or most important response.
218: Statements in source code; for example, they can be explicitly delimited by semicolons or parentheses, curly braces or square brackets, or implicitly delimited by spaces or end-of-line characters.
220: An expression in the source code; syntactically defined by the programming language used; it can be an assignment of function calls, object member assignments, routine calls, or another combination of constants, variables, operators, and routines that produce a result or side effect.
302: Dump file, also known as a storage dump; may include additional information such as indexes or metadata.
304: Storage snapshot; may include additional information such as indexes or metadata.
402: Execution control code for a debug object in the debugger, such as requesting or simulating execution control over the debug object, including stepping through the debug object, setting breakpoints, or executing the debug object until a breakpoint is reached.
404: Cross-level mapping in debuggers or other tools, such as mapping between source code and intermediate representation or mapping between intermediate representation and trace data.
406: A replay component that uses trace files to simulate the execution of a debug object; the trace replay component 406, alone or in conjunction with other execution controllers 402, 408 (implementation-dependent), uses traces to simulate the execution of the original process and allows viewing of CPU state and memory units over time; in some embodiments, this simulation can be performed forward or backward.
408: A replay adapter for the replay component, which allows the replay component to send requests and receive responses that are also used during real-time debugging. In a trace file debugging scenario, the replay layer (i.e., the replay component plus the replay adapter) receives and responds to main requests from the debugger, which can be received and responded to by the runtime in the real-time debugging scenario, and the replay adapter can also make secondary requests to the trace file.
410: Replay adapter interface; configured for communication with the debugger.
414: A secondary request for the trace from the replay adapter, where “secondary” indicates a lower level of abstraction than the main request 214; the secondary request may be a machine-level request, which may be implemented as communication to the trace file reader, or it may be implemented internally within the replay adapter (e.g., as a function call).
416: A response to a machine-level request that seeks information from the trace; also known as a "secondary response," as in the response at the abstract level of the secondary request, rather than as in the second response; it can be implemented as communication from a trace file reader or internally within a replay adapter (e.g., as a function result or data structure update).
418: Performing a trace; Although the dashed lines in Figure 4 indicate that a given trace may include individual items or omit individual items, this document assumes that the trace is not empty, and therefore it is shown as a solid line over the box that generally tracks data 454; 418 can also refer to the activity of creating a trace, which is sometimes also called a “trace” or “record”.
420: A trace file containing execution trace data; this may include machine-level trace data, i.e., data that records execution activities at the native code level.
422: Precise tracking data during tracking.
424: A timecode in a trace that identifies a specific point in time during the execution of the traced code; it may be linked to or embedded in other data within the trace, for example, trace data that explicitly states the point in time at which the stated operation is associated with the stated memory address relating to the stated data value; the timecode may be implemented as, for example, a clock tick or an instruction counter; for each recorded operation, some traces may contain a unique timecode, but in some trace data, the timecode may be repeated or omitted.
428: Gap in the timecodes of a trace, used to explicitly or implicitly indicate the execution time points in which tracing was not performed (e.g., a range when tracing is disabled for a thread or processing unit). This can include any gap where adjacent timecodes differ by a default value or a specified increment (typically 1), for example, the gap for timecode sequences 2, 3, 4, 300, 301, 302 is between 4 and 300, and the gap for timecode sequences 250, 500, 750, 1000, 2000, 2250, 2500 is between 1000 and 2000.
430: Indexes to data in the trace file, such as reverse lookup data structures, used to quickly identify trace attributes, memory lifetime index information, and other searchable lists of locations in the trace data that may be of particular interest.
432: Keyframes in tracking data; for example, they may exist at fixed intervals in the tracking data to allow for faster replay jumps to (or near) keyframes during tracking playback.
434: The code executed, such as the opcodes and parameters of the debug object's machine-level code executed by the processor while the debug object is running and being traced.
436: Stack activity that occurs while the object being debugged is running and being traced, such as stack growth, stack shrinkage, and the execution time at which this activity occurs.
438: Data stream; can correspond to a single thread or a group of threads, can correspond to a processor unit (e.g., a processor core); can correspond to all cores in a given processor socket; can be annotated with metadata to aid in replay.
440: Processor core activities that occur while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by the core.
442: Processor socket activity that occurs while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by any core located in a given processor socket.
444: Thread activity that occurs while the debug object is running and being traced, such as instructions executed during thread runtime, memory accesses performed during thread runtime, and associated metadata such as thread IDs and timestamps.
446: Register activities that occur while the debug object is running and being traced, such as what value is read from which register at what timecode, and what value is written to which register at what timecode.
448: Memory address
450: Instruction opcode
452: Data value
454: Generally refers to tracking data.
456: A tuple, i.e., two or more items of trace data associated in a trace, representing the same operation during trace execution; for example, a memory read operation or a memory write operation may be recorded as a tuple on a single line in the trace, which contains or otherwise associates the opcode (e.g., read or write), the address (e.g., RAM address or register ID), and the data value that has been read or written together.
458: Tracking entry
502: Memory unit, such as a byte or word in RAM or ROM, processor register, cache line, or other addressable memory unit.
504: The stack, for example, is a portion of memory where state information is pushed when a routine is entered, and then popped as control returns from the routine to the code that called the routine; it is generally distinguished from heap memory.
506: The stack base address defines the starting point from which the stack is allocated in contiguous memory; the stack is assumed to grow in a known direction using the allocation of stack memory in the system, which in a given system may be upward (i.e., the address increases as an item is pushed onto the stack), but in another system it may also be downward (i.e., the address decreases as an item is pushed onto the stack); the term "growing" here refers to the direction of stack growth in the system under discussion, while "shrinking" refers to the opposite direction.
508: Stack frame, or allocation record, is allocated on the stack when a routine is called; it typically contains the return address, which identifies the location in the code where execution will resume when the routine returns; it may also contain the address of a value passed as an argument to the routine when it is called, or the address of such an argument value.
510: Heap memory allocated and released along with the construction and release of objects; in some cases, the heap can be automatically garbage collected, and the heap identifies and marks it as available memory, which holds objects that are no longer reachable during the live execution of the process; in other cases, memory allocated from the heap requires a separate explicit call to release the allocated memory.
512: Object
514: Cache memory; for example, it can be in RAM working memory or on the processor chip.
516: Registers in the processor core
518: Object property; a named value that is part of an object; it can be a function, in which case the property is usually called a method; it also refers to a function that implements an object property; a function is a routine that returns a value.
520: ROM (Read-Only Memory); typically non-volatile.
522: Non-volatile memory other than onboard ROM, such as removable flash memory, disk or optical disk storage, magnetic tape storage, etc.
524: RAM (Random Access Memory); typically volatile.
526: Local memory, for example, memory that is local to the stated or implicit context, such as memory that is local to the routine during its execution and then freed, or memory that is local to the thread.
528: Global memory, such as memory that is global for a stated or implicit context, such as memory that is global relative to a set of multiple routines or relative to a set of threads during the execution of any of them.
530: The characteristics of memory that the addition or reduction of an entity outside a thread may alter the value stored in the memory cell, such as whether the memory cell is write-protected relative to other threads, or whether it is in shared memory (such as memory that is global relative to multiple threads).
602: Memory cell specification, such as an address in ROM or RAM or cache, or a register ID, or another item that specifies the memory cell by distinguishing it from other memory cells to allow access (read or write, or a reasonable attempt to read or write) to the memory cell; multiple memory cells may also be specified, for example, as a range of addresses.
604: Register ID, for example, register name, or index to a register array.
606: Address range, that is, a set of adjacent addresses that identify a set of corresponding contiguous memory units; as an example, a range can be specified as a pair of addresses (high address and low address); as another example, a range can be specified as a base address and a count of contiguous units based on the base address.
608: A specification of one or more execution time points, for example, as a specific time code or a range of time codes; the range can be specified as a pair of time codes (start time code and end time code), or it can be specified as a base time code and a count of time code increments, such as the number of clock ticks or the number of instructions.
610: Instruction count, which can be used as a time code; it can be an absolute count from the start of execution of a procedure, or a relative count such as when execution resumes from a thread.
612: System clock value, for example, in milliseconds or CPU cycles.
614: Execution time range specification, that is, data that specifies the range of execution time points; for example, it can be implemented as a pair of time codes (start and end) or as a base time code and a count of time code increments based on the base time code.
616: Execution Time Point
618: Perform control operations, such as stepping forward, stepping backward to skip, going to the specified location, setting or clearing breakpoints, etc.
620: Identifier for performing a control operation; for step or continue operations, it refers to or includes the direction (i.e., forward or backward; "reverse" and "backward" are used interchangeably in this document), and also refers to or includes the increment size (e.g., one step, step skipping a routine, or continue until a breakpoint is encountered).
702: Data values derived from tracking data
704: Instruction Pointer, which identifies a specific instruction or execution point in the trace data; it is a reference position for replay execution to move forward or backward; "backward" means towards younger execution points, and "forward" means towards older execution points.
706: Status code indicating the result of a request, such as successful execution of control operation, control operation initiated (for asynchronous control), or control operation failed.
800: Tracking and Replay Execution Control System
802: The process of the program being traced; it may include one or more threads.
804: Thread
806: A user request for a tool used to perform control operations.
808: Program metadata or tool metadata, such as data that does not have a separate specific number but is still discussed here.
810: Source intermediate mapping, i.e., a mapping between source code or source code item(s) and one or more intermediate representations of source code or source code item(s); mapping 810 is an example of cross-level mapping 404.
812: Intermediate native mapping, i.e., a mapping between one or more intermediate representations and native instructions or other trace data; mapping 812 is an example of cross-level mapping 404.
814: Record of native instruction 116 in the trace; may include, for example, trace data 422 with precise location, executed code 434, tuple 456, or generally trace data 454.
816: JIT (Just-In-Time) Compiler
818: Calls to routines or other calls, such as transferring control to an exception handler or interrupt handler.
820: Return address, that is, the point in time or instruction where execution will continue after calling 818.
822: A set of trace data, such as native instructions, that correspond to specific source code statements S or source code expressions E; for example, this could include a record of the execution of instructions that are generated entirely by compiling source code statements S or source code expressions E, rather than from the compilation of source code statements and expressions adjacent to S or E.
824: Edge instructions of group 822; each group typically has two edges—if the instructions are ordered, one edge is the youngest instruction in the group, and the other edge is the oldest instruction in the group; regardless of whether all instructions in a group are ordered relative to each other, an instruction X in a group of instructions G in the tracing is on an edge of G when X satisfies at least one of the following conditions: X is the first instruction of G encountered during forward execution of the tracing (“first forward edge”), X is the last instruction of G encountered during forward execution of the tracing (“last forward edge”), X is the first instruction of G encountered during backward execution of the tracing (“first backward edge”), or X is the last instruction of G encountered during backward execution of the tracing (“last backward edge”).
826: Intermediate representation, such as low-level code, like intermediate language code, or abstract syntax tree, or symbol table.
828: Breakpoint
830: Breakpoint Range
902: Forward step operation, also known as "forward step" or "step" (when the default or only direction is forward), refers to stepping forward and skipping one source code statement.
904: Forward step-in operation, also known as "forward step-in" or "step-in" (default or only when the direction is forward), means that the entry into the routine is skipped forward, so the next statement to be executed is the first statement of the routine body.
906: Forward step skip operation, also known as "forward step skip" or "step skip" (default or only when the direction is forward), means stepping forward and skipping through the routine, so the next statement to be executed is the first statement after the routine call.
908: Forward step-out operation, also known as "forward step-out" or "step-out" (default or only when the direction is forward), means that forward stepping skips the remainder of the current routine, so the next statement to be executed is the first statement after the routine call.
910: Continue forward operation. When the default or only the direction is forward, also known as "continue" or "run," it means continuing execution forward until a breakpoint is encountered or the process terminates.
912: The backward step operation, also known as "stepping backward," refers to skipping one source code statement by stepping backward.
914: Step-back entry, also known as "step-forward entry," means stepping backward into the routine. Therefore, the next statement to be executed in reverse is the last statement of the routine body.
916: The backward step skip operation, also known as "backward step skip," refers to stepping backward into and through a routine, so the next statement to be executed in reverse is the first statement before the routine call.
918: Step backward, also known as "step back out," means stepping backward to skip the remainder of the current routine. Therefore, the next statement to be executed in reverse is the first statement before the routine call.
920: Continue backwards, also known as "continue backwards," "run backwards," or "run in reverse," means continuing execution backwards until a breakpoint is encountered or the process begins.
Some implementations may use different definitions for operations 902-920, for example, by executing more or fewer instructions or by using different names.
922: Set a breakpoint range, which specifies that execution should pause at any address or execution time point within the specified range of multiple addresses or execution time points.
924: Setting Breakpoints
1004: Thread ID
1006: Thread state, such as created, runnable, running, suspended, blocked, terminated.
1008: Thread code, that is, the code that is executed or can be executed when a thread runs.
1010: Thread memory, for example, memory that is local to a thread, or memory that is global to a thread and is accessed by the thread as it executes.
1102: Symbol Table
1104: Identifiers used in the source code
1106: Data Type
1108: Abstract Data Tree
1110: Intermediate languages, such as Microsoft General Intermediate Language, bytecode (Oracle Corporation trademark), Register Transfer Language, Parrot Intermediate Representation, Standard Portable Intermediate Representation, IR Intermediate Language (LLVM Foundation trademark), etc.
1112: Intermediate Language Code
1300: Example of a trace replay execution control method, and a flowchart illustrating the above method.
1302: Identification Procedure
1304: Received execution control request
1306: Using a mapping between source code and intermediate representation
1308: Using the mapping between intermediate representation and tracking
1310: For example, controlling the response by executing forward or backward, or by setting parameters (direction, increment) on such execution.
1312: Execute the traced instructions during replay, for example, by emulation or by controlling the replay of operations specified in the trace as native instructions (not necessarily all of which are in the trace).
1314: Set a breakpoint or breakpoint range; including 922, 924, or both.
1316: Send a response to the execution control request.
1318: For example, by executing up to the edge of the group before pausing at a breakpoint, align a set of traced instructions with source code statements or expressions.
1400: Flowchart
1402: This indicates a backward stepping exit request.
1404: Sets a breakpoint at the execution location immediately preceding the specified location; when A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, location A is "immediately preceding" location B in the trace.
1406: Set a breakpoint at the edge of a set of instructions that corresponds to a specific source code statement or expression.
1408: Sets a breakpoint range that covers (and in some implementations matches) the range specified as receiving dynamically compiled (“jitted”) code.
1410: Set a breakpoint to step over the specified runtime routine.
1412: An instruction was encountered during the original execution or replay execution.
1414: Exceeding the hardware constraint on the maximum number of breakpoints that can be monitored simultaneously.
1416: Avoid terminating the procedure
1418: Termination of Procedure
1420: For example, by specifying the execution of source code statements or expressions to be executed, one can gain high-level control over the original execution or replay execution.
1422: Execute (original or replay) a process, thread, or program.
1424: Get the user's selection of source code statements or expressions
1426: User selection of source code statements or expressions
1428: Debugging process, thread, or program
1430: Forward execution process, thread, or program
1432: Backward execution of a process, thread, or program
1434: Set a large breakpoint range; this breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in the trace.
1436: Large breakpoint range
1438: Recording tracking data from the real-time process.
1440: Group the traced instructions, i.e., create or specify group 822
1442: Clear breakpoints or breakpoint ranges
Operating environment
Referring to Figure 1, an operating environment 100 for one embodiment includes at least one computer system 102. The computer system 102 may or may not be a multiprocessor computer system. The operating environment may include one or more machines within a given computer system, which may be clustered in a cloud, networked as client servers, and/or peer-to-peer. Individual machines are computer systems, and a group of collaborating machines is also a computer system. A given computer system 102 may be configured for, for example, end-users with applications, for administrators, as a server, as a distributed processing node, and/or otherwise.
Human user 104 can interact with computer system 102 via typed text, touch, voice, mobile, computer vision, gestures, and/or other forms of I/O, using a display, keyboard, and other peripheral devices 106. Screen 126 may be a movable peripheral device 106 or may be an integral part of system 102. The user interface may support interaction between one embodiment and one or more human users. The user interface may include a command-line interface, a graphical user interface (GUI), a natural user interface (NUI), a voice command interface, and/or other user interface (UI) presentations, which may be presented as different options or may be integrated.
System administrators, network administrators, software developers, engineers, and end users are all specific types of users 104. Automated agents, scripts, playback software, etc., representing one or more individuals can also be users 104. Storage devices and/or network devices may be considered peripheral devices in some embodiments, while in other embodiments they may be considered part of system 102, depending on their separability from processor 110. For example, other computer systems not shown in FIG1 may technically interact with computer system 102 or another system embodiment using one or more connections to network 108 via network interface devices.
Each computer system 102 includes at least one processor 110. Like other suitable systems, computer system 102 also includes one or more computer-readable storage media 112. Media 112 can be of various physical types. Media 112 can be volatile memory, non-volatile memory, in-situ fixed media, removable media, magnetic media, optical media, solid-state media, and/or other types of physically persistent storage media (as opposed to media that merely transmits signals). Specifically, when inserted or otherwise installed, a configured medium 114, such as a portable (i.e., external) hard disk drive, CD, DVD, memory stick, or other removable non-volatile storage medium, can functionally become a technical part of the computer system, making its contents accessible for interaction with and use by the processor 110. Removably configured media 114 is an example of computer-readable storage media 112. Other examples of computer-readable storage media 112 include built-in RAM, ROM, hard disks, and other memory storage devices that are not readily removable by the user 104. To comply with current U.S. patent requirements, under any pending or granted claim in the United States, a computer-readable medium, a computer-readable storage medium, or a computer-readable memory is not a signal itself or merely energy.
For example, medium 114 is configured with binary instructions 116 executable by processor 110; "executable" is used broadly herein to include machine code, interpreted code, bytecode, and/or code running on a virtual machine. Medium 114 is also configured with data 118, which is created, modified, referenced, and/or otherwise used for technical effects through the execution of instructions 116. Instructions 116 and data 118 configure the memory or other storage medium 114 in which they reside; when the memory or other computer-readable storage medium is a functional part of a given computer system, instructions 116 and data 118 also configure the computer system. In some embodiments, a portion of data 118 represents real-world items such as product characteristics, inventory, physical measurements, settings, images, readings, targets, volumes, etc. Such data may also be transformed through backup, restore, commit, abort, reformatting, and/or other technical operations.
While an embodiment can be described as being implemented by software instructions executed by one or more processors in a computing device (e.g., a general-purpose computer, server, or cluster), this description does not represent an exhaustive list of all possible embodiments. Those skilled in the art will understand that the same or similar functionality can often also be implemented directly in hardware logic, in whole or in part, to provide the same or similar technical effects. Alternatively, or in addition to software implementation, the technical functionality described herein can be performed at least in part by one or more hardware logic components. For example, and without excluding other implementations, an embodiment may include hardware processors 110, 128, such as field-programmable gate arrays (FPGAs), application-specific integrated circuits (ASICs), application-specific standard products (ASSPs), system-on-a-chip components (SOCs), complex programmable logic devices (CPLDs), and similar components. For example, components of an embodiment may be grouped into interactive functional modules based on their inputs, outputs, and/or their technical effects.
In addition to processor 110 (e.g., CPU, ALU, FPU, and/or GPU), memory/storage medium 112, and display 126, the operating environment may also include other hardware 128, such as batteries, buses, power supplies, wired and wireless network interface cards. The terms "screen" and "display" are used interchangeably herein. Display 126 may include one or more touchscreens, a screen responsive to input from a pen or tablet, or a screen for output only. In some embodiments, peripheral devices 106, such as human user I/O devices (screen, keyboard, mouse, tablet, microphone, speaker, motion sensor, etc.), will be operatively communicating with one or more processors 110 and memory. The software process may be user 104.
In some embodiments, the system includes multiple computers connected by network 108. Networking interface devices may use components such as packet-switched network interface cards, wireless transceivers, or telephone network interfaces (e.g., these may be present in a given computer system) to provide access to network 108. However, one embodiment may also transmit technical data and/or technical instructions via direct memory access, removable non-volatile media, or other information storage, retrieval, and/or transmission methods.
Those skilled in the art will understand that the foregoing and other aspects presented herein in the context of an "operating environment" can form part of a given embodiment. The headings of this document are not intended to strictly categorize features into sets of features specific to embodiments and non-embodiments.
One or more items are shown in dashed lines in the accompanying drawings, or listed in parentheses, to emphasize that they are not necessarily part of the illustrated operating environment or all embodiments, but may interoperate with items in the operating environment or some embodiments discussed herein. Items not shown in dashed lines or parentheses are not necessarily required in any drawing or any embodiment. In particular, Figure 1 is provided for convenience; the inclusion of an item in Figure 1 does not imply that the item or its described use was known prior to the invention.
Debugging environment
Figure 2 illustrates a real-time process debugging environment, which is an example of operating environment 100. Debugger 200 contains various components, many of which are not shown here because many are well-known. The primary use of execution control, as taught herein, can be in environments where real-time process debugging is infeasible or at least undesirable. Nevertheless, real-time process debugging is shown for the context and because it can be combined with trace-based debugging utilizing the execution control taught herein.
Debugger 200 can be a conventional debugger or can be adapted to perform the execution control taught herein. The debugger shown includes a data access component 208 (DAC). In this real-time debugging 1428 environment, DAC 208 communicates with the runtime 204 of the real-time debug object 202 to obtain memory items 206 by using a master request 214 to the runtime and a master response 216 from the runtime. The debugger then updates its user interface 210 accordingly. The user interface presents status information at a relatively high level (e.g., in terms of artifacts defined in source code 212). However, those skilled in the art will understand that the execution control taught herein does not require DAC 208 or other adapters.
Figure 3 illustrates a dump debugging environment, which is another example of operating environment 100. Debugger 200 uses its data access component 208 or functionally similar code to read memory contents from dump file 302 or snapshot 304, or both, as well as other state information at specific points in time during the execution of the debugged object.
Figure 4 illustrates a trace-based debugging environment, another example of operating environment 100. The debugger 200 shown is used in conjunction with or includes (since the scope of the debugger can be defined by a given developer, for example, to include replay adapter 408) a technical adapter that allows the debugger to interact with trace 418 more or less as if the debugger were interacting with the runtime. For example, in this example, the same format could be used for the main request 214 and main response 216 used in the real-time process debugging environment of Figure 2. However, trace-based debugging 1428 can offer developers less flexibility than real-time process debugging because variables and other memory contents accessible through the runtime are not necessarily readable from the trace. The granularity of execution control using a familiar trace-based debugger can also be greater than the granularity available through the teachings presented herein. Finer granularity can provide better control during debugging, thereby accelerating defect location identification and understanding of defects.
Tracing-based debugging, with appropriate execution control code 402, a replay component 406, and a mapping 404 between tracing data and source code 212, can support reverse execution 1422 in the form of a reverse replay of the traced execution. In contrast, in real-time debugging, the debugged object is typically not reverse executed.
The replay adapter 408 shown includes an interface 410 to the debugger, which in this example presents an API to the debugger that matches at least a subset of the APIs presented to a traditional debugger by runtime 204 to support real-time process debugging 1428. Other implementations are also possible. Moreover, as shown by the dashed lines around the replay adapter 408 in Figure 4, in some implementations, some or all of the replay adapters can be considered part of the debugger 200, since the debugger is an adapted debugger 200 containing code that utilizes one or more cross-level mappings 404. For example, instead of using external messages, one variant implements the main request 214 and main response 216, as well as interface 410, as function calls, returns, and interfaces within the debugger. In some variants, the debugger includes and utilizes the cross-level mapping 404, and there is no separate replay adapter 408. Debugger DAC 208 can be used to map address 448 to higher-level object 512. The debugger cross-level mapping 404 and its associated code (i.e., one or more of the execution controller 402, replay component 406, and replay adapter 408) can be used to map source code statements 218 or expressions 220, or both, to specific native instructions 434 or native instruction sets 822. In some embodiments, similar to dump debugging, the DAC 208 has runtime internal knowledge and can read runtime data structures to determine where the JIT source code is located for a given set of IL instructions. The machine architecture on which the debug object runs can be significantly different from the machine architecture on which the debugger runs, but the DAC can be designed to read runtime data structures and handle hardware/runtime differences.
Figure 4 illustrates the communication between the replay component 406 and the trace 418 in the form of a machine-level request 414 and a response 416. This is one possible implementation, as an example, which could use a trace reader (not shown) to receive and respond to the request. However, in another implementation, the machine-level request 414 and response 416 take the form of function calls within the replay adapter 408, which include functions that read from the trace 418 and pass back their caller information found in the trace. Thus, the replay component can maintain current state information, such as which position in the trace 418 is identified by the current instruction pointer 704.
As shown in the figure, trace 418 can be stored in one or more files 420 and can include various types of trace data, as well as metadata that supports or defines the search for the trace data. Some or all of trace 418 can also reside in RAM. Some examples of trace data include precisely located trace data 422 (such as copies of low-level instructions and their operands (also known as "native instructions")), timecode 424 which can be used to sort trace data items relative to each other, memory snapshot 304 or dump file 302, index 430 into the original trace data, keyframes 432 inserted into the original trace data at specified intervals, copies of code 434 executed by the debug object during trace 1422, stack activity 436, data streams 438 read or written by the debug object during trace, processor activity based on per core 440 or per socket (multiple cores) 442, thread activity during trace 444, register reads and writes during trace 446, tuples 456 that associate memory address 448 with instruction 450 and one or more values 452 and optionally also with timecode 424, and other 454 reads or writes or values or opcodes captured during trace. In some embodiments, an instance of any one of items 216, 422, 434, 436, 438, 440, 442, 444, 446, 456 conforms to trace “entry” 458. In some, any minimal portion of trace data 454 that itself represents a change in the state of the traced program conforms to trace “entry” 458. Missing data in the trace can also be considered state information, such as gaps 428 in the timecode sequence.
Figure 5 illustrates various memories 112 that can be tracked and thus subject to changes in value or allocation state according to the teachings herein, changes in value or allocation state being performed by the execution of native instructions under the control of execution 1422. Examples of memory cells 502 shown include stack 504 (including data such as its base address 506 and allocated stack frames 508), heap contents 510 such as object 512, or metadata such as garbage collection data, cache 514, processor registers 516, object members such as attribute 518, addressable units in ROM 520 or RAM 524, removable or third-level memory 522, local memory 526, and global memory 528. Memory cells may have one or more characteristics 530 that increase or decrease the accessibility of the memory cell, for example, the memory may be in kernel space, may be shared, may be DMA-enabled, etc.
Figure 6 illustrates the contents of machine-level request 414. As mentioned above, these requests can be implemented using communication data structures, or they can be implemented as parameters of a routine. Some examples of the contents of machine-level request 414 are a memory cell specification 602 and a specification 608 of one or more execution time points 616. Memory cell 502 can be specified as, for example, a single address 448, an address range 606, or a register name 604. Time code 424 can be specified as, for example, an instruction count 610 or a system clock value 612, and this specification can be for a single specific execution time point 616 (a point during trace, or a specific native instruction) or a range of execution time 614 (i.e., the span or period or interval of execution time during trace, or a set of consecutive native instructions).
Figure 7 illustrates the contents of machine-level request response 416. As mentioned above, these request responses can be implemented using communication data structures, or they can be implemented as routine function return values or side effects. Some examples of the contents of machine-level request response 416 are: a value 702 for one or more memory locations specified in the corresponding request 414; an instruction pointer 704 indicating which instruction will be executed next (or which instruction has just finished executing 1422); and a status code 706 containing flags associated, for example, with an instruction, or an error, or a condition (such as an end-of-file marker). Each thread may have a corresponding instruction pointer 704.
Some tracking and replay execution control systems
Figure 8 illustrates a trace replay execution control system 800, each of which is a system 102 configured according to the execution teachings provided herein. If the execution control system operates in a real-time debugging environment, it contains a debug object program 124 with a callable runtime 204. Although debugging is used as an example, execution control can also be performed as taught herein in other contexts, such as for performance analysis or software health monitoring. The debug object or other replayed program includes one or more processes 802, each of which may include one or more threads 804. Those skilled in the art will understand that the terms “process” and “thread” are used in different ways, for example, sometimes as synonyms for each other, and sometimes with different meanings. In either case, the execution control teachings provided herein can be applied because, under either meaning of “process” or “thread,” process 802 and thread 804 have corresponding source code 212 and corresponding traced instructions 434.
Regardless of whether replay execution occurs in a real-time debugging environment, the state information of the replayed program is maintained and updated as the replay execution "proces." In this sense, "procesuspension" includes forward execution, backward execution, or both. State information includes, for example, one or more instruction pointer values indicating execution time(s) in trace 418, and changes in traced program variable values captured in trace 418. To indicate the presence of state information, the boxes for process(s) 802 are shown in FIG. 8 inside the debug object program 124 box with solid lines instead of dashed lines. However, those skilled in the art will recognize that state information may also be maintained within execution controller 402 or at one or more other locations within system 800.
The execution controller 402 itself includes software executed using processor 110 and memory 112. The traced program 124 is other software having source code 212 and metadata 808. The execution controller 402 uses a source intermediate map 810 to map the source code 212 to an intermediate representation 826 of that source code. The execution controller 402 also uses an intermediate native map 812 to map the intermediate representation 826 to the trace 418 (including a record 814 of native instructions collected from the trace). These maps 810, 812 are collectively referred to herein as “cross-level maps”. Note that a given embodiment may include one or more cross-level maps 404; for example, source-to-intermediate and intermediate-to-native functionality may be integrated into a single source-to-native map 404.
In some cases, such as in the case of .NET languages, the compiler creates the source-to-IL mapping 810. However, there are runtimes 204 that can directly execute the source language; one example is (a trademark of Oracle Corporation). In this case, the runtime itself compiles the language to an intermediate format and simultaneously creates the source-to-IL mapping. In the case of managed languages similar to .NET languages, the high-level language compiler does not perform native IL mapping; instead, the JIT compiler in runtime 204 does. Compilers that compile to native code also do not perform native IL mapping. In fact, if such a compiler has any form of IL, it is likely an implementation detail of that compiler. In some embodiments, execution control utilizes the native IL mapping 812 generated by the runtime.
Some implementations obtain the generated IL from tracing native instructions. For example, some implementations simulate CPU operation by emulating it and use native instructions to replay the tracing. In some cases, the IL alone is not sufficient information to recreate the native instructions. In some cases, the native instructions themselves are insufficient to implement IL stepping or IL breakpoints. Additionally, a mapping between native and IL instructions is used. Some embodiments use mappings without relying on native instructions (which may not even exist in the tracing) to implement debuggers that support stepping through IL code using a tracing replayer that does not rely on knowledge of native instructions. Such implementations can trace the instruction pointer by the range provided in the mapping or by any consecutive or non-consecutive collection of the specified items.
Supplement on cross-level mapping
To further illustrate the cross-level mapping 404, consider the following example: some source code 212, a portion of some corresponding intermediate language code used as intermediate representation 826, and a portion of some native instructions. Due to the patent office's restrictions on the inclusion of computer code in patent documents, and because showing a portion is sufficient to illustrate mapping 404 in the context of the other information provided herein and the knowledge of a person skilled in the art, only portions of the intermediate language code and native instructions are shown here.
Original C# source code:
Sample source-to-IL mapping. This sample is hand-generated. The actual implementation is typically unreadable to humans. That is, the source-to-IL mapping will usually be implemented in binary format rather than text format. Nevertheless, the following material illustrates the functionality of the source-to-IL mapping to those skilled in the art. The mapping is not a one-to-one mapping; some parts of the source code line end at different locations in the IL code. For a single source program, there are many correctly generated IL transformations.
Sample IL to native mapping. Similar to source-to-IL mapping, this is manually generated, and the implementation will exist as a data structure, for example, at runtime. For a single generated IL, there are many correctly generated native code transformations. Because the JIT compiler can add complexity due to processor-specific optimizations, and because debug 1428 using traced programs may not execute on the same processor type (i.e., different optimizations will be applied), it is not simply possible to run the JIT on the IL and the result cannot be guaranteed to be the same as running it during the generation of trace 418. In this example, the IL begins with "IL_", and the native code is represented as <memory address><hexadecimal representation of native code><assembly mnemonic>.
Typically, kernel 120 is present, and is explicitly shown in Figure 8 to help prevent confusion between runtime 204 and kernel 120. The cross-level mapping and execution control described herein assume that the runtime is present in most (if not all) configurations when execution is traced to create trace 418.
Additional aspects of System 800 and related systems
Some embodiments of system 800 include a JIT compiler 816 for dynamically compiling the code of the traced program 124. Some aspects of execution control address the challenges created by JIT compilation, for example, by supporting breakpoint ranges 830, which allow breakpoints to be encountered even if native code spanning the breakpoint location has not yet been generated by compilation, provided the address range that will contain the generated code is known. For example, breakpoint range 830 can be specified as ranges 606 or 614, while individual breakpoints 828 are specified as specific single locations within trace 418.
Referring again to Figure 8, some embodiments of system 800 include a return address 820 for call 818. This return address 820 may be used, for example, when performing a reverse step-out execution control operation that steps out of the calling routine during reverse execution.
Some embodiments improve the accuracy of execution control by providing a more precise correspondence between source code statements or expressions and the traced instructions that implement them. For example, some familiar methods of tracing replay step into the middle of the traced instructions corresponding to a given source code statement 218 or expression 220, which can be confusing. Some embodiments described herein definitively define a set of 822 traced instructions corresponding to a given source code statement 218 or expression 220 (e.g., generated by compilation to implement). The execution controller then sets the instruction pointer to a location at an edge 824 of this set of 822, instead of somewhere in the middle as before. Which edge 824 is selected can depend on whether the execution is replaying forward or backward; for example, a first forward edge is selected for forward replay, and a first backward edge is selected for backward replay. Alternatively, the same edge can always be used regardless of the replay direction; for example, the instruction pointer can always be set at the first forward edge.
Figure 9 illustrates several execution control operations 618. For example, a user presents a control operation request 806 to the debugger 200 or other tool 122 via user interface 210. Execution controller 402 translates the control operation request 806 into a change in the state of process 802. The operations shown include forward step 902, forward step into 904, forward step skip 906, forward step out 908, continue forward 910, backward step 912, backward step into 914, backward step skip 916, backward step out 918, continue backward 920, set breakpoint range 922, and set breakpoint 924. In these operation names, "forward" indicates performing replay forward, and "backward" indicates performing replay backward.
Various step operations 902-920 can be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar operations with similar or identical names. However, internally, for example, they can be implemented through innovations for aligning source code with traces using cross-level mapping 404, instruction group 822, and specific breakpoint placement. Continue operations 910, 920 can also be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar continue operations, while internally, they utilize cross-level mapping 404 or instruction group 822, or both. Set breakpoint operation 924 can also be implemented so that, from the developer's perspective, it operates in a manner similar to or identical to the familiar breakpoint setting operation, while internally, it utilizes cross-level mapping 404 or instruction group 822, or both.
Figure 10 illustrates the thread 804 activity information 444 that can be captured in a given trace 418. It shows the thread identifier 1004, thread state indication 1006, thread executable code 1008, and memory unit 502 status information 1010 such as thread local variables and their identifiers.
Figure 11 illustrates some examples of intermediate representation 826. Examples shown include symbol table 1102, which associates source code identifiers 1104 (variable names, function names, object members, and method names, etc.) with data types 1106 (e.g., integers, floating-point numbers, strings, booleans, and user-defined types). Another example is abstract syntax tree 1108. Other examples include code 1112 written in one or more intermediate languages 1110. More generally, some embodiments use intermediate representation 826 that shares the structure of an intermediate representation created by the compiler, or even a copy thereof. However, intermediate representation 826 is placed in the context of an execution controller, opposite to the compiler's context. Furthermore, intermediate representation 826 is used for tracing replay of the execution tracing 418 of previously generated code, rather than being used to generate that code in the first place.
A technician will recognize that a given source code 212 can potentially be used to generate many different versions of the corresponding IL. However, only one of these versions will be used in the program, and the symbol information emitted by the compiler will correspond to the emitted IL. The debugger can be designed to load only the corresponding symbol information, so only one mapping will exist. In some systems, the runtime may include multiple versions of native code for a given routine; for example, both optimized and non-optimized versions of native code for debugging may exist, or multi-level JIT functionality may provide multiple versions of native code in memory. In such a multi-native version system, replay can still be performed. For example, when a breakpoint is set, it can be set in all existing versions of the native code. Some embodiments use native code generated by the JIT as well as IL code, which are obtained from or via trace 418. Some embodiments also use the corresponding symbol information for the source/IL mapping, which may or may not be included in the same trace file 420.
Figure 12 is a variation of Figure 2. In the environment of Figure 12, both real-time debugging and replay execution are supported. Replay is supported by a scrolling trace 418, which records the forward execution of the real-time debug object in real time, while the debug object executes according to the prompts of debugger 200. For efficiency, only, for example, a pair of buffers is used to track the latest instructions. Trace 418 is written to one buffer until it is full, then to another buffer until it is full, then written back to the first buffer (overwriting the earlier trace), and so on. Alternatively, instead of the scrolling window, all execution activity during the debug 1428 session can be tracked. As another alternative, previously recorded trace 418 can be accessed during the real-time debug session.
Some additional system examples
Examples are provided in this document to help illustrate various aspects of the technology; however, the examples given in this document do not describe all possible embodiments. Embodiments are not limited to the specific implementations, arrangements, displays, features, methods, or scenarios provided herein. A given embodiment may include, for example, additional or different technical features, mechanisms, sequences, or data structures, and may otherwise deviate from the examples provided herein.
Referring to Figures 1-2, some embodiments use or provide a trace replay execution control system 800. This system includes a processor 110, a memory 112 operatively communicative to the processor, and a trace 418 recorded during the execution of program 124 in conjunction with runtime 204 and kernel 120. The trace includes a record 814 of native code instructions 116 executed in at least one thread 804 of the program. Source code 212 of at least a portion of the program is also present.
System 800 also includes a source intermediate mapping 810 that maps between source code and intermediate representation 826 of source code, and an intermediate native mapping 812 that maps between intermediate representation 826 and trace 418.
System 800 also includes an execution controller 402 in software tool 122. The execution controller is configured to control the replay execution of trace 418 in response to request 806 when executed using the processor. In the replay execution, the source code is associated with trace native code instructions or other trace entries through source intermediate maps and intermediate native maps.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: forward execution step into 904 operation, forward execution step out 908 operation, and forward execution step skip 906 operation.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: a backward step-in operation 914, a backward step-out operation 918, and a backward step-skip operation 916.
In some embodiments, execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: continuing forward execution in the trace 910 until any position within the breakpoint range 830 is reached, and continuing backward execution in the trace 920 until a position within the breakpoint range is reached.
In some embodiments, system 800 is configured to step into a portion of source code that has not yet been compiled into native code instructions during replay execution.
In some embodiments, the intermediate representation 826 includes at least one of the following: a symbol table 1102 that associates at least two identifiers 1104 used in the source code with a data type 1106, an abstract syntax tree 1108 derived from at least a portion of the source code, or a conversion 1112 from at least a portion of the source code 212 to the intermediate language 1110.
In some embodiments, tracing 418 does not contain any execution instance of runtime 204, and tracing 418 is not configured to call tracing to execute any runtime-specific code.
In some embodiments, system 800 includes a real-time debug object 202 of program 124 having a runtime callable instance. In some embodiments, trace 418 is recorded from a real-time process and the system is configured to replay the execution of the trace.
In some embodiments, system 800 is configured to skip a portion of the replay execution of trace 418 because execution controller 402 moves the replay execution from a first execution point of the trace to a second execution point of the trace, and the system does not execute trace native code instructions or other trace entries that would otherwise be executed through continued execution from the first position to the second position.
Those skilled in the art will understand that other systems are also within the scope of the teachings presented herein. In particular, some other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any system or apparatus using any of the execution control teachings herein is within this disclosure, whether or not it is in the specific example provided.
Some method examples
Figure 13 illustrates an example of an execution control method 1300, which is an example of a method executed or assisted by an execution controller 402, a cross-level mapping 404, or other items discussed herein. This example method includes identifying a managed program tracked by 1302 as a tracked managed program. Identifying a program as tracked is simple; if a program is being tracked, or has been tracked previously, then it is a tracked program. To some extent, it involves identifying a program as managed because it is managed when it depends on runtime 204 for real-time execution, and runtime 204 may provide different services in different implementations. In many cases, runtime 204 provides automatic management of heap memory through garbage collection based on reachability analysis, reference counting, or other mechanisms. However, what is of greater interest in this application is the use of runtime 204 to execute intermediate language code 1112. In some runtimes, the translation from source to native instructions is not modularized into a source-to-intermediate language stage, followed by an intermediate language-to-native code stage. For example, some platforms execute source code directly (a trademark of Oracle Corporation, USA). For the purposes of this application only, a "managed" program is a program that relies on runtime 204 to generate native instructions. A managed program may also be subject to or not subject to garbage collection performed by the runtime.
The method 1300 shown also includes receiving a request 1304 to perform a control operation on a trace playback. This request may be a request 806 directly from the user through the user interface, or a request 214 from the debugger to the trace execution controllers 402, 406, or 408.
The illustrated method 1300 also includes a mapping 1306 from source code to an intermediate representation and a mapping 1308 from the intermediate representation to native code. This can be done in two stages as indicated, or in some other embodiments, in a single combined stage from source code to native instructions. However, unlike compilation itself, whether in two stages or one stage, mappings 1306 and 1308 are not for generating code for execution, but rather for associating source code locations with locations in the trace of previously generated and executed instructions.
Some implementations map 1306 from source code to an intermediate representation using a symbol file that contains hashes, checksums, or other identifiers of the IL corresponding to the source. If the identifiers match, the debugger loads the symbol file. This symbol file also contains identifiers for each source file used to compile the IL. Before the debugger loads the source files and maps the IL code to the source, it verifies the source file identifiers using the identifiers contained in the symbol file.
When IL is compiled just-in-time (JIT), some implementations use a runtime-generated mapping to map 1308 from IL to native code. In some implementations, the runtime may not guarantee backward compatibility regarding how JIT will occur, and therefore is free to change the JIT process at any time. In such implementations, debuggers may not be able to make assumptions about what the native code output by the JIT process will contain. Therefore, debuggers may request the runtime to provide the mapping between native code and IL.
Some variations of the method 1300 shown include aligning native instruction sets with source code statements or expressions 1318, which are generated by compiling from these source code statements or expressions.
The illustrated method 1300 includes control 1310 for replay, which is to perform "execution control". An example of control 1310 is executing 1312 native instructions or other trace entries corresponding to step, step in, step skip, step out, or continue operation, thereby changing the state of process 802. Another example of control 1310 is setting 1314 individual breakpoints or breakpoint ranges. Those skilled in the art will recognize that performing step, step in, step skip, or step out operations involves setting breakpoints, but it is also possible to set breakpoints without executing native instructions or other trace entries, for example, when preparing for continue operation. In some embodiments, the code itself is not modified to set breakpoints in the trace. Those skilled in the art will recognize that the processor can set execution breakpoints via instructions (e.g., int3 in some Intel architectures) or via hardware breakpoints (registers that specify which address to monitor). In some embodiments, the trace replay execution control system 800 provides similar capabilities. Some implementations do not modify the code flow and support an arbitrarily large number of breakpoints.
Finally, the method 1300 shown includes sending 1316 a response to the request, such as response 416 or another message or data structure containing instruction pointer 704 or status code 706.
Figure 14 illustrates some additional execution control steps that may be performed in some embodiments. Some familiar debuggers do not support the backward step-out operation 918. However, some embodiments identify 1402 as a request for the backward step-out operation 918 and implement the operation as taught herein.
Debuggers can implement some familiar breakpoint operations, namely, the operation for setting a breakpoint 1314. However, some embodiments set breakpoints 1314 and 1404 immediately before the specified location. Some embodiments set breakpoints 1314 and 1406 at the edge of the instruction group 824. Some embodiments set breakpoint range 830 of 1314 and 1408 on, for example, an address range designated for receiving code that is compiled just-in-time (JIT-compiled). In particular, some embodiments set large breakpoint ranges 1436 and 830 of 1434, 1314, and 1408. Some embodiments set breakpoints 1314 and 1410 as part of implementing a step-skip operation to step over runtime routines that the developer may not be interested in. For example, such runtime routines may perform garbage collection, JIT compilation, anti-malware or other security checks, or runtime 204 stewardship functions. The other steps shown in Figure 14 are discussed elsewhere in this document or included for completeness; for example, not only can breakpoints be set, but breakpoint 1442 can also be cleared.
Unless otherwise indicated, the technical methods shown in the figures or otherwise disclosed will be executed automatically by, for example, system 800. Within the scope of actions involving human administrators or other humans, the methods may also be executed partially automatically and partially manually; for example, a person may select 1426 source code statements or expressions and then use tool 122 user interface to request step operations or breakpoint operations. However, a completely manual method is not considered here as an innovation. In a given embodiment, zero or more example steps of the method may be repeated, possibly with different parameters or data to be manipulated. The steps in one embodiment may also be performed in a different order than those shown in the figures. Steps may be performed sequentially, in a partially overlapping manner, or in complete parallel. The order in which steps are performed during a given method can vary from execution of one method to execution of another. Steps may also be omitted, combined, renamed, regrouped, or otherwise deviated from the illustrated flow if the method being performed is operable and conforms to at least one claim.
Some embodiments use or provide a computer-implemented method for a trace replay execution control method. One example method includes identifying, at 1302, the managed program being traced, i.e., a program configured to execute in conjunction with runtime calls and configured to be traced. The example also includes receiving, at 1304, a trace replay execution control request in a software tool running on a computing system. Based on the trace replay execution control request, the example method automatically maps, at 1306, the source code of the traced managed program to an intermediate representation of the source code, and at 1308, the intermediate representation to a trace, at 418. The trace includes a record of native code instructions traced when the traced managed program is executed. Trace 418 does not include any execution instances at runtime. The example method also executes, at 1312, the traced native code instructions corresponding to the trace replay execution control request, thereby replaying a portion of the trace.
In some embodiments, the trace replay execution control request identifier 1402 performs a step-out operation backward to step out of the routine, and the method includes setting breakpoints 1314 and 1404 on the trace native code instructions, the breakpoints having a position immediately preceding the location of the return address of the call to the routine. For the purposes of this method, when 1412A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, position A in the trace is "immediately preceding" position B. For the purposes of this method, when performing source-level debugging, alignment 1318 can associate instruction group edge 824 with the most recently executed source file line number, statement, or expression executed before the current function call. Some embodiments set breakpoints at the call location of the routine; for example, some embodiments set breakpoints at the call location of the current function.
Typically, the source code contains statement 218 and expression 220. In some embodiments, the method includes setting breakpoints 1406 and 1314 on trace native code instruction 116, which are located at edge 824 of a group 822 containing all trace native code instructions mapped by the method to a given statement or expression in the source code. In some implementations, the group contains only all trace native code instructions, and may also contain other instructions.
In some embodiments, the received trace replay execution control requests 806, 214, 414 are named, identified, or otherwise invoked according to one of the following: performing a forward step skip 906 operation to step forward skip a routine; performing a backward step skip 916 operation to step backward skip a routine; performing a forward step enter 904 operation to step forward enter a routine; or performing a backward step enter 914 operation to step backward enter a routine.
In some cases, the received trace replay execution control requests 806, 214, 414 name, identify, or otherwise invoke replay functionality according to the forward execution step-in 904 operation to step into a user code routine, and the replay execution of the user code routine includes the replay execution of at least one call 818 to a runtime routine 204, and the call to the runtime routine has no corresponding call statement or call expression in the source code. In this context, some embodiments include at least one of the following: setting 1408 to specify a breakpoint range designated as receiving the entire memory extent of the dynamically compiled code, or setting a breakpoint 1410 to perform a step-skip operation on the call to the runtime routine.
In some embodiments, the forward stepping into step 904 is performed as follows. The debugger 200, configured according to the teachings herein, maps the source line range 1306 to the intermediate language range and the intermediate language range 1308 to the native range. The debugger then performs this step using low-level primitives; this can be done using instruction-level single-stepping or breakpoints. When the call instruction 818 is encountered, the debugger determines whether the target is a high-level source step that indicates a stepping into at the source level, or a runtime implementation detail that should not be stepped into because it is not explicitly stated in the source code. For example, this determination can be done by querying the runtime or by searching for the name of the calling routine in the source code. If the call is for a different high-level (shown in the source code) routine, the debugger queries runtime 204 (e.g., via DAC 208) to determine whether the calling routine has been JIT-compiled. If the calling routine has been JIT-compiled, the debugger performs stepping into the call using instruction-level single-stepping or by setting a breakpoint inside the target routine to perform stepping into step 904. If the calling routine has not yet been JIT-compiled, the debugger will set breakpoints on the JIT compiler or on the target address region written by the JIT compiler using DAC 208 or another mechanism, with the JIT compilation using multiple data breakpoints. The debugger allows running a trace replay until the JIT compilation is complete. The debugger sets breakpoints on the JIT-compiled target and runs. This continues until native instructions no longer fall within the native step range mapped from the initial action, or the program exits. An exception is a special case that should fall on a catch target.
In some embodiments, the trace replay execution control request invokes at least one of the following operations: continue tracing replay execution forward 910 in the trace until breakpoint 828 is reached; continue tracing replay execution forward 910 in the trace until a position in breakpoint range 830 is reached; continue tracing replay execution backward 920 in the trace until breakpoint 828 is reached; or continue tracing replay execution backward 920 in the trace until a position in breakpoint range 830 is reached. Some embodiments also include other operations that may be invoked in the request, including one or more of, for example, performing a step-in backward 914 operation; performing a step-out backward 918 operation; performing a step-skip backward 916 operation; performing a step-in forward 904 operation; performing a step-out forward 908 operation; and performing a step-skip forward 906 operation. More generally, a given embodiment may be limited to any subset of the operations taught herein.
In some cases, during the execution of the managed program being traced to create trace 418, the maximum number of breakpoints is constrained by the hardware breakpoint constraint that the processor can monitor up to N addresses at a time. However, in some embodiments, the method sets more than N breakpoints during the replay execution of the trace, thus exceeding the hardware breakpoint constraint.
Those skilled in the art will understand that other methods are also within the scope of the teachings presented herein. In particular, other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any method of implementing control teachings using the teachings herein is within this disclosure, regardless of whether it is within the specific examples provided.
Examples of media configurations
Some embodiments include a configured computer-readable storage medium 112. Medium 112 may include a disk (magnetic, optical, or otherwise), RAM, EEPROMs or other ROMs, and/or other configurable memories, particularly computer-readable media (which are not merely for transmitting signals or energy). The configured storage medium may in particular be a removable storage medium 114, such as a CD, DVD, or flash memory. General-purpose memory (which may be removable or non-removable, and may be volatile or non-volatile) may be configured in embodiments to form the configured medium using items such as an execution controller 402, a playback adapter 408, an instruction set 822, a cross-level mapping 404, machine-level requests 414 and responses 416, and a breakpoint range 830, in the form of data 118 and instructions 116 read from the removable medium 114 and/or another source such as a network connection. As disclosed herein, the configured medium 112 is capable of causing a computer system to perform technical processing steps for horizontal cross-level (high-level in tool 122 to low-level in trace 418) playback execution control. Therefore, the accompanying drawings help illustrate the configured storage medium embodiments and process embodiments, as well as system and process embodiments. In particular, Figures 4, 13, or 14, or any other processing steps taught herein, can be used to help configure the storage medium to form the configured medium embodiment.
Some embodiments use or provide computer-readable storage media 112, 114 configured with code that, when executed by computer processor 110, performs a trace replay execution control method. In this example, the trace replay execution control method includes receiving a trace replay execution control request 1304 from a software tool running on a computing system. The method includes mapping 1306 between the source code of the traced managed program and an intermediate representation of the source code, and mapping 1308 between the intermediate representation and a trace 418, based on the trace replay execution control request. The trace 418 includes a record of processor activity, such as native code instructions traced when the traced managed program is executed, since the trace does not include any execution instances at runtime. In this example, the trace replay execution control method also includes executing 1312 trace native code instructions or other trace entries corresponding to the trace replay execution control request, or setting a breakpoint 1314 on the trace native code instructions to control the replay of traces traced by 1310.
Some embodiments operate in combination with debugger 200, and in some of these cases, the traced managed program includes a real-time process and an execution runtime 204. Without terminating the traced managed program at 1416, debugger 200 communicates with the execution runtime 204 of the traced managed program, and the method uses trace 418 to control 1310 to perform a backward replay. That is, in this example, reverse debugging is intertwined with real-time process debugging.
Some embodiments perform one, two, three, or all four of the following activities of particular interest. One particularly interesting activity is the execution of 204 at high-level control 1420 using machine-level information from trace 418. In this context, "high-level" control refers to control based on user selection 1426 (obtained from user 104 via a user interface) that specifies an identifier or statement or expression in the source code. In this context, "machine-level" information refers to processor architecture-specific information, such as a particular instruction set or a particular microarchitecture.
Another particularly interesting activity is the forward and backward execution of both the real-time debug objects 202 and 802 of the managed program being debugged by debug 200.
Another particularly interesting activity is stepping into the call shown in the source code, at least in part, by setting a large breakpoint range of 1434 to 1436. In this case, the breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in tracing 418.
Another particularly interesting activity is to simultaneously debug the real-time debug object 202 of the managed program being debugged (200), trace 418 trace data from the real-time process, and then use at least some of the trace data recorded to perform reverse execution debugging on the real-time process.
Those skilled in the art will understand that other configurations of media embodiments are also within the scope of the teachings of this invention. In particular, some other embodiments may include statutory media configured with code for performing cross-level mapping 404 at execution time, using breakpoint range 830, and implementing other teachings provided herein, while departing from the specific examples described herein. Media configured to perform methods using any execution control teachings taught herein are within the scope of this disclosure, regardless of whether they are in the specific examples provided.
Example with JIT code
Assume the source code includes classes similar to those in C#, as shown below:
If the language is C++, the developer would reasonably expect that the call to WiggleLeg() in Squid.Swim() can be compiled into the following form (similar to assembly code):
CALL 0x0c84fabd; 0x0c84fabd is the address of Squid::WiggleLeg().
In this scenario, 0x0c84fabd would begin implementing Squid::WiggleLeg(). However, this is not the case in managed software executed in runtime 204. Code executed in runtime 204 is compiled "just-in-time," also known as "jit." If this is the first call to Squid::WiggleLeg(), there will be no machine instruction 116 for Squid::WiggleLeg(). It has not yet been compiled. Therefore, instead of having the machine instruction implement Squid::WiggleLeg(), 0x0c84fabd would have some instructions that look something like this (in pseudocode):
This point in the code is called a "stub". The compilation process is lengthy and complex, so developers who typically try to analyze or debug their applications by tracing them often don't want to document the compilation process in detail. However, trace 418 may record at least a portion of the stub, even if the traced instructions are unlikely to be of interest to those debugging the code. In real-time process debugging, the runtime typically skips this part of the code. However, when debugging only from trace 418, the runtime 204 of the debugged object is not executed, so the stub cannot be skipped. Instead, one embodiment can leverage the functionality of an out-of-process debugging utility typically used to read data from dump file 302, and an innovative trace replay functionality that can be used together to find the address range of all JITTED code at runtime. Upon receiving a request to step into a method call, one embodiment can temporarily set a breakpoint 1314 on the JITTED code range and virtually execute forward (i.e., replay forward) until the first JITTED code range is read. Once read, the embodiment can remove the breakpoint. In this way, developers can skip all these uninteresting "stubs" of code. Some implementations further optimize the method by targeting the address range of the breakpoints to be limited to the range of `Squid::WiggleLeg_implementation`.
Some additional combinations and variations
Any combination of these combinations of code, data structures, logic, components, communications, and/or their functional equivalents may also be combined with any of the systems and their variants described above. A process may include any step described herein in any operable subset or combination or sequence. Each variant may appear alone or in combination with any one or more other variants. Each variant may appear with any process, and each process may be combined with any one or more other processes. Each process or combination of processes (including variants) may be combined with any of the media combinations and variants described above.
In some embodiments, the trace replay component uses source-IL mapping and IL-machine mapping to convert between the location in trace file 420 (e.g., indicated by timecode 424) and the location in source code 212 (e.g., indicated by line number).
In some embodiments, a portion of runtime functionality is provided in the trace replay component 406. However, instead of mediating between the debugger, user code, and operating system as in the real-time process of Figure 2, the runtime functionality mediates between the debugger and trace(s)420.
Some trace recording processes record only two types of data. One type of data is the execution of code instructions 116, which may be executed in parallel on multiple threads. The other type of data is a snapshot 304 of a specific block of memory taken at discrete points in execution time, such as to capture a portion of the stack. However, other trace processes record different or additional types of data, as shown in Figure 4. In some cases, the trace contains a valid representation of all recorded instructions and all their inputs and outputs. The recording of trace 418 can be made efficient by relying on the determinism of processor(s) 110 and primarily recording information that cannot be inferred from that determinism, as well as information already recorded in trace 418. In some implementations, most of trace 418 is data, rather than the executed code instructions; such data is often indeterminate. The trace can be primarily seed data plus indeterminate information. In some cases, only information entering the cache of the traced processor(s) is recorded in trace 418; for example, reading the value V into the processor cache is input into the trace, but writing the value V from a processor register to memory location X is not necessarily input into the trace. If a write operation to X behaves differently in terms of the traced program, it is because at some point the written value is returned from X to the processor register, at which point, if tracing is still enabled, the entry in trace 418 can be executed.
This document describes the execution control of a high-level program derived from a process tracing using examples, illustrations, definitions, and other descriptive materials. Technicians will recognize that process traces can be created at the machine level using various techniques, such as Windows Event Tracing (ETW) or "Time Travel Tracing" for systems running Microsoft environments, tracing for runtime environments (trademarks of Efficios, Inc. and Linus Torvalds, respectively), tracing for similar environments (trademarks of Oracle Corporation and X/Open, Inc., respectively), and other tracing techniques. The trace can then be replayed using hardware emulation. Sometimes, the process is written in a high-level language that requires a runtime framework to actually execute the process. One example is a .NET application running in the Common Language Runtime (CLR). Moving forward or backward in a trace is not helpful in itself to developers of high-level programs because the view of the trace is a view of the runtime or just-in-time compiled code, not a view of the high-level program. This document describes a method for mapping machine-level instructions in a trace to high-level operations in the program. This allows for setting and reaching breakpoints, as well as forward and backward stepping in high-level languages.
The process of stepping through the code at a high-level runtime can be achieved by abstracting the complexity into three layers. At the lowest level (level 0) is the process trace 418. This trace contains enough information to allow the recorded process execution to be simulated at the hardware level.
At level 1, a properly configured system can apply some very basic hardware debugging support for replaying traces. This support may include: the ability to play the process forward or backward, read the process memory, read the thread context (for each thread), set hardware breakpoints, and single-step machine instructions for each thread.
At level 2, support is provided for mapping the range of machine instructions to the range of higher-level virtual machine (VM) instructions or another type of code. Operations in level 1 can be used to debug higher-level code. In some configurations, the operations to be supported are forward, backward, setting breakpoints, stepping in, stepping out, and stepping skipping. Details of the implementation for each operation are given below in the examples.
Regarding forward and backward execution, in this example, they are equivalent in high-level and machine-level execution, so this is handled entirely at level 1.
Regarding breakpoints, in this example, breakpoints are set using a mapping defined in layer 2 to map higher-level breakpoints to hardware breakpoints. When a hardware breakpoint is encountered, the implementation can use this mapping to map that hardware breakpoint back to a higher-level breakpoint.
Regarding forward and reverse stepping exits, a hardware breakpoint can be set at the function's return address using stack tracing. To implement reverse stepping exit, the breakpoint is set on the instruction preceding the return address.
Regarding forward and backward step skipping, step skipping can be achieved by looking at the next instruction to be executed. Depending on the instruction, the implementation can use Level 1 to either perform single-stepping or set a breakpoint and run until it is reached. The "call" instruction is an example of an instruction that requires a breakpoint. Most other instructions can use single-stepping. Unlike some familiar approaches, this example debugger implementation can use mappings in Level 2 to repeat the stepping operation until the instruction pointer or code execution time point is at the appropriate stop point in the higher-level runtime. This inspires the discussion of instruction group 822 elsewhere in this paper.
Regarding reverse step-in, to perform reverse step-in, this implementation uses the single-step operation defined in Layer 1. If the machine has just returned from the calling instruction, this usage will return the execution time point to the return instruction of the previous call. If the machine has not just returned from the call, the machine will simply backtrack to the previous instruction. Similar to step-skip, the implementation can use the mapping in Layer 2 to know when execution is at a stop point, and may need to perform single-steps several times to align the trace with the source code 1318.
Regarding forward stepping, in this implementation, forward stepping is similar to reverse stepping. However, difficulties can arise if the higher-level runtime needs to perform work that is not directly related to the running higher-level code. Some examples are just-in-time (JIT) compilation, runtime housekeeping, and stepping operations that require some form of runtime resolution (transparent proxies in .NET are an example of this challenge). These difficulties can be addressed by implementing any or all of the following: One option is to set a large breakpoint range for all JIT-compiled code at the start of stepping. If the breakpoint is encountered after stepping, the implementation can complete the step when the next stopping point is reached. Another option is to implement logic in the stepping engine that fully understands the runtime, knowing when to skip calls and when to single-step through calls, allowing the implementation to stop stepping at appropriate points in the higher-level runtime.
In some embodiments, out-of-process execution control controls the execution of IL instructions by using, for example, the functionality provided by replay component 406 and IL-to-address mapping 812. The functionality provided by replay component 406 or other execution controllers 402, 408 for execution control includes:
Get the status (register values) of all threads.
Step forward or backward by one instruction
Run forward or backward until the instruction pointer reaches the specified address set.
The IL-to-address mapping exists in the memory image of the process or trace, and the replay layer can provide it to an off-process execution control debugger. One perspective suggests that this example involves converting IL-level debugging into machine-level debugging.
By stepping individual instructions, or by running forward and backward in the trace until a specific instruction address is reached, some implementations support the application of high-level execution control to the trace using source-to-IL mapping 810, IL-to-native mapping 812, native-style out-of-process execution control, and the ability to run forward and backward in the trace 418.
Consider examples of real-time process debugging.
As a further illustration of trace-based execution control, consider that certain embodiments may resemble or differ from real-time debugging. Several components are referenced below, and those skilled in the art will understand their relationship to other examples provided herein, and in particular, that functionality may be grouped into different components for ease of understanding or implementation without departing from the execution control teachings provided herein. The system 800 components discussed in this example include:
User Interface (UI). The user interface graphically displays a representation of the debugger's program state to the user. Examples of program state include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, the set of variables in each frame of the call stack, and the values of these variables.
Source translation. This part of the code translation is responsible for translating between runtime abstractions and source code-level abstractions. For example, the CLR runtime uses IL instructions encoded in binary file format to represent code, while C# source code has the syntax of text statements. As an example, this layer of the debugger can translate between runtime abstraction layers (e.g., those defined in ECMA-335, Common Language Architecture (CLI) version 6 (June 2012) or later) and C# abstraction layers (e.g., those defined in C# language specification version 5.0 or later).
Runtime translation. The runtime translation section of the debugger is responsible for translating between low-level concepts (such as memory and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, a call stack for each thread, and the IL instructions to be executed next. Note that the call stack at the abstract runtime layer does not have to be the same as the call stack at the abstract source code level. Only in the case of real-time debugging, this layer uses inter-procedural communication mechanisms to request the runtime within the process being debugged to perform work in order to assist with certain tasks. For example, to set a breakpoint at an IL instruction in method Foo at offset 28, this layer sends a message to the runtime requesting it to set the breakpoint at offset 28 of Foo. The thread within the runtime then receives the message, translates the Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. It is reasonable to consider the part of the runtime that serves those requests as functionally located within this layer of the debugger, even if it is implemented in a different process.
The basics. The low-level parts of the debugger are responsible for using the kernel, dump files, or traces to generate memory and registers that will be read by the runtime translation section. For kernel procedures, this is implemented in some environments via APIs such as ReadProcessMemory. For trace files, it supports parsing the file and establishing a mapping between time t and a set of memory and register contents recorded at that time.
Considering these components, consider the scenario where a breakpoint is set and the program is executed forward until the breakpoint is reached. One perspective suggests that real-time process debugging generally involves the following actions.
Action 1. User Interface. The user clicks the mouse on the displayed source code line to indicate where a breakpoint should be set.
Action 2. Source Transformation. Source code lines are transformed into specific method and IL instruction offsets.
Action 3. Runtime Translation. The message is sent to the runtime, where the method + IL instruction offset is translated into a memory address. Then, the breakpoint opcode is written to that address.
Action 4. User Interface. Users click buttons in the UI to indicate whether they want the process to run.
Action 5. Source Transformation. Forward the request to be executed.
Action 6. Runtime Translation. A message is sent to runtime 204, requesting it to proceed forward. Upon receiving the message, the runtime proceeds forward and then reaches the breakpoint at the previously set specific memory address. The breakpoint's memory address is translated back to the method and IL offset, and a notification message is then sent back to the debugger, indicating that the breakpoint at the specific method/IL offset has been reached.
Action 7. Source Transformation. The message indicating that the breakpoint has been reached is transformed from the method and IL offset back to the source line, and notifications about the breakpoint being reached at that source line continue to be sent to the UI.
Action 8. User Interface. The UI requests additional information about the new state of the process, allowing it to display current state information to the user, such as the current call stack for each thread.
Action 9. Source Transformation. To provide a source abstraction of the call stack, this component first requests a runtime abstraction that receives the call stack.
Action 10. Runtime Transition. To provide a runtime abstraction of the call stack, this component first requests to receive the state of memory and registers.
Action 11. Basics. Determine the memory and registers at the current time.
Action 12. Runtime Transformation. Using memory and registers, compute the runtime abstraction of the call stack.
Action 13. Source Transformation. Calculate the source code abstraction of the call stack using the runtime abstraction of the call stack.
Action 14. User Interface. Using the source code abstraction of the call stack, the UI can now display the current state of the process being debugged to the user.
In some embodiments, when using tracing actions 3, 6, and 11, the operation is no longer the same. For actions 3 and 6, no procedure can receive messages to set breakpoints, to advance execution, or to send back notifications when a breakpoint is reached. For action 11, no procedure can use the kernel API to query and determine memory or registers.
Therefore, in some embodiments, in order to achieve action 3 above, the source translation code requires the runtime translation code to indicate which memory address X has machine code for a given method + IL offset where a breakpoint should be set. This address X is saved for later use.
To achieve action 6 above, in some embodiments, the source translation code directly instructs the low-level base of the debugger or (multiple) other tools to advance the tracing to a new time t', where t' is the next time point where the machine instruction at address X will be simulated or emulated for execution. For action 6, one embodiment can use the same procedure typically used in dump debugging to translate from an IL offset to a procedure memory offset. However, this embodiment uses the translated memory offset to set a virtual breakpoint within the tracing replay engine. The virtual procedure (replay execution) stops when the replay engine reads this memory address during virtual execution. Indeed, if the tracing contains more than one version of the same functionality (via re-jitted), the runtime translation may require the tracing to provide multiple addresses to cover a single breakpoint. This address can be different for different time ranges in the tracing, or it can be the address of a runtime function (such as a jittering function) so that the runtime translation can locate the new re-jitted position of the function.
To achieve the above action 11, instead of reading from the real-time process, trace 418 is read and memory and registers corresponding to time t' are provided.
Replay debugging scene
By providing access to both forward and backward execution during debugging, system 800 can enhance debugging efficiency. For example, some embodiments support the following debugging scenarios.
By using context, technicians will realize that production debugging is difficult. Suppose a customer reports an issue on the website. How do developers debug it? Some familiar methods rely on information such as logs and dumps, which only provide point-in-time information. Therefore, if the problem doesn't reproduce or occur at the specific moment captured in the logs or dumps, developers must try again to capture useful information at different points in the execution, meaning it takes much longer to resolve the issue.
Instead, imagine an environment that can tell developers exactly what's happening in a production application, line by line. Using Microsoft Time Travel debugging or other reverse-execution replay implementations allows team members to collect a high-fidelity record of the application's behavior. Developers can then debug the application offline in a familiar environment, such as a Microsoft environment or other debugging or IDE.
As a concrete example, suppose the SmartHotels360 website is experiencing an issue; this is a demo website whose code is publicly available from Microsoft via GitHub.com. The developers of the company running the SmartHotels360 website receive a report from users indicating that a feature in BestHotels is no longer displaying data. However, it was working perfectly before, and the issue has not been reproduced in the company's test or staging environments. Members of the operations or engineering team have collected logs (trace 418) of the application while running the code powering the malfunctioning feature. Trace 418 can be collected into file 420 via command-line tools, or automatically triggered by a cloud environment (or another cloud environment) when certain conditions are met, such as throwing more exceptions than expected.
The developer opens the debugger and loads the SmartHotels360 code and trace file 420. Execution stops at a breakpoint on line 28 in the API that returns to BestHotels. Now, even though this is a log file, in this example, the developer can use many familiar commands to navigate it using a debugger they are typically familiar with. The developer wants to know what happened when the API was called. The developer steps over lines 28 and 29 and sees from the Locals window that after stepping over line 29, bestHotels has zero entries. If the debugger supports data hints, the developer can also view them, at least in this example.
Now, the developer has identified the cause of the problem in the `BestHotels()` routine. Therefore, the developer wants to investigate what happened in `BestHotels()`. Alternatively, to see what happened back to the original call, the developer could click Continue, click the breakpoint again, and step into the next call to `BestHotels()`, even though the values, objects, and memory addresses might differ from the partially debugged call. Alternatively, when the debugger state is difficult to reproduce, the developer could restart the application, which could be time-consuming. However, in this example, the environment supports time-travel debugging. Therefore, the developer uses the Reverse Continue button (requesting to continue backwards 920 operations) to rewind the application to the state of the previous breakpoint. One result of this rewind is that the locale will be reset to its previous state at line 28 before the aforementioned stepping is performed. Now, by ensuring that all values, objects, and memory addresses from the partially debugged call are the same, the developer can skip the `Load()` routine and step into `BestHotels()`.
At this point, the developer decides to step through `BestHotels()` and delve deeper into `GetBestHotels()`. Therefore, the developer wants to skip line 36 and then step into line 37. Suppose the developer accidentally pressed the skip button multiple times. Through time travel debugging, the developer can quickly go back and see what happened in `GetBestHotels()`. In fact, the developer can use the backstep button (requesting to step back into operation 914), which will take execution into `GetBestHotels()` and play it backward. The developer discovers that at the end of `GetBestHotels()`, the value of the local variable `bestHotels` (corresponding to the count) is zero. Clearly, all levels were filtered out.
Therefore, the developers decided to test the assumption by checking the ratings of all hotels. Remember, this trace occurred in production, so these values are actual. The developers can evaluate the expression using the debugger's live window, which is possible through the live debugging process. The developers evaluated the expression "AllHotels.Select(h => h.rating)" in the debugger's live window and found that the ratings were floating-point numbers, while the code was checking for rating values equal to integers 4 or 5. There was a data type mismatch; the shape of the data in production did not match the application's expectations.
Now suppose the developer has completed the debugging described above and wants to discuss it with a colleague and show them in detail what happened. The developer wants to start over at the beginning of the investigation and wants a way to quickly return to a specific point of interest. Therefore, the developer sets a breakpoint on line 21 and then rewinds to that breakpoint. Replaying then allows the developer to reproduce the debugging steps. If the developer wants to jump to the end, they can continue until they reach the last breakpoint they set.
In short, developers can use the application's high-fidelity tracing 418 to quickly debug issues, capturing what actually happened in production. With the power of a debugger adapted to the replay described here, developers can debug using a familiar debugger user interface and can debug forward and backward, saving significant developer time.
in conclusion
Although specific embodiments are explicitly shown and described herein as processes, configured media, or systems, it should be understood that the discussion of one type of embodiment generally extends to several other types of embodiments. For example, the process descriptions taken in conjunction with Figures 13 and 14 also help to describe the configured media and to describe the technical effects and operation of those similar systems and manufactures discussed in conjunction with the other figures. It is not necessarily required that limitations from one embodiment be read into another. In particular, processes are not necessarily limited to the data structures and arrangements presented when discussing systems or manufactures such as configured memory.
Those skilled in the art will understand that implementation details may relate to specific code, such as a specific API, a specific domain, and a specific sample program, and therefore may not necessarily appear in every embodiment. Those skilled in the art will also understand that program identifiers and some other terms used in discussing details are implementation-specific and therefore not necessarily related to every embodiment. Nevertheless, while their presence is not necessarily required herein, such details can assist some readers by providing context and/or can illustrate some of the many possible implementations of the techniques discussed herein.
References herein to an embodiment having some feature X, and references elsewhere herein to an embodiment having some feature Y, do not exclude embodiments having both feature X and feature Y, unless such exclusion is expressly indicated herein. All possible limitations of the claims are within the scope of this disclosure, as any feature that is prescribed as part of an embodiment may be expressly removed from some other embodiment, even if no specific exclusion is given in any example herein. The term “embodiment” is used herein only as a more convenient form of “process, system, article of manufacture, computer-readable medium of configuration and/or other example of the teachings herein applied in a manner consistent with applicable law.” Therefore, a given “embodiment” may include any combination of features disclosed herein, provided that the embodiment is consistent with at least one claim.
In each embodiment, not every item shown in the figures must be presented. Instead, an embodiment may include items not explicitly shown in the figures. Although some possibilities are illustrated herein by way of specific examples in the text and figures, embodiments may deviate from these examples. For example, specific technical effects or features of an example may be omitted, renamed, grouped differently, repeated, instantiated differently in hardware and/or software, or a mixture of effects or features appearing in two or more examples. In some embodiments, functionality shown in one location may also be provided in different locations; for example, those skilled in the art will recognize that functional modules can be defined in various ways in a given implementation without having to omit the desired technical effects from a collection of interactive modules considered as a whole.
The figures are referenced throughout the text using reference numerals. Any apparent inconsistencies in the wording related to a given figure reference in the figures or text should be understood as simply broadening the scope of the number referred to. Even when using the same figure reference, different instances of a given figure reference may refer to different embodiments. Similarly, given figure references...
It can be used to refer to verbs, nouns, and/or corresponding instances of each, for example, processor 110.
Instruction 110 can be processed by executing instructions.
As used herein, terms such as “an” and “the” include one or more of the indicated item or step. In particular, in the claims, a reference to an item generally means that there is at least one such item, while a reference to a step indicates at least one instance of performing that step.
The headings are for convenience only; information about a given topic can be found outside of the sections that indicate the subject in the headings.
All claims and abstracts submitted are part of the specification.
Although exemplary embodiments have been shown in the accompanying drawings and described above, it will be apparent to those skilled in the art that various modifications may be made without departing from the principles and concepts set forth in the claims, and such modifications do not necessarily encompass the entire abstract concept. Although the subject matter has been described in language specific to structural features and/or procedural actions, it should be understood that the subject matter defined in the appended claims is not necessarily limited to the specific technical features or actions described in the claims. Each means or aspect or technical effect identified in a given definition or example need not be presented or utilized in every embodiment. Rather, the specific features, actions, and effects described are disclosed as examples for consideration in implementing the claims.
To the maximum extent permitted by law, all changes that fall within the entire abstract concept but fall within the equivalent meaning and scope of the claims should be included within its scope.
Technical Field
Embodiments of this disclosure relate to execution control with cross-level tracking mapping.
Background Technology
Computer software is typically complex. Part of this complexity may stem from the nature of the work a program is designed to perform—for example, tracking a large number of real-world items or ongoing transactions over hours or longer, coordinating activities with other complex software, controlling complex hardware, and so on. Complexity also arises in almost any real-world use of software because many details are introduced and must be properly managed to instruct the computer hardware how to perform real-world work that would have been far less precise when initially described in English or another natural language. In other words, the conversion from a high-level description to a low-level implementation executable by a computer system inevitably introduces complexity. Even the source code of programming languages, which are more precise than natural languages, remains at a relatively high level and is therefore ambiguous, open to various interpretations and implementations. As the source code is translated into low-level instructions directly executable by computing hardware, many details are introduced and choices are made during the translation process.
Complexity introduces the possibility of commonly recognized programming errors (also known as "defects" or bugs). The process of identifying the cause of a defect and attempting to modify the program to remedy or remove its effects is called "debugging." Specialized software tools that assist in debugging are called "debuggers." The program being debugged is called a "debugging object."
Debugging is often easiest when developers can run a debug object at will, either slowly or at full speed, or pause its execution at will, and can inspect all its state information at any point during its execution. This is known as "real-time process debugging." However, such complete access to a debug object is often unavailable. For example, a debug object might be production software, which cannot be debugged in real-time without violating service agreements or harming the reputation, security, or financial condition of stakeholders. Pausing a real-time process debug object for even a few seconds at a time while a developer examines variable values, checks which functions are called with which parameter values, reviews source code, considers possible interpretations of defects, and designs tests that might help identify, remedy, or eliminate defects could cause unacceptable harm.
Therefore, state information is sometimes logged while the debug object is executing so that it can be examined later without essentially pausing the debug object's execution. Creating such a log may slow down the debug object, but it can provide useful information without compromising production performance goals as much as real-time debugging. For example, the debug object can be paused long enough to create a memory dump that copies some or all memory values associated with the debugger to disk at a specific point in time. Some aspects of the debug object's execution can also be logged in an execution trace. In cases where the debug object is not a real-time process, some debuggers support using such a trace to replay the traced execution of the debug object. Some debuggers allow the debug object's execution to be replayed forward or backward, enabling "time travel," "reverse," or "historical" debugging.
However, because execution traces may contain less information than is sometimes available during real-time process debugging, and because they record state information at a low level, technical challenges arise when debuggers or other software tools attempt to control replay execution (i.e., execution based on the recorded trace). Depending on the implementation, execution control operations that developers are familiar with and frequently use during real-time debugging may be less accurate or simply unavailable when attempted during trace-based replay.
Therefore, advancements in using low-level execution tracing to effectively and accurately achieve high-level execution control through debuggers or other replay or logging tools can help improve the information available to developers or automated performance monitoring tools. Consequently, such advancements will tend to improve the functionality of computer systems by supporting a more accurate understanding of their behavior and by enabling the mitigation or elimination of system defects.
Summary of the Invention
Some of the techniques described herein involve mapping locations in the program's source code to corresponding locations in the program's execution tracing, thereby improving the accuracy of execution control in tracing-based debugging. Some teachings involve specific breakpoint setting procedures that set one or more breakpoints at locations aligned with source code expressions or statements. Technical mechanisms for adapting to real-time debugging environments to support tracing-based reverse execution are described. Specific technical tools and techniques are described herein in response to the challenges of replaying debug object execution forward or backward or both forward and backward based on execution tracing. Other technical activities related to the teachings herein will also become apparent to those skilled in the art.
Some embodiments described herein use or provide trace replay execution control capabilities that utilize a processor, memory, traces recorded during the execution of a program at runtime, program source code, mappings between source code and its intermediate representations and traces, and an execution controller in a debugger or other tool. The runtime contains supporting code that provides dynamic compilation or memory garbage collection services as the traced program is executed and the trace is captured. A trace may include a record of native code instructions executed by the program. A trace may include a record of data accessed during program execution while the debug object is being executed. A trace may include one or more memory dumps or snapshots. A trace may be stored in one or more files or portions of non-volatile or volatile memory. The execution controller is configured to control the replay execution of the trace in response to a request from a tool. During replay, breakpoints configured to help align grouped native instructions with their corresponding source code entries are used, with the source code and trace native code instructions or other trace entries associated through source intermediate mappings and intermediate native mappings.
Some embodiments described herein use or perform computer-implemented trace replay execution control. The managed program being traced is identified. A managed program (also called a “runtime management” program) is a program configured to execute in conjunction with calls to the runtime. The managed program being traced is a program that is being traced or configured to be traced. A trace replay execution control request is received in a software tool. Based on the trace replay execution control request, a mapping is made between the source code of the managed program being traced and an intermediate representation of that source code, and another mapping is made between that intermediate representation and the trace. The trace does not include any execution instances of the runtime. Replay of the trace can be controlled by, for example, simulating the trace activity in a direction and number corresponding to the trace replay execution control request (e.g., taking a step forward, or repeating the entire routine by stepping over it), or by setting breakpoints at the trace locations, or by performing both of the above.
The examples given are merely illustrative. This "Summary" is not intended to identify key or essential features of the claimed subject matter, nor is it intended to limit the scope of the claimed subject matter. Rather, this "Summary" is provided to introduce some technical concepts in a simplified form, which will be further described in the "Detailed Description" below. The invention is defined by the claims, and in the event of any conflict between the Summary and the claims, the claims shall prevail.
Attached Figure Description
A more specific description will be given with reference to the accompanying drawings. These drawings are only illustrative of selected aspects and therefore cannot fully define the coverage or scope. Although dashed lines indicate that some items are optional, any item recited in the claims or any item that a person skilled in the art would consider non-optional for embodying the claims should be understood to be present in some form in an embodiment of the claims.
Figure 1 is a block diagram showing a computer system and also showing the configured storage media;
Figure 2 is a block diagram illustrating aspects of real-time process debugging;
Figure 3 is a block diagram illustrating aspects of debugging based on a copy of the memory made at a single point in time;
Figure 4 is a block diagram illustrating aspects of an example architecture for trace-based debugging, including the main request and response between the debugger and the replay adapter;
Figure 5 is a block diagram showing various memory cells that can be referenced during debugging or in tracing;
Figure 6 is a block diagram illustrating a machine-level request that can seek information from the execution trace or impose execution control during the replay of the execution trace.
Figure 7 is a block diagram illustrating the response to a machine-level request;
Figure 8 is a block diagram illustrating an example tracking replay execution control system;
Figure 9 is a block diagram illustrating some of the control operations performed during the tracking and replay process;
Figure 10 is a block diagram illustrating some aspects of thread tracing data;
Figure 11 is a block diagram illustrating some aspects of one or more intermediate representations;
Figure 12 is a block diagram illustrating some aspects of a real-time process debugging environment adapted to use traces that support reverse execution debugging;
Figure 13 is a flowchart illustrating an example trace replay execution control method; and
Figure 14 is a flowchart further illustrating some of the tracking replay execution control methods.
Detailed Implementation
Overview
Debugging in a production cloud environment presents significant technical challenges. For example, suppose a specific request R for an online shopping cart is not working. How can developers debug the processing of request R without slowing down the processing of all other requests and minimizing the slowdown in the processing of request R? To find the defect, developers use information about what is happening internally in the code, such as a way to look at the values of variables at one or more points of interest during the processing of request R.
The trace-based debugging innovations discussed here help overcome technical challenges that traditional methods cannot solve. For example, many traditional debuggers and debugging methods allow developers to set halt breakpoints to obtain information about variable values. A halt breakpoint is an instruction to pause execution, giving developers time to examine memory contents at a given point in processing and consider possible interpretations of what is observed. However, in a production environment, halt breakpoints may pause the processing of a large number of requests, cause requests to fail completely (e.g., timeout), or cause execution to take a different path—none of which are desirable. Even pausing only a single thread can lead to unwanted aborted requests and produce unpredictable side effects that hinder debugging, degrade performance, or both.
Some familiar debugging methods involve adding print statements at specific points in the code to print the value of a particular variable, or adding other code, for example, to test the value of a variable to see if it is the value the developer expected at that point in the code. However, these methods may require recompiling and redeploying the code, which is undesirable in production environments, especially if recompiling and redeploying are to be done multiple times as part of an iterative debugging process to find and fix individual defects.
Developers can inject operations into request handling code at execution time to create a copy of some or all of the memory relevant to the request. This copy can include a "snapshot" 304 (an in-memory copy of a process that shares memory allocation pages with the original process via copy-on-write) or a "dump" file 302 (a serialized copy of the process), or both. Some traditional debuggers can read dump files or snapshots and, given appropriate metadata, present the memory contents in a specific format that shows variable values converted from binary to an informative structure including variable names and displayed based on the variable's corresponding data type. However, dumping memory to a file is time-consuming, slowing down not only request R but also the processing of all requests in the example scenario. While taking a snapshot is much faster than creating a dump file, it can require many attempts by the developer to find useful points in the processing to obtain a memory snapshot that reveals the defect, and snapshots consume space in RAM. To view memory at another point in time other than execution time, captured in a dump file or snapshot, another copy of the memory can be created.
Real-time processes are used to view memory at any point in time during the real-time process. In many modern computing systems, as illustrated in the example in Figure 2, the real-time debug object 202, in addition to depending on the operating system, also includes a runtime 204. The runtime 204 provides garbage collection or dynamic code compilation (i.e., JIT compilation or compilation of intermediate language code) or both. Garbage collection may utilize object reachability analysis, object reference counting, or other strategies. Some configurations include an interpreted runtime 204, and those skilled in the art will recognize that the teachings herein can be applied to exercise execution control over the interpreted runtime by overlaying the interpreter's view onto the native trace and using breakpoints within the interpreter itself. Additionally, some runtimes (e.g., runtimes) do not always JIT compile their IL representation (what Java terminology calls "bytecode"). Instead, the runtime may choose to interpret bytecode for less frequently used functions. In this case, execution control may be exercised over the runtime code itself, and a mapping may be made from native code to internal runtime data structures to IL to source code. The mapping from native code to internal runtime data structures to IL can be considered an example of an intermediate native mapping 812, and the mapping from IL to source code can be considered an example of a source intermediate mapping 810.
Unlike processes lacking runtime capabilities, which can be directly controlled by the debugger through the insertion of pause breakpoints, runtime-dependent processes cannot be directly controlled by the debugger 200 because their runtime is effectively hidden from the debugger's memory entries 206, such as memory locations, memory contents, and instruction pointers. To show the developer what is in memory during debugging, the debugger sends a main request 214 to the runtime requesting the current memory values. The runtime sends these values back to the debugger in a main response 216, and the debugger displays the values it received in the response message in a user interface 210.
As a specific example of the drawbacks of the previous approach, consider runtime 204, which is implemented as a virtual machine executing intermediate language (IL). IL code cannot be easily debugged using a traditional native code debugger because that debugger is intended for debugging the virtual machine/runtime, not the IL code.
The runtime also controls the execution of the real-time debug object. Traditional debuggers for IL or languages that compile to IL work by establishing a communication channel between the debugger and the runtime inside the debug object. The runtime within the debug object performs most of the work required to provide the debugging experience. In one example, to set a breakpoint at offset 28 in the intermediate language (IL) instruction in method Foo, a message is sent to the runtime requesting it to set the breakpoint at offset 28 in Foo. The thread within the runtime then receives the message, translates Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. Similarly, to perform familiar execution control operations, such as stepping, stepping in, stepping out, and stepping skipping, the debugger sends a main request 214 to the runtime requesting the operation. The runtime 204 performs the operation and sends an updated status to the debugger in a main response 216, and the debugger displays the result indicated in the response message in a user interface 210.
User interface 210 graphically displays to the user a representation of the debugger's debug object program state. Examples of program states include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, a set of variables in each frame of the call stack, and the values of these variables. The user interface may include windows displaying local data of the routine, watched variables and their values, source code, expression evaluators, and other information about the live debug object 202.
In some implementations, the runtime translation section of debugger 200 is responsible for translating between low-level concepts (such as memory units and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, one or more call stacks for each thread, and the IL instructions to be executed next. Note that the call stack of the abstract runtime layer is not necessarily the same as the call stack at the abstract source code level; for example, the virtual machine's call stack may not match the virtual call stack of the IL code being executed within the virtual machine.
Creating an execution trace 418 of the process is possible. The trace can then be replayed using a simulation of the computer system 102. Sometimes, the trace process is written in source code 212, a high-level language that needs to be executed by the runtime 204 in real-time debugging object 202. The trace itself can be difficult to debug because the trace data reflects a view at a low level (e.g., runtime or just-in-time compiled code or both), rather than the high-level language in which the program was written. Some tracing techniques do not provide a high-level view of the process that the user 104 might prefer. Most high-level runtimes require the runtime itself to provide information about the program running within its framework. Therefore, regular debugging may require the process to be executed within the runtime, which is not optional when debugging is based on a trace rather than a real-time process.
Like any other process, runtime can be traced. However, debugging software other than runtime is more common than debugging runtime. The tracing process can include or exclude tracing some or all of the code that is part of the runtime itself.
This functionality does not apply to situations where there is no trace file currently running. To control the execution of a live process that is executing code that depends on a runtime 204 error, the debugger can send a message to the runtime requesting an action such as "step" or "run," which the runtime then performs on behalf of the debugger.
The ability for a debugger to send messages to the runtime to perform actions on behalf of the debugger does not apply to trace files for which there is no currently executing runtime. Dump files 302 and snapshots 304 are similar to traces in that the runtime is unavailable. A runtime can be represented as a dump, snapshot, or trace, but it is not currently executing and therefore cannot be invoked in the traditional way.
Nevertheless, the trace file 420 can be made part of the debugging environment. Some trace-based debugging embodiments discussed here extend debugging power, allowing the debugger to replay execution from the trace file, starting from one or more points in execution time chosen by the developer, and then moving forward or backward in increments chosen by the developer within the trace execution. One approach is to insert a replay layer between the trace and a high-level language debugger. The replay layer understands runtime execution control messages, thereby allowing high-level control over the traced process.
In some cases, developers can use a "time travel" debugger to control execution replay, running forward or backward in execution time as the recorded trace 418 is replayed. This leverages the debugger's ability to present program state information and memory, such as instruction pointers (multiple), in useful high-level (e.g., named and data-data-based) variable representations, not only for snapshots as before but now for continuous replays of segments of execution time recorded during code execution. Debugging can be made more efficient by aligning grouped trace data with corresponding source code structures (such as expressions and statements). Developers can examine memory values captured in the trace at multiple points in a high-level representation based on the low-level data recorded in the trace file.
As the trace is replayed, the included replay layer can be used to control the state of the debug object. With this adaptation, debugger 200 can apply a runtime (high-level) view of the process trace that has been recorded as machine-level operations. For the purposes of this application only, "machine-level" operations are operations specified at the machine-specific level. Generally, "native" and "machine-level" are used interchangeably herein relative to instructions or code.
Some may view some of the embodiments described herein in a broader context. For example, concepts such as controlled execution, recorded execution, and replaying recorded execution may be considered relevant to specific embodiments. However, this does not accord with the availability of a broad context and seeks proprietary rights to abstract concepts; they are not. Rather, this disclosure focuses on providing suitable specific embodiments whose technical effects fully or partially solve specific technical problems, such as how to automatically associate high-level control requests with machine-level tracing, and other problems addressed herein. Other media, systems, and methods relating to controlled execution, recorded execution, or replaying recorded execution are not within the scope of this invention. Thus, ambiguity, mere abstraction, lack of technical features, and the associated problems of proof are also avoided upon proper understanding of this disclosure.
Technical features
The technical features of the embodiments described herein will be apparent to those skilled in the art and will also be apparent to various interested readers in a variety of ways. Some embodiments address technical activities rooted in computing technology and improve the functionality of computing systems by aiding in debugging these systems, thereby improving system uptime, system accuracy, and power utilization relative to the computational results produced. For example, some embodiments provide system debuggability functionality that helps reduce the amount of time developers spend locating defects while debugging by allowing replay execution to move backward to the desired point rather than restarting from the beginning of execution and moving forward to that point. Some embodiments improve system debuggability by accurately aligning trace data with corresponding source code statements. Some embodiments provide additional debugging functionality in the system, such as the ability to set breakpoint address ranges instead of setting breakpoints at one address at a time.
Some embodiments include technical components, such as computing hardware, that interact with the software in a manner that goes beyond typical interactions within a general-purpose computer. For example, in addition to general interactions (such as general memory allocation, general memory reads and writes, general instruction execution, and some form of I/O), some embodiments described herein also implement backward step-out replay operations as disclosed herein.
Some of the technical effects provided by the embodiments include: more efficient use of debugging time, reduced re-tracing to obtain additional trace data, and improved debugger functionality for exploring defect causality.
Some embodiments include technical adaptations. Some embodiments include a replay layer adapter that accepts requests formatted for runtime, i.e., in a message format compatible with familiar debugger runtime communication, and responds to these requests in a format that can be used by the runtime during real-time debugging. In some embodiments, the replay adapter provides an interface that hides the differences between real-time process debugging, dump-based debugging, and time-travel tracing-based debugging. Some embodiments include a mapping between source code, intermediate representations(s), and trace data.
From the provided description, other advantages of the technical features based on the teachings will also be apparent to those skilled in the art.
Acronyms and Abbreviations
The following defines some acronyms and abbreviations. Other abbreviations may be defined elsewhere in this document, or may not require any definition and will be understood by those skilled in the art.
ALU: Arithmetic and Logic Unit
API: Application Programming Interface
BIOS: Basic Input/Output System
CD: Compressed disc
CPU: Central Processing Unit
DAC: Data Access Component
DVD: Digital Multifunction Disc or Digital Video Disc
FPGA: Field Programmable Gate Array
FPU: Floating-point processing unit
GPU: Graphics Processing Unit
GUI: Graphical User Interface
IDE: Integrated Development Environment, sometimes also called an "interactive development environment".
IL: Intermediate Language
OS: Operating System
RAM: Random Access Memory
ROM: Read-Only Memory
Additional terms
Reference is made herein to exemplary embodiments such as those shown in the accompanying drawings, and specific language is used to describe them. However, changes and further modifications to the features illustrated herein, as well as additional technical applications of the abstract principles illustrated by specific embodiments herein, that may occur to those skilled in the art, should be considered within the scope of the claims.
The meanings of the terms are stated in this disclosure, and these statements should be carefully considered when reading the claims. Specific examples are given, but those skilled in the art will understand that other examples may also fall within the meanings of the terms used and within the scope of one or more claims. The terms herein do not necessarily have the same meaning as they do in their general use (especially in non-technical use), in a particular industry, or in a particular dictionary or encyclopedia. Reference numerals may be used with a variety of wording to help indicate the breadth of the terminology. Omission of reference numerals from a given text does not necessarily mean that the text does not discuss the figures. The inventors claim and exercise their rights to their own lexicographical compilations. Terms in quotation marks are explicitly defined, but may also be implicitly defined without quotation marks. Terms may be defined explicitly or implicitly in the “Detailed Description” and/or elsewhere in the application.
As used herein, "computer system" can include, for example, one or more servers, motherboards, processing nodes, laptop computers, tablets, personal computers (portable or non-portable), personal digital assistants, smartphones, smartwatches, smart bracelets, cellular or mobile phones, other mobile devices having at least a processor and memory, video game systems, augmented reality systems, holographic projection systems, televisions, wearable computing systems, Internet of Things nodes, and/or other devices that provide one or more processors that are at least partially controlled by instructions. Instructions may take the form of firmware or other software in memory and/or dedicated circuitry.
A "multithreaded" computer system is a computer system that supports multiple threads of execution. The term "thread" should be understood to include any sequence of instructions that can be performed or scheduled (and possibly synchronized), and may also be referred to as, for example, as a "procedure" or "coroutine". Threads can run in parallel, sequentially, or in a combination of parallel execution (e.g., multiprocessing) and sequential execution (e.g., time-sliced).
A processor is a unit for processing threads, and is the core of implementations such as simultaneous multithreading. Processors comprise hardware. A given chip can contain one or more processors. Processors can be general-purpose or customized for specific purposes, such as vector processing, graphics processing, signal processing, floating-point arithmetic, encryption, I/O processing, etc.
The "kernel" includes the operating system, virtual machine monitor, virtual machine, BIOS code, and similar hardware interface software.
"Code" refers to processor instructions, data (including constants, variables, and data structures), or both. "Code" and "software" are used interchangeably in this document. Executable code, interpreted code, and firmware are some examples of code. Code that is interpreted or compiled for execution is called "source code."
The term "program" is used extensively in this article to include applications, kernels, drivers, interrupt handlers, firmware, state machines, libraries, and other code written by programmers (also known as developers) and/or automatically generated.
"Service" refers to consumable programs provided in a cloud computing environment or other network environment.
An "execution time point" refers to a specific point in time that is executed for a processing unit or thread, especially in relation to tracing execution. References to "specific execution time" or "execution time t" in this document refer to execution time points. For example, an execution time point can be implemented as a timecode variable or timecode value, or as a relative position in other records of tracing or execution activity. An execution time point ta "earlier than" or "later than" an execution time point tb indicates that the relative order of the two execution time points is determined. Similarly, a "younger" execution time point is a later execution time point than an "older" execution time point.
Information regarding the order of events in a tracing may be incomplete. Therefore, a tracing may have enough information to determine that event A precedes event B, or that event D follows event C. However, the relative order of events may also be partially or completely uncertain, even when considering a tracing. A tracing may show that event E does not follow event F, but this does not necessarily mean that E precedes event F; similarly, without a tracing also showing that K follows J, a tracing may show that event K does not precede event J. A tracing may also lack sufficient information to establish any order of two specific events relative to each other.
A "timecode" represents a monotonically changing value that can be used to impose order on at least some events in an execution tracing. It can be expected that timecodes are typically monotonically increasing values, but they can also be implemented as monotonically decreasing values. Some examples of timecodes include instruction counters, clock times (also known as clock ticks), and completely artificial (not register- or instruction-based) monotonic values. Depending on the tracing, all or some, or no, of the traced events may have corresponding associated timecodes. When timecodes exist, they can be unique, or they may simply be monotonic due to some timecode values being repeated.
A "memory cell" refers to an addressable unit of memory. Examples include bytes or words in RAM or ROM, processor registers, cache lines, and other addressable memory cells.
An emulator performs a simulation that provides the same functionality as the original hardware, but uses a different implementation or different hardware, or both. An example is a CPU emulator, which functions similarly to a CPU and can be used to execute code like the original CPU hardware, but with a different implementation; for example, the emulator can run on completely different physical hardware.
Unless otherwise stated, as used herein, “include” allows for additional elements (i.e., include means contain).
"Optimization" means improvement, not necessarily perfection. For example, an already optimized program or algorithm can be further improved.
For example, the term "process" is sometimes used herein as a term in the field of computer science and, in a technical sense, encompasses users of computational resources, namely coroutines, threads, tasks, interrupt handlers, application processes, kernel processes, procedures, and object methods. "Process" is also used herein as a term in patent law, for example, when describing process claims in contrast to system claims or claims of articles of manufacture (configured storage media). Similarly, the term "method" is sometimes used herein as a technical term in the field of computer science (a "routine") and also as a term in the field of patent law ("process"). Those skilled in the art will understand the meaning intended for use in particular contexts and will also understand that (in the sense of patent law) a given claimed process or method can sometimes be implemented using one or more processes or methods (in the sense of computer science).
Contrary to the absence of automation, "automatically" refers to the use of automation (e.g., general-purpose computing hardware configured by software for the specific operations and technical effects discussed herein). In particular, steps performed "automatically," while potentially initiated or interactively guided by a human, are not manually executed on paper or in the human mind. Automated steps are performed by machines to achieve one or more technical effects that would be impossible without such technological interaction.
Those skilled in the art will understand that technical effects are the presumptive purpose of technical embodiments. For example, the fact that an embodiment involves computation, and that some computations can also be performed without technical components (e.g., by paper and pencil, or even as mental steps), does not eliminate the presence of technical effects or alter the specificity and technical nature of the embodiment. Operations such as searching trace data at a sufficiently fast speed to allow replay within one or two orders of magnitude of the original execution speed, and computations for grouping native instructions for the trace and aligning instruction groups with corresponding source code items, should be understood herein to require, in addition to their inherent digital nature, a speed and accuracy unattainable by human thought processes (human thought cannot directly interface with trace files or other digital storage to retrieve necessary trace data). This is well understood by those skilled in the art, but others may sometimes benefit from being informed or reminded of the facts. Unless otherwise stated, contrary to mere thought experiments, embodiments are assumed to be capable of large-scale operation in a production environment or a test laboratory within a production environment.
"Computationally" also implies the use of computing devices (at least a processor and memory) and excludes results obtained solely by human thought or action. For example, performing arithmetic with paper and pencil, as understood herein, is not computationally arithmetic. Computational results are faster, broader, deeper, more accurate, more consistent, more comprehensive, and/or provide technical effects beyond the reach of human performance. A "computational step" is a step performed computationally. Neither "automatically" nor "computationally" necessarily means "immediately." "Computationally" and "automatically" are used interchangeably in this document.
"Actively" means without a direct request from the user. In fact, the user may not even be aware that an active step in an embodiment is possible until the result of the step has been presented to the user. Unless otherwise stated, any computational and/or automatic steps described herein may also be performed actively.
Throughout the document, the optional phrase "(multiple)" is used to indicate the presence of one or more of the indicated features. For example, "(multiple) processors" means "one or more processors" or equivalently "at least one processor".
For purposes of U.S. law and practice, the use of the term “step” in the claims or elsewhere herein is not intended to invoke means plus function, steps plus function, or to require interpretation under 35 U.S.C. 112(6)/112(f). Any presumption of such effect is hereby expressly rejected.
For the purposes of U.S. law and practice, claims are not intended to invoke a means-plus-function interpretation unless the phrase “means for…” is used. Claim language intended to be interpreted as means-plus-function language (if any) will explicitly state this intention by using the phrase “means for…”. When a means-plus-function interpretation is adopted, whether by using “means for…” and/or by the court’s legal interpretation of the claim language, the means listed in the specification for a given noun or given verb shall be understood to be linked to the claim language and hereby linked in any way that: appears in the same box in the drawing block diagram, is denoted by the same or similar name, or is denoted by the same reference numerals. For example, if a claim limitation refers to “zac widget” and that claim limitation is subject to a means-plus-function interpretation, then all structures identified anywhere “zac widget” is mentioned in any block, paragraph, or example in the specification, or bound together by any reference numerals assigned to the zac widget, shall be considered part of the structures identified in the zac widget application and contribute to defining the equivalent itemset of the zac widget structure.
Throughout this document, unless otherwise expressly stated, any reference to a step in the process is assumed to be that the step can be performed directly by the interested party, and/or indirectly by a party through an intervention mechanism and/or intervention entity, and still within the scope of that step. That is, unless explicitly stated as directly performed, the step does not need to be performed directly by the interested party. For example, steps involving actions performed by the interested party concerning a destination or other subject, such as alignment, clearing, compiling, continuing, controlling, debugging, simulating, encountering, exceeding, executing, acquiring, grouping, identifying, mapping, receiving, recording, replaying, requesting, responding, sending, setting, specifying, stepping (and variations such as stepping in, stepping out, stepping skipping), terminating, tracing (and alignment, aligned, clearing, cleared, etc.), may involve intervention actions performed by another party, such as forwarding, copying, uploading, downloading, encoding, decoding, compressing, decompressing, encrypting, decrypting, authenticating, invoking, etc., but should still be understood as being performed directly by the interested party.
Whenever data or instructions are referenced, it should be understood that, for example, these items configure computer-readable storage memory and/or computer-readable storage media to convert them into a particular article, as opposed to simply existing on paper, in a person's mind, merely energy, or merely a signal propagating on a wire. For the purposes of U.S. patent protection, according to the interpretation of the U.S. Patent and Trademark Office (USPTO) in the re Nuijten case, memory or other computer-readable storage media is not a propagation of a signal, carrier wave, or merely energy outside the scope of the patentable subject matter. In the United States, no claim covers the signal itself, and any claim interpretation that asserts the contrary is unreasonable. Unless expressly stated otherwise in a claim granted outside the United States, the claims do not cover the signal itself.
Furthermore, although there are obvious contrary provisions elsewhere herein, it should be understood that there is a clear distinction between (a) computer-readable storage media and computer-readable repositories and (b) transmission media (also referred to as signal media or energy-only). A transmission medium is a computer-readable medium or energy-only that propagates a signal or carrier wave. Conversely, computer-readable storage media and computer-readable repositories are not computer-readable media that propagate a signal or carrier wave. Unless expressly stated otherwise in the claims, “computer-readable medium” means computer-readable storage media, not the propagation of a signal itself, nor energy-only.
The term "example" in this document is illustrative. The term "example" is not to be used interchangeably with "invention." Examples may be freely shared or borrowed to create other examples (provided the result is operable), even if the resulting combinations of aspects are not explicitly described herein. It is necessary for a person skilled in the art to perceive that every licensed combination is essential, contrary to the policy of acknowledging that patent specifications are written for those skilled in the art. Formal calculations of combinations and informal intuition regarding the number of possible combinations, even those arising from a small number of composable features, will indicate that there are numerous combinations of aspects described herein. Therefore, requiring an explicit description of each combination contradicts the policy of requiring a concise patent specification and demanding knowledge of the relevant technical field from the reader.
List of reference numerals
The following list is provided for convenience and support of the accompanying drawings and as part of the specification text, which describe innovations by referencing multiple items. However, items not listed herein may still be part of a given embodiment. For clarity and readability, the given reference numerals are cited near some (but not all) of the referenced items in the text. Different examples or instances of the given items may use the same reference numerals. The list of reference numerals is:
100: Operating environment, also known as computing environment
102: Computer system, also known as computing system or computing architecture.
104: User
106: Peripheral equipment
108: Generally refers to the internet.
110: Processor
112: Computer-readable storage media, such as RAM, hard disk
114: Removably configurable computer-readable storage media
116: Processor-executable instructions; may be on removable media or in other memory (volatile or non-volatile or both).
118: Data
120: (Multiple) kernels, such as (multiple) operating systems, BIOS, device drivers.
122: Tools, such as antivirus software, profilers, debuggers, editors, compilers, interpreters, security penetration testers, obfuscators, automated performance monitoring tools, etc., can be adapted to use the execution control taught in this article.
124: Applications, such as word processors, web browsers, spreadsheets
126: Display screen
128: Computing hardware, not otherwise associated with reference numerals 106, 108, 110, 112, 114.
200: Debugger, also referring to debugging activities.
202: Real-time debugging of object programs or procedures
204: Runtime, such as the Common Language Runtime, a virtual machine, or other virtual machines that dynamically translate code for execution (trademark of Oracle U.S., Inc.)
206: Memory items, such as application or system data structures.
208: Data Access Components for the Debugger
210: Debugger User Interface
212: Source code, related information such as metadata and symbol tables.
214: A master request from the debugger for information about a source of debug object, such as a live debug object, dump file reader software, snapshot reader software, or trace file reader software.
216: A response to a master request that seeks information from a debug object's information source or state change; also known as a "master response," such as in a response at the abstraction level of the master request, rather than in a first, initial, or most important response.
218: Statements in source code; for example, they can be explicitly delimited by semicolons or parentheses, curly braces or square brackets, or implicitly delimited by spaces or end-of-line characters.
220: An expression in the source code; syntactically defined by the programming language used; it can be an assignment of function calls, object member assignments, routine calls, or another combination of constants, variables, operators, and routines that produce a result or side effect.
302: Dump file, also known as a storage dump; may include additional information such as indexes or metadata.
304: Storage snapshot; may include additional information such as indexes or metadata.
402: Execution control code for a debug object in the debugger, such as requesting or simulating execution control over the debug object, including stepping through the debug object, setting breakpoints, or executing the debug object until a breakpoint is reached.
404: Cross-level mapping in debuggers or other tools, such as mapping between source code and intermediate representation or mapping between intermediate representation and trace data.
406: A replay component that uses trace files to simulate the execution of a debug object; the trace replay component 406, alone or in conjunction with other execution controllers 402, 408 (implementation-dependent), uses traces to simulate the execution of the original process and allows viewing of CPU state and memory units over time; in some embodiments, this simulation can be performed forward or backward.
408: A replay adapter for the replay component, which allows the replay component to send requests and receive responses that are also used during real-time debugging. In a trace file debugging scenario, the replay layer (i.e., the replay component plus the replay adapter) receives and responds to main requests from the debugger, which can be received and responded to by the runtime in the real-time debugging scenario, and the replay adapter can also make secondary requests to the trace file.
410: Replay adapter interface; configured for communication with the debugger.
414: A secondary request for the trace from the replay adapter, where “secondary” indicates a lower level of abstraction than the main request 214; the secondary request may be a machine-level request, which may be implemented as communication to the trace file reader, or it may be implemented internally within the replay adapter (e.g., as a function call).
416: A response to a machine-level request that seeks information from the trace; also known as a "secondary response," as in the response at the abstract level of the secondary request, rather than as in the second response; it can be implemented as communication from a trace file reader or internally within a replay adapter (e.g., as a function result or data structure update).
418: Performing a trace; Although the dashed lines in Figure 4 indicate that a given trace may include individual items or omit individual items, this document assumes that the trace is not empty, and therefore it is shown as a solid line over the box that generally tracks data 454; 418 can also refer to the activity of creating a trace, which is sometimes also called a “trace” or “record”.
420: A trace file containing execution trace data; this may include machine-level trace data, i.e., data that records execution activities at the native code level.
422: Precise tracking data during tracking.
424: A timecode in a trace that identifies a specific point in time during the execution of the traced code; it may be linked to or embedded in other data within the trace, for example, trace data that explicitly states the point in time at which the stated operation is associated with the stated memory address relating to the stated data value; the timecode may be implemented as, for example, a clock tick or an instruction counter; for each recorded operation, some traces may contain a unique timecode, but in some trace data, the timecode may be repeated or omitted.
428: Gap in the timecodes of a trace, used to explicitly or implicitly indicate the execution time points in which tracing was not performed (e.g., a range when tracing is disabled for a thread or processing unit). This can include any gap where adjacent timecodes differ by a default value or a specified increment (typically 1), for example, the gap for timecode sequences 2, 3, 4, 300, 301, 302 is between 4 and 300, and the gap for timecode sequences 250, 500, 750, 1000, 2000, 2250, 2500 is between 1000 and 2000.
430: Indexes to data in the trace file, such as reverse lookup data structures, used to quickly identify trace attributes, memory lifetime index information, and other searchable lists of locations in the trace data that may be of particular interest.
432: Keyframes in tracking data; for example, they may exist at fixed intervals in the tracking data to allow for faster replay jumps to (or near) keyframes during tracking playback.
434: The code executed, such as the opcodes and parameters of the debug object's machine-level code executed by the processor while the debug object is running and being traced.
436: Stack activity that occurs while the object being debugged is running and being traced, such as stack growth, stack shrinkage, and the execution time at which this activity occurs.
438: Data stream; can correspond to a single thread or a group of threads, can correspond to a processor unit (e.g., a processor core); can correspond to all cores in a given processor socket; can be annotated with metadata to aid in replay.
440: Processor core activities that occur while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by the core.
442: Processor socket activity that occurs while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by any core located in a given processor socket.
444: Thread activity that occurs while the debug object is running and being traced, such as instructions executed during thread runtime, memory accesses performed during thread runtime, and associated metadata such as thread IDs and timestamps.
446: Register activities that occur while the debug object is running and being traced, such as what value is read from which register at what timecode, and what value is written to which register at what timecode.
448: Memory address
450: Instruction opcode
452: Data value
454: Generally refers to tracking data.
456: A tuple, i.e., two or more items of trace data associated in a trace, representing the same operation during trace execution; for example, a memory read operation or a memory write operation may be recorded as a tuple on a single line in the trace, which contains or otherwise associates the opcode (e.g., read or write), the address (e.g., RAM address or register ID), and the data value that has been read or written together.
458: Tracking entry
502: Memory unit, such as a byte or word in RAM or ROM, processor register, cache line, or other addressable memory unit.
504: The stack, for example, is a portion of memory where state information is pushed when a routine is entered, and then popped as control returns from the routine to the code that called the routine; it is generally distinguished from heap memory.
506: The stack base address defines the starting point from which the stack is allocated in contiguous memory; the stack is assumed to grow in a known direction using the allocation of stack memory in the system, which in a given system may be upward (i.e., the address increases as an item is pushed onto the stack), but in another system it may also be downward (i.e., the address decreases as an item is pushed onto the stack); the term "growing" here refers to the direction of stack growth in the system under discussion, while "shrinking" refers to the opposite direction.
508: Stack frame, or allocation record, is allocated on the stack when a routine is called; it typically contains the return address, which identifies the location in the code where execution will resume when the routine returns; it may also contain the address of a value passed as an argument to the routine when it is called, or the address of such an argument value.
510: Heap memory allocated and released along with the construction and release of objects; in some cases, the heap can be automatically garbage collected, and the heap identifies and marks it as available memory, which holds objects that are no longer reachable during the live execution of the process; in other cases, memory allocated from the heap requires a separate explicit call to release the allocated memory.
512: Object
514: Cache memory; for example, it can be in RAM working memory or on the processor chip.
516: Registers in the processor core
518: Object property; a named value that is part of an object; it can be a function, in which case the property is usually called a method; it also refers to a function that implements an object property; a function is a routine that returns a value.
520: ROM (Read-Only Memory); typically non-volatile.
522: Non-volatile memory other than onboard ROM, such as removable flash memory, disk or optical disk storage, magnetic tape storage, etc.
524: RAM (Random Access Memory); typically volatile.
526: Local memory, for example, memory that is local to the stated or implicit context, such as memory that is local to the routine during its execution and then freed, or memory that is local to the thread.
528: Global memory, such as memory that is global for a stated or implicit context, such as memory that is global relative to a set of multiple routines or relative to a set of threads during the execution of any of them.
530: The characteristics of memory that the addition or reduction of an entity outside a thread may alter the value stored in the memory cell, such as whether the memory cell is write-protected relative to other threads, or whether it is in shared memory (such as memory that is global relative to multiple threads).
602: Memory cell specification, such as an address in ROM or RAM or cache, or a register ID, or another item that specifies the memory cell by distinguishing it from other memory cells to allow access (read or write, or a reasonable attempt to read or write) to the memory cell; multiple memory cells may also be specified, for example, as a range of addresses.
604: Register ID, for example, register name, or index to a register array.
606: Address range, that is, a set of adjacent addresses that identify a set of corresponding contiguous memory units; as an example, a range can be specified as a pair of addresses (high address and low address); as another example, a range can be specified as a base address and a count of contiguous units based on the base address.
608: A specification of one or more execution time points, for example, as a specific time code or a range of time codes; the range can be specified as a pair of time codes (start time code and end time code), or it can be specified as a base time code and a count of time code increments, such as the number of clock ticks or the number of instructions.
610: Instruction count, which can be used as a time code; it can be an absolute count from the start of execution of a procedure, or a relative count such as when execution resumes from a thread.
612: System clock value, for example, in milliseconds or CPU cycles.
614: Execution time range specification, that is, data that specifies the range of execution time points; for example, it can be implemented as a pair of time codes (start and end) or as a base time code and a count of time code increments based on the base time code.
616: Execution Time Point
618: Perform control operations, such as stepping forward, stepping backward to skip, going to the specified location, setting or clearing breakpoints, etc.
620: Identifier for performing a control operation; for step or continue operations, it refers to or includes the direction (i.e., forward or backward; "reverse" and "backward" are used interchangeably in this document), and also refers to or includes the increment size (e.g., one step, step skipping a routine, or continue until a breakpoint is encountered).
702: Data values derived from tracking data
704: Instruction Pointer, which identifies a specific instruction or execution point in the trace data; it is a reference position for replay execution to move forward or backward; "backward" means towards younger execution points, and "forward" means towards older execution points.
706: Status code indicating the result of a request, such as successful execution of control operation, control operation initiated (for asynchronous control), or control operation failed.
800: Tracking and Replay Execution Control System
802: The process of the program being traced; it may include one or more threads.
804: Thread
806: A user request for a tool used to perform control operations.
808: Program metadata or tool metadata, such as data that does not have a separate specific number but is still discussed here.
810: Source intermediate mapping, i.e., a mapping between source code or source code item(s) and one or more intermediate representations of source code or source code item(s); mapping 810 is an example of cross-level mapping 404.
812: Intermediate native mapping, i.e., a mapping between one or more intermediate representations and native instructions or other trace data; mapping 812 is an example of cross-level mapping 404.
814: Record of native instruction 116 in the trace; may include, for example, trace data 422 with precise location, executed code 434, tuple 456, or generally trace data 454.
816: JIT (Just-In-Time) Compiler
818: Calls to routines or other calls, such as transferring control to an exception handler or interrupt handler.
820: Return address, that is, the point in time or instruction where execution will continue after calling 818.
822: A set of trace data, such as native instructions, that correspond to specific source code statements S or source code expressions E; for example, this could include a record of the execution of instructions that are generated entirely by compiling source code statements S or source code expressions E, rather than from the compilation of source code statements and expressions adjacent to S or E.
824: Edge instructions of group 822; each group typically has two edges—if the instructions are ordered, one edge is the youngest instruction in the group, and the other edge is the oldest instruction in the group; regardless of whether all instructions in a group are ordered relative to each other, an instruction X in a group of instructions G in the tracing is on an edge of G when X satisfies at least one of the following conditions: X is the first instruction of G encountered during forward execution of the tracing (“first forward edge”), X is the last instruction of G encountered during forward execution of the tracing (“last forward edge”), X is the first instruction of G encountered during backward execution of the tracing (“first backward edge”), or X is the last instruction of G encountered during backward execution of the tracing (“last backward edge”).
826: Intermediate representation, such as low-level code, like intermediate language code, or abstract syntax tree, or symbol table.
828: Breakpoint
830: Breakpoint Range
902: Forward step operation, also known as "forward step" or "step" (when the default or only direction is forward), refers to stepping forward and skipping one source code statement.
904: Forward step-in operation, also known as "forward step-in" or "step-in" (default or only when the direction is forward), means that the entry into the routine is skipped forward, so the next statement to be executed is the first statement of the routine body.
906: Forward step skip operation, also known as "forward step skip" or "step skip" (default or only when the direction is forward), means stepping forward and skipping through the routine, so the next statement to be executed is the first statement after the routine call.
908: Forward step-out operation, also known as "forward step-out" or "step-out" (default or only when the direction is forward), means that forward stepping skips the remainder of the current routine, so the next statement to be executed is the first statement after the routine call.
910: Continue forward operation. When the default or only the direction is forward, also known as "continue" or "run," it means continuing execution forward until a breakpoint is encountered or the process terminates.
912: The backward step operation, also known as "stepping backward," refers to skipping one source code statement by stepping backward.
914: Step-back entry, also known as "step-forward entry," means stepping backward into the routine. Therefore, the next statement to be executed in reverse is the last statement of the routine body.
916: The backward step skip operation, also known as "backward step skip," refers to stepping backward into and through a routine, so the next statement to be executed in reverse is the first statement before the routine call.
918: Step backward, also known as "step back out," means stepping backward to skip the remainder of the current routine. Therefore, the next statement to be executed in reverse is the first statement before the routine call.
920: Continue backwards, also known as "continue backwards," "run backwards," or "run in reverse," means continuing execution backwards until a breakpoint is encountered or the process begins.
Some implementations may use different definitions for operations 902-920, for example, by executing more or fewer instructions or by using different names.
922: Set a breakpoint range, which specifies that execution should pause at any address or execution time point within the specified range of multiple addresses or execution time points.
924: Setting Breakpoints
1004: Thread ID
1006: Thread state, such as created, runnable, running, suspended, blocked, terminated.
1008: Thread code, that is, the code that is executed or can be executed when a thread runs.
1010: Thread memory, for example, memory that is local to a thread, or memory that is global to a thread and is accessed by the thread as it executes.
1102: Symbol Table
1104: Identifiers used in the source code
1106: Data Type
1108: Abstract Data Tree
1110: Intermediate languages, such as Microsoft General Intermediate Language, bytecode (Oracle Corporation trademark), Register Transfer Language, Parrot Intermediate Representation, Standard Portable Intermediate Representation, IR Intermediate Language (LLVM Foundation trademark), etc.
1112: Intermediate Language Code
1300: Example of a trace replay execution control method, and a flowchart illustrating the above method.
1302: Identification Procedure
1304: Received execution control request
1306: Using a mapping between source code and intermediate representation
1308: Using the mapping between intermediate representation and tracking
1310: For example, controlling the response by executing forward or backward, or by setting parameters (direction, increment) on such execution.
1312: Execute the traced instructions during replay, for example, by emulation or by controlling the replay of operations specified in the trace as native instructions (not necessarily all of which are in the trace).
1314: Set a breakpoint or breakpoint range; including 922, 924, or both.
1316: Send a response to the execution control request.
1318: For example, by executing up to the edge of the group before pausing at a breakpoint, align a set of traced instructions with source code statements or expressions.
1400: Flowchart
1402: This indicates a backward stepping exit request.
1404: Sets a breakpoint at the execution location immediately preceding the specified location; when A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, location A is "immediately preceding" location B in the trace.
1406: Set a breakpoint at the edge of a set of instructions that corresponds to a specific source code statement or expression.
1408: Sets a breakpoint range that covers (and in some implementations matches) the range specified as receiving dynamically compiled (“jitted”) code.
1410: Set a breakpoint to step over the specified runtime routine.
1412: An instruction was encountered during the original execution or replay execution.
1414: Exceeding the hardware constraint on the maximum number of breakpoints that can be monitored simultaneously.
1416: Avoid terminating the procedure
1418: Termination of Procedure
1420: For example, by specifying the execution of source code statements or expressions to be executed, one can gain high-level control over the original execution or replay execution.
1422: Execute (original or replay) a process, thread, or program.
1424: Get the user's selection of source code statements or expressions
1426: User selection of source code statements or expressions
1428: Debugging process, thread, or program
1430: Forward execution process, thread, or program
1432: Backward execution of a process, thread, or program
1434: Set a large breakpoint range; this breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in the trace.
1436: Large breakpoint range
1438: Recording tracking data from the real-time process.
1440: Group the traced instructions, i.e., create or specify group 822
1442: Clear breakpoints or breakpoint ranges
Operating environment
Referring to Figure 1, an operating environment 100 for one embodiment includes at least one computer system 102. The computer system 102 may or may not be a multiprocessor computer system. The operating environment may include one or more machines within a given computer system, which may be clustered in a cloud, networked as client servers, and/or peer-to-peer. Individual machines are computer systems, and a group of collaborating machines is also a computer system. A given computer system 102 may be configured for, for example, end-users with applications, for administrators, as a server, as a distributed processing node, and/or otherwise.
Human user 104 can interact with computer system 102 via typed text, touch, voice, mobile, computer vision, gestures, and/or other forms of I/O, using a display, keyboard, and other peripheral devices 106. Screen 126 may be a movable peripheral device 106 or may be an integral part of system 102. The user interface may support interaction between one embodiment and one or more human users. The user interface may include a command-line interface, a graphical user interface (GUI), a natural user interface (NUI), a voice command interface, and/or other user interface (UI) presentations, which may be presented as different options or may be integrated.
System administrators, network administrators, software developers, engineers, and end users are all specific types of users 104. Automated agents, scripts, playback software, etc., representing one or more individuals can also be users 104. Storage devices and/or network devices may be considered peripheral devices in some embodiments, while in other embodiments they may be considered part of system 102, depending on their separability from processor 110. For example, other computer systems not shown in FIG1 may technically interact with computer system 102 or another system embodiment using one or more connections to network 108 via network interface devices.
Each computer system 102 includes at least one processor 110. Like other suitable systems, computer system 102 also includes one or more computer-readable storage media 112. Media 112 can be of various physical types. Media 112 can be volatile memory, non-volatile memory, in-situ fixed media, removable media, magnetic media, optical media, solid-state media, and/or other types of physically persistent storage media (as opposed to media that merely transmits signals). Specifically, when inserted or otherwise installed, a configured medium 114, such as a portable (i.e., external) hard disk drive, CD, DVD, memory stick, or other removable non-volatile storage medium, can functionally become a technical part of the computer system, making its contents accessible for interaction with and use by the processor 110. Removably configured media 114 is an example of computer-readable storage media 112. Other examples of computer-readable storage media 112 include built-in RAM, ROM, hard disks, and other memory storage devices that are not readily removable by the user 104. To comply with current U.S. patent requirements, under any pending or granted claim in the United States, a computer-readable medium, a computer-readable storage medium, or a computer-readable memory is not a signal itself or merely energy.
For example, medium 114 is configured with binary instructions 116 executable by processor 110; "executable" is used broadly herein to include machine code, interpreted code, bytecode, and/or code running on a virtual machine. Medium 114 is also configured with data 118, which is created, modified, referenced, and/or otherwise used for technical effects through the execution of instructions 116. Instructions 116 and data 118 configure the memory or other storage medium 114 in which they reside; when the memory or other computer-readable storage medium is a functional part of a given computer system, instructions 116 and data 118 also configure the computer system. In some embodiments, a portion of data 118 represents real-world items such as product characteristics, inventory, physical measurements, settings, images, readings, targets, volumes, etc. Such data may also be transformed through backup, restore, commit, abort, reformatting, and/or other technical operations.
While an embodiment can be described as being implemented by software instructions executed by one or more processors in a computing device (e.g., a general-purpose computer, server, or cluster), this description does not represent an exhaustive list of all possible embodiments. Those skilled in the art will understand that the same or similar functionality can often also be implemented directly in hardware logic, in whole or in part, to provide the same or similar technical effects. Alternatively, or in addition to software implementation, the technical functionality described herein can be performed at least in part by one or more hardware logic components. For example, and without excluding other implementations, an embodiment may include hardware processors 110, 128, such as field-programmable gate arrays (FPGAs), application-specific integrated circuits (ASICs), application-specific standard products (ASSPs), system-on-a-chip components (SOCs), complex programmable logic devices (CPLDs), and similar components. For example, components of an embodiment may be grouped into interactive functional modules based on their inputs, outputs, and/or their technical effects.
In addition to processor 110 (e.g., CPU, ALU, FPU, and/or GPU), memory/storage medium 112, and display 126, the operating environment may also include other hardware 128, such as batteries, buses, power supplies, wired and wireless network interface cards. The terms "screen" and "display" are used interchangeably herein. Display 126 may include one or more touchscreens, a screen responsive to input from a pen or tablet, or a screen for output only. In some embodiments, peripheral devices 106, such as human user I/O devices (screen, keyboard, mouse, tablet, microphone, speaker, motion sensor, etc.), will be operatively communicating with one or more processors 110 and memory. The software process may be user 104.
In some embodiments, the system includes multiple computers connected by network 108. Networking interface devices may use components such as packet-switched network interface cards, wireless transceivers, or telephone network interfaces (e.g., these may be present in a given computer system) to provide access to network 108. However, one embodiment may also transmit technical data and/or technical instructions via direct memory access, removable non-volatile media, or other information storage, retrieval, and/or transmission methods.
Those skilled in the art will understand that the foregoing and other aspects presented herein in the context of an "operating environment" can form part of a given embodiment. The headings of this document are not intended to strictly categorize features into sets of features specific to embodiments and non-embodiments.
One or more items are shown in dashed lines in the accompanying drawings, or listed in parentheses, to emphasize that they are not necessarily part of the illustrated operating environment or all embodiments, but may interoperate with items in the operating environment or some embodiments discussed herein. Items not shown in dashed lines or parentheses are not necessarily required in any drawing or any embodiment. In particular, Figure 1 is provided for convenience; the inclusion of an item in Figure 1 does not imply that the item or its described use was known prior to the invention.
Debugging environment
Figure 2 illustrates a real-time process debugging environment, which is an example of operating environment 100. Debugger 200 contains various components, many of which are not shown here because many are well-known. The primary use of execution control, as taught herein, can be in environments where real-time process debugging is infeasible or at least undesirable. Nevertheless, real-time process debugging is shown for the context and because it can be combined with trace-based debugging utilizing the execution control taught herein.
Debugger 200 can be a conventional debugger or can be adapted to perform the execution control taught herein. The debugger shown includes a data access component 208 (DAC). In this real-time debugging 1428 environment, DAC 208 communicates with the runtime 204 of the real-time debug object 202 to obtain memory items 206 by using a master request 214 to the runtime and a master response 216 from the runtime. The debugger then updates its user interface 210 accordingly. The user interface presents status information at a relatively high level (e.g., in terms of artifacts defined in source code 212). However, those skilled in the art will understand that the execution control taught herein does not require DAC 208 or other adapters.
Figure 3 illustrates a dump debugging environment, which is another example of operating environment 100. Debugger 200 uses its data access component 208 or functionally similar code to read memory contents from dump file 302 or snapshot 304, or both, as well as other state information at specific points in time during the execution of the debugged object.
Figure 4 illustrates a trace-based debugging environment, another example of operating environment 100. The debugger 200 shown is used in conjunction with or includes (since the scope of the debugger can be defined by a given developer, for example, to include replay adapter 408) a technical adapter that allows the debugger to interact with trace 418 more or less as if the debugger were interacting with the runtime. For example, in this example, the same format could be used for the main request 214 and main response 216 used in the real-time process debugging environment of Figure 2. However, trace-based debugging 1428 can offer developers less flexibility than real-time process debugging because variables and other memory contents accessible through the runtime are not necessarily readable from the trace. The granularity of execution control using a familiar trace-based debugger can also be greater than the granularity available through the teachings presented herein. Finer granularity can provide better control during debugging, thereby accelerating defect location identification and understanding of defects.
Tracing-based debugging, with appropriate execution control code 402, a replay component 406, and a mapping 404 between tracing data and source code 212, can support reverse execution 1422 in the form of a reverse replay of the traced execution. In contrast, in real-time debugging, the debugged object is typically not reverse executed.
The replay adapter 408 shown includes an interface 410 to the debugger, which in this example presents an API to the debugger that matches at least a subset of the APIs presented to a traditional debugger by runtime 204 to support real-time process debugging 1428. Other implementations are also possible. Moreover, as shown by the dashed lines around the replay adapter 408 in Figure 4, in some implementations, some or all of the replay adapters can be considered part of the debugger 200, since the debugger is an adapted debugger 200 containing code that utilizes one or more cross-level mappings 404. For example, instead of using external messages, one variant implements the main request 214 and main response 216, as well as interface 410, as function calls, returns, and interfaces within the debugger. In some variants, the debugger includes and utilizes the cross-level mapping 404, and there is no separate replay adapter 408. Debugger DAC 208 can be used to map address 448 to higher-level object 512. The debugger cross-level mapping 404 and its associated code (i.e., one or more of the execution controller 402, replay component 406, and replay adapter 408) can be used to map source code statements 218 or expressions 220, or both, to specific native instructions 434 or native instruction sets 822. In some embodiments, similar to dump debugging, the DAC 208 has runtime internal knowledge and can read runtime data structures to determine where the JIT source code is located for a given set of IL instructions. The machine architecture on which the debug object runs can be significantly different from the machine architecture on which the debugger runs, but the DAC can be designed to read runtime data structures and handle hardware/runtime differences.
Figure 4 illustrates the communication between the replay component 406 and the trace 418 in the form of a machine-level request 414 and a response 416. This is one possible implementation, as an example, which could use a trace reader (not shown) to receive and respond to the request. However, in another implementation, the machine-level request 414 and response 416 take the form of function calls within the replay adapter 408, which include functions that read from the trace 418 and pass back their caller information found in the trace. Thus, the replay component can maintain current state information, such as which position in the trace 418 is identified by the current instruction pointer 704.
As shown in the figure, trace 418 can be stored in one or more files 420 and can include various types of trace data, as well as metadata that supports or defines the search for the trace data. Some or all of trace 418 can also reside in RAM. Some examples of trace data include precisely located trace data 422 (such as copies of low-level instructions and their operands (also known as "native instructions")), timecode 424 which can be used to sort trace data items relative to each other, memory snapshot 304 or dump file 302, index 430 into the original trace data, keyframes 432 inserted into the original trace data at specified intervals, copies of code 434 executed by the debug object during trace 1422, stack activity 436, data streams 438 read or written by the debug object during trace, processor activity based on per core 440 or per socket (multiple cores) 442, thread activity during trace 444, register reads and writes during trace 446, tuples 456 that associate memory address 448 with instruction 450 and one or more values 452 and optionally also with timecode 424, and other 454 reads or writes or values or opcodes captured during trace. In some embodiments, an instance of any one of items 216, 422, 434, 436, 438, 440, 442, 444, 446, 456 conforms to trace “entry” 458. In some, any minimal portion of trace data 454 that itself represents a change in the state of the traced program conforms to trace “entry” 458. Missing data in the trace can also be considered state information, such as gaps 428 in the timecode sequence.
Figure 5 illustrates various memories 112 that can be tracked and thus subject to changes in value or allocation state according to the teachings herein, changes in value or allocation state being performed by the execution of native instructions under the control of execution 1422. Examples of memory cells 502 shown include stack 504 (including data such as its base address 506 and allocated stack frames 508), heap contents 510 such as object 512, or metadata such as garbage collection data, cache 514, processor registers 516, object members such as attribute 518, addressable units in ROM 520 or RAM 524, removable or third-level memory 522, local memory 526, and global memory 528. Memory cells may have one or more characteristics 530 that increase or decrease the accessibility of the memory cell, for example, the memory may be in kernel space, may be shared, may be DMA-enabled, etc.
Figure 6 illustrates the contents of machine-level request 414. As mentioned above, these requests can be implemented using communication data structures, or they can be implemented as parameters of a routine. Some examples of the contents of machine-level request 414 are a memory cell specification 602 and a specification 608 of one or more execution time points 616. Memory cell 502 can be specified as, for example, a single address 448, an address range 606, or a register name 604. Time code 424 can be specified as, for example, an instruction count 610 or a system clock value 612, and this specification can be for a single specific execution time point 616 (a point during trace, or a specific native instruction) or a range of execution time 614 (i.e., the span or period or interval of execution time during trace, or a set of consecutive native instructions).
Figure 7 illustrates the contents of machine-level request response 416. As mentioned above, these request responses can be implemented using communication data structures, or they can be implemented as routine function return values or side effects. Some examples of the contents of machine-level request response 416 are: a value 702 for one or more memory locations specified in the corresponding request 414; an instruction pointer 704 indicating which instruction will be executed next (or which instruction has just finished executing 1422); and a status code 706 containing flags associated, for example, with an instruction, or an error, or a condition (such as an end-of-file marker). Each thread may have a corresponding instruction pointer 704.
Some tracking and replay execution control systems
Figure 8 illustrates a trace replay execution control system 800, each of which is a system 102 configured according to the execution teachings provided herein. If the execution control system operates in a real-time debugging environment, it contains a debug object program 124 with a callable runtime 204. Although debugging is used as an example, execution control can also be performed as taught herein in other contexts, such as for performance analysis or software health monitoring. The debug object or other replayed program includes one or more processes 802, each of which may include one or more threads 804. Those skilled in the art will understand that the terms “process” and “thread” are used in different ways, for example, sometimes as synonyms for each other, and sometimes with different meanings. In either case, the execution control teachings provided herein can be applied because, under either meaning of “process” or “thread,” process 802 and thread 804 have corresponding source code 212 and corresponding traced instructions 434.
Regardless of whether replay execution occurs in a real-time debugging environment, the state information of the replayed program is maintained and updated as the replay execution "proces." In this sense, "procesuspension" includes forward execution, backward execution, or both. State information includes, for example, one or more instruction pointer values indicating execution time(s) in trace 418, and changes in traced program variable values captured in trace 418. To indicate the presence of state information, the boxes for process(s) 802 are shown in FIG. 8 inside the debug object program 124 box with solid lines instead of dashed lines. However, those skilled in the art will recognize that state information may also be maintained within execution controller 402 or at one or more other locations within system 800.
The execution controller 402 itself includes software executed using processor 110 and memory 112. The traced program 124 is other software having source code 212 and metadata 808. The execution controller 402 uses a source intermediate map 810 to map the source code 212 to an intermediate representation 826 of that source code. The execution controller 402 also uses an intermediate native map 812 to map the intermediate representation 826 to the trace 418 (including a record 814 of native instructions collected from the trace). These maps 810, 812 are collectively referred to herein as “cross-level maps”. Note that a given embodiment may include one or more cross-level maps 404; for example, source-to-intermediate and intermediate-to-native functionality may be integrated into a single source-to-native map 404.
In some cases, such as in the case of .NET languages, the compiler creates the source-to-IL mapping 810. However, there are runtimes 204 that can directly execute the source language; one example is (a trademark of Oracle Corporation). In this case, the runtime itself compiles the language to an intermediate format and simultaneously creates the source-to-IL mapping. In the case of managed languages similar to .NET languages, the high-level language compiler does not perform native IL mapping; instead, the JIT compiler in runtime 204 does. Compilers that compile to native code also do not perform native IL mapping. In fact, if such a compiler has any form of IL, it is likely an implementation detail of that compiler. In some embodiments, execution control utilizes the native IL mapping 812 generated by the runtime.
Some implementations obtain the generated IL from tracing native instructions. For example, some implementations simulate CPU operation by emulating it and use native instructions to replay the tracing. In some cases, the IL alone is not sufficient information to recreate the native instructions. In some cases, the native instructions themselves are insufficient to implement IL stepping or IL breakpoints. Additionally, a mapping between native and IL instructions is used. Some embodiments use mappings without relying on native instructions (which may not even exist in the tracing) to implement debuggers that support stepping through IL code using a tracing replayer that does not rely on knowledge of native instructions. Such implementations can trace the instruction pointer by the range provided in the mapping or by any consecutive or non-consecutive collection of the specified items.
Supplement on cross-level mapping
To further illustrate the cross-level mapping 404, consider the following example: some source code 212, a portion of some corresponding intermediate language code used as intermediate representation 826, and a portion of some native instructions. Due to the patent office's restrictions on the inclusion of computer code in patent documents, and because showing a portion is sufficient to illustrate mapping 404 in the context of the other information provided herein and the knowledge of a person skilled in the art, only portions of the intermediate language code and native instructions are shown here.
Original C# source code:
Sample source-to-IL mapping. This sample is hand-generated. The actual implementation is typically unreadable to humans. That is, the source-to-IL mapping will usually be implemented in binary format rather than text format. Nevertheless, the following material illustrates the functionality of the source-to-IL mapping to those skilled in the art. The mapping is not a one-to-one mapping; some parts of the source code line end at different locations in the IL code. For a single source program, there are many correctly generated IL transformations.
Sample IL to native mapping. Similar to source-to-IL mapping, this is manually generated, and the implementation will exist as a data structure, for example, at runtime. For a single generated IL, there are many correctly generated native code transformations. Because the JIT compiler can add complexity due to processor-specific optimizations, and because debug 1428 using traced programs may not execute on the same processor type (i.e., different optimizations will be applied), it is not simply possible to run the JIT on the IL and the result cannot be guaranteed to be the same as running it during the generation of trace 418. In this example, the IL begins with "IL_", and the native code is represented as <memory address><hexadecimal representation of native code><assembly mnemonic>.
Typically, kernel 120 is present, and is explicitly shown in Figure 8 to help prevent confusion between runtime 204 and kernel 120. The cross-level mapping and execution control described herein assume that the runtime is present in most (if not all) configurations when execution is traced to create trace 418.
Additional aspects of System 800 and related systems
Some embodiments of system 800 include a JIT compiler 816 for dynamically compiling the code of the traced program 124. Some aspects of execution control address the challenges created by JIT compilation, for example, by supporting breakpoint ranges 830, which allow breakpoints to be encountered even if native code spanning the breakpoint location has not yet been generated by compilation, provided the address range that will contain the generated code is known. For example, breakpoint range 830 can be specified as ranges 606 or 614, while individual breakpoints 828 are specified as specific single locations within trace 418.
Referring again to Figure 8, some embodiments of system 800 include a return address 820 for call 818. This return address 820 may be used, for example, when performing a reverse step-out execution control operation that steps out of the calling routine during reverse execution.
Some embodiments improve the accuracy of execution control by providing a more precise correspondence between source code statements or expressions and the traced instructions that implement them. For example, some familiar methods of tracing replay step into the middle of the traced instructions corresponding to a given source code statement 218 or expression 220, which can be confusing. Some embodiments described herein definitively define a set of 822 traced instructions corresponding to a given source code statement 218 or expression 220 (e.g., generated by compilation to implement). The execution controller then sets the instruction pointer to a location at an edge 824 of this set of 822, instead of somewhere in the middle as before. Which edge 824 is selected can depend on whether the execution is replaying forward or backward; for example, a first forward edge is selected for forward replay, and a first backward edge is selected for backward replay. Alternatively, the same edge can always be used regardless of the replay direction; for example, the instruction pointer can always be set at the first forward edge.
Figure 9 illustrates several execution control operations 618. For example, a user presents a control operation request 806 to the debugger 200 or other tool 122 via user interface 210. Execution controller 402 translates the control operation request 806 into a change in the state of process 802. The operations shown include forward step 902, forward step into 904, forward step skip 906, forward step out 908, continue forward 910, backward step 912, backward step into 914, backward step skip 916, backward step out 918, continue backward 920, set breakpoint range 922, and set breakpoint 924. In these operation names, "forward" indicates performing replay forward, and "backward" indicates performing replay backward.
Various step operations 902-920 can be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar operations with similar or identical names. However, internally, for example, they can be implemented through innovations for aligning source code with traces using cross-level mapping 404, instruction group 822, and specific breakpoint placement. Continue operations 910, 920 can also be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar continue operations, while internally, they utilize cross-level mapping 404 or instruction group 822, or both. Set breakpoint operation 924 can also be implemented so that, from the developer's perspective, it operates in a manner similar to or identical to the familiar breakpoint setting operation, while internally, it utilizes cross-level mapping 404 or instruction group 822, or both.
Figure 10 illustrates the thread 804 activity information 444 that can be captured in a given trace 418. It shows the thread identifier 1004, thread state indication 1006, thread executable code 1008, and memory unit 502 status information 1010 such as thread local variables and their identifiers.
Figure 11 illustrates some examples of intermediate representation 826. Examples shown include symbol table 1102, which associates source code identifiers 1104 (variable names, function names, object members, and method names, etc.) with data types 1106 (e.g., integers, floating-point numbers, strings, booleans, and user-defined types). Another example is abstract syntax tree 1108. Other examples include code 1112 written in one or more intermediate languages 1110. More generally, some embodiments use intermediate representation 826 that shares the structure of an intermediate representation created by the compiler, or even a copy thereof. However, intermediate representation 826 is placed in the context of an execution controller, opposite to the compiler's context. Furthermore, intermediate representation 826 is used for tracing replay of the execution tracing 418 of previously generated code, rather than being used to generate that code in the first place.
A technician will recognize that a given source code 212 can potentially be used to generate many different versions of the corresponding IL. However, only one of these versions will be used in the program, and the symbol information emitted by the compiler will correspond to the emitted IL. The debugger can be designed to load only the corresponding symbol information, so only one mapping will exist. In some systems, the runtime may include multiple versions of native code for a given routine; for example, both optimized and non-optimized versions of native code for debugging may exist, or multi-level JIT functionality may provide multiple versions of native code in memory. In such a multi-native version system, replay can still be performed. For example, when a breakpoint is set, it can be set in all existing versions of the native code. Some embodiments use native code generated by the JIT as well as IL code, which are obtained from or via trace 418. Some embodiments also use the corresponding symbol information for the source/IL mapping, which may or may not be included in the same trace file 420.
Figure 12 is a variation of Figure 2. In the environment of Figure 12, both real-time debugging and replay execution are supported. Replay is supported by a scrolling trace 418, which records the forward execution of the real-time debug object in real time, while the debug object executes according to the prompts of debugger 200. For efficiency, only, for example, a pair of buffers is used to track the latest instructions. Trace 418 is written to one buffer until it is full, then to another buffer until it is full, then written back to the first buffer (overwriting the earlier trace), and so on. Alternatively, instead of the scrolling window, all execution activity during the debug 1428 session can be tracked. As another alternative, previously recorded trace 418 can be accessed during the real-time debug session.
Some additional system examples
Examples are provided in this document to help illustrate various aspects of the technology; however, the examples given in this document do not describe all possible embodiments. Embodiments are not limited to the specific implementations, arrangements, displays, features, methods, or scenarios provided herein. A given embodiment may include, for example, additional or different technical features, mechanisms, sequences, or data structures, and may otherwise deviate from the examples provided herein.
Referring to Figures 1-2, some embodiments use or provide a trace replay execution control system 800. This system includes a processor 110, a memory 112 operatively communicative to the processor, and a trace 418 recorded during the execution of program 124 in conjunction with runtime 204 and kernel 120. The trace includes a record 814 of native code instructions 116 executed in at least one thread 804 of the program. Source code 212 of at least a portion of the program is also present.
System 800 also includes a source intermediate mapping 810 that maps between source code and intermediate representation 826 of source code, and an intermediate native mapping 812 that maps between intermediate representation 826 and trace 418.
System 800 also includes an execution controller 402 in software tool 122. The execution controller is configured to control the replay execution of trace 418 in response to request 806 when executed using the processor. In the replay execution, the source code is associated with trace native code instructions or other trace entries through source intermediate maps and intermediate native maps.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: forward execution step into 904 operation, forward execution step out 908 operation, and forward execution step skip 906 operation.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: a backward step-in operation 914, a backward step-out operation 918, and a backward step-skip operation 916.
In some embodiments, execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: continuing forward execution in the trace 910 until any position within the breakpoint range 830 is reached, and continuing backward execution in the trace 920 until a position within the breakpoint range is reached.
In some embodiments, system 800 is configured to step into a portion of source code that has not yet been compiled into native code instructions during replay execution.
In some embodiments, the intermediate representation 826 includes at least one of the following: a symbol table 1102 that associates at least two identifiers 1104 used in the source code with a data type 1106, an abstract syntax tree 1108 derived from at least a portion of the source code, or a conversion 1112 from at least a portion of the source code 212 to the intermediate language 1110.
In some embodiments, tracing 418 does not contain any execution instance of runtime 204, and tracing 418 is not configured to call tracing to execute any runtime-specific code.
In some embodiments, system 800 includes a real-time debug object 202 of program 124 having a runtime callable instance. In some embodiments, trace 418 is recorded from a real-time process and the system is configured to replay the execution of the trace.
In some embodiments, system 800 is configured to skip a portion of the replay execution of trace 418 because execution controller 402 moves the replay execution from a first execution point of the trace to a second execution point of the trace, and the system does not execute trace native code instructions or other trace entries that would otherwise be executed through continued execution from the first position to the second position.
Those skilled in the art will understand that other systems are also within the scope of the teachings presented herein. In particular, some other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any system or apparatus using any of the execution control teachings herein is within this disclosure, whether or not it is in the specific example provided.
Some method examples
Figure 13 illustrates an example of an execution control method 1300, which is an example of a method executed or assisted by an execution controller 402, a cross-level mapping 404, or other items discussed herein. This example method includes identifying a managed program tracked by 1302 as a tracked managed program. Identifying a program as tracked is simple; if a program is being tracked, or has been tracked previously, then it is a tracked program. To some extent, it involves identifying a program as managed because it is managed when it depends on runtime 204 for real-time execution, and runtime 204 may provide different services in different implementations. In many cases, runtime 204 provides automatic management of heap memory through garbage collection based on reachability analysis, reference counting, or other mechanisms. However, what is of greater interest in this application is the use of runtime 204 to execute intermediate language code 1112. In some runtimes, the translation from source to native instructions is not modularized into a source-to-intermediate language stage, followed by an intermediate language-to-native code stage. For example, some platforms execute source code directly (a trademark of Oracle Corporation, USA). For the purposes of this application only, a "managed" program is a program that relies on runtime 204 to generate native instructions. A managed program may also be subject to or not subject to garbage collection performed by the runtime.
The method 1300 shown also includes receiving a request 1304 to perform a control operation on a trace playback. This request may be a request 806 directly from the user through the user interface, or a request 214 from the debugger to the trace execution controllers 402, 406, or 408.
The illustrated method 1300 also includes a mapping 1306 from source code to an intermediate representation and a mapping 1308 from the intermediate representation to native code. This can be done in two stages as indicated, or in some other embodiments, in a single combined stage from source code to native instructions. However, unlike compilation itself, whether in two stages or one stage, mappings 1306 and 1308 are not for generating code for execution, but rather for associating source code locations with locations in the trace of previously generated and executed instructions.
Some implementations map 1306 from source code to an intermediate representation using a symbol file that contains hashes, checksums, or other identifiers of the IL corresponding to the source. If the identifiers match, the debugger loads the symbol file. This symbol file also contains identifiers for each source file used to compile the IL. Before the debugger loads the source files and maps the IL code to the source, it verifies the source file identifiers using the identifiers contained in the symbol file.
When IL is compiled just-in-time (JIT), some implementations use a runtime-generated mapping to map 1308 from IL to native code. In some implementations, the runtime may not guarantee backward compatibility regarding how JIT will occur, and therefore is free to change the JIT process at any time. In such implementations, debuggers may not be able to make assumptions about what the native code output by the JIT process will contain. Therefore, debuggers may request the runtime to provide the mapping between native code and IL.
Some variations of the method 1300 shown include aligning native instruction sets with source code statements or expressions 1318, which are generated by compiling from these source code statements or expressions.
The illustrated method 1300 includes control 1310 for replay, which is to perform "execution control". An example of control 1310 is executing 1312 native instructions or other trace entries corresponding to step, step in, step skip, step out, or continue operation, thereby changing the state of process 802. Another example of control 1310 is setting 1314 individual breakpoints or breakpoint ranges. Those skilled in the art will recognize that performing step, step in, step skip, or step out operations involves setting breakpoints, but it is also possible to set breakpoints without executing native instructions or other trace entries, for example, when preparing for continue operation. In some embodiments, the code itself is not modified to set breakpoints in the trace. Those skilled in the art will recognize that the processor can set execution breakpoints via instructions (e.g., int3 in some Intel architectures) or via hardware breakpoints (registers that specify which address to monitor). In some embodiments, the trace replay execution control system 800 provides similar capabilities. Some implementations do not modify the code flow and support an arbitrarily large number of breakpoints.
Finally, the method 1300 shown includes sending 1316 a response to the request, such as response 416 or another message or data structure containing instruction pointer 704 or status code 706.
Figure 14 illustrates some additional execution control steps that may be performed in some embodiments. Some familiar debuggers do not support the backward step-out operation 918. However, some embodiments identify 1402 as a request for the backward step-out operation 918 and implement the operation as taught herein.
Debuggers can implement some familiar breakpoint operations, namely, the operation for setting a breakpoint 1314. However, some embodiments set breakpoints 1314 and 1404 immediately before the specified location. Some embodiments set breakpoints 1314 and 1406 at the edge of the instruction group 824. Some embodiments set breakpoint range 830 of 1314 and 1408 on, for example, an address range designated for receiving code that is compiled just-in-time (JIT-compiled). In particular, some embodiments set large breakpoint ranges 1436 and 830 of 1434, 1314, and 1408. Some embodiments set breakpoints 1314 and 1410 as part of implementing a step-skip operation to step over runtime routines that the developer may not be interested in. For example, such runtime routines may perform garbage collection, JIT compilation, anti-malware or other security checks, or runtime 204 stewardship functions. The other steps shown in Figure 14 are discussed elsewhere in this document or included for completeness; for example, not only can breakpoints be set, but breakpoint 1442 can also be cleared.
Unless otherwise indicated, the technical methods shown in the figures or otherwise disclosed will be executed automatically by, for example, system 800. Within the scope of actions involving human administrators or other humans, the methods may also be executed partially automatically and partially manually; for example, a person may select 1426 source code statements or expressions and then use tool 122 user interface to request step operations or breakpoint operations. However, a completely manual method is not considered here as an innovation. In a given embodiment, zero or more example steps of the method may be repeated, possibly with different parameters or data to be manipulated. The steps in one embodiment may also be performed in a different order than those shown in the figures. Steps may be performed sequentially, in a partially overlapping manner, or in complete parallel. The order in which steps are performed during a given method can vary from execution of one method to execution of another. Steps may also be omitted, combined, renamed, regrouped, or otherwise deviated from the illustrated flow if the method being performed is operable and conforms to at least one claim.
Some embodiments use or provide a computer-implemented method for a trace replay execution control method. One example method includes identifying, at 1302, the managed program being traced, i.e., a program configured to execute in conjunction with runtime calls and configured to be traced. The example also includes receiving, at 1304, a trace replay execution control request in a software tool running on a computing system. Based on the trace replay execution control request, the example method automatically maps, at 1306, the source code of the traced managed program to an intermediate representation of the source code, and at 1308, the intermediate representation to a trace, at 418. The trace includes a record of native code instructions traced when the traced managed program is executed. Trace 418 does not include any execution instances at runtime. The example method also executes, at 1312, the traced native code instructions corresponding to the trace replay execution control request, thereby replaying a portion of the trace.
In some embodiments, the trace replay execution control request identifier 1402 performs a step-out operation backward to step out of the routine, and the method includes setting breakpoints 1314 and 1404 on the trace native code instructions, the breakpoints having a position immediately preceding the location of the return address of the call to the routine. For the purposes of this method, when 1412A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, position A in the trace is "immediately preceding" position B. For the purposes of this method, when performing source-level debugging, alignment 1318 can associate instruction group edge 824 with the most recently executed source file line number, statement, or expression executed before the current function call. Some embodiments set breakpoints at the call location of the routine; for example, some embodiments set breakpoints at the call location of the current function.
Typically, the source code contains statement 218 and expression 220. In some embodiments, the method includes setting breakpoints 1406 and 1314 on trace native code instruction 116, which are located at edge 824 of a group 822 containing all trace native code instructions mapped by the method to a given statement or expression in the source code. In some implementations, the group contains only all trace native code instructions, and may also contain other instructions.
In some embodiments, the received trace replay execution control requests 806, 214, 414 are named, identified, or otherwise invoked according to one of the following: performing a forward step skip 906 operation to step forward skip a routine; performing a backward step skip 916 operation to step backward skip a routine; performing a forward step enter 904 operation to step forward enter a routine; or performing a backward step enter 914 operation to step backward enter a routine.
In some cases, the received trace replay execution control requests 806, 214, 414 name, identify, or otherwise invoke replay functionality according to the forward execution step-in 904 operation to step into a user code routine, and the replay execution of the user code routine includes the replay execution of at least one call 818 to a runtime routine 204, and the call to the runtime routine has no corresponding call statement or call expression in the source code. In this context, some embodiments include at least one of the following: setting 1408 to specify a breakpoint range designated as receiving the entire memory extent of the dynamically compiled code, or setting a breakpoint 1410 to perform a step-skip operation on the call to the runtime routine.
In some embodiments, the forward stepping into step 904 is performed as follows. The debugger 200, configured according to the teachings herein, maps the source line range 1306 to the intermediate language range and the intermediate language range 1308 to the native range. The debugger then performs this step using low-level primitives; this can be done using instruction-level single-stepping or breakpoints. When the call instruction 818 is encountered, the debugger determines whether the target is a high-level source step that indicates a stepping into at the source level, or a runtime implementation detail that should not be stepped into because it is not explicitly stated in the source code. For example, this determination can be done by querying the runtime or by searching for the name of the calling routine in the source code. If the call is for a different high-level (shown in the source code) routine, the debugger queries runtime 204 (e.g., via DAC 208) to determine whether the calling routine has been JIT-compiled. If the calling routine has been JIT-compiled, the debugger performs stepping into the call using instruction-level single-stepping or by setting a breakpoint inside the target routine to perform stepping into step 904. If the calling routine has not yet been JIT-compiled, the debugger will set breakpoints on the JIT compiler or on the target address region written by the JIT compiler using DAC 208 or another mechanism, with the JIT compilation using multiple data breakpoints. The debugger allows running a trace replay until the JIT compilation is complete. The debugger sets breakpoints on the JIT-compiled target and runs. This continues until native instructions no longer fall within the native step range mapped from the initial action, or the program exits. An exception is a special case that should fall on a catch target.
In some embodiments, the trace replay execution control request invokes at least one of the following operations: continue tracing replay execution forward 910 in the trace until breakpoint 828 is reached; continue tracing replay execution forward 910 in the trace until a position in breakpoint range 830 is reached; continue tracing replay execution backward 920 in the trace until breakpoint 828 is reached; or continue tracing replay execution backward 920 in the trace until a position in breakpoint range 830 is reached. Some embodiments also include other operations that may be invoked in the request, including one or more of, for example, performing a step-in backward 914 operation; performing a step-out backward 918 operation; performing a step-skip backward 916 operation; performing a step-in forward 904 operation; performing a step-out forward 908 operation; and performing a step-skip forward 906 operation. More generally, a given embodiment may be limited to any subset of the operations taught herein.
In some cases, during the execution of the managed program being traced to create trace 418, the maximum number of breakpoints is constrained by the hardware breakpoint constraint that the processor can monitor up to N addresses at a time. However, in some embodiments, the method sets more than N breakpoints during the replay execution of the trace, thus exceeding the hardware breakpoint constraint.
Those skilled in the art will understand that other methods are also within the scope of the teachings presented herein. In particular, other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any method of implementing control teachings using the teachings herein is within this disclosure, regardless of whether it is within the specific examples provided.
Examples of media configurations
Some embodiments include a configured computer-readable storage medium 112. Medium 112 may include a disk (magnetic, optical, or otherwise), RAM, EEPROMs or other ROMs, and/or other configurable memories, particularly computer-readable media (which are not merely for transmitting signals or energy). The configured storage medium may in particular be a removable storage medium 114, such as a CD, DVD, or flash memory. General-purpose memory (which may be removable or non-removable, and may be volatile or non-volatile) may be configured in embodiments to form the configured medium using items such as an execution controller 402, a playback adapter 408, an instruction set 822, a cross-level mapping 404, machine-level requests 414 and responses 416, and a breakpoint range 830, in the form of data 118 and instructions 116 read from the removable medium 114 and/or another source such as a network connection. As disclosed herein, the configured medium 112 is capable of causing a computer system to perform technical processing steps for horizontal cross-level (high-level in tool 122 to low-level in trace 418) playback execution control. Therefore, the accompanying drawings help illustrate the configured storage medium embodiments and process embodiments, as well as system and process embodiments. In particular, Figures 4, 13, or 14, or any other processing steps taught herein, can be used to help configure the storage medium to form the configured medium embodiment.
Some embodiments use or provide computer-readable storage media 112, 114 configured with code that, when executed by computer processor 110, performs a trace replay execution control method. In this example, the trace replay execution control method includes receiving a trace replay execution control request 1304 from a software tool running on a computing system. The method includes mapping 1306 between the source code of the traced managed program and an intermediate representation of the source code, and mapping 1308 between the intermediate representation and a trace 418, based on the trace replay execution control request. The trace 418 includes a record of processor activity, such as native code instructions traced when the traced managed program is executed, since the trace does not include any execution instances at runtime. In this example, the trace replay execution control method also includes executing 1312 trace native code instructions or other trace entries corresponding to the trace replay execution control request, or setting a breakpoint 1314 on the trace native code instructions to control the replay of traces traced by 1310.
Some embodiments operate in combination with debugger 200, and in some of these cases, the traced managed program includes a real-time process and an execution runtime 204. Without terminating the traced managed program at 1416, debugger 200 communicates with the execution runtime 204 of the traced managed program, and the method uses trace 418 to control 1310 to perform a backward replay. That is, in this example, reverse debugging is intertwined with real-time process debugging.
Some embodiments perform one, two, three, or all four of the following activities of particular interest. One particularly interesting activity is the execution of 204 at high-level control 1420 using machine-level information from trace 418. In this context, "high-level" control refers to control based on user selection 1426 (obtained from user 104 via a user interface) that specifies an identifier or statement or expression in the source code. In this context, "machine-level" information refers to processor architecture-specific information, such as a particular instruction set or a particular microarchitecture.
Another particularly interesting activity is the forward and backward execution of both the real-time debug objects 202 and 802 of the managed program being debugged by debug 200.
Another particularly interesting activity is stepping into the call shown in the source code, at least in part, by setting a large breakpoint range of 1434 to 1436. In this case, the breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in tracing 418.
Another particularly interesting activity is to simultaneously debug the real-time debug object 202 of the managed program being debugged (200), trace 418 trace data from the real-time process, and then use at least some of the trace data recorded to perform reverse execution debugging on the real-time process.
Those skilled in the art will understand that other configurations of media embodiments are also within the scope of the teachings of this invention. In particular, some other embodiments may include statutory media configured with code for performing cross-level mapping 404 at execution time, using breakpoint range 830, and implementing other teachings provided herein, while departing from the specific examples described herein. Media configured to perform methods using any execution control teachings taught herein are within the scope of this disclosure, regardless of whether they are in the specific examples provided.
Example with JIT code
Assume the source code includes classes similar to those in C#, as shown below:
If the language is C++, the developer would reasonably expect that the call to WiggleLeg() in Squid.Swim() can be compiled into the following form (similar to assembly code):
CALL 0x0c84fabd; 0x0c84fabd is the address of Squid::WiggleLeg().
In this scenario, 0x0c84fabd would begin implementing Squid::WiggleLeg(). However, this is not the case in managed software executed in runtime 204. Code executed in runtime 204 is compiled "just-in-time," also known as "jit." If this is the first call to Squid::WiggleLeg(), there will be no machine instruction 116 for Squid::WiggleLeg(). It has not yet been compiled. Therefore, instead of having the machine instruction implement Squid::WiggleLeg(), 0x0c84fabd would have some instructions that look something like this (in pseudocode):
This point in the code is called a "stub". The compilation process is lengthy and complex, so developers who typically try to analyze or debug their applications by tracing them often don't want to document the compilation process in detail. However, trace 418 may record at least a portion of the stub, even if the traced instructions are unlikely to be of interest to those debugging the code. In real-time process debugging, the runtime typically skips this part of the code. However, when debugging only from trace 418, the runtime 204 of the debugged object is not executed, so the stub cannot be skipped. Instead, one embodiment can leverage the functionality of an out-of-process debugging utility typically used to read data from dump file 302, and an innovative trace replay functionality that can be used together to find the address range of all JITTED code at runtime. Upon receiving a request to step into a method call, one embodiment can temporarily set a breakpoint 1314 on the JITTED code range and virtually execute forward (i.e., replay forward) until the first JITTED code range is read. Once read, the embodiment can remove the breakpoint. In this way, developers can skip all these uninteresting "stubs" of code. Some implementations further optimize the method by targeting the address range of the breakpoints to be limited to the range of `Squid::WiggleLeg_implementation`.
Some additional combinations and variations
Any combination of these combinations of code, data structures, logic, components, communications, and/or their functional equivalents may also be combined with any of the systems and their variants described above. A process may include any step described herein in any operable subset or combination or sequence. Each variant may appear alone or in combination with any one or more other variants. Each variant may appear with any process, and each process may be combined with any one or more other processes. Each process or combination of processes (including variants) may be combined with any of the media combinations and variants described above.
In some embodiments, the trace replay component uses source-IL mapping and IL-machine mapping to convert between the location in trace file 420 (e.g., indicated by timecode 424) and the location in source code 212 (e.g., indicated by line number).
In some embodiments, a portion of runtime functionality is provided in the trace replay component 406. However, instead of mediating between the debugger, user code, and operating system as in the real-time process of Figure 2, the runtime functionality mediates between the debugger and trace(s)420.
Some trace recording processes record only two types of data. One type of data is the execution of code instructions 116, which may be executed in parallel on multiple threads. The other type of data is a snapshot 304 of a specific block of memory taken at discrete points in execution time, such as to capture a portion of the stack. However, other trace processes record different or additional types of data, as shown in Figure 4. In some cases, the trace contains a valid representation of all recorded instructions and all their inputs and outputs. The recording of trace 418 can be made efficient by relying on the determinism of processor(s) 110 and primarily recording information that cannot be inferred from that determinism, as well as information already recorded in trace 418. In some implementations, most of trace 418 is data, rather than the executed code instructions; such data is often indeterminate. The trace can be primarily seed data plus indeterminate information. In some cases, only information entering the cache of the traced processor(s) is recorded in trace 418; for example, reading the value V into the processor cache is input into the trace, but writing the value V from a processor register to memory location X is not necessarily input into the trace. If a write operation to X behaves differently in terms of the traced program, it is because at some point the written value is returned from X to the processor register, at which point, if tracing is still enabled, the entry in trace 418 can be executed.
This document describes the execution control of a high-level program derived from a process tracing using examples, illustrations, definitions, and other descriptive materials. Technicians will recognize that process traces can be created at the machine level using various techniques, such as Windows Event Tracing (ETW) or "Time Travel Tracing" for systems running Microsoft environments, tracing for runtime environments (trademarks of Efficios, Inc. and Linus Torvalds, respectively), tracing for similar environments (trademarks of Oracle Corporation and X/Open, Inc., respectively), and other tracing techniques. The trace can then be replayed using hardware emulation. Sometimes, the process is written in a high-level language that requires a runtime framework to actually execute the process. One example is a .NET application running in the Common Language Runtime (CLR). Moving forward or backward in a trace is not helpful in itself to developers of high-level programs because the view of the trace is a view of the runtime or just-in-time compiled code, not a view of the high-level program. This document describes a method for mapping machine-level instructions in a trace to high-level operations in the program. This allows for setting and reaching breakpoints, as well as forward and backward stepping in high-level languages.
The process of stepping through the code at a high-level runtime can be achieved by abstracting the complexity into three layers. At the lowest level (level 0) is the process trace 418. This trace contains enough information to allow the recorded process execution to be simulated at the hardware level.
At level 1, a properly configured system can apply some very basic hardware debugging support for replaying traces. This support may include: the ability to play the process forward or backward, read the process memory, read the thread context (for each thread), set hardware breakpoints, and single-step machine instructions for each thread.
At level 2, support is provided for mapping the range of machine instructions to the range of higher-level virtual machine (VM) instructions or another type of code. Operations in level 1 can be used to debug higher-level code. In some configurations, the operations to be supported are forward, backward, setting breakpoints, stepping in, stepping out, and stepping skipping. Details of the implementation for each operation are given below in the examples.
Regarding forward and backward execution, in this example, they are equivalent in high-level and machine-level execution, so this is handled entirely at level 1.
Regarding breakpoints, in this example, breakpoints are set using a mapping defined in layer 2 to map higher-level breakpoints to hardware breakpoints. When a hardware breakpoint is encountered, the implementation can use this mapping to map that hardware breakpoint back to a higher-level breakpoint.
Regarding forward and reverse stepping exits, a hardware breakpoint can be set at the function's return address using stack tracing. To implement reverse stepping exit, the breakpoint is set on the instruction preceding the return address.
Regarding forward and backward step skipping, step skipping can be achieved by looking at the next instruction to be executed. Depending on the instruction, the implementation can use Level 1 to either perform single-stepping or set a breakpoint and run until it is reached. The "call" instruction is an example of an instruction that requires a breakpoint. Most other instructions can use single-stepping. Unlike some familiar approaches, this example debugger implementation can use mappings in Level 2 to repeat the stepping operation until the instruction pointer or code execution time point is at the appropriate stop point in the higher-level runtime. This inspires the discussion of instruction group 822 elsewhere in this paper.
Regarding reverse step-in, to perform reverse step-in, this implementation uses the single-step operation defined in Layer 1. If the machine has just returned from the calling instruction, this usage will return the execution time point to the return instruction of the previous call. If the machine has not just returned from the call, the machine will simply backtrack to the previous instruction. Similar to step-skip, the implementation can use the mapping in Layer 2 to know when execution is at a stop point, and may need to perform single-steps several times to align the trace with the source code 1318.
Regarding forward stepping, in this implementation, forward stepping is similar to reverse stepping. However, difficulties can arise if the higher-level runtime needs to perform work that is not directly related to the running higher-level code. Some examples are just-in-time (JIT) compilation, runtime housekeeping, and stepping operations that require some form of runtime resolution (transparent proxies in .NET are an example of this challenge). These difficulties can be addressed by implementing any or all of the following: One option is to set a large breakpoint range for all JIT-compiled code at the start of stepping. If the breakpoint is encountered after stepping, the implementation can complete the step when the next stopping point is reached. Another option is to implement logic in the stepping engine that fully understands the runtime, knowing when to skip calls and when to single-step through calls, allowing the implementation to stop stepping at appropriate points in the higher-level runtime.
In some embodiments, out-of-process execution control controls the execution of IL instructions by using, for example, the functionality provided by replay component 406 and IL-to-address mapping 812. The functionality provided by replay component 406 or other execution controllers 402, 408 for execution control includes:
Get the status (register values) of all threads.
Step forward or backward by one instruction
Run forward or backward until the instruction pointer reaches the specified address set.
The IL-to-address mapping exists in the memory image of the process or trace, and the replay layer can provide it to an off-process execution control debugger. One perspective suggests that this example involves converting IL-level debugging into machine-level debugging.
By stepping individual instructions, or by running forward and backward in the trace until a specific instruction address is reached, some implementations support the application of high-level execution control to the trace using source-to-IL mapping 810, IL-to-native mapping 812, native-style out-of-process execution control, and the ability to run forward and backward in the trace 418.
Consider examples of real-time process debugging.
As a further illustration of trace-based execution control, consider that certain embodiments may resemble or differ from real-time debugging. Several components are referenced below, and those skilled in the art will understand their relationship to other examples provided herein, and in particular, that functionality may be grouped into different components for ease of understanding or implementation without departing from the execution control teachings provided herein. The system 800 components discussed in this example include:
User Interface (UI). The user interface graphically displays a representation of the debugger's program state to the user. Examples of program state include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, the set of variables in each frame of the call stack, and the values of these variables.
Source translation. This part of the code translation is responsible for translating between runtime abstractions and source code-level abstractions. For example, the CLR runtime uses IL instructions encoded in binary file format to represent code, while C# source code has the syntax of text statements. As an example, this layer of the debugger can translate between runtime abstraction layers (e.g., those defined in ECMA-335, Common Language Architecture (CLI) version 6 (June 2012) or later) and C# abstraction layers (e.g., those defined in C# language specification version 5.0 or later).
Runtime translation. The runtime translation section of the debugger is responsible for translating between low-level concepts (such as memory and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, a call stack for each thread, and the IL instructions to be executed next. Note that the call stack at the abstract runtime layer does not have to be the same as the call stack at the abstract source code level. Only in the case of real-time debugging, this layer uses inter-procedural communication mechanisms to request the runtime within the process being debugged to perform work in order to assist with certain tasks. For example, to set a breakpoint at an IL instruction in method Foo at offset 28, this layer sends a message to the runtime requesting it to set the breakpoint at offset 28 of Foo. The thread within the runtime then receives the message, translates the Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. It is reasonable to consider the part of the runtime that serves those requests as functionally located within this layer of the debugger, even if it is implemented in a different process.
The basics. The low-level parts of the debugger are responsible for using the kernel, dump files, or traces to generate memory and registers that will be read by the runtime translation section. For kernel procedures, this is implemented in some environments via APIs such as ReadProcessMemory. For trace files, it supports parsing the file and establishing a mapping between time t and a set of memory and register contents recorded at that time.
Considering these components, consider the scenario where a breakpoint is set and the program is executed forward until the breakpoint is reached. One perspective suggests that real-time process debugging generally involves the following actions.
Action 1. User Interface. The user clicks the mouse on the displayed source code line to indicate where a breakpoint should be set.
Action 2. Source Transformation. Source code lines are transformed into specific method and IL instruction offsets.
Action 3. Runtime Translation. The message is sent to the runtime, where the method + IL instruction offset is translated into a memory address. Then, the breakpoint opcode is written to that address.
Action 4. User Interface. Users click buttons in the UI to indicate whether they want the process to run.
Action 5. Source Transformation. Forward the request to be executed.
Action 6. Runtime Translation. A message is sent to runtime 204, requesting it to proceed forward. Upon receiving the message, the runtime proceeds forward and then reaches the breakpoint at the previously set specific memory address. The breakpoint's memory address is translated back to the method and IL offset, and a notification message is then sent back to the debugger, indicating that the breakpoint at the specific method/IL offset has been reached.
Action 7. Source Transformation. The message indicating that the breakpoint has been reached is transformed from the method and IL offset back to the source line, and notifications about the breakpoint being reached at that source line continue to be sent to the UI.
Action 8. User Interface. The UI requests additional information about the new state of the process, allowing it to display current state information to the user, such as the current call stack for each thread.
Action 9. Source Transformation. To provide a source abstraction of the call stack, this component first requests a runtime abstraction that receives the call stack.
Action 10. Runtime Transition. To provide a runtime abstraction of the call stack, this component first requests to receive the state of memory and registers.
Action 11. Basics. Determine the memory and registers at the current time.
Action 12. Runtime Transformation. Using memory and registers, compute the runtime abstraction of the call stack.
Action 13. Source Transformation. Calculate the source code abstraction of the call stack using the runtime abstraction of the call stack.
Action 14. User Interface. Using the source code abstraction of the call stack, the UI can now display the current state of the process being debugged to the user.
In some embodiments, when using tracing actions 3, 6, and 11, the operation is no longer the same. For actions 3 and 6, no procedure can receive messages to set breakpoints, to advance execution, or to send back notifications when a breakpoint is reached. For action 11, no procedure can use the kernel API to query and determine memory or registers.
Therefore, in some embodiments, in order to achieve action 3 above, the source translation code requires the runtime translation code to indicate which memory address X has machine code for a given method + IL offset where a breakpoint should be set. This address X is saved for later use.
To achieve action 6 above, in some embodiments, the source translation code directly instructs the low-level base of the debugger or (multiple) other tools to advance the tracing to a new time t', where t' is the next time point where the machine instruction at address X will be simulated or emulated for execution. For action 6, one embodiment can use the same procedure typically used in dump debugging to translate from an IL offset to a procedure memory offset. However, this embodiment uses the translated memory offset to set a virtual breakpoint within the tracing replay engine. The virtual procedure (replay execution) stops when the replay engine reads this memory address during virtual execution. Indeed, if the tracing contains more than one version of the same functionality (via re-jitted), the runtime translation may require the tracing to provide multiple addresses to cover a single breakpoint. This address can be different for different time ranges in the tracing, or it can be the address of a runtime function (such as a jittering function) so that the runtime translation can locate the new re-jitted position of the function.
To achieve the above action 11, instead of reading from the real-time process, trace 418 is read and memory and registers corresponding to time t' are provided.
Replay debugging scene
By providing access to both forward and backward execution during debugging, system 800 can enhance debugging efficiency. For example, some embodiments support the following debugging scenarios.
By using context, technicians will realize that production debugging is difficult. Suppose a customer reports an issue on the website. How do developers debug it? Some familiar methods rely on information such as logs and dumps, which only provide point-in-time information. Therefore, if the problem doesn't reproduce or occur at the specific moment captured in the logs or dumps, developers must try again to capture useful information at different points in the execution, meaning it takes much longer to resolve the issue.
Instead, imagine an environment that can tell developers exactly what's happening in a production application, line by line. Using Microsoft Time Travel debugging or other reverse-execution replay implementations allows team members to collect a high-fidelity record of the application's behavior. Developers can then debug the application offline in a familiar environment, such as a Microsoft environment or other debugging or IDE.
As a concrete example, suppose the SmartHotels360 website is experiencing an issue; this is a demo website whose code is publicly available from Microsoft via GitHub.com. The developers of the company running the SmartHotels360 website receive a report from users indicating that a feature in BestHotels is no longer displaying data. However, it was working perfectly before, and the issue has not been reproduced in the company's test or staging environments. Members of the operations or engineering team have collected logs (trace 418) of the application while running the code powering the malfunctioning feature. Trace 418 can be collected into file 420 via command-line tools, or automatically triggered by a cloud environment (or another cloud environment) when certain conditions are met, such as throwing more exceptions than expected.
The developer opens the debugger and loads the SmartHotels360 code and trace file 420. Execution stops at a breakpoint on line 28 in the API that returns to BestHotels. Now, even though this is a log file, in this example, the developer can use many familiar commands to navigate it using a debugger they are typically familiar with. The developer wants to know what happened when the API was called. The developer steps over lines 28 and 29 and sees from the Locals window that after stepping over line 29, bestHotels has zero entries. If the debugger supports data hints, the developer can also view them, at least in this example.
Now, the developer has identified the cause of the problem in the `BestHotels()` routine. Therefore, the developer wants to investigate what happened in `BestHotels()`. Alternatively, to see what happened back to the original call, the developer could click Continue, click the breakpoint again, and step into the next call to `BestHotels()`, even though the values, objects, and memory addresses might differ from the partially debugged call. Alternatively, when the debugger state is difficult to reproduce, the developer could restart the application, which could be time-consuming. However, in this example, the environment supports time-travel debugging. Therefore, the developer uses the Reverse Continue button (requesting to continue backwards 920 operations) to rewind the application to the state of the previous breakpoint. One result of this rewind is that the locale will be reset to its previous state at line 28 before the aforementioned stepping is performed. Now, by ensuring that all values, objects, and memory addresses from the partially debugged call are the same, the developer can skip the `Load()` routine and step into `BestHotels()`.
At this point, the developer decides to step through `BestHotels()` and delve deeper into `GetBestHotels()`. Therefore, the developer wants to skip line 36 and then step into line 37. Suppose the developer accidentally pressed the skip button multiple times. Through time travel debugging, the developer can quickly go back and see what happened in `GetBestHotels()`. In fact, the developer can use the backstep button (requesting to step back into operation 914), which will take execution into `GetBestHotels()` and play it backward. The developer discovers that at the end of `GetBestHotels()`, the value of the local variable `bestHotels` (corresponding to the count) is zero. Clearly, all levels were filtered out.
Therefore, the developers decided to test the assumption by checking the ratings of all hotels. Remember, this trace occurred in production, so these values are actual. The developers can evaluate the expression using the debugger's live window, which is possible through the live debugging process. The developers evaluated the expression "AllHotels.Select(h => h.rating)" in the debugger's live window and found that the ratings were floating-point numbers, while the code was checking for rating values equal to integers 4 or 5. There was a data type mismatch; the shape of the data in production did not match the application's expectations.
Now suppose the developer has completed the debugging described above and wants to discuss it with a colleague and show them in detail what happened. The developer wants to start over at the beginning of the investigation and wants a way to quickly return to a specific point of interest. Therefore, the developer sets a breakpoint on line 21 and then rewinds to that breakpoint. Replaying then allows the developer to reproduce the debugging steps. If the developer wants to jump to the end, they can continue until they reach the last breakpoint they set.
In short, developers can use the application's high-fidelity tracing 418 to quickly debug issues, capturing what actually happened in production. With the power of a debugger adapted to the replay described here, developers can debug using a familiar debugger user interface and can debug forward and backward, saving significant developer time.
in conclusion
Although specific embodiments are explicitly shown and described herein as processes, configured media, or systems, it should be understood that the discussion of one type of embodiment generally extends to several other types of embodiments. For example, the process descriptions taken in conjunction with Figures 13 and 14 also help to describe the configured media and to describe the technical effects and operation of those similar systems and manufactures discussed in conjunction with the other figures. It is not necessarily required that limitations from one embodiment be read into another. In particular, processes are not necessarily limited to the data structures and arrangements presented when discussing systems or manufactures such as configured memory.
Those skilled in the art will understand that implementation details may relate to specific code, such as a specific API, a specific domain, and a specific sample program, and therefore may not necessarily appear in every embodiment. Those skilled in the art will also understand that program identifiers and some other terms used in discussing details are implementation-specific and therefore not necessarily related to every embodiment. Nevertheless, while their presence is not necessarily required herein, such details can assist some readers by providing context and/or can illustrate some of the many possible implementations of the techniques discussed herein.
References herein to an embodiment having some feature X, and references elsewhere herein to an embodiment having some feature Y, do not exclude embodiments having both feature X and feature Y, unless such exclusion is expressly indicated herein. All possible limitations of the claims are within the scope of this disclosure, as any feature that is prescribed as part of an embodiment may be expressly removed from some other embodiment, even if no specific exclusion is given in any example herein. The term “embodiment” is used herein only as a more convenient form of “process, system, article of manufacture, computer-readable medium of configuration and/or other example of the teachings herein applied in a manner consistent with applicable law.” Therefore, a given “embodiment” may include any combination of features disclosed herein, provided that the embodiment is consistent with at least one claim.
In each embodiment, not every item shown in the figures must be presented. Instead, an embodiment may include items not explicitly shown in the figures. Although some possibilities are illustrated herein by way of specific examples in the text and figures, embodiments may deviate from these examples. For example, specific technical effects or features of an example may be omitted, renamed, grouped differently, repeated, instantiated differently in hardware and/or software, or a mixture of effects or features appearing in two or more examples. In some embodiments, functionality shown in one location may also be provided in different locations; for example, those skilled in the art will recognize that functional modules can be defined in various ways in a given implementation without having to omit the desired technical effects from a collection of interactive modules considered as a whole.
The figures are referenced throughout the text using reference numerals. Any apparent inconsistencies in the wording related to a given figure reference in the figures or text should be understood as simply broadening the scope of the number referred to. Even when using the same figure reference, different instances of a given figure reference may refer to different embodiments. Similarly, given figure references...
It can be used to refer to verbs, nouns, and/or corresponding instances of each, for example, processor 110.
Instruction 110 can be processed by executing instructions.
As used herein, terms such as “an” and “the” include one or more of the indicated item or step. In particular, in the claims, a reference to an item generally means that there is at least one such item, while a reference to a step indicates at least one instance of performing that step.
The headings are for convenience only; information about a given topic can be found outside of the sections that indicate the subject in the headings.
All claims and abstracts submitted are part of the specification.
Although exemplary embodiments have been shown in the accompanying drawings and described above, it will be apparent to those skilled in the art that various modifications may be made without departing from the principles and concepts set forth in the claims, and such modifications do not necessarily encompass the entire abstract concept. Although the subject matter has been described in language specific to structural features and/or procedural actions, it should be understood that the subject matter defined in the appended claims is not necessarily limited to the specific technical features or actions described in the claims. Each means or aspect or technical effect identified in a given definition or example need not be presented or utilized in every embodiment. Rather, the specific features, actions, and effects described are disclosed as examples for consideration in implementing the claims.
To the maximum extent permitted by law, all changes that fall within the entire abstract concept but fall within the equivalent meaning and scope of the claims should be included within its scope.
Technical Field
Embodiments of this disclosure relate to execution control with cross-level tracking mapping.
Background Technology
Computer software is typically complex. Part of this complexity may stem from the nature of the work a program is designed to perform—for example, tracking a large number of real-world items or ongoing transactions over hours or longer, coordinating activities with other complex software, controlling complex hardware, and so on. Complexity also arises in almost any real-world use of software because many details are introduced and must be properly managed to instruct the computer hardware how to perform real-world work that would have been far less precise when initially described in English or another natural language. In other words, the conversion from a high-level description to a low-level implementation executable by a computer system inevitably introduces complexity. Even the source code of programming languages, which are more precise than natural languages, remains at a relatively high level and is therefore ambiguous, open to various interpretations and implementations. As the source code is translated into low-level instructions directly executable by computing hardware, many details are introduced and choices are made during the translation process.
Complexity introduces the possibility of commonly recognized programming errors (also known as "defects" or bugs). The process of identifying the cause of a defect and attempting to modify the program to remedy or remove its effects is called "debugging." Specialized software tools that assist in debugging are called "debuggers." The program being debugged is called a "debugging object."
Debugging is often easiest when developers can run a debug object at will, either slowly or at full speed, or pause its execution at will, and can inspect all its state information at any point during its execution. This is known as "real-time process debugging." However, such complete access to a debug object is often unavailable. For example, a debug object might be production software, which cannot be debugged in real-time without violating service agreements or harming the reputation, security, or financial condition of stakeholders. Pausing a real-time process debug object for even a few seconds at a time while a developer examines variable values, checks which functions are called with which parameter values, reviews source code, considers possible interpretations of defects, and designs tests that might help identify, remedy, or eliminate defects could cause unacceptable harm.
Therefore, state information is sometimes logged while the debug object is executing so that it can be examined later without essentially pausing the debug object's execution. Creating such a log may slow down the debug object, but it can provide useful information without compromising production performance goals as much as real-time debugging. For example, the debug object can be paused long enough to create a memory dump that copies some or all memory values associated with the debugger to disk at a specific point in time. Some aspects of the debug object's execution can also be logged in an execution trace. In cases where the debug object is not a real-time process, some debuggers support using such a trace to replay the traced execution of the debug object. Some debuggers allow the debug object's execution to be replayed forward or backward, enabling "time travel," "reverse," or "historical" debugging.
However, because execution traces may contain less information than is sometimes available during real-time process debugging, and because they record state information at a low level, technical challenges arise when debuggers or other software tools attempt to control replay execution (i.e., execution based on the recorded trace). Depending on the implementation, execution control operations that developers are familiar with and frequently use during real-time debugging may be less accurate or simply unavailable when attempted during trace-based replay.
Therefore, advancements in using low-level execution tracing to effectively and accurately achieve high-level execution control through debuggers or other replay or logging tools can help improve the information available to developers or automated performance monitoring tools. Consequently, such advancements will tend to improve the functionality of computer systems by supporting a more accurate understanding of their behavior and by enabling the mitigation or elimination of system defects.
Summary of the Invention
Some of the techniques described herein involve mapping locations in the program's source code to corresponding locations in the program's execution tracing, thereby improving the accuracy of execution control in tracing-based debugging. Some teachings involve specific breakpoint setting procedures that set one or more breakpoints at locations aligned with source code expressions or statements. Technical mechanisms for adapting to real-time debugging environments to support tracing-based reverse execution are described. Specific technical tools and techniques are described herein in response to the challenges of replaying debug object execution forward or backward or both forward and backward based on execution tracing. Other technical activities related to the teachings herein will also become apparent to those skilled in the art.
Some embodiments described herein use or provide trace replay execution control capabilities that utilize a processor, memory, traces recorded during the execution of a program at runtime, program source code, mappings between source code and its intermediate representations and traces, and an execution controller in a debugger or other tool. The runtime contains supporting code that provides dynamic compilation or memory garbage collection services as the traced program is executed and the trace is captured. A trace may include a record of native code instructions executed by the program. A trace may include a record of data accessed during program execution while the debug object is being executed. A trace may include one or more memory dumps or snapshots. A trace may be stored in one or more files or portions of non-volatile or volatile memory. The execution controller is configured to control the replay execution of the trace in response to a request from a tool. During replay, breakpoints configured to help align grouped native instructions with their corresponding source code entries are used, with the source code and trace native code instructions or other trace entries associated through source intermediate mappings and intermediate native mappings.
Some embodiments described herein use or perform computer-implemented trace replay execution control. The managed program being traced is identified. A managed program (also called a “runtime management” program) is a program configured to execute in conjunction with calls to the runtime. The managed program being traced is a program that is being traced or configured to be traced. A trace replay execution control request is received in a software tool. Based on the trace replay execution control request, a mapping is made between the source code of the managed program being traced and an intermediate representation of that source code, and another mapping is made between that intermediate representation and the trace. The trace does not include any execution instances of the runtime. Replay of the trace can be controlled by, for example, simulating the trace activity in a direction and number corresponding to the trace replay execution control request (e.g., taking a step forward, or repeating the entire routine by stepping over it), or by setting breakpoints at the trace locations, or by performing both of the above.
The examples given are merely illustrative. This "Summary" is not intended to identify key or essential features of the claimed subject matter, nor is it intended to limit the scope of the claimed subject matter. Rather, this "Summary" is provided to introduce some technical concepts in a simplified form, which will be further described in the "Detailed Description" below. The invention is defined by the claims, and in the event of any conflict between the Summary and the claims, the claims shall prevail.
Attached Figure Description
A more specific description will be given with reference to the accompanying drawings. These drawings are only illustrative of selected aspects and therefore cannot fully define the coverage or scope. Although dashed lines indicate that some items are optional, any item recited in the claims or any item that a person skilled in the art would consider non-optional for embodying the claims should be understood to be present in some form in an embodiment of the claims.
Figure 1 is a block diagram showing a computer system and also showing the configured storage media;
Figure 2 is a block diagram illustrating aspects of real-time process debugging;
Figure 3 is a block diagram illustrating aspects of debugging based on a copy of the memory made at a single point in time;
Figure 4 is a block diagram illustrating aspects of an example architecture for trace-based debugging, including the main request and response between the debugger and the replay adapter;
Figure 5 is a block diagram showing various memory cells that can be referenced during debugging or in tracing;
Figure 6 is a block diagram illustrating a machine-level request that can seek information from the execution trace or impose execution control during the replay of the execution trace.
Figure 7 is a block diagram illustrating the response to a machine-level request;
Figure 8 is a block diagram illustrating an example tracking replay execution control system;
Figure 9 is a block diagram illustrating some of the control operations performed during the tracking and replay process;
Figure 10 is a block diagram illustrating some aspects of thread tracing data;
Figure 11 is a block diagram illustrating some aspects of one or more intermediate representations;
Figure 12 is a block diagram illustrating some aspects of a real-time process debugging environment adapted to use traces that support reverse execution debugging;
Figure 13 is a flowchart illustrating an example trace replay execution control method; and
Figure 14 is a flowchart further illustrating some of the tracking replay execution control methods.
Detailed Implementation
Overview
Debugging in a production cloud environment presents significant technical challenges. For example, suppose a specific request R for an online shopping cart is not working. How can developers debug the processing of request R without slowing down the processing of all other requests and minimizing the slowdown in the processing of request R? To find the defect, developers use information about what is happening internally in the code, such as a way to look at the values of variables at one or more points of interest during the processing of request R.
The trace-based debugging innovations discussed here help overcome technical challenges that traditional methods cannot solve. For example, many traditional debuggers and debugging methods allow developers to set halt breakpoints to obtain information about variable values. A halt breakpoint is an instruction to pause execution, giving developers time to examine memory contents at a given point in processing and consider possible interpretations of what is observed. However, in a production environment, halt breakpoints may pause the processing of a large number of requests, cause requests to fail completely (e.g., timeout), or cause execution to take a different path—none of which are desirable. Even pausing only a single thread can lead to unwanted aborted requests and produce unpredictable side effects that hinder debugging, degrade performance, or both.
Some familiar debugging methods involve adding print statements at specific points in the code to print the value of a particular variable, or adding other code, for example, to test the value of a variable to see if it is the value the developer expected at that point in the code. However, these methods may require recompiling and redeploying the code, which is undesirable in production environments, especially if recompiling and redeploying are to be done multiple times as part of an iterative debugging process to find and fix individual defects.
Developers can inject operations into request handling code at execution time to create a copy of some or all of the memory relevant to the request. This copy can include a "snapshot" 304 (an in-memory copy of a process that shares memory allocation pages with the original process via copy-on-write) or a "dump" file 302 (a serialized copy of the process), or both. Some traditional debuggers can read dump files or snapshots and, given appropriate metadata, present the memory contents in a specific format that shows variable values converted from binary to an informative structure including variable names and displayed based on the variable's corresponding data type. However, dumping memory to a file is time-consuming, slowing down not only request R but also the processing of all requests in the example scenario. While taking a snapshot is much faster than creating a dump file, it can require many attempts by the developer to find useful points in the processing to obtain a memory snapshot that reveals the defect, and snapshots consume space in RAM. To view memory at another point in time other than execution time, captured in a dump file or snapshot, another copy of the memory can be created.
Real-time processes are used to view memory at any point in time during the real-time process. In many modern computing systems, as illustrated in the example in Figure 2, the real-time debug object 202, in addition to depending on the operating system, also includes a runtime 204. The runtime 204 provides garbage collection or dynamic code compilation (i.e., JIT compilation or compilation of intermediate language code) or both. Garbage collection may utilize object reachability analysis, object reference counting, or other strategies. Some configurations include an interpreted runtime 204, and those skilled in the art will recognize that the teachings herein can be applied to exercise execution control over the interpreted runtime by overlaying the interpreter's view onto the native trace and using breakpoints within the interpreter itself. Additionally, some runtimes (e.g., runtimes) do not always JIT compile their IL representation (what Java terminology calls "bytecode"). Instead, the runtime may choose to interpret bytecode for less frequently used functions. In this case, execution control may be exercised over the runtime code itself, and a mapping may be made from native code to internal runtime data structures to IL to source code. The mapping from native code to internal runtime data structures to IL can be considered an example of an intermediate native mapping 812, and the mapping from IL to source code can be considered an example of a source intermediate mapping 810.
Unlike processes lacking runtime capabilities, which can be directly controlled by the debugger through the insertion of pause breakpoints, runtime-dependent processes cannot be directly controlled by the debugger 200 because their runtime is effectively hidden from the debugger's memory entries 206, such as memory locations, memory contents, and instruction pointers. To show the developer what is in memory during debugging, the debugger sends a main request 214 to the runtime requesting the current memory values. The runtime sends these values back to the debugger in a main response 216, and the debugger displays the values it received in the response message in a user interface 210.
As a specific example of the drawbacks of the previous approach, consider runtime 204, which is implemented as a virtual machine executing intermediate language (IL). IL code cannot be easily debugged using a traditional native code debugger because that debugger is intended for debugging the virtual machine/runtime, not the IL code.
The runtime also controls the execution of the real-time debug object. Traditional debuggers for IL or languages that compile to IL work by establishing a communication channel between the debugger and the runtime inside the debug object. The runtime within the debug object performs most of the work required to provide the debugging experience. In one example, to set a breakpoint at offset 28 in the intermediate language (IL) instruction in method Foo, a message is sent to the runtime requesting it to set the breakpoint at offset 28 in Foo. The thread within the runtime then receives the message, translates Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. Similarly, to perform familiar execution control operations, such as stepping, stepping in, stepping out, and stepping skipping, the debugger sends a main request 214 to the runtime requesting the operation. The runtime 204 performs the operation and sends an updated status to the debugger in a main response 216, and the debugger displays the result indicated in the response message in a user interface 210.
User interface 210 graphically displays to the user a representation of the debugger's debug object program state. Examples of program states include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, a set of variables in each frame of the call stack, and the values of these variables. The user interface may include windows displaying local data of the routine, watched variables and their values, source code, expression evaluators, and other information about the live debug object 202.
In some implementations, the runtime translation section of debugger 200 is responsible for translating between low-level concepts (such as memory units and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, one or more call stacks for each thread, and the IL instructions to be executed next. Note that the call stack of the abstract runtime layer is not necessarily the same as the call stack at the abstract source code level; for example, the virtual machine's call stack may not match the virtual call stack of the IL code being executed within the virtual machine.
Creating an execution trace 418 of the process is possible. The trace can then be replayed using a simulation of the computer system 102. Sometimes, the trace process is written in source code 212, a high-level language that needs to be executed by the runtime 204 in real-time debugging object 202. The trace itself can be difficult to debug because the trace data reflects a view at a low level (e.g., runtime or just-in-time compiled code or both), rather than the high-level language in which the program was written. Some tracing techniques do not provide a high-level view of the process that the user 104 might prefer. Most high-level runtimes require the runtime itself to provide information about the program running within its framework. Therefore, regular debugging may require the process to be executed within the runtime, which is not optional when debugging is based on a trace rather than a real-time process.
Like any other process, runtime can be traced. However, debugging software other than runtime is more common than debugging runtime. The tracing process can include or exclude tracing some or all of the code that is part of the runtime itself.
This functionality does not apply to situations where there is no trace file currently running. To control the execution of a live process that is executing code that depends on a runtime 204 error, the debugger can send a message to the runtime requesting an action such as "step" or "run," which the runtime then performs on behalf of the debugger.
The ability for a debugger to send messages to the runtime to perform actions on behalf of the debugger does not apply to trace files for which there is no currently executing runtime. Dump files 302 and snapshots 304 are similar to traces in that the runtime is unavailable. A runtime can be represented as a dump, snapshot, or trace, but it is not currently executing and therefore cannot be invoked in the traditional way.
Nevertheless, the trace file 420 can be made part of the debugging environment. Some trace-based debugging embodiments discussed here extend debugging power, allowing the debugger to replay execution from the trace file, starting from one or more points in execution time chosen by the developer, and then moving forward or backward in increments chosen by the developer within the trace execution. One approach is to insert a replay layer between the trace and a high-level language debugger. The replay layer understands runtime execution control messages, thereby allowing high-level control over the traced process.
In some cases, developers can use a "time travel" debugger to control execution replay, running forward or backward in execution time as the recorded trace 418 is replayed. This leverages the debugger's ability to present program state information and memory, such as instruction pointers (multiple), in useful high-level (e.g., named and data-data-based) variable representations, not only for snapshots as before but now for continuous replays of segments of execution time recorded during code execution. Debugging can be made more efficient by aligning grouped trace data with corresponding source code structures (such as expressions and statements). Developers can examine memory values captured in the trace at multiple points in a high-level representation based on the low-level data recorded in the trace file.
As the trace is replayed, the included replay layer can be used to control the state of the debug object. With this adaptation, debugger 200 can apply a runtime (high-level) view of the process trace that has been recorded as machine-level operations. For the purposes of this application only, "machine-level" operations are operations specified at the machine-specific level. Generally, "native" and "machine-level" are used interchangeably herein relative to instructions or code.
Some may view some of the embodiments described herein in a broader context. For example, concepts such as controlled execution, recorded execution, and replaying recorded execution may be considered relevant to specific embodiments. However, this does not accord with the availability of a broad context and seeks proprietary rights to abstract concepts; they are not. Rather, this disclosure focuses on providing suitable specific embodiments whose technical effects fully or partially solve specific technical problems, such as how to automatically associate high-level control requests with machine-level tracing, and other problems addressed herein. Other media, systems, and methods relating to controlled execution, recorded execution, or replaying recorded execution are not within the scope of this invention. Thus, ambiguity, mere abstraction, lack of technical features, and the associated problems of proof are also avoided upon proper understanding of this disclosure.
Technical features
The technical features of the embodiments described herein will be apparent to those skilled in the art and will also be apparent to various interested readers in a variety of ways. Some embodiments address technical activities rooted in computing technology and improve the functionality of computing systems by aiding in debugging these systems, thereby improving system uptime, system accuracy, and power utilization relative to the computational results produced. For example, some embodiments provide system debuggability functionality that helps reduce the amount of time developers spend locating defects while debugging by allowing replay execution to move backward to the desired point rather than restarting from the beginning of execution and moving forward to that point. Some embodiments improve system debuggability by accurately aligning trace data with corresponding source code statements. Some embodiments provide additional debugging functionality in the system, such as the ability to set breakpoint address ranges instead of setting breakpoints at one address at a time.
Some embodiments include technical components, such as computing hardware, that interact with the software in a manner that goes beyond typical interactions within a general-purpose computer. For example, in addition to general interactions (such as general memory allocation, general memory reads and writes, general instruction execution, and some form of I/O), some embodiments described herein also implement backward step-out replay operations as disclosed herein.
Some of the technical effects provided by the embodiments include: more efficient use of debugging time, reduced re-tracing to obtain additional trace data, and improved debugger functionality for exploring defect causality.
Some embodiments include technical adaptations. Some embodiments include a replay layer adapter that accepts requests formatted for runtime, i.e., in a message format compatible with familiar debugger runtime communication, and responds to these requests in a format that can be used by the runtime during real-time debugging. In some embodiments, the replay adapter provides an interface that hides the differences between real-time process debugging, dump-based debugging, and time-travel tracing-based debugging. Some embodiments include a mapping between source code, intermediate representations(s), and trace data.
From the provided description, other advantages of the technical features based on the teachings will also be apparent to those skilled in the art.
Acronyms and Abbreviations
The following defines some acronyms and abbreviations. Other abbreviations may be defined elsewhere in this document, or may not require any definition and will be understood by those skilled in the art.
ALU: Arithmetic and Logic Unit
API: Application Programming Interface
BIOS: Basic Input/Output System
CD: Compressed disc
CPU: Central Processing Unit
DAC: Data Access Component
DVD: Digital Multifunction Disc or Digital Video Disc
FPGA: Field Programmable Gate Array
FPU: Floating-point processing unit
GPU: Graphics Processing Unit
GUI: Graphical User Interface
IDE: Integrated Development Environment, sometimes also called an "interactive development environment".
IL: Intermediate Language
OS: Operating System
RAM: Random Access Memory
ROM: Read-Only Memory
Additional terms
Reference is made herein to exemplary embodiments such as those shown in the accompanying drawings, and specific language is used to describe them. However, changes and further modifications to the features illustrated herein, as well as additional technical applications of the abstract principles illustrated by specific embodiments herein, that may occur to those skilled in the art, should be considered within the scope of the claims.
The meanings of the terms are stated in this disclosure, and these statements should be carefully considered when reading the claims. Specific examples are given, but those skilled in the art will understand that other examples may also fall within the meanings of the terms used and within the scope of one or more claims. The terms herein do not necessarily have the same meaning as they do in their general use (especially in non-technical use), in a particular industry, or in a particular dictionary or encyclopedia. Reference numerals may be used with a variety of wording to help indicate the breadth of the terminology. Omission of reference numerals from a given text does not necessarily mean that the text does not discuss the figures. The inventors claim and exercise their rights to their own lexicographical compilations. Terms in quotation marks are explicitly defined, but may also be implicitly defined without quotation marks. Terms may be defined explicitly or implicitly in the “Detailed Description” and/or elsewhere in the application.
As used herein, "computer system" can include, for example, one or more servers, motherboards, processing nodes, laptop computers, tablets, personal computers (portable or non-portable), personal digital assistants, smartphones, smartwatches, smart bracelets, cellular or mobile phones, other mobile devices having at least a processor and memory, video game systems, augmented reality systems, holographic projection systems, televisions, wearable computing systems, Internet of Things nodes, and/or other devices that provide one or more processors that are at least partially controlled by instructions. Instructions may take the form of firmware or other software in memory and/or dedicated circuitry.
A "multithreaded" computer system is a computer system that supports multiple threads of execution. The term "thread" should be understood to include any sequence of instructions that can be performed or scheduled (and possibly synchronized), and may also be referred to as, for example, as a "procedure" or "coroutine". Threads can run in parallel, sequentially, or in a combination of parallel execution (e.g., multiprocessing) and sequential execution (e.g., time-sliced).
A processor is a unit for processing threads, and is the core of implementations such as simultaneous multithreading. Processors comprise hardware. A given chip can contain one or more processors. Processors can be general-purpose or customized for specific purposes, such as vector processing, graphics processing, signal processing, floating-point arithmetic, encryption, I/O processing, etc.
The "kernel" includes the operating system, virtual machine monitor, virtual machine, BIOS code, and similar hardware interface software.
"Code" refers to processor instructions, data (including constants, variables, and data structures), or both. "Code" and "software" are used interchangeably in this document. Executable code, interpreted code, and firmware are some examples of code. Code that is interpreted or compiled for execution is called "source code."
The term "program" is used extensively in this article to include applications, kernels, drivers, interrupt handlers, firmware, state machines, libraries, and other code written by programmers (also known as developers) and/or automatically generated.
"Service" refers to consumable programs provided in a cloud computing environment or other network environment.
An "execution time point" refers to a specific point in time that is executed for a processing unit or thread, especially in relation to tracing execution. References to "specific execution time" or "execution time t" in this document refer to execution time points. For example, an execution time point can be implemented as a timecode variable or timecode value, or as a relative position in other records of tracing or execution activity. An execution time point ta "earlier than" or "later than" an execution time point tb indicates that the relative order of the two execution time points is determined. Similarly, a "younger" execution time point is a later execution time point than an "older" execution time point.
Information regarding the order of events in a tracing may be incomplete. Therefore, a tracing may have enough information to determine that event A precedes event B, or that event D follows event C. However, the relative order of events may also be partially or completely uncertain, even when considering a tracing. A tracing may show that event E does not follow event F, but this does not necessarily mean that E precedes event F; similarly, without a tracing also showing that K follows J, a tracing may show that event K does not precede event J. A tracing may also lack sufficient information to establish any order of two specific events relative to each other.
A "timecode" represents a monotonically changing value that can be used to impose order on at least some events in an execution tracing. It can be expected that timecodes are typically monotonically increasing values, but they can also be implemented as monotonically decreasing values. Some examples of timecodes include instruction counters, clock times (also known as clock ticks), and completely artificial (not register- or instruction-based) monotonic values. Depending on the tracing, all or some, or no, of the traced events may have corresponding associated timecodes. When timecodes exist, they can be unique, or they may simply be monotonic due to some timecode values being repeated.
A "memory cell" refers to an addressable unit of memory. Examples include bytes or words in RAM or ROM, processor registers, cache lines, and other addressable memory cells.
An emulator performs a simulation that provides the same functionality as the original hardware, but uses a different implementation or different hardware, or both. An example is a CPU emulator, which functions similarly to a CPU and can be used to execute code like the original CPU hardware, but with a different implementation; for example, the emulator can run on completely different physical hardware.
Unless otherwise stated, as used herein, “include” allows for additional elements (i.e., include means contain).
"Optimization" means improvement, not necessarily perfection. For example, an already optimized program or algorithm can be further improved.
For example, the term "process" is sometimes used herein as a term in the field of computer science and, in a technical sense, encompasses users of computational resources, namely coroutines, threads, tasks, interrupt handlers, application processes, kernel processes, procedures, and object methods. "Process" is also used herein as a term in patent law, for example, when describing process claims in contrast to system claims or claims of articles of manufacture (configured storage media). Similarly, the term "method" is sometimes used herein as a technical term in the field of computer science (a "routine") and also as a term in the field of patent law ("process"). Those skilled in the art will understand the meaning intended for use in particular contexts and will also understand that (in the sense of patent law) a given claimed process or method can sometimes be implemented using one or more processes or methods (in the sense of computer science).
Contrary to the absence of automation, "automatically" refers to the use of automation (e.g., general-purpose computing hardware configured by software for the specific operations and technical effects discussed herein). In particular, steps performed "automatically," while potentially initiated or interactively guided by a human, are not manually executed on paper or in the human mind. Automated steps are performed by machines to achieve one or more technical effects that would be impossible without such technological interaction.
Those skilled in the art will understand that technical effects are the presumptive purpose of technical embodiments. For example, the fact that an embodiment involves computation, and that some computations can also be performed without technical components (e.g., by paper and pencil, or even as mental steps), does not eliminate the presence of technical effects or alter the specificity and technical nature of the embodiment. Operations such as searching trace data at a sufficiently fast speed to allow replay within one or two orders of magnitude of the original execution speed, and computations for grouping native instructions for the trace and aligning instruction groups with corresponding source code items, should be understood herein to require, in addition to their inherent digital nature, a speed and accuracy unattainable by human thought processes (human thought cannot directly interface with trace files or other digital storage to retrieve necessary trace data). This is well understood by those skilled in the art, but others may sometimes benefit from being informed or reminded of the facts. Unless otherwise stated, contrary to mere thought experiments, embodiments are assumed to be capable of large-scale operation in a production environment or a test laboratory within a production environment.
"Computationally" also implies the use of computing devices (at least a processor and memory) and excludes results obtained solely by human thought or action. For example, performing arithmetic with paper and pencil, as understood herein, is not computationally arithmetic. Computational results are faster, broader, deeper, more accurate, more consistent, more comprehensive, and/or provide technical effects beyond the reach of human performance. A "computational step" is a step performed computationally. Neither "automatically" nor "computationally" necessarily means "immediately." "Computationally" and "automatically" are used interchangeably in this document.
"Actively" means without a direct request from the user. In fact, the user may not even be aware that an active step in an embodiment is possible until the result of the step has been presented to the user. Unless otherwise stated, any computational and/or automatic steps described herein may also be performed actively.
Throughout the document, the optional phrase "(multiple)" is used to indicate the presence of one or more of the indicated features. For example, "(multiple) processors" means "one or more processors" or equivalently "at least one processor".
For purposes of U.S. law and practice, the use of the term “step” in the claims or elsewhere herein is not intended to invoke means plus function, steps plus function, or to require interpretation under 35 U.S.C. 112(6)/112(f). Any presumption of such effect is hereby expressly rejected.
For the purposes of U.S. law and practice, claims are not intended to invoke a means-plus-function interpretation unless the phrase “means for…” is used. Claim language intended to be interpreted as means-plus-function language (if any) will explicitly state this intention by using the phrase “means for…”. When a means-plus-function interpretation is adopted, whether by using “means for…” and/or by the court’s legal interpretation of the claim language, the means listed in the specification for a given noun or given verb shall be understood to be linked to the claim language and hereby linked in any way that: appears in the same box in the drawing block diagram, is denoted by the same or similar name, or is denoted by the same reference numerals. For example, if a claim limitation refers to “zac widget” and that claim limitation is subject to a means-plus-function interpretation, then all structures identified anywhere “zac widget” is mentioned in any block, paragraph, or example in the specification, or bound together by any reference numerals assigned to the zac widget, shall be considered part of the structures identified in the zac widget application and contribute to defining the equivalent itemset of the zac widget structure.
Throughout this document, unless otherwise expressly stated, any reference to a step in the process is assumed to be that the step can be performed directly by the interested party, and/or indirectly by a party through an intervention mechanism and/or intervention entity, and still within the scope of that step. That is, unless explicitly stated as directly performed, the step does not need to be performed directly by the interested party. For example, steps involving actions performed by the interested party concerning a destination or other subject, such as alignment, clearing, compiling, continuing, controlling, debugging, simulating, encountering, exceeding, executing, acquiring, grouping, identifying, mapping, receiving, recording, replaying, requesting, responding, sending, setting, specifying, stepping (and variations such as stepping in, stepping out, stepping skipping), terminating, tracing (and alignment, aligned, clearing, cleared, etc.), may involve intervention actions performed by another party, such as forwarding, copying, uploading, downloading, encoding, decoding, compressing, decompressing, encrypting, decrypting, authenticating, invoking, etc., but should still be understood as being performed directly by the interested party.
Whenever data or instructions are referenced, it should be understood that, for example, these items configure computer-readable storage memory and/or computer-readable storage media to convert them into a particular article, as opposed to simply existing on paper, in a person's mind, merely energy, or merely a signal propagating on a wire. For the purposes of U.S. patent protection, according to the interpretation of the U.S. Patent and Trademark Office (USPTO) in the re Nuijten case, memory or other computer-readable storage media is not a propagation of a signal, carrier wave, or merely energy outside the scope of the patentable subject matter. In the United States, no claim covers the signal itself, and any claim interpretation that asserts the contrary is unreasonable. Unless expressly stated otherwise in a claim granted outside the United States, the claims do not cover the signal itself.
Furthermore, although there are obvious contrary provisions elsewhere herein, it should be understood that there is a clear distinction between (a) computer-readable storage media and computer-readable repositories and (b) transmission media (also referred to as signal media or energy-only). A transmission medium is a computer-readable medium or energy-only that propagates a signal or carrier wave. Conversely, computer-readable storage media and computer-readable repositories are not computer-readable media that propagate a signal or carrier wave. Unless expressly stated otherwise in the claims, “computer-readable medium” means computer-readable storage media, not the propagation of a signal itself, nor energy-only.
The term "example" in this document is illustrative. The term "example" is not to be used interchangeably with "invention." Examples may be freely shared or borrowed to create other examples (provided the result is operable), even if the resulting combinations of aspects are not explicitly described herein. It is necessary for a person skilled in the art to perceive that every licensed combination is essential, contrary to the policy of acknowledging that patent specifications are written for those skilled in the art. Formal calculations of combinations and informal intuition regarding the number of possible combinations, even those arising from a small number of composable features, will indicate that there are numerous combinations of aspects described herein. Therefore, requiring an explicit description of each combination contradicts the policy of requiring a concise patent specification and demanding knowledge of the relevant technical field from the reader.
List of reference numerals
The following list is provided for convenience and support of the accompanying drawings and as part of the specification text, which describe innovations by referencing multiple items. However, items not listed herein may still be part of a given embodiment. For clarity and readability, the given reference numerals are cited near some (but not all) of the referenced items in the text. Different examples or instances of the given items may use the same reference numerals. The list of reference numerals is:
100: Operating environment, also known as computing environment
102: Computer system, also known as computing system or computing architecture.
104: User
106: Peripheral equipment
108: Generally refers to the internet.
110: Processor
112: Computer-readable storage media, such as RAM, hard disk
114: Removably configurable computer-readable storage media
116: Processor-executable instructions; may be on removable media or in other memory (volatile or non-volatile or both).
118: Data
120: (Multiple) kernels, such as (multiple) operating systems, BIOS, device drivers.
122: Tools, such as antivirus software, profilers, debuggers, editors, compilers, interpreters, security penetration testers, obfuscators, automated performance monitoring tools, etc., can be adapted to use the execution control taught in this article.
124: Applications, such as word processors, web browsers, spreadsheets
126: Display screen
128: Computing hardware, not otherwise associated with reference numerals 106, 108, 110, 112, 114.
200: Debugger, also referring to debugging activities.
202: Real-time debugging of object programs or procedures
204: Runtime, such as the Common Language Runtime, a virtual machine, or other virtual machines that dynamically translate code for execution (trademark of Oracle U.S., Inc.)
206: Memory items, such as application or system data structures.
208: Data Access Components for the Debugger
210: Debugger User Interface
212: Source code, related information such as metadata and symbol tables.
214: A master request from the debugger for information about a source of debug object, such as a live debug object, dump file reader software, snapshot reader software, or trace file reader software.
216: A response to a master request that seeks information from a debug object's information source or state change; also known as a "master response," such as in a response at the abstraction level of the master request, rather than in a first, initial, or most important response.
218: Statements in source code; for example, they can be explicitly delimited by semicolons or parentheses, curly braces or square brackets, or implicitly delimited by spaces or end-of-line characters.
220: An expression in the source code; syntactically defined by the programming language used; it can be an assignment of function calls, object member assignments, routine calls, or another combination of constants, variables, operators, and routines that produce a result or side effect.
302: Dump file, also known as a storage dump; may include additional information such as indexes or metadata.
304: Storage snapshot; may include additional information such as indexes or metadata.
402: Execution control code for a debug object in the debugger, such as requesting or simulating execution control over the debug object, including stepping through the debug object, setting breakpoints, or executing the debug object until a breakpoint is reached.
404: Cross-level mapping in debuggers or other tools, such as mapping between source code and intermediate representation or mapping between intermediate representation and trace data.
406: A replay component that uses trace files to simulate the execution of a debug object; the trace replay component 406, alone or in conjunction with other execution controllers 402, 408 (implementation-dependent), uses traces to simulate the execution of the original process and allows viewing of CPU state and memory units over time; in some embodiments, this simulation can be performed forward or backward.
408: A replay adapter for the replay component, which allows the replay component to send requests and receive responses that are also used during real-time debugging. In a trace file debugging scenario, the replay layer (i.e., the replay component plus the replay adapter) receives and responds to main requests from the debugger, which can be received and responded to by the runtime in the real-time debugging scenario, and the replay adapter can also make secondary requests to the trace file.
410: Replay adapter interface; configured for communication with the debugger.
414: A secondary request for the trace from the replay adapter, where “secondary” indicates a lower level of abstraction than the main request 214; the secondary request may be a machine-level request, which may be implemented as communication to the trace file reader, or it may be implemented internally within the replay adapter (e.g., as a function call).
416: A response to a machine-level request that seeks information from the trace; also known as a "secondary response," as in the response at the abstract level of the secondary request, rather than as in the second response; it can be implemented as communication from a trace file reader or internally within a replay adapter (e.g., as a function result or data structure update).
418: Performing a trace; Although the dashed lines in Figure 4 indicate that a given trace may include individual items or omit individual items, this document assumes that the trace is not empty, and therefore it is shown as a solid line over the box that generally tracks data 454; 418 can also refer to the activity of creating a trace, which is sometimes also called a “trace” or “record”.
420: A trace file containing execution trace data; this may include machine-level trace data, i.e., data that records execution activities at the native code level.
422: Precise tracking data during tracking.
424: A timecode in a trace that identifies a specific point in time during the execution of the traced code; it may be linked to or embedded in other data within the trace, for example, trace data that explicitly states the point in time at which the stated operation is associated with the stated memory address relating to the stated data value; the timecode may be implemented as, for example, a clock tick or an instruction counter; for each recorded operation, some traces may contain a unique timecode, but in some trace data, the timecode may be repeated or omitted.
428: Gap in the timecodes of a trace, used to explicitly or implicitly indicate the execution time points in which tracing was not performed (e.g., a range when tracing is disabled for a thread or processing unit). This can include any gap where adjacent timecodes differ by a default value or a specified increment (typically 1), for example, the gap for timecode sequences 2, 3, 4, 300, 301, 302 is between 4 and 300, and the gap for timecode sequences 250, 500, 750, 1000, 2000, 2250, 2500 is between 1000 and 2000.
430: Indexes to data in the trace file, such as reverse lookup data structures, used to quickly identify trace attributes, memory lifetime index information, and other searchable lists of locations in the trace data that may be of particular interest.
432: Keyframes in tracking data; for example, they may exist at fixed intervals in the tracking data to allow for faster replay jumps to (or near) keyframes during tracking playback.
434: The code executed, such as the opcodes and parameters of the debug object's machine-level code executed by the processor while the debug object is running and being traced.
436: Stack activity that occurs while the object being debugged is running and being traced, such as stack growth, stack shrinkage, and the execution time at which this activity occurs.
438: Data stream; can correspond to a single thread or a group of threads, can correspond to a processor unit (e.g., a processor core); can correspond to all cores in a given processor socket; can be annotated with metadata to aid in replay.
440: Processor core activities that occur while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by the core.
442: Processor socket activity that occurs while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by any core located in a given processor socket.
444: Thread activity that occurs while the debug object is running and being traced, such as instructions executed during thread runtime, memory accesses performed during thread runtime, and associated metadata such as thread IDs and timestamps.
446: Register activities that occur while the debug object is running and being traced, such as what value is read from which register at what timecode, and what value is written to which register at what timecode.
448: Memory address
450: Instruction opcode
452: Data value
454: Generally refers to tracking data.
456: A tuple, i.e., two or more items of trace data associated in a trace, representing the same operation during trace execution; for example, a memory read operation or a memory write operation may be recorded as a tuple on a single line in the trace, which contains or otherwise associates the opcode (e.g., read or write), the address (e.g., RAM address or register ID), and the data value that has been read or written together.
458: Tracking entry
502: Memory unit, such as a byte or word in RAM or ROM, processor register, cache line, or other addressable memory unit.
504: The stack, for example, is a portion of memory where state information is pushed when a routine is entered, and then popped as control returns from the routine to the code that called the routine; it is generally distinguished from heap memory.
506: The stack base address defines the starting point from which the stack is allocated in contiguous memory; the stack is assumed to grow in a known direction using the allocation of stack memory in the system, which in a given system may be upward (i.e., the address increases as an item is pushed onto the stack), but in another system it may also be downward (i.e., the address decreases as an item is pushed onto the stack); the term "growing" here refers to the direction of stack growth in the system under discussion, while "shrinking" refers to the opposite direction.
508: Stack frame, or allocation record, is allocated on the stack when a routine is called; it typically contains the return address, which identifies the location in the code where execution will resume when the routine returns; it may also contain the address of a value passed as an argument to the routine when it is called, or the address of such an argument value.
510: Heap memory allocated and released along with the construction and release of objects; in some cases, the heap can be automatically garbage collected, and the heap identifies and marks it as available memory, which holds objects that are no longer reachable during the live execution of the process; in other cases, memory allocated from the heap requires a separate explicit call to release the allocated memory.
512: Object
514: Cache memory; for example, it can be in RAM working memory or on the processor chip.
516: Registers in the processor core
518: Object property; a named value that is part of an object; it can be a function, in which case the property is usually called a method; it also refers to a function that implements an object property; a function is a routine that returns a value.
520: ROM (Read-Only Memory); typically non-volatile.
522: Non-volatile memory other than onboard ROM, such as removable flash memory, disk or optical disk storage, magnetic tape storage, etc.
524: RAM (Random Access Memory); typically volatile.
526: Local memory, for example, memory that is local to the stated or implicit context, such as memory that is local to the routine during its execution and then freed, or memory that is local to the thread.
528: Global memory, such as memory that is global for a stated or implicit context, such as memory that is global relative to a set of multiple routines or relative to a set of threads during the execution of any of them.
530: The characteristics of memory that the addition or reduction of an entity outside a thread may alter the value stored in the memory cell, such as whether the memory cell is write-protected relative to other threads, or whether it is in shared memory (such as memory that is global relative to multiple threads).
602: Memory cell specification, such as an address in ROM or RAM or cache, or a register ID, or another item that specifies the memory cell by distinguishing it from other memory cells to allow access (read or write, or a reasonable attempt to read or write) to the memory cell; multiple memory cells may also be specified, for example, as a range of addresses.
604: Register ID, for example, register name, or index to a register array.
606: Address range, that is, a set of adjacent addresses that identify a set of corresponding contiguous memory units; as an example, a range can be specified as a pair of addresses (high address and low address); as another example, a range can be specified as a base address and a count of contiguous units based on the base address.
608: A specification of one or more execution time points, for example, as a specific time code or a range of time codes; the range can be specified as a pair of time codes (start time code and end time code), or it can be specified as a base time code and a count of time code increments, such as the number of clock ticks or the number of instructions.
610: Instruction count, which can be used as a time code; it can be an absolute count from the start of execution of a procedure, or a relative count such as when execution resumes from a thread.
612: System clock value, for example, in milliseconds or CPU cycles.
614: Execution time range specification, that is, data that specifies the range of execution time points; for example, it can be implemented as a pair of time codes (start and end) or as a base time code and a count of time code increments based on the base time code.
616: Execution Time Point
618: Perform control operations, such as stepping forward, stepping backward to skip, going to the specified location, setting or clearing breakpoints, etc.
620: Identifier for performing a control operation; for step or continue operations, it refers to or includes the direction (i.e., forward or backward; "reverse" and "backward" are used interchangeably in this document), and also refers to or includes the increment size (e.g., one step, step skipping a routine, or continue until a breakpoint is encountered).
702: Data values derived from tracking data
704: Instruction Pointer, which identifies a specific instruction or execution point in the trace data; it is a reference position for replay execution to move forward or backward; "backward" means towards younger execution points, and "forward" means towards older execution points.
706: Status code indicating the result of a request, such as successful execution of control operation, control operation initiated (for asynchronous control), or control operation failed.
800: Tracking and Replay Execution Control System
802: The process of the program being traced; it may include one or more threads.
804: Thread
806: A user request for a tool used to perform control operations.
808: Program metadata or tool metadata, such as data that does not have a separate specific number but is still discussed here.
810: Source intermediate mapping, i.e., a mapping between source code or source code item(s) and one or more intermediate representations of source code or source code item(s); mapping 810 is an example of cross-level mapping 404.
812: Intermediate native mapping, i.e., a mapping between one or more intermediate representations and native instructions or other trace data; mapping 812 is an example of cross-level mapping 404.
814: Record of native instruction 116 in the trace; may include, for example, trace data 422 with precise location, executed code 434, tuple 456, or generally trace data 454.
816: JIT (Just-In-Time) Compiler
818: Calls to routines or other calls, such as transferring control to an exception handler or interrupt handler.
820: Return address, that is, the point in time or instruction where execution will continue after calling 818.
822: A set of trace data, such as native instructions, that correspond to specific source code statements S or source code expressions E; for example, this could include a record of the execution of instructions that are generated entirely by compiling source code statements S or source code expressions E, rather than from the compilation of source code statements and expressions adjacent to S or E.
824: Edge instructions of group 822; each group typically has two edges—if the instructions are ordered, one edge is the youngest instruction in the group, and the other edge is the oldest instruction in the group; regardless of whether all instructions in a group are ordered relative to each other, an instruction X in a group of instructions G in the tracing is on an edge of G when X satisfies at least one of the following conditions: X is the first instruction of G encountered during forward execution of the tracing (“first forward edge”), X is the last instruction of G encountered during forward execution of the tracing (“last forward edge”), X is the first instruction of G encountered during backward execution of the tracing (“first backward edge”), or X is the last instruction of G encountered during backward execution of the tracing (“last backward edge”).
826: Intermediate representation, such as low-level code, like intermediate language code, or abstract syntax tree, or symbol table.
828: Breakpoint
830: Breakpoint Range
902: Forward step operation, also known as "forward step" or "step" (when the default or only direction is forward), refers to stepping forward and skipping one source code statement.
904: Forward step-in operation, also known as "forward step-in" or "step-in" (default or only when the direction is forward), means that the entry into the routine is skipped forward, so the next statement to be executed is the first statement of the routine body.
906: Forward step skip operation, also known as "forward step skip" or "step skip" (default or only when the direction is forward), means stepping forward and skipping through the routine, so the next statement to be executed is the first statement after the routine call.
908: Forward step-out operation, also known as "forward step-out" or "step-out" (default or only when the direction is forward), means that forward stepping skips the remainder of the current routine, so the next statement to be executed is the first statement after the routine call.
910: Continue forward operation. When the default or only the direction is forward, also known as "continue" or "run," it means continuing execution forward until a breakpoint is encountered or the process terminates.
912: The backward step operation, also known as "stepping backward," refers to skipping one source code statement by stepping backward.
914: Step-back entry, also known as "step-forward entry," means stepping backward into the routine. Therefore, the next statement to be executed in reverse is the last statement of the routine body.
916: The backward step skip operation, also known as "backward step skip," refers to stepping backward into and through a routine, so the next statement to be executed in reverse is the first statement before the routine call.
918: Step backward, also known as "step back out," means stepping backward to skip the remainder of the current routine. Therefore, the next statement to be executed in reverse is the first statement before the routine call.
920: Continue backwards, also known as "continue backwards," "run backwards," or "run in reverse," means continuing execution backwards until a breakpoint is encountered or the process begins.
Some implementations may use different definitions for operations 902-920, for example, by executing more or fewer instructions or by using different names.
922: Set a breakpoint range, which specifies that execution should pause at any address or execution time point within the specified range of multiple addresses or execution time points.
924: Setting Breakpoints
1004: Thread ID
1006: Thread state, such as created, runnable, running, suspended, blocked, terminated.
1008: Thread code, that is, the code that is executed or can be executed when a thread runs.
1010: Thread memory, for example, memory that is local to a thread, or memory that is global to a thread and is accessed by the thread as it executes.
1102: Symbol Table
1104: Identifiers used in the source code
1106: Data Type
1108: Abstract Data Tree
1110: Intermediate languages, such as Microsoft General Intermediate Language, bytecode (Oracle Corporation trademark), Register Transfer Language, Parrot Intermediate Representation, Standard Portable Intermediate Representation, IR Intermediate Language (LLVM Foundation trademark), etc.
1112: Intermediate Language Code
1300: Example of a trace replay execution control method, and a flowchart illustrating the above method.
1302: Identification Procedure
1304: Received execution control request
1306: Using a mapping between source code and intermediate representation
1308: Using the mapping between intermediate representation and tracking
1310: For example, controlling the response by executing forward or backward, or by setting parameters (direction, increment) on such execution.
1312: Execute the traced instructions during replay, for example, by emulation or by controlling the replay of operations specified in the trace as native instructions (not necessarily all of which are in the trace).
1314: Set a breakpoint or breakpoint range; including 922, 924, or both.
1316: Send a response to the execution control request.
1318: For example, by executing up to the edge of the group before pausing at a breakpoint, align a set of traced instructions with source code statements or expressions.
1400: Flowchart
1402: This indicates a backward stepping exit request.
1404: Sets a breakpoint at the execution location immediately preceding the specified location; when A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, location A is "immediately preceding" location B in the trace.
1406: Set a breakpoint at the edge of a set of instructions that corresponds to a specific source code statement or expression.
1408: Sets a breakpoint range that covers (and in some implementations matches) the range specified as receiving dynamically compiled (“jitted”) code.
1410: Set a breakpoint to step over the specified runtime routine.
1412: An instruction was encountered during the original execution or replay execution.
1414: Exceeding the hardware constraint on the maximum number of breakpoints that can be monitored simultaneously.
1416: Avoid terminating the procedure
1418: Termination of Procedure
1420: For example, by specifying the execution of source code statements or expressions to be executed, one can gain high-level control over the original execution or replay execution.
1422: Execute (original or replay) a process, thread, or program.
1424: Get the user's selection of source code statements or expressions
1426: User selection of source code statements or expressions
1428: Debugging process, thread, or program
1430: Forward execution process, thread, or program
1432: Backward execution of a process, thread, or program
1434: Set a large breakpoint range; this breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in the trace.
1436: Large breakpoint range
1438: Recording tracking data from the real-time process.
1440: Group the traced instructions, i.e., create or specify group 822
1442: Clear breakpoints or breakpoint ranges
Operating environment
Referring to Figure 1, an operating environment 100 for one embodiment includes at least one computer system 102. The computer system 102 may or may not be a multiprocessor computer system. The operating environment may include one or more machines within a given computer system, which may be clustered in a cloud, networked as client servers, and/or peer-to-peer. Individual machines are computer systems, and a group of collaborating machines is also a computer system. A given computer system 102 may be configured for, for example, end-users with applications, for administrators, as a server, as a distributed processing node, and/or otherwise.
Human user 104 can interact with computer system 102 via typed text, touch, voice, mobile, computer vision, gestures, and/or other forms of I/O, using a display, keyboard, and other peripheral devices 106. Screen 126 may be a movable peripheral device 106 or may be an integral part of system 102. The user interface may support interaction between one embodiment and one or more human users. The user interface may include a command-line interface, a graphical user interface (GUI), a natural user interface (NUI), a voice command interface, and/or other user interface (UI) presentations, which may be presented as different options or may be integrated.
System administrators, network administrators, software developers, engineers, and end users are all specific types of users 104. Automated agents, scripts, playback software, etc., representing one or more individuals can also be users 104. Storage devices and/or network devices may be considered peripheral devices in some embodiments, while in other embodiments they may be considered part of system 102, depending on their separability from processor 110. For example, other computer systems not shown in FIG1 may technically interact with computer system 102 or another system embodiment using one or more connections to network 108 via network interface devices.
Each computer system 102 includes at least one processor 110. Like other suitable systems, computer system 102 also includes one or more computer-readable storage media 112. Media 112 can be of various physical types. Media 112 can be volatile memory, non-volatile memory, in-situ fixed media, removable media, magnetic media, optical media, solid-state media, and/or other types of physically persistent storage media (as opposed to media that merely transmits signals). Specifically, when inserted or otherwise installed, a configured medium 114, such as a portable (i.e., external) hard disk drive, CD, DVD, memory stick, or other removable non-volatile storage medium, can functionally become a technical part of the computer system, making its contents accessible for interaction with and use by the processor 110. Removably configured media 114 is an example of computer-readable storage media 112. Other examples of computer-readable storage media 112 include built-in RAM, ROM, hard disks, and other memory storage devices that are not readily removable by the user 104. To comply with current U.S. patent requirements, under any pending or granted claim in the United States, a computer-readable medium, a computer-readable storage medium, or a computer-readable memory is not a signal itself or merely energy.
For example, medium 114 is configured with binary instructions 116 executable by processor 110; "executable" is used broadly herein to include machine code, interpreted code, bytecode, and/or code running on a virtual machine. Medium 114 is also configured with data 118, which is created, modified, referenced, and/or otherwise used for technical effects through the execution of instructions 116. Instructions 116 and data 118 configure the memory or other storage medium 114 in which they reside; when the memory or other computer-readable storage medium is a functional part of a given computer system, instructions 116 and data 118 also configure the computer system. In some embodiments, a portion of data 118 represents real-world items such as product characteristics, inventory, physical measurements, settings, images, readings, targets, volumes, etc. Such data may also be transformed through backup, restore, commit, abort, reformatting, and/or other technical operations.
While an embodiment can be described as being implemented by software instructions executed by one or more processors in a computing device (e.g., a general-purpose computer, server, or cluster), this description does not represent an exhaustive list of all possible embodiments. Those skilled in the art will understand that the same or similar functionality can often also be implemented directly in hardware logic, in whole or in part, to provide the same or similar technical effects. Alternatively, or in addition to software implementation, the technical functionality described herein can be performed at least in part by one or more hardware logic components. For example, and without excluding other implementations, an embodiment may include hardware processors 110, 128, such as field-programmable gate arrays (FPGAs), application-specific integrated circuits (ASICs), application-specific standard products (ASSPs), system-on-a-chip components (SOCs), complex programmable logic devices (CPLDs), and similar components. For example, components of an embodiment may be grouped into interactive functional modules based on their inputs, outputs, and/or their technical effects.
In addition to processor 110 (e.g., CPU, ALU, FPU, and/or GPU), memory/storage medium 112, and display 126, the operating environment may also include other hardware 128, such as batteries, buses, power supplies, wired and wireless network interface cards. The terms "screen" and "display" are used interchangeably herein. Display 126 may include one or more touchscreens, a screen responsive to input from a pen or tablet, or a screen for output only. In some embodiments, peripheral devices 106, such as human user I/O devices (screen, keyboard, mouse, tablet, microphone, speaker, motion sensor, etc.), will be operatively communicating with one or more processors 110 and memory. The software process may be user 104.
In some embodiments, the system includes multiple computers connected by network 108. Networking interface devices may use components such as packet-switched network interface cards, wireless transceivers, or telephone network interfaces (e.g., these may be present in a given computer system) to provide access to network 108. However, one embodiment may also transmit technical data and/or technical instructions via direct memory access, removable non-volatile media, or other information storage, retrieval, and/or transmission methods.
Those skilled in the art will understand that the foregoing and other aspects presented herein in the context of an "operating environment" can form part of a given embodiment. The headings of this document are not intended to strictly categorize features into sets of features specific to embodiments and non-embodiments.
One or more items are shown in dashed lines in the accompanying drawings, or listed in parentheses, to emphasize that they are not necessarily part of the illustrated operating environment or all embodiments, but may interoperate with items in the operating environment or some embodiments discussed herein. Items not shown in dashed lines or parentheses are not necessarily required in any drawing or any embodiment. In particular, Figure 1 is provided for convenience; the inclusion of an item in Figure 1 does not imply that the item or its described use was known prior to the invention.
Debugging environment
Figure 2 illustrates a real-time process debugging environment, which is an example of operating environment 100. Debugger 200 contains various components, many of which are not shown here because many are well-known. The primary use of execution control, as taught herein, can be in environments where real-time process debugging is infeasible or at least undesirable. Nevertheless, real-time process debugging is shown for the context and because it can be combined with trace-based debugging utilizing the execution control taught herein.
Debugger 200 can be a conventional debugger or can be adapted to perform the execution control taught herein. The debugger shown includes a data access component 208 (DAC). In this real-time debugging 1428 environment, DAC 208 communicates with the runtime 204 of the real-time debug object 202 to obtain memory items 206 by using a master request 214 to the runtime and a master response 216 from the runtime. The debugger then updates its user interface 210 accordingly. The user interface presents status information at a relatively high level (e.g., in terms of artifacts defined in source code 212). However, those skilled in the art will understand that the execution control taught herein does not require DAC 208 or other adapters.
Figure 3 illustrates a dump debugging environment, which is another example of operating environment 100. Debugger 200 uses its data access component 208 or functionally similar code to read memory contents from dump file 302 or snapshot 304, or both, as well as other state information at specific points in time during the execution of the debugged object.
Figure 4 illustrates a trace-based debugging environment, another example of operating environment 100. The debugger 200 shown is used in conjunction with or includes (since the scope of the debugger can be defined by a given developer, for example, to include replay adapter 408) a technical adapter that allows the debugger to interact with trace 418 more or less as if the debugger were interacting with the runtime. For example, in this example, the same format could be used for the main request 214 and main response 216 used in the real-time process debugging environment of Figure 2. However, trace-based debugging 1428 can offer developers less flexibility than real-time process debugging because variables and other memory contents accessible through the runtime are not necessarily readable from the trace. The granularity of execution control using a familiar trace-based debugger can also be greater than the granularity available through the teachings presented herein. Finer granularity can provide better control during debugging, thereby accelerating defect location identification and understanding of defects.
Tracing-based debugging, with appropriate execution control code 402, a replay component 406, and a mapping 404 between tracing data and source code 212, can support reverse execution 1422 in the form of a reverse replay of the traced execution. In contrast, in real-time debugging, the debugged object is typically not reverse executed.
The replay adapter 408 shown includes an interface 410 to the debugger, which in this example presents an API to the debugger that matches at least a subset of the APIs presented to a traditional debugger by runtime 204 to support real-time process debugging 1428. Other implementations are also possible. Moreover, as shown by the dashed lines around the replay adapter 408 in Figure 4, in some implementations, some or all of the replay adapters can be considered part of the debugger 200, since the debugger is an adapted debugger 200 containing code that utilizes one or more cross-level mappings 404. For example, instead of using external messages, one variant implements the main request 214 and main response 216, as well as interface 410, as function calls, returns, and interfaces within the debugger. In some variants, the debugger includes and utilizes the cross-level mapping 404, and there is no separate replay adapter 408. Debugger DAC 208 can be used to map address 448 to higher-level object 512. The debugger cross-level mapping 404 and its associated code (i.e., one or more of the execution controller 402, replay component 406, and replay adapter 408) can be used to map source code statements 218 or expressions 220, or both, to specific native instructions 434 or native instruction sets 822. In some embodiments, similar to dump debugging, the DAC 208 has runtime internal knowledge and can read runtime data structures to determine where the JIT source code is located for a given set of IL instructions. The machine architecture on which the debug object runs can be significantly different from the machine architecture on which the debugger runs, but the DAC can be designed to read runtime data structures and handle hardware/runtime differences.
Figure 4 illustrates the communication between the replay component 406 and the trace 418 in the form of a machine-level request 414 and a response 416. This is one possible implementation, as an example, which could use a trace reader (not shown) to receive and respond to the request. However, in another implementation, the machine-level request 414 and response 416 take the form of function calls within the replay adapter 408, which include functions that read from the trace 418 and pass back their caller information found in the trace. Thus, the replay component can maintain current state information, such as which position in the trace 418 is identified by the current instruction pointer 704.
As shown in the figure, trace 418 can be stored in one or more files 420 and can include various types of trace data, as well as metadata that supports or defines the search for the trace data. Some or all of trace 418 can also reside in RAM. Some examples of trace data include precisely located trace data 422 (such as copies of low-level instructions and their operands (also known as "native instructions")), timecode 424 which can be used to sort trace data items relative to each other, memory snapshot 304 or dump file 302, index 430 into the original trace data, keyframes 432 inserted into the original trace data at specified intervals, copies of code 434 executed by the debug object during trace 1422, stack activity 436, data streams 438 read or written by the debug object during trace, processor activity based on per core 440 or per socket (multiple cores) 442, thread activity during trace 444, register reads and writes during trace 446, tuples 456 that associate memory address 448 with instruction 450 and one or more values 452 and optionally also with timecode 424, and other 454 reads or writes or values or opcodes captured during trace. In some embodiments, an instance of any one of items 216, 422, 434, 436, 438, 440, 442, 444, 446, 456 conforms to trace “entry” 458. In some, any minimal portion of trace data 454 that itself represents a change in the state of the traced program conforms to trace “entry” 458. Missing data in the trace can also be considered state information, such as gaps 428 in the timecode sequence.
Figure 5 illustrates various memories 112 that can be tracked and thus subject to changes in value or allocation state according to the teachings herein, changes in value or allocation state being performed by the execution of native instructions under the control of execution 1422. Examples of memory cells 502 shown include stack 504 (including data such as its base address 506 and allocated stack frames 508), heap contents 510 such as object 512, or metadata such as garbage collection data, cache 514, processor registers 516, object members such as attribute 518, addressable units in ROM 520 or RAM 524, removable or third-level memory 522, local memory 526, and global memory 528. Memory cells may have one or more characteristics 530 that increase or decrease the accessibility of the memory cell, for example, the memory may be in kernel space, may be shared, may be DMA-enabled, etc.
Figure 6 illustrates the contents of machine-level request 414. As mentioned above, these requests can be implemented using communication data structures, or they can be implemented as parameters of a routine. Some examples of the contents of machine-level request 414 are a memory cell specification 602 and a specification 608 of one or more execution time points 616. Memory cell 502 can be specified as, for example, a single address 448, an address range 606, or a register name 604. Time code 424 can be specified as, for example, an instruction count 610 or a system clock value 612, and this specification can be for a single specific execution time point 616 (a point during trace, or a specific native instruction) or a range of execution time 614 (i.e., the span or period or interval of execution time during trace, or a set of consecutive native instructions).
Figure 7 illustrates the contents of machine-level request response 416. As mentioned above, these request responses can be implemented using communication data structures, or they can be implemented as routine function return values or side effects. Some examples of the contents of machine-level request response 416 are: a value 702 for one or more memory locations specified in the corresponding request 414; an instruction pointer 704 indicating which instruction will be executed next (or which instruction has just finished executing 1422); and a status code 706 containing flags associated, for example, with an instruction, or an error, or a condition (such as an end-of-file marker). Each thread may have a corresponding instruction pointer 704.
Some tracking and replay execution control systems
Figure 8 illustrates a trace replay execution control system 800, each of which is a system 102 configured according to the execution teachings provided herein. If the execution control system operates in a real-time debugging environment, it contains a debug object program 124 with a callable runtime 204. Although debugging is used as an example, execution control can also be performed as taught herein in other contexts, such as for performance analysis or software health monitoring. The debug object or other replayed program includes one or more processes 802, each of which may include one or more threads 804. Those skilled in the art will understand that the terms “process” and “thread” are used in different ways, for example, sometimes as synonyms for each other, and sometimes with different meanings. In either case, the execution control teachings provided herein can be applied because, under either meaning of “process” or “thread,” process 802 and thread 804 have corresponding source code 212 and corresponding traced instructions 434.
Regardless of whether replay execution occurs in a real-time debugging environment, the state information of the replayed program is maintained and updated as the replay execution "proces." In this sense, "procesuspension" includes forward execution, backward execution, or both. State information includes, for example, one or more instruction pointer values indicating execution time(s) in trace 418, and changes in traced program variable values captured in trace 418. To indicate the presence of state information, the boxes for process(s) 802 are shown in FIG. 8 inside the debug object program 124 box with solid lines instead of dashed lines. However, those skilled in the art will recognize that state information may also be maintained within execution controller 402 or at one or more other locations within system 800.
The execution controller 402 itself includes software executed using processor 110 and memory 112. The traced program 124 is other software having source code 212 and metadata 808. The execution controller 402 uses a source intermediate map 810 to map the source code 212 to an intermediate representation 826 of that source code. The execution controller 402 also uses an intermediate native map 812 to map the intermediate representation 826 to the trace 418 (including a record 814 of native instructions collected from the trace). These maps 810, 812 are collectively referred to herein as “cross-level maps”. Note that a given embodiment may include one or more cross-level maps 404; for example, source-to-intermediate and intermediate-to-native functionality may be integrated into a single source-to-native map 404.
In some cases, such as in the case of .NET languages, the compiler creates the source-to-IL mapping 810. However, there are runtimes 204 that can directly execute the source language; one example is (a trademark of Oracle Corporation). In this case, the runtime itself compiles the language to an intermediate format and simultaneously creates the source-to-IL mapping. In the case of managed languages similar to .NET languages, the high-level language compiler does not perform native IL mapping; instead, the JIT compiler in runtime 204 does. Compilers that compile to native code also do not perform native IL mapping. In fact, if such a compiler has any form of IL, it is likely an implementation detail of that compiler. In some embodiments, execution control utilizes the native IL mapping 812 generated by the runtime.
Some implementations obtain the generated IL from tracing native instructions. For example, some implementations simulate CPU operation by emulating it and use native instructions to replay the tracing. In some cases, the IL alone is not sufficient information to recreate the native instructions. In some cases, the native instructions themselves are insufficient to implement IL stepping or IL breakpoints. Additionally, a mapping between native and IL instructions is used. Some embodiments use mappings without relying on native instructions (which may not even exist in the tracing) to implement debuggers that support stepping through IL code using a tracing replayer that does not rely on knowledge of native instructions. Such implementations can trace the instruction pointer by the range provided in the mapping or by any consecutive or non-consecutive collection of the specified items.
Supplement on cross-level mapping
To further illustrate the cross-level mapping 404, consider the following example: some source code 212, a portion of some corresponding intermediate language code used as intermediate representation 826, and a portion of some native instructions. Due to the patent office's restrictions on the inclusion of computer code in patent documents, and because showing a portion is sufficient to illustrate mapping 404 in the context of the other information provided herein and the knowledge of a person skilled in the art, only portions of the intermediate language code and native instructions are shown here.
Original C# source code:
Sample source-to-IL mapping. This sample is hand-generated. The actual implementation is typically unreadable to humans. That is, the source-to-IL mapping will usually be implemented in binary format rather than text format. Nevertheless, the following material illustrates the functionality of the source-to-IL mapping to those skilled in the art. The mapping is not a one-to-one mapping; some parts of the source code line end at different locations in the IL code. For a single source program, there are many correctly generated IL transformations.
Sample IL to native mapping. Similar to source-to-IL mapping, this is manually generated, and the implementation will exist as a data structure, for example, at runtime. For a single generated IL, there are many correctly generated native code transformations. Because the JIT compiler can add complexity due to processor-specific optimizations, and because debug 1428 using traced programs may not execute on the same processor type (i.e., different optimizations will be applied), it is not simply possible to run the JIT on the IL and the result cannot be guaranteed to be the same as running it during the generation of trace 418. In this example, the IL begins with "IL_", and the native code is represented as <memory address><hexadecimal representation of native code><assembly mnemonic>.
Typically, kernel 120 is present, and is explicitly shown in Figure 8 to help prevent confusion between runtime 204 and kernel 120. The cross-level mapping and execution control described herein assume that the runtime is present in most (if not all) configurations when execution is traced to create trace 418.
Additional aspects of System 800 and related systems
Some embodiments of system 800 include a JIT compiler 816 for dynamically compiling the code of the traced program 124. Some aspects of execution control address the challenges created by JIT compilation, for example, by supporting breakpoint ranges 830, which allow breakpoints to be encountered even if native code spanning the breakpoint location has not yet been generated by compilation, provided the address range that will contain the generated code is known. For example, breakpoint range 830 can be specified as ranges 606 or 614, while individual breakpoints 828 are specified as specific single locations within trace 418.
Referring again to Figure 8, some embodiments of system 800 include a return address 820 for call 818. This return address 820 may be used, for example, when performing a reverse step-out execution control operation that steps out of the calling routine during reverse execution.
Some embodiments improve the accuracy of execution control by providing a more precise correspondence between source code statements or expressions and the traced instructions that implement them. For example, some familiar methods of tracing replay step into the middle of the traced instructions corresponding to a given source code statement 218 or expression 220, which can be confusing. Some embodiments described herein definitively define a set of 822 traced instructions corresponding to a given source code statement 218 or expression 220 (e.g., generated by compilation to implement). The execution controller then sets the instruction pointer to a location at an edge 824 of this set of 822, instead of somewhere in the middle as before. Which edge 824 is selected can depend on whether the execution is replaying forward or backward; for example, a first forward edge is selected for forward replay, and a first backward edge is selected for backward replay. Alternatively, the same edge can always be used regardless of the replay direction; for example, the instruction pointer can always be set at the first forward edge.
Figure 9 illustrates several execution control operations 618. For example, a user presents a control operation request 806 to the debugger 200 or other tool 122 via user interface 210. Execution controller 402 translates the control operation request 806 into a change in the state of process 802. The operations shown include forward step 902, forward step into 904, forward step skip 906, forward step out 908, continue forward 910, backward step 912, backward step into 914, backward step skip 916, backward step out 918, continue backward 920, set breakpoint range 922, and set breakpoint 924. In these operation names, "forward" indicates performing replay forward, and "backward" indicates performing replay backward.
Various step operations 902-920 can be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar operations with similar or identical names. However, internally, for example, they can be implemented through innovations for aligning source code with traces using cross-level mapping 404, instruction group 822, and specific breakpoint placement. Continue operations 910, 920 can also be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar continue operations, while internally, they utilize cross-level mapping 404 or instruction group 822, or both. Set breakpoint operation 924 can also be implemented so that, from the developer's perspective, it operates in a manner similar to or identical to the familiar breakpoint setting operation, while internally, it utilizes cross-level mapping 404 or instruction group 822, or both.
Figure 10 illustrates the thread 804 activity information 444 that can be captured in a given trace 418. It shows the thread identifier 1004, thread state indication 1006, thread executable code 1008, and memory unit 502 status information 1010 such as thread local variables and their identifiers.
Figure 11 illustrates some examples of intermediate representation 826. Examples shown include symbol table 1102, which associates source code identifiers 1104 (variable names, function names, object members, and method names, etc.) with data types 1106 (e.g., integers, floating-point numbers, strings, booleans, and user-defined types). Another example is abstract syntax tree 1108. Other examples include code 1112 written in one or more intermediate languages 1110. More generally, some embodiments use intermediate representation 826 that shares the structure of an intermediate representation created by the compiler, or even a copy thereof. However, intermediate representation 826 is placed in the context of an execution controller, opposite to the compiler's context. Furthermore, intermediate representation 826 is used for tracing replay of the execution tracing 418 of previously generated code, rather than being used to generate that code in the first place.
A technician will recognize that a given source code 212 can potentially be used to generate many different versions of the corresponding IL. However, only one of these versions will be used in the program, and the symbol information emitted by the compiler will correspond to the emitted IL. The debugger can be designed to load only the corresponding symbol information, so only one mapping will exist. In some systems, the runtime may include multiple versions of native code for a given routine; for example, both optimized and non-optimized versions of native code for debugging may exist, or multi-level JIT functionality may provide multiple versions of native code in memory. In such a multi-native version system, replay can still be performed. For example, when a breakpoint is set, it can be set in all existing versions of the native code. Some embodiments use native code generated by the JIT as well as IL code, which are obtained from or via trace 418. Some embodiments also use the corresponding symbol information for the source/IL mapping, which may or may not be included in the same trace file 420.
Figure 12 is a variation of Figure 2. In the environment of Figure 12, both real-time debugging and replay execution are supported. Replay is supported by a scrolling trace 418, which records the forward execution of the real-time debug object in real time, while the debug object executes according to the prompts of debugger 200. For efficiency, only, for example, a pair of buffers is used to track the latest instructions. Trace 418 is written to one buffer until it is full, then to another buffer until it is full, then written back to the first buffer (overwriting the earlier trace), and so on. Alternatively, instead of the scrolling window, all execution activity during the debug 1428 session can be tracked. As another alternative, previously recorded trace 418 can be accessed during the real-time debug session.
Some additional system examples
Examples are provided in this document to help illustrate various aspects of the technology; however, the examples given in this document do not describe all possible embodiments. Embodiments are not limited to the specific implementations, arrangements, displays, features, methods, or scenarios provided herein. A given embodiment may include, for example, additional or different technical features, mechanisms, sequences, or data structures, and may otherwise deviate from the examples provided herein.
Referring to Figures 1-2, some embodiments use or provide a trace replay execution control system 800. This system includes a processor 110, a memory 112 operatively communicative to the processor, and a trace 418 recorded during the execution of program 124 in conjunction with runtime 204 and kernel 120. The trace includes a record 814 of native code instructions 116 executed in at least one thread 804 of the program. Source code 212 of at least a portion of the program is also present.
System 800 also includes a source intermediate mapping 810 that maps between source code and intermediate representation 826 of source code, and an intermediate native mapping 812 that maps between intermediate representation 826 and trace 418.
System 800 also includes an execution controller 402 in software tool 122. The execution controller is configured to control the replay execution of trace 418 in response to request 806 when executed using the processor. In the replay execution, the source code is associated with trace native code instructions or other trace entries through source intermediate maps and intermediate native maps.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: forward execution step into 904 operation, forward execution step out 908 operation, and forward execution step skip 906 operation.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: a backward step-in operation 914, a backward step-out operation 918, and a backward step-skip operation 916.
In some embodiments, execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: continuing forward execution in the trace 910 until any position within the breakpoint range 830 is reached, and continuing backward execution in the trace 920 until a position within the breakpoint range is reached.
In some embodiments, system 800 is configured to step into a portion of source code that has not yet been compiled into native code instructions during replay execution.
In some embodiments, the intermediate representation 826 includes at least one of the following: a symbol table 1102 that associates at least two identifiers 1104 used in the source code with a data type 1106, an abstract syntax tree 1108 derived from at least a portion of the source code, or a conversion 1112 from at least a portion of the source code 212 to the intermediate language 1110.
In some embodiments, tracing 418 does not contain any execution instance of runtime 204, and tracing 418 is not configured to call tracing to execute any runtime-specific code.
In some embodiments, system 800 includes a real-time debug object 202 of program 124 having a runtime callable instance. In some embodiments, trace 418 is recorded from a real-time process and the system is configured to replay the execution of the trace.
In some embodiments, system 800 is configured to skip a portion of the replay execution of trace 418 because execution controller 402 moves the replay execution from a first execution point of the trace to a second execution point of the trace, and the system does not execute trace native code instructions or other trace entries that would otherwise be executed through continued execution from the first position to the second position.
Those skilled in the art will understand that other systems are also within the scope of the teachings presented herein. In particular, some other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any system or apparatus using any of the execution control teachings herein is within this disclosure, whether or not it is in the specific example provided.
Some method examples
Figure 13 illustrates an example of an execution control method 1300, which is an example of a method executed or assisted by an execution controller 402, a cross-level mapping 404, or other items discussed herein. This example method includes identifying a managed program tracked by 1302 as a tracked managed program. Identifying a program as tracked is simple; if a program is being tracked, or has been tracked previously, then it is a tracked program. To some extent, it involves identifying a program as managed because it is managed when it depends on runtime 204 for real-time execution, and runtime 204 may provide different services in different implementations. In many cases, runtime 204 provides automatic management of heap memory through garbage collection based on reachability analysis, reference counting, or other mechanisms. However, what is of greater interest in this application is the use of runtime 204 to execute intermediate language code 1112. In some runtimes, the translation from source to native instructions is not modularized into a source-to-intermediate language stage, followed by an intermediate language-to-native code stage. For example, some platforms execute source code directly (a trademark of Oracle Corporation, USA). For the purposes of this application only, a "managed" program is a program that relies on runtime 204 to generate native instructions. A managed program may also be subject to or not subject to garbage collection performed by the runtime.
The method 1300 shown also includes receiving a request 1304 to perform a control operation on a trace playback. This request may be a request 806 directly from the user through the user interface, or a request 214 from the debugger to the trace execution controllers 402, 406, or 408.
The illustrated method 1300 also includes a mapping 1306 from source code to an intermediate representation and a mapping 1308 from the intermediate representation to native code. This can be done in two stages as indicated, or in some other embodiments, in a single combined stage from source code to native instructions. However, unlike compilation itself, whether in two stages or one stage, mappings 1306 and 1308 are not for generating code for execution, but rather for associating source code locations with locations in the trace of previously generated and executed instructions.
Some implementations map 1306 from source code to an intermediate representation using a symbol file that contains hashes, checksums, or other identifiers of the IL corresponding to the source. If the identifiers match, the debugger loads the symbol file. This symbol file also contains identifiers for each source file used to compile the IL. Before the debugger loads the source files and maps the IL code to the source, it verifies the source file identifiers using the identifiers contained in the symbol file.
When IL is compiled just-in-time (JIT), some implementations use a runtime-generated mapping to map 1308 from IL to native code. In some implementations, the runtime may not guarantee backward compatibility regarding how JIT will occur, and therefore is free to change the JIT process at any time. In such implementations, debuggers may not be able to make assumptions about what the native code output by the JIT process will contain. Therefore, debuggers may request the runtime to provide the mapping between native code and IL.
Some variations of the method 1300 shown include aligning native instruction sets with source code statements or expressions 1318, which are generated by compiling from these source code statements or expressions.
The illustrated method 1300 includes control 1310 for replay, which is to perform "execution control". An example of control 1310 is executing 1312 native instructions or other trace entries corresponding to step, step in, step skip, step out, or continue operation, thereby changing the state of process 802. Another example of control 1310 is setting 1314 individual breakpoints or breakpoint ranges. Those skilled in the art will recognize that performing step, step in, step skip, or step out operations involves setting breakpoints, but it is also possible to set breakpoints without executing native instructions or other trace entries, for example, when preparing for continue operation. In some embodiments, the code itself is not modified to set breakpoints in the trace. Those skilled in the art will recognize that the processor can set execution breakpoints via instructions (e.g., int3 in some Intel architectures) or via hardware breakpoints (registers that specify which address to monitor). In some embodiments, the trace replay execution control system 800 provides similar capabilities. Some implementations do not modify the code flow and support an arbitrarily large number of breakpoints.
Finally, the method 1300 shown includes sending 1316 a response to the request, such as response 416 or another message or data structure containing instruction pointer 704 or status code 706.
Figure 14 illustrates some additional execution control steps that may be performed in some embodiments. Some familiar debuggers do not support the backward step-out operation 918. However, some embodiments identify 1402 as a request for the backward step-out operation 918 and implement the operation as taught herein.
Debuggers can implement some familiar breakpoint operations, namely, the operation for setting a breakpoint 1314. However, some embodiments set breakpoints 1314 and 1404 immediately before the specified location. Some embodiments set breakpoints 1314 and 1406 at the edge of the instruction group 824. Some embodiments set breakpoint range 830 of 1314 and 1408 on, for example, an address range designated for receiving code that is compiled just-in-time (JIT-compiled). In particular, some embodiments set large breakpoint ranges 1436 and 830 of 1434, 1314, and 1408. Some embodiments set breakpoints 1314 and 1410 as part of implementing a step-skip operation to step over runtime routines that the developer may not be interested in. For example, such runtime routines may perform garbage collection, JIT compilation, anti-malware or other security checks, or runtime 204 stewardship functions. The other steps shown in Figure 14 are discussed elsewhere in this document or included for completeness; for example, not only can breakpoints be set, but breakpoint 1442 can also be cleared.
Unless otherwise indicated, the technical methods shown in the figures or otherwise disclosed will be executed automatically by, for example, system 800. Within the scope of actions involving human administrators or other humans, the methods may also be executed partially automatically and partially manually; for example, a person may select 1426 source code statements or expressions and then use tool 122 user interface to request step operations or breakpoint operations. However, a completely manual method is not considered here as an innovation. In a given embodiment, zero or more example steps of the method may be repeated, possibly with different parameters or data to be manipulated. The steps in one embodiment may also be performed in a different order than those shown in the figures. Steps may be performed sequentially, in a partially overlapping manner, or in complete parallel. The order in which steps are performed during a given method can vary from execution of one method to execution of another. Steps may also be omitted, combined, renamed, regrouped, or otherwise deviated from the illustrated flow if the method being performed is operable and conforms to at least one claim.
Some embodiments use or provide a computer-implemented method for a trace replay execution control method. One example method includes identifying, at 1302, the managed program being traced, i.e., a program configured to execute in conjunction with runtime calls and configured to be traced. The example also includes receiving, at 1304, a trace replay execution control request in a software tool running on a computing system. Based on the trace replay execution control request, the example method automatically maps, at 1306, the source code of the traced managed program to an intermediate representation of the source code, and at 1308, the intermediate representation to a trace, at 418. The trace includes a record of native code instructions traced when the traced managed program is executed. Trace 418 does not include any execution instances at runtime. The example method also executes, at 1312, the traced native code instructions corresponding to the trace replay execution control request, thereby replaying a portion of the trace.
In some embodiments, the trace replay execution control request identifier 1402 performs a step-out operation backward to step out of the routine, and the method includes setting breakpoints 1314 and 1404 on the trace native code instructions, the breakpoints having a position immediately preceding the location of the return address of the call to the routine. For the purposes of this method, when 1412A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, position A in the trace is "immediately preceding" position B. For the purposes of this method, when performing source-level debugging, alignment 1318 can associate instruction group edge 824 with the most recently executed source file line number, statement, or expression executed before the current function call. Some embodiments set breakpoints at the call location of the routine; for example, some embodiments set breakpoints at the call location of the current function.
Typically, the source code contains statement 218 and expression 220. In some embodiments, the method includes setting breakpoints 1406 and 1314 on trace native code instruction 116, which are located at edge 824 of a group 822 containing all trace native code instructions mapped by the method to a given statement or expression in the source code. In some implementations, the group contains only all trace native code instructions, and may also contain other instructions.
In some embodiments, the received trace replay execution control requests 806, 214, 414 are named, identified, or otherwise invoked according to one of the following: performing a forward step skip 906 operation to step forward skip a routine; performing a backward step skip 916 operation to step backward skip a routine; performing a forward step enter 904 operation to step forward enter a routine; or performing a backward step enter 914 operation to step backward enter a routine.
In some cases, the received trace replay execution control requests 806, 214, 414 name, identify, or otherwise invoke replay functionality according to the forward execution step-in 904 operation to step into a user code routine, and the replay execution of the user code routine includes the replay execution of at least one call 818 to a runtime routine 204, and the call to the runtime routine has no corresponding call statement or call expression in the source code. In this context, some embodiments include at least one of the following: setting 1408 to specify a breakpoint range designated as receiving the entire memory extent of the dynamically compiled code, or setting a breakpoint 1410 to perform a step-skip operation on the call to the runtime routine.
In some embodiments, the forward stepping into step 904 is performed as follows. The debugger 200, configured according to the teachings herein, maps the source line range 1306 to the intermediate language range and the intermediate language range 1308 to the native range. The debugger then performs this step using low-level primitives; this can be done using instruction-level single-stepping or breakpoints. When the call instruction 818 is encountered, the debugger determines whether the target is a high-level source step that indicates a stepping into at the source level, or a runtime implementation detail that should not be stepped into because it is not explicitly stated in the source code. For example, this determination can be done by querying the runtime or by searching for the name of the calling routine in the source code. If the call is for a different high-level (shown in the source code) routine, the debugger queries runtime 204 (e.g., via DAC 208) to determine whether the calling routine has been JIT-compiled. If the calling routine has been JIT-compiled, the debugger performs stepping into the call using instruction-level single-stepping or by setting a breakpoint inside the target routine to perform stepping into step 904. If the calling routine has not yet been JIT-compiled, the debugger will set breakpoints on the JIT compiler or on the target address region written by the JIT compiler using DAC 208 or another mechanism, with the JIT compilation using multiple data breakpoints. The debugger allows running a trace replay until the JIT compilation is complete. The debugger sets breakpoints on the JIT-compiled target and runs. This continues until native instructions no longer fall within the native step range mapped from the initial action, or the program exits. An exception is a special case that should fall on a catch target.
In some embodiments, the trace replay execution control request invokes at least one of the following operations: continue tracing replay execution forward 910 in the trace until breakpoint 828 is reached; continue tracing replay execution forward 910 in the trace until a position in breakpoint range 830 is reached; continue tracing replay execution backward 920 in the trace until breakpoint 828 is reached; or continue tracing replay execution backward 920 in the trace until a position in breakpoint range 830 is reached. Some embodiments also include other operations that may be invoked in the request, including one or more of, for example, performing a step-in backward 914 operation; performing a step-out backward 918 operation; performing a step-skip backward 916 operation; performing a step-in forward 904 operation; performing a step-out forward 908 operation; and performing a step-skip forward 906 operation. More generally, a given embodiment may be limited to any subset of the operations taught herein.
In some cases, during the execution of the managed program being traced to create trace 418, the maximum number of breakpoints is constrained by the hardware breakpoint constraint that the processor can monitor up to N addresses at a time. However, in some embodiments, the method sets more than N breakpoints during the replay execution of the trace, thus exceeding the hardware breakpoint constraint.
Those skilled in the art will understand that other methods are also within the scope of the teachings presented herein. In particular, other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any method of implementing control teachings using the teachings herein is within this disclosure, regardless of whether it is within the specific examples provided.
Examples of media configurations
Some embodiments include a configured computer-readable storage medium 112. Medium 112 may include a disk (magnetic, optical, or otherwise), RAM, EEPROMs or other ROMs, and/or other configurable memories, particularly computer-readable media (which are not merely for transmitting signals or energy). The configured storage medium may in particular be a removable storage medium 114, such as a CD, DVD, or flash memory. General-purpose memory (which may be removable or non-removable, and may be volatile or non-volatile) may be configured in embodiments to form the configured medium using items such as an execution controller 402, a playback adapter 408, an instruction set 822, a cross-level mapping 404, machine-level requests 414 and responses 416, and a breakpoint range 830, in the form of data 118 and instructions 116 read from the removable medium 114 and/or another source such as a network connection. As disclosed herein, the configured medium 112 is capable of causing a computer system to perform technical processing steps for horizontal cross-level (high-level in tool 122 to low-level in trace 418) playback execution control. Therefore, the accompanying drawings help illustrate the configured storage medium embodiments and process embodiments, as well as system and process embodiments. In particular, Figures 4, 13, or 14, or any other processing steps taught herein, can be used to help configure the storage medium to form the configured medium embodiment.
Some embodiments use or provide computer-readable storage media 112, 114 configured with code that, when executed by computer processor 110, performs a trace replay execution control method. In this example, the trace replay execution control method includes receiving a trace replay execution control request 1304 from a software tool running on a computing system. The method includes mapping 1306 between the source code of the traced managed program and an intermediate representation of the source code, and mapping 1308 between the intermediate representation and a trace 418, based on the trace replay execution control request. The trace 418 includes a record of processor activity, such as native code instructions traced when the traced managed program is executed, since the trace does not include any execution instances at runtime. In this example, the trace replay execution control method also includes executing 1312 trace native code instructions or other trace entries corresponding to the trace replay execution control request, or setting a breakpoint 1314 on the trace native code instructions to control the replay of traces traced by 1310.
Some embodiments operate in combination with debugger 200, and in some of these cases, the traced managed program includes a real-time process and an execution runtime 204. Without terminating the traced managed program at 1416, debugger 200 communicates with the execution runtime 204 of the traced managed program, and the method uses trace 418 to control 1310 to perform a backward replay. That is, in this example, reverse debugging is intertwined with real-time process debugging.
Some embodiments perform one, two, three, or all four of the following activities of particular interest. One particularly interesting activity is the execution of 204 at high-level control 1420 using machine-level information from trace 418. In this context, "high-level" control refers to control based on user selection 1426 (obtained from user 104 via a user interface) that specifies an identifier or statement or expression in the source code. In this context, "machine-level" information refers to processor architecture-specific information, such as a particular instruction set or a particular microarchitecture.
Another particularly interesting activity is the forward and backward execution of both the real-time debug objects 202 and 802 of the managed program being debugged by debug 200.
Another particularly interesting activity is stepping into the call shown in the source code, at least in part, by setting a large breakpoint range of 1434 to 1436. In this case, the breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in tracing 418.
Another particularly interesting activity is to simultaneously debug the real-time debug object 202 of the managed program being debugged (200), trace 418 trace data from the real-time process, and then use at least some of the trace data recorded to perform reverse execution debugging on the real-time process.
Those skilled in the art will understand that other configurations of media embodiments are also within the scope of the teachings of this invention. In particular, some other embodiments may include statutory media configured with code for performing cross-level mapping 404 at execution time, using breakpoint range 830, and implementing other teachings provided herein, while departing from the specific examples described herein. Media configured to perform methods using any execution control teachings taught herein are within the scope of this disclosure, regardless of whether they are in the specific examples provided.
Example with JIT code
Assume the source code includes classes similar to those in C#, as shown below:
If the language is C++, the developer would reasonably expect that the call to WiggleLeg() in Squid.Swim() can be compiled into the following form (similar to assembly code):
CALL 0x0c84fabd; 0x0c84fabd is the address of Squid::WiggleLeg().
In this scenario, 0x0c84fabd would begin implementing Squid::WiggleLeg(). However, this is not the case in managed software executed in runtime 204. Code executed in runtime 204 is compiled "just-in-time," also known as "jit." If this is the first call to Squid::WiggleLeg(), there will be no machine instruction 116 for Squid::WiggleLeg(). It has not yet been compiled. Therefore, instead of having the machine instruction implement Squid::WiggleLeg(), 0x0c84fabd would have some instructions that look something like this (in pseudocode):
This point in the code is called a "stub". The compilation process is lengthy and complex, so developers who typically try to analyze or debug their applications by tracing them often don't want to document the compilation process in detail. However, trace 418 may record at least a portion of the stub, even if the traced instructions are unlikely to be of interest to those debugging the code. In real-time process debugging, the runtime typically skips this part of the code. However, when debugging only from trace 418, the runtime 204 of the debugged object is not executed, so the stub cannot be skipped. Instead, one embodiment can leverage the functionality of an out-of-process debugging utility typically used to read data from dump file 302, and an innovative trace replay functionality that can be used together to find the address range of all JITTED code at runtime. Upon receiving a request to step into a method call, one embodiment can temporarily set a breakpoint 1314 on the JITTED code range and virtually execute forward (i.e., replay forward) until the first JITTED code range is read. Once read, the embodiment can remove the breakpoint. In this way, developers can skip all these uninteresting "stubs" of code. Some implementations further optimize the method by targeting the address range of the breakpoints to be limited to the range of `Squid::WiggleLeg_implementation`.
Some additional combinations and variations
Any combination of these combinations of code, data structures, logic, components, communications, and/or their functional equivalents may also be combined with any of the systems and their variants described above. A process may include any step described herein in any operable subset or combination or sequence. Each variant may appear alone or in combination with any one or more other variants. Each variant may appear with any process, and each process may be combined with any one or more other processes. Each process or combination of processes (including variants) may be combined with any of the media combinations and variants described above.
In some embodiments, the trace replay component uses source-IL mapping and IL-machine mapping to convert between the location in trace file 420 (e.g., indicated by timecode 424) and the location in source code 212 (e.g., indicated by line number).
In some embodiments, a portion of runtime functionality is provided in the trace replay component 406. However, instead of mediating between the debugger, user code, and operating system as in the real-time process of Figure 2, the runtime functionality mediates between the debugger and trace(s)420.
Some trace recording processes record only two types of data. One type of data is the execution of code instructions 116, which may be executed in parallel on multiple threads. The other type of data is a snapshot 304 of a specific block of memory taken at discrete points in execution time, such as to capture a portion of the stack. However, other trace processes record different or additional types of data, as shown in Figure 4. In some cases, the trace contains a valid representation of all recorded instructions and all their inputs and outputs. The recording of trace 418 can be made efficient by relying on the determinism of processor(s) 110 and primarily recording information that cannot be inferred from that determinism, as well as information already recorded in trace 418. In some implementations, most of trace 418 is data, rather than the executed code instructions; such data is often indeterminate. The trace can be primarily seed data plus indeterminate information. In some cases, only information entering the cache of the traced processor(s) is recorded in trace 418; for example, reading the value V into the processor cache is input into the trace, but writing the value V from a processor register to memory location X is not necessarily input into the trace. If a write operation to X behaves differently in terms of the traced program, it is because at some point the written value is returned from X to the processor register, at which point, if tracing is still enabled, the entry in trace 418 can be executed.
This document describes the execution control of a high-level program derived from a process tracing using examples, illustrations, definitions, and other descriptive materials. Technicians will recognize that process traces can be created at the machine level using various techniques, such as Windows Event Tracing (ETW) or "Time Travel Tracing" for systems running Microsoft environments, tracing for runtime environments (trademarks of Efficios, Inc. and Linus Torvalds, respectively), tracing for similar environments (trademarks of Oracle Corporation and X/Open, Inc., respectively), and other tracing techniques. The trace can then be replayed using hardware emulation. Sometimes, the process is written in a high-level language that requires a runtime framework to actually execute the process. One example is a .NET application running in the Common Language Runtime (CLR). Moving forward or backward in a trace is not helpful in itself to developers of high-level programs because the view of the trace is a view of the runtime or just-in-time compiled code, not a view of the high-level program. This document describes a method for mapping machine-level instructions in a trace to high-level operations in the program. This allows for setting and reaching breakpoints, as well as forward and backward stepping in high-level languages.
The process of stepping through the code at a high-level runtime can be achieved by abstracting the complexity into three layers. At the lowest level (level 0) is the process trace 418. This trace contains enough information to allow the recorded process execution to be simulated at the hardware level.
At level 1, a properly configured system can apply some very basic hardware debugging support for replaying traces. This support may include: the ability to play the process forward or backward, read the process memory, read the thread context (for each thread), set hardware breakpoints, and single-step machine instructions for each thread.
At level 2, support is provided for mapping the range of machine instructions to the range of higher-level virtual machine (VM) instructions or another type of code. Operations in level 1 can be used to debug higher-level code. In some configurations, the operations to be supported are forward, backward, setting breakpoints, stepping in, stepping out, and stepping skipping. Details of the implementation for each operation are given below in the examples.
Regarding forward and backward execution, in this example, they are equivalent in high-level and machine-level execution, so this is handled entirely at level 1.
Regarding breakpoints, in this example, breakpoints are set using a mapping defined in layer 2 to map higher-level breakpoints to hardware breakpoints. When a hardware breakpoint is encountered, the implementation can use this mapping to map that hardware breakpoint back to a higher-level breakpoint.
Regarding forward and reverse stepping exits, a hardware breakpoint can be set at the function's return address using stack tracing. To implement reverse stepping exit, the breakpoint is set on the instruction preceding the return address.
Regarding forward and backward step skipping, step skipping can be achieved by looking at the next instruction to be executed. Depending on the instruction, the implementation can use Level 1 to either perform single-stepping or set a breakpoint and run until it is reached. The "call" instruction is an example of an instruction that requires a breakpoint. Most other instructions can use single-stepping. Unlike some familiar approaches, this example debugger implementation can use mappings in Level 2 to repeat the stepping operation until the instruction pointer or code execution time point is at the appropriate stop point in the higher-level runtime. This inspires the discussion of instruction group 822 elsewhere in this paper.
Regarding reverse step-in, to perform reverse step-in, this implementation uses the single-step operation defined in Layer 1. If the machine has just returned from the calling instruction, this usage will return the execution time point to the return instruction of the previous call. If the machine has not just returned from the call, the machine will simply backtrack to the previous instruction. Similar to step-skip, the implementation can use the mapping in Layer 2 to know when execution is at a stop point, and may need to perform single-steps several times to align the trace with the source code 1318.
Regarding forward stepping, in this implementation, forward stepping is similar to reverse stepping. However, difficulties can arise if the higher-level runtime needs to perform work that is not directly related to the running higher-level code. Some examples are just-in-time (JIT) compilation, runtime housekeeping, and stepping operations that require some form of runtime resolution (transparent proxies in .NET are an example of this challenge). These difficulties can be addressed by implementing any or all of the following: One option is to set a large breakpoint range for all JIT-compiled code at the start of stepping. If the breakpoint is encountered after stepping, the implementation can complete the step when the next stopping point is reached. Another option is to implement logic in the stepping engine that fully understands the runtime, knowing when to skip calls and when to single-step through calls, allowing the implementation to stop stepping at appropriate points in the higher-level runtime.
In some embodiments, out-of-process execution control controls the execution of IL instructions by using, for example, the functionality provided by replay component 406 and IL-to-address mapping 812. The functionality provided by replay component 406 or other execution controllers 402, 408 for execution control includes:
Get the status (register values) of all threads.
Step forward or backward by one instruction
Run forward or backward until the instruction pointer reaches the specified address set.
The IL-to-address mapping exists in the memory image of the process or trace, and the replay layer can provide it to an off-process execution control debugger. One perspective suggests that this example involves converting IL-level debugging into machine-level debugging.
By stepping individual instructions, or by running forward and backward in the trace until a specific instruction address is reached, some implementations support the application of high-level execution control to the trace using source-to-IL mapping 810, IL-to-native mapping 812, native-style out-of-process execution control, and the ability to run forward and backward in the trace 418.
Consider examples of real-time process debugging.
As a further illustration of trace-based execution control, consider that certain embodiments may resemble or differ from real-time debugging. Several components are referenced below, and those skilled in the art will understand their relationship to other examples provided herein, and in particular, that functionality may be grouped into different components for ease of understanding or implementation without departing from the execution control teachings provided herein. The system 800 components discussed in this example include:
User Interface (UI). The user interface graphically displays a representation of the debugger's program state to the user. Examples of program state include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, the set of variables in each frame of the call stack, and the values of these variables.
Source translation. This part of the code translation is responsible for translating between runtime abstractions and source code-level abstractions. For example, the CLR runtime uses IL instructions encoded in binary file format to represent code, while C# source code has the syntax of text statements. As an example, this layer of the debugger can translate between runtime abstraction layers (e.g., those defined in ECMA-335, Common Language Architecture (CLI) version 6 (June 2012) or later) and C# abstraction layers (e.g., those defined in C# language specification version 5.0 or later).
Runtime translation. The runtime translation section of the debugger is responsible for translating between low-level concepts (such as memory and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, a call stack for each thread, and the IL instructions to be executed next. Note that the call stack at the abstract runtime layer does not have to be the same as the call stack at the abstract source code level. Only in the case of real-time debugging, this layer uses inter-procedural communication mechanisms to request the runtime within the process being debugged to perform work in order to assist with certain tasks. For example, to set a breakpoint at an IL instruction in method Foo at offset 28, this layer sends a message to the runtime requesting it to set the breakpoint at offset 28 of Foo. The thread within the runtime then receives the message, translates the Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. It is reasonable to consider the part of the runtime that serves those requests as functionally located within this layer of the debugger, even if it is implemented in a different process.
The basics. The low-level parts of the debugger are responsible for using the kernel, dump files, or traces to generate memory and registers that will be read by the runtime translation section. For kernel procedures, this is implemented in some environments via APIs such as ReadProcessMemory. For trace files, it supports parsing the file and establishing a mapping between time t and a set of memory and register contents recorded at that time.
Considering these components, consider the scenario where a breakpoint is set and the program is executed forward until the breakpoint is reached. One perspective suggests that real-time process debugging generally involves the following actions.
Action 1. User Interface. The user clicks the mouse on the displayed source code line to indicate where a breakpoint should be set.
Action 2. Source Transformation. Source code lines are transformed into specific method and IL instruction offsets.
Action 3. Runtime Translation. The message is sent to the runtime, where the method + IL instruction offset is translated into a memory address. Then, the breakpoint opcode is written to that address.
Action 4. User Interface. Users click buttons in the UI to indicate whether they want the process to run.
Action 5. Source Transformation. Forward the request to be executed.
Action 6. Runtime Translation. A message is sent to runtime 204, requesting it to proceed forward. Upon receiving the message, the runtime proceeds forward and then reaches the breakpoint at the previously set specific memory address. The breakpoint's memory address is translated back to the method and IL offset, and a notification message is then sent back to the debugger, indicating that the breakpoint at the specific method/IL offset has been reached.
Action 7. Source Transformation. The message indicating that the breakpoint has been reached is transformed from the method and IL offset back to the source line, and notifications about the breakpoint being reached at that source line continue to be sent to the UI.
Action 8. User Interface. The UI requests additional information about the new state of the process, allowing it to display current state information to the user, such as the current call stack for each thread.
Action 9. Source Transformation. To provide a source abstraction of the call stack, this component first requests a runtime abstraction that receives the call stack.
Action 10. Runtime Transition. To provide a runtime abstraction of the call stack, this component first requests to receive the state of memory and registers.
Action 11. Basics. Determine the memory and registers at the current time.
Action 12. Runtime Transformation. Using memory and registers, compute the runtime abstraction of the call stack.
Action 13. Source Transformation. Calculate the source code abstraction of the call stack using the runtime abstraction of the call stack.
Action 14. User Interface. Using the source code abstraction of the call stack, the UI can now display the current state of the process being debugged to the user.
In some embodiments, when using tracing actions 3, 6, and 11, the operation is no longer the same. For actions 3 and 6, no procedure can receive messages to set breakpoints, to advance execution, or to send back notifications when a breakpoint is reached. For action 11, no procedure can use the kernel API to query and determine memory or registers.
Therefore, in some embodiments, in order to achieve action 3 above, the source translation code requires the runtime translation code to indicate which memory address X has machine code for a given method + IL offset where a breakpoint should be set. This address X is saved for later use.
To achieve action 6 above, in some embodiments, the source translation code directly instructs the low-level base of the debugger or (multiple) other tools to advance the tracing to a new time t', where t' is the next time point where the machine instruction at address X will be simulated or emulated for execution. For action 6, one embodiment can use the same procedure typically used in dump debugging to translate from an IL offset to a procedure memory offset. However, this embodiment uses the translated memory offset to set a virtual breakpoint within the tracing replay engine. The virtual procedure (replay execution) stops when the replay engine reads this memory address during virtual execution. Indeed, if the tracing contains more than one version of the same functionality (via re-jitted), the runtime translation may require the tracing to provide multiple addresses to cover a single breakpoint. This address can be different for different time ranges in the tracing, or it can be the address of a runtime function (such as a jittering function) so that the runtime translation can locate the new re-jitted position of the function.
To achieve the above action 11, instead of reading from the real-time process, trace 418 is read and memory and registers corresponding to time t' are provided.
Replay debugging scene
By providing access to both forward and backward execution during debugging, system 800 can enhance debugging efficiency. For example, some embodiments support the following debugging scenarios.
By using context, technicians will realize that production debugging is difficult. Suppose a customer reports an issue on the website. How do developers debug it? Some familiar methods rely on information such as logs and dumps, which only provide point-in-time information. Therefore, if the problem doesn't reproduce or occur at the specific moment captured in the logs or dumps, developers must try again to capture useful information at different points in the execution, meaning it takes much longer to resolve the issue.
Instead, imagine an environment that can tell developers exactly what's happening in a production application, line by line. Using Microsoft Time Travel debugging or other reverse-execution replay implementations allows team members to collect a high-fidelity record of the application's behavior. Developers can then debug the application offline in a familiar environment, such as a Microsoft environment or other debugging or IDE.
As a concrete example, suppose the SmartHotels360 website is experiencing an issue; this is a demo website whose code is publicly available from Microsoft via GitHub.com. The developers of the company running the SmartHotels360 website receive a report from users indicating that a feature in BestHotels is no longer displaying data. However, it was working perfectly before, and the issue has not been reproduced in the company's test or staging environments. Members of the operations or engineering team have collected logs (trace 418) of the application while running the code powering the malfunctioning feature. Trace 418 can be collected into file 420 via command-line tools, or automatically triggered by a cloud environment (or another cloud environment) when certain conditions are met, such as throwing more exceptions than expected.
The developer opens the debugger and loads the SmartHotels360 code and trace file 420. Execution stops at a breakpoint on line 28 in the API that returns to BestHotels. Now, even though this is a log file, in this example, the developer can use many familiar commands to navigate it using a debugger they are typically familiar with. The developer wants to know what happened when the API was called. The developer steps over lines 28 and 29 and sees from the Locals window that after stepping over line 29, bestHotels has zero entries. If the debugger supports data hints, the developer can also view them, at least in this example.
Now, the developer has identified the cause of the problem in the `BestHotels()` routine. Therefore, the developer wants to investigate what happened in `BestHotels()`. Alternatively, to see what happened back to the original call, the developer could click Continue, click the breakpoint again, and step into the next call to `BestHotels()`, even though the values, objects, and memory addresses might differ from the partially debugged call. Alternatively, when the debugger state is difficult to reproduce, the developer could restart the application, which could be time-consuming. However, in this example, the environment supports time-travel debugging. Therefore, the developer uses the Reverse Continue button (requesting to continue backwards 920 operations) to rewind the application to the state of the previous breakpoint. One result of this rewind is that the locale will be reset to its previous state at line 28 before the aforementioned stepping is performed. Now, by ensuring that all values, objects, and memory addresses from the partially debugged call are the same, the developer can skip the `Load()` routine and step into `BestHotels()`.
At this point, the developer decides to step through `BestHotels()` and delve deeper into `GetBestHotels()`. Therefore, the developer wants to skip line 36 and then step into line 37. Suppose the developer accidentally pressed the skip button multiple times. Through time travel debugging, the developer can quickly go back and see what happened in `GetBestHotels()`. In fact, the developer can use the backstep button (requesting to step back into operation 914), which will take execution into `GetBestHotels()` and play it backward. The developer discovers that at the end of `GetBestHotels()`, the value of the local variable `bestHotels` (corresponding to the count) is zero. Clearly, all levels were filtered out.
Therefore, the developers decided to test the assumption by checking the ratings of all hotels. Remember, this trace occurred in production, so these values are actual. The developers can evaluate the expression using the debugger's live window, which is possible through the live debugging process. The developers evaluated the expression "AllHotels.Select(h => h.rating)" in the debugger's live window and found that the ratings were floating-point numbers, while the code was checking for rating values equal to integers 4 or 5. There was a data type mismatch; the shape of the data in production did not match the application's expectations.
Now suppose the developer has completed the debugging described above and wants to discuss it with a colleague and show them in detail what happened. The developer wants to start over at the beginning of the investigation and wants a way to quickly return to a specific point of interest. Therefore, the developer sets a breakpoint on line 21 and then rewinds to that breakpoint. Replaying then allows the developer to reproduce the debugging steps. If the developer wants to jump to the end, they can continue until they reach the last breakpoint they set.
In short, developers can use the application's high-fidelity tracing 418 to quickly debug issues, capturing what actually happened in production. With the power of a debugger adapted to the replay described here, developers can debug using a familiar debugger user interface and can debug forward and backward, saving significant developer time.
in conclusion
Although specific embodiments are explicitly shown and described herein as processes, configured media, or systems, it should be understood that the discussion of one type of embodiment generally extends to several other types of embodiments. For example, the process descriptions taken in conjunction with Figures 13 and 14 also help to describe the configured media and to describe the technical effects and operation of those similar systems and manufactures discussed in conjunction with the other figures. It is not necessarily required that limitations from one embodiment be read into another. In particular, processes are not necessarily limited to the data structures and arrangements presented when discussing systems or manufactures such as configured memory.
Those skilled in the art will understand that implementation details may relate to specific code, such as a specific API, a specific domain, and a specific sample program, and therefore may not necessarily appear in every embodiment. Those skilled in the art will also understand that program identifiers and some other terms used in discussing details are implementation-specific and therefore not necessarily related to every embodiment. Nevertheless, while their presence is not necessarily required herein, such details can assist some readers by providing context and/or can illustrate some of the many possible implementations of the techniques discussed herein.
References herein to an embodiment having some feature X, and references elsewhere herein to an embodiment having some feature Y, do not exclude embodiments having both feature X and feature Y, unless such exclusion is expressly indicated herein. All possible limitations of the claims are within the scope of this disclosure, as any feature that is prescribed as part of an embodiment may be expressly removed from some other embodiment, even if no specific exclusion is given in any example herein. The term “embodiment” is used herein only as a more convenient form of “process, system, article of manufacture, computer-readable medium of configuration and/or other example of the teachings herein applied in a manner consistent with applicable law.” Therefore, a given “embodiment” may include any combination of features disclosed herein, provided that the embodiment is consistent with at least one claim.
In each embodiment, not every item shown in the figures must be presented. Instead, an embodiment may include items not explicitly shown in the figures. Although some possibilities are illustrated herein by way of specific examples in the text and figures, embodiments may deviate from these examples. For example, specific technical effects or features of an example may be omitted, renamed, grouped differently, repeated, instantiated differently in hardware and/or software, or a mixture of effects or features appearing in two or more examples. In some embodiments, functionality shown in one location may also be provided in different locations; for example, those skilled in the art will recognize that functional modules can be defined in various ways in a given implementation without having to omit the desired technical effects from a collection of interactive modules considered as a whole.
The figures are referenced throughout the text using reference numerals. Any apparent inconsistencies in the wording related to a given figure reference in the figures or text should be understood as simply broadening the scope of the number referred to. Even when using the same figure reference, different instances of a given figure reference may refer to different embodiments. Similarly, given figure references...
It can be used to refer to verbs, nouns, and/or corresponding instances of each, for example, processor 110.
Instruction 110 can be processed by executing instructions.
As used herein, terms such as “an” and “the” include one or more of the indicated item or step. In particular, in the claims, a reference to an item generally means that there is at least one such item, while a reference to a step indicates at least one instance of performing that step.
The headings are for convenience only; information about a given topic can be found outside of the sections that indicate the subject in the headings.
All claims and abstracts submitted are part of the specification.
Although exemplary embodiments have been shown in the accompanying drawings and described above, it will be apparent to those skilled in the art that various modifications may be made without departing from the principles and concepts set forth in the claims, and such modifications do not necessarily encompass the entire abstract concept. Although the subject matter has been described in language specific to structural features and/or procedural actions, it should be understood that the subject matter defined in the appended claims is not necessarily limited to the specific technical features or actions described in the claims. Each means or aspect or technical effect identified in a given definition or example need not be presented or utilized in every embodiment. Rather, the specific features, actions, and effects described are disclosed as examples for consideration in implementing the claims.
To the maximum extent permitted by law, all changes that fall within the entire abstract concept but fall within the equivalent meaning and scope of the claims should be included within its scope.
Execution control with cross-level tracing mapping
Technical Field
Embodiments of this disclosure relate to execution control with cross-level tracking mapping.
Background Technology
Computer software is typically complex. Part of this complexity may stem from the nature of the work a program is designed to perform—for example, tracking a large number of real-world items or ongoing transactions over hours or longer, coordinating activities with other complex software, controlling complex hardware, and so on. Complexity also arises in almost any real-world use of software because many details are introduced and must be properly managed to instruct the computer hardware how to perform real-world work that would have been far less precise when initially described in English or another natural language. In other words, the conversion from a high-level description to a low-level implementation executable by a computer system inevitably introduces complexity. Even the source code of programming languages, which are more precise than natural languages, remains at a relatively high level and is therefore ambiguous, open to various interpretations and implementations. As the source code is translated into low-level instructions directly executable by computing hardware, many details are introduced and choices are made during the translation process.
Complexity introduces the possibility of commonly recognized programming errors (also known as "defects" or bugs). The process of identifying the cause of a defect and attempting to modify the program to remedy or remove its effects is called "debugging." Specialized software tools that assist in debugging are called "debuggers." The program being debugged is called a "debugging object."
Debugging is often easiest when developers can run a debug object at will, either slowly or at full speed, or pause its execution at will, and can inspect all its state information at any point during its execution. This is known as "real-time process debugging." However, such complete access to a debug object is often unavailable. For example, a debug object might be production software, which cannot be debugged in real-time without violating service agreements or harming the reputation, security, or financial condition of stakeholders. Pausing a real-time process debug object for even a few seconds at a time while a developer examines variable values, checks which functions are called with which parameter values, reviews source code, considers possible interpretations of defects, and designs tests that might help identify, remedy, or eliminate defects could cause unacceptable harm.
Therefore, state information is sometimes logged while the debug object is executing so that it can be examined later without essentially pausing the debug object's execution. Creating such a log may slow down the debug object, but it can provide useful information without compromising production performance goals as much as real-time debugging. For example, the debug object can be paused long enough to create a memory dump that copies some or all memory values associated with the debugger to disk at a specific point in time. Some aspects of the debug object's execution can also be logged in an execution trace. In cases where the debug object is not a real-time process, some debuggers support using such a trace to replay the traced execution of the debug object. Some debuggers allow the debug object's execution to be replayed forward or backward, enabling "time travel," "reverse," or "historical" debugging.
However, because execution traces may contain less information than is sometimes available during real-time process debugging, and because they record state information at a low level, technical challenges arise when debuggers or other software tools attempt to control replay execution (i.e., execution based on the recorded trace). Depending on the implementation, execution control operations that developers are familiar with and frequently use during real-time debugging may be less accurate or simply unavailable when attempted during trace-based replay.
Therefore, advancements in using low-level execution tracing to effectively and accurately achieve high-level execution control through debuggers or other replay or logging tools can help improve the information available to developers or automated performance monitoring tools. Consequently, such advancements will tend to improve the functionality of computer systems by supporting a more accurate understanding of their behavior and by enabling the mitigation or elimination of system defects.
Summary of the Invention
Some of the techniques described herein involve mapping locations in the program's source code to corresponding locations in the program's execution tracing, thereby improving the accuracy of execution control in tracing-based debugging. Some teachings involve specific breakpoint setting procedures that set one or more breakpoints at locations aligned with source code expressions or statements. Technical mechanisms for adapting to real-time debugging environments to support tracing-based reverse execution are described. Specific technical tools and techniques are described herein in response to the challenges of replaying debug object execution forward or backward or both forward and backward based on execution tracing. Other technical activities related to the teachings herein will also become apparent to those skilled in the art.
Some embodiments described herein use or provide trace replay execution control capabilities that utilize a processor, memory, traces recorded during the execution of a program at runtime, program source code, mappings between source code and its intermediate representations and traces, and an execution controller in a debugger or other tool. The runtime contains supporting code that provides dynamic compilation or memory garbage collection services as the traced program is executed and the trace is captured. A trace may include a record of native code instructions executed by the program. A trace may include a record of data accessed during program execution while the debug object is being executed. A trace may include one or more memory dumps or snapshots. A trace may be stored in one or more files or portions of non-volatile or volatile memory. The execution controller is configured to control the replay execution of the trace in response to a request from a tool. During replay, breakpoints configured to help align grouped native instructions with their corresponding source code entries are used, with the source code and trace native code instructions or other trace entries associated through source intermediate mappings and intermediate native mappings.
Some embodiments described herein use or perform computer-implemented trace replay execution control. The managed program being traced is identified. A managed program (also called a “runtime management” program) is a program configured to execute in conjunction with calls to the runtime. The managed program being traced is a program that is being traced or configured to be traced. A trace replay execution control request is received in a software tool. Based on the trace replay execution control request, a mapping is made between the source code of the managed program being traced and an intermediate representation of that source code, and another mapping is made between that intermediate representation and the trace. The trace does not include any execution instances of the runtime. Replay of the trace can be controlled by, for example, simulating the trace activity in a direction and number corresponding to the trace replay execution control request (e.g., taking a step forward, or repeating the entire routine by stepping over it), or by setting breakpoints at the trace locations, or by performing both of the above.
The examples given are merely illustrative. This "Summary" is not intended to identify key or essential features of the claimed subject matter, nor is it intended to limit the scope of the claimed subject matter. Rather, this "Summary" is provided to introduce some technical concepts in a simplified form, which will be further described in the "Detailed Description" below. The invention is defined by the claims, and in the event of any conflict between the Summary and the claims, the claims shall prevail.
Attached Figure Description
A more specific description will be given with reference to the accompanying drawings. These drawings are only illustrative of selected aspects and therefore cannot fully define the coverage or scope. Although dashed lines indicate that some items are optional, any item recited in the claims or any item that a person skilled in the art would consider non-optional for embodying the claims should be understood to be present in some form in an embodiment of the claims.
Figure 1 is a block diagram showing a computer system and also showing the configured storage media;
Figure 2 is a block diagram illustrating aspects of real-time process debugging;
Figure 3 is a block diagram illustrating aspects of debugging based on a copy of the memory made at a single point in time;
Figure 4 is a block diagram illustrating aspects of an example architecture for trace-based debugging, including the main request and response between the debugger and the replay adapter;
Figure 5 is a block diagram showing various memory cells that can be referenced during debugging or in tracing;
Figure 6 is a block diagram illustrating a machine-level request that can seek information from the execution trace or impose execution control during the replay of the execution trace.
Figure 7 is a block diagram illustrating the response to a machine-level request;
Figure 8 is a block diagram illustrating an example tracking replay execution control system;
Figure 9 is a block diagram illustrating some of the control operations performed during the tracking and replay process;
Figure 10 is a block diagram illustrating some aspects of thread tracing data;
Figure 11 is a block diagram illustrating some aspects of one or more intermediate representations;
Figure 12 is a block diagram illustrating some aspects of a real-time process debugging environment adapted to use traces that support reverse execution debugging;
Figure 13 is a flowchart illustrating an example trace replay execution control method; and
Figure 14 is a flowchart further illustrating some of the tracking replay execution control methods.
Detailed Implementation
Overview
Debugging in a production cloud environment presents significant technical challenges. For example, suppose a specific request R for an online shopping cart is not working. How can developers debug the processing of request R without slowing down the processing of all other requests and minimizing the slowdown in the processing of request R? To find the defect, developers use information about what is happening internally in the code, such as a way to look at the values of variables at one or more points of interest during the processing of request R.
The trace-based debugging innovations discussed here help overcome technical challenges that traditional methods cannot solve. For example, many traditional debuggers and debugging methods allow developers to set halt breakpoints to obtain information about variable values. A halt breakpoint is an instruction to pause execution, giving developers time to examine memory contents at a given point in processing and consider possible interpretations of what is observed. However, in a production environment, halt breakpoints may pause the processing of a large number of requests, cause requests to fail completely (e.g., timeout), or cause execution to take a different path—none of which are desirable. Even pausing only a single thread can lead to unwanted aborted requests and produce unpredictable side effects that hinder debugging, degrade performance, or both.
Some familiar debugging methods involve adding print statements at specific points in the code to print the value of a particular variable, or adding other code, for example, to test the value of a variable to see if it is the value the developer expected at that point in the code. However, these methods may require recompiling and redeploying the code, which is undesirable in production environments, especially if recompiling and redeploying are to be done multiple times as part of an iterative debugging process to find and fix individual defects.
Developers can inject operations into request handling code at execution time to create a copy of some or all of the memory relevant to the request. This copy can include a "snapshot" 304 (an in-memory copy of a process that shares memory allocation pages with the original process via copy-on-write) or a "dump" file 302 (a serialized copy of the process), or both. Some traditional debuggers can read dump files or snapshots and, given appropriate metadata, present the memory contents in a specific format that shows variable values converted from binary to an informative structure including variable names and displayed based on the variable's corresponding data type. However, dumping memory to a file is time-consuming, slowing down not only request R but also the processing of all requests in the example scenario. While taking a snapshot is much faster than creating a dump file, it can require many attempts by the developer to find useful points in the processing to obtain a memory snapshot that reveals the defect, and snapshots consume space in RAM. To view memory at another point in time other than execution time, captured in a dump file or snapshot, another copy of the memory can be created.
Real-time processes are used to view memory at any point in time during the real-time process. In many modern computing systems, as illustrated in the example in Figure 2, the real-time debug object 202, in addition to depending on the operating system, also includes a runtime 204. The runtime 204 provides garbage collection or dynamic code compilation (i.e., JIT compilation or compilation of intermediate language code) or both. Garbage collection may utilize object reachability analysis, object reference counting, or other strategies. Some configurations include an interpreted runtime 204, and those skilled in the art will recognize that the teachings herein can be applied to exercise execution control over the interpreted runtime by overlaying the interpreter's view onto the native trace and using breakpoints within the interpreter itself. Additionally, some runtimes (e.g., runtimes) do not always JIT compile their IL representation (what Java terminology calls "bytecode"). Instead, the runtime may choose to interpret bytecode for less frequently used functions. In this case, execution control may be exercised over the runtime code itself, and a mapping may be made from native code to internal runtime data structures to IL to source code. The mapping from native code to internal runtime data structures to IL can be considered an example of an intermediate native mapping 812, and the mapping from IL to source code can be considered an example of a source intermediate mapping 810.
Unlike processes lacking runtime capabilities, which can be directly controlled by the debugger through the insertion of pause breakpoints, runtime-dependent processes cannot be directly controlled by the debugger 200 because their runtime is effectively hidden from the debugger's memory entries 206, such as memory locations, memory contents, and instruction pointers. To show the developer what is in memory during debugging, the debugger sends a main request 214 to the runtime requesting the current memory values. The runtime sends these values back to the debugger in a main response 216, and the debugger displays the values it received in the response message in a user interface 210.
As a specific example of the drawbacks of the previous approach, consider runtime 204, which is implemented as a virtual machine executing intermediate language (IL). IL code cannot be easily debugged using a traditional native code debugger because that debugger is intended for debugging the virtual machine/runtime, not the IL code.
The runtime also controls the execution of the real-time debug object. Traditional debuggers for IL or languages that compile to IL work by establishing a communication channel between the debugger and the runtime inside the debug object. The runtime within the debug object performs most of the work required to provide the debugging experience. In one example, to set a breakpoint at offset 28 in the intermediate language (IL) instruction in method Foo, a message is sent to the runtime requesting it to set the breakpoint at offset 28 in Foo. The thread within the runtime then receives the message, translates Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. Similarly, to perform familiar execution control operations, such as stepping, stepping in, stepping out, and stepping skipping, the debugger sends a main request 214 to the runtime requesting the operation. The runtime 204 performs the operation and sends an updated status to the debugger in a main response 216, and the debugger displays the result indicated in the response message in a user interface 210.
User interface 210 graphically displays to the user a representation of the debugger's debug object program state. Examples of program states include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, a set of variables in each frame of the call stack, and the values of these variables. The user interface may include windows displaying local data of the routine, watched variables and their values, source code, expression evaluators, and other information about the live debug object 202.
In some implementations, the runtime translation section of debugger 200 is responsible for translating between low-level concepts (such as memory units and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, one or more call stacks for each thread, and the IL instructions to be executed next. Note that the call stack of the abstract runtime layer is not necessarily the same as the call stack at the abstract source code level; for example, the virtual machine's call stack may not match the virtual call stack of the IL code being executed within the virtual machine.
Creating an execution trace 418 of the process is possible. The trace can then be replayed using a simulation of the computer system 102. Sometimes, the trace process is written in source code 212, a high-level language that needs to be executed by the runtime 204 in real-time debugging object 202. The trace itself can be difficult to debug because the trace data reflects a view at a low level (e.g., runtime or just-in-time compiled code or both), rather than the high-level language in which the program was written. Some tracing techniques do not provide a high-level view of the process that the user 104 might prefer. Most high-level runtimes require the runtime itself to provide information about the program running within its framework. Therefore, regular debugging may require the process to be executed within the runtime, which is not optional when debugging is based on a trace rather than a real-time process.
Like any other process, runtime can be traced. However, debugging software other than runtime is more common than debugging runtime. The tracing process can include or exclude tracing some or all of the code that is part of the runtime itself.
This functionality does not apply to situations where there is no trace file currently running. To control the execution of a live process that is executing code that depends on a runtime 204 error, the debugger can send a message to the runtime requesting an action such as "step" or "run," which the runtime then performs on behalf of the debugger.
The ability for a debugger to send messages to the runtime to perform actions on behalf of the debugger does not apply to trace files for which there is no currently executing runtime. Dump files 302 and snapshots 304 are similar to traces in that the runtime is unavailable. A runtime can be represented as a dump, snapshot, or trace, but it is not currently executing and therefore cannot be invoked in the traditional way.
Nevertheless, the trace file 420 can be made part of the debugging environment. Some trace-based debugging embodiments discussed here extend debugging power, allowing the debugger to replay execution from the trace file, starting from one or more points in execution time chosen by the developer, and then moving forward or backward in increments chosen by the developer within the trace execution. One approach is to insert a replay layer between the trace and a high-level language debugger. The replay layer understands runtime execution control messages, thereby allowing high-level control over the traced process.
In some cases, developers can use a "time travel" debugger to control execution replay, running forward or backward in execution time as the recorded trace 418 is replayed. This leverages the debugger's ability to present program state information and memory, such as instruction pointers (multiple), in useful high-level (e.g., named and data-data-based) variable representations, not only for snapshots as before but now for continuous replays of segments of execution time recorded during code execution. Debugging can be made more efficient by aligning grouped trace data with corresponding source code structures (such as expressions and statements). Developers can examine memory values captured in the trace at multiple points in a high-level representation based on the low-level data recorded in the trace file.
As the trace is replayed, the included replay layer can be used to control the state of the debug object. With this adaptation, debugger 200 can apply a runtime (high-level) view of the process trace that has been recorded as machine-level operations. For the purposes of this application only, "machine-level" operations are operations specified at the machine-specific level. Generally, "native" and "machine-level" are used interchangeably herein relative to instructions or code.
Some may view some of the embodiments described herein in a broader context. For example, concepts such as controlled execution, recorded execution, and replaying recorded execution may be considered relevant to specific embodiments. However, this does not accord with the availability of a broad context and seeks proprietary rights to abstract concepts; they are not. Rather, this disclosure focuses on providing suitable specific embodiments whose technical effects fully or partially solve specific technical problems, such as how to automatically associate high-level control requests with machine-level tracing, and other problems addressed herein. Other media, systems, and methods relating to controlled execution, recorded execution, or replaying recorded execution are not within the scope of this invention. Thus, ambiguity, mere abstraction, lack of technical features, and the associated problems of proof are also avoided upon proper understanding of this disclosure.
Technical features
The technical features of the embodiments described herein will be apparent to those skilled in the art and will also be apparent to various interested readers in a variety of ways. Some embodiments address technical activities rooted in computing technology and improve the functionality of computing systems by aiding in debugging these systems, thereby improving system uptime, system accuracy, and power utilization relative to the computational results produced. For example, some embodiments provide system debuggability functionality that helps reduce the amount of time developers spend locating defects while debugging by allowing replay execution to move backward to the desired point rather than restarting from the beginning of execution and moving forward to that point. Some embodiments improve system debuggability by accurately aligning trace data with corresponding source code statements. Some embodiments provide additional debugging functionality in the system, such as the ability to set breakpoint address ranges instead of setting breakpoints at one address at a time.
Some embodiments include technical components, such as computing hardware, that interact with the software in a manner that goes beyond typical interactions within a general-purpose computer. For example, in addition to general interactions (such as general memory allocation, general memory reads and writes, general instruction execution, and some form of I/O), some embodiments described herein also implement backward step-out replay operations as disclosed herein.
Some of the technical effects provided by the embodiments include: more efficient use of debugging time, reduced re-tracing to obtain additional trace data, and improved debugger functionality for exploring defect causality.
Some embodiments include technical adaptations. Some embodiments include a replay layer adapter that accepts requests formatted for runtime, i.e., in a message format compatible with familiar debugger runtime communication, and responds to these requests in a format that can be used by the runtime during real-time debugging. In some embodiments, the replay adapter provides an interface that hides the differences between real-time process debugging, dump-based debugging, and time-travel tracing-based debugging. Some embodiments include a mapping between source code, intermediate representations(s), and trace data.
From the provided description, other advantages of the technical features based on the teachings will also be apparent to those skilled in the art.
Acronyms and Abbreviations
The following defines some acronyms and abbreviations. Other abbreviations may be defined elsewhere in this document, or may not require any definition and will be understood by those skilled in the art.
ALU: Arithmetic and Logic Unit
API: Application Programming Interface
BIOS: Basic Input/Output System
CD: Compressed disc
CPU: Central Processing Unit
DAC: Data Access Component
DVD: Digital Multifunction Disc or Digital Video Disc
FPGA: Field Programmable Gate Array
FPU: Floating-point processing unit
GPU: Graphics Processing Unit
GUI: Graphical User Interface
IDE: Integrated Development Environment, sometimes also called an "interactive development environment".
IL: Intermediate Language
OS: Operating System
RAM: Random Access Memory
ROM: Read-Only Memory
Additional terms
Reference is made herein to exemplary embodiments such as those shown in the accompanying drawings, and specific language is used to describe them. However, changes and further modifications to the features illustrated herein, as well as additional technical applications of the abstract principles illustrated by specific embodiments herein, that may occur to those skilled in the art, should be considered within the scope of the claims.
The meanings of the terms are stated in this disclosure, and these statements should be carefully considered when reading the claims. Specific examples are given, but those skilled in the art will understand that other examples may also fall within the meanings of the terms used and within the scope of one or more claims. The terms herein do not necessarily have the same meaning as they do in their general use (especially in non-technical use), in a particular industry, or in a particular dictionary or encyclopedia. Reference numerals may be used with a variety of wording to help indicate the breadth of the terminology. Omission of reference numerals from a given text does not necessarily mean that the text does not discuss the figures. The inventors claim and exercise their rights to their own lexicographical compilations. Terms in quotation marks are explicitly defined, but may also be implicitly defined without quotation marks. Terms may be defined explicitly or implicitly in the “Detailed Description” and/or elsewhere in the application.
As used herein, "computer system" can include, for example, one or more servers, motherboards, processing nodes, laptop computers, tablets, personal computers (portable or non-portable), personal digital assistants, smartphones, smartwatches, smart bracelets, cellular or mobile phones, other mobile devices having at least a processor and memory, video game systems, augmented reality systems, holographic projection systems, televisions, wearable computing systems, Internet of Things nodes, and/or other devices that provide one or more processors that are at least partially controlled by instructions. Instructions may take the form of firmware or other software in memory and/or dedicated circuitry.
A "multithreaded" computer system is a computer system that supports multiple threads of execution. The term "thread" should be understood to include any sequence of instructions that can be performed or scheduled (and possibly synchronized), and may also be referred to as, for example, as a "procedure" or "coroutine". Threads can run in parallel, sequentially, or in a combination of parallel execution (e.g., multiprocessing) and sequential execution (e.g., time-sliced).
A processor is a unit for processing threads, and is the core of implementations such as simultaneous multithreading. Processors comprise hardware. A given chip can contain one or more processors. Processors can be general-purpose or customized for specific purposes, such as vector processing, graphics processing, signal processing, floating-point arithmetic, encryption, I/O processing, etc.
The "kernel" includes the operating system, virtual machine monitor, virtual machine, BIOS code, and similar hardware interface software.
"Code" refers to processor instructions, data (including constants, variables, and data structures), or both. "Code" and "software" are used interchangeably in this document. Executable code, interpreted code, and firmware are some examples of code. Code that is interpreted or compiled for execution is called "source code."
The term "program" is used extensively in this article to include applications, kernels, drivers, interrupt handlers, firmware, state machines, libraries, and other code written by programmers (also known as developers) and/or automatically generated.
"Service" refers to consumable programs provided in a cloud computing environment or other network environment.
An "execution time point" refers to a specific point in time that is executed for a processing unit or thread, especially in relation to tracing execution. References to "specific execution time" or "execution time t" in this document refer to execution time points. For example, an execution time point can be implemented as a timecode variable or timecode value, or as a relative position in other records of tracing or execution activity. An execution time point ta "earlier than" or "later than" an execution time point tb indicates that the relative order of the two execution time points is determined. Similarly, a "younger" execution time point is a later execution time point than an "older" execution time point.
Information regarding the order of events in a tracing may be incomplete. Therefore, a tracing may have enough information to determine that event A precedes event B, or that event D follows event C. However, the relative order of events may also be partially or completely uncertain, even when considering a tracing. A tracing may show that event E does not follow event F, but this does not necessarily mean that E precedes event F; similarly, without a tracing also showing that K follows J, a tracing may show that event K does not precede event J. A tracing may also lack sufficient information to establish any order of two specific events relative to each other.
A "timecode" represents a monotonically changing value that can be used to impose order on at least some events in an execution tracing. It can be expected that timecodes are typically monotonically increasing values, but they can also be implemented as monotonically decreasing values. Some examples of timecodes include instruction counters, clock times (also known as clock ticks), and completely artificial (not register- or instruction-based) monotonic values. Depending on the tracing, all or some, or no, of the traced events may have corresponding associated timecodes. When timecodes exist, they can be unique, or they may simply be monotonic due to some timecode values being repeated.
A "memory cell" refers to an addressable unit of memory. Examples include bytes or words in RAM or ROM, processor registers, cache lines, and other addressable memory cells.
An emulator performs a simulation that provides the same functionality as the original hardware, but uses a different implementation or different hardware, or both. An example is a CPU emulator, which functions similarly to a CPU and can be used to execute code like the original CPU hardware, but with a different implementation; for example, the emulator can run on completely different physical hardware.
Unless otherwise stated, as used herein, “include” allows for additional elements (i.e., include means contain).
"Optimization" means improvement, not necessarily perfection. For example, an already optimized program or algorithm can be further improved.
For example, the term "process" is sometimes used herein as a term in the field of computer science and, in a technical sense, encompasses users of computational resources, namely coroutines, threads, tasks, interrupt handlers, application processes, kernel processes, procedures, and object methods. "Process" is also used herein as a term in patent law, for example, when describing process claims in contrast to system claims or claims of articles of manufacture (configured storage media). Similarly, the term "method" is sometimes used herein as a technical term in the field of computer science (a "routine") and also as a term in the field of patent law ("process"). Those skilled in the art will understand the meaning intended for use in particular contexts and will also understand that (in the sense of patent law) a given claimed process or method can sometimes be implemented using one or more processes or methods (in the sense of computer science).
Contrary to the absence of automation, "automatically" refers to the use of automation (e.g., general-purpose computing hardware configured by software for the specific operations and technical effects discussed herein). In particular, steps performed "automatically," while potentially initiated or interactively guided by a human, are not manually executed on paper or in the human mind. Automated steps are performed by machines to achieve one or more technical effects that would be impossible without such technological interaction.
Those skilled in the art will understand that technical effects are the presumptive purpose of technical embodiments. For example, the fact that an embodiment involves computation, and that some computations can also be performed without technical components (e.g., by paper and pencil, or even as mental steps), does not eliminate the presence of technical effects or alter the specificity and technical nature of the embodiment. Operations such as searching trace data at a sufficiently fast speed to allow replay within one or two orders of magnitude of the original execution speed, and computations for grouping native instructions for the trace and aligning instruction groups with corresponding source code items, should be understood herein to require, in addition to their inherent digital nature, a speed and accuracy unattainable by human thought processes (human thought cannot directly interface with trace files or other digital storage to retrieve necessary trace data). This is well understood by those skilled in the art, but others may sometimes benefit from being informed or reminded of the facts. Unless otherwise stated, contrary to mere thought experiments, embodiments are assumed to be capable of large-scale operation in a production environment or a test laboratory within a production environment.
"Computationally" also implies the use of computing devices (at least a processor and memory) and excludes results obtained solely by human thought or action. For example, performing arithmetic with paper and pencil, as understood herein, is not computationally arithmetic. Computational results are faster, broader, deeper, more accurate, more consistent, more comprehensive, and/or provide technical effects beyond the reach of human performance. A "computational step" is a step performed computationally. Neither "automatically" nor "computationally" necessarily means "immediately." "Computationally" and "automatically" are used interchangeably in this document.
"Actively" means without a direct request from the user. In fact, the user may not even be aware that an active step in an embodiment is possible until the result of the step has been presented to the user. Unless otherwise stated, any computational and/or automatic steps described herein may also be performed actively.
Throughout the document, the optional phrase "(multiple)" is used to indicate the presence of one or more of the indicated features. For example, "(multiple) processors" means "one or more processors" or equivalently "at least one processor".
For purposes of U.S. law and practice, the use of the term “step” in the claims or elsewhere herein is not intended to invoke means plus function, steps plus function, or to require interpretation under 35 U.S.C. 112(6)/112(f). Any presumption of such effect is hereby expressly rejected.
For the purposes of U.S. law and practice, claims are not intended to invoke a means-plus-function interpretation unless the phrase “means for…” is used. Claim language intended to be interpreted as means-plus-function language (if any) will explicitly state this intention by using the phrase “means for…”. When a means-plus-function interpretation is adopted, whether by using “means for…” and/or by the court’s legal interpretation of the claim language, the means listed in the specification for a given noun or given verb shall be understood to be linked to the claim language and hereby linked in any way that: appears in the same box in the drawing block diagram, is denoted by the same or similar name, or is denoted by the same reference numerals. For example, if a claim limitation refers to “zac widget” and that claim limitation is subject to a means-plus-function interpretation, then all structures identified anywhere “zac widget” is mentioned in any block, paragraph, or example in the specification, or bound together by any reference numerals assigned to the zac widget, shall be considered part of the structures identified in the zac widget application and contribute to defining the equivalent itemset of the zac widget structure.
Throughout this document, unless otherwise expressly stated, any reference to a step in the process is assumed to be that the step can be performed directly by the interested party, and/or indirectly by a party through an intervention mechanism and/or intervention entity, and still within the scope of that step. That is, unless explicitly stated as directly performed, the step does not need to be performed directly by the interested party. For example, steps involving actions performed by the interested party concerning a destination or other subject, such as alignment, clearing, compiling, continuing, controlling, debugging, simulating, encountering, exceeding, executing, acquiring, grouping, identifying, mapping, receiving, recording, replaying, requesting, responding, sending, setting, specifying, stepping (and variations such as stepping in, stepping out, stepping skipping), terminating, tracing (and alignment, aligned, clearing, cleared, etc.), may involve intervention actions performed by another party, such as forwarding, copying, uploading, downloading, encoding, decoding, compressing, decompressing, encrypting, decrypting, authenticating, invoking, etc., but should still be understood as being performed directly by the interested party.
Whenever data or instructions are referenced, it should be understood that, for example, these items configure computer-readable storage memory and/or computer-readable storage media to convert them into a particular article, as opposed to simply existing on paper, in a person's mind, merely energy, or merely a signal propagating on a wire. For the purposes of U.S. patent protection, according to the interpretation of the U.S. Patent and Trademark Office (USPTO) in the re Nuijten case, memory or other computer-readable storage media is not a propagation of a signal, carrier wave, or merely energy outside the scope of the patentable subject matter. In the United States, no claim covers the signal itself, and any claim interpretation that asserts the contrary is unreasonable. Unless expressly stated otherwise in a claim granted outside the United States, the claims do not cover the signal itself.
Furthermore, although there are obvious contrary provisions elsewhere herein, it should be understood that there is a clear distinction between (a) computer-readable storage media and computer-readable repositories and (b) transmission media (also referred to as signal media or energy-only). A transmission medium is a computer-readable medium or energy-only that propagates a signal or carrier wave. Conversely, computer-readable storage media and computer-readable repositories are not computer-readable media that propagate a signal or carrier wave. Unless expressly stated otherwise in the claims, “computer-readable medium” means computer-readable storage media, not the propagation of a signal itself, nor energy-only.
The term "example" in this document is illustrative. The term "example" is not to be used interchangeably with "invention." Examples may be freely shared or borrowed to create other examples (provided the result is operable), even if the resulting combinations of aspects are not explicitly described herein. It is necessary for a person skilled in the art to perceive that every licensed combination is essential, contrary to the policy of acknowledging that patent specifications are written for those skilled in the art. Formal calculations of combinations and informal intuition regarding the number of possible combinations, even those arising from a small number of composable features, will indicate that there are numerous combinations of aspects described herein. Therefore, requiring an explicit description of each combination contradicts the policy of requiring a concise patent specification and demanding knowledge of the relevant technical field from the reader.
List of reference numerals
The following list is provided for convenience and support of the accompanying drawings and as part of the specification text, which describe innovations by referencing multiple items. However, items not listed herein may still be part of a given embodiment. For clarity and readability, the given reference numerals are cited near some (but not all) of the referenced items in the text. Different examples or instances of the given items may use the same reference numerals. The list of reference numerals is:
100: Operating environment, also known as computing environment
102: Computer system, also known as computing system or computing architecture.
104: User
106: Peripheral equipment
108: Generally refers to the internet.
110: Processor
112: Computer-readable storage media, such as RAM, hard disk
114: Removably configurable computer-readable storage media
116: Processor-executable instructions; may be on removable media or in other memory (volatile or non-volatile or both).
118: Data
120: (Multiple) kernels, such as (multiple) operating systems, BIOS, device drivers.
122: Tools, such as antivirus software, profilers, debuggers, editors, compilers, interpreters, security penetration testers, obfuscators, automated performance monitoring tools, etc., can be adapted to use the execution control taught in this article.
124: Applications, such as word processors, web browsers, spreadsheets
126: Display screen
128: Computing hardware, not otherwise associated with reference numerals 106, 108, 110, 112, 114.
200: Debugger, also referring to debugging activities.
202: Real-time debugging of object programs or procedures
204: Runtime, such as the Common Language Runtime, a virtual machine, or other virtual machines that dynamically translate code for execution (trademark of Oracle U.S., Inc.)
206: Memory items, such as application or system data structures.
208: Data Access Components for the Debugger
210: Debugger User Interface
212: Source code, related information such as metadata and symbol tables.
214: A master request from the debugger for information about a source of debug object, such as a live debug object, dump file reader software, snapshot reader software, or trace file reader software.
216: A response to a master request that seeks information from a debug object's information source or state change; also known as a "master response," such as in a response at the abstraction level of the master request, rather than in a first, initial, or most important response.
218: Statements in source code; for example, they can be explicitly delimited by semicolons or parentheses, curly braces or square brackets, or implicitly delimited by spaces or end-of-line characters.
220: An expression in the source code; syntactically defined by the programming language used; it can be an assignment of function calls, object member assignments, routine calls, or another combination of constants, variables, operators, and routines that produce a result or side effect.
302: Dump file, also known as a storage dump; may include additional information such as indexes or metadata.
304: Storage snapshot; may include additional information such as indexes or metadata.
402: Execution control code for a debug object in the debugger, such as requesting or simulating execution control over the debug object, including stepping through the debug object, setting breakpoints, or executing the debug object until a breakpoint is reached.
404: Cross-level mapping in debuggers or other tools, such as mapping between source code and intermediate representation or mapping between intermediate representation and trace data.
406: A replay component that uses trace files to simulate the execution of a debug object; the trace replay component 406, alone or in conjunction with other execution controllers 402, 408 (implementation-dependent), uses traces to simulate the execution of the original process and allows viewing of CPU state and memory units over time; in some embodiments, this simulation can be performed forward or backward.
408: A replay adapter for the replay component, which allows the replay component to send requests and receive responses that are also used during real-time debugging. In a trace file debugging scenario, the replay layer (i.e., the replay component plus the replay adapter) receives and responds to main requests from the debugger, which can be received and responded to by the runtime in the real-time debugging scenario, and the replay adapter can also make secondary requests to the trace file.
410: Replay adapter interface; configured for communication with the debugger.
414: A secondary request for the trace from the replay adapter, where “secondary” indicates a lower level of abstraction than the main request 214; the secondary request may be a machine-level request, which may be implemented as communication to the trace file reader, or it may be implemented internally within the replay adapter (e.g., as a function call).
416: A response to a machine-level request that seeks information from the trace; also known as a "secondary response," as in the response at the abstract level of the secondary request, rather than as in the second response; it can be implemented as communication from a trace file reader or internally within a replay adapter (e.g., as a function result or data structure update).
418: Performing a trace; Although the dashed lines in Figure 4 indicate that a given trace may include individual items or omit individual items, this document assumes that the trace is not empty, and therefore it is shown as a solid line over the box that generally tracks data 454; 418 can also refer to the activity of creating a trace, which is sometimes also called a “trace” or “record”.
420: A trace file containing execution trace data; this may include machine-level trace data, i.e., data that records execution activities at the native code level.
422: Precise tracking data during tracking.
424: A timecode in a trace that identifies a specific point in time during the execution of the traced code; it may be linked to or embedded in other data within the trace, for example, trace data that explicitly states the point in time at which the stated operation is associated with the stated memory address relating to the stated data value; the timecode may be implemented as, for example, a clock tick or an instruction counter; for each recorded operation, some traces may contain a unique timecode, but in some trace data, the timecode may be repeated or omitted.
428: Gap in the timecodes of a trace, used to explicitly or implicitly indicate the execution time points in which tracing was not performed (e.g., a range when tracing is disabled for a thread or processing unit). This can include any gap where adjacent timecodes differ by a default value or a specified increment (typically 1), for example, the gap for timecode sequences 2, 3, 4, 300, 301, 302 is between 4 and 300, and the gap for timecode sequences 250, 500, 750, 1000, 2000, 2250, 2500 is between 1000 and 2000.
430: Indexes to data in the trace file, such as reverse lookup data structures, used to quickly identify trace attributes, memory lifetime index information, and other searchable lists of locations in the trace data that may be of particular interest.
432: Keyframes in tracking data; for example, they may exist at fixed intervals in the tracking data to allow for faster replay jumps to (or near) keyframes during tracking playback.
434: The code executed, such as the opcodes and parameters of the debug object's machine-level code executed by the processor while the debug object is running and being traced.
436: Stack activity that occurs while the object being debugged is running and being traced, such as stack growth, stack shrinkage, and the execution time at which this activity occurs.
438: Data stream; can correspond to a single thread or a group of threads, can correspond to a processor unit (e.g., a processor core); can correspond to all cores in a given processor socket; can be annotated with metadata to aid in replay.
440: Processor core activities that occur while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by the core.
442: Processor socket activity that occurs while the debug object is running and being traced, such as the opcodes and parameters of instructions executed by any core located in a given processor socket.
444: Thread activity that occurs while the debug object is running and being traced, such as instructions executed during thread runtime, memory accesses performed during thread runtime, and associated metadata such as thread IDs and timestamps.
446: Register activities that occur while the debug object is running and being traced, such as what value is read from which register at what timecode, and what value is written to which register at what timecode.
448: Memory address
450: Instruction opcode
452: Data value
454: Generally refers to tracking data.
456: A tuple, i.e., two or more items of trace data associated in a trace, representing the same operation during trace execution; for example, a memory read operation or a memory write operation may be recorded as a tuple on a single line in the trace, which contains or otherwise associates the opcode (e.g., read or write), the address (e.g., RAM address or register ID), and the data value that has been read or written together.
458: Tracking entry
502: Memory unit, such as a byte or word in RAM or ROM, processor register, cache line, or other addressable memory unit.
504: The stack, for example, is a portion of memory where state information is pushed when a routine is entered, and then popped as control returns from the routine to the code that called the routine; it is generally distinguished from heap memory.
506: The stack base address defines the starting point from which the stack is allocated in contiguous memory; the stack is assumed to grow in a known direction using the allocation of stack memory in the system, which in a given system may be upward (i.e., the address increases as an item is pushed onto the stack), but in another system it may also be downward (i.e., the address decreases as an item is pushed onto the stack); the term "growing" here refers to the direction of stack growth in the system under discussion, while "shrinking" refers to the opposite direction.
508: Stack frame, or allocation record, is allocated on the stack when a routine is called; it typically contains the return address, which identifies the location in the code where execution will resume when the routine returns; it may also contain the address of a value passed as an argument to the routine when it is called, or the address of such an argument value.
510: Heap memory allocated and released along with the construction and release of objects; in some cases, the heap can be automatically garbage collected, and the heap identifies and marks it as available memory, which holds objects that are no longer reachable during the live execution of the process; in other cases, memory allocated from the heap requires a separate explicit call to release the allocated memory.
512: Object
514: Cache memory; for example, it can be in RAM working memory or on the processor chip.
516: Registers in the processor core
518: Object property; a named value that is part of an object; it can be a function, in which case the property is usually called a method; it also refers to a function that implements an object property; a function is a routine that returns a value.
520: ROM (Read-Only Memory); typically non-volatile.
522: Non-volatile memory other than onboard ROM, such as removable flash memory, disk or optical disk storage, magnetic tape storage, etc.
524: RAM (Random Access Memory); typically volatile.
526: Local memory, for example, memory that is local to the stated or implicit context, such as memory that is local to the routine during its execution and then freed, or memory that is local to the thread.
528: Global memory, such as memory that is global for a stated or implicit context, such as memory that is global relative to a set of multiple routines or relative to a set of threads during the execution of any of them.
530: The characteristics of memory that the addition or reduction of an entity outside a thread may alter the value stored in the memory cell, such as whether the memory cell is write-protected relative to other threads, or whether it is in shared memory (such as memory that is global relative to multiple threads).
602: Memory cell specification, such as an address in ROM or RAM or cache, or a register ID, or another item that specifies the memory cell by distinguishing it from other memory cells to allow access (read or write, or a reasonable attempt to read or write) to the memory cell; multiple memory cells may also be specified, for example, as a range of addresses.
604: Register ID, for example, register name, or index to a register array.
606: Address range, that is, a set of adjacent addresses that identify a set of corresponding contiguous memory units; as an example, a range can be specified as a pair of addresses (high address and low address); as another example, a range can be specified as a base address and a count of contiguous units based on the base address.
608: A specification of one or more execution time points, for example, as a specific time code or a range of time codes; the range can be specified as a pair of time codes (start time code and end time code), or it can be specified as a base time code and a count of time code increments, such as the number of clock ticks or the number of instructions.
610: Instruction count, which can be used as a time code; it can be an absolute count from the start of execution of a procedure, or a relative count such as when execution resumes from a thread.
612: System clock value, for example, in milliseconds or CPU cycles.
614: Execution time range specification, that is, data that specifies the range of execution time points; for example, it can be implemented as a pair of time codes (start and end) or as a base time code and a count of time code increments based on the base time code.
616: Execution Time Point
618: Perform control operations, such as stepping forward, stepping backward to skip, going to the specified location, setting or clearing breakpoints, etc.
620: Identifier for performing a control operation; for step or continue operations, it refers to or includes the direction (i.e., forward or backward; "reverse" and "backward" are used interchangeably in this document), and also refers to or includes the increment size (e.g., one step, step skipping a routine, or continue until a breakpoint is encountered).
702: Data values derived from tracking data
704: Instruction Pointer, which identifies a specific instruction or execution point in the trace data; it is a reference position for replay execution to move forward or backward; "backward" means towards younger execution points, and "forward" means towards older execution points.
706: Status code indicating the result of a request, such as successful execution of control operation, control operation initiated (for asynchronous control), or control operation failed.
800: Tracking and Replay Execution Control System
802: The process of the program being traced; it may include one or more threads.
804: Thread
806: A user request for a tool used to perform control operations.
808: Program metadata or tool metadata, such as data that does not have a separate specific number but is still discussed here.
810: Source intermediate mapping, i.e., a mapping between source code or source code item(s) and one or more intermediate representations of source code or source code item(s); mapping 810 is an example of cross-level mapping 404.
812: Intermediate native mapping, i.e., a mapping between one or more intermediate representations and native instructions or other trace data; mapping 812 is an example of cross-level mapping 404.
814: Record of native instruction 116 in the trace; may include, for example, trace data 422 with precise location, executed code 434, tuple 456, or generally trace data 454.
816: JIT (Just-In-Time) Compiler
818: Calls to routines or other calls, such as transferring control to an exception handler or interrupt handler.
820: Return address, that is, the point in time or instruction where execution will continue after calling 818.
822: A set of trace data, such as native instructions, that correspond to specific source code statements S or source code expressions E; for example, this could include a record of the execution of instructions that are generated entirely by compiling source code statements S or source code expressions E, rather than from the compilation of source code statements and expressions adjacent to S or E.
824: Edge instructions of group 822; each group typically has two edges—if the instructions are ordered, one edge is the youngest instruction in the group, and the other edge is the oldest instruction in the group; regardless of whether all instructions in a group are ordered relative to each other, an instruction X in a group of instructions G in the tracing is on an edge of G when X satisfies at least one of the following conditions: X is the first instruction of G encountered during forward execution of the tracing (“first forward edge”), X is the last instruction of G encountered during forward execution of the tracing (“last forward edge”), X is the first instruction of G encountered during backward execution of the tracing (“first backward edge”), or X is the last instruction of G encountered during backward execution of the tracing (“last backward edge”).
826: Intermediate representation, such as low-level code, like intermediate language code, or abstract syntax tree, or symbol table.
828: Breakpoint
830: Breakpoint Range
902: Forward step operation, also known as "forward step" or "step" (when the default or only direction is forward), refers to stepping forward and skipping one source code statement.
904: Forward step-in operation, also known as "forward step-in" or "step-in" (default or only when the direction is forward), means that the entry into the routine is skipped forward, so the next statement to be executed is the first statement of the routine body.
906: Forward step skip operation, also known as "forward step skip" or "step skip" (default or only when the direction is forward), means stepping forward and skipping through the routine, so the next statement to be executed is the first statement after the routine call.
908: Forward step-out operation, also known as "forward step-out" or "step-out" (default or only when the direction is forward), means that forward stepping skips the remainder of the current routine, so the next statement to be executed is the first statement after the routine call.
910: Continue forward operation. When the default or only the direction is forward, also known as "continue" or "run," it means continuing execution forward until a breakpoint is encountered or the process terminates.
912: The backward step operation, also known as "stepping backward," refers to skipping one source code statement by stepping backward.
914: Step-back entry, also known as "step-forward entry," means stepping backward into the routine. Therefore, the next statement to be executed in reverse is the last statement of the routine body.
916: The backward step skip operation, also known as "backward step skip," refers to stepping backward into and through a routine, so the next statement to be executed in reverse is the first statement before the routine call.
918: Step backward, also known as "step back out," means stepping backward to skip the remainder of the current routine. Therefore, the next statement to be executed in reverse is the first statement before the routine call.
920: Continue backwards, also known as "continue backwards," "run backwards," or "run in reverse," means continuing execution backwards until a breakpoint is encountered or the process begins.
Some implementations may use different definitions for operations 902-920, for example, by executing more or fewer instructions or by using different names.
922: Set a breakpoint range, which specifies that execution should pause at any address or execution time point within the specified range of multiple addresses or execution time points.
924: Setting Breakpoints
1004: Thread ID
1006: Thread state, such as created, runnable, running, suspended, blocked, terminated.
1008: Thread code, that is, the code that is executed or can be executed when a thread runs.
1010: Thread memory, for example, memory that is local to a thread, or memory that is global to a thread and is accessed by the thread as it executes.
1102: Symbol Table
1104: Identifiers used in the source code
1106: Data Type
1108: Abstract Data Tree
1110: Intermediate languages, such as Microsoft General Intermediate Language, bytecode (Oracle Corporation trademark), Register Transfer Language, Parrot Intermediate Representation, Standard Portable Intermediate Representation, IR Intermediate Language (LLVM Foundation trademark), etc.
1112: Intermediate Language Code
1300: Example of a trace replay execution control method, and a flowchart illustrating the above method.
1302: Identification Procedure
1304: Received execution control request
1306: Using a mapping between source code and intermediate representation
1308: Using the mapping between intermediate representation and tracking
1310: For example, controlling the response by executing forward or backward, or by setting parameters (direction, increment) on such execution.
1312: Execute the traced instructions during replay, for example, by emulation or by controlling the replay of operations specified in the trace as native instructions (not necessarily all of which are in the trace).
1314: Set a breakpoint or breakpoint range; including 922, 924, or both.
1316: Send a response to the execution control request.
1318: For example, by executing up to the edge of the group before pausing at a breakpoint, align a set of traced instructions with source code statements or expressions.
1400: Flowchart
1402: This indicates a backward stepping exit request.
1404: Sets a breakpoint at the execution location immediately preceding the specified location; when A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, location A is "immediately preceding" location B in the trace.
1406: Set a breakpoint at the edge of a set of instructions that corresponds to a specific source code statement or expression.
1408: Sets a breakpoint range that covers (and in some implementations matches) the range specified as receiving dynamically compiled (“jitted”) code.
1410: Set a breakpoint to step over the specified runtime routine.
1412: An instruction was encountered during the original execution or replay execution.
1414: Exceeding the hardware constraint on the maximum number of breakpoints that can be monitored simultaneously.
1416: Avoid terminating the procedure
1418: Termination of Procedure
1420: For example, by specifying the execution of source code statements or expressions to be executed, one can gain high-level control over the original execution or replay execution.
1422: Execute (original or replay) a process, thread, or program.
1424: Get the user's selection of source code statements or expressions
1426: User selection of source code statements or expressions
1428: Debugging process, thread, or program
1430: Forward execution process, thread, or program
1432: Backward execution of a process, thread, or program
1434: Set a large breakpoint range; this breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in the trace.
1436: Large breakpoint range
1438: Recording tracking data from the real-time process.
1440: Group the traced instructions, i.e., create or specify group 822
1442: Clear breakpoints or breakpoint ranges
Operating environment
Referring to Figure 1, an operating environment 100 for one embodiment includes at least one computer system 102. The computer system 102 may or may not be a multiprocessor computer system. The operating environment may include one or more machines within a given computer system, which may be clustered in a cloud, networked as client servers, and/or peer-to-peer. Individual machines are computer systems, and a group of collaborating machines is also a computer system. A given computer system 102 may be configured for, for example, end-users with applications, for administrators, as a server, as a distributed processing node, and/or otherwise.
Human user 104 can interact with computer system 102 via typed text, touch, voice, mobile, computer vision, gestures, and/or other forms of I/O, using a display, keyboard, and other peripheral devices 106. Screen 126 may be a movable peripheral device 106 or may be an integral part of system 102. The user interface may support interaction between one embodiment and one or more human users. The user interface may include a command-line interface, a graphical user interface (GUI), a natural user interface (NUI), a voice command interface, and/or other user interface (UI) presentations, which may be presented as different options or may be integrated.
System administrators, network administrators, software developers, engineers, and end users are all specific types of users 104. Automated agents, scripts, playback software, etc., representing one or more individuals can also be users 104. Storage devices and/or network devices may be considered peripheral devices in some embodiments, while in other embodiments they may be considered part of system 102, depending on their separability from processor 110. For example, other computer systems not shown in FIG1 may technically interact with computer system 102 or another system embodiment using one or more connections to network 108 via network interface devices.
Each computer system 102 includes at least one processor 110. Like other suitable systems, computer system 102 also includes one or more computer-readable storage media 112. Media 112 can be of various physical types. Media 112 can be volatile memory, non-volatile memory, in-situ fixed media, removable media, magnetic media, optical media, solid-state media, and/or other types of physically persistent storage media (as opposed to media that merely transmits signals). Specifically, when inserted or otherwise installed, a configured medium 114, such as a portable (i.e., external) hard disk drive, CD, DVD, memory stick, or other removable non-volatile storage medium, can functionally become a technical part of the computer system, making its contents accessible for interaction with and use by the processor 110. Removably configured media 114 is an example of computer-readable storage media 112. Other examples of computer-readable storage media 112 include built-in RAM, ROM, hard disks, and other memory storage devices that are not readily removable by the user 104. To comply with current U.S. patent requirements, under any pending or granted claim in the United States, a computer-readable medium, a computer-readable storage medium, or a computer-readable memory is not a signal itself or merely energy.
For example, medium 114 is configured with binary instructions 116 executable by processor 110; "executable" is used broadly herein to include machine code, interpreted code, bytecode, and/or code running on a virtual machine. Medium 114 is also configured with data 118, which is created, modified, referenced, and/or otherwise used for technical effects through the execution of instructions 116. Instructions 116 and data 118 configure the memory or other storage medium 114 in which they reside; when the memory or other computer-readable storage medium is a functional part of a given computer system, instructions 116 and data 118 also configure the computer system. In some embodiments, a portion of data 118 represents real-world items such as product characteristics, inventory, physical measurements, settings, images, readings, targets, volumes, etc. Such data may also be transformed through backup, restore, commit, abort, reformatting, and/or other technical operations.
While an embodiment can be described as being implemented by software instructions executed by one or more processors in a computing device (e.g., a general-purpose computer, server, or cluster), this description does not represent an exhaustive list of all possible embodiments. Those skilled in the art will understand that the same or similar functionality can often also be implemented directly in hardware logic, in whole or in part, to provide the same or similar technical effects. Alternatively, or in addition to software implementation, the technical functionality described herein can be performed at least in part by one or more hardware logic components. For example, and without excluding other implementations, an embodiment may include hardware processors 110, 128, such as field-programmable gate arrays (FPGAs), application-specific integrated circuits (ASICs), application-specific standard products (ASSPs), system-on-a-chip components (SOCs), complex programmable logic devices (CPLDs), and similar components. For example, components of an embodiment may be grouped into interactive functional modules based on their inputs, outputs, and/or their technical effects.
In addition to processor 110 (e.g., CPU, ALU, FPU, and/or GPU), memory/storage medium 112, and display 126, the operating environment may also include other hardware 128, such as batteries, buses, power supplies, wired and wireless network interface cards. The terms "screen" and "display" are used interchangeably herein. Display 126 may include one or more touchscreens, a screen responsive to input from a pen or tablet, or a screen for output only. In some embodiments, peripheral devices 106, such as human user I/O devices (screen, keyboard, mouse, tablet, microphone, speaker, motion sensor, etc.), will be operatively communicating with one or more processors 110 and memory. The software process may be user 104.
In some embodiments, the system includes multiple computers connected by network 108. Networking interface devices may use components such as packet-switched network interface cards, wireless transceivers, or telephone network interfaces (e.g., these may be present in a given computer system) to provide access to network 108. However, one embodiment may also transmit technical data and/or technical instructions via direct memory access, removable non-volatile media, or other information storage, retrieval, and/or transmission methods.
Those skilled in the art will understand that the foregoing and other aspects presented herein in the context of an "operating environment" can form part of a given embodiment. The headings of this document are not intended to strictly categorize features into sets of features specific to embodiments and non-embodiments.
One or more items are shown in dashed lines in the accompanying drawings, or listed in parentheses, to emphasize that they are not necessarily part of the illustrated operating environment or all embodiments, but may interoperate with items in the operating environment or some embodiments discussed herein. Items not shown in dashed lines or parentheses are not necessarily required in any drawing or any embodiment. In particular, Figure 1 is provided for convenience; the inclusion of an item in Figure 1 does not imply that the item or its described use was known prior to the invention.
Debugging environment
Figure 2 illustrates a real-time process debugging environment, which is an example of operating environment 100. Debugger 200 contains various components, many of which are not shown here because many are well-known. The primary use of execution control, as taught herein, can be in environments where real-time process debugging is infeasible or at least undesirable. Nevertheless, real-time process debugging is shown for the context and because it can be combined with trace-based debugging utilizing the execution control taught herein.
Debugger 200 can be a conventional debugger or can be adapted to perform the execution control taught herein. The debugger shown includes a data access component 208 (DAC). In this real-time debugging 1428 environment, DAC 208 communicates with the runtime 204 of the real-time debug object 202 to obtain memory items 206 by using a master request 214 to the runtime and a master response 216 from the runtime. The debugger then updates its user interface 210 accordingly. The user interface presents status information at a relatively high level (e.g., in terms of artifacts defined in source code 212). However, those skilled in the art will understand that the execution control taught herein does not require DAC 208 or other adapters.
Figure 3 illustrates a dump debugging environment, which is another example of operating environment 100. Debugger 200 uses its data access component 208 or functionally similar code to read memory contents from dump file 302 or snapshot 304, or both, as well as other state information at specific points in time during the execution of the debugged object.
Figure 4 illustrates a trace-based debugging environment, another example of operating environment 100. The debugger 200 shown is used in conjunction with or includes (since the scope of the debugger can be defined by a given developer, for example, to include replay adapter 408) a technical adapter that allows the debugger to interact with trace 418 more or less as if the debugger were interacting with the runtime. For example, in this example, the same format could be used for the main request 214 and main response 216 used in the real-time process debugging environment of Figure 2. However, trace-based debugging 1428 can offer developers less flexibility than real-time process debugging because variables and other memory contents accessible through the runtime are not necessarily readable from the trace. The granularity of execution control using a familiar trace-based debugger can also be greater than the granularity available through the teachings presented herein. Finer granularity can provide better control during debugging, thereby accelerating defect location identification and understanding of defects.
Tracing-based debugging, with appropriate execution control code 402, a replay component 406, and a mapping 404 between tracing data and source code 212, can support reverse execution 1422 in the form of a reverse replay of the traced execution. In contrast, in real-time debugging, the debugged object is typically not reverse executed.
The replay adapter 408 shown includes an interface 410 to the debugger, which in this example presents an API to the debugger that matches at least a subset of the APIs presented to a traditional debugger by runtime 204 to support real-time process debugging 1428. Other implementations are also possible. Moreover, as shown by the dashed lines around the replay adapter 408 in Figure 4, in some implementations, some or all of the replay adapters can be considered part of the debugger 200, since the debugger is an adapted debugger 200 containing code that utilizes one or more cross-level mappings 404. For example, instead of using external messages, one variant implements the main request 214 and main response 216, as well as interface 410, as function calls, returns, and interfaces within the debugger. In some variants, the debugger includes and utilizes the cross-level mapping 404, and there is no separate replay adapter 408. Debugger DAC 208 can be used to map address 448 to higher-level object 512. The debugger cross-level mapping 404 and its associated code (i.e., one or more of the execution controller 402, replay component 406, and replay adapter 408) can be used to map source code statements 218 or expressions 220, or both, to specific native instructions 434 or native instruction sets 822. In some embodiments, similar to dump debugging, the DAC 208 has runtime internal knowledge and can read runtime data structures to determine where the JIT source code is located for a given set of IL instructions. The machine architecture on which the debug object runs can be significantly different from the machine architecture on which the debugger runs, but the DAC can be designed to read runtime data structures and handle hardware/runtime differences.
Figure 4 illustrates the communication between the replay component 406 and the trace 418 in the form of a machine-level request 414 and a response 416. This is one possible implementation, as an example, which could use a trace reader (not shown) to receive and respond to the request. However, in another implementation, the machine-level request 414 and response 416 take the form of function calls within the replay adapter 408, which include functions that read from the trace 418 and pass back their caller information found in the trace. Thus, the replay component can maintain current state information, such as which position in the trace 418 is identified by the current instruction pointer 704.
As shown in the figure, trace 418 can be stored in one or more files 420 and can include various types of trace data, as well as metadata that supports or defines the search for the trace data. Some or all of trace 418 can also reside in RAM. Some examples of trace data include precisely located trace data 422 (such as copies of low-level instructions and their operands (also known as "native instructions")), timecode 424 which can be used to sort trace data items relative to each other, memory snapshot 304 or dump file 302, index 430 into the original trace data, keyframes 432 inserted into the original trace data at specified intervals, copies of code 434 executed by the debug object during trace 1422, stack activity 436, data streams 438 read or written by the debug object during trace, processor activity based on per core 440 or per socket (multiple cores) 442, thread activity during trace 444, register reads and writes during trace 446, tuples 456 that associate memory address 448 with instruction 450 and one or more values 452 and optionally also with timecode 424, and other 454 reads or writes or values or opcodes captured during trace. In some embodiments, an instance of any one of items 216, 422, 434, 436, 438, 440, 442, 444, 446, 456 conforms to trace “entry” 458. In some, any minimal portion of trace data 454 that itself represents a change in the state of the traced program conforms to trace “entry” 458. Missing data in the trace can also be considered state information, such as gaps 428 in the timecode sequence.
Figure 5 illustrates various memories 112 that can be tracked and thus subject to changes in value or allocation state according to the teachings herein, changes in value or allocation state being performed by the execution of native instructions under the control of execution 1422. Examples of memory cells 502 shown include stack 504 (including data such as its base address 506 and allocated stack frames 508), heap contents 510 such as object 512, or metadata such as garbage collection data, cache 514, processor registers 516, object members such as attribute 518, addressable units in ROM 520 or RAM 524, removable or third-level memory 522, local memory 526, and global memory 528. Memory cells may have one or more characteristics 530 that increase or decrease the accessibility of the memory cell, for example, the memory may be in kernel space, may be shared, may be DMA-enabled, etc.
Figure 6 illustrates the contents of machine-level request 414. As mentioned above, these requests can be implemented using communication data structures, or they can be implemented as parameters of a routine. Some examples of the contents of machine-level request 414 are a memory cell specification 602 and a specification 608 of one or more execution time points 616. Memory cell 502 can be specified as, for example, a single address 448, an address range 606, or a register name 604. Time code 424 can be specified as, for example, an instruction count 610 or a system clock value 612, and this specification can be for a single specific execution time point 616 (a point during trace, or a specific native instruction) or a range of execution time 614 (i.e., the span or period or interval of execution time during trace, or a set of consecutive native instructions).
Figure 7 illustrates the contents of machine-level request response 416. As mentioned above, these request responses can be implemented using communication data structures, or they can be implemented as routine function return values or side effects. Some examples of the contents of machine-level request response 416 are: a value 702 for one or more memory locations specified in the corresponding request 414; an instruction pointer 704 indicating which instruction will be executed next (or which instruction has just finished executing 1422); and a status code 706 containing flags associated, for example, with an instruction, or an error, or a condition (such as an end-of-file marker). Each thread may have a corresponding instruction pointer 704.
Some tracking and replay execution control systems
Figure 8 illustrates a trace replay execution control system 800, each of which is a system 102 configured according to the execution teachings provided herein. If the execution control system operates in a real-time debugging environment, it contains a debug object program 124 with a callable runtime 204. Although debugging is used as an example, execution control can also be performed as taught herein in other contexts, such as for performance analysis or software health monitoring. The debug object or other replayed program includes one or more processes 802, each of which may include one or more threads 804. Those skilled in the art will understand that the terms “process” and “thread” are used in different ways, for example, sometimes as synonyms for each other, and sometimes with different meanings. In either case, the execution control teachings provided herein can be applied because, under either meaning of “process” or “thread,” process 802 and thread 804 have corresponding source code 212 and corresponding traced instructions 434.
Regardless of whether replay execution occurs in a real-time debugging environment, the state information of the replayed program is maintained and updated as the replay execution "proces." In this sense, "procesuspension" includes forward execution, backward execution, or both. State information includes, for example, one or more instruction pointer values indicating execution time(s) in trace 418, and changes in traced program variable values captured in trace 418. To indicate the presence of state information, the boxes for process(s) 802 are shown in FIG. 8 inside the debug object program 124 box with solid lines instead of dashed lines. However, those skilled in the art will recognize that state information may also be maintained within execution controller 402 or at one or more other locations within system 800.
The execution controller 402 itself includes software executed using processor 110 and memory 112. The traced program 124 is other software having source code 212 and metadata 808. The execution controller 402 uses a source intermediate map 810 to map the source code 212 to an intermediate representation 826 of that source code. The execution controller 402 also uses an intermediate native map 812 to map the intermediate representation 826 to the trace 418 (including a record 814 of native instructions collected from the trace). These maps 810, 812 are collectively referred to herein as “cross-level maps”. Note that a given embodiment may include one or more cross-level maps 404; for example, source-to-intermediate and intermediate-to-native functionality may be integrated into a single source-to-native map 404.
In some cases, such as in the case of .NET languages, the compiler creates the source-to-IL mapping 810. However, there are runtimes 204 that can directly execute the source language; one example is (a trademark of Oracle Corporation). In this case, the runtime itself compiles the language to an intermediate format and simultaneously creates the source-to-IL mapping. In the case of managed languages similar to .NET languages, the high-level language compiler does not perform native IL mapping; instead, the JIT compiler in runtime 204 does. Compilers that compile to native code also do not perform native IL mapping. In fact, if such a compiler has any form of IL, it is likely an implementation detail of that compiler. In some embodiments, execution control utilizes the native IL mapping 812 generated by the runtime.
Some implementations obtain the generated IL from tracing native instructions. For example, some implementations simulate CPU operation by emulating it and use native instructions to replay the tracing. In some cases, the IL alone is not sufficient information to recreate the native instructions. In some cases, the native instructions themselves are insufficient to implement IL stepping or IL breakpoints. Additionally, a mapping between native and IL instructions is used. Some embodiments use mappings without relying on native instructions (which may not even exist in the tracing) to implement debuggers that support stepping through IL code using a tracing replayer that does not rely on knowledge of native instructions. Such implementations can trace the instruction pointer by the range provided in the mapping or by any consecutive or non-consecutive collection of the specified items.
Supplement on cross-level mapping
To further illustrate the cross-level mapping 404, consider the following example: some source code 212, a portion of some corresponding intermediate language code used as intermediate representation 826, and a portion of some native instructions. Due to the patent office's restrictions on the inclusion of computer code in patent documents, and because showing a portion is sufficient to illustrate mapping 404 in the context of the other information provided herein and the knowledge of a person skilled in the art, only portions of the intermediate language code and native instructions are shown here.
Original C# source code:
Sample source-to-IL mapping. This sample is hand-generated. The actual implementation is typically unreadable to humans. That is, the source-to-IL mapping will usually be implemented in binary format rather than text format. Nevertheless, the following material illustrates the functionality of the source-to-IL mapping to those skilled in the art. The mapping is not a one-to-one mapping; some parts of the source code line end at different locations in the IL code. For a single source program, there are many correctly generated IL transformations.
Sample IL to native mapping. Similar to source-to-IL mapping, this is manually generated, and the implementation will exist as a data structure, for example, at runtime. For a single generated IL, there are many correctly generated native code transformations. Because the JIT compiler can add complexity due to processor-specific optimizations, and because debug 1428 using traced programs may not execute on the same processor type (i.e., different optimizations will be applied), it is not simply possible to run the JIT on the IL and the result cannot be guaranteed to be the same as running it during the generation of trace 418. In this example, the IL begins with "IL_", and the native code is represented as <memory address><hexadecimal representation of native code><assembly mnemonic>.
Typically, kernel 120 is present, and is explicitly shown in Figure 8 to help prevent confusion between runtime 204 and kernel 120. The cross-level mapping and execution control described herein assume that the runtime is present in most (if not all) configurations when execution is traced to create trace 418.
Additional aspects of System 800 and related systems
Some embodiments of system 800 include a JIT compiler 816 for dynamically compiling the code of the traced program 124. Some aspects of execution control address the challenges created by JIT compilation, for example, by supporting breakpoint ranges 830, which allow breakpoints to be encountered even if native code spanning the breakpoint location has not yet been generated by compilation, provided the address range that will contain the generated code is known. For example, breakpoint range 830 can be specified as ranges 606 or 614, while individual breakpoints 828 are specified as specific single locations within trace 418.
Referring again to Figure 8, some embodiments of system 800 include a return address 820 for call 818. This return address 820 may be used, for example, when performing a reverse step-out execution control operation that steps out of the calling routine during reverse execution.
Some embodiments improve the accuracy of execution control by providing a more precise correspondence between source code statements or expressions and the traced instructions that implement them. For example, some familiar methods of tracing replay step into the middle of the traced instructions corresponding to a given source code statement 218 or expression 220, which can be confusing. Some embodiments described herein definitively define a set of 822 traced instructions corresponding to a given source code statement 218 or expression 220 (e.g., generated by compilation to implement). The execution controller then sets the instruction pointer to a location at an edge 824 of this set of 822, instead of somewhere in the middle as before. Which edge 824 is selected can depend on whether the execution is replaying forward or backward; for example, a first forward edge is selected for forward replay, and a first backward edge is selected for backward replay. Alternatively, the same edge can always be used regardless of the replay direction; for example, the instruction pointer can always be set at the first forward edge.
Figure 9 illustrates several execution control operations 618. For example, a user presents a control operation request 806 to the debugger 200 or other tool 122 via user interface 210. Execution controller 402 translates the control operation request 806 into a change in the state of process 802. The operations shown include forward step 902, forward step into 904, forward step skip 906, forward step out 908, continue forward 910, backward step 912, backward step into 914, backward step skip 916, backward step out 918, continue backward 920, set breakpoint range 922, and set breakpoint 924. In these operation names, "forward" indicates performing replay forward, and "backward" indicates performing replay backward.
Various step operations 902-920 can be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar operations with similar or identical names. However, internally, for example, they can be implemented through innovations for aligning source code with traces using cross-level mapping 404, instruction group 822, and specific breakpoint placement. Continue operations 910, 920 can also be implemented so that, from the developer's perspective, they operate in a manner similar to or identical to familiar continue operations, while internally, they utilize cross-level mapping 404 or instruction group 822, or both. Set breakpoint operation 924 can also be implemented so that, from the developer's perspective, it operates in a manner similar to or identical to the familiar breakpoint setting operation, while internally, it utilizes cross-level mapping 404 or instruction group 822, or both.
Figure 10 illustrates the thread 804 activity information 444 that can be captured in a given trace 418. It shows the thread identifier 1004, thread state indication 1006, thread executable code 1008, and memory unit 502 status information 1010 such as thread local variables and their identifiers.
Figure 11 illustrates some examples of intermediate representation 826. Examples shown include symbol table 1102, which associates source code identifiers 1104 (variable names, function names, object members, and method names, etc.) with data types 1106 (e.g., integers, floating-point numbers, strings, booleans, and user-defined types). Another example is abstract syntax tree 1108. Other examples include code 1112 written in one or more intermediate languages 1110. More generally, some embodiments use intermediate representation 826 that shares the structure of an intermediate representation created by the compiler, or even a copy thereof. However, intermediate representation 826 is placed in the context of an execution controller, opposite to the compiler's context. Furthermore, intermediate representation 826 is used for tracing replay of the execution tracing 418 of previously generated code, rather than being used to generate that code in the first place.
A technician will recognize that a given source code 212 can potentially be used to generate many different versions of the corresponding IL. However, only one of these versions will be used in the program, and the symbol information emitted by the compiler will correspond to the emitted IL. The debugger can be designed to load only the corresponding symbol information, so only one mapping will exist. In some systems, the runtime may include multiple versions of native code for a given routine; for example, both optimized and non-optimized versions of native code for debugging may exist, or multi-level JIT functionality may provide multiple versions of native code in memory. In such a multi-native version system, replay can still be performed. For example, when a breakpoint is set, it can be set in all existing versions of the native code. Some embodiments use native code generated by the JIT as well as IL code, which are obtained from or via trace 418. Some embodiments also use the corresponding symbol information for the source/IL mapping, which may or may not be included in the same trace file 420.
Figure 12 is a variation of Figure 2. In the environment of Figure 12, both real-time debugging and replay execution are supported. Replay is supported by a scrolling trace 418, which records the forward execution of the real-time debug object in real time, while the debug object executes according to the prompts of debugger 200. For efficiency, only, for example, a pair of buffers is used to track the latest instructions. Trace 418 is written to one buffer until it is full, then to another buffer until it is full, then written back to the first buffer (overwriting the earlier trace), and so on. Alternatively, instead of the scrolling window, all execution activity during the debug 1428 session can be tracked. As another alternative, previously recorded trace 418 can be accessed during the real-time debug session.
Some additional system examples
Examples are provided in this document to help illustrate various aspects of the technology; however, the examples given in this document do not describe all possible embodiments. Embodiments are not limited to the specific implementations, arrangements, displays, features, methods, or scenarios provided herein. A given embodiment may include, for example, additional or different technical features, mechanisms, sequences, or data structures, and may otherwise deviate from the examples provided herein.
Referring to Figures 1-2, some embodiments use or provide a trace replay execution control system 800. This system includes a processor 110, a memory 112 operatively communicative to the processor, and a trace 418 recorded during the execution of program 124 in conjunction with runtime 204 and kernel 120. The trace includes a record 814 of native code instructions 116 executed in at least one thread 804 of the program. Source code 212 of at least a portion of the program is also present.
System 800 also includes a source intermediate mapping 810 that maps between source code and intermediate representation 826 of source code, and an intermediate native mapping 812 that maps between intermediate representation 826 and trace 418.
System 800 also includes an execution controller 402 in software tool 122. The execution controller is configured to control the replay execution of trace 418 in response to request 806 when executed using the processor. In the replay execution, the source code is associated with trace native code instructions or other trace entries through source intermediate maps and intermediate native maps.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: forward execution step into 904 operation, forward execution step out 908 operation, and forward execution step skip 906 operation.
In some embodiments, the execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: a backward step-in operation 914, a backward step-out operation 918, and a backward step-skip operation 916.
In some embodiments, execution controller 402 is configured to translate a request for at least the following operations 618 into corresponding execution of trace native code instructions: continuing forward execution in the trace 910 until any position within the breakpoint range 830 is reached, and continuing backward execution in the trace 920 until a position within the breakpoint range is reached.
In some embodiments, system 800 is configured to step into a portion of source code that has not yet been compiled into native code instructions during replay execution.
In some embodiments, the intermediate representation 826 includes at least one of the following: a symbol table 1102 that associates at least two identifiers 1104 used in the source code with a data type 1106, an abstract syntax tree 1108 derived from at least a portion of the source code, or a conversion 1112 from at least a portion of the source code 212 to the intermediate language 1110.
In some embodiments, tracing 418 does not contain any execution instance of runtime 204, and tracing 418 is not configured to call tracing to execute any runtime-specific code.
In some embodiments, system 800 includes a real-time debug object 202 of program 124 having a runtime callable instance. In some embodiments, trace 418 is recorded from a real-time process and the system is configured to replay the execution of the trace.
In some embodiments, system 800 is configured to skip a portion of the replay execution of trace 418 because execution controller 402 moves the replay execution from a first execution point of the trace to a second execution point of the trace, and the system does not execute trace native code instructions or other trace entries that would otherwise be executed through continued execution from the first position to the second position.
Those skilled in the art will understand that other systems are also within the scope of the teachings presented herein. In particular, some other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any system or apparatus using any of the execution control teachings herein is within this disclosure, whether or not it is in the specific example provided.
Some method examples
Figure 13 illustrates an example of an execution control method 1300, which is an example of a method executed or assisted by an execution controller 402, a cross-level mapping 404, or other items discussed herein. This example method includes identifying a managed program tracked by 1302 as a tracked managed program. Identifying a program as tracked is simple; if a program is being tracked, or has been tracked previously, then it is a tracked program. To some extent, it involves identifying a program as managed because it is managed when it depends on runtime 204 for real-time execution, and runtime 204 may provide different services in different implementations. In many cases, runtime 204 provides automatic management of heap memory through garbage collection based on reachability analysis, reference counting, or other mechanisms. However, what is of greater interest in this application is the use of runtime 204 to execute intermediate language code 1112. In some runtimes, the translation from source to native instructions is not modularized into a source-to-intermediate language stage, followed by an intermediate language-to-native code stage. For example, some platforms execute source code directly (a trademark of Oracle Corporation, USA). For the purposes of this application only, a "managed" program is a program that relies on runtime 204 to generate native instructions. A managed program may also be subject to or not subject to garbage collection performed by the runtime.
The method 1300 shown also includes receiving a request 1304 to perform a control operation on a trace playback. This request may be a request 806 directly from the user through the user interface, or a request 214 from the debugger to the trace execution controllers 402, 406, or 408.
The illustrated method 1300 also includes a mapping 1306 from source code to an intermediate representation and a mapping 1308 from the intermediate representation to native code. This can be done in two stages as indicated, or in some other embodiments, in a single combined stage from source code to native instructions. However, unlike compilation itself, whether in two stages or one stage, mappings 1306 and 1308 are not for generating code for execution, but rather for associating source code locations with locations in the trace of previously generated and executed instructions.
Some implementations map 1306 from source code to an intermediate representation using a symbol file that contains hashes, checksums, or other identifiers of the IL corresponding to the source. If the identifiers match, the debugger loads the symbol file. This symbol file also contains identifiers for each source file used to compile the IL. Before the debugger loads the source files and maps the IL code to the source, it verifies the source file identifiers using the identifiers contained in the symbol file.
When IL is compiled just-in-time (JIT), some implementations use a runtime-generated mapping to map 1308 from IL to native code. In some implementations, the runtime may not guarantee backward compatibility regarding how JIT will occur, and therefore is free to change the JIT process at any time. In such implementations, debuggers may not be able to make assumptions about what the native code output by the JIT process will contain. Therefore, debuggers may request the runtime to provide the mapping between native code and IL.
Some variations of the method 1300 shown include aligning native instruction sets with source code statements or expressions 1318, which are generated by compiling from these source code statements or expressions.
The illustrated method 1300 includes control 1310 for replay, which is to perform "execution control". An example of control 1310 is executing 1312 native instructions or other trace entries corresponding to step, step in, step skip, step out, or continue operation, thereby changing the state of process 802. Another example of control 1310 is setting 1314 individual breakpoints or breakpoint ranges. Those skilled in the art will recognize that performing step, step in, step skip, or step out operations involves setting breakpoints, but it is also possible to set breakpoints without executing native instructions or other trace entries, for example, when preparing for continue operation. In some embodiments, the code itself is not modified to set breakpoints in the trace. Those skilled in the art will recognize that the processor can set execution breakpoints via instructions (e.g., int3 in some Intel architectures) or via hardware breakpoints (registers that specify which address to monitor). In some embodiments, the trace replay execution control system 800 provides similar capabilities. Some implementations do not modify the code flow and support an arbitrarily large number of breakpoints.
Finally, the method 1300 shown includes sending 1316 a response to the request, such as response 416 or another message or data structure containing instruction pointer 704 or status code 706.
Figure 14 illustrates some additional execution control steps that may be performed in some embodiments. Some familiar debuggers do not support the backward step-out operation 918. However, some embodiments identify 1402 as a request for the backward step-out operation 918 and implement the operation as taught herein.
Debuggers can implement some familiar breakpoint operations, namely, the operation for setting a breakpoint 1314. However, some embodiments set breakpoints 1314 and 1404 immediately before the specified location. Some embodiments set breakpoints 1314 and 1406 at the edge of the instruction group 824. Some embodiments set breakpoint range 830 of 1314 and 1408 on, for example, an address range designated for receiving code that is compiled just-in-time (JIT-compiled). In particular, some embodiments set large breakpoint ranges 1436 and 830 of 1434, 1314, and 1408. Some embodiments set breakpoints 1314 and 1410 as part of implementing a step-skip operation to step over runtime routines that the developer may not be interested in. For example, such runtime routines may perform garbage collection, JIT compilation, anti-malware or other security checks, or runtime 204 stewardship functions. The other steps shown in Figure 14 are discussed elsewhere in this document or included for completeness; for example, not only can breakpoints be set, but breakpoint 1442 can also be cleared.
Unless otherwise indicated, the technical methods shown in the figures or otherwise disclosed will be executed automatically by, for example, system 800. Within the scope of actions involving human administrators or other humans, the methods may also be executed partially automatically and partially manually; for example, a person may select 1426 source code statements or expressions and then use tool 122 user interface to request step operations or breakpoint operations. However, a completely manual method is not considered here as an innovation. In a given embodiment, zero or more example steps of the method may be repeated, possibly with different parameters or data to be manipulated. The steps in one embodiment may also be performed in a different order than those shown in the figures. Steps may be performed sequentially, in a partially overlapping manner, or in complete parallel. The order in which steps are performed during a given method can vary from execution of one method to execution of another. Steps may also be omitted, combined, renamed, regrouped, or otherwise deviated from the illustrated flow if the method being performed is operable and conforms to at least one claim.
Some embodiments use or provide a computer-implemented method for a trace replay execution control method. One example method includes identifying, at 1302, the managed program being traced, i.e., a program configured to execute in conjunction with runtime calls and configured to be traced. The example also includes receiving, at 1304, a trace replay execution control request in a software tool running on a computing system. Based on the trace replay execution control request, the example method automatically maps, at 1306, the source code of the traced managed program to an intermediate representation of the source code, and at 1308, the intermediate representation to a trace, at 418. The trace includes a record of native code instructions traced when the traced managed program is executed. Trace 418 does not include any execution instances at runtime. The example method also executes, at 1312, the traced native code instructions corresponding to the trace replay execution control request, thereby replaying a portion of the trace.
In some embodiments, the trace replay execution control request identifier 1402 performs a step-out operation backward to step out of the routine, and the method includes setting breakpoints 1314 and 1404 on the trace native code instructions, the breakpoints having a position immediately preceding the location of the return address of the call to the routine. For the purposes of this method, when 1412A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B, position A in the trace is "immediately preceding" position B. For the purposes of this method, when performing source-level debugging, alignment 1318 can associate instruction group edge 824 with the most recently executed source file line number, statement, or expression executed before the current function call. Some embodiments set breakpoints at the call location of the routine; for example, some embodiments set breakpoints at the call location of the current function.
Typically, the source code contains statement 218 and expression 220. In some embodiments, the method includes setting breakpoints 1406 and 1314 on trace native code instruction 116, which are located at edge 824 of a group 822 containing all trace native code instructions mapped by the method to a given statement or expression in the source code. In some implementations, the group contains only all trace native code instructions, and may also contain other instructions.
In some embodiments, the received trace replay execution control requests 806, 214, 414 are named, identified, or otherwise invoked according to one of the following: performing a forward step skip 906 operation to step forward skip a routine; performing a backward step skip 916 operation to step backward skip a routine; performing a forward step enter 904 operation to step forward enter a routine; or performing a backward step enter 914 operation to step backward enter a routine.
In some cases, the received trace replay execution control requests 806, 214, 414 name, identify, or otherwise invoke replay functionality according to the forward execution step-in 904 operation to step into a user code routine, and the replay execution of the user code routine includes the replay execution of at least one call 818 to a runtime routine 204, and the call to the runtime routine has no corresponding call statement or call expression in the source code. In this context, some embodiments include at least one of the following: setting 1408 to specify a breakpoint range designated as receiving the entire memory extent of the dynamically compiled code, or setting a breakpoint 1410 to perform a step-skip operation on the call to the runtime routine.
In some embodiments, the forward stepping into step 904 is performed as follows. The debugger 200, configured according to the teachings herein, maps the source line range 1306 to the intermediate language range and the intermediate language range 1308 to the native range. The debugger then performs this step using low-level primitives; this can be done using instruction-level single-stepping or breakpoints. When the call instruction 818 is encountered, the debugger determines whether the target is a high-level source step that indicates a stepping into at the source level, or a runtime implementation detail that should not be stepped into because it is not explicitly stated in the source code. For example, this determination can be done by querying the runtime or by searching for the name of the calling routine in the source code. If the call is for a different high-level (shown in the source code) routine, the debugger queries runtime 204 (e.g., via DAC 208) to determine whether the calling routine has been JIT-compiled. If the calling routine has been JIT-compiled, the debugger performs stepping into the call using instruction-level single-stepping or by setting a breakpoint inside the target routine to perform stepping into step 904. If the calling routine has not yet been JIT-compiled, the debugger will set breakpoints on the JIT compiler or on the target address region written by the JIT compiler using DAC 208 or another mechanism, with the JIT compilation using multiple data breakpoints. The debugger allows running a trace replay until the JIT compilation is complete. The debugger sets breakpoints on the JIT-compiled target and runs. This continues until native instructions no longer fall within the native step range mapped from the initial action, or the program exits. An exception is a special case that should fall on a catch target.
In some embodiments, the trace replay execution control request invokes at least one of the following operations: continue tracing replay execution forward 910 in the trace until breakpoint 828 is reached; continue tracing replay execution forward 910 in the trace until a position in breakpoint range 830 is reached; continue tracing replay execution backward 920 in the trace until breakpoint 828 is reached; or continue tracing replay execution backward 920 in the trace until a position in breakpoint range 830 is reached. Some embodiments also include other operations that may be invoked in the request, including one or more of, for example, performing a step-in backward 914 operation; performing a step-out backward 918 operation; performing a step-skip backward 916 operation; performing a step-in forward 904 operation; performing a step-out forward 908 operation; and performing a step-skip forward 906 operation. More generally, a given embodiment may be limited to any subset of the operations taught herein.
In some cases, during the execution of the managed program being traced to create trace 418, the maximum number of breakpoints is constrained by the hardware breakpoint constraint that the processor can monitor up to N addresses at a time. However, in some embodiments, the method sets more than N breakpoints during the replay execution of the trace, thus exceeding the hardware breakpoint constraint.
Those skilled in the art will understand that other methods are also within the scope of the teachings presented herein. In particular, other systems may perform cross-level mapping 404, use breakpoint range 830, and implement other teachings provided herein, while departing from the specific examples described herein. Any method of implementing control teachings using the teachings herein is within this disclosure, regardless of whether it is within the specific examples provided.
Examples of media configurations
Some embodiments include a configured computer-readable storage medium 112. Medium 112 may include a disk (magnetic, optical, or otherwise), RAM, EEPROMs or other ROMs, and/or other configurable memories, particularly computer-readable media (which are not merely for transmitting signals or energy). The configured storage medium may in particular be a removable storage medium 114, such as a CD, DVD, or flash memory. General-purpose memory (which may be removable or non-removable, and may be volatile or non-volatile) may be configured in embodiments to form the configured medium using items such as an execution controller 402, a playback adapter 408, an instruction set 822, a cross-level mapping 404, machine-level requests 414 and responses 416, and a breakpoint range 830, in the form of data 118 and instructions 116 read from the removable medium 114 and/or another source such as a network connection. As disclosed herein, the configured medium 112 is capable of causing a computer system to perform technical processing steps for horizontal cross-level (high-level in tool 122 to low-level in trace 418) playback execution control. Therefore, the accompanying drawings help illustrate the configured storage medium embodiments and process embodiments, as well as system and process embodiments. In particular, Figures 4, 13, or 14, or any other processing steps taught herein, can be used to help configure the storage medium to form the configured medium embodiment.
Some embodiments use or provide computer-readable storage media 112, 114 configured with code that, when executed by computer processor 110, performs a trace replay execution control method. In this example, the trace replay execution control method includes receiving a trace replay execution control request 1304 from a software tool running on a computing system. The method includes mapping 1306 between the source code of the traced managed program and an intermediate representation of the source code, and mapping 1308 between the intermediate representation and a trace 418, based on the trace replay execution control request. The trace 418 includes a record of processor activity, such as native code instructions traced when the traced managed program is executed, since the trace does not include any execution instances at runtime. In this example, the trace replay execution control method also includes executing 1312 trace native code instructions or other trace entries corresponding to the trace replay execution control request, or setting a breakpoint 1314 on the trace native code instructions to control the replay of traces traced by 1310.
Some embodiments operate in combination with debugger 200, and in some of these cases, the traced managed program includes a real-time process and an execution runtime 204. Without terminating the traced managed program at 1416, debugger 200 communicates with the execution runtime 204 of the traced managed program, and the method uses trace 418 to control 1310 to perform a backward replay. That is, in this example, reverse debugging is intertwined with real-time process debugging.
Some embodiments perform one, two, three, or all four of the following activities of particular interest. One particularly interesting activity is the execution of 204 at high-level control 1420 using machine-level information from trace 418. In this context, "high-level" control refers to control based on user selection 1426 (obtained from user 104 via a user interface) that specifies an identifier or statement or expression in the source code. In this context, "machine-level" information refers to processor architecture-specific information, such as a particular instruction set or a particular microarchitecture.
Another particularly interesting activity is the forward and backward execution of both the real-time debug objects 202 and 802 of the managed program being debugged by debug 200.
Another particularly interesting activity is stepping into the call shown in the source code, at least in part, by setting a large breakpoint range of 1434 to 1436. In this case, the breakpoint range is "large" when it covers at least one thousand consecutive addresses or instructions in tracing 418.
Another particularly interesting activity is to simultaneously debug the real-time debug object 202 of the managed program being debugged (200), trace 418 trace data from the real-time process, and then use at least some of the trace data recorded to perform reverse execution debugging on the real-time process.
Those skilled in the art will understand that other configurations of media embodiments are also within the scope of the teachings of this invention. In particular, some other embodiments may include statutory media configured with code for performing cross-level mapping 404 at execution time, using breakpoint range 830, and implementing other teachings provided herein, while departing from the specific examples described herein. Media configured to perform methods using any execution control teachings taught herein are within the scope of this disclosure, regardless of whether they are in the specific examples provided.
Example with JIT code
Assume the source code includes classes similar to those in C#, as shown below:
If the language is C++, the developer would reasonably expect that the call to WiggleLeg() in Squid.Swim() can be compiled into the following form (similar to assembly code):
CALL 0x0c84fabd; 0x0c84fabd is the address of Squid::WiggleLeg().
In this scenario, 0x0c84fabd would begin implementing Squid::WiggleLeg(). However, this is not the case in managed software executed in runtime 204. Code executed in runtime 204 is compiled "just-in-time," also known as "jit." If this is the first call to Squid::WiggleLeg(), there will be no machine instruction 116 for Squid::WiggleLeg(). It has not yet been compiled. Therefore, instead of having the machine instruction implement Squid::WiggleLeg(), 0x0c84fabd would have some instructions that look something like this (in pseudocode):
This point in the code is called a "stub". The compilation process is lengthy and complex, so developers who typically try to analyze or debug their applications by tracing them often don't want to document the compilation process in detail. However, trace 418 may record at least a portion of the stub, even if the traced instructions are unlikely to be of interest to those debugging the code. In real-time process debugging, the runtime typically skips this part of the code. However, when debugging only from trace 418, the runtime 204 of the debugged object is not executed, so the stub cannot be skipped. Instead, one embodiment can leverage the functionality of an out-of-process debugging utility typically used to read data from dump file 302, and an innovative trace replay functionality that can be used together to find the address range of all JITTED code at runtime. Upon receiving a request to step into a method call, one embodiment can temporarily set a breakpoint 1314 on the JITTED code range and virtually execute forward (i.e., replay forward) until the first JITTED code range is read. Once read, the embodiment can remove the breakpoint. In this way, developers can skip all these uninteresting "stubs" of code. Some implementations further optimize the method by targeting the address range of the breakpoints to be limited to the range of `Squid::WiggleLeg_implementation`.
Some additional combinations and variations
Any combination of these combinations of code, data structures, logic, components, communications, and/or their functional equivalents may also be combined with any of the systems and their variants described above. A process may include any step described herein in any operable subset or combination or sequence. Each variant may appear alone or in combination with any one or more other variants. Each variant may appear with any process, and each process may be combined with any one or more other processes. Each process or combination of processes (including variants) may be combined with any of the media combinations and variants described above.
In some embodiments, the trace replay component uses source-IL mapping and IL-machine mapping to convert between the location in trace file 420 (e.g., indicated by timecode 424) and the location in source code 212 (e.g., indicated by line number).
In some embodiments, a portion of runtime functionality is provided in the trace replay component 406. However, instead of mediating between the debugger, user code, and operating system as in the real-time process of Figure 2, the runtime functionality mediates between the debugger and trace(s)420.
Some trace recording processes record only two types of data. One type of data is the execution of code instructions 116, which may be executed in parallel on multiple threads. The other type of data is a snapshot 304 of a specific block of memory taken at discrete points in execution time, such as to capture a portion of the stack. However, other trace processes record different or additional types of data, as shown in Figure 4. In some cases, the trace contains a valid representation of all recorded instructions and all their inputs and outputs. The recording of trace 418 can be made efficient by relying on the determinism of processor(s) 110 and primarily recording information that cannot be inferred from that determinism, as well as information already recorded in trace 418. In some implementations, most of trace 418 is data, rather than the executed code instructions; such data is often indeterminate. The trace can be primarily seed data plus indeterminate information. In some cases, only information entering the cache of the traced processor(s) is recorded in trace 418; for example, reading the value V into the processor cache is input into the trace, but writing the value V from a processor register to memory location X is not necessarily input into the trace. If a write operation to X behaves differently in terms of the traced program, it is because at some point the written value is returned from X to the processor register, at which point, if tracing is still enabled, the entry in trace 418 can be executed.
This document describes the execution control of a high-level program derived from a process tracing using examples, illustrations, definitions, and other descriptive materials. Technicians will recognize that process traces can be created at the machine level using various techniques, such as Windows Event Tracing (ETW) or "Time Travel Tracing" for systems running Microsoft environments, tracing for runtime environments (trademarks of Efficios, Inc. and Linus Torvalds, respectively), tracing for similar environments (trademarks of Oracle Corporation and X/Open, Inc., respectively), and other tracing techniques. The trace can then be replayed using hardware emulation. Sometimes, the process is written in a high-level language that requires a runtime framework to actually execute the process. One example is a .NET application running in the Common Language Runtime (CLR). Moving forward or backward in a trace is not helpful in itself to developers of high-level programs because the view of the trace is a view of the runtime or just-in-time compiled code, not a view of the high-level program. This document describes a method for mapping machine-level instructions in a trace to high-level operations in the program. This allows for setting and reaching breakpoints, as well as forward and backward stepping in high-level languages.
The process of stepping through the code at a high-level runtime can be achieved by abstracting the complexity into three layers. At the lowest level (level 0) is the process trace 418. This trace contains enough information to allow the recorded process execution to be simulated at the hardware level.
At level 1, a properly configured system can apply some very basic hardware debugging support for replaying traces. This support may include: the ability to play the process forward or backward, read the process memory, read the thread context (for each thread), set hardware breakpoints, and single-step machine instructions for each thread.
At level 2, support is provided for mapping the range of machine instructions to the range of higher-level virtual machine (VM) instructions or another type of code. Operations in level 1 can be used to debug higher-level code. In some configurations, the operations to be supported are forward, backward, setting breakpoints, stepping in, stepping out, and stepping skipping. Details of the implementation for each operation are given below in the examples.
Regarding forward and backward execution, in this example, they are equivalent in high-level and machine-level execution, so this is handled entirely at level 1.
Regarding breakpoints, in this example, breakpoints are set using a mapping defined in layer 2 to map higher-level breakpoints to hardware breakpoints. When a hardware breakpoint is encountered, the implementation can use this mapping to map that hardware breakpoint back to a higher-level breakpoint.
Regarding forward and reverse stepping exits, a hardware breakpoint can be set at the function's return address using stack tracing. To implement reverse stepping exit, the breakpoint is set on the instruction preceding the return address.
Regarding forward and backward step skipping, step skipping can be achieved by looking at the next instruction to be executed. Depending on the instruction, the implementation can use Level 1 to either perform single-stepping or set a breakpoint and run until it is reached. The "call" instruction is an example of an instruction that requires a breakpoint. Most other instructions can use single-stepping. Unlike some familiar approaches, this example debugger implementation can use mappings in Level 2 to repeat the stepping operation until the instruction pointer or code execution time point is at the appropriate stop point in the higher-level runtime. This inspires the discussion of instruction group 822 elsewhere in this paper.
Regarding reverse step-in, to perform reverse step-in, this implementation uses the single-step operation defined in Layer 1. If the machine has just returned from the calling instruction, this usage will return the execution time point to the return instruction of the previous call. If the machine has not just returned from the call, the machine will simply backtrack to the previous instruction. Similar to step-skip, the implementation can use the mapping in Layer 2 to know when execution is at a stop point, and may need to perform single-steps several times to align the trace with the source code 1318.
Regarding forward stepping, in this implementation, forward stepping is similar to reverse stepping. However, difficulties can arise if the higher-level runtime needs to perform work that is not directly related to the running higher-level code. Some examples are just-in-time (JIT) compilation, runtime housekeeping, and stepping operations that require some form of runtime resolution (transparent proxies in .NET are an example of this challenge). These difficulties can be addressed by implementing any or all of the following: One option is to set a large breakpoint range for all JIT-compiled code at the start of stepping. If the breakpoint is encountered after stepping, the implementation can complete the step when the next stopping point is reached. Another option is to implement logic in the stepping engine that fully understands the runtime, knowing when to skip calls and when to single-step through calls, allowing the implementation to stop stepping at appropriate points in the higher-level runtime.
In some embodiments, out-of-process execution control controls the execution of IL instructions by using, for example, the functionality provided by replay component 406 and IL-to-address mapping 812. The functionality provided by replay component 406 or other execution controllers 402, 408 for execution control includes:
Get the status (register values) of all threads.
Step forward or backward by one instruction
Run forward or backward until the instruction pointer reaches the specified address set.
The IL-to-address mapping exists in the memory image of the process or trace, and the replay layer can provide it to an off-process execution control debugger. One perspective suggests that this example involves converting IL-level debugging into machine-level debugging.
By stepping individual instructions, or by running forward and backward in the trace until a specific instruction address is reached, some implementations support the application of high-level execution control to the trace using source-to-IL mapping 810, IL-to-native mapping 812, native-style out-of-process execution control, and the ability to run forward and backward in the trace 418.
Consider examples of real-time process debugging.
As a further illustration of trace-based execution control, consider that certain embodiments may resemble or differ from real-time debugging. Several components are referenced below, and those skilled in the art will understand their relationship to other examples provided herein, and in particular, that functionality may be grouped into different components for ease of understanding or implementation without departing from the execution control teachings provided herein. The system 800 components discussed in this example include:
User Interface (UI). The user interface graphically displays a representation of the debugger's program state to the user. Examples of program state include a list of threads, the next line of source code to be executed on each thread, the call stack for each thread, the set of variables in each frame of the call stack, and the values of these variables.
Source translation. This part of the code translation is responsible for translating between runtime abstractions and source code-level abstractions. For example, the CLR runtime uses IL instructions encoded in binary file format to represent code, while C# source code has the syntax of text statements. As an example, this layer of the debugger can translate between runtime abstraction layers (e.g., those defined in ECMA-335, Common Language Architecture (CLI) version 6 (June 2012) or later) and C# abstraction layers (e.g., those defined in C# language specification version 5.0 or later).
Runtime translation. The runtime translation section of the debugger is responsible for translating between low-level concepts (such as memory and registers) and runtime abstractions. Examples of runtime abstractions include a list of threads, a call stack for each thread, and the IL instructions to be executed next. Note that the call stack at the abstract runtime layer does not have to be the same as the call stack at the abstract source code level. Only in the case of real-time debugging, this layer uses inter-procedural communication mechanisms to request the runtime within the process being debugged to perform work in order to assist with certain tasks. For example, to set a breakpoint at an IL instruction in method Foo at offset 28, this layer sends a message to the runtime requesting it to set the breakpoint at offset 28 of Foo. The thread within the runtime then receives the message, translates the Foo IL offset 28 into machine instructions residing at memory address 0x4567123512395, and then writes the breakpoint instruction at that location. It is reasonable to consider the part of the runtime that serves those requests as functionally located within this layer of the debugger, even if it is implemented in a different process.
The basics. The low-level parts of the debugger are responsible for using the kernel, dump files, or traces to generate memory and registers that will be read by the runtime translation section. For kernel procedures, this is implemented in some environments via APIs such as ReadProcessMemory. For trace files, it supports parsing the file and establishing a mapping between time t and a set of memory and register contents recorded at that time.
Considering these components, consider the scenario where a breakpoint is set and the program is executed forward until the breakpoint is reached. One perspective suggests that real-time process debugging generally involves the following actions.
Action 1. User Interface. The user clicks the mouse on the displayed source code line to indicate where a breakpoint should be set.
Action 2. Source Transformation. Source code lines are transformed into specific method and IL instruction offsets.
Action 3. Runtime Translation. The message is sent to the runtime, where the method + IL instruction offset is translated into a memory address. Then, the breakpoint opcode is written to that address.
Action 4. User Interface. Users click buttons in the UI to indicate whether they want the process to run.
Action 5. Source Transformation. Forward the request to be executed.
Action 6. Runtime Translation. A message is sent to runtime 204, requesting it to proceed forward. Upon receiving the message, the runtime proceeds forward and then reaches the breakpoint at the previously set specific memory address. The breakpoint's memory address is translated back to the method and IL offset, and a notification message is then sent back to the debugger, indicating that the breakpoint at the specific method/IL offset has been reached.
Action 7. Source Transformation. The message indicating that the breakpoint has been reached is transformed from the method and IL offset back to the source line, and notifications about the breakpoint being reached at that source line continue to be sent to the UI.
Action 8. User Interface. The UI requests additional information about the new state of the process, allowing it to display current state information to the user, such as the current call stack for each thread.
Action 9. Source Transformation. To provide a source abstraction of the call stack, this component first requests a runtime abstraction that receives the call stack.
Action 10. Runtime Transition. To provide a runtime abstraction of the call stack, this component first requests to receive the state of memory and registers.
Action 11. Basics. Determine the memory and registers at the current time.
Action 12. Runtime Transformation. Using memory and registers, compute the runtime abstraction of the call stack.
Action 13. Source Transformation. Calculate the source code abstraction of the call stack using the runtime abstraction of the call stack.
Action 14. User Interface. Using the source code abstraction of the call stack, the UI can now display the current state of the process being debugged to the user.
In some embodiments, when using tracing actions 3, 6, and 11, the operation is no longer the same. For actions 3 and 6, no procedure can receive messages to set breakpoints, to advance execution, or to send back notifications when a breakpoint is reached. For action 11, no procedure can use the kernel API to query and determine memory or registers.
Therefore, in some embodiments, in order to achieve action 3 above, the source translation code requires the runtime translation code to indicate which memory address X has machine code for a given method + IL offset where a breakpoint should be set. This address X is saved for later use.
To achieve action 6 above, in some embodiments, the source translation code directly instructs the low-level base of the debugger or (multiple) other tools to advance the tracing to a new time t', where t' is the next time point where the machine instruction at address X will be simulated or emulated for execution. For action 6, one embodiment can use the same procedure typically used in dump debugging to translate from an IL offset to a procedure memory offset. However, this embodiment uses the translated memory offset to set a virtual breakpoint within the tracing replay engine. The virtual procedure (replay execution) stops when the replay engine reads this memory address during virtual execution. Indeed, if the tracing contains more than one version of the same functionality (via re-jitted), the runtime translation may require the tracing to provide multiple addresses to cover a single breakpoint. This address can be different for different time ranges in the tracing, or it can be the address of a runtime function (such as a jittering function) so that the runtime translation can locate the new re-jitted position of the function.
To achieve the above action 11, instead of reading from the real-time process, trace 418 is read and memory and registers corresponding to time t' are provided.
Replay debugging scene
By providing access to both forward and backward execution during debugging, system 800 can enhance debugging efficiency. For example, some embodiments support the following debugging scenarios.
By using context, technicians will realize that production debugging is difficult. Suppose a customer reports an issue on the website. How do developers debug it? Some familiar methods rely on information such as logs and dumps, which only provide point-in-time information. Therefore, if the problem doesn't reproduce or occur at the specific moment captured in the logs or dumps, developers must try again to capture useful information at different points in the execution, meaning it takes much longer to resolve the issue.
Instead, imagine an environment that can tell developers exactly what's happening in a production application, line by line. Using Microsoft Time Travel debugging or other reverse-execution replay implementations allows team members to collect a high-fidelity record of the application's behavior. Developers can then debug the application offline in a familiar environment, such as a Microsoft environment or other debugging or IDE.
As a concrete example, suppose the SmartHotels360 website is experiencing an issue; this is a demo website whose code is publicly available from Microsoft via GitHub.com. The developers of the company running the SmartHotels360 website receive a report from users indicating that a feature in BestHotels is no longer displaying data. However, it was working perfectly before, and the issue has not been reproduced in the company's test or staging environments. Members of the operations or engineering team have collected logs (trace 418) of the application while running the code powering the malfunctioning feature. Trace 418 can be collected into file 420 via command-line tools, or automatically triggered by a cloud environment (or another cloud environment) when certain conditions are met, such as throwing more exceptions than expected.
The developer opens the debugger and loads the SmartHotels360 code and trace file 420. Execution stops at a breakpoint on line 28 in the API that returns to BestHotels. Now, even though this is a log file, in this example, the developer can use many familiar commands to navigate it using a debugger they are typically familiar with. The developer wants to know what happened when the API was called. The developer steps over lines 28 and 29 and sees from the Locals window that after stepping over line 29, bestHotels has zero entries. If the debugger supports data hints, the developer can also view them, at least in this example.
Now, the developer has identified the cause of the problem in the `BestHotels()` routine. Therefore, the developer wants to investigate what happened in `BestHotels()`. Alternatively, to see what happened back to the original call, the developer could click Continue, click the breakpoint again, and step into the next call to `BestHotels()`, even though the values, objects, and memory addresses might differ from the partially debugged call. Alternatively, when the debugger state is difficult to reproduce, the developer could restart the application, which could be time-consuming. However, in this example, the environment supports time-travel debugging. Therefore, the developer uses the Reverse Continue button (requesting to continue backwards 920 operations) to rewind the application to the state of the previous breakpoint. One result of this rewind is that the locale will be reset to its previous state at line 28 before the aforementioned stepping is performed. Now, by ensuring that all values, objects, and memory addresses from the partially debugged call are the same, the developer can skip the `Load()` routine and step into `BestHotels()`.
At this point, the developer decides to step through `BestHotels()` and delve deeper into `GetBestHotels()`. Therefore, the developer wants to skip line 36 and then step into line 37. Suppose the developer accidentally pressed the skip button multiple times. Through time travel debugging, the developer can quickly go back and see what happened in `GetBestHotels()`. In fact, the developer can use the backstep button (requesting to step back into operation 914), which will take execution into `GetBestHotels()` and play it backward. The developer discovers that at the end of `GetBestHotels()`, the value of the local variable `bestHotels` (corresponding to the count) is zero. Clearly, all levels were filtered out.
Therefore, the developers decided to test the assumption by checking the ratings of all hotels. Remember, this trace occurred in production, so these values are actual. The developers can evaluate the expression using the debugger's live window, which is possible through the live debugging process. The developers evaluated the expression "AllHotels.Select(h => h.rating)" in the debugger's live window and found that the ratings were floating-point numbers, while the code was checking for rating values equal to integers 4 or 5. There was a data type mismatch; the shape of the data in production did not match the application's expectations.
Now suppose the developer has completed the debugging described above and wants to discuss it with a colleague and show them in detail what happened. The developer wants to start over at the beginning of the investigation and wants a way to quickly return to a specific point of interest. Therefore, the developer sets a breakpoint on line 21 and then rewinds to that breakpoint. Replaying then allows the developer to reproduce the debugging steps. If the developer wants to jump to the end, they can continue until they reach the last breakpoint they set.
In short, developers can use the application's high-fidelity tracing 418 to quickly debug issues, capturing what actually happened in production. With the power of a debugger adapted to the replay described here, developers can debug using a familiar debugger user interface and can debug forward and backward, saving significant developer time.
in conclusion
Although specific embodiments are explicitly shown and described herein as processes, configured media, or systems, it should be understood that the discussion of one type of embodiment generally extends to several other types of embodiments. For example, the process descriptions taken in conjunction with Figures 13 and 14 also help to describe the configured media and to describe the technical effects and operation of those similar systems and manufactures discussed in conjunction with the other figures. It is not necessarily required that limitations from one embodiment be read into another. In particular, processes are not necessarily limited to the data structures and arrangements presented when discussing systems or manufactures such as configured memory.
Those skilled in the art will understand that implementation details may relate to specific code, such as a specific API, a specific domain, and a specific sample program, and therefore may not necessarily appear in every embodiment. Those skilled in the art will also understand that program identifiers and some other terms used in discussing details are implementation-specific and therefore not necessarily related to every embodiment. Nevertheless, while their presence is not necessarily required herein, such details can assist some readers by providing context and/or can illustrate some of the many possible implementations of the techniques discussed herein.
References herein to an embodiment having some feature X, and references elsewhere herein to an embodiment having some feature Y, do not exclude embodiments having both feature X and feature Y, unless such exclusion is expressly indicated herein. All possible limitations of the claims are within the scope of this disclosure, as any feature that is prescribed as part of an embodiment may be expressly removed from some other embodiment, even if no specific exclusion is given in any example herein. The term “embodiment” is used herein only as a more convenient form of “process, system, article of manufacture, computer-readable medium of configuration and/or other example of the teachings herein applied in a manner consistent with applicable law.” Therefore, a given “embodiment” may include any combination of features disclosed herein, provided that the embodiment is consistent with at least one claim.
In each embodiment, not every item shown in the figures must be presented. Instead, an embodiment may include items not explicitly shown in the figures. Although some possibilities are illustrated herein by way of specific examples in the text and figures, embodiments may deviate from these examples. For example, specific technical effects or features of an example may be omitted, renamed, grouped differently, repeated, instantiated differently in hardware and/or software, or a mixture of effects or features appearing in two or more examples. In some embodiments, functionality shown in one location may also be provided in different locations; for example, those skilled in the art will recognize that functional modules can be defined in various ways in a given implementation without having to omit the desired technical effects from a collection of interactive modules considered as a whole.
The figures are referenced throughout the text using reference numerals. Any apparent inconsistencies in the wording related to a given figure reference in the figures or text should be understood as simply broadening the scope of the number referred to. Even when using the same figure reference, different instances of a given figure reference may refer to different embodiments. Similarly, given figure references...
It can be used to refer to verbs, nouns, and/or corresponding instances of each, for example, processor 110.
Instruction 110 can be processed by executing instructions.
As used herein, terms such as “an” and “the” include one or more of the indicated item or step. In particular, in the claims, a reference to an item generally means that there is at least one such item, while a reference to a step indicates at least one instance of performing that step.
The headings are for convenience only; information about a given topic can be found outside of the sections that indicate the subject in the headings.
All claims and abstracts submitted are part of the specification.
Although exemplary embodiments have been shown in the accompanying drawings and described above, it will be apparent to those skilled in the art that various modifications may be made without departing from the principles and concepts set forth in the claims, and such modifications do not necessarily encompass the entire abstract concept. Although the subject matter has been described in language specific to structural features and/or procedural actions, it should be understood that the subject matter defined in the appended claims is not necessarily limited to the specific technical features or actions described in the claims. Each means or aspect or technical effect identified in a given definition or example need not be presented or utilized in every embodiment. Rather, the specific features, actions, and effects described are disclosed as examples for consideration in implementing the claims.
To the maximum extent permitted by law, all changes that fall within the entire abstract concept but fall within the equivalent meaning and scope of the claims should be included within its scope.

Claims (20)

1. A tracking and playback execution control system, comprising:
processor;
A memory operable and communicative with the processor;
The trace recorded during the execution of the program in combination with calls to the program runtime and the kernel, wherein the trace includes trace entries that include a record of the activity of native code instructions executed in at least one thread of the program, wherein the activity of the native code instructions is traced when the program is executed, and wherein the trace does not include any execution instances of the program runtime.
At least a portion of the source code of the program;
Source intermediate mapping, which automatically maps between the source code of the at least portion of the program and an intermediate representation of the source code of the at least portion of the program;
Intermediate native mapping, which automatically maps between the intermediate representation of the source code of at least a portion of the program and the tracing; and
An execution controller in a software tool, wherein the execution controller is configured to control the replay execution of the trace in response to receiving a trace replay execution control request when executed by the processor, wherein the source code is associated with the trace entry through the source intermediate map and the intermediate native map.
2. The tracking replay execution control system of claim 1, wherein the execution controller is further configured to translate requests for at least the following operations into corresponding executions of tracking native code instructions:
Perform a forward step-in operation;
Execute the step-out operation forward; and
Perform a step-skip operation forward.
3. The tracking replay execution control system of claim 1, wherein the execution controller is further configured to translate requests for at least the following operations into corresponding executions of tracking native code instructions:
Perform a backward step-in operation;
Perform a step-out operation backward; and
Perform a step-skip operation backward.
4. The tracking replay execution control system of claim 1, wherein the execution controller is further configured to translate requests for at least the following operations into corresponding executions of tracking native code instructions:
The tracing continues forward until a position within the breakpoint range is reached, and
The tracing continues backward until the position within the breakpoint range is reached.
5. The tracking replay execution control system of claim 1, wherein the tracking replay execution control system is configured to step into a portion of the source code of at least a portion of the program, the portion of the source code not yet compiled into native code instructions during the replay execution of the tracking.
6. The tracking replay execution control system of claim 1, wherein the intermediate representation of the source code of the at least portion of the program comprises at least one of the following:
A symbol table that associates at least two identifiers used in at least a portion of the source code of the program with data types;
An abstract syntax tree derived from at least a portion of the source code of the program; or
The conversion of at least a portion of the source code of the program into an intermediate language.
7. The trace replay execution control system of claim 1, wherein the trace does not contain any execution instance of the program's runtime, because the trace replay execution control system is not configured to invoke the trace to execute any code specific to the program's runtime.
8. The tracking replay execution control system of claim 1, further comprising a real-time process of the program having a callable instance of the program at runtime, wherein the tracking is recorded from the real-time process of the program and the tracking replay execution control system is configured to replay the execution of the tracking recorded from the real-time process of the program.
9. The tracking replay execution control system of claim 1, wherein the tracking replay execution control system is configured to skip a portion of the tracking replay execution because the execution controller moves the replay execution of the portion of the tracking from a first execution time point of the tracking to a second execution time point of the tracking, and the tracking replay execution control system does not execute tracking native code instructions that would otherwise be executed by continuing execution from the first execution time point of the tracking to the second execution time point of the tracking.
10. A method for tracking and replaying execution control, comprising:
Identify the managed program being tracked, the managed program being tracked being configured to execute in conjunction with runtime and kernel calls to the managed program being tracked during execution;
Receive a trace replay execution control request, wherein the trace replay execution control request is received in a software tool running on a computing system;
Based on the received trace replay execution control request, an automatic mapping is performed between the source code of the traced managed program and an intermediate representation of the source code of the traced managed program, and an automatic mapping is performed between the intermediate representation of the source code of the traced managed program and a trace recorded during the execution of the traced managed program, wherein the trace includes trace entries, the trace entries including: a record of the activity of native code instructions executed by at least one processor in at least one thread of the traced managed program, wherein the activity of the native code instructions is traced when the traced managed program is executed, and wherein the trace does not include any execution instance of the runtime of the traced managed program; and
Execute trace native code instructions corresponding to the trace replay execution control request, wherein the source code is associated with the trace entry through a source intermediate map and the intermediate native map, thereby replaying the execution of a portion of the trace.
11. The trace replay execution control method of claim 10, wherein the trace replay execution control request indicates a backward step-out operation to step out of the routine, and the trace replay execution control method further includes setting a breakpoint on the trace native code instruction, the breakpoint having a position immediately preceding the return address of the call to the routine, and wherein position A in the trace immediately precedes position B when A is encountered before B during forward execution of the trace and there are at most five trace native code instructions between A and B.
12. The trace replay execution control method of claim 10, wherein the source code of the traced managed program comprises statements and expressions, wherein the trace replay execution control method further comprises setting breakpoints on trace native code instructions, the breakpoints being on the edge of a set of all trace native code instructions, the all trace native code instructions being mapped by the trace replay execution control method to a given statement or a given expression in the source code of the traced managed program, and wherein X is on the edge of G when instruction X in a set of instructions G being traced satisfies at least one of the following conditions:
X is the first instruction of G encountered during the forward execution of the trace;
X is the last instruction of G encountered during the forward execution of the trace;
X is the first instruction of G encountered during the backward execution of the trace; or
X is the last instruction of G encountered during the backward execution of the trace.
13. The tracking replay execution control method according to claim 12, wherein the tracking replay execution control request invokes one of the following:
Perform a forward step skip operation to skip the routine step by step;
Perform a backward step skip operation to skip the routine step by step;
Perform a forward step-in operation to step into the forward step-in routine; or
Perform a backward step-in operation to step into the backward step-in routine.
14. The trace replay execution control method of claim 10, wherein the trace replay execution control request identifies a forward execution step-in operation to step into a user code routine, wherein the replay execution of the user code routine includes the replay execution of at least one call to a runtime routine, wherein the at least one call to the runtime routine has no corresponding call statement or call expression in the source code of the traced managed program, and wherein the trace replay execution control method further comprises at least one of the following:
Set a breakpoint range that specifies the entire memory range designated to receive dynamically compiled code; or
Set breakpoints to perform step-skip operations on at least one call to the runtime routine.
15. The tracking replay execution control method according to claim 10, wherein the tracking replay execution control request invokes at least one of the following operations:
The replay execution continues forward during the tracing until the breakpoint is reached.
The replay execution continues forward during the tracing until the position within the breakpoint range is reached.
The execution is replayed and traced backwards during the tracing process until a breakpoint is reached.
The replay execution continues to be traced backward until the position within the breakpoint range is reached.
Perform a backward step-in operation;
Perform a step-out operation backward;
Perform a step-skip operation backward;
Perform a forward step-in operation;
Execute the step-out operation forward; or
Perform a step-skip operation forward.
16. The trace replay execution control method of claim 10, wherein during the execution of the traced managed program, the maximum number of breakpoints is constrained by a hardware breakpoint constraint that the processor can monitor up to N addresses at a time, and wherein the trace replay execution control method further includes setting more than N breakpoints during the replay execution of the traced portion, thereby exceeding the hardware breakpoint constraint.
17. A computer-readable storage medium storing data and instructions, the data and instructions executing a trace-replay execution control method when executed by a processor operably in communication with the memory, the trace-replay execution control method comprising:
Identify the managed program being tracked, the managed program being tracked being configured to execute in conjunction with runtime and kernel calls to the managed program being tracked during execution;
Receive a trace replay execution control request, wherein the trace replay execution control request is received in a software tool running on a computing system;
Based on the received trace replay execution control request, an automatic mapping is performed between the source code of the traced managed program and an intermediate representation of the source code of the traced managed program, and an automatic mapping is performed between the intermediate representation of the source code of the traced managed program and a trace recorded during the execution of the traced managed program, wherein the trace includes trace entries, the trace entries including: a record of the activity of native code instructions executed by at least one processor in at least one thread of the traced managed program, wherein the activity of the native code instructions is traced when the traced managed program is executed, and wherein the trace does not include any execution instance of the runtime of the traced managed program; and
Execute trace native code instructions corresponding to the trace replay execution control request, or set breakpoints on trace native code instructions, wherein the source code is associated with the trace entry through a source intermediate map and the intermediate native map, thereby controlling the replay execution of the trace.
18. The computer-readable storage medium of claim 17, wherein the traced managed program is combined with debugger code, including a real-time process and the execution runtime of the traced managed program, and wherein the debugger code communicates with the execution runtime of the traced managed program, and the trace replay execution control method further includes using the trace control to perform a replay backward without terminating the traced managed program.
19. The computer-readable storage medium of claim 17, wherein the trace replay execution control method further comprises at least two of the following execution control activities:
Using machine-level information in the trace to control the execution of the runtime of the traced managed program at a high level, wherein controlling the execution of the runtime of the traced managed program at a high level refers to control based on user selection, the user selection specifying identifiers or statements or expressions in the source code of the traced managed program, and the machine-level information in the trace refers to processor architecture-specific information.
Debugging both the forward and backward execution of the process of the managed program being traced;
At least in part, stepping into the calls shown in the source code of the traced managed program is achieved by setting a large breakpoint range, wherein the breakpoint range is large when it covers at least one thousand consecutive addresses or instructions in the trace;
When the tracing includes at least two versions of the native code of the routine, it maps to a specific version of the native code of the routine; or
While debugging the real-time process of the managed program being tracked, trace data from the real-time process is recorded, and then at least some of the recorded trace data is used to perform reverse execution debugging on the real-time process.
20. The computer-readable storage medium of claim 17, wherein the trace replay execution control method further comprises at least three of the following execution control activities:
Using machine-level information in the trace to control the execution of the runtime of the traced managed program at a high level, wherein controlling the execution of the runtime of the traced managed program at a high level refers to control based on user selection, the user selection specifying identifiers or statements or expressions in the source code of the traced managed program, and the machine-level information in the trace refers to processor architecture-specific information.
Debugging both the forward and backward execution of the process of the managed program being traced;
At least in part, stepping into the calls shown in the source code of the traced managed program is achieved by setting a large breakpoint range, wherein the breakpoint range is large when it covers at least one thousand consecutive addresses or instructions in the trace;
When the tracing includes at least two versions of the native code of the routine, it maps to a specific version of the native code of the routine; or
While debugging the real-time process of the managed program being tracked, trace data from the real-time process is recorded, and then at least some of the recorded trace data is used to perform reverse execution debugging on the real-time process.
HK62021024900.4A 2018-05-02 2019-04-25 Execution control with cross-level trace mapping HK40035552B (en)

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
US15/969,721 2018-05-02

Publications (2)

Publication Number Publication Date
HK40035552A HK40035552A (en) 2021-05-14
HK40035552B true HK40035552B (en) 2025-10-03

Family

ID=

Similar Documents

Publication Publication Date Title
KR102898770B1 (en) Execution control through cross-level trace mapping
US11249881B2 (en) Selectively tracing portions of computer process execution
US10621068B2 (en) Software code debugger for quick detection of error root causes
US10541042B2 (en) Level-crossing memory trace inspection queries
EP3785125B1 (en) Selectively tracing portions of computer process execution
US10657031B2 (en) Scalable execution tracing for large program codebases
CN102541731B (en) Platform-agnostic diagnostic data collection and display
CN115705250A (en) Monitoring stack usage to optimize programs
Watson Writing high-performance. NET code
HK40035552A (en) Execution control with cross-level trace mapping
Kim Dual Execution And Its Applications
Leija Leveraging System Call Interposition for Low-Level Process Manipulation
Vilk Righting Web Development
Perianayagam Reproducing software experiments
Altekar et al. Output-deterministic replay for multicore debugging