[[Property:title|13 Debugging and Run-time Monitoring]] [[Property:link_title|Debugging and Run-time Monitoring]] [[Property:weight|-2]] [[Property:uuid|a53f6a74-7145-35ab-ed5e-2905aeb88774]] The next set of EiffelStudio capabilities enable 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.
TESTROOT and pick-and-drop the name of the procedure make (the first routine, after the declaration of the two attributes o1 and o2 ) to the Enable all icon, used here as a hole. This sets and enables a breakpoint on the routine. Click the button labeled Show/Hide information about breakpoints above to get the list of breakpoints, as shown in the next figure.
[[Image:index-83]]
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. Pick-and-drop make to the Context Tool -- from the Context Tool itself, since its name appears there, or the Editing Tool); this sets the Context to the Feature Tab. Select the Flat view if that wasn't the last one used:
[[Image:index-84]]
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 menu of possibilities. Try enabling and unsetting a few of these marks; you might get something like this:
[[Image:index-85]]
The breakpoint mark for the routine's third instruction, create o2 , is red but not filled; 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; enabled; set but disabled.
You can see the list of enabled and disabled breakpoints by clicking the Output Tab, or the Display info button in the Project Toolbar.
For the continuation of this tour it doesn't matter which exact breakpoints of make 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.
Debug menu:
[[Image:index-82]]
The buttons are shown here in full bloom, but at any times some of them will be grayed out. Terminate is only active when execution has started and not terminated; Interrupt is only active when the execution is active (not stopped at a breakpoint).
The Debug 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 , CTRL-F5 for Run without breakpoints , F5 for Run with breakpoints , CTRL-Shift-F5 for Interrupt , Shift-F5 for Terminate .
Start execution of the compiled system by clicking Run with breakpoints . The display automatically switches to accommodate supplementary tools providing debugging information. Execution stops on the breakpoint that you have enabled on the first instruction of procedure make :
[[Image:index-87]]
The pane at the bottom left indicates that execution has stopped in make . The Context shows the flat form of that routine, with a new icon to indicate the stop point which execution has reached. At the bottom right is a new tool, the '''Object Editor''', 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 TESTROOT .
* The class (as you could also see from its text in a Development Window) has two attributes o1 and o2 , 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 create { HEIR } o1 and create o2 , 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. Here the once function io has not yet been called, but when it is it will return an object of type STD_FILES .
The execution-time objects that you may display in an Object Editor are our latest kind of EiffelStudio "development object", along with classes, features, explanations, clusters; notice the distinctive icon, a rectangular mesh shape suggestive of an object's division into fields. It appears colored for actual objects and gray for Void references such as operating_environment.
Step-by-step (or press the function key F10 twice). Monitor, in the flat form of make , the marker that shows execution progress; note that the marker always points to the next operation to be executed. After the two steps, the Context and Object Tools look like this:
[[Image:index-88]]
The last instruction that you executed is create { HEIR } o1 , meaning create an object and attach it to o1 , but instead of using the declared type PARENT of o1 use its proper descendant HEIR . As a result, the entry for o1 in the Object Tool no longer shows Void but an object of type HEIR . 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, pick-and-drop its identifier in place (that is to say, drop it in the Object Tool itself). A new object entry appears, showing the object.
HEIR , to the Context Tool above the Object window. The effect is the same as if you had pick-and-dropped the '''class''' name HEIR : retarget the Context Tool to that class.
In the same way that you can drop a feature pebble into a tool that expects a class, you can also drop an object pebble, which will be understood as denoting the object's generating class.
Because the Context Tool is showing a class, it has switched to the default format for classes, Ancestors , and is showing the ancestors of HEIR . Click the Feature Tab of the Context Tool to set it back to feature information for the continuation of our debugging session. No feature is currently displayed.
Step-by-step once more to advance just before the call o1 . display .
Choosing Step-by-step again would execute the next step in the current routine, the call o1 . display , treating the entire execution of display from class HEIR 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 HEIR , since o1 is declared of type PARENT and it's only through polymorphism, o1 being dynamically of type HEIR at this point, and through dynamic binding, that the execution ends up calling a routine from HEIR . Of course here it's obvious because of the wording of the create 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 display routine in class HEIR .
You can also expand the Call stack pane on the left to see the full call stack, consisting here of only two levels. Minimize it to get the above display back.
Now click Step out of routine (Shift-F11) to finish the execution of display . This brings you back to the next instruction of the calling routine, make of TESTROOT .
Terminate button (Shift-F5) to end execution. The execution-specific tools go away and the display returns to what it was before execution.
Interrupt button (CTRL-Shift-F5). 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 the program. 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.