Module Info
Embed build-time metadata (version, git commit, maintainer, OS) into your
Rust binary so it survives crashes. The data lives in an ELF
.note.package section, so when your process dies and dumps core, the metadata
travels with it. Tools like coredumpctl, readelf -n, and GDB see exactly
which build crashed, even if the binary has been redeployed or deleted.
Why module-info?
When a deployed binary crashes, the hardest question is often "which build was
this?" Symbol files get lost, tags drift, and the binary on disk may already be
gone. module-info answers it from the core dump alone:
- Survives the crash. The metadata is an ELF note baked into the image, so it is captured in the core dump even if the binary has been redeployed or deleted.
- Standard, tool-ready format. Follows the systemd package-metadata
spec,
so
coredumpctl,readelf -n, GDB, and existing crash-analysis tooling read it with no changes. - Auto-detected. Version, git branch/commit/repo, OS, and package details
are collected at build time from
Cargo.toml, git, and the OS. A typical setup needs three lines. - Build-time only. The note is written during the build, so carrying it
costs nothing at runtime. Reading the metadata back from inside the running
process is optional and lives behind the
embed-module-infofeature. - Executables and shared libraries. Both carry their own
.note.package. - Cross-platform safe. Compiles everywhere; it is a no-op on non-Linux targets, so the same source builds on Windows and macOS.
What gets embedded
A small JSON record in the binary's .note.package section, one key/value pair
per line and ASCII-only (see Limitations):
Reading it back needs no special tooling. On binutils 2.39+, readelf -n
decodes the note directly:
(The exact Data size depends on your field values.)
Quick start
1. Add the dependency.
Requires Rust 1.74 or newer.
2. Add a build.rs at your project root:
3. Embed the note by adding one macro at your crate root (src/main.rs or
src/lib.rs):
embed!;
That's it. Your binary now carries its metadata. Most fields are detected
automatically from Cargo.toml, git, and the OS. To set the maintainer and a
few extras, add this to Cargo.toml:
[]
= "team@contoso.com" # contact email or team UUID
= "agent" # optional
= "Contoso, Ltd." # optional
How the three pieces fit. The [build-dependencies] entry runs the build
script, which collects the metadata and tells the linker to add the
.note.package section. The [dependencies] entry plus the embed-module-info
feature anchor that section in the final binary and provide the runtime
read-back API. module_info::embed!() is that anchor; it expands to nothing on
non-Linux targets, so the same source builds everywhere. In a workspace, each
binary or shared library that should carry metadata needs its own build.rs
and embed!() call.
Read it back at runtime (optional)
use get_module_info;
if let Ok = get_module_info!
// Or grab everything as a HashMap:
if let Ok = get_module_info!
ModuleInfoField does not need importing: the get_module_info! macro matches
the variant name (e.g. ModuleInfoField::Version) as a token.
Runtime read-back is a convenience; the main feature is that the metadata is recoverable from a crash dump without it.
Platform support
- Linux: full functionality. Emits the
.note.packagesection at build time; runtime accessors read it back. - Windows / macOS / other: no-op. Nothing is embedded, build-script entry
points compile to empty stubs (so the same source builds everywhere), and the
runtime accessors return
ModuleInfoError::NotAvailable, so handle that in cross-platform code.
Verify it worked
.note.package is an allocated section, so it survives strip.
Reading metadata from a core dump
This is the payoff: because the note sits in the first read-only page, it is
captured in the core dump even when the binary is gone. A core has no section
headers, so pull a field straight out of the dumped bytes with strings:
|
Or use coredumpctl on systemd hosts. The full
guide has the full commands, and the
sample_crashing_process example exercises it end to end.
Limitations
- Linux/ELF only. On other targets embedding is a no-op (the build still
compiles) and the runtime accessors return
ModuleInfoError::NotAvailable. - GNU ld / gold linker. The note is placed with an
INSERT AFTERlinker script. Alternative linkers (lld,mold) may not honor it; if you use one, confirm the section is present withreadelf -n. - ASCII-only fields. Values are sanitized to printable ASCII.
©/®/™become(c)/(r)/(tm); all other non-ASCII (accents, curly quotes, CJK) is dropped, so prefer ASCII spellings at the source. - 1 KiB cap. The whole JSON record must fit in 1 KiB or the build fails
with
MetadataTooLarge. - Requires Rust 1.74+ and a Cargo
build.rscontext.
Learn more
The full guide covers everything beyond the basics:
- Metadata fields and configuration
- CI integration: wiring up build numbers from Azure Pipelines, GitHub Actions, etc.
- Custom
build.rs: supplying metadata programmatically and static-library flows - Disabling optional fields, cross-compilation, inspection, error handling, and security
API reference: docs.rs/module-info.
Changelog: CHANGELOG.md. Security policy: SECURITY.md.
License
This project is licensed under the MIT License. See LICENSE.txt for the full license text.
Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit Contributor License Agreements.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.