/rust/registry/src/index.crates.io-6f17d22bba15001f/gimli-0.29.0/src/read/dwarf.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use alloc::string::String; |
2 | | use alloc::sync::Arc; |
3 | | |
4 | | use crate::common::{ |
5 | | DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase, |
6 | | DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, |
7 | | DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwarfFileType, DwoId, Encoding, |
8 | | LocationListsOffset, RangeListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset, |
9 | | }; |
10 | | use crate::constants; |
11 | | use crate::read::{ |
12 | | Abbreviations, AbbreviationsCache, AbbreviationsCacheStrategy, AttributeValue, DebugAbbrev, |
13 | | DebugAddr, DebugAranges, DebugCuIndex, DebugInfo, DebugInfoUnitHeadersIter, DebugLine, |
14 | | DebugLineStr, DebugLoc, DebugLocLists, DebugRanges, DebugRngLists, DebugStr, DebugStrOffsets, |
15 | | DebugTuIndex, DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, |
16 | | EntriesRaw, EntriesTree, Error, IncompleteLineProgram, LocListIter, LocationLists, Range, |
17 | | RangeLists, RawLocListIter, RawRngListIter, Reader, ReaderOffset, ReaderOffsetId, Result, |
18 | | RngListIter, Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, UnitOffset, UnitType, |
19 | | }; |
20 | | |
21 | | /// All of the commonly used DWARF sections. |
22 | | /// |
23 | | /// This is useful for storing sections when `T` does not implement `Reader`. |
24 | | /// It can be used to create a `Dwarf` that references the data in `self`. |
25 | | /// If `T` does implement `Reader`, then use `Dwarf` directly. |
26 | | /// |
27 | | /// ## Example Usage |
28 | | /// |
29 | | /// It can be useful to load DWARF sections into owned data structures, |
30 | | /// such as `Vec`. However, we do not implement the `Reader` trait |
31 | | /// for `Vec`, because it would be very inefficient, but this trait |
32 | | /// is required for all of the methods that parse the DWARF data. |
33 | | /// So we first load the DWARF sections into `Vec`s, and then use |
34 | | /// `borrow` to create `Reader`s that reference the data. |
35 | | /// |
36 | | /// ```rust,no_run |
37 | | /// # fn example() -> Result<(), gimli::Error> { |
38 | | /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
39 | | /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. |
40 | | /// let dwarf_sections: gimli::DwarfSections<Vec<u8>> = gimli::DwarfSections::load(loader)?; |
41 | | /// // Create references to the DWARF sections. |
42 | | /// let dwarf: gimli::Dwarf<_> = dwarf_sections.borrow(|section| { |
43 | | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
44 | | /// }); |
45 | | /// # unreachable!() |
46 | | /// # } |
47 | | /// ``` |
48 | | #[derive(Debug)] |
49 | | pub struct DwarfSections<T> { |
50 | | /// The `.debug_abbrev` section. |
51 | | pub debug_abbrev: DebugAbbrev<T>, |
52 | | /// The `.debug_addr` section. |
53 | | pub debug_addr: DebugAddr<T>, |
54 | | /// The `.debug_aranges` section. |
55 | | pub debug_aranges: DebugAranges<T>, |
56 | | /// The `.debug_info` section. |
57 | | pub debug_info: DebugInfo<T>, |
58 | | /// The `.debug_line` section. |
59 | | pub debug_line: DebugLine<T>, |
60 | | /// The `.debug_line_str` section. |
61 | | pub debug_line_str: DebugLineStr<T>, |
62 | | /// The `.debug_str` section. |
63 | | pub debug_str: DebugStr<T>, |
64 | | /// The `.debug_str_offsets` section. |
65 | | pub debug_str_offsets: DebugStrOffsets<T>, |
66 | | /// The `.debug_types` section. |
67 | | pub debug_types: DebugTypes<T>, |
68 | | /// The `.debug_loc` section. |
69 | | pub debug_loc: DebugLoc<T>, |
70 | | /// The `.debug_loclists` section. |
71 | | pub debug_loclists: DebugLocLists<T>, |
72 | | /// The `.debug_ranges` section. |
73 | | pub debug_ranges: DebugRanges<T>, |
74 | | /// The `.debug_rnglists` section. |
75 | | pub debug_rnglists: DebugRngLists<T>, |
76 | | } |
77 | | |
78 | | impl<T> DwarfSections<T> { |
79 | | /// Try to load the DWARF sections using the given loader function. |
80 | | /// |
81 | | /// `section` loads a DWARF section from the object file. |
82 | | /// It should return an empty section if the section does not exist. |
83 | 0 | pub fn load<F, E>(mut section: F) -> core::result::Result<Self, E> |
84 | 0 | where |
85 | 0 | F: FnMut(SectionId) -> core::result::Result<T, E>, |
86 | 0 | { |
87 | 0 | Ok(DwarfSections { |
88 | 0 | // Section types are inferred. |
89 | 0 | debug_abbrev: Section::load(&mut section)?, |
90 | 0 | debug_addr: Section::load(&mut section)?, |
91 | 0 | debug_aranges: Section::load(&mut section)?, |
92 | 0 | debug_info: Section::load(&mut section)?, |
93 | 0 | debug_line: Section::load(&mut section)?, |
94 | 0 | debug_line_str: Section::load(&mut section)?, |
95 | 0 | debug_str: Section::load(&mut section)?, |
96 | 0 | debug_str_offsets: Section::load(&mut section)?, |
97 | 0 | debug_types: Section::load(&mut section)?, |
98 | 0 | debug_loc: Section::load(&mut section)?, |
99 | 0 | debug_loclists: Section::load(&mut section)?, |
100 | 0 | debug_ranges: Section::load(&mut section)?, |
101 | 0 | debug_rnglists: Section::load(&mut section)?, |
102 | | }) |
103 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfSections<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#0}, ()> Unexecuted instantiation: <gimli::read::dwarf::DwarfSections<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#1}, ()> Unexecuted instantiation: <gimli::read::dwarf::DwarfSections<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<backtrace::symbolize::gimli::elf::handle_split_dwarf::{closure#0}, ()> Unexecuted instantiation: <gimli::read::dwarf::DwarfSections<_>>::load::<_, _> |
104 | | |
105 | | /// Create a `Dwarf` structure that references the data in `self`. |
106 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R> |
107 | 0 | where |
108 | 0 | F: FnMut(&'a T) -> R, |
109 | 0 | { |
110 | 0 | Dwarf::from_sections(DwarfSections { |
111 | 0 | debug_abbrev: self.debug_abbrev.borrow(&mut borrow), |
112 | 0 | debug_addr: self.debug_addr.borrow(&mut borrow), |
113 | 0 | debug_aranges: self.debug_aranges.borrow(&mut borrow), |
114 | 0 | debug_info: self.debug_info.borrow(&mut borrow), |
115 | 0 | debug_line: self.debug_line.borrow(&mut borrow), |
116 | 0 | debug_line_str: self.debug_line_str.borrow(&mut borrow), |
117 | 0 | debug_str: self.debug_str.borrow(&mut borrow), |
118 | 0 | debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), |
119 | 0 | debug_types: self.debug_types.borrow(&mut borrow), |
120 | 0 | debug_loc: self.debug_loc.borrow(&mut borrow), |
121 | 0 | debug_loclists: self.debug_loclists.borrow(&mut borrow), |
122 | 0 | debug_ranges: self.debug_ranges.borrow(&mut borrow), |
123 | 0 | debug_rnglists: self.debug_rnglists.borrow(&mut borrow), |
124 | 0 | }) |
125 | 0 | } |
126 | | |
127 | | /// Create a `Dwarf` structure that references the data in `self` and `sup`. |
128 | | /// |
129 | | /// This is like `borrow`, but also includes the supplementary object file. |
130 | | /// This is useful when `R` implements `Reader` but `T` does not. |
131 | | /// |
132 | | /// ## Example Usage |
133 | | /// |
134 | | /// ```rust,no_run |
135 | | /// # fn example() -> Result<(), gimli::Error> { |
136 | | /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
137 | | /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
138 | | /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. |
139 | | /// let dwarf_sections: gimli::DwarfSections<Vec<u8>> = gimli::DwarfSections::load(loader)?; |
140 | | /// let dwarf_sup_sections: gimli::DwarfSections<Vec<u8>> = gimli::DwarfSections::load(sup_loader)?; |
141 | | /// // Create references to the DWARF sections. |
142 | | /// let dwarf = dwarf_sections.borrow_with_sup(&dwarf_sup_sections, |section| { |
143 | | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
144 | | /// }); |
145 | | /// # unreachable!() |
146 | | /// # } |
147 | | /// ``` |
148 | 0 | pub fn borrow_with_sup<'a, F, R>(&'a self, sup: &'a Self, mut borrow: F) -> Dwarf<R> |
149 | 0 | where |
150 | 0 | F: FnMut(&'a T) -> R, |
151 | 0 | { |
152 | 0 | let mut dwarf = self.borrow(&mut borrow); |
153 | 0 | dwarf.set_sup(sup.borrow(&mut borrow)); |
154 | 0 | dwarf |
155 | 0 | } |
156 | | } |
157 | | |
158 | | /// All of the commonly used DWARF sections, and other common information. |
159 | | #[derive(Debug, Default)] |
160 | | pub struct Dwarf<R> { |
161 | | /// The `.debug_abbrev` section. |
162 | | pub debug_abbrev: DebugAbbrev<R>, |
163 | | |
164 | | /// The `.debug_addr` section. |
165 | | pub debug_addr: DebugAddr<R>, |
166 | | |
167 | | /// The `.debug_aranges` section. |
168 | | pub debug_aranges: DebugAranges<R>, |
169 | | |
170 | | /// The `.debug_info` section. |
171 | | pub debug_info: DebugInfo<R>, |
172 | | |
173 | | /// The `.debug_line` section. |
174 | | pub debug_line: DebugLine<R>, |
175 | | |
176 | | /// The `.debug_line_str` section. |
177 | | pub debug_line_str: DebugLineStr<R>, |
178 | | |
179 | | /// The `.debug_str` section. |
180 | | pub debug_str: DebugStr<R>, |
181 | | |
182 | | /// The `.debug_str_offsets` section. |
183 | | pub debug_str_offsets: DebugStrOffsets<R>, |
184 | | |
185 | | /// The `.debug_types` section. |
186 | | pub debug_types: DebugTypes<R>, |
187 | | |
188 | | /// The location lists in the `.debug_loc` and `.debug_loclists` sections. |
189 | | pub locations: LocationLists<R>, |
190 | | |
191 | | /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections. |
192 | | pub ranges: RangeLists<R>, |
193 | | |
194 | | /// The type of this file. |
195 | | pub file_type: DwarfFileType, |
196 | | |
197 | | /// The DWARF sections for a supplementary object file. |
198 | | pub sup: Option<Arc<Dwarf<R>>>, |
199 | | |
200 | | /// A cache of previously parsed abbreviations for units in this file. |
201 | | pub abbreviations_cache: AbbreviationsCache, |
202 | | } |
203 | | |
204 | | impl<T> Dwarf<T> { |
205 | | /// Try to load the DWARF sections using the given loader function. |
206 | | /// |
207 | | /// `section` loads a DWARF section from the object file. |
208 | | /// It should return an empty section if the section does not exist. |
209 | | /// |
210 | | /// After loading, the user should set the `file_type` field and |
211 | | /// call `load_sup` if required. |
212 | 0 | pub fn load<F, E>(section: F) -> core::result::Result<Self, E> |
213 | 0 | where |
214 | 0 | F: FnMut(SectionId) -> core::result::Result<T, E>, |
215 | 0 | { |
216 | 0 | let sections = DwarfSections::load(section)?; |
217 | 0 | Ok(Self::from_sections(sections)) |
218 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#0}, ()> Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#1}, ()> Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<backtrace::symbolize::gimli::elf::handle_split_dwarf::{closure#0}, ()> Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::load::<_, _> |
219 | | |
220 | | /// Load the DWARF sections from the supplementary object file. |
221 | | /// |
222 | | /// `section` operates the same as for `load`. |
223 | | /// |
224 | | /// Sets `self.sup`, replacing any previous value. |
225 | 0 | pub fn load_sup<F, E>(&mut self, section: F) -> core::result::Result<(), E> |
226 | 0 | where |
227 | 0 | F: FnMut(SectionId) -> core::result::Result<T, E>, |
228 | 0 | { |
229 | 0 | self.set_sup(Self::load(section)?); |
230 | 0 | Ok(()) |
231 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load_sup::<<backtrace::symbolize::gimli::Context>::new::{closure#1}, ()> Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::load_sup::<_, _> |
232 | | |
233 | | /// Create a `Dwarf` structure from the given sections. |
234 | | /// |
235 | | /// The caller should set the `file_type` and `sup` fields if required. |
236 | 0 | fn from_sections(sections: DwarfSections<T>) -> Self { |
237 | 0 | Dwarf { |
238 | 0 | debug_abbrev: sections.debug_abbrev, |
239 | 0 | debug_addr: sections.debug_addr, |
240 | 0 | debug_aranges: sections.debug_aranges, |
241 | 0 | debug_info: sections.debug_info, |
242 | 0 | debug_line: sections.debug_line, |
243 | 0 | debug_line_str: sections.debug_line_str, |
244 | 0 | debug_str: sections.debug_str, |
245 | 0 | debug_str_offsets: sections.debug_str_offsets, |
246 | 0 | debug_types: sections.debug_types, |
247 | 0 | locations: LocationLists::new(sections.debug_loc, sections.debug_loclists), |
248 | 0 | ranges: RangeLists::new(sections.debug_ranges, sections.debug_rnglists), |
249 | 0 | file_type: DwarfFileType::Main, |
250 | 0 | sup: None, |
251 | 0 | abbreviations_cache: AbbreviationsCache::new(), |
252 | 0 | } |
253 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from_sections Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::from_sections |
254 | | |
255 | | /// Create a `Dwarf` structure that references the data in `self`. |
256 | | /// |
257 | | /// This is useful when `R` implements `Reader` but `T` does not. |
258 | | /// |
259 | | /// ## Example Usage |
260 | | /// |
261 | | /// It can be useful to load DWARF sections into owned data structures, |
262 | | /// such as `Vec`. However, we do not implement the `Reader` trait |
263 | | /// for `Vec`, because it would be very inefficient, but this trait |
264 | | /// is required for all of the methods that parse the DWARF data. |
265 | | /// So we first load the DWARF sections into `Vec`s, and then use |
266 | | /// `borrow` to create `Reader`s that reference the data. |
267 | | /// |
268 | | /// ```rust,no_run |
269 | | /// # fn example() -> Result<(), gimli::Error> { |
270 | | /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
271 | | /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
272 | | /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. |
273 | | /// let mut owned_dwarf: gimli::Dwarf<Vec<u8>> = gimli::Dwarf::load(loader)?; |
274 | | /// owned_dwarf.load_sup(sup_loader)?; |
275 | | /// // Create references to the DWARF sections. |
276 | | /// let dwarf = owned_dwarf.borrow(|section| { |
277 | | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
278 | | /// }); |
279 | | /// # unreachable!() |
280 | | /// # } |
281 | | /// ``` |
282 | | #[deprecated(note = "use `DwarfSections::borrow` instead")] |
283 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R> |
284 | 0 | where |
285 | 0 | F: FnMut(&'a T) -> R, |
286 | 0 | { |
287 | 0 | Dwarf { |
288 | 0 | debug_abbrev: self.debug_abbrev.borrow(&mut borrow), |
289 | 0 | debug_addr: self.debug_addr.borrow(&mut borrow), |
290 | 0 | debug_aranges: self.debug_aranges.borrow(&mut borrow), |
291 | 0 | debug_info: self.debug_info.borrow(&mut borrow), |
292 | 0 | debug_line: self.debug_line.borrow(&mut borrow), |
293 | 0 | debug_line_str: self.debug_line_str.borrow(&mut borrow), |
294 | 0 | debug_str: self.debug_str.borrow(&mut borrow), |
295 | 0 | debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), |
296 | 0 | debug_types: self.debug_types.borrow(&mut borrow), |
297 | 0 | locations: self.locations.borrow(&mut borrow), |
298 | 0 | ranges: self.ranges.borrow(&mut borrow), |
299 | 0 | file_type: self.file_type, |
300 | 0 | sup: self.sup().map(|sup| Arc::new(sup.borrow(borrow))), |
301 | 0 | abbreviations_cache: AbbreviationsCache::new(), |
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | | /// Store the DWARF sections for the supplementary object file. |
306 | 0 | pub fn set_sup(&mut self, sup: Dwarf<T>) { |
307 | 0 | self.sup = Some(Arc::new(sup)); |
308 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::set_sup Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::set_sup |
309 | | |
310 | | /// Return a reference to the DWARF sections for the supplementary object file. |
311 | 0 | pub fn sup(&self) -> Option<&Dwarf<T>> { |
312 | 0 | self.sup.as_ref().map(Arc::as_ref) |
313 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::sup Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::sup |
314 | | } |
315 | | |
316 | | impl<R: Reader> Dwarf<R> { |
317 | | /// Parse abbreviations and store them in the cache. |
318 | | /// |
319 | | /// This will iterate over the units in `self.debug_info` to determine the |
320 | | /// abbreviations offsets. |
321 | | /// |
322 | | /// Errors during parsing abbreviations are also stored in the cache. |
323 | | /// Errors during iterating over the units are ignored. |
324 | 0 | pub fn populate_abbreviations_cache(&mut self, strategy: AbbreviationsCacheStrategy) { |
325 | 0 | self.abbreviations_cache |
326 | 0 | .populate(strategy, &self.debug_abbrev, self.debug_info.units()); |
327 | 0 | } |
328 | | |
329 | | /// Iterate the unit headers in the `.debug_info` section. |
330 | | /// |
331 | | /// Can be [used with |
332 | | /// `FallibleIterator`](./index.html#using-with-fallibleiterator). |
333 | | #[inline] |
334 | 0 | pub fn units(&self) -> DebugInfoUnitHeadersIter<R> { |
335 | 0 | self.debug_info.units() |
336 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::units Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::units |
337 | | |
338 | | /// Construct a new `Unit` from the given unit header. |
339 | | #[inline] |
340 | 0 | pub fn unit(&self, header: UnitHeader<R>) -> Result<Unit<R>> { |
341 | 0 | Unit::new(self, header) |
342 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::unit Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::unit |
343 | | |
344 | | /// Iterate the type-unit headers in the `.debug_types` section. |
345 | | /// |
346 | | /// Can be [used with |
347 | | /// `FallibleIterator`](./index.html#using-with-fallibleiterator). |
348 | | #[inline] |
349 | 0 | pub fn type_units(&self) -> DebugTypesUnitHeadersIter<R> { |
350 | 0 | self.debug_types.units() |
351 | 0 | } |
352 | | |
353 | | /// Parse the abbreviations for a compilation unit. |
354 | | #[inline] |
355 | 0 | pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Arc<Abbreviations>> { |
356 | 0 | self.abbreviations_cache |
357 | 0 | .get(&self.debug_abbrev, unit.debug_abbrev_offset()) |
358 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::abbreviations Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::abbreviations |
359 | | |
360 | | /// Return the string offset at the given index. |
361 | | #[inline] |
362 | 0 | pub fn string_offset( |
363 | 0 | &self, |
364 | 0 | unit: &Unit<R>, |
365 | 0 | index: DebugStrOffsetsIndex<R::Offset>, |
366 | 0 | ) -> Result<DebugStrOffset<R::Offset>> { |
367 | 0 | self.debug_str_offsets |
368 | 0 | .get_str_offset(unit.header.format(), unit.str_offsets_base, index) |
369 | 0 | } |
370 | | |
371 | | /// Return the string at the given offset in `.debug_str`. |
372 | | #[inline] |
373 | 0 | pub fn string(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { |
374 | 0 | self.debug_str.get_str(offset) |
375 | 0 | } |
376 | | |
377 | | /// Return the string at the given offset in `.debug_line_str`. |
378 | | #[inline] |
379 | 0 | pub fn line_string(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { |
380 | 0 | self.debug_line_str.get_str(offset) |
381 | 0 | } |
382 | | |
383 | | /// Return an attribute value as a string slice. |
384 | | /// |
385 | | /// If the attribute value is one of: |
386 | | /// |
387 | | /// - an inline `DW_FORM_string` string |
388 | | /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section |
389 | | /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary |
390 | | /// object file |
391 | | /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str` |
392 | | /// section |
393 | | /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit |
394 | | /// |
395 | | /// then return the attribute's string value. Returns an error if the attribute |
396 | | /// value does not have a string form, or if a string form has an invalid value. |
397 | 0 | pub fn attr_string(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<R> { |
398 | 0 | match attr { |
399 | 0 | AttributeValue::String(string) => Ok(string), |
400 | 0 | AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset), |
401 | 0 | AttributeValue::DebugStrRefSup(offset) => { |
402 | 0 | if let Some(sup) = self.sup() { |
403 | 0 | sup.debug_str.get_str(offset) |
404 | | } else { |
405 | 0 | Err(Error::ExpectedStringAttributeValue) |
406 | | } |
407 | | } |
408 | 0 | AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset), |
409 | 0 | AttributeValue::DebugStrOffsetsIndex(index) => { |
410 | 0 | let offset = self.debug_str_offsets.get_str_offset( |
411 | 0 | unit.header.format(), |
412 | 0 | unit.str_offsets_base, |
413 | 0 | index, |
414 | 0 | )?; |
415 | 0 | self.debug_str.get_str(offset) |
416 | | } |
417 | 0 | _ => Err(Error::ExpectedStringAttributeValue), |
418 | | } |
419 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::attr_string Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::attr_string |
420 | | |
421 | | /// Return the address at the given index. |
422 | 0 | pub fn address(&self, unit: &Unit<R>, index: DebugAddrIndex<R::Offset>) -> Result<u64> { |
423 | 0 | self.debug_addr |
424 | 0 | .get_address(unit.encoding().address_size, unit.addr_base, index) |
425 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::address Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::address |
426 | | |
427 | | /// Try to return an attribute value as an address. |
428 | | /// |
429 | | /// If the attribute value is one of: |
430 | | /// |
431 | | /// - a `DW_FORM_addr` |
432 | | /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit |
433 | | /// |
434 | | /// then return the address. |
435 | | /// Returns `None` for other forms. |
436 | 0 | pub fn attr_address(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<Option<u64>> { |
437 | 0 | match attr { |
438 | 0 | AttributeValue::Addr(addr) => Ok(Some(addr)), |
439 | 0 | AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some), |
440 | 0 | _ => Ok(None), |
441 | | } |
442 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::attr_address Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::attr_address |
443 | | |
444 | | /// Return the range list offset for the given raw offset. |
445 | | /// |
446 | | /// This handles adding `DW_AT_GNU_ranges_base` if required. |
447 | 0 | pub fn ranges_offset_from_raw( |
448 | 0 | &self, |
449 | 0 | unit: &Unit<R>, |
450 | 0 | offset: RawRangeListsOffset<R::Offset>, |
451 | 0 | ) -> RangeListsOffset<R::Offset> { |
452 | 0 | if self.file_type == DwarfFileType::Dwo && unit.header.version() < 5 { |
453 | 0 | RangeListsOffset(offset.0.wrapping_add(unit.rnglists_base.0)) |
454 | | } else { |
455 | 0 | RangeListsOffset(offset.0) |
456 | | } |
457 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::ranges_offset_from_raw Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::ranges_offset_from_raw |
458 | | |
459 | | /// Return the range list offset at the given index. |
460 | 0 | pub fn ranges_offset( |
461 | 0 | &self, |
462 | 0 | unit: &Unit<R>, |
463 | 0 | index: DebugRngListsIndex<R::Offset>, |
464 | 0 | ) -> Result<RangeListsOffset<R::Offset>> { |
465 | 0 | self.ranges |
466 | 0 | .get_offset(unit.encoding(), unit.rnglists_base, index) |
467 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::ranges_offset Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::ranges_offset |
468 | | |
469 | | /// Iterate over the `RangeListEntry`s starting at the given offset. |
470 | 0 | pub fn ranges( |
471 | 0 | &self, |
472 | 0 | unit: &Unit<R>, |
473 | 0 | offset: RangeListsOffset<R::Offset>, |
474 | 0 | ) -> Result<RngListIter<R>> { |
475 | 0 | self.ranges.ranges( |
476 | 0 | offset, |
477 | 0 | unit.encoding(), |
478 | 0 | unit.low_pc, |
479 | 0 | &self.debug_addr, |
480 | 0 | unit.addr_base, |
481 | 0 | ) |
482 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::ranges Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::ranges |
483 | | |
484 | | /// Iterate over the `RawRngListEntry`ies starting at the given offset. |
485 | 0 | pub fn raw_ranges( |
486 | 0 | &self, |
487 | 0 | unit: &Unit<R>, |
488 | 0 | offset: RangeListsOffset<R::Offset>, |
489 | 0 | ) -> Result<RawRngListIter<R>> { |
490 | 0 | self.ranges.raw_ranges(offset, unit.encoding()) |
491 | 0 | } |
492 | | |
493 | | /// Try to return an attribute value as a range list offset. |
494 | | /// |
495 | | /// If the attribute value is one of: |
496 | | /// |
497 | | /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections |
498 | | /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit |
499 | | /// |
500 | | /// then return the range list offset of the range list. |
501 | | /// Returns `None` for other forms. |
502 | 0 | pub fn attr_ranges_offset( |
503 | 0 | &self, |
504 | 0 | unit: &Unit<R>, |
505 | 0 | attr: AttributeValue<R>, |
506 | 0 | ) -> Result<Option<RangeListsOffset<R::Offset>>> { |
507 | 0 | match attr { |
508 | 0 | AttributeValue::RangeListsRef(offset) => { |
509 | 0 | Ok(Some(self.ranges_offset_from_raw(unit, offset))) |
510 | | } |
511 | 0 | AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some), |
512 | 0 | _ => Ok(None), |
513 | | } |
514 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::attr_ranges_offset Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::attr_ranges_offset |
515 | | |
516 | | /// Try to return an attribute value as a range list entry iterator. |
517 | | /// |
518 | | /// If the attribute value is one of: |
519 | | /// |
520 | | /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections |
521 | | /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit |
522 | | /// |
523 | | /// then return an iterator over the entries in the range list. |
524 | | /// Returns `None` for other forms. |
525 | 0 | pub fn attr_ranges( |
526 | 0 | &self, |
527 | 0 | unit: &Unit<R>, |
528 | 0 | attr: AttributeValue<R>, |
529 | 0 | ) -> Result<Option<RngListIter<R>>> { |
530 | 0 | match self.attr_ranges_offset(unit, attr)? { |
531 | 0 | Some(offset) => Ok(Some(self.ranges(unit, offset)?)), |
532 | 0 | None => Ok(None), |
533 | | } |
534 | 0 | } |
535 | | |
536 | | /// Return an iterator for the address ranges of a `DebuggingInformationEntry`. |
537 | | /// |
538 | | /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`. |
539 | 0 | pub fn die_ranges( |
540 | 0 | &self, |
541 | 0 | unit: &Unit<R>, |
542 | 0 | entry: &DebuggingInformationEntry<R>, |
543 | 0 | ) -> Result<RangeIter<R>> { |
544 | 0 | let mut low_pc = None; |
545 | 0 | let mut high_pc = None; |
546 | 0 | let mut size = None; |
547 | 0 | let mut attrs = entry.attrs(); |
548 | 0 | while let Some(attr) = attrs.next()? { |
549 | 0 | match attr.name() { |
550 | | constants::DW_AT_low_pc => { |
551 | | low_pc = Some( |
552 | 0 | self.attr_address(unit, attr.value())? |
553 | 0 | .ok_or(Error::UnsupportedAttributeForm)?, |
554 | | ); |
555 | | } |
556 | 0 | constants::DW_AT_high_pc => match attr.value() { |
557 | 0 | AttributeValue::Udata(val) => size = Some(val), |
558 | 0 | attr => { |
559 | 0 | high_pc = Some( |
560 | 0 | self.attr_address(unit, attr)? |
561 | 0 | .ok_or(Error::UnsupportedAttributeForm)?, |
562 | | ); |
563 | | } |
564 | | }, |
565 | | constants::DW_AT_ranges => { |
566 | 0 | if let Some(list) = self.attr_ranges(unit, attr.value())? { |
567 | 0 | return Ok(RangeIter(RangeIterInner::List(list))); |
568 | 0 | } |
569 | | } |
570 | 0 | _ => {} |
571 | | } |
572 | | } |
573 | 0 | let range = low_pc.and_then(|begin| { |
574 | 0 | let end = size.map(|size| begin + size).or(high_pc); |
575 | 0 | // TODO: perhaps return an error if `end` is `None` |
576 | 0 | end.map(|end| Range { begin, end }) |
577 | 0 | }); |
578 | 0 | Ok(RangeIter(RangeIterInner::Single(range))) |
579 | 0 | } |
580 | | |
581 | | /// Return an iterator for the address ranges of a `Unit`. |
582 | | /// |
583 | | /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the |
584 | | /// root `DebuggingInformationEntry`. |
585 | 0 | pub fn unit_ranges(&self, unit: &Unit<R>) -> Result<RangeIter<R>> { |
586 | 0 | let mut cursor = unit.header.entries(&unit.abbreviations); |
587 | 0 | cursor.next_dfs()?; |
588 | 0 | let root = cursor.current().ok_or(Error::MissingUnitDie)?; |
589 | 0 | self.die_ranges(unit, root) |
590 | 0 | } |
591 | | |
592 | | /// Return the location list offset at the given index. |
593 | 0 | pub fn locations_offset( |
594 | 0 | &self, |
595 | 0 | unit: &Unit<R>, |
596 | 0 | index: DebugLocListsIndex<R::Offset>, |
597 | 0 | ) -> Result<LocationListsOffset<R::Offset>> { |
598 | 0 | self.locations |
599 | 0 | .get_offset(unit.encoding(), unit.loclists_base, index) |
600 | 0 | } |
601 | | |
602 | | /// Iterate over the `LocationListEntry`s starting at the given offset. |
603 | 0 | pub fn locations( |
604 | 0 | &self, |
605 | 0 | unit: &Unit<R>, |
606 | 0 | offset: LocationListsOffset<R::Offset>, |
607 | 0 | ) -> Result<LocListIter<R>> { |
608 | 0 | match self.file_type { |
609 | 0 | DwarfFileType::Main => self.locations.locations( |
610 | 0 | offset, |
611 | 0 | unit.encoding(), |
612 | 0 | unit.low_pc, |
613 | 0 | &self.debug_addr, |
614 | 0 | unit.addr_base, |
615 | 0 | ), |
616 | 0 | DwarfFileType::Dwo => self.locations.locations_dwo( |
617 | 0 | offset, |
618 | 0 | unit.encoding(), |
619 | 0 | unit.low_pc, |
620 | 0 | &self.debug_addr, |
621 | 0 | unit.addr_base, |
622 | 0 | ), |
623 | | } |
624 | 0 | } |
625 | | |
626 | | /// Iterate over the raw `LocationListEntry`s starting at the given offset. |
627 | 0 | pub fn raw_locations( |
628 | 0 | &self, |
629 | 0 | unit: &Unit<R>, |
630 | 0 | offset: LocationListsOffset<R::Offset>, |
631 | 0 | ) -> Result<RawLocListIter<R>> { |
632 | 0 | match self.file_type { |
633 | 0 | DwarfFileType::Main => self.locations.raw_locations(offset, unit.encoding()), |
634 | 0 | DwarfFileType::Dwo => self.locations.raw_locations_dwo(offset, unit.encoding()), |
635 | | } |
636 | 0 | } |
637 | | |
638 | | /// Try to return an attribute value as a location list offset. |
639 | | /// |
640 | | /// If the attribute value is one of: |
641 | | /// |
642 | | /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections |
643 | | /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit |
644 | | /// |
645 | | /// then return the location list offset of the location list. |
646 | | /// Returns `None` for other forms. |
647 | 0 | pub fn attr_locations_offset( |
648 | 0 | &self, |
649 | 0 | unit: &Unit<R>, |
650 | 0 | attr: AttributeValue<R>, |
651 | 0 | ) -> Result<Option<LocationListsOffset<R::Offset>>> { |
652 | 0 | match attr { |
653 | 0 | AttributeValue::LocationListsRef(offset) => Ok(Some(offset)), |
654 | 0 | AttributeValue::DebugLocListsIndex(index) => { |
655 | 0 | self.locations_offset(unit, index).map(Some) |
656 | | } |
657 | 0 | _ => Ok(None), |
658 | | } |
659 | 0 | } |
660 | | |
661 | | /// Try to return an attribute value as a location list entry iterator. |
662 | | /// |
663 | | /// If the attribute value is one of: |
664 | | /// |
665 | | /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections |
666 | | /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit |
667 | | /// |
668 | | /// then return an iterator over the entries in the location list. |
669 | | /// Returns `None` for other forms. |
670 | 0 | pub fn attr_locations( |
671 | 0 | &self, |
672 | 0 | unit: &Unit<R>, |
673 | 0 | attr: AttributeValue<R>, |
674 | 0 | ) -> Result<Option<LocListIter<R>>> { |
675 | 0 | match self.attr_locations_offset(unit, attr)? { |
676 | 0 | Some(offset) => Ok(Some(self.locations(unit, offset)?)), |
677 | 0 | None => Ok(None), |
678 | | } |
679 | 0 | } |
680 | | |
681 | | /// Call `Reader::lookup_offset_id` for each section, and return the first match. |
682 | | /// |
683 | | /// The first element of the tuple is `true` for supplementary sections. |
684 | 0 | pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> { |
685 | 0 | None.or_else(|| self.debug_abbrev.lookup_offset_id(id)) |
686 | 0 | .or_else(|| self.debug_addr.lookup_offset_id(id)) |
687 | 0 | .or_else(|| self.debug_aranges.lookup_offset_id(id)) |
688 | 0 | .or_else(|| self.debug_info.lookup_offset_id(id)) |
689 | 0 | .or_else(|| self.debug_line.lookup_offset_id(id)) |
690 | 0 | .or_else(|| self.debug_line_str.lookup_offset_id(id)) |
691 | 0 | .or_else(|| self.debug_str.lookup_offset_id(id)) |
692 | 0 | .or_else(|| self.debug_str_offsets.lookup_offset_id(id)) |
693 | 0 | .or_else(|| self.debug_types.lookup_offset_id(id)) |
694 | 0 | .or_else(|| self.locations.lookup_offset_id(id)) |
695 | 0 | .or_else(|| self.ranges.lookup_offset_id(id)) |
696 | 0 | .map(|(id, offset)| (false, id, offset)) |
697 | 0 | .or_else(|| { |
698 | 0 | self.sup() |
699 | 0 | .and_then(|sup| sup.lookup_offset_id(id)) |
700 | 0 | .map(|(_, id, offset)| (true, id, offset)) |
701 | 0 | }) |
702 | 0 | } |
703 | | |
704 | | /// Returns a string representation of the given error. |
705 | | /// |
706 | | /// This uses information from the DWARF sections to provide more information in some cases. |
707 | 0 | pub fn format_error(&self, err: Error) -> String { |
708 | 0 | #[allow(clippy::single_match)] |
709 | 0 | match err { |
710 | 0 | Error::UnexpectedEof(id) => match self.lookup_offset_id(id) { |
711 | 0 | Some((sup, section, offset)) => { |
712 | 0 | return format!( |
713 | 0 | "{} at {}{}+0x{:x}", |
714 | 0 | err, |
715 | 0 | section.name(), |
716 | 0 | if sup { "(sup)" } else { "" }, |
717 | 0 | offset.into_u64(), |
718 | | ); |
719 | | } |
720 | 0 | None => {} |
721 | | }, |
722 | 0 | _ => {} |
723 | | } |
724 | 0 | err.description().into() |
725 | 0 | } |
726 | | } |
727 | | |
728 | | impl<R: Clone> Dwarf<R> { |
729 | | /// Assuming `self` was loaded from a .dwo, take the appropriate |
730 | | /// sections from `parent` (which contains the skeleton unit for this |
731 | | /// dwo) such as `.debug_addr` and merge them into this `Dwarf`. |
732 | 0 | pub fn make_dwo(&mut self, parent: &Dwarf<R>) { |
733 | 0 | self.file_type = DwarfFileType::Dwo; |
734 | 0 | // These sections are always taken from the parent file and not the dwo. |
735 | 0 | self.debug_addr = parent.debug_addr.clone(); |
736 | 0 | // .debug_rnglists comes from the DWO, .debug_ranges comes from the |
737 | 0 | // parent file. |
738 | 0 | self.ranges |
739 | 0 | .set_debug_ranges(parent.ranges.debug_ranges().clone()); |
740 | 0 | self.sup = parent.sup.clone(); |
741 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Dwarf<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::make_dwo Unexecuted instantiation: <gimli::read::dwarf::Dwarf<_>>::make_dwo |
742 | | } |
743 | | |
744 | | /// The sections from a `.dwp` file. |
745 | | /// |
746 | | /// This is useful for storing sections when `T` does not implement `Reader`. |
747 | | /// It can be used to create a `DwarfPackage` that references the data in `self`. |
748 | | /// If `T` does implement `Reader`, then use `DwarfPackage` directly. |
749 | | /// |
750 | | /// ## Example Usage |
751 | | /// |
752 | | /// It can be useful to load DWARF sections into owned data structures, |
753 | | /// such as `Vec`. However, we do not implement the `Reader` trait |
754 | | /// for `Vec`, because it would be very inefficient, but this trait |
755 | | /// is required for all of the methods that parse the DWARF data. |
756 | | /// So we first load the DWARF sections into `Vec`s, and then use |
757 | | /// `borrow` to create `Reader`s that reference the data. |
758 | | /// |
759 | | /// ```rust,no_run |
760 | | /// # fn example() -> Result<(), gimli::Error> { |
761 | | /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; |
762 | | /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. |
763 | | /// let dwp_sections: gimli::DwarfPackageSections<Vec<u8>> = gimli::DwarfPackageSections::load(loader)?; |
764 | | /// // Create references to the DWARF sections. |
765 | | /// let dwp: gimli::DwarfPackage<_> = dwp_sections.borrow( |
766 | | /// |section| gimli::EndianSlice::new(§ion, gimli::LittleEndian), |
767 | | /// gimli::EndianSlice::new(&[], gimli::LittleEndian), |
768 | | /// )?; |
769 | | /// # unreachable!() |
770 | | /// # } |
771 | | /// ``` |
772 | | #[derive(Debug)] |
773 | | pub struct DwarfPackageSections<T> { |
774 | | /// The `.debug_cu_index` section. |
775 | | pub cu_index: DebugCuIndex<T>, |
776 | | /// The `.debug_tu_index` section. |
777 | | pub tu_index: DebugTuIndex<T>, |
778 | | /// The `.debug_abbrev.dwo` section. |
779 | | pub debug_abbrev: DebugAbbrev<T>, |
780 | | /// The `.debug_info.dwo` section. |
781 | | pub debug_info: DebugInfo<T>, |
782 | | /// The `.debug_line.dwo` section. |
783 | | pub debug_line: DebugLine<T>, |
784 | | /// The `.debug_str.dwo` section. |
785 | | pub debug_str: DebugStr<T>, |
786 | | /// The `.debug_str_offsets.dwo` section. |
787 | | pub debug_str_offsets: DebugStrOffsets<T>, |
788 | | /// The `.debug_loc.dwo` section. |
789 | | /// |
790 | | /// Only present when using GNU split-dwarf extension to DWARF 4. |
791 | | pub debug_loc: DebugLoc<T>, |
792 | | /// The `.debug_loclists.dwo` section. |
793 | | pub debug_loclists: DebugLocLists<T>, |
794 | | /// The `.debug_rnglists.dwo` section. |
795 | | pub debug_rnglists: DebugRngLists<T>, |
796 | | /// The `.debug_types.dwo` section. |
797 | | /// |
798 | | /// Only present when using GNU split-dwarf extension to DWARF 4. |
799 | | pub debug_types: DebugTypes<T>, |
800 | | } |
801 | | |
802 | | impl<T> DwarfPackageSections<T> { |
803 | | /// Try to load the `.dwp` sections using the given loader function. |
804 | | /// |
805 | | /// `section` loads a DWARF section from the object file. |
806 | | /// It should return an empty section if the section does not exist. |
807 | 0 | pub fn load<F, E>(mut section: F) -> core::result::Result<Self, E> |
808 | 0 | where |
809 | 0 | F: FnMut(SectionId) -> core::result::Result<T, E>, |
810 | 0 | E: From<Error>, |
811 | 0 | { |
812 | 0 | Ok(DwarfPackageSections { |
813 | 0 | // Section types are inferred. |
814 | 0 | cu_index: Section::load(&mut section)?, |
815 | 0 | tu_index: Section::load(&mut section)?, |
816 | 0 | debug_abbrev: Section::load(&mut section)?, |
817 | 0 | debug_info: Section::load(&mut section)?, |
818 | 0 | debug_line: Section::load(&mut section)?, |
819 | 0 | debug_str: Section::load(&mut section)?, |
820 | 0 | debug_str_offsets: Section::load(&mut section)?, |
821 | 0 | debug_loc: Section::load(&mut section)?, |
822 | 0 | debug_loclists: Section::load(&mut section)?, |
823 | 0 | debug_rnglists: Section::load(&mut section)?, |
824 | 0 | debug_types: Section::load(&mut section)?, |
825 | | }) |
826 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackageSections<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#2}, gimli::read::Error> Unexecuted instantiation: <gimli::read::dwarf::DwarfPackageSections<_>>::load::<_, _> |
827 | | |
828 | | /// Create a `DwarfPackage` structure that references the data in `self`. |
829 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F, empty: R) -> Result<DwarfPackage<R>> |
830 | 0 | where |
831 | 0 | F: FnMut(&'a T) -> R, |
832 | 0 | R: Reader, |
833 | 0 | { |
834 | 0 | DwarfPackage::from_sections( |
835 | 0 | DwarfPackageSections { |
836 | 0 | cu_index: self.cu_index.borrow(&mut borrow), |
837 | 0 | tu_index: self.tu_index.borrow(&mut borrow), |
838 | 0 | debug_abbrev: self.debug_abbrev.borrow(&mut borrow), |
839 | 0 | debug_info: self.debug_info.borrow(&mut borrow), |
840 | 0 | debug_line: self.debug_line.borrow(&mut borrow), |
841 | 0 | debug_str: self.debug_str.borrow(&mut borrow), |
842 | 0 | debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), |
843 | 0 | debug_loc: self.debug_loc.borrow(&mut borrow), |
844 | 0 | debug_loclists: self.debug_loclists.borrow(&mut borrow), |
845 | 0 | debug_rnglists: self.debug_rnglists.borrow(&mut borrow), |
846 | 0 | debug_types: self.debug_types.borrow(&mut borrow), |
847 | 0 | }, |
848 | 0 | empty, |
849 | 0 | ) |
850 | 0 | } |
851 | | } |
852 | | |
853 | | /// The sections from a `.dwp` file, with parsed indices. |
854 | | #[derive(Debug)] |
855 | | pub struct DwarfPackage<R: Reader> { |
856 | | /// The compilation unit index in the `.debug_cu_index` section. |
857 | | pub cu_index: UnitIndex<R>, |
858 | | |
859 | | /// The type unit index in the `.debug_tu_index` section. |
860 | | pub tu_index: UnitIndex<R>, |
861 | | |
862 | | /// The `.debug_abbrev.dwo` section. |
863 | | pub debug_abbrev: DebugAbbrev<R>, |
864 | | |
865 | | /// The `.debug_info.dwo` section. |
866 | | pub debug_info: DebugInfo<R>, |
867 | | |
868 | | /// The `.debug_line.dwo` section. |
869 | | pub debug_line: DebugLine<R>, |
870 | | |
871 | | /// The `.debug_str.dwo` section. |
872 | | pub debug_str: DebugStr<R>, |
873 | | |
874 | | /// The `.debug_str_offsets.dwo` section. |
875 | | pub debug_str_offsets: DebugStrOffsets<R>, |
876 | | |
877 | | /// The `.debug_loc.dwo` section. |
878 | | /// |
879 | | /// Only present when using GNU split-dwarf extension to DWARF 4. |
880 | | pub debug_loc: DebugLoc<R>, |
881 | | |
882 | | /// The `.debug_loclists.dwo` section. |
883 | | pub debug_loclists: DebugLocLists<R>, |
884 | | |
885 | | /// The `.debug_rnglists.dwo` section. |
886 | | pub debug_rnglists: DebugRngLists<R>, |
887 | | |
888 | | /// The `.debug_types.dwo` section. |
889 | | /// |
890 | | /// Only present when using GNU split-dwarf extension to DWARF 4. |
891 | | pub debug_types: DebugTypes<R>, |
892 | | |
893 | | /// An empty section. |
894 | | /// |
895 | | /// Used when creating `Dwarf<R>`. |
896 | | pub empty: R, |
897 | | } |
898 | | |
899 | | impl<R: Reader> DwarfPackage<R> { |
900 | | /// Try to load the `.dwp` sections using the given loader function. |
901 | | /// |
902 | | /// `section` loads a DWARF section from the object file. |
903 | | /// It should return an empty section if the section does not exist. |
904 | 0 | pub fn load<F, E>(section: F, empty: R) -> core::result::Result<Self, E> |
905 | 0 | where |
906 | 0 | F: FnMut(SectionId) -> core::result::Result<R, E>, |
907 | 0 | E: From<Error>, |
908 | 0 | { |
909 | 0 | let sections = DwarfPackageSections::load(section)?; |
910 | 0 | Ok(Self::from_sections(sections, empty)?) |
911 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::load::<<backtrace::symbolize::gimli::Context>::new::{closure#2}, gimli::read::Error> Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<_>>::load::<_, _> |
912 | | |
913 | | /// Create a `DwarfPackage` structure from the given sections. |
914 | 0 | fn from_sections(sections: DwarfPackageSections<R>, empty: R) -> Result<Self> { |
915 | 0 | Ok(DwarfPackage { |
916 | 0 | cu_index: sections.cu_index.index()?, |
917 | 0 | tu_index: sections.tu_index.index()?, |
918 | 0 | debug_abbrev: sections.debug_abbrev, |
919 | 0 | debug_info: sections.debug_info, |
920 | 0 | debug_line: sections.debug_line, |
921 | 0 | debug_str: sections.debug_str, |
922 | 0 | debug_str_offsets: sections.debug_str_offsets, |
923 | 0 | debug_loc: sections.debug_loc, |
924 | 0 | debug_loclists: sections.debug_loclists, |
925 | 0 | debug_rnglists: sections.debug_rnglists, |
926 | 0 | debug_types: sections.debug_types, |
927 | 0 | empty, |
928 | | }) |
929 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from_sections Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<_>>::from_sections |
930 | | |
931 | | /// Find the compilation unit with the given DWO identifier and return its section |
932 | | /// contributions. |
933 | | /// |
934 | | /// ## Example Usage |
935 | | /// |
936 | | /// ```rust,no_run |
937 | | /// # fn example<R: gimli::Reader>( |
938 | | /// # dwarf: &gimli::Dwarf<R>, |
939 | | /// # dwp: &gimli::DwarfPackage<R>, |
940 | | /// # dwo_id: gimli::DwoId, |
941 | | /// # ) -> Result<(), gimli::Error> { |
942 | | /// if let Some(dwo) = dwp.find_cu(dwo_id, dwarf)? { |
943 | | /// let dwo_header = dwo.units().next()?.expect("DWO should have one unit"); |
944 | | /// let dwo_unit = dwo.unit(dwo_header)?; |
945 | | /// // Do something with `dwo_unit`. |
946 | | /// } |
947 | | /// # unreachable!() |
948 | | /// # } |
949 | 0 | pub fn find_cu(&self, id: DwoId, parent: &Dwarf<R>) -> Result<Option<Dwarf<R>>> { |
950 | 0 | let row = match self.cu_index.find(id.0) { |
951 | 0 | Some(row) => row, |
952 | 0 | None => return Ok(None), |
953 | | }; |
954 | 0 | self.cu_sections(row, parent).map(Some) |
955 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_cu Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<_>>::find_cu |
956 | | |
957 | | /// Find the type unit with the given type signature and return its section |
958 | | /// contributions. |
959 | 0 | pub fn find_tu( |
960 | 0 | &self, |
961 | 0 | signature: DebugTypeSignature, |
962 | 0 | parent: &Dwarf<R>, |
963 | 0 | ) -> Result<Option<Dwarf<R>>> { |
964 | 0 | let row = match self.tu_index.find(signature.0) { |
965 | 0 | Some(row) => row, |
966 | 0 | None => return Ok(None), |
967 | | }; |
968 | 0 | self.tu_sections(row, parent).map(Some) |
969 | 0 | } |
970 | | |
971 | | /// Return the section contributions of the compilation unit at the given index. |
972 | | /// |
973 | | /// The index must be in the range `1..cu_index.unit_count`. |
974 | | /// |
975 | | /// This function should only be needed by low level parsers. |
976 | 0 | pub fn cu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> { |
977 | 0 | self.sections(self.cu_index.sections(index)?, parent) |
978 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::cu_sections Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<_>>::cu_sections |
979 | | |
980 | | /// Return the section contributions of the compilation unit at the given index. |
981 | | /// |
982 | | /// The index must be in the range `1..tu_index.unit_count`. |
983 | | /// |
984 | | /// This function should only be needed by low level parsers. |
985 | 0 | pub fn tu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> { |
986 | 0 | self.sections(self.tu_index.sections(index)?, parent) |
987 | 0 | } |
988 | | |
989 | | /// Return the section contributions of a unit. |
990 | | /// |
991 | | /// This function should only be needed by low level parsers. |
992 | 0 | pub fn sections( |
993 | 0 | &self, |
994 | 0 | sections: UnitIndexSectionIterator<R>, |
995 | 0 | parent: &Dwarf<R>, |
996 | 0 | ) -> Result<Dwarf<R>> { |
997 | 0 | let mut abbrev_offset = 0; |
998 | 0 | let mut abbrev_size = 0; |
999 | 0 | let mut info_offset = 0; |
1000 | 0 | let mut info_size = 0; |
1001 | 0 | let mut line_offset = 0; |
1002 | 0 | let mut line_size = 0; |
1003 | 0 | let mut loc_offset = 0; |
1004 | 0 | let mut loc_size = 0; |
1005 | 0 | let mut loclists_offset = 0; |
1006 | 0 | let mut loclists_size = 0; |
1007 | 0 | let mut str_offsets_offset = 0; |
1008 | 0 | let mut str_offsets_size = 0; |
1009 | 0 | let mut rnglists_offset = 0; |
1010 | 0 | let mut rnglists_size = 0; |
1011 | 0 | let mut types_offset = 0; |
1012 | 0 | let mut types_size = 0; |
1013 | 0 | for section in sections { |
1014 | 0 | match section.section { |
1015 | 0 | SectionId::DebugAbbrev => { |
1016 | 0 | abbrev_offset = section.offset; |
1017 | 0 | abbrev_size = section.size; |
1018 | 0 | } |
1019 | 0 | SectionId::DebugInfo => { |
1020 | 0 | info_offset = section.offset; |
1021 | 0 | info_size = section.size; |
1022 | 0 | } |
1023 | 0 | SectionId::DebugLine => { |
1024 | 0 | line_offset = section.offset; |
1025 | 0 | line_size = section.size; |
1026 | 0 | } |
1027 | 0 | SectionId::DebugLoc => { |
1028 | 0 | loc_offset = section.offset; |
1029 | 0 | loc_size = section.size; |
1030 | 0 | } |
1031 | 0 | SectionId::DebugLocLists => { |
1032 | 0 | loclists_offset = section.offset; |
1033 | 0 | loclists_size = section.size; |
1034 | 0 | } |
1035 | 0 | SectionId::DebugStrOffsets => { |
1036 | 0 | str_offsets_offset = section.offset; |
1037 | 0 | str_offsets_size = section.size; |
1038 | 0 | } |
1039 | 0 | SectionId::DebugRngLists => { |
1040 | 0 | rnglists_offset = section.offset; |
1041 | 0 | rnglists_size = section.size; |
1042 | 0 | } |
1043 | 0 | SectionId::DebugTypes => { |
1044 | 0 | types_offset = section.offset; |
1045 | 0 | types_size = section.size; |
1046 | 0 | } |
1047 | 0 | SectionId::DebugMacro | SectionId::DebugMacinfo => { |
1048 | 0 | // These are valid but we can't parse these yet. |
1049 | 0 | } |
1050 | 0 | _ => return Err(Error::UnknownIndexSection), |
1051 | | } |
1052 | | } |
1053 | | |
1054 | 0 | let debug_abbrev = self.debug_abbrev.dwp_range(abbrev_offset, abbrev_size)?; |
1055 | 0 | let debug_info = self.debug_info.dwp_range(info_offset, info_size)?; |
1056 | 0 | let debug_line = self.debug_line.dwp_range(line_offset, line_size)?; |
1057 | 0 | let debug_loc = self.debug_loc.dwp_range(loc_offset, loc_size)?; |
1058 | 0 | let debug_loclists = self |
1059 | 0 | .debug_loclists |
1060 | 0 | .dwp_range(loclists_offset, loclists_size)?; |
1061 | 0 | let debug_str_offsets = self |
1062 | 0 | .debug_str_offsets |
1063 | 0 | .dwp_range(str_offsets_offset, str_offsets_size)?; |
1064 | 0 | let debug_rnglists = self |
1065 | 0 | .debug_rnglists |
1066 | 0 | .dwp_range(rnglists_offset, rnglists_size)?; |
1067 | 0 | let debug_types = self.debug_types.dwp_range(types_offset, types_size)?; |
1068 | | |
1069 | 0 | let debug_str = self.debug_str.clone(); |
1070 | 0 |
|
1071 | 0 | let debug_addr = parent.debug_addr.clone(); |
1072 | 0 | let debug_ranges = parent.ranges.debug_ranges().clone(); |
1073 | 0 |
|
1074 | 0 | let debug_aranges = self.empty.clone().into(); |
1075 | 0 | let debug_line_str = self.empty.clone().into(); |
1076 | 0 |
|
1077 | 0 | Ok(Dwarf { |
1078 | 0 | debug_abbrev, |
1079 | 0 | debug_addr, |
1080 | 0 | debug_aranges, |
1081 | 0 | debug_info, |
1082 | 0 | debug_line, |
1083 | 0 | debug_line_str, |
1084 | 0 | debug_str, |
1085 | 0 | debug_str_offsets, |
1086 | 0 | debug_types, |
1087 | 0 | locations: LocationLists::new(debug_loc, debug_loclists), |
1088 | 0 | ranges: RangeLists::new(debug_ranges, debug_rnglists), |
1089 | 0 | file_type: DwarfFileType::Dwo, |
1090 | 0 | sup: parent.sup.clone(), |
1091 | 0 | abbreviations_cache: AbbreviationsCache::new(), |
1092 | 0 | }) |
1093 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::sections Unexecuted instantiation: <gimli::read::dwarf::DwarfPackage<_>>::sections |
1094 | | } |
1095 | | |
1096 | | /// All of the commonly used information for a unit in the `.debug_info` or `.debug_types` |
1097 | | /// sections. |
1098 | | #[derive(Debug)] |
1099 | | pub struct Unit<R, Offset = <R as Reader>::Offset> |
1100 | | where |
1101 | | R: Reader<Offset = Offset>, |
1102 | | Offset: ReaderOffset, |
1103 | | { |
1104 | | /// The header of the unit. |
1105 | | pub header: UnitHeader<R, Offset>, |
1106 | | |
1107 | | /// The parsed abbreviations for the unit. |
1108 | | pub abbreviations: Arc<Abbreviations>, |
1109 | | |
1110 | | /// The `DW_AT_name` attribute of the unit. |
1111 | | pub name: Option<R>, |
1112 | | |
1113 | | /// The `DW_AT_comp_dir` attribute of the unit. |
1114 | | pub comp_dir: Option<R>, |
1115 | | |
1116 | | /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0. |
1117 | | pub low_pc: u64, |
1118 | | |
1119 | | /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0. |
1120 | | pub str_offsets_base: DebugStrOffsetsBase<Offset>, |
1121 | | |
1122 | | /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0. |
1123 | | pub addr_base: DebugAddrBase<Offset>, |
1124 | | |
1125 | | /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0. |
1126 | | pub loclists_base: DebugLocListsBase<Offset>, |
1127 | | |
1128 | | /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0. |
1129 | | pub rnglists_base: DebugRngListsBase<Offset>, |
1130 | | |
1131 | | /// The line number program of the unit. |
1132 | | pub line_program: Option<IncompleteLineProgram<R, Offset>>, |
1133 | | |
1134 | | /// The DWO ID of a skeleton unit or split compilation unit. |
1135 | | pub dwo_id: Option<DwoId>, |
1136 | | } |
1137 | | |
1138 | | impl<R: Reader> Unit<R> { |
1139 | | /// Construct a new `Unit` from the given unit header. |
1140 | | #[inline] |
1141 | 0 | pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> { |
1142 | 0 | let abbreviations = dwarf.abbreviations(&header)?; |
1143 | 0 | Self::new_with_abbreviations(dwarf, header, abbreviations) |
1144 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::new Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::new |
1145 | | |
1146 | | /// Construct a new `Unit` from the given unit header and abbreviations. |
1147 | | /// |
1148 | | /// The abbreviations for this call can be obtained using `dwarf.abbreviations(&header)`. |
1149 | | /// The caller may implement caching to reuse the `Abbreviations` across units with the |
1150 | | /// same `header.debug_abbrev_offset()` value. |
1151 | | #[inline] |
1152 | 0 | pub fn new_with_abbreviations( |
1153 | 0 | dwarf: &Dwarf<R>, |
1154 | 0 | header: UnitHeader<R>, |
1155 | 0 | abbreviations: Arc<Abbreviations>, |
1156 | 0 | ) -> Result<Self> { |
1157 | 0 | let mut unit = Unit { |
1158 | 0 | abbreviations, |
1159 | 0 | name: None, |
1160 | 0 | comp_dir: None, |
1161 | 0 | low_pc: 0, |
1162 | 0 | str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file( |
1163 | 0 | header.encoding(), |
1164 | 0 | dwarf.file_type, |
1165 | 0 | ), |
1166 | 0 | // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided. |
1167 | 0 | addr_base: DebugAddrBase(R::Offset::from_u8(0)), |
1168 | 0 | loclists_base: DebugLocListsBase::default_for_encoding_and_file( |
1169 | 0 | header.encoding(), |
1170 | 0 | dwarf.file_type, |
1171 | 0 | ), |
1172 | 0 | rnglists_base: DebugRngListsBase::default_for_encoding_and_file( |
1173 | 0 | header.encoding(), |
1174 | 0 | dwarf.file_type, |
1175 | 0 | ), |
1176 | 0 | line_program: None, |
1177 | 0 | dwo_id: match header.type_() { |
1178 | 0 | UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => Some(dwo_id), |
1179 | 0 | _ => None, |
1180 | | }, |
1181 | 0 | header, |
1182 | 0 | }; |
1183 | 0 | let mut name = None; |
1184 | 0 | let mut comp_dir = None; |
1185 | 0 | let mut line_program_offset = None; |
1186 | 0 | let mut low_pc_attr = None; |
1187 | 0 |
|
1188 | 0 | { |
1189 | 0 | let mut cursor = unit.header.entries(&unit.abbreviations); |
1190 | 0 | cursor.next_dfs()?; |
1191 | 0 | let root = cursor.current().ok_or(Error::MissingUnitDie)?; |
1192 | 0 | let mut attrs = root.attrs(); |
1193 | 0 | while let Some(attr) = attrs.next()? { |
1194 | 0 | match attr.name() { |
1195 | 0 | constants::DW_AT_name => { |
1196 | 0 | name = Some(attr.value()); |
1197 | 0 | } |
1198 | 0 | constants::DW_AT_comp_dir => { |
1199 | 0 | comp_dir = Some(attr.value()); |
1200 | 0 | } |
1201 | 0 | constants::DW_AT_low_pc => { |
1202 | 0 | low_pc_attr = Some(attr.value()); |
1203 | 0 | } |
1204 | | constants::DW_AT_stmt_list => { |
1205 | 0 | if let AttributeValue::DebugLineRef(offset) = attr.value() { |
1206 | 0 | line_program_offset = Some(offset); |
1207 | 0 | } |
1208 | | } |
1209 | | constants::DW_AT_str_offsets_base => { |
1210 | 0 | if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() { |
1211 | 0 | unit.str_offsets_base = base; |
1212 | 0 | } |
1213 | | } |
1214 | | constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { |
1215 | 0 | if let AttributeValue::DebugAddrBase(base) = attr.value() { |
1216 | 0 | unit.addr_base = base; |
1217 | 0 | } |
1218 | | } |
1219 | | constants::DW_AT_loclists_base => { |
1220 | 0 | if let AttributeValue::DebugLocListsBase(base) = attr.value() { |
1221 | 0 | unit.loclists_base = base; |
1222 | 0 | } |
1223 | | } |
1224 | | constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { |
1225 | 0 | if let AttributeValue::DebugRngListsBase(base) = attr.value() { |
1226 | 0 | unit.rnglists_base = base; |
1227 | 0 | } |
1228 | | } |
1229 | | constants::DW_AT_GNU_dwo_id => { |
1230 | 0 | if unit.dwo_id.is_none() { |
1231 | 0 | if let AttributeValue::DwoId(dwo_id) = attr.value() { |
1232 | 0 | unit.dwo_id = Some(dwo_id); |
1233 | 0 | } |
1234 | 0 | } |
1235 | | } |
1236 | 0 | _ => {} |
1237 | | } |
1238 | | } |
1239 | | } |
1240 | | |
1241 | 0 | unit.name = match name { |
1242 | 0 | Some(val) => dwarf.attr_string(&unit, val).ok(), |
1243 | 0 | None => None, |
1244 | | }; |
1245 | 0 | unit.comp_dir = match comp_dir { |
1246 | 0 | Some(val) => dwarf.attr_string(&unit, val).ok(), |
1247 | 0 | None => None, |
1248 | | }; |
1249 | 0 | unit.line_program = match line_program_offset { |
1250 | 0 | Some(offset) => Some(dwarf.debug_line.program( |
1251 | 0 | offset, |
1252 | 0 | unit.header.address_size(), |
1253 | 0 | unit.comp_dir.clone(), |
1254 | 0 | unit.name.clone(), |
1255 | 0 | )?), |
1256 | 0 | None => None, |
1257 | | }; |
1258 | 0 | if let Some(low_pc_attr) = low_pc_attr { |
1259 | 0 | if let Some(addr) = dwarf.attr_address(&unit, low_pc_attr)? { |
1260 | 0 | unit.low_pc = addr; |
1261 | 0 | } |
1262 | 0 | } |
1263 | 0 | Ok(unit) |
1264 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::new_with_abbreviations Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::new_with_abbreviations |
1265 | | |
1266 | | /// Return the encoding parameters for this unit. |
1267 | | #[inline] |
1268 | 0 | pub fn encoding(&self) -> Encoding { |
1269 | 0 | self.header.encoding() |
1270 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::encoding Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::encoding |
1271 | | |
1272 | | /// Read the `DebuggingInformationEntry` at the given offset. |
1273 | 0 | pub fn entry(&self, offset: UnitOffset<R::Offset>) -> Result<DebuggingInformationEntry<R>> { |
1274 | 0 | self.header.entry(&self.abbreviations, offset) |
1275 | 0 | } |
1276 | | |
1277 | | /// Navigate this unit's `DebuggingInformationEntry`s. |
1278 | | #[inline] |
1279 | 0 | pub fn entries(&self) -> EntriesCursor<R> { |
1280 | 0 | self.header.entries(&self.abbreviations) |
1281 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::entries Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::entries |
1282 | | |
1283 | | /// Navigate this unit's `DebuggingInformationEntry`s |
1284 | | /// starting at the given offset. |
1285 | | #[inline] |
1286 | 0 | pub fn entries_at_offset(&self, offset: UnitOffset<R::Offset>) -> Result<EntriesCursor<R>> { |
1287 | 0 | self.header.entries_at_offset(&self.abbreviations, offset) |
1288 | 0 | } |
1289 | | |
1290 | | /// Navigate this unit's `DebuggingInformationEntry`s as a tree |
1291 | | /// starting at the given offset. |
1292 | | #[inline] |
1293 | 0 | pub fn entries_tree(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesTree<R>> { |
1294 | 0 | self.header.entries_tree(&self.abbreviations, offset) |
1295 | 0 | } |
1296 | | |
1297 | | /// Read the raw data that defines the Debugging Information Entries. |
1298 | | #[inline] |
1299 | 0 | pub fn entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>> { |
1300 | 0 | self.header.entries_raw(&self.abbreviations, offset) |
1301 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::entries_raw Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::entries_raw |
1302 | | |
1303 | | /// Copy attributes that are subject to relocation from another unit. This is intended |
1304 | | /// to be used to copy attributes from a skeleton compilation unit to the corresponding |
1305 | | /// split compilation unit. |
1306 | 0 | pub fn copy_relocated_attributes(&mut self, other: &Unit<R>) { |
1307 | 0 | self.low_pc = other.low_pc; |
1308 | 0 | self.addr_base = other.addr_base; |
1309 | 0 | if self.header.version() < 5 { |
1310 | 0 | self.rnglists_base = other.rnglists_base; |
1311 | 0 | } |
1312 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::copy_relocated_attributes Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::copy_relocated_attributes |
1313 | | |
1314 | | /// Find the dwo name (if any) for this unit, automatically handling the differences |
1315 | | /// between the standardized DWARF 5 split DWARF format and the pre-DWARF 5 GNU |
1316 | | /// extension. |
1317 | | /// |
1318 | | /// The returned value is relative to this unit's `comp_dir`. |
1319 | 0 | pub fn dwo_name(&self) -> Result<Option<AttributeValue<R>>> { |
1320 | 0 | let mut entries = self.entries(); |
1321 | 0 | entries.next_entry()?; |
1322 | 0 | let entry = entries.current().ok_or(Error::MissingUnitDie)?; |
1323 | 0 | if self.header.version() < 5 { |
1324 | 0 | entry.attr_value(constants::DW_AT_GNU_dwo_name) |
1325 | | } else { |
1326 | 0 | entry.attr_value(constants::DW_AT_dwo_name) |
1327 | | } |
1328 | 0 | } Unexecuted instantiation: <gimli::read::dwarf::Unit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwo_name Unexecuted instantiation: <gimli::read::dwarf::Unit<_>>::dwo_name |
1329 | | } |
1330 | | |
1331 | | impl<T: ReaderOffset> UnitSectionOffset<T> { |
1332 | | /// Convert an offset to be relative to the start of the given unit, |
1333 | | /// instead of relative to the start of the section. |
1334 | | /// Returns `None` if the offset is not within the unit entries. |
1335 | 0 | pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>> |
1336 | 0 | where |
1337 | 0 | R: Reader<Offset = T>, |
1338 | 0 | { |
1339 | 0 | let (offset, unit_offset) = match (self, unit.header.offset()) { |
1340 | | ( |
1341 | 0 | UnitSectionOffset::DebugInfoOffset(offset), |
1342 | 0 | UnitSectionOffset::DebugInfoOffset(unit_offset), |
1343 | 0 | ) => (offset.0, unit_offset.0), |
1344 | | ( |
1345 | 0 | UnitSectionOffset::DebugTypesOffset(offset), |
1346 | 0 | UnitSectionOffset::DebugTypesOffset(unit_offset), |
1347 | 0 | ) => (offset.0, unit_offset.0), |
1348 | 0 | _ => return None, |
1349 | | }; |
1350 | 0 | let offset = match offset.checked_sub(unit_offset) { |
1351 | 0 | Some(offset) => UnitOffset(offset), |
1352 | 0 | None => return None, |
1353 | | }; |
1354 | 0 | if !unit.header.is_valid_offset(offset) { |
1355 | 0 | return None; |
1356 | 0 | } |
1357 | 0 | Some(offset) |
1358 | 0 | } |
1359 | | } |
1360 | | |
1361 | | impl<T: ReaderOffset> UnitOffset<T> { |
1362 | | /// Convert an offset to be relative to the start of the .debug_info section, |
1363 | | /// instead of relative to the start of the given compilation unit. |
1364 | | /// |
1365 | | /// Does not check that the offset is valid. |
1366 | 0 | pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T> |
1367 | 0 | where |
1368 | 0 | R: Reader<Offset = T>, |
1369 | 0 | { |
1370 | 0 | match unit.header.offset() { |
1371 | 0 | UnitSectionOffset::DebugInfoOffset(unit_offset) => { |
1372 | 0 | DebugInfoOffset(unit_offset.0 + self.0).into() |
1373 | | } |
1374 | 0 | UnitSectionOffset::DebugTypesOffset(unit_offset) => { |
1375 | 0 | DebugTypesOffset(unit_offset.0 + self.0).into() |
1376 | | } |
1377 | | } |
1378 | 0 | } |
1379 | | } |
1380 | | |
1381 | | /// An iterator for the address ranges of a `DebuggingInformationEntry`. |
1382 | | /// |
1383 | | /// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`. |
1384 | | #[derive(Debug)] |
1385 | | pub struct RangeIter<R: Reader>(RangeIterInner<R>); |
1386 | | |
1387 | | #[derive(Debug)] |
1388 | | enum RangeIterInner<R: Reader> { |
1389 | | Single(Option<Range>), |
1390 | | List(RngListIter<R>), |
1391 | | } |
1392 | | |
1393 | | impl<R: Reader> Default for RangeIter<R> { |
1394 | 0 | fn default() -> Self { |
1395 | 0 | RangeIter(RangeIterInner::Single(None)) |
1396 | 0 | } |
1397 | | } |
1398 | | |
1399 | | impl<R: Reader> RangeIter<R> { |
1400 | | /// Advance the iterator to the next range. |
1401 | 0 | pub fn next(&mut self) -> Result<Option<Range>> { |
1402 | 0 | match self.0 { |
1403 | 0 | RangeIterInner::Single(ref mut range) => Ok(range.take()), |
1404 | 0 | RangeIterInner::List(ref mut list) => list.next(), |
1405 | | } |
1406 | 0 | } |
1407 | | } |
1408 | | |
1409 | | #[cfg(feature = "fallible-iterator")] |
1410 | | impl<R: Reader> fallible_iterator::FallibleIterator for RangeIter<R> { |
1411 | | type Item = Range; |
1412 | | type Error = Error; |
1413 | | |
1414 | | #[inline] |
1415 | | fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { |
1416 | | RangeIter::next(self) |
1417 | | } |
1418 | | } |
1419 | | |
1420 | | #[cfg(test)] |
1421 | | mod tests { |
1422 | | use super::*; |
1423 | | use crate::read::EndianSlice; |
1424 | | use crate::{Endianity, LittleEndian}; |
1425 | | |
1426 | | /// Ensure that `Dwarf<R>` is covariant wrt R. |
1427 | | #[test] |
1428 | | fn test_dwarf_variance() { |
1429 | | /// This only needs to compile. |
1430 | | fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf<EndianSlice<'a, E>>) -> Dwarf<EndianSlice<'b, E>> { |
1431 | | x |
1432 | | } |
1433 | | } |
1434 | | |
1435 | | /// Ensure that `Unit<R>` is covariant wrt R. |
1436 | | #[test] |
1437 | | fn test_dwarf_unit_variance() { |
1438 | | /// This only needs to compile. |
1439 | | fn _f<'a: 'b, 'b, E: Endianity>(x: Unit<EndianSlice<'a, E>>) -> Unit<EndianSlice<'b, E>> { |
1440 | | x |
1441 | | } |
1442 | | } |
1443 | | |
1444 | | #[test] |
1445 | | fn test_send() { |
1446 | | fn assert_is_send<T: Send>() {} |
1447 | | assert_is_send::<Dwarf<EndianSlice<LittleEndian>>>(); |
1448 | | assert_is_send::<Unit<EndianSlice<LittleEndian>>>(); |
1449 | | } |
1450 | | |
1451 | | #[test] |
1452 | | fn test_format_error() { |
1453 | | let dwarf_sections = DwarfSections::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap(); |
1454 | | let sup_sections = DwarfSections::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap(); |
1455 | | let dwarf = dwarf_sections.borrow_with_sup(&sup_sections, |section| { |
1456 | | EndianSlice::new(section, LittleEndian) |
1457 | | }); |
1458 | | |
1459 | | match dwarf.debug_str.get_str(DebugStrOffset(1)) { |
1460 | | Ok(r) => panic!("Unexpected str {:?}", r), |
1461 | | Err(e) => { |
1462 | | assert_eq!( |
1463 | | dwarf.format_error(e), |
1464 | | "Hit the end of input before it was expected at .debug_str+0x1" |
1465 | | ); |
1466 | | } |
1467 | | } |
1468 | | match dwarf.sup().unwrap().debug_str.get_str(DebugStrOffset(1)) { |
1469 | | Ok(r) => panic!("Unexpected str {:?}", r), |
1470 | | Err(e) => { |
1471 | | assert_eq!( |
1472 | | dwarf.format_error(e), |
1473 | | "Hit the end of input before it was expected at .debug_str(sup)+0x1" |
1474 | | ); |
1475 | | } |
1476 | | } |
1477 | | assert_eq!(dwarf.format_error(Error::Io), Error::Io.description()); |
1478 | | } |
1479 | | } |