/rust/registry/src/index.crates.io-6f17d22bba15001f/gimli-0.31.1/src/read/abbrev.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Functions for parsing DWARF debugging abbreviations. |
2 | | |
3 | | use alloc::collections::btree_map; |
4 | | use alloc::sync::Arc; |
5 | | use alloc::vec::Vec; |
6 | | use core::convert::TryFrom; |
7 | | use core::fmt::{self, Debug}; |
8 | | use core::iter::FromIterator; |
9 | | use core::ops::Deref; |
10 | | |
11 | | use crate::common::{DebugAbbrevOffset, Encoding, SectionId}; |
12 | | use crate::constants; |
13 | | use crate::endianity::Endianity; |
14 | | use crate::read::{ |
15 | | DebugInfoUnitHeadersIter, EndianSlice, Error, Reader, ReaderOffset, Result, Section, UnitHeader, |
16 | | }; |
17 | | |
18 | | /// The `DebugAbbrev` struct represents the abbreviations describing |
19 | | /// `DebuggingInformationEntry`s' attribute names and forms found in the |
20 | | /// `.debug_abbrev` section. |
21 | | #[derive(Debug, Default, Clone, Copy)] |
22 | | pub struct DebugAbbrev<R> { |
23 | | debug_abbrev_section: R, |
24 | | } |
25 | | |
26 | | impl<'input, Endian> DebugAbbrev<EndianSlice<'input, Endian>> |
27 | | where |
28 | | Endian: Endianity, |
29 | | { |
30 | | /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` |
31 | | /// section. |
32 | | /// |
33 | | /// It is the caller's responsibility to read the `.debug_abbrev` section and |
34 | | /// present it as a `&[u8]` slice. That means using some ELF loader on |
35 | | /// Linux, a Mach-O loader on macOS, etc. |
36 | | /// |
37 | | /// ``` |
38 | | /// use gimli::{DebugAbbrev, LittleEndian}; |
39 | | /// |
40 | | /// # let buf = [0x00, 0x01, 0x02, 0x03]; |
41 | | /// # let read_debug_abbrev_section_somehow = || &buf; |
42 | | /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); |
43 | | /// ``` |
44 | 0 | pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { |
45 | 0 | Self::from(EndianSlice::new(debug_abbrev_section, endian)) |
46 | 0 | } |
47 | | } |
48 | | |
49 | | impl<R: Reader> DebugAbbrev<R> { |
50 | | /// Parse the abbreviations at the given `offset` within this |
51 | | /// `.debug_abbrev` section. |
52 | | /// |
53 | | /// The `offset` should generally be retrieved from a unit header. |
54 | 0 | pub fn abbreviations( |
55 | 0 | &self, |
56 | 0 | debug_abbrev_offset: DebugAbbrevOffset<R::Offset>, |
57 | 0 | ) -> Result<Abbreviations> { |
58 | 0 | let input = &mut self.debug_abbrev_section.clone(); |
59 | 0 | input.skip(debug_abbrev_offset.0)?; |
60 | 0 | Abbreviations::parse(input) |
61 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::abbreviations Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<_>>::abbreviations |
62 | | } |
63 | | |
64 | | impl<T> DebugAbbrev<T> { |
65 | | /// Create a `DebugAbbrev` section that references the data in `self`. |
66 | | /// |
67 | | /// This is useful when `R` implements `Reader` but `T` does not. |
68 | | /// |
69 | | /// Used by `DwarfSections::borrow`. |
70 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev<R> |
71 | 0 | where |
72 | 0 | F: FnMut(&'a T) -> R, |
73 | 0 | { |
74 | 0 | borrow(&self.debug_abbrev_section).into() |
75 | 0 | } |
76 | | } |
77 | | |
78 | | impl<R> Section<R> for DebugAbbrev<R> { |
79 | 0 | fn id() -> SectionId { |
80 | 0 | SectionId::DebugAbbrev |
81 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::id Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<_> as gimli::read::Section<_>>::id |
82 | | |
83 | 0 | fn reader(&self) -> &R { |
84 | 0 | &self.debug_abbrev_section |
85 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::reader Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<_> as gimli::read::Section<_>>::reader |
86 | | } |
87 | | |
88 | | impl<R> From<R> for DebugAbbrev<R> { |
89 | 0 | fn from(debug_abbrev_section: R) -> Self { |
90 | 0 | DebugAbbrev { |
91 | 0 | debug_abbrev_section, |
92 | 0 | } |
93 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as core::convert::From<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from Unexecuted instantiation: <gimli::read::abbrev::DebugAbbrev<_> as core::convert::From<_>>::from |
94 | | } |
95 | | |
96 | | /// The strategy to use for caching abbreviations. |
97 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
98 | | #[non_exhaustive] |
99 | | pub enum AbbreviationsCacheStrategy { |
100 | | /// Cache abbreviations that are used more than once. |
101 | | /// |
102 | | /// This is useful if the units in the `.debug_info` section will be parsed only once. |
103 | | Duplicates, |
104 | | /// Cache all abbreviations. |
105 | | /// |
106 | | /// This is useful if the units in the `.debug_info` section will be parsed more than once. |
107 | | All, |
108 | | } |
109 | | |
110 | | /// A cache of previously parsed `Abbreviations`. |
111 | | #[derive(Debug, Default)] |
112 | | pub struct AbbreviationsCache { |
113 | | abbreviations: btree_map::BTreeMap<u64, Result<Arc<Abbreviations>>>, |
114 | | } |
115 | | |
116 | | impl AbbreviationsCache { |
117 | | /// Create an empty abbreviations cache. |
118 | 0 | pub fn new() -> Self { |
119 | 0 | Self::default() |
120 | 0 | } |
121 | | |
122 | | /// Parse abbreviations and store them in the cache. |
123 | | /// |
124 | | /// This will iterate over the given units to determine the abbreviations |
125 | | /// offsets. Any existing cache entries are discarded. |
126 | | /// |
127 | | /// Errors during parsing abbreviations are also stored in the cache. |
128 | | /// Errors during iterating over the units are ignored. |
129 | 0 | pub fn populate<R: Reader>( |
130 | 0 | &mut self, |
131 | 0 | strategy: AbbreviationsCacheStrategy, |
132 | 0 | debug_abbrev: &DebugAbbrev<R>, |
133 | 0 | mut units: DebugInfoUnitHeadersIter<R>, |
134 | 0 | ) { |
135 | 0 | let mut offsets = Vec::new(); |
136 | 0 | match strategy { |
137 | | AbbreviationsCacheStrategy::Duplicates => { |
138 | 0 | while let Ok(Some(unit)) = units.next() { |
139 | 0 | offsets.push(unit.debug_abbrev_offset()); |
140 | 0 | } |
141 | 0 | offsets.sort_unstable_by_key(|offset| offset.0); |
142 | 0 | let mut prev_offset = R::Offset::from_u8(0); |
143 | 0 | let mut count = 0; |
144 | 0 | offsets.retain(|offset| { |
145 | 0 | if count == 0 || prev_offset != offset.0 { |
146 | 0 | prev_offset = offset.0; |
147 | 0 | count = 1; |
148 | 0 | } else { |
149 | 0 | count += 1; |
150 | 0 | } |
151 | 0 | count == 2 |
152 | 0 | }); |
153 | 0 | } |
154 | | AbbreviationsCacheStrategy::All => { |
155 | 0 | while let Ok(Some(unit)) = units.next() { |
156 | 0 | offsets.push(unit.debug_abbrev_offset()); |
157 | 0 | } |
158 | 0 | offsets.sort_unstable_by_key(|offset| offset.0); |
159 | 0 | offsets.dedup(); |
160 | 0 | } |
161 | | } |
162 | 0 | self.abbreviations = offsets |
163 | 0 | .into_iter() |
164 | 0 | .map(|offset| { |
165 | 0 | ( |
166 | 0 | offset.0.into_u64(), |
167 | 0 | debug_abbrev.abbreviations(offset).map(Arc::new), |
168 | 0 | ) |
169 | 0 | }) |
170 | 0 | .collect(); |
171 | 0 | } |
172 | | |
173 | | /// Set an entry in the abbreviations cache. |
174 | | /// |
175 | | /// This is only required if you want to manually populate the cache. |
176 | 0 | pub fn set<R: Reader>( |
177 | 0 | &mut self, |
178 | 0 | offset: DebugAbbrevOffset<R::Offset>, |
179 | 0 | abbreviations: Arc<Abbreviations>, |
180 | 0 | ) { |
181 | 0 | self.abbreviations |
182 | 0 | .insert(offset.0.into_u64(), Ok(abbreviations)); |
183 | 0 | } |
184 | | |
185 | | /// Parse the abbreviations at the given offset. |
186 | | /// |
187 | | /// This uses the cache if possible, but does not update it. |
188 | 0 | pub fn get<R: Reader>( |
189 | 0 | &self, |
190 | 0 | debug_abbrev: &DebugAbbrev<R>, |
191 | 0 | offset: DebugAbbrevOffset<R::Offset>, |
192 | 0 | ) -> Result<Arc<Abbreviations>> { |
193 | 0 | match self.abbreviations.get(&offset.0.into_u64()) { |
194 | 0 | Some(entry) => entry.clone(), |
195 | 0 | None => debug_abbrev.abbreviations(offset).map(Arc::new), |
196 | | } |
197 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AbbreviationsCache>::get::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::AbbreviationsCache>::get::<_> |
198 | | } |
199 | | |
200 | | /// A set of type abbreviations. |
201 | | /// |
202 | | /// Construct an `Abbreviations` instance with the |
203 | | /// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) |
204 | | /// method. |
205 | | #[derive(Debug, Default, Clone)] |
206 | | pub struct Abbreviations { |
207 | | vec: Vec<Abbreviation>, |
208 | | map: btree_map::BTreeMap<u64, Abbreviation>, |
209 | | } |
210 | | |
211 | | impl Abbreviations { |
212 | | /// Construct a new, empty set of abbreviations. |
213 | 0 | fn empty() -> Abbreviations { |
214 | 0 | Abbreviations { |
215 | 0 | vec: Vec::new(), |
216 | 0 | map: btree_map::BTreeMap::new(), |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | | /// Insert an abbreviation into the set. |
221 | | /// |
222 | | /// Returns `Ok` if it is the first abbreviation in the set with its code, |
223 | | /// `Err` if the code is a duplicate and there already exists an |
224 | | /// abbreviation in the set with the given abbreviation's code. |
225 | 0 | fn insert(&mut self, abbrev: Abbreviation) -> ::core::result::Result<(), ()> { |
226 | 0 | let code_usize = abbrev.code as usize; |
227 | 0 | if code_usize as u64 == abbrev.code { |
228 | | // Optimize for sequential abbreviation codes by storing them |
229 | | // in a Vec, as long as the map doesn't already contain them. |
230 | | // A potential further optimization would be to allow some |
231 | | // holes in the Vec, but there's no need for that yet. |
232 | 0 | if code_usize - 1 < self.vec.len() { |
233 | 0 | return Err(()); |
234 | 0 | } else if code_usize - 1 == self.vec.len() { |
235 | 0 | if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { |
236 | 0 | return Err(()); |
237 | | } else { |
238 | 0 | self.vec.push(abbrev); |
239 | 0 | return Ok(()); |
240 | | } |
241 | 0 | } |
242 | 0 | } |
243 | 0 | match self.map.entry(abbrev.code) { |
244 | 0 | btree_map::Entry::Occupied(_) => Err(()), |
245 | 0 | btree_map::Entry::Vacant(entry) => { |
246 | 0 | entry.insert(abbrev); |
247 | 0 | Ok(()) |
248 | | } |
249 | | } |
250 | 0 | } |
251 | | |
252 | | /// Get the abbreviation associated with the given code. |
253 | | #[inline] |
254 | 0 | pub fn get(&self, code: u64) -> Option<&Abbreviation> { |
255 | 0 | if let Ok(code) = usize::try_from(code) { |
256 | 0 | let index = code.checked_sub(1)?; |
257 | 0 | if index < self.vec.len() { |
258 | 0 | return Some(&self.vec[index]); |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | 0 | self.map.get(&code) |
263 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviations>::get Unexecuted instantiation: <gimli::read::abbrev::Abbreviations>::get |
264 | | |
265 | | /// Parse a series of abbreviations, terminated by a null abbreviation. |
266 | 0 | fn parse<R: Reader>(input: &mut R) -> Result<Abbreviations> { |
267 | 0 | let mut abbrevs = Abbreviations::empty(); |
268 | | |
269 | 0 | while let Some(abbrev) = Abbreviation::parse(input)? { |
270 | 0 | if abbrevs.insert(abbrev).is_err() { |
271 | 0 | return Err(Error::DuplicateAbbreviationCode); |
272 | 0 | } |
273 | | } |
274 | | |
275 | 0 | Ok(abbrevs) |
276 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviations>::parse::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::Abbreviations>::parse::<_> |
277 | | } |
278 | | |
279 | | /// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: |
280 | | /// its code, tag type, whether it has children, and its set of attributes. |
281 | | #[derive(Debug, Clone, PartialEq, Eq)] |
282 | | pub struct Abbreviation { |
283 | | code: u64, |
284 | | tag: constants::DwTag, |
285 | | has_children: constants::DwChildren, |
286 | | attributes: Attributes, |
287 | | } |
288 | | |
289 | | impl Abbreviation { |
290 | | /// Construct a new `Abbreviation`. |
291 | | /// |
292 | | /// ### Panics |
293 | | /// |
294 | | /// Panics if `code` is `0`. |
295 | 0 | pub(crate) fn new( |
296 | 0 | code: u64, |
297 | 0 | tag: constants::DwTag, |
298 | 0 | has_children: constants::DwChildren, |
299 | 0 | attributes: Attributes, |
300 | 0 | ) -> Abbreviation { |
301 | 0 | assert_ne!(code, 0); |
302 | 0 | Abbreviation { |
303 | 0 | code, |
304 | 0 | tag, |
305 | 0 | has_children, |
306 | 0 | attributes, |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | /// Get this abbreviation's code. |
311 | | #[inline] |
312 | 0 | pub fn code(&self) -> u64 { |
313 | 0 | self.code |
314 | 0 | } |
315 | | |
316 | | /// Get this abbreviation's tag. |
317 | | #[inline] |
318 | 0 | pub fn tag(&self) -> constants::DwTag { |
319 | 0 | self.tag |
320 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::tag Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::tag |
321 | | |
322 | | /// Return true if this abbreviation's type has children, false otherwise. |
323 | | #[inline] |
324 | 0 | pub fn has_children(&self) -> bool { |
325 | 0 | self.has_children == constants::DW_CHILDREN_yes |
326 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::has_children Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::has_children |
327 | | |
328 | | /// Get this abbreviation's attributes. |
329 | | #[inline] |
330 | 0 | pub fn attributes(&self) -> &[AttributeSpecification] { |
331 | 0 | &self.attributes[..] |
332 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::attributes Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::attributes |
333 | | |
334 | | /// Parse an abbreviation's tag. |
335 | 0 | fn parse_tag<R: Reader>(input: &mut R) -> Result<constants::DwTag> { |
336 | 0 | let val = input.read_uleb128_u16()?; |
337 | 0 | if val == 0 { |
338 | 0 | Err(Error::AbbreviationTagZero) |
339 | | } else { |
340 | 0 | Ok(constants::DwTag(val)) |
341 | | } |
342 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_tag::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_tag::<_> |
343 | | |
344 | | /// Parse an abbreviation's "does the type have children?" byte. |
345 | 0 | fn parse_has_children<R: Reader>(input: &mut R) -> Result<constants::DwChildren> { |
346 | 0 | let val = input.read_u8()?; |
347 | 0 | let val = constants::DwChildren(val); |
348 | 0 | if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes { |
349 | 0 | Ok(val) |
350 | | } else { |
351 | 0 | Err(Error::BadHasChildren) |
352 | | } |
353 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_has_children::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_has_children::<_> |
354 | | |
355 | | /// Parse a series of attribute specifications, terminated by a null attribute |
356 | | /// specification. |
357 | 0 | fn parse_attributes<R: Reader>(input: &mut R) -> Result<Attributes> { |
358 | 0 | let mut attrs = Attributes::new(); |
359 | | |
360 | 0 | while let Some(attr) = AttributeSpecification::parse(input)? { |
361 | 0 | attrs.push(attr); |
362 | 0 | } |
363 | | |
364 | 0 | Ok(attrs) |
365 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_attributes::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse_attributes::<_> |
366 | | |
367 | | /// Parse an abbreviation. Return `None` for the null abbreviation, `Some` |
368 | | /// for an actual abbreviation. |
369 | 0 | fn parse<R: Reader>(input: &mut R) -> Result<Option<Abbreviation>> { |
370 | 0 | let code = input.read_uleb128()?; |
371 | 0 | if code == 0 { |
372 | 0 | return Ok(None); |
373 | 0 | } |
374 | | |
375 | 0 | let tag = Self::parse_tag(input)?; |
376 | 0 | let has_children = Self::parse_has_children(input)?; |
377 | 0 | let attributes = Self::parse_attributes(input)?; |
378 | 0 | let abbrev = Abbreviation::new(code, tag, has_children, attributes); |
379 | 0 | Ok(Some(abbrev)) |
380 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::Abbreviation>::parse::<_> |
381 | | } |
382 | | |
383 | | /// A list of attributes found in an `Abbreviation` |
384 | | #[derive(Clone)] |
385 | | pub(crate) enum Attributes { |
386 | | Inline { |
387 | | buf: [AttributeSpecification; MAX_ATTRIBUTES_INLINE], |
388 | | len: usize, |
389 | | }, |
390 | | Heap(Vec<AttributeSpecification>), |
391 | | } |
392 | | |
393 | | // Length of 5 based on benchmark results for both x86-64 and i686. |
394 | | const MAX_ATTRIBUTES_INLINE: usize = 5; |
395 | | |
396 | | impl Attributes { |
397 | | /// Returns a new empty list of attributes |
398 | 0 | fn new() -> Attributes { |
399 | 0 | let default = |
400 | 0 | AttributeSpecification::new(constants::DW_AT_null, constants::DW_FORM_null, None); |
401 | 0 | Attributes::Inline { |
402 | 0 | buf: [default; 5], |
403 | 0 | len: 0, |
404 | 0 | } |
405 | 0 | } |
406 | | |
407 | | /// Pushes a new value onto this list of attributes. |
408 | 0 | fn push(&mut self, attr: AttributeSpecification) { |
409 | 0 | match self { |
410 | 0 | Attributes::Heap(list) => list.push(attr), |
411 | | Attributes::Inline { |
412 | 0 | buf, |
413 | 0 | len: MAX_ATTRIBUTES_INLINE, |
414 | 0 | } => { |
415 | 0 | let mut list = buf.to_vec(); |
416 | 0 | list.push(attr); |
417 | 0 | *self = Attributes::Heap(list); |
418 | 0 | } |
419 | 0 | Attributes::Inline { buf, len } => { |
420 | 0 | buf[*len] = attr; |
421 | 0 | *len += 1; |
422 | 0 | } |
423 | | } |
424 | 0 | } |
425 | | } |
426 | | |
427 | | impl Debug for Attributes { |
428 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
429 | 0 | (**self).fmt(f) |
430 | 0 | } |
431 | | } |
432 | | |
433 | | impl PartialEq for Attributes { |
434 | 0 | fn eq(&self, other: &Attributes) -> bool { |
435 | 0 | **self == **other |
436 | 0 | } |
437 | | } |
438 | | |
439 | | impl Eq for Attributes {} |
440 | | |
441 | | impl Deref for Attributes { |
442 | | type Target = [AttributeSpecification]; |
443 | 0 | fn deref(&self) -> &[AttributeSpecification] { |
444 | 0 | match self { |
445 | 0 | Attributes::Inline { buf, len } => &buf[..*len], |
446 | 0 | Attributes::Heap(list) => list, |
447 | | } |
448 | 0 | } |
449 | | } |
450 | | |
451 | | impl FromIterator<AttributeSpecification> for Attributes { |
452 | 0 | fn from_iter<I>(iter: I) -> Attributes |
453 | 0 | where |
454 | 0 | I: IntoIterator<Item = AttributeSpecification>, |
455 | 0 | { |
456 | 0 | let mut list = Attributes::new(); |
457 | 0 | for item in iter { |
458 | 0 | list.push(item); |
459 | 0 | } |
460 | 0 | list |
461 | 0 | } |
462 | | } |
463 | | |
464 | | impl From<Vec<AttributeSpecification>> for Attributes { |
465 | 0 | fn from(list: Vec<AttributeSpecification>) -> Attributes { |
466 | 0 | Attributes::Heap(list) |
467 | 0 | } |
468 | | } |
469 | | |
470 | | /// The description of an attribute in an abbreviated type. It is a pair of name |
471 | | /// and form. |
472 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
473 | | pub struct AttributeSpecification { |
474 | | name: constants::DwAt, |
475 | | form: constants::DwForm, |
476 | | implicit_const_value: i64, |
477 | | } |
478 | | |
479 | | impl AttributeSpecification { |
480 | | /// Construct a new `AttributeSpecification` from the given name and form |
481 | | /// and implicit const value. |
482 | | #[inline] |
483 | 0 | pub fn new( |
484 | 0 | name: constants::DwAt, |
485 | 0 | form: constants::DwForm, |
486 | 0 | implicit_const_value: Option<i64>, |
487 | 0 | ) -> AttributeSpecification { |
488 | 0 | debug_assert!( |
489 | 0 | (form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) |
490 | 0 | || (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()) |
491 | | ); |
492 | 0 | AttributeSpecification { |
493 | 0 | name, |
494 | 0 | form, |
495 | 0 | implicit_const_value: implicit_const_value.unwrap_or(0), |
496 | 0 | } |
497 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::new Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::new |
498 | | |
499 | | /// Get the attribute's name. |
500 | | #[inline] |
501 | 0 | pub fn name(&self) -> constants::DwAt { |
502 | 0 | self.name |
503 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::name Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::name |
504 | | |
505 | | /// Get the attribute's form. |
506 | | #[inline] |
507 | 0 | pub fn form(&self) -> constants::DwForm { |
508 | 0 | self.form |
509 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::form Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::form |
510 | | |
511 | | /// Get the attribute's implicit const value. |
512 | | #[inline] |
513 | 0 | pub fn implicit_const_value(&self) -> Option<i64> { |
514 | 0 | if self.form == constants::DW_FORM_implicit_const { |
515 | 0 | Some(self.implicit_const_value) |
516 | | } else { |
517 | 0 | None |
518 | | } |
519 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::implicit_const_value Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::implicit_const_value |
520 | | |
521 | | /// Return the size of the attribute, in bytes. |
522 | | /// |
523 | | /// Note that because some attributes are variably sized, the size cannot |
524 | | /// always be known without parsing, in which case we return `None`. |
525 | 0 | pub fn size<R: Reader>(&self, header: &UnitHeader<R>) -> Option<usize> { |
526 | 0 | get_attribute_size(self.form, header.encoding()).map(usize::from) |
527 | 0 | } |
528 | | |
529 | | /// Parse an attribute's form. |
530 | 0 | fn parse_form<R: Reader>(input: &mut R) -> Result<constants::DwForm> { |
531 | 0 | let val = input.read_uleb128_u16()?; |
532 | 0 | if val == 0 { |
533 | 0 | Err(Error::AttributeFormZero) |
534 | | } else { |
535 | 0 | Ok(constants::DwForm(val)) |
536 | | } |
537 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::parse_form::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::parse_form::<_> |
538 | | |
539 | | /// Parse an attribute specification. Returns `None` for the null attribute |
540 | | /// specification, `Some` for an actual attribute specification. |
541 | 0 | fn parse<R: Reader>(input: &mut R) -> Result<Option<AttributeSpecification>> { |
542 | 0 | let name = input.read_uleb128_u16()?; |
543 | 0 | if name == 0 { |
544 | | // Parse the null attribute specification. |
545 | 0 | let form = input.read_uleb128_u16()?; |
546 | 0 | return if form == 0 { |
547 | 0 | Ok(None) |
548 | | } else { |
549 | 0 | Err(Error::ExpectedZero) |
550 | | }; |
551 | 0 | } |
552 | 0 |
|
553 | 0 | let name = constants::DwAt(name); |
554 | 0 | let form = Self::parse_form(input)?; |
555 | 0 | let implicit_const_value = if form == constants::DW_FORM_implicit_const { |
556 | 0 | Some(input.read_sleb128()?) |
557 | | } else { |
558 | 0 | None |
559 | | }; |
560 | 0 | let spec = AttributeSpecification::new(name, form, implicit_const_value); |
561 | 0 | Ok(Some(spec)) |
562 | 0 | } Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::parse::<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> Unexecuted instantiation: <gimli::read::abbrev::AttributeSpecification>::parse::<_> |
563 | | } |
564 | | |
565 | | #[inline] |
566 | 0 | pub(crate) fn get_attribute_size(form: constants::DwForm, encoding: Encoding) -> Option<u8> { |
567 | 0 | match form { |
568 | 0 | constants::DW_FORM_addr => Some(encoding.address_size), |
569 | | |
570 | 0 | constants::DW_FORM_implicit_const | constants::DW_FORM_flag_present => Some(0), |
571 | | |
572 | | constants::DW_FORM_data1 |
573 | | | constants::DW_FORM_flag |
574 | | | constants::DW_FORM_strx1 |
575 | | | constants::DW_FORM_ref1 |
576 | 0 | | constants::DW_FORM_addrx1 => Some(1), |
577 | | |
578 | | constants::DW_FORM_data2 |
579 | | | constants::DW_FORM_ref2 |
580 | | | constants::DW_FORM_addrx2 |
581 | 0 | | constants::DW_FORM_strx2 => Some(2), |
582 | | |
583 | 0 | constants::DW_FORM_addrx3 | constants::DW_FORM_strx3 => Some(3), |
584 | | |
585 | | constants::DW_FORM_data4 |
586 | | | constants::DW_FORM_ref_sup4 |
587 | | | constants::DW_FORM_ref4 |
588 | | | constants::DW_FORM_strx4 |
589 | 0 | | constants::DW_FORM_addrx4 => Some(4), |
590 | | |
591 | | constants::DW_FORM_data8 |
592 | | | constants::DW_FORM_ref8 |
593 | | | constants::DW_FORM_ref_sig8 |
594 | 0 | | constants::DW_FORM_ref_sup8 => Some(8), |
595 | | |
596 | 0 | constants::DW_FORM_data16 => Some(16), |
597 | | |
598 | | constants::DW_FORM_sec_offset |
599 | | | constants::DW_FORM_GNU_ref_alt |
600 | | | constants::DW_FORM_strp |
601 | | | constants::DW_FORM_strp_sup |
602 | | | constants::DW_FORM_GNU_strp_alt |
603 | 0 | | constants::DW_FORM_line_strp => Some(encoding.format.word_size()), |
604 | | |
605 | | constants::DW_FORM_ref_addr => { |
606 | | // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr |
607 | | // has the same size as an address on the target system. This was changed |
608 | | // in DWARF version 3. |
609 | 0 | Some(if encoding.version == 2 { |
610 | 0 | encoding.address_size |
611 | | } else { |
612 | 0 | encoding.format.word_size() |
613 | | }) |
614 | | } |
615 | | |
616 | | // Variably sized forms. |
617 | | constants::DW_FORM_block |
618 | | | constants::DW_FORM_block1 |
619 | | | constants::DW_FORM_block2 |
620 | | | constants::DW_FORM_block4 |
621 | | | constants::DW_FORM_exprloc |
622 | | | constants::DW_FORM_ref_udata |
623 | | | constants::DW_FORM_string |
624 | | | constants::DW_FORM_sdata |
625 | | | constants::DW_FORM_udata |
626 | 0 | | constants::DW_FORM_indirect => None, |
627 | | |
628 | | // We don't know the size of unknown forms. |
629 | 0 | _ => None, |
630 | | } |
631 | 0 | } Unexecuted instantiation: gimli::read::abbrev::get_attribute_size Unexecuted instantiation: gimli::read::abbrev::get_attribute_size |
632 | | |
633 | | #[cfg(test)] |
634 | | pub(crate) mod tests { |
635 | | use super::*; |
636 | | use crate::constants; |
637 | | use crate::endianity::LittleEndian; |
638 | | use crate::read::{EndianSlice, Error}; |
639 | | use crate::test_util::GimliSectionMethods; |
640 | | #[cfg(target_pointer_width = "32")] |
641 | | use core::u32; |
642 | | use test_assembler::Section; |
643 | | |
644 | | pub trait AbbrevSectionMethods { |
645 | | fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self; |
646 | | fn abbrev_null(self) -> Self; |
647 | | fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self; |
648 | | fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self; |
649 | | fn abbrev_attr_null(self) -> Self; |
650 | | } |
651 | | |
652 | | impl AbbrevSectionMethods for Section { |
653 | | fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self { |
654 | | self.uleb(code).uleb(tag.0.into()).D8(children.0) |
655 | | } |
656 | | |
657 | | fn abbrev_null(self) -> Self { |
658 | | self.D8(0) |
659 | | } |
660 | | |
661 | | fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self { |
662 | | self.uleb(name.0.into()).uleb(form.0.into()) |
663 | | } |
664 | | |
665 | | fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self { |
666 | | self.uleb(name.0.into()) |
667 | | .uleb(constants::DW_FORM_implicit_const.0.into()) |
668 | | .sleb(value) |
669 | | } |
670 | | |
671 | | fn abbrev_attr_null(self) -> Self { |
672 | | self.D8(0).D8(0) |
673 | | } |
674 | | } |
675 | | |
676 | | #[test] |
677 | | fn test_debug_abbrev_ok() { |
678 | | let extra_start = [1, 2, 3, 4]; |
679 | | let expected_rest = [5, 6, 7, 8]; |
680 | | #[rustfmt::skip] |
681 | | let buf = Section::new() |
682 | | .append_bytes(&extra_start) |
683 | | .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
684 | | .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) |
685 | | .abbrev_attr_null() |
686 | | .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) |
687 | | .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) |
688 | | .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) |
689 | | .abbrev_attr_null() |
690 | | .abbrev_null() |
691 | | .append_bytes(&expected_rest) |
692 | | .get_contents() |
693 | | .unwrap(); |
694 | | |
695 | | let abbrev1 = Abbreviation::new( |
696 | | 1, |
697 | | constants::DW_TAG_compile_unit, |
698 | | constants::DW_CHILDREN_yes, |
699 | | vec![ |
700 | | AttributeSpecification::new( |
701 | | constants::DW_AT_producer, |
702 | | constants::DW_FORM_strp, |
703 | | None, |
704 | | ), |
705 | | AttributeSpecification::new( |
706 | | constants::DW_AT_language, |
707 | | constants::DW_FORM_data2, |
708 | | None, |
709 | | ), |
710 | | ] |
711 | | .into(), |
712 | | ); |
713 | | |
714 | | let abbrev2 = Abbreviation::new( |
715 | | 2, |
716 | | constants::DW_TAG_subprogram, |
717 | | constants::DW_CHILDREN_no, |
718 | | vec![AttributeSpecification::new( |
719 | | constants::DW_AT_name, |
720 | | constants::DW_FORM_string, |
721 | | None, |
722 | | )] |
723 | | .into(), |
724 | | ); |
725 | | |
726 | | let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian); |
727 | | let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len()); |
728 | | let abbrevs = debug_abbrev |
729 | | .abbreviations(debug_abbrev_offset) |
730 | | .expect("Should parse abbreviations"); |
731 | | assert_eq!(abbrevs.get(1), Some(&abbrev1)); |
732 | | assert_eq!(abbrevs.get(2), Some(&abbrev2)); |
733 | | } |
734 | | |
735 | | #[test] |
736 | | fn test_abbreviations_insert() { |
737 | | fn abbrev(code: u16) -> Abbreviation { |
738 | | Abbreviation::new( |
739 | | code.into(), |
740 | | constants::DwTag(code), |
741 | | constants::DW_CHILDREN_no, |
742 | | vec![].into(), |
743 | | ) |
744 | | } |
745 | | |
746 | | fn assert_abbrev(abbrevs: &Abbreviations, code: u16) { |
747 | | let abbrev = abbrevs.get(code.into()).unwrap(); |
748 | | assert_eq!(abbrev.tag(), constants::DwTag(code)); |
749 | | } |
750 | | |
751 | | // Sequential insert. |
752 | | let mut abbrevs = Abbreviations::empty(); |
753 | | abbrevs.insert(abbrev(1)).unwrap(); |
754 | | abbrevs.insert(abbrev(2)).unwrap(); |
755 | | assert_eq!(abbrevs.vec.len(), 2); |
756 | | assert!(abbrevs.map.is_empty()); |
757 | | assert_abbrev(&abbrevs, 1); |
758 | | assert_abbrev(&abbrevs, 2); |
759 | | |
760 | | // Out of order insert. |
761 | | let mut abbrevs = Abbreviations::empty(); |
762 | | abbrevs.insert(abbrev(2)).unwrap(); |
763 | | abbrevs.insert(abbrev(3)).unwrap(); |
764 | | assert!(abbrevs.vec.is_empty()); |
765 | | assert_abbrev(&abbrevs, 2); |
766 | | assert_abbrev(&abbrevs, 3); |
767 | | |
768 | | // Mixed order insert. |
769 | | let mut abbrevs = Abbreviations::empty(); |
770 | | abbrevs.insert(abbrev(1)).unwrap(); |
771 | | abbrevs.insert(abbrev(3)).unwrap(); |
772 | | abbrevs.insert(abbrev(2)).unwrap(); |
773 | | assert_eq!(abbrevs.vec.len(), 2); |
774 | | assert_abbrev(&abbrevs, 1); |
775 | | assert_abbrev(&abbrevs, 2); |
776 | | assert_abbrev(&abbrevs, 3); |
777 | | |
778 | | // Duplicate code in vec. |
779 | | let mut abbrevs = Abbreviations::empty(); |
780 | | abbrevs.insert(abbrev(1)).unwrap(); |
781 | | abbrevs.insert(abbrev(2)).unwrap(); |
782 | | assert_eq!(abbrevs.insert(abbrev(1)), Err(())); |
783 | | assert_eq!(abbrevs.insert(abbrev(2)), Err(())); |
784 | | |
785 | | // Duplicate code in map when adding to map. |
786 | | let mut abbrevs = Abbreviations::empty(); |
787 | | abbrevs.insert(abbrev(2)).unwrap(); |
788 | | assert_eq!(abbrevs.insert(abbrev(2)), Err(())); |
789 | | |
790 | | // Duplicate code in map when adding to vec. |
791 | | let mut abbrevs = Abbreviations::empty(); |
792 | | abbrevs.insert(abbrev(2)).unwrap(); |
793 | | abbrevs.insert(abbrev(1)).unwrap(); |
794 | | assert_eq!(abbrevs.insert(abbrev(2)), Err(())); |
795 | | |
796 | | // 32-bit usize conversions. |
797 | | let mut abbrevs = Abbreviations::empty(); |
798 | | abbrevs.insert(abbrev(2)).unwrap(); |
799 | | } |
800 | | |
801 | | #[test] |
802 | | #[cfg(target_pointer_width = "32")] |
803 | | fn test_abbreviations_insert_32() { |
804 | | fn abbrev(code: u64) -> Abbreviation { |
805 | | Abbreviation::new( |
806 | | code, |
807 | | constants::DwTag(code as u16), |
808 | | constants::DW_CHILDREN_no, |
809 | | vec![].into(), |
810 | | ) |
811 | | } |
812 | | |
813 | | fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { |
814 | | let abbrev = abbrevs.get(code).unwrap(); |
815 | | assert_eq!(abbrev.tag(), constants::DwTag(code as u16)); |
816 | | } |
817 | | |
818 | | let mut abbrevs = Abbreviations::empty(); |
819 | | abbrevs.insert(abbrev(1)).unwrap(); |
820 | | |
821 | | let wrap_code = (u32::MAX as u64 + 1) + 1; |
822 | | // `get` should not treat the wrapped code as `1`. |
823 | | assert_eq!(abbrevs.get(wrap_code), None); |
824 | | // `insert` should not treat the wrapped code as `1`. |
825 | | abbrevs.insert(abbrev(wrap_code)).unwrap(); |
826 | | assert_abbrev(&abbrevs, 1); |
827 | | assert_abbrev(&abbrevs, wrap_code); |
828 | | } |
829 | | |
830 | | #[test] |
831 | | fn test_parse_abbreviations_ok() { |
832 | | let expected_rest = [1, 2, 3, 4]; |
833 | | #[rustfmt::skip] |
834 | | let buf = Section::new() |
835 | | .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
836 | | .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) |
837 | | .abbrev_attr_null() |
838 | | .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) |
839 | | .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) |
840 | | .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) |
841 | | .abbrev_attr_null() |
842 | | .abbrev_null() |
843 | | .append_bytes(&expected_rest) |
844 | | .get_contents() |
845 | | .unwrap(); |
846 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
847 | | |
848 | | let abbrev1 = Abbreviation::new( |
849 | | 1, |
850 | | constants::DW_TAG_compile_unit, |
851 | | constants::DW_CHILDREN_yes, |
852 | | vec![ |
853 | | AttributeSpecification::new( |
854 | | constants::DW_AT_producer, |
855 | | constants::DW_FORM_strp, |
856 | | None, |
857 | | ), |
858 | | AttributeSpecification::new( |
859 | | constants::DW_AT_language, |
860 | | constants::DW_FORM_data2, |
861 | | None, |
862 | | ), |
863 | | ] |
864 | | .into(), |
865 | | ); |
866 | | |
867 | | let abbrev2 = Abbreviation::new( |
868 | | 2, |
869 | | constants::DW_TAG_subprogram, |
870 | | constants::DW_CHILDREN_no, |
871 | | vec![AttributeSpecification::new( |
872 | | constants::DW_AT_name, |
873 | | constants::DW_FORM_string, |
874 | | None, |
875 | | )] |
876 | | .into(), |
877 | | ); |
878 | | |
879 | | let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations"); |
880 | | assert_eq!(abbrevs.get(1), Some(&abbrev1)); |
881 | | assert_eq!(abbrevs.get(2), Some(&abbrev2)); |
882 | | assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); |
883 | | } |
884 | | |
885 | | #[test] |
886 | | fn test_parse_abbreviations_duplicate() { |
887 | | let expected_rest = [1, 2, 3, 4]; |
888 | | #[rustfmt::skip] |
889 | | let buf = Section::new() |
890 | | .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
891 | | .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) |
892 | | .abbrev_attr_null() |
893 | | .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) |
894 | | .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) |
895 | | .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) |
896 | | .abbrev_attr_null() |
897 | | .abbrev_null() |
898 | | .append_bytes(&expected_rest) |
899 | | .get_contents() |
900 | | .unwrap(); |
901 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
902 | | |
903 | | match Abbreviations::parse(buf) { |
904 | | Err(Error::DuplicateAbbreviationCode) => {} |
905 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
906 | | }; |
907 | | } |
908 | | |
909 | | #[test] |
910 | | fn test_parse_abbreviation_tag_ok() { |
911 | | let buf = [0x01, 0x02]; |
912 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
913 | | let tag = Abbreviation::parse_tag(rest).expect("Should parse tag"); |
914 | | assert_eq!(tag, constants::DW_TAG_array_type); |
915 | | assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); |
916 | | } |
917 | | |
918 | | #[test] |
919 | | fn test_parse_abbreviation_tag_zero() { |
920 | | let buf = [0x00]; |
921 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
922 | | match Abbreviation::parse_tag(buf) { |
923 | | Err(Error::AbbreviationTagZero) => {} |
924 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
925 | | }; |
926 | | } |
927 | | |
928 | | #[test] |
929 | | fn test_parse_abbreviation_has_children() { |
930 | | let buf = [0x00, 0x01, 0x02]; |
931 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
932 | | let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); |
933 | | assert_eq!(val, constants::DW_CHILDREN_no); |
934 | | let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); |
935 | | assert_eq!(val, constants::DW_CHILDREN_yes); |
936 | | match Abbreviation::parse_has_children(rest) { |
937 | | Err(Error::BadHasChildren) => {} |
938 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
939 | | }; |
940 | | } |
941 | | |
942 | | #[test] |
943 | | fn test_parse_abbreviation_ok() { |
944 | | let expected_rest = [0x01, 0x02, 0x03, 0x04]; |
945 | | let buf = Section::new() |
946 | | .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
947 | | .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) |
948 | | .abbrev_attr_null() |
949 | | .append_bytes(&expected_rest) |
950 | | .get_contents() |
951 | | .unwrap(); |
952 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
953 | | |
954 | | let expect = Some(Abbreviation::new( |
955 | | 1, |
956 | | constants::DW_TAG_subprogram, |
957 | | constants::DW_CHILDREN_no, |
958 | | vec![AttributeSpecification::new( |
959 | | constants::DW_AT_name, |
960 | | constants::DW_FORM_string, |
961 | | None, |
962 | | )] |
963 | | .into(), |
964 | | )); |
965 | | |
966 | | let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); |
967 | | assert_eq!(abbrev, expect); |
968 | | assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); |
969 | | } |
970 | | |
971 | | #[test] |
972 | | fn test_parse_abbreviation_implicit_const_ok() { |
973 | | let expected_rest = [0x01, 0x02, 0x03, 0x04]; |
974 | | let buf = Section::new() |
975 | | .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
976 | | .abbrev_attr_implicit_const(constants::DW_AT_name, -42) |
977 | | .abbrev_attr_null() |
978 | | .append_bytes(&expected_rest) |
979 | | .get_contents() |
980 | | .unwrap(); |
981 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
982 | | |
983 | | let expect = Some(Abbreviation::new( |
984 | | 1, |
985 | | constants::DW_TAG_subprogram, |
986 | | constants::DW_CHILDREN_no, |
987 | | vec![AttributeSpecification::new( |
988 | | constants::DW_AT_name, |
989 | | constants::DW_FORM_implicit_const, |
990 | | Some(-42), |
991 | | )] |
992 | | .into(), |
993 | | )); |
994 | | |
995 | | let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); |
996 | | assert_eq!(abbrev, expect); |
997 | | assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); |
998 | | } |
999 | | |
1000 | | #[test] |
1001 | | fn test_parse_abbreviation_implicit_const_no_const() { |
1002 | | let buf = Section::new() |
1003 | | .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) |
1004 | | .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const) |
1005 | | .get_contents() |
1006 | | .unwrap(); |
1007 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
1008 | | |
1009 | | match Abbreviation::parse(buf) { |
1010 | | Err(Error::UnexpectedEof(_)) => {} |
1011 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
1012 | | } |
1013 | | } |
1014 | | |
1015 | | #[test] |
1016 | | fn test_parse_null_abbreviation_ok() { |
1017 | | let expected_rest = [0x01, 0x02, 0x03, 0x04]; |
1018 | | let buf = Section::new() |
1019 | | .abbrev_null() |
1020 | | .append_bytes(&expected_rest) |
1021 | | .get_contents() |
1022 | | .unwrap(); |
1023 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
1024 | | |
1025 | | let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation"); |
1026 | | assert!(abbrev.is_none()); |
1027 | | assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); |
1028 | | } |
1029 | | |
1030 | | #[test] |
1031 | | fn test_parse_attribute_form_ok() { |
1032 | | let buf = [0x01, 0x02]; |
1033 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
1034 | | let tag = AttributeSpecification::parse_form(rest).expect("Should parse form"); |
1035 | | assert_eq!(tag, constants::DW_FORM_addr); |
1036 | | assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); |
1037 | | } |
1038 | | |
1039 | | #[test] |
1040 | | fn test_parse_attribute_form_zero() { |
1041 | | let buf = [0x00]; |
1042 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
1043 | | match AttributeSpecification::parse_form(buf) { |
1044 | | Err(Error::AttributeFormZero) => {} |
1045 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
1046 | | }; |
1047 | | } |
1048 | | |
1049 | | #[test] |
1050 | | fn test_parse_null_attribute_specification_ok() { |
1051 | | let buf = [0x00, 0x00, 0x01]; |
1052 | | let rest = &mut EndianSlice::new(&buf, LittleEndian); |
1053 | | let attr = |
1054 | | AttributeSpecification::parse(rest).expect("Should parse null attribute specification"); |
1055 | | assert!(attr.is_none()); |
1056 | | assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian)); |
1057 | | } |
1058 | | |
1059 | | #[test] |
1060 | | fn test_parse_attribute_specifications_name_zero() { |
1061 | | let buf = [0x00, 0x01, 0x00, 0x00]; |
1062 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
1063 | | match AttributeSpecification::parse(buf) { |
1064 | | Err(Error::ExpectedZero) => {} |
1065 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
1066 | | }; |
1067 | | } |
1068 | | |
1069 | | #[test] |
1070 | | fn test_parse_attribute_specifications_form_zero() { |
1071 | | let buf = [0x01, 0x00, 0x00, 0x00]; |
1072 | | let buf = &mut EndianSlice::new(&buf, LittleEndian); |
1073 | | match AttributeSpecification::parse(buf) { |
1074 | | Err(Error::AttributeFormZero) => {} |
1075 | | otherwise => panic!("Unexpected result: {:?}", otherwise), |
1076 | | }; |
1077 | | } |
1078 | | |
1079 | | #[test] |
1080 | | fn test_get_abbrev_zero() { |
1081 | | let mut abbrevs = Abbreviations::empty(); |
1082 | | abbrevs |
1083 | | .insert(Abbreviation::new( |
1084 | | 1, |
1085 | | constants::DwTag(1), |
1086 | | constants::DW_CHILDREN_no, |
1087 | | vec![].into(), |
1088 | | )) |
1089 | | .unwrap(); |
1090 | | assert!(abbrevs.get(0).is_none()); |
1091 | | } |
1092 | | } |