mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-07 15:22:31 +01:00
Updated to upcoming 23.09
git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2393 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
[[Property:title|Debugging and Run-time Monitoring]]
|
||||
[[Property:weight|-2]]
|
||||
[[Property:uuid|a53f6a74-7145-35ab-ed5e-2905aeb88774]]
|
||||
|
||||
The next set of EiffelStudio capabilities enables you to control and monitor the execution of your systems. The obvious immediate application is to debugging; but the more general goal is to let you follow the execution of your systems, explore the object structures, and gain a better understanding of the software.
|
||||
|
||||
|
||||
==A reminder about debugging in Eiffel==
|
||||
|
||||
Before looking at debugging facilities don't forget that debugging in Eiffel is different. The presence of Design by Contract mechanisms gives the debugging process a clear sense of direction. The speed of the recompilation process makes it easy to recompile after a change; after getting rid of syntax and validity errors, you run the system again, and remaining errors are often caught as violations of contract clauses -- routine preconditions, routine postconditions, class invariants.
|
||||
|
||||
The facilities to be described now are also useful when you find such an error, as they will help you study its execution context. In fact, one of the characteristics of the debugging mechanism is that there is no "debugger" proper, no more than there is a "browser"; you have instead a set of facilities supporting controlled execution and debugging. This means for example that:
|
||||
* While debugging, you can access all the browsing capabilities to explore the features and classes surrounding the cause of an error.
|
||||
* While browsing, you can launch or resume execution, and follow its progress through the debugging facilities.
|
||||
* If execution stops on an exception -- for example, an assertion violation or arithmetic overflow -- you have all the environment's facilities at your disposal to understand what happened.
|
||||
|
||||
|
||||
==Setting breakpoints==
|
||||
|
||||
To control the execution you will set breakpoints, indicating places where you want to interrupt the execution. You may set a breakpoint on an individual instruction of a routine, on the routine's precondition or postcondition, or on the routine as a whole, meaning its first operation (precondition or instruction).
|
||||
|
||||
A group of icons on the Project Toolbar help control breakpoints. They are known in EiffelStudio terminology as "''buttonholes''", meaning that they can serve both as buttons (you can click them to get some functions) and holes (you can pick-and-drop into them to get some other functions).
|
||||
|
||||
[[Image:es gt debug buttons|Run and debug buttons]]
|
||||
|
||||
The labels correspond to the icons' use as buttons: enable all set breakpoints ([[Image:16x16--breakpoints-enable-icon]]), disable them all ([[Image:16x16--breakpoints-disable-icon]]), remove them all ([[Image:breakpoints-delete-icon]]), and display information on current breakpoints using the Breakpoints tool ([[Image:debug-show-breakpoints-tool]]). The difference between "disabling" and "removing" is that disabling turns off breakpoints until further notice but remembers them, so that you can later re-enable them, whereas "removing" clears them for good.
|
||||
|
||||
Here you also see icons for controlling execution: '''run''' ([[Image:debug-run-icon]]), '''step-by-step''' ([[Image:debug-step-over-icon]]), '''step into routine''' ([[Image:debug-step-into-icon]]), '''step out of routine''' ([[Image:debug-step-out-icon]]).
|
||||
|
||||
Target a Development Window to the class <code>TESTROOT</code> and pick-and-drop the name of the procedure <code>make</code> (the first routine, after the declaration of the two attributes <code>o1</code> and <code>o2</code>) to the '''Enable all''' icon, used here as a hole. This sets and enables a breakpoint on the routine. Click the button labeled '''Show information about breakpoints''' ([[Image:debug-show-breakpoints-tool]]). This will invoke the '''Breakpoints tool''', as shown in the next figure.
|
||||
|
||||
[[Image:es gt breakpoints tool 01|The Breakpoints tool]]
|
||||
|
||||
This shows that so far you have enabled only one breakpoint. For a finer degree of control, let's look at the feature's flat form. Close the Breakpoints tool, then pick-and-drop <code>make</code> from the Editing Tool to the Feature tool (anywhere in the lower left pane should do; this sets the pane's context to the <code lang=text>Feature</code> Tool. Select the '''Flat''' view if that wasn't the last one used:
|
||||
|
||||
[[Image:es gt development window breakpoints 01|Breakpoint set in "make"]]
|
||||
|
||||
The small circles on the left side of the Flat form indicate breakpoint positions. Empty ones are not set; enabled breakpoints are marked by a circle filled with red. At the moment only one is enabled, corresponding to the first instruction of the routine since, as noted, setting a breakpoint on a routine as a whole means setting it on its first operation.
|
||||
|
||||
By (left) clicking on a breakpoint mark, you toggle it between enabled and not set. You can also right-click on a mark to get a [[Breakpoint menu|menu]] of possibilities:
|
||||
|
||||
[[Image:es gt breakpoint context menu 01|Breakpoint context menu]]
|
||||
|
||||
Try enabling and unsetting a few of these marks; you might get something like this:
|
||||
|
||||
[[Image:es gt development window breakpoints 02|Multiple breakpoints: not set; enabled; set but disabled]]
|
||||
|
||||
The breakpoint mark for the routine's third instruction, <code>create o2</code>, is filled but not red ([[Image:bp-disabled-icon]]); this means it is set but not enabled. You can obtain this by right-clicking on the mark and choosing '''Disable breakpoint''' on the menu that comes up. Any potential breakpoint will be in one of three states: '''not set''' ([[Image:bp-slot-icon]]); '''set and enabled''' ([[Image:bp-enabled-icon]]); '''set but not enabled''' ([[Image:bp-disabled-icon]]).
|
||||
|
||||
Remember, you can see the complete list of enabled and disabled breakpoints by making the Breakpoints tool visible ... which you do by clicking the '''Show information about breakpoints''' ([[Image:debug-show-breakpoints-tool]]) button in the Project Toolbar.
|
||||
|
||||
For the remainder of this chapter it doesn't matter which exact breakpoints of <code>make</code> you've set, as long as the one on its first instruction is set and enabled (red-filled circle) as above. Please make sure this is the case before proceeding.
|
||||
|
||||
|
||||
==Executing with breakpoints==
|
||||
|
||||
To execute, you will use the following Run buttons in the Project toolbar, or the corresponding entries in the '''Execution menu''':
|
||||
|
||||
[[Image:es gt debug buttons|Run and debug buttons]]
|
||||
|
||||
Most of the buttons shown here are enabled, but at different times some of them will be disabled (grayed out.)
|
||||
|
||||
The '''Execution menu''' entries will also remind you of shortcuts: F10 for '''Step-by-step''', F11 for '''Step into routine''', Shift-F11 for '''Step out of routine''', <code>CTRL-F5</code> for '''Run ignoring breakpoints''', F5 for '''Run with breakpoints''', <code>CTRL-Shift-F5</code> for '''Interrupt execution''', Shift-F5 for '''Stop execution'''.
|
||||
|
||||
[[Image:es gt execution menu 01|Execution menu]]
|
||||
|
||||
Start execution of the compiled system by clicking the '''Run''' button ([[Image:debug-run-icon]]). Run actually means "Run and stop at enabled breakpoints." EiffelStudio automatically switches to '''Execution mode''' to accommodate supplementary tools providing debugging information. Execution stops on the breakpoint that you have enabled on the first instruction of procedure <code>make</code>:
|
||||
|
||||
[[Image:es gt debug breakpoint reached 01|Stopped at first breakpoint in "make"]]
|
||||
|
||||
By default, in Execution mode, EiffelStudio looks a little different. Specifically, the Feature tool now occupies the space that was previously held by the Editing tool. The '''Call Stack''' is in the tall pane on the right, and the '''Object tool''' and '''Watch tool''' are on the bottom, under the Feature tool.
|
||||
|
||||
The Call Stack indicates that execution has stopped in <code>make</code>. The Feature tool shows the flat form of that routine, with an icon ([[Image:debug-stopped-on-breakpoint-icon|Stopped on enabled breakpoint]]) to indicate the stop point which execution has reached. The Object tool, which shows the content of current object and (later) related objects. At the moment you can see that:
|
||||
* The current object is an instance of class <code>TESTROOT</code>.
|
||||
* The class (as you could also see from its text in a Development Window) has two attributes <code>o1</code> and <code>o2</code>, both declared as type <code>PARENT</code>, for which the corresponding fields in the current object are both void; this is as expected since you haven't yet executed the two creation instructions <code> create {HEIR} o1</code> and <code>create o2</code>, as they come after the breakpoint.
|
||||
* Along with attributes, an Eiffel class may have '''once functions''', executed at most once -- the first time they are called -- in a given session, and from then on always returning the same value. You can see the status of these by expanding the entry "Once routines" in the Object tool. Here the once function <code>io</code> has not yet been called, but after it has it will return an object of type <code>STD_FILES</code>.
|
||||
|
||||
The execution-time objects that you may display in the Object tool are our latest kind of EiffelStudio "development object", along with classes, features, explanations, clusters; notice the distinctive icon ([[Image:debugger-object-eiffel-icon]]), a rectangular mesh shape suggestive of an object's division into fields. It appears colored for actual objects and gray ([[Image:debugger-object-void-icon]]) for Void references such as <code>operating_environment.</code>
|
||||
|
||||
|
||||
==Monitoring progress==
|
||||
|
||||
Click twice on '''Step-by-step''' ([[Image:debug-step-over-icon]]), or press the function key F10 twice. Monitor, in the flat form of <code>make</code>, the marker that shows execution progress; note that the marker always points to the ''next'' operation to be executed. After the two steps, the Feature and Object tools look like this:
|
||||
|
||||
[[Image:es gt debug step by step 01]]
|
||||
|
||||
The last instruction that you executed is <code>create {HEIR} o1</code>, meaning create an object and attach it to <code>o1</code>, but instead of using the declared type <code>PARENT</code> of <code>o1</code> use its proper descendant <code>HEIR</code>. As a result, the entry for <code>o1</code> in the Object tool no longer shows <code>Void</code> but an object of type <code>HEIR</code>. Note that all objects are identified by their addresses in hexadecimal; such an address is by itself meaningless, but enables you to see quickly whether two object references are attached to the same object. The addresses you see as you run the Guided Tour will -- except for some unlikely coincidence -- be different from the ones appearing here.
|
||||
|
||||
Note that since the garbage collector compacts memory and hence may move objects around, the address of a given object is not guaranteed to remain the same throughout a session.
|
||||
|
||||
To see the details of the object, expand its entry in the Object tool.
|
||||
|
||||
|
||||
==From the instance to the class==
|
||||
|
||||
Now notice what happens if you pick the type name (<code>HEIR</code>) from the entry for object <code>o1</code> in the Object tool, and then drop it in the Feature tool above. The context changes from the Feature tool to the Class tool and is retargeted on <code>HEIR</code>. The Class tool has switched to the default format for classes, '''Ancestors''', and is showing the ancestors of <code>HEIR</code>. Click the Feature tab to get back to feature information for the continuation of our debugging session.
|
||||
|
||||
|
||||
==Stepping into and out of a routine==
|
||||
|
||||
Click '''Step-by-step''' once more to advance just before the call <code>o1.display</code>.
|
||||
|
||||
Choosing '''Step-by-step''' again would execute the next step in the current routine, the call <code>o1.display</code>, treating the entire execution of <code>display</code> from class <code>HEIR</code> as a single operation. Assume instead that you want to go ''into'' that routine and follow the details of its execution. For one thing, you might not know that it's a routine of class <code>HEIR</code>, since <code>o1</code> is declared of type <code>PARENT</code> and it's only through polymorphism, that is, <code>o1</code> being dynamically of type <code>HEIR</code> at this point, and through dynamic binding, that the execution ends up calling a routine from <code>HEIR</code>. Of course here it's obvious because of the wording of the <code>create</code> a few lines up, but in many cases, especially all those for which polymorphism and dynamic binding are ''really'' interesting, the exact type won't be immediately clear from the neighboring software text.
|
||||
|
||||
Click the '''Step into routine''' button (or press F11). This brings execution to the beginning of the appropriate <code>display</code> routine in class <code>HEIR</code>.
|
||||
|
||||
[[Image:es gt debug step into 01]]
|
||||
|
||||
While you're here notice the Call Stack tool. It shows that we are currently executing feature <code>display</code> of class <code>HEIR</code>, which, as can be seen on the second line of the stack, was called from feature <code>make</code> of class <code>TESTROOT</code>.
|
||||
|
||||
Now click '''Step out of routine''' ([[Image:debug-step-out-icon]]), or press Shift-F11 to finish the execution of <code>display</code>. This brings you back to the next instruction of the calling routine, <code>make</code> of <code>TESTROOT</code>.
|
||||
|
||||
|
||||
==Terminating==
|
||||
|
||||
You may now click the '''Stop execution''' button ([[Image:debug-stop-icon]]), or press Shift-F5, to end execution. The execution-specific tools go away and the display returns to what it was before execution.
|
||||
|
||||
|
||||
==Other debugging capabilities==
|
||||
|
||||
In this little application nothing runs long enough to give you the time to interrupt it. In a longer-running application you may want to interrupt execution, <span>without</span> necessarily terminating it, while it's running (not stopped on a breakpoint). This is the purpose of the '''Interrupt execution''' button ([[Image:debug-pause-icon]]), which can also be triggered by pressing <code>CTRL-Shift-F5</code>. It will interrupt execution at the closest potential breakpoint position, letting you -- as when execution stops because of an exception -- take advantage of all the debugging and browsing facilities to see what's going on inside your running system. You may then restart execution -- with or without breakpoints, single-stepping, out of the current routine, into the next routine -- by choosing the appropriate Run button
|
||||
|
||||
In debugging sessions for more advanced applications, you will also find self-explanatory mechanisms enabling you, in addition to what we have seen, to examine all the objects on the "call stack": arguments and local entities of the current routine, its caller, caller's caller and so on.
|
||||
|
||||
The combination of these facilities provides you with a level of ''dynamic'' information on the execution of your system that matches the ''static'' information that the browsing mechanisms studied in preceding sections provide about the system's structure.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user