Debugging Basics: The Call Stack

Every now and again someone will ask why they’re seeing a certain exception in their Delphi code in the Borland newsgroups, and I’ll frequently ask for a call stack so that I can give them a more accurate answer. I’m surprised at how often the response is, "How do I do that?" since to me the call stack is probably the debugging tool I use most frequently. So here is a short introduction to using the call stack.

What Is the Call Stack?

The call stack window is a list of functions and procedures in the inverse order in which they were called. Imagine you have a procedure called DoSomething and three different procedures which call it named Proc1, Proc2, and Proc3. If DoSomething takes an argument and you have an exception inside of DoSomething because the argument which was passed was nil, wouldn’t it be useful to know which of the three procedures is passing nil to DoSomething? That’s the sort of thing the call stack can help with. Imagine that Proc2 was incorrectly passing nil to DoSomething. When the debugger stops inside of DoSomething, viewing the call stack will show DoSomething on the top of the stack with Proc2 immediately below it. Hence you can easily tell which of the three procedures is causing the bug, even though the bug itself is in a different procedure than the one in which the debugger stops.

Call Stack Window Features

That by itself is useful, but there’s more. Look closely at the call stack window in the IDE and you can see that it shows you not only the names of the methods but the arguments passed as well.

Also, if you double-click on the methods in the call stack the debugger will take you to the approximate place where the method called the next higher method on the stack.

Why Don’t Some Procedures Show In the Call Stack?

In Delphi 7 you can only see procedures in the call stack for which there is debug information. So if you have compiled components without debug information or have not checked "Use debug DCUs" in Project->Options->Compiler->Debug, then there will be parts of the code — component internals and the Delphi VCL/RTL, respectively — which will not appear in the call stack. In Delphi 2005 and 2006 the call stack window has been enhanced to try and derive useful call stack information even when no debug symbols are present.

Alternatives to the IDE’s Call Stack Window

There are several third-party tools which can also help with call stack debugging in different ways than what the IDE offers. Debugging extensions such as the JCL’s debugging helpers can produce useful call stacks at runtime, making it possible to debug problems experienced by your customers which you are unable to reproduce yourself. There are commercial products which add additional bells and whistles, but I’m personally happy with what the JCL offers.

Also, AutomatedQA’s AQTime profiler has a couple of call-stack related features. Static analysis can show you which routines could potentially call each other without even running the application. Their performance profiler, on the other hand, tracks how many times routines in fact called each other over the course of executing an application. Both are useful.