buildid/
lib.rs

1//! Examine the build-id and similar values for your library or executable
2//!
3//! ```
4//! println!("{:?}", buildid::build_id())
5//! ```
6//!
7//! build-id is a value which is guaranteed to change when any of the component objects of a binary
8//! change. A change in the build-id does not guarantee that the executable or it's components are
9//! actually different. Two distinct executables may have a different build-id if they were
10//! modified after linking (for example, by `chrpath` or similar).
11//!
12//! build-id is intended to be sufficient to identify the appropriate debug information to use for
13//! a given object, and is used for this purpose by `gdb` and other debuggers.
14//!
15//! build-id is also used by `mesa` as a key component in their caching of shaders (changes in the
16//! build-id cause the cache to be discarded).
17//!
18//! Executables and shared objects contain build-ids. Using `buildid::build_id()` will return the
19//! build-id for the object that includes `buildid` (this crate). For example, if you write a
20//! shared object (shared library) using this crate, and provide a way to get the build-id in it's
21//! external API, that call will return the build-id of the shared object/library (not the
22//! executable).
23//!
24//! By default, the `buildid` crate will pick the best build-id lookup function it can for your
25//! platform. If one is not available, it may fail to compile. If you have a custom build-id lookup
26//! mechanism you want to tell `buildid` about, enabling one of the features may help.
27//!
28//! # Optional Features
29//!
30//! For all of the build-id lookup customization features, we recommend only setting them in
31//! top-level crates than have a complete understanding of the final link step for the executable.
32//!
33//! ## `buildid-symbol-start-end`
34//!
35//! When enabled, assume the presence of 2 symbols named "__build_id_start" and "__build_id_end", and
36//! use these to find the build-id. For gnu linkers, these symbols exist and can be used
37//! automatically.
38//!
39//! If they aren't present for some reason, one can provide the symbols by using a custom
40//! ldscript (linker script). See `buildid-linker-symbols` for a linker script mechanism to provide
41//! these.
42//!
43//! This method takes precedence over automatically enable build-id
44//! lookup methods, and over `buildid-section-inject`.
45//!
46//! ## `buildid-custom-inject`
47//!
48//! When enabled, assume that a function `int build_id__get(unsigned char **build_id, size_t *len)`
49//! is provided (with C linkage) that can locate and return the build-id. The `build_id__get` must
50//! return `1` if a build-id is located (and modify the `build_id` and `len` arguments to point to
51//! the memory containing the build-id and to contain the number of bytes in the build-id
52//! respectively), return `0` if no build-id exists, and return a negative error code if an
53//! unexpected error occurred. This method takes precedence over all other build-id lookup methods
54//! (if enabled).
55//!
56//! ## `buildid-section-inject`
57//!
58//! When enabled, inject our own symbol into the section where build id is expected to be located,
59//! and use the build-time environment variable `BUILD_ID_SIZE` to determine how many bytes to
60//! read. This method will only function on some platforms (basically: GNU ones). Note that
61//! `BUILD_ID_SIZE` must be set correctly, and differs for GNU ld (bfd) and LLVM lld.
62//!
63//! Note that in all cases this works, `buildid-symbol-start-end` is likely to work and be more
64//! reliable.
65//!
66//! This method takes precedence over the default lookup methods if enabled.
67//!
68//! ## `buildid-linker-symbols`
69//!
70//! When enabled, depend on the `buildid-linker-symbols` crate to automatically create the symbols
71//! needed by `buildid-symbol-start-end` on gnu-like linkers.
72//!
73//! # Platform Details
74//!
75//!  - On unix variants other than those with apple as the vendor, the `.note.gnu.build-id` is
76//!    used. Note that GNU LD and LLD generate different sized build-ids using different hash
77//!    functions. Unless additional features are enabled, the `.note.gnu.build-id` is located via
78//!    `dl_iterate_phdr()`.
79//!  - On Apple unix variants (MacOS), the `LC_UUID` (loader command uuid) is returned directly as
80//!    a slice.
81//!  - On windows, the module is parsed for a CodeView descriptor containing a GUID (which is
82//!    returned directly as a slice). If mingw is used, the same info will appear in the `.buildid`
83//!    section, but this lookup method is not used by this library.
84//!  - On wasm, no data is provided
85//!
86//! # Ensuring build-id is enabled
87//!
88//!  - On windows when using mingw, build-id may not be enabled by default. To enable, set
89//!    RUSTFLAGS="-Clink-args=-Wl,--build-id" in the environment before running cargo. The same
90//!    argument works for any system using GNU LD or compatible.
91//!
92//!  - On most linux platforms, build-id is enabled by default by gcc. Sometimes clang on the same
93//!    platform does not have build-id enabled though. Set `RUSTFLAGS="-Clink-args=-Wl,--build-id"`
94//!    to ensure build id is enabled for clang or gcc
95//!
96//!  - MacOS appears to enable build-id (LC_UUID) by default, with no change needed.
97//!  - Windows MSVC appears to enable build-id (CodeView GUID) by default, with no change needed.
98#![no_std]
99
100#[cfg(test)]
101extern crate alloc;
102
103cfg_if::cfg_if! {
104    if #[cfg(all(test,
105            not(all(
106                target_family = "unix",
107                not(target_vendor = "apple"),
108            ))
109        ))] {
110        mod align;
111    }
112}
113
114cfg_if::cfg_if! {
115    if #[cfg(any(test,
116            all(
117                not(feature = "buildid-custom-inject"),
118                feature = "buildid-section-inject")
119            )
120        )] {
121        mod constparse;
122    }
123}
124
125cfg_if::cfg_if! {
126
127    if #[cfg(feature = "buildid-custom-inject")] {
128        #[path = "custom-inject.rs"]
129        mod target;
130    } else if  #[cfg(feature = "buildid-section-inject")] {
131        #[path = "section-inject.rs"]
132        mod target;
133    } else if #[cfg(feature = "buildid-symbol-start-end")] {
134        #[path = "symbol-start-end.rs"]
135        mod target;
136    } else if #[cfg(all(
137        target_family = "unix",
138        not(target_vendor = "apple"),
139    ))] {
140        #[path = "elf.rs"]
141        mod target;
142        mod align;
143    } else if #[cfg(all(
144        target_family = "unix",
145        target_vendor = "apple",
146    ))] {
147        #[path = "mach.rs"]
148        mod target;
149    } else if #[cfg(target_family = "windows")] {
150        #[path = "windows.rs"]
151        mod target;
152    } else if #[cfg(target_family = "wasm")] {
153        mod target {
154            pub fn build_id() -> Option<&'static [u8]> {
155                // not sure how to implement this right now. need to introspect the wasm object in some way
156                None
157            }
158        }
159    }
160}
161
162/// If present, return the build-id or platform equivalent
163pub fn build_id() -> Option<&'static [u8]> {
164    target::build_id()
165}
166
167#[cfg(doctest)]
168mod test_readme {
169    #[doc = include_str!("../README.md")]
170    extern "C" {}
171}