I'm always amazed at how little time some developers take to learn about debugging techniques and tools. While I agree that good planning and design, along with smart compilers, can reduce the number of bugs in a program, it doesn't eliminate them. Even using a programming environment like Java with its lack of pointer manipulation and garbage collection only protects a programmer so far. In fact, all of these tools typically protect programmers from simple bugs like null pointers. This leaves the very hard to find bugs that are often timing-dependent.
The latest crop of debuggers does a pretty good job of catching fatal errors. Some even handle more difficult problems like memory leakage properly. Unfortunately, many developers don't take advantage of more advanced techniques like memory monitoring because they're unaware of the feature or don't know how to employ it. Novice developers often resort to basic printf statements and utilize only simple breakpoints to find any kind of bug.
Debuggers with more powerful watch and breakpoints provide a better method for isolating problems, but it takes some effort to understand how these features work. It also requires practice to use the conditionals and scripting support to reduce the amount of information or the number of breaks that occur. The problem of information overload gets worse when using trace support.
Tracing support is critical to debugging real-time systems, especially those that interact with other systems. It is surprising how few people actually utilize tracing tools or specify them as part of their toolset. This is often due to lack of experience with tracing tools or experiences with poor implementations. In some cases, tracing tools incur significant overhead that can make them impractical. However, that has become less of a problem, as tool developers recognize the growing demand for good trace tools. Trace hardware is being built into processor cores. Trace buffers in the gigasample range are practical, and analysis tools are slowly but surely improving.
Although tracing tools are part of a good debugging toolset, they're not always found within a debugger. System trace tools, like LynuxWorks' SpyKer for Linux, are often available as standalone products that provide insight into a program's interaction with the operating system and other applications. Of course, integration with a debugger can be a real bonus. Take Green Hills Software's TimeMachine, for example. Details of events within a trace can be examined down to the source code that's displayed in the integrated development environment's editor.
Take a look at your current toolset and you might find it already has tracing capabilities. Many trace tools don't need hardware support, although the added overhead should be considered. Remember, not everything can be solved by using breakpoints.