pw_build_info#
Pigweed AI summary: The pw_build_info module provides tooling, build integration, and libraries for generating, embedding, and parsing build-related information that is embedded into binaries. It simplifies the process of integrating rich version metadata to answer more complex questions about compiled binaries. The GNU build IDs library provides C++ and python libraries for reading GNU build IDs generated by the link step of a C++ executable. This module also explains how to update the linker script to include a section to contain the generated build ID and how to generate
Warning
This module is incomplete, but the build ID integration is ready for use.
pw_build_info provides tooling, build integration, and libraries for generating, embedding, and parsing build-related information that is embedded into binaries. Simple numeric version numbering doesn’t typically express things like where the binary originated, what devices it’s compatible with, whether local changes were present when the binary was built, and more. pw_build_info simplifies the process of integrating rich version metadata to answer more complex questions about compiled binaries.
GNU build IDs#
Pigweed AI summary: The GNU build IDs module provides C++ and Python libraries for reading build IDs generated by the link step of a C++ executable. These build IDs are essentially hashes of the final linked binary, allowing for accurate identification of matching binaries. Linux executables can automatically generate GNU build IDs, but Windows and macOS binaries cannot. To generate GNU build IDs as part of a firmware image, the linker script must be updated to include a section named ".note.gnu.build-id". The module also includes Python utilities for parsing
This module provides C++ and python libraries for reading GNU build IDs generated by the link step of a C++ executable. These build IDs are essentially hashes of the final linked binary, meaning two identical binaries will have identical build IDs. This can be used to accurately identify matching binaries.
Linux executables that depend on the build_id
GN target will automatically
generate GNU build IDs. Windows and macOS binaries cannot use this target as
the implementation of GNU build IDs depends on the ELF file format.
A separate GN target build_id_or_noop
is available which provides an empty
build ID on platforms where GNU build ID is not available while still providing
a real GNU build ID where supported.
Getting started#
Pigweed AI summary: This document provides instructions for generating GNU build IDs as part of a firmware image. To do this, the embedded target's linker script must be updated to include a section named ".note.gnu.build-id" alongside the ".text" and ".rodata" sections. The document provides examples of how to update the linker script, including copying a linker snippet into a pre-existing section or directly inserting a build ID into an existing section. When depending on "$dir_pw_build_info:build_id", a GNU build
To generate GNU build IDs as part of your firmware image, you’ll need to update your embedded target’s linker script.
Updating your linker script#
Pigweed AI summary: To include a generated build ID in a custom linker script, a new section named ".note.gnu.build-id" should be added alongside ".text" and ".rodata". Alternatively, the build ID can be inserted into an existing section, but this may slow down reading the build ID. If the linker script is auto-generated, the "INSERT AFTER" directive can be used to append the build ID to the default linker script. An example of how to directly insert the build ID into an existing section and
If your project has a custom linker scipt, you’ll need to update it to include
a section to contain the generated build ID. This section should be placed
alongside the .text
and .rodata
sections, and named
.note.gnu.build-id
.
/* Main executable code. */
.code : ALIGN(4)
{
. = ALIGN(4);
/* Application code. */
*(.text)
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
...
} >FLASH
/* GNU build ID section. */
.note.gnu.build-id :
{
. = ALIGN(4);
gnu_build_id_begin = .;
*(.note.gnu.build-id);
} >FLASH
/* Explicitly initialized global and static data. (.data) */
.static_init_ram : ALIGN(4)
{
*(.data)
*(.data*)
...
} >RAM AT> FLASH
Alternatively, you can copy the following linker snippet into a pre-existing section. This makes reading the build ID slower, so whenever possibe prefer creating a dedicated section for the build ID.
/*
* Copyright 2021 The Pigweed Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/* Include this linker snippet in a section of your linker script that specifies
* where .rodata or .text will live in flash.
*/
. = ALIGN(4);
gnu_build_id_begin = .;
*(.note.gnu.build-id);
An example of directly inserting a build ID into an existing section is provided below:
/* Main executable code. */
.code : ALIGN(4)
{
. = ALIGN(4);
/* Application code. */
*(.text)
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
gnu_build_id_begin = .;
*(.note.gnu.build-id);
...
} >FLASH
If your linker script is auto-generated, you may be able to use the
INSERT AFTER
linker script directive to append the build ID as seen in the
Linux host support for pw_build_info’s build ID integration:
/*
* Copyright 2021 The Pigweed Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
SECTIONS
{
.note.gnu.build-id :
{
INCLUDE build_id_linker_snippet.ld
}
}
/*
* The INSERT directive instructs the linker to append the directives in this
* script to the default linker script, rather than replace the default with
* this script. The build ID is read only, so place it just after .rodata.
*/
INSERT AFTER .rodata
Generating the build ID#
Pigweed AI summary: This section explains that when using "$dir_pw_build_info:build_id" as a dependency, a GNU build ID will be generated during the final link step for any binaries that depend on that library. The build ID can be read by calling "pw::build_info::BuildId()", but it is not a string and must be converted to hex or base64 to be printed.
When you depend on "$dir_pw_build_info:build_id
, a GNU build ID will be
generated at the final link step of any binaries that depend on that library
(whether directly or transitively). Those binaries will be able to read the
build ID by calling pw::build_info::BuildId()
. Note that the build ID
is not a string, but raw binary data, so to print it you’ll need to convert
it to hex or base64.
Python API reference#
Pigweed AI summary: This is a Python API reference for functions related to reading GNU build IDs from ELF binaries. The functions include "read_build_id_from_section", "read_build_id_from_symbol", "read_build_id", and "find_matching_elf". These functions search for the build ID in different ways, such as searching for a specific section or symbol, and can be slow operations. The "find_matching_elf" function recursively searches a directory for an ELF file with a matching UUID.
- read_build_id_from_section(elf_file: BinaryIO) Optional[bytes] #
Reads a GNU build ID from an ELF binary by searching for a
.note.gnu.build-id
section.
- read_build_id_from_symbol(elf_file: BinaryIO) Optional[bytes] #
Reads a GNU build ID from an ELF binary by searching for a
gnu_build_id_begin
symbol. This can be a rather slow operation.
- read_build_id(elf_file: BinaryIO) Optional[bytes] #
Reads a GNU build ID from an ELF binary, first checking for a GNU build ID section and then falling back to search for a
gnu_build_id_begin
symbol.
- find_matching_elf(uuid: bytes, search_dir: Path) Optional[Path] #
Recursively searches a directory for an ELF file with a matching UUID.
Warning: This can take on the order of several seconds.
Python utility#
Pigweed AI summary: The Python utility tool called "build_id" can extract GNU build IDs from ELF files. By running the tool on a binary with a GNU build ID, the build ID will be printed out if it is found. An example command to use the tool is shown.
GNU build IDs can be parsed out of ELF files using the build_id
python tool.
Simply point the tool to a binary with a GNU build ID and the build ID will be
printed out if it is found.
$ python -m pw_build_info.build_id my_device_image.elf
d43cce74f18522052f77a1fa3fb7a25fe33f40dd