Non-intrusive debug

Debugging represents a very significant part of an embedded software development project. All developers have their own favorite approaches and each one has its strengths and weaknesses. A key issue is how intrusive the debug tools are - i.e. the extent to which debugging software affects the functionality of the code. This is not a black and white issue, as a number of factors and priorities need to be considered. This article outlines different approaches to debugging, from the perspective of intrusion, and also considers the implications with respect to code optimization.

What is intrusive debug?There are two parameters that characterize any piece of code: size and speed. In broad terms, intrusive debug may be anything that affects either of these factors.

A number common debug techniques involve the incorporation of additional code into the application, the sole function of which is to facilitate debug. This affects the overall memory footprint and may have an effect on the execution time of the application code. There may also be unexpected side-effects caused by the use of this code.

If a system has plenty of memory – over and above the needs of the application code – the inclusion of extra debug software should not be a problem. However, many embedded systems are designed to have enough memory, but only just enough, and there is no provision for adding more just during debug time. Under these circumstances, the additional memory hit would be very problematic.

An example of an intrusive debug technique, that is very widely used and exhibits this issue, is the temporary addition of printf() calls to to track the path through some code. Such instrumented code might look something like this:

The entire application needs to be rebuilt every time you want to change the debug setup.

The printf() function needs to send its output somewhere. Figuring out where to send the text to and setting up the library function to do this may be challenging.

This function is quite large, as it has way more functionality than required for debugging. Unless the application code uses printf() (which is unlikely), inclusion of the library function will have a drastic effect on the memory footprint.

Many library functions are non-reentrant and their use in a multithreaded system may be problematic.

Some of these problems may be addressed by using custom functions, written specifically for doing debug and designed to be small and simple. A possible set might be:

The intrusion into embedded code’s execution performance – i.e. how fast it runs – can be even more of a problem than memory footprint, as its effect may be much subtler. Outputting “trace” data, as shown in the above example, takes time and that execution time may be significant.

Another situation when execution time may be adversely affected is when using an RTOS. Ironically, although such an operating system is intended to help the developer build real time applications, the built-in (normally optional) debug facilities, whilst very useful in some situations, may affect the real time execution profile. In other words, the code might run differently (from a time perspective) depending on whether the debug facility is activated or not. This is, by definition, intrusion.

When does intrusion not matter?Given that sufficient memory is available, a debug technology that increases the image size is unlikely to affect the execution of the application code by that fact alone. The only intrusion will be on the execution performance. So, time-critical (i.e. real time) code is the most sensitive. Code with no particular time constraints – pure logic/algorithms – will be unaffected. Hence, the intrusion level of debug does not matter at all when checking out code logic.