Who needs a debugger anyway?
If you met someone in a bar, say, and you got talking, they are likely to ask what you do. You will probably reply that you are an embedded software developer. [Actually, in my experience, this can be a bit of a conversation killer. You might be better saying you are an airline pilot or a brain surgeon.] If they carry on talking with you, they might ask you what that job entails and you would probably answer with something about designing software and writing C/C++ code. Of course, that is not really the case. Most embedded software developers spend the bulk of their time debugging.
This does beg the question: what does debugging actually mean? The answer is less simple than you might expect …
Many years ago, when computers were big and expensive, there were no debugging tools that we would recognize today. Frankly, programmers made less errors. One reason for this was that time on the computer was precious, so the programmer would write the code down on paper first, thinking it through very thoroughly. They would very carefully proof read to avoid syntax errors, as just one slip could waste a computer run. Then they would think through the operation of the code, dry running it on paper to check the logic. Eventually, this carefully scrutinized code would be submitted to the computer. After the run, the results would be studied and, if an error was detected, the code would be modified to include extra printf() [or equivalent] lines to show how values were changing. By using conditional compilation, “debug” and “production” versions of code could be compiled.
So, why not take this approach when writing embedded software today? The first part – writing the code on paper and thinking a lot – might be a very good practice. However, the ready access to computers that cost almost nothing has moved us away from such an approach. The practice of adding printf() calls to log values is still amazingly common, despite it being quite problematic for embedded applications. There are five key issues:
- Most implementations of printf() are quite large. The function needs to address a very wide range of formatting situations and that takes a lot of code. This does not matter in a desktop software context, but memory is rarely in abundance in an embedded system.
- There is the question of where the output of printf() actually goes. Many embedded systems have nothing that looks like a “console” and directing output back to a host computer can be challenging.
- In a multi-threading context – i.e. when using an RTOS – reentrancy is a concern. If two threads try to use printf() at the same time, confusion can result.
- Every time you want to change the variables you are looking at, a complete rebuild and download of the code is required.
- Lastly, of course, formatting and sending the output [somewhere] takes time. If it is a real time application, this overhead can introduce problems.
So, for most systems, using printf() as a debug tool is not viable. Much better is to attach a debugger to the target system using JTAG. This can give ready access to all the target data and addresses the five issues thus:
- There is no extra code on the target.
- Data is displayed on the host computer without effort.
- The debugger needs to be task-aware, but that is well understood.
- Code only needs to be rebuilt to fix bugs.
- A JTAG connection is not totally non-intrusive in the time domain, but the impact is typically quite small.
I am left wondering whether, if developers were rationed in their computer access and, hence, required to write out all code by hand and do some thinking, would better code result and debug time be reduced?
[With thanks to my colleague Rizwan Rasheed, who suggested this topic.]
Comments
Leave a Reply
You must be logged in to post a comment.
As the JTAG is one good way of debugging, sometime it may not be feasible to afford due to cost factor. The other way would be to take complete RAM dump and analyse those dumps offline to verify the system behaviour.
If we have enough memory, other option would be to enable the important logs and save them in the RAM buffer and which can be extracted from the RAM dumps later.
This is fair comment Mallikarjun. In years gone by, “core dumps” were a very common debug tool and the analysis of such data [“dump cracking”] was a specialist and sought-after skill. My question would be: how do you get the data out of the RAM? Also, how do you stop execution in order to do so? If you have some alternate means to attach a debugger [serial, Ethernet etc.] that might be an option, but, in that case, more conventional debugging techniques would be available. It would be unusual for a JTAG interface to be cost prohibited, as it only requires a very cheap connector and even that only needs to be fitted to boards that will be used for debug.
I prefer thinking to doing, therefore I hate debugging. Coding, of course, is a necessity, even for me. The result of my preference is that I go over and over my design and coding – to the frustration of those who confuse overt activity with productivity – and have to spend very little time debugging it. In fact a debugger to me is actually a learning tool doubling up as a first-stage informal verifier; I do not expect to find bugs and feel chastened when I do.
For a course which I am writing, I’m thinking of using mbed. One of the reasons for this is that there is no easy way, as yet, to debug mbed code compiled and built online! This is a contrarian view but, if I’m teaching design and programming, I want people to do it properly and the relatively simple exercises used on courses should be fixable upon careful inspection, with minimal clues from the run-time behaviour.
When there is real need for a debugger, the need is usually for a good debugger, so I always appreciate having one around. But, yes, I do think that we would write better code if we thought more about it before and during the writing and placed less reliance on tools to find the mistakes we should not have made.
Peter – I think you and I are of a like mind. I recall, many years ago, being told off for not doing anything. I was sitting at my desk thinking, but because I had no tangible evidence [noise, paper etc.] of activity, it was assume that I was doing nothing. However, I must quote myself from a previous posting: “Sometimes I sits and thinks. Other times I just sits.”