/rust/registry/src/index.crates.io-1949cf8c6b5b557f/addr2line-0.24.2/src/frame.rs
Line | Count | Source |
1 | | use alloc::borrow::Cow; |
2 | | use alloc::string::String; |
3 | | use core::iter; |
4 | | |
5 | | use crate::{maybe_small, Error, Function, InlinedFunction, ResUnit}; |
6 | | |
7 | | /// A source location. |
8 | | pub struct Location<'a> { |
9 | | /// The file name. |
10 | | pub file: Option<&'a str>, |
11 | | /// The line number. |
12 | | pub line: Option<u32>, |
13 | | /// The column number. |
14 | | /// |
15 | | /// A value of `Some(0)` indicates the left edge. |
16 | | pub column: Option<u32>, |
17 | | } |
18 | | |
19 | | /// A function frame. |
20 | | pub struct Frame<'ctx, R: gimli::Reader> { |
21 | | /// The DWARF unit offset corresponding to the DIE of the function. |
22 | | pub dw_die_offset: Option<gimli::UnitOffset<R::Offset>>, |
23 | | /// The name of the function. |
24 | | pub function: Option<FunctionName<R>>, |
25 | | /// The source location corresponding to this frame. |
26 | | pub location: Option<Location<'ctx>>, |
27 | | } |
28 | | |
29 | | /// An iterator over function frames. |
30 | | pub struct FrameIter<'ctx, R>(FrameIterState<'ctx, R>) |
31 | | where |
32 | | R: gimli::Reader; |
33 | | |
34 | | enum FrameIterState<'ctx, R> |
35 | | where |
36 | | R: gimli::Reader, |
37 | | { |
38 | | Empty, |
39 | | Location(Option<Location<'ctx>>), |
40 | | Frames(FrameIterFrames<'ctx, R>), |
41 | | } |
42 | | |
43 | | struct FrameIterFrames<'ctx, R> |
44 | | where |
45 | | R: gimli::Reader, |
46 | | { |
47 | | unit: &'ctx ResUnit<R>, |
48 | | sections: &'ctx gimli::Dwarf<R>, |
49 | | function: &'ctx Function<R>, |
50 | | inlined_functions: iter::Rev<maybe_small::IntoIter<&'ctx InlinedFunction<R>>>, |
51 | | next: Option<Location<'ctx>>, |
52 | | } |
53 | | |
54 | | impl<'ctx, R> FrameIter<'ctx, R> |
55 | | where |
56 | | R: gimli::Reader + 'ctx, |
57 | | { |
58 | 0 | pub(crate) fn new_empty() -> Self { |
59 | 0 | FrameIter(FrameIterState::Empty) |
60 | 0 | } Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::new_empty Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::new_empty |
61 | | |
62 | 0 | pub(crate) fn new_location(location: Location<'ctx>) -> Self { |
63 | 0 | FrameIter(FrameIterState::Location(Some(location))) |
64 | 0 | } Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::new_location Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::new_location |
65 | | |
66 | 0 | pub(crate) fn new_frames( |
67 | 0 | unit: &'ctx ResUnit<R>, |
68 | 0 | sections: &'ctx gimli::Dwarf<R>, |
69 | 0 | function: &'ctx Function<R>, |
70 | 0 | inlined_functions: maybe_small::Vec<&'ctx InlinedFunction<R>>, |
71 | 0 | location: Option<Location<'ctx>>, |
72 | 0 | ) -> Self { |
73 | 0 | FrameIter(FrameIterState::Frames(FrameIterFrames { |
74 | 0 | unit, |
75 | 0 | sections, |
76 | 0 | function, |
77 | 0 | inlined_functions: inlined_functions.into_iter().rev(), |
78 | 0 | next: location, |
79 | 0 | })) |
80 | 0 | } Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::new_frames Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::new_frames |
81 | | |
82 | | /// Advances the iterator and returns the next frame. |
83 | | #[allow(clippy::should_implement_trait)] |
84 | 0 | pub fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> { |
85 | 0 | let frames = match &mut self.0 { |
86 | 0 | FrameIterState::Empty => return Ok(None), |
87 | 0 | FrameIterState::Location(location) => { |
88 | | // We can't move out of a mutable reference, so use `take` instead. |
89 | 0 | let location = location.take(); |
90 | 0 | self.0 = FrameIterState::Empty; |
91 | 0 | return Ok(Some(Frame { |
92 | 0 | dw_die_offset: None, |
93 | 0 | function: None, |
94 | 0 | location, |
95 | 0 | })); |
96 | | } |
97 | 0 | FrameIterState::Frames(frames) => frames, |
98 | | }; |
99 | | |
100 | 0 | let loc = frames.next.take(); |
101 | 0 | let func = match frames.inlined_functions.next() { |
102 | 0 | Some(func) => func, |
103 | | None => { |
104 | 0 | let frame = Frame { |
105 | 0 | dw_die_offset: Some(frames.function.dw_die_offset), |
106 | 0 | function: frames.function.name.clone().map(|name| FunctionName { |
107 | 0 | name, |
108 | 0 | language: frames.unit.lang, |
109 | 0 | }), Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::next::{closure#0}Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::next::{closure#0} |
110 | 0 | location: loc, |
111 | | }; |
112 | 0 | self.0 = FrameIterState::Empty; |
113 | 0 | return Ok(Some(frame)); |
114 | | } |
115 | | }; |
116 | | |
117 | 0 | let mut next = Location { |
118 | 0 | file: None, |
119 | 0 | line: if func.call_line != 0 { |
120 | 0 | Some(func.call_line) |
121 | | } else { |
122 | 0 | None |
123 | | }, |
124 | 0 | column: if func.call_column != 0 { |
125 | 0 | Some(func.call_column) |
126 | | } else { |
127 | 0 | None |
128 | | }, |
129 | | }; |
130 | 0 | if let Some(call_file) = func.call_file { |
131 | 0 | if let Some(lines) = frames.unit.parse_lines(frames.sections)? { |
132 | 0 | next.file = lines.file(call_file); |
133 | 0 | } |
134 | 0 | } |
135 | 0 | frames.next = Some(next); |
136 | | |
137 | | Ok(Some(Frame { |
138 | 0 | dw_die_offset: Some(func.dw_die_offset), |
139 | 0 | function: func.name.clone().map(|name| FunctionName { |
140 | 0 | name, |
141 | 0 | language: frames.unit.lang, |
142 | 0 | }), Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::next::{closure#1}Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::next::{closure#1} |
143 | 0 | location: loc, |
144 | | })) |
145 | 0 | } Unexecuted instantiation: <addr2line::frame::FrameIter<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::next Unexecuted instantiation: <addr2line::frame::FrameIter<_>>::next |
146 | | } |
147 | | |
148 | | #[cfg(feature = "fallible-iterator")] |
149 | | impl<'ctx, R> fallible_iterator::FallibleIterator for FrameIter<'ctx, R> |
150 | | where |
151 | | R: gimli::Reader + 'ctx, |
152 | | { |
153 | | type Item = Frame<'ctx, R>; |
154 | | type Error = Error; |
155 | | |
156 | | #[inline] |
157 | | fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> { |
158 | | self.next() |
159 | | } |
160 | | } |
161 | | |
162 | | /// A function name. |
163 | | pub struct FunctionName<R: gimli::Reader> { |
164 | | /// The name of the function. |
165 | | pub name: R, |
166 | | /// The language of the compilation unit containing this function. |
167 | | pub language: Option<gimli::DwLang>, |
168 | | } |
169 | | |
170 | | impl<R: gimli::Reader> FunctionName<R> { |
171 | | /// The raw name of this function before demangling. |
172 | 0 | pub fn raw_name(&self) -> Result<Cow<'_, str>, Error> { |
173 | 0 | self.name.to_string_lossy() |
174 | 0 | } |
175 | | |
176 | | /// The name of this function after demangling (if applicable). |
177 | 0 | pub fn demangle(&self) -> Result<Cow<'_, str>, Error> { |
178 | 0 | self.raw_name().map(|x| demangle_auto(x, self.language)) |
179 | 0 | } |
180 | | } |
181 | | |
182 | | /// Demangle a symbol name using the demangling scheme for the given language. |
183 | | /// |
184 | | /// Returns `None` if demangling failed or is not required. |
185 | | #[allow(unused_variables)] |
186 | 0 | pub fn demangle(name: &str, language: gimli::DwLang) -> Option<String> { |
187 | 0 | match language { |
188 | | #[cfg(feature = "rustc-demangle")] |
189 | | gimli::DW_LANG_Rust => rustc_demangle::try_demangle(name) |
190 | | .ok() |
191 | | .as_ref() |
192 | | .map(|x| format!("{:#}", x)), |
193 | | #[cfg(feature = "cpp_demangle")] |
194 | | gimli::DW_LANG_C_plus_plus |
195 | | | gimli::DW_LANG_C_plus_plus_03 |
196 | | | gimli::DW_LANG_C_plus_plus_11 |
197 | | | gimli::DW_LANG_C_plus_plus_14 => cpp_demangle::Symbol::new(name) |
198 | | .ok() |
199 | | .and_then(|x| x.demangle(&Default::default()).ok()), |
200 | 0 | _ => None, |
201 | | } |
202 | 0 | } |
203 | | |
204 | | /// Apply 'best effort' demangling of a symbol name. |
205 | | /// |
206 | | /// If `language` is given, then only the demangling scheme for that language |
207 | | /// is used. |
208 | | /// |
209 | | /// If `language` is `None`, then heuristics are used to determine how to |
210 | | /// demangle the name. Currently, these heuristics are very basic. |
211 | | /// |
212 | | /// If demangling fails or is not required, then `name` is returned unchanged. |
213 | 0 | pub fn demangle_auto(name: Cow<'_, str>, language: Option<gimli::DwLang>) -> Cow<'_, str> { |
214 | 0 | match language { |
215 | 0 | Some(language) => demangle(name.as_ref(), language), |
216 | 0 | None => demangle(name.as_ref(), gimli::DW_LANG_Rust) |
217 | 0 | .or_else(|| demangle(name.as_ref(), gimli::DW_LANG_C_plus_plus)), |
218 | | } |
219 | 0 | .map(Cow::from) |
220 | 0 | .unwrap_or(name) |
221 | 0 | } |