1. Today's topic

We learn to establish:

text
which firmware is running;
which commit it was built from;
which toolchain was used;
which sdkconfig was used;
the binary's SHA-256;
which ELF is required for the coredump.

The main idea: version=1.8.0 is not enough. Complete firmware identity consists of source, configuration, dependencies, toolchain and the hash of the specific artifact.

2. Why this matters

For postmortem analysis, an address cannot be symbolicated based on the version alone:

text
version=1.8.0
PC=0x40091a42

The same version may have been built with different sdkconfig, stack sizes, patches and component versions. You need:

c
Git commit;
dirty state;
ESP-IDF version;
sdkconfig hash;
dependencies.lock hash;
ELF SHA-256;
firmware.bin SHA-256.

For EC25, complete device identity also includes:

c
EC25 firmware;
MBN profile;
hardware revision;
config generation.

3. Theory

Version, build identity, reproducibility, authenticity

  • Version: 1.8.0 — convenient for a person.
  • Build identity: commit, configuration, dependencies and toolchain.
  • Reproducibility: two independent builds produce identical bytes.
  • Authenticity: the release manifest is signed with a trusted key.

A Git commit is not enough

If the working tree is dirty, the commit does not describe the binary. A release must require:

text
git_dirty=false

ESP-IDF reproducible build

In sdkconfig.defaults:

text
CONFIG_APP_REPRODUCIBLE_BUILD=y

Do not use:

text
__DATE__
__TIME__

Toolchain pinning

Poor approach:

text
image: espressif/idf:latest

Better approach:

text
image: espressif/idf:v6.0.2@sha256:<digest>

esp_app_desc_t

ESP-IDF includes esp_app_desc_t in the image:

c
project name;
version;
ESP-IDF version;
secure version;
app_elf_sha256.

The runtime CLI version command must display these fields.

Release manifest

The manifest links:

text
source -> environment -> configuration -> artifacts -> validation

Example fields:

c
{
  "project": "traffic-controller",
  "version": "1.8.0",
  "git_commit": "9ac04be12f91",
  "dirty": false,
  "idf": "v6.0.2",
  "sdkconfig_sha256": "...",
  "app_bin_sha256": "...",
  "app_elf_sha256": "...",
  "hil_result": "passed"
}

Do not try to embed the binary's SHA-256 inside the binary itself: that is a self-reference. Store the final binary's hash in an external manifest.

STM32

For STM32, preserve:

c
firmware.elf;
firmware.map;
firmware.hex/bin;
.ioc;
startup;
linker script;
HAL/LL/CMSIS versions;
STM32CubeMX version;
compiler version;
build flags.

It is better to keep generated code in Git and check in CI that regenerating the .ioc produces no diff.

4. Common mistakes

  • The version contains only 1.8.0.
  • The release is built from a dirty tree.
  • Using __DATE__/__TIME__.
  • CI uses latest.
  • Managed components are not pinned.
  • The .bin is saved, but the .elf is deleted.
  • An ELF from a different build is used for a coredump.
  • sdkconfig is not preserved.
  • STM32 .ioc and CubeMX version are not preserved.
  • Production rebuilds firmware locally instead of using the CI artifact.

5. A practical task for 30–60 minutes

Create RELEASE_POLICY.md:

markdown
# Firmware release policy
1. Release builds are created only by CI.
2. Release source trees must be clean.
3. Every release has a semantic version and Git commit.
4. ESP-IDF and toolchain are pinned by container digest.
5. sdkconfig and dependency lock are archived.
6. Reproducible build mode is enabled.
7. Application ELF and BIN must reproduce bit-for-bit.
8. ELF, map, binaries and flash metadata are retained.
9. All artifacts have SHA-256 hashes.
10. Release manifest is signed.
11. Production flashes only immutable release artifacts.
12. Field diagnostics report firmware and modem identities.

Check two builds in different directories:

text
cmp /tmp/repro-a/build/traffic_controller.bin /tmp/repro-b/build/traffic_controller.bin
cmp /tmp/repro-a/build/traffic_controller.elf /tmp/repro-b/build/traffic_controller.elf

Assemble a release bundle:

text
.bin
.elf
.map
bootloader.bin
partition-table.bin
partition CSV
flasher_args.json
sdkconfig
dependencies.lock
version.txt
manifest
HIL report

6. What to read or try next

  • ESP-IDF Reproducible Builds.
  • esp_app_desc_t and App Image Format.
  • IDF Component Manager dependencies.lock.
  • STM32CubeMX command-line generation and user code sections.
Two firmware files both report version 1.8.0, but were built with different sdkconfig. What can you conclude?

Criteria: Use complete build identity rather than a version label alone.

Exercise

Review a release bundle containing only firmware.bin and version.txt. Name the evidence missing for reproducibility and postmortem analysis, without rebuilding anything.

Self-check criteria: Distinguish saved artifacts from demonstrated reproducibility. Keep the binary hash external to avoid self-reference.

Show the supplied answer

Preserve the exact ELF, configuration/sdkconfig and dependency lock, source commit and clean-tree status, pinned toolchain, relevant map/flash metadata, artifact SHA-256 values and the external release manifest. Reproducibility is checked with independent builds, not inferred from version.txt.