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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! Reader, writer, and Linux ELF/DWARF converter for [LLVM GSYM], in safe Rust.
//!
//! GSYM maps an instruction address to a function name, a source file and line,
//! and the chain of inlined calls at that address. It stores nothing else, so a
//! GSYM file is far smaller than the DWARF it was built from, and its sorted
//! address index can be memory-mapped and queried without parsing the rest of
//! the file.
//!
//! This crate implements the format directly. It does not link LLVM, call
//! `llvm-gsymutil`, or depend on `BlazeSym`.
//!
//! # Quick start
//!
//! Build a file in memory and resolve an address:
//!
//! ```
//! use gsym::{AddressRange, FileEntry, Function, Gsym, GsymBuilder, LineEntry};
//!
//! let mut builder = GsymBuilder::new().base_address(0x4000);
//! let source = builder.add_file(FileEntry::new(b"src", b"main.rs"))?;
//! builder.add_function(Function {
//! lines: vec![LineEntry::new(0x4010, source, 12)],
//! ..Function::new(AddressRange::new(0x4010, 0x4020), b"example")
//! })?;
//! let bytes = builder.to_bytes()?;
//!
//! let gsym = Gsym::parse(&bytes)?;
//! let hit = gsym.lookup(0x4014)?.expect("address is covered");
//! assert_eq!(hit.frames()[0].name, b"example");
//! assert_eq!(hit.frames()[0].line, 12);
//! assert_eq!(hit.frames()[0].offset, 4);
//! # Ok::<(), gsym::Error>(())
//! ```
//!
//! Read a file written by this crate or by `llvm-gsymutil`:
//!
//! ```no_run
//! use gsym::Gsym;
//!
//! let gsym = Gsym::open("app.gsym")?;
//! if let Some(hit) = gsym.lookup(0x401120)? {
//! for frame in hit.frames() {
//! println!(
//! "{}{} at {}:{}",
//! String::from_utf8_lossy(frame.name),
//! if frame.inlined { " (inlined)" } else { "" },
//! String::from_utf8_lossy(frame.basename),
//! frame.line,
//! );
//! }
//! }
//! # Ok::<(), gsym::Error>(())
//! ```
//!
//! Build one from an executable's own DWARF (`convert` feature, on by default):
//!
//! ```no_run
//! # #[cfg(feature = "convert")]
//! # fn run() -> gsym::Result<()> {
//! use gsym::convert::ElfConverter;
//!
//! let report = ElfConverter::default().convert_path("./app")?;
//! std::fs::write("./app.gsym", report.builder.to_bytes()?)?;
//! # Ok(())
//! # }
//! ```
//!
//! # Choosing an entry point
//!
//! | To … | Use | Notes |
//! | --- | --- | --- |
//! | query a file on disk | [`Gsym::open`] | safe; reads one owned snapshot |
//! | query bytes you already hold | [`Gsym::parse`] | any `AsRef<[u8]>`, borrowed or owned, no copy |
//! | query a large file without reading it all | `MappedGsym::map` | `mmap` feature; `unsafe` |
//! | create a file | [`GsymBuilder`] | deterministic output from semantic records |
//! | import ELF and DWARF | `convert::ElfConverter` | `convert` feature |
//! | change version or byte order | [`Gsym::transcode`] | or [`DecodedGsym`] to edit in between |
//! | split into shards | [`DecodedGsym::segments`] | size-bounded, independently readable |
//! | check an untrusted file | [`Gsym::verify`] | checks the whole file up front |
//!
//! All readers are the same type, [`Gsym<D>`](Gsym) over different byte
//! storage, so the query API does not change with the choice.
//!
//! # Usage notes
//!
//! * Addresses are unslid. A GSYM file records the virtual addresses of the ELF
//! image it was built from, so an address captured from a running PIE
//! executable or shared object must have its load bias subtracted first.
//! Skipping that step is the usual cause of an empty or wrong result; see
//! [`docs::symbolication`].
//!
//! * Names and paths are bytes. The format stores raw bytes and this crate does
//! not reject non-UTF-8 data, so results are `&[u8]`. Use
//! `String::from_utf8_lossy` to display them, or `str::from_utf8` when
//! invalid data should be reported.
//!
//! * Version 1 is the default and is what current tooling reads. Version 2
//! raises v1's 4 GiB offset limits and its 20-byte build-ID limit but needs
//! LLVM 23 or newer, so it must be requested with [`GsymVersion::V2`].
//!
//! * Lookups take `&self` and keep no interior state. There is no global cache
//! and no lock, so one reader can be shared across threads. The one reusable
//! buffer, [`LookupScratch`], belongs to the caller.
//!
//! # Feature flags
//!
//! | Feature | Default | Adds |
//! | --- | --- | --- |
//! | `mmap` | yes | `MappedGsym`, a reader backed by a read-only memory map |
//! | `convert` | yes | the `convert` module: Linux ELF and DWARF import |
//! | `debuginfod` | no | debuginfod network lookup during conversion |
//!
//! The codec needs neither default feature:
//!
//! ```toml
//! [dependencies]
//! gsym-rs = { version = "0.1", default-features = false }
//! ```
//!
//! # Errors
//!
//! Fallible entry points return [`Result<T>`](Result). Its error type is
//! [`Error`], which covers malformed input, model violations, exceeded limits,
//! I/O, and, with `convert`, ELF and DWARF diagnostics. It is
//! `#[non_exhaustive]`, so a match on it needs a fallback arm.
//!
//! Malformed input produces an `Err` rather than a panic. Lookup validates only
//! the records it reads, so a file of unknown provenance is worth one
//! [`Gsym::verify`] at load time.
//!
//! # Guides
//!
//! - [`docs::symbolication`]: unslid addresses, reading frames, storage choices,
//! performance, threading.
//! - [`docs::cookbook`]: worked examples for every part of the API.
//! - [`docs::format`]: the on-disk format, version 1 and version 2.
//!
//! [LLVM GSYM]: https://llvm.org/doxygen/namespacellvm_1_1gsym.html
/// Linux ELF and DWARF conversion support.
pub use ;
pub use Endian;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use GsymVersion;
pub use WriterOptions;
pub use ;
/// Compiles the README's examples as doctests without rendering it twice.
;