Home ESF Logo Text Only Quick link to main content

Home | Services | Events | Features | Interviews | Profiles | Reviews | News | Resources | Press | Archive

Section 7: Breakpoints, Call Stack, Watch Window, CPU Window


Being able to pause a program by pressing the pause button is not extra specially useful. Whilst it does give you the opportunity to stop your application during a long processing loop, more often than not, you will find yourself wanting to stop the program in the confines of a procedure or function that takes less than a millisecond to run. In order to do this, Delphi provides "Breakpoints". These can be set in a number of ways - the simplest being to click on the left hand margin of the code, level with the line you want the debugger to stop at when it arrives there.

Doing this will leave a red circle in the margin of the code. If the circle isn't red, then Delphi is trying to tell you that the line you have placed the breakpoint on will either never be reached, or does not




Figure 13 A Breakpoint
represent a "runnable" line of code (i.e. you have placed the breakpoint on a line that contains no code, or a comment).





Figure 14 A Breakpoint set on an Unreachable Line

Having placed a basic breakpoint in this way, the program will execute as normal if you run it in from within Delphi, until it reaches the line with the breakpoint set, and then the program will automatically hit the pause button, and wait for you to dictate what happens next.

NOTE - Breakpoints are not stored and do not constitute a part of the program, they constitute a setting of the IDE for the specific project into which they are placed, and hence have no effect whatsoever on a program if it is running outside of the IDE.

Delphi does not automatically switch across to the code window when it hits a breakpoint, which can be confusing (the application suddenly becomes unresponsive for no apparent reason), but it does highlight its own start bar panel in a different colour to indicate that it needs attention.

One final warning about Breakpoints... I have yet to uncover the exact circumstances under which it can occur, but on one particular shared project in which I have been in volved, the development team has on occasion found that the code consistently stops at a "phantom" breakpoint. (I believe that this is because somehow, someone copied an .OPT or a .CFG file from one machine to another, and confused the IDE in the process). These "phantom" breakpoints can be removed by calling up the breakpoint list, and removing all items from the list.

The breakpoint list (which can be accessed by selecting View, Debug windows, Breakpoints, or Ctrl-Alt-B) also allows the programmer to set conditions on breakpoints. For example - Stop on this line when the loop control variable reaches 16 - A real time saving feature, if you have a problem that only exposes itself on the 20,000th iteration of a loop. Using the breakpoint list dialog, it is also possible








Figure 15 The Breakpoint List

for the developer to set a breakpoint that is not tied to any particular line of code, but to an event like a the value of a variable being changed. This can be extremely valuable if you have a value which should be invariant, but is actually changing unexpectedly. We leave it as an exercise in experimentation to find out how this is done.

Once the program has paused, you will probably want to set about tracing line by line through the code as described in the previous section. Following the execution of the code, however, is only part of the story, what you really want to know as a developer is what the variables and properties of your objects and components contain. Delphi provides various methods of gaining this information.

The Watch Window

The most useful of these devices is the watch window. This can be called upon by selecting
View, Debug Windows, Watch Window (or alternatively using the shortcut keystroke Ctrl-Alt-W). The watch window allows the developer to type nearly any expression (including function calls on variables), and the IDE will evaluate each entry every time the program comes to a stop (i.e. every time you press the F7 key to step through the program). This means that you can watch not only the progress of the code, but also its effect on the variables and properties that comprise your application.






















To insert an item into the watch window, call it up as described, and press the insert key (or right click and select "Add Watch", or highlight an empty slot, and press enter). This will present a dialog box, with a space to type in the thing you want to "Watch". There are various options that allow you to change the way in which the data is displayed, however, Delphi is very good at presenting the information that you want in a readable format, and it is rarely necessary to deviate from the default. As an alternative, Delphi provides the facility to add a watch by selecting the item you wish to watch in the text editor, and right clicking on it. The menu that results contains the option Debug, with a submenu that includes the option "Add Watch at Cursor". (This has a shortcut key of F5)

Delphi provides another useful feature, which in some cases can save you the effort of calling up the watch window and adding an item to it. By placing the mouse cursor over a variable in the code while the program is stopped, the IDE will after a short pause display a hint, containing the value of the "thing" over which the mouse cursor is resting.

Local Watches

Delphi also provides a second form of Watch window, which collects and automatically displays all of the variables that are local to the procedure or function that is currently being executed. This can be displayed by selecting from the menus View, Debug Windows, Local Variables (or alternatively Ctrl-Alt-L).

Because it requires a lot of work to keep each individual watch updated, having a lot of them on display at one time can slow down stepwise execution of the code quite noticeably. It is therefore a good idea to try and limit the number of watches that you have at one time.

There is no particular limit to what you can look at with the watch window. As stated earlier, it is able to evaluate expressions, as well as to display the current contents of a simple variable. It can also display arrays of data, and the contents of complex record structures. The only thing it has problems with is Objects, which it can only show individual fields of upon request.
One final limitation which you will notice whilst using the watch window, is that it will often display a message about optimisation, rather than the value you were hoping to see. This is because Delphi optimises variables out of the code until they are absolutely needed, and then removes them again as soon as they have served their purpose. It is possible to turn off compiler optimisation, which alleviates this problem.

The CPU window

For those developers who have experience in programming in Assembler, it is possible to get Delphi to display a view of the CPU, and to trace through the source code at the assembly language level, rather than at the source code level (multiple assembly language instructions will in general result from any individual Pascal source code instruction). The CPU window can be called upon by selecting View, Debug Windows, CPU (Ctrl-Alt-C).













Figure 16 The CPU Window

This view shows the contents of the CPU registers, the assembly language instruction that is about to be executed, and a "load of other stuff I don't pretend to understand". It's fascinating to look at, but unless you have experience of Assembly language, an inner knowledge of the Intel CPU architecture, and endless patience, and an intractable coding bug to sort out, you are unlikely to find it especially useful.

The Call Stack Window

Rather more useful than the CPU window, is the Call Stack Window. This facility allows you to answer the often asked question "How the **** did it get in here!?"... You know that sinking feeling when you realise a procedure that you never expected to be called "here", is suddenly found to be running. By bringing up the call stack, you can find out the path of nested procedure ca lls that brought the execution point to its current location.














Figure 17 The Call Stack Window
Note that as with the other debug windows, it is only updated when the code is "stopped", so you will probably have to place a breakpoint to make use of the facility properly. Delphi goes one better than simply displaying the call stack, it is in fact an active list, and clicking on any one item in the list, will jump you in the code window to the calling point in the "previous" procedure. The call stack will also give you an indication of the parameters that were passed at the time of the call. This facility is particularly useful in the context of an event driven program, where quite often you can find yourself asking the question with the expletive in it above.

Thread Window


When you begin writing more advanced applications, you may find it advantageous to make use of one of the new features of the 32 bit Windows Operating System - namely support for threads. If you haven't used threads, or come across them before, then you have never used one of the latest versions of Word. Word employs threads extensively, but most noticeably to spell check as you type. A thread is an extra "independent front of execution" which exists in your code, and can be used to perform some useful background function, while your application continues to respond and react to user interaction. Word uses threads, not only for the spell checking feature, but also for the grammar checker, for the auto-save function, for the display of images embedded in the text, and doubtless a host of less obvious purposes.








Figure 18 The Thread Status Window

Threads are useful because the amount of processor time they use (their priority) can be set by the developer, and can even be changed whilst they are executing. On the downside, they can, if programmed incorrectly, lead to some "surprising" effects and some hard to track bugs. The Thread Window (View, Debug Windows, Threads or Ctrl-Alt-T) displays the threads that are running at any one time, with some additional information about the state of the thread.
That Completes our brief tour of the debugging facilities available to the Delphi programmer. There is more to it than described here, but the most important features have all been covered, and for your first foray in to Delphi programming, you should find that you now have as much information as you need.
In the next section we will look at some of the labour saving devices built in to the IDE, and we will take a brief tour around some of the more important settings that the IDE provides for the programmer.




Home | Services | Events | Features | Interviews | Profiles | Reviews | News | Resources | Press | Archive
About ITWales | Privacy Policy

All material on this website ©2002-2008 ITWales
spacer

Search ITWales

Advanced Search
envelope Subscribe to
ITWales Updates
Click Here!