/rust/registry/src/index.crates.io-1949cf8c6b5b557f/addr2line-0.25.1/src/lookup.rs
Line | Count | Source |
1 | | use alloc::sync::Arc; |
2 | | use core::marker::PhantomData; |
3 | | use core::ops::ControlFlow; |
4 | | |
5 | | /// This struct contains the information needed to find split DWARF data |
6 | | /// and to produce a `gimli::Dwarf<R>` for it. |
7 | | pub struct SplitDwarfLoad<R> { |
8 | | /// The dwo id, for looking up in a DWARF package, or for |
9 | | /// verifying an unpacked dwo found on the file system |
10 | | pub dwo_id: gimli::DwoId, |
11 | | /// The compilation directory `path` is relative to. |
12 | | pub comp_dir: Option<R>, |
13 | | /// A path on the filesystem, relative to `comp_dir` to find this dwo. |
14 | | pub path: Option<R>, |
15 | | /// Once the split DWARF data is loaded, the loader is expected |
16 | | /// to call [make_dwo(parent)](gimli::read::Dwarf::make_dwo) before |
17 | | /// returning the data. |
18 | | pub parent: Arc<gimli::Dwarf<R>>, |
19 | | } |
20 | | |
21 | | /// Operations that consult debug information may require additional files |
22 | | /// to be loaded if split DWARF is being used. This enum returns the result |
23 | | /// of the operation in the `Output` variant, or information about the split |
24 | | /// DWARF that is required and a continuation to invoke once it is available |
25 | | /// in the `Load` variant. |
26 | | /// |
27 | | /// This enum is intended to be used in a loop like so: |
28 | | /// ```no_run |
29 | | /// # use addr2line::*; |
30 | | /// # use std::sync::Arc; |
31 | | /// # let ctx: Context<gimli::EndianSlice<gimli::RunTimeEndian>> = todo!(); |
32 | | /// # let do_split_dwarf_load = |load: SplitDwarfLoad<gimli::EndianSlice<gimli::RunTimeEndian>>| -> Option<Arc<gimli::Dwarf<gimli::EndianSlice<gimli::RunTimeEndian>>>> { None }; |
33 | | /// const ADDRESS: u64 = 0xdeadbeef; |
34 | | /// let mut r = ctx.find_frames(ADDRESS); |
35 | | /// let result = loop { |
36 | | /// match r { |
37 | | /// LookupResult::Output(result) => break result, |
38 | | /// LookupResult::Load { load, continuation } => { |
39 | | /// let dwo = do_split_dwarf_load(load); |
40 | | /// r = continuation.resume(dwo); |
41 | | /// } |
42 | | /// } |
43 | | /// }; |
44 | | /// ``` |
45 | | pub enum LookupResult<L: LookupContinuation> { |
46 | | /// The lookup requires split DWARF data to be loaded. |
47 | | Load { |
48 | | /// The information needed to find the split DWARF data. |
49 | | load: SplitDwarfLoad<<L as LookupContinuation>::Buf>, |
50 | | /// The continuation to resume with the loaded split DWARF data. |
51 | | continuation: L, |
52 | | }, |
53 | | /// The lookup has completed and produced an output. |
54 | | Output(<L as LookupContinuation>::Output), |
55 | | } |
56 | | |
57 | | /// This trait represents a partially complete operation that can be resumed |
58 | | /// once a load of needed split DWARF data is completed or abandoned by the |
59 | | /// API consumer. |
60 | | pub trait LookupContinuation: Sized { |
61 | | /// The final output of this operation. |
62 | | type Output; |
63 | | /// The type of reader used. |
64 | | type Buf: gimli::Reader; |
65 | | |
66 | | /// Resumes the operation with the provided data. |
67 | | /// |
68 | | /// After the caller loads the split DWARF data required, call this |
69 | | /// method to resume the operation. The return value of this method |
70 | | /// indicates if the computation has completed or if further data is |
71 | | /// required. |
72 | | /// |
73 | | /// If the additional data cannot be located, or the caller does not |
74 | | /// support split DWARF, `resume(None)` can be used to continue the |
75 | | /// operation with the data that is available. |
76 | | fn resume(self, input: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self>; |
77 | | } |
78 | | |
79 | | impl<L: LookupContinuation> LookupResult<L> { |
80 | | /// Callers that do not handle split DWARF can call `skip_all_loads` |
81 | | /// to fast-forward to the end result. This result is produced with |
82 | | /// the data that is available and may be less accurate than the |
83 | | /// the results that would be produced if the caller did properly |
84 | | /// support split DWARF. |
85 | 0 | pub fn skip_all_loads(mut self) -> L::Output { |
86 | | loop { |
87 | 0 | self = match self { |
88 | 0 | LookupResult::Output(t) => return t, |
89 | 0 | LookupResult::Load { continuation, .. } => continuation.resume(None), |
90 | | }; |
91 | | } |
92 | 0 | } |
93 | | |
94 | 0 | pub(crate) fn map<T, F: FnOnce(L::Output) -> T>( |
95 | 0 | self, |
96 | 0 | f: F, |
97 | 0 | ) -> LookupResult<MappedLookup<T, L, F>> { |
98 | 0 | match self { |
99 | 0 | LookupResult::Output(t) => LookupResult::Output(f(t)), |
100 | 0 | LookupResult::Load { load, continuation } => LookupResult::Load { |
101 | 0 | load, |
102 | 0 | continuation: MappedLookup { |
103 | 0 | original: continuation, |
104 | 0 | mutator: f, |
105 | 0 | }, |
106 | 0 | }, |
107 | | } |
108 | 0 | } Unexecuted instantiation: <addr2line::lookup::LookupResult<addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>>>::map::<core::result::Result<(core::option::Option<&addr2line::function::Function<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>, core::option::Option<addr2line::frame::Location>), gimli::read::Error>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0}>Unexecuted instantiation: <addr2line::lookup::LookupResult<_>>::map::<_, _> |
109 | | |
110 | 0 | pub(crate) fn unwrap(self) -> L::Output { |
111 | 0 | match self { |
112 | 0 | LookupResult::Output(t) => t, |
113 | 0 | LookupResult::Load { .. } => unreachable!("Internal API misuse"), |
114 | | } |
115 | 0 | } |
116 | | } |
117 | | |
118 | | pub(crate) struct SimpleLookup<T, R, F> |
119 | | where |
120 | | F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T, |
121 | | R: gimli::Reader, |
122 | | { |
123 | | f: F, |
124 | | phantom: PhantomData<(T, R)>, |
125 | | } |
126 | | |
127 | | impl<T, R, F> SimpleLookup<T, R, F> |
128 | | where |
129 | | F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T, |
130 | | R: gimli::Reader, |
131 | | { |
132 | 0 | pub(crate) fn new_complete(t: F::Output) -> LookupResult<SimpleLookup<T, R, F>> { |
133 | 0 | LookupResult::Output(t) |
134 | 0 | } Unexecuted instantiation: <addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>>::new_completeUnexecuted instantiation: <addr2line::lookup::SimpleLookup<_, _, _>>::new_complete |
135 | | |
136 | 0 | pub(crate) fn new_needs_load( |
137 | 0 | load: SplitDwarfLoad<R>, |
138 | 0 | f: F, |
139 | 0 | ) -> LookupResult<SimpleLookup<T, R, F>> { |
140 | 0 | LookupResult::Load { |
141 | 0 | load, |
142 | 0 | continuation: SimpleLookup { |
143 | 0 | f, |
144 | 0 | phantom: PhantomData, |
145 | 0 | }, |
146 | 0 | } |
147 | 0 | } Unexecuted instantiation: <addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>>::new_needs_loadUnexecuted instantiation: <addr2line::lookup::SimpleLookup<_, _, _>>::new_needs_load |
148 | | } |
149 | | |
150 | | impl<T, R, F> LookupContinuation for SimpleLookup<T, R, F> |
151 | | where |
152 | | F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T, |
153 | | R: gimli::Reader, |
154 | | { |
155 | | type Output = T; |
156 | | type Buf = R; |
157 | | |
158 | 0 | fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> { |
159 | 0 | LookupResult::Output((self.f)(v)) |
160 | 0 | } Unexecuted instantiation: <addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}> as addr2line::lookup::LookupContinuation>::resumeUnexecuted instantiation: <addr2line::lookup::SimpleLookup<_, _, _> as addr2line::lookup::LookupContinuation>::resume |
161 | | } |
162 | | |
163 | | pub(crate) struct MappedLookup<T, L, F> |
164 | | where |
165 | | L: LookupContinuation, |
166 | | F: FnOnce(L::Output) -> T, |
167 | | { |
168 | | original: L, |
169 | | mutator: F, |
170 | | } |
171 | | |
172 | | impl<T, L, F> LookupContinuation for MappedLookup<T, L, F> |
173 | | where |
174 | | L: LookupContinuation, |
175 | | F: FnOnce(L::Output) -> T, |
176 | | { |
177 | | type Output = T; |
178 | | type Buf = L::Buf; |
179 | | |
180 | 0 | fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> { |
181 | 0 | match self.original.resume(v) { |
182 | 0 | LookupResult::Output(t) => LookupResult::Output((self.mutator)(t)), |
183 | 0 | LookupResult::Load { load, continuation } => LookupResult::Load { |
184 | 0 | load, |
185 | 0 | continuation: MappedLookup { |
186 | 0 | original: continuation, |
187 | 0 | mutator: self.mutator, |
188 | 0 | }, |
189 | 0 | }, |
190 | | } |
191 | 0 | } Unexecuted instantiation: <addr2line::lookup::MappedLookup<core::result::Result<(core::option::Option<&addr2line::function::Function<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>, core::option::Option<addr2line::frame::Location>), gimli::read::Error>, addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0}> as addr2line::lookup::LookupContinuation>::resumeUnexecuted instantiation: <addr2line::lookup::MappedLookup<_, _, _> as addr2line::lookup::LookupContinuation>::resume |
192 | | } |
193 | | |
194 | | /// Some functions (e.g. `find_frames`) require considering multiple |
195 | | /// compilation units, each of which might require their own split DWARF |
196 | | /// lookup (and thus produce a continuation). |
197 | | /// |
198 | | /// We store the underlying continuation here as well as a mutator function |
199 | | /// that will either a) decide that the result of this continuation is |
200 | | /// what is needed and mutate it to the final result or b) produce another |
201 | | /// `LookupResult`. `new_lookup` will in turn eagerly drive any non-continuation |
202 | | /// `LookupResult` with successive invocations of the mutator, until a new |
203 | | /// continuation or a final result is produced. And finally, the impl of |
204 | | /// `LookupContinuation::resume` will call `new_lookup` each time the |
205 | | /// computation is resumed. |
206 | | pub(crate) struct LoopingLookup<T, L, F> |
207 | | where |
208 | | L: LookupContinuation, |
209 | | F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>, |
210 | | { |
211 | | continuation: L, |
212 | | mutator: F, |
213 | | } |
214 | | |
215 | | impl<T, L, F> LoopingLookup<T, L, F> |
216 | | where |
217 | | L: LookupContinuation, |
218 | | F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>, |
219 | | { |
220 | 0 | pub(crate) fn new_complete(t: T) -> LookupResult<Self> { |
221 | 0 | LookupResult::Output(t) |
222 | 0 | } Unexecuted instantiation: <addr2line::lookup::LoopingLookup<core::result::Result<addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>, gimli::read::Error>, addr2line::lookup::MappedLookup<core::result::Result<(core::option::Option<&addr2line::function::Function<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>, core::option::Option<addr2line::frame::Location>), gimli::read::Error>, addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0}>, <addr2line::Context<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_frames::{closure#0}>>::new_completeUnexecuted instantiation: <addr2line::lookup::LoopingLookup<_, _, _>>::new_complete |
223 | | |
224 | 0 | pub(crate) fn new_lookup(mut r: LookupResult<L>, mut mutator: F) -> LookupResult<Self> { |
225 | | // Drive the loop eagerly so that we only ever have to represent one state |
226 | | // (the r == ControlFlow::Continue state) in LoopingLookup. |
227 | | loop { |
228 | 0 | match r { |
229 | 0 | LookupResult::Output(l) => match mutator(l) { |
230 | 0 | ControlFlow::Break(t) => return LookupResult::Output(t), |
231 | 0 | ControlFlow::Continue(r2) => { |
232 | 0 | r = r2; |
233 | 0 | } |
234 | | }, |
235 | 0 | LookupResult::Load { load, continuation } => { |
236 | 0 | return LookupResult::Load { |
237 | 0 | load, |
238 | 0 | continuation: LoopingLookup { |
239 | 0 | continuation, |
240 | 0 | mutator, |
241 | 0 | }, |
242 | 0 | }; |
243 | | } |
244 | | } |
245 | | } |
246 | 0 | } Unexecuted instantiation: <addr2line::lookup::LoopingLookup<core::result::Result<addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>, gimli::read::Error>, addr2line::lookup::MappedLookup<core::result::Result<(core::option::Option<&addr2line::function::Function<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>, core::option::Option<addr2line::frame::Location>), gimli::read::Error>, addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0}>, <addr2line::Context<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_frames::{closure#0}>>::new_lookupUnexecuted instantiation: <addr2line::lookup::LoopingLookup<_, _, _>>::new_lookup |
247 | | } |
248 | | |
249 | | impl<T, L, F> LookupContinuation for LoopingLookup<T, L, F> |
250 | | where |
251 | | L: LookupContinuation, |
252 | | F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>, |
253 | | { |
254 | | type Output = T; |
255 | | type Buf = L::Buf; |
256 | | |
257 | 0 | fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> { |
258 | 0 | let r = self.continuation.resume(v); |
259 | 0 | LoopingLookup::new_lookup(r, self.mutator) |
260 | 0 | } Unexecuted instantiation: <addr2line::lookup::LoopingLookup<core::result::Result<addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>, gimli::read::Error>, addr2line::lookup::MappedLookup<core::result::Result<(core::option::Option<&addr2line::function::Function<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>, core::option::Option<addr2line::frame::Location>), gimli::read::Error>, addr2line::lookup::SimpleLookup<core::result::Result<(addr2line::DebugFile, gimli::read::dwarf::UnitRef<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>), gimli::read::Error>, gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}>, <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0}>, <addr2line::Context<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_frames::{closure#0}> as addr2line::lookup::LookupContinuation>::resumeUnexecuted instantiation: <addr2line::lookup::LoopingLookup<_, _, _> as addr2line::lookup::LookupContinuation>::resume |
261 | | } |