Set up an embedded / firmware project¶
Embedded projects break the assumptions a desktop project makes: the compiler is a cross-compiler
inside a proprietary IDE, there may be no compile_commands.json, headers come from a vendor SDK and
define hardware registers, and some source is hand-written assembly. This guide gets Understand to an
accurate analysis anyway.
What's different about embedded¶
- Cross-compiler + vendor IDE — the build runs under an embedded toolchain, not plain
gcc. - Vendor / register headers — correct include paths and predefined macros matter more, because
the wrong
#ifdefbranch leaves whole drivers as inactive code. - Often no standard build export — many embedded IDEs don't emit a compilation database.
- Assembly — startup code, ISRs, and hot loops are frequently
.asm/.s.
1. Give Understand the real include & macro set¶
Accuracy in Strict (Clang) mode depends on matching how the firmware is compiled. In order of preference:
- Import a compilation database if your toolchain can emit one —
und add -cmake compile_commands.json. - Capture the build with Buildspy/Build Watcher — it works with any gcc-like compiler, and
you can point the wrappers at a cross-compiler with
-cc/-cxxor theUND_PBCCCOMPILER/UND_PBCXXCOMPILERenvironment variables. See Build Watcher vs Buildspy. - Set includes and macros by hand when neither is possible — add the vendor SDK include
directories and the toolchain's predefined macros with the
-C++Includes,-C++SystemIncludes, and-C++Macrossettings (or Project → Improve Project Accuracy). Your compiler can usually dump its predefined macros (e.g. gcc-like:-dM -E), which you can feed in directly.
One target per project
Firmware often builds several images from shared sources with different macro sets. Analyze one
target/configuration per project so the active #ifdef branches match a real build — mixing
configurations produces contradictory parsing.
2. Know what happens to the assembly¶
Understand parses assembly for two assemblers only: Coldfire 68K and IBM (System/370 mainframe) —
selected per project under the Assembly language options. If your startup code and ISRs are written
for one of those targets, add the .asm/.s files and calls into and out of them appear; see the
Assembly notes in Per-language accuracy notes.
For any other architecture (ARM Cortex-M, RISC-V, Xtensa, DSP assembly, …) Understand does not parse the assembly, so references between C/C++ and those files won't resolve. The practical approach is to analyze the C/C++ side and treat the assembly boundary (vector table, startup, ISR entry points) as landmarks you locate by search instead.
3. Verify accuracy, then find the landmarks¶
Check Parse Accuracy on the Home dashboard and clear analysis errors first. Then orient yourself in the firmware the way most embedded teams do — locate the main loop, the state machine, and the interrupt handlers, and trace outward from them with the 10-minute tour and call graphs.
Where to next¶
- Create an accurate C/C++ project (Strict vs Fuzzy).
- Capture your build — Build Watcher vs Buildspy.
- Fix parse errors if entities are missing or duplicated.
- Analyze machine-generated code if part of the firmware is model-generated.
- Firmware often has a coding standard to meet — see Which coding standard should I check against?, safety-critical development, and the compliance guides for ISO 26262 and IEC 62304.