When I create a project with CodeWarrior for MCU using Processor Expert and S08GB60, I’m asked if I want to have a Debug and/or Release configuration:
Debug or Release? For an embedded microcontroller? Does this make any sense?
Debug and Release in the Desktop World
In the Desktop World, ‘Debug’ and ‘Release’ builds have following typical meaning:
- Debug builds have debugging and symbolic information included. The compiler is not optimizing to make debugging ‘easier’.
- Release builds have the debugging and symbolic information (Dwarf in ELF/Dwarf files) stripped off. Optimizations are enabled for best performance or code density.
So the idea is that you have something easy to develop and debug. And once everything works, you create the optimized Release version and ship. That makes much sense, especially as the binary file size is greatly reduced with the debug information stripped off. Additionally loading that file is faster too, as smaller in size. So a lot of good reasons to create a Release version.
The problems start if it works in the Debug version, and everything crumbles to dust in the Release one (see Surviving the Release Version).
To the end: Debug and Release versions make sense because of the binary file size. If you are not debugging, you do not need the debug information with the binary loaded.
Debug and Release in the Embedded World
Embedded Debugging is different: If you debug your application, then the debug information remains on the host, while only the code gets downloaded to the target. The debug information is not loaded into the target memory. This means that advantage of a release version does not exist here.
Oh, wait: there might be still good reasons.
- Bootloader: If I’m using a loader on the target which can load other applications, then having stripped of the debug information reduces the file size. That way I can load files faster.
- Embedded Linux: If my application loads libraries or executables, then having the debug information removed saves loading time and space in RAM.
- Making Reverse Engineering harder: removing the debug information pretty much means decoding and debugging things on assembly level. That makes reverse engineering harder. But only harder, but does not prevent it. So I see little value in this use case.
Debug Information (Symbolics)
How to remove the debug information? Typically the linker and/or the compiler offer an option to either remove the information or not to generate it:
And what about the other aspect: the compiler optimizations? Does ‘Debug’ not mean that the compiler optimizations are disabled so I still can debug? And that it is not possible to debug optimized code?
My thinking is: I use and debug with the compiler options I intend to release the software. I don’t want to be in the situation that I have two different versions of my applications. This not only increases the efforts, but as well the risks. What if one works, but not the other? So I set the compiler optimizations to the level I want them, and use that for the development and for the release.
But then someone might say “oh, but you cannot debug optimized code”. I might need to inspect the registers or the assembly code to see what is really going on. But (normally) this is not the fault of the debugger, but of the compiler. The ELF/Dwarf object and debug format is sophisticated enough, that it allows to describe information for highly optimized code. So compilers could (!) generate debugging information for highly optimized code, if they just would do it . From my previous life as a compiler engineer I know it is hard work to keep the right debugging information through all the optimization stages, but it is possible. And it is hard work. It is good that compilers are optimizing for code size and code speed, but a compiler which does not produce the correct debugging information for highly optimized code is simply not state of the art any more. There are a lot of ‘ease-of-use’ efforts going on in the industry, but I think this needs to start as well in the compilers to produce correct debugging information to make highly optimized code easier to use.
- For Embedded (with the exception of things like Embedded Linux) ‘Debug’ or ‘Release’ versions do not make sense.
- I debug with the same compiler options as I will deliver my project at the end. That way I do not need to keep two different set of options or binaries, and I’m debugging what I’m getting at the end.
- It should be possible to debug highly optimized code. In my experience it is just the compiler (and rarely the debugger) which fails to do it correctly. I wish compilers would get better in producing the correct debugging information.
PS: if you are wondering what is the difference between the ‘Release’ and ‘Debug’ Processor Expert configuration as shown for the S08GB60A at the beginning of this post: In the ‘Release’ configuration the debug port will be disabled in the microcontroller configuration using a configuration register. That register will be written during startup of the processor. You will not be able to debug the device after that point .