buildid/
lib.rs

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

#[cfg(test)]
extern crate alloc;

cfg_if::cfg_if! {
    if #[cfg(all(test,
            not(all(
                target_family = "unix",
                not(target_vendor = "apple"),
            ))
        ))] {
        mod align;
    }
}

cfg_if::cfg_if! {
    if #[cfg(any(test,
            all(
                not(feature = "buildid-custom-inject"),
                feature = "buildid-section-inject")
            )
        )] {
        mod constparse;
    }
}

cfg_if::cfg_if! {

    if #[cfg(feature = "buildid-custom-inject")] {
        #[path = "custom-inject.rs"]
        mod target;
    } else if  #[cfg(feature = "buildid-section-inject")] {
        #[path = "section-inject.rs"]
        mod target;
    } else if #[cfg(feature = "buildid-symbol-start-end")] {
        #[path = "symbol-start-end.rs"]
        mod target;
    } else if #[cfg(all(
        target_family = "unix",
        not(target_vendor = "apple"),
    ))] {
        #[path = "elf.rs"]
        mod target;
        mod align;
    } else if #[cfg(all(
        target_family = "unix",
        target_vendor = "apple",
    ))] {
        #[path = "mach.rs"]
        mod target;
    } else if #[cfg(target_family = "windows")] {
        #[path = "windows.rs"]
        mod target;
    } else if #[cfg(target_family = "wasm")] {
        mod target {
            pub fn build_id() -> Option<&'static [u8]> {
                // not sure how to implement this right now. need to introspect the wasm object in some way
                None
            }
        }
    }
}

/// If present, return the build-id or platform equivalent
pub fn build_id() -> Option<&'static [u8]> {
    target::build_id()
}

#[cfg(doctest)]
mod test_readme {
    #[doc = include_str!("../README.md")]
    extern "C" {}
}